blob: 7c14537e64504722de45add6e7cf3e2d51d0dee3 [file] [log] [blame]
Dan Talaycoc901f4d2010-03-07 21:55:45 -08001
Dan Talaycod2ca1032010-03-10 14:40:26 -08002import sys
Dan Talayco92c99122010-06-03 13:53:18 -07003import copy
Dan Talaycod2ca1032010-03-10 14:40:26 -08004
5try:
6 import scapy.all as scapy
7except:
8 try:
9 import scapy as scapy
10 except:
11 sys.exit("Need to install scapy for packet parsing")
Dan Talayco41eae8b2010-03-10 13:57:06 -080012
Dan Talaycoc901f4d2010-03-07 21:55:45 -080013import oftest.controller as controller
14import oftest.cstruct as ofp
15import oftest.message as message
16import oftest.dataplane as dataplane
17import oftest.action as action
Dan Talayco41eae8b2010-03-10 13:57:06 -080018import oftest.parse as parse
Dan Talaycoc901f4d2010-03-07 21:55:45 -080019import logging
Dan Talayco4b2bee62010-07-20 14:10:05 -070020import types
Dan Talaycoc901f4d2010-03-07 21:55:45 -080021
Dan Talaycoba3745c2010-07-21 21:51:08 -070022global skipped_test_count
23skipped_test_count = 0
24
Dan Talayco551befa2010-07-15 17:05:32 -070025# Some useful defines
26IP_ETHERTYPE = 0x800
27TCP_PROTOCOL = 0x6
28UDP_PROTOCOL = 0x11
29
Dan Talayco98fada92010-07-17 00:36:21 -070030def clear_switch(parent, port_list, logger):
31 """
32 Clear the switch configuration
33
34 @param parent Object implementing controller and assert equal
35 @param logger Logging object
36 """
37 for port in port_list:
38 clear_port_config(parent, port, logger)
39 delete_all_flows(parent.controller, logger)
40
Dan Talayco41eae8b2010-03-10 13:57:06 -080041def delete_all_flows(ctrl, logger):
42 """
43 Delete all flows on the switch
44 @param ctrl The controller object for the test
45 @param logger Logging object
46 """
47
Dan Talaycoc901f4d2010-03-07 21:55:45 -080048 logger.info("Deleting all flows")
49 msg = message.flow_mod()
50 msg.match.wildcards = ofp.OFPFW_ALL
Dan Talayco41eae8b2010-03-10 13:57:06 -080051 msg.out_port = ofp.OFPP_NONE
Dan Talaycoc901f4d2010-03-07 21:55:45 -080052 msg.command = ofp.OFPFC_DELETE
53 msg.buffer_id = 0xffffffff
Dan Talayco41eae8b2010-03-10 13:57:06 -080054 return ctrl.message_send(msg)
55
Dan Talayco98fada92010-07-17 00:36:21 -070056def clear_port_config(parent, port, logger):
57 """
58 Clear the port configuration (currently only no flood setting)
59
60 @param parent Object implementing controller and assert equal
61 @param logger Logging object
62 """
63 rv = port_config_set(parent.controller, port,
64 0, ofp.OFPPC_NO_FLOOD, logger)
65 self.assertEqual(rv, 0, "Failed to reset port config")
66
Dan Talayco41eae8b2010-03-10 13:57:06 -080067def simple_tcp_packet(pktlen=100,
68 dl_dst='00:01:02:03:04:05',
69 dl_src='00:06:07:08:09:0a',
Tatsuya Yabe460321e2010-05-25 17:50:49 -070070 dl_vlan_enable=False,
71 dl_vlan=0,
72 dl_vlan_pcp=0,
Dan Talayco551befa2010-07-15 17:05:32 -070073 dl_vlan_cfi=0,
Dan Talayco41eae8b2010-03-10 13:57:06 -080074 ip_src='192.168.0.1',
75 ip_dst='192.168.0.2',
Tatsuya Yabe460321e2010-05-25 17:50:49 -070076 ip_tos=0,
Dan Talayco41eae8b2010-03-10 13:57:06 -080077 tcp_sport=1234,
78 tcp_dport=80
79 ):
80 """
81 Return a simple dataplane TCP packet
82
83 Supports a few parameters:
84 @param len Length of packet in bytes w/o CRC
85 @param dl_dst Destinatino MAC
86 @param dl_src Source MAC
Tatsuya Yabe460321e2010-05-25 17:50:49 -070087 @param dl_vlan_enable True if the packet is with vlan, False otherwise
88 @param dl_vlan VLAN ID
89 @param dl_vlan_pcp VLAN priority
Dan Talayco41eae8b2010-03-10 13:57:06 -080090 @param ip_src IP source
91 @param ip_dst IP destination
Tatsuya Yabe460321e2010-05-25 17:50:49 -070092 @param ip_tos IP ToS
Dan Talayco41eae8b2010-03-10 13:57:06 -080093 @param tcp_dport TCP destination port
94 @param ip_sport TCP source port
95
96 Generates a simple TCP request. Users
97 shouldn't assume anything about this packet other than that
98 it is a valid ethernet/IP/TCP frame.
99 """
Dan Talayco551befa2010-07-15 17:05:32 -0700100 # Note Dot1Q.id is really CFI
Tatsuya Yabe460321e2010-05-25 17:50:49 -0700101 if (dl_vlan_enable):
102 pkt = scapy.Ether(dst=dl_dst, src=dl_src)/ \
Dan Talayco551befa2010-07-15 17:05:32 -0700103 scapy.Dot1Q(prio=dl_vlan_pcp, id=dl_vlan_cfi, vlan=dl_vlan)/ \
Tatsuya Yabe460321e2010-05-25 17:50:49 -0700104 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos)/ \
105 scapy.TCP(sport=tcp_sport, dport=tcp_dport)
106 else:
107 pkt = scapy.Ether(dst=dl_dst, src=dl_src)/ \
108 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos)/ \
109 scapy.TCP(sport=tcp_sport, dport=tcp_dport)
110
Dan Talayco41eae8b2010-03-10 13:57:06 -0800111 pkt = pkt/("D" * (pktlen - len(pkt)))
112
113 return pkt
114
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700115def simple_icmp_packet(pktlen=60,
116 dl_dst='00:01:02:03:04:05',
117 dl_src='00:06:07:08:09:0a',
118 dl_vlan_enable=False,
119 dl_vlan=0,
120 dl_vlan_pcp=0,
121 ip_src='192.168.0.1',
122 ip_dst='192.168.0.2',
123 ip_tos=0,
124 icmp_type=8,
125 icmp_code=0
126 ):
127 """
128 Return a simple ICMP packet
129
130 Supports a few parameters:
131 @param len Length of packet in bytes w/o CRC
132 @param dl_dst Destinatino MAC
133 @param dl_src Source MAC
134 @param dl_vlan_enable True if the packet is with vlan, False otherwise
135 @param dl_vlan VLAN ID
136 @param dl_vlan_pcp VLAN priority
137 @param ip_src IP source
138 @param ip_dst IP destination
139 @param ip_tos IP ToS
140 @param icmp_type ICMP type
141 @param icmp_code ICMP code
142
143 Generates a simple ICMP ECHO REQUEST. Users
144 shouldn't assume anything about this packet other than that
145 it is a valid ethernet/ICMP frame.
146 """
147 if (dl_vlan_enable):
148 pkt = scapy.Ether(dst=dl_dst, src=dl_src)/ \
149 scapy.Dot1Q(prio=dl_vlan_pcp, id=0, vlan=dl_vlan)/ \
150 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos)/ \
151 scapy.ICMP(type=icmp_type, code=icmp_code)
152 else:
153 pkt = scapy.Ether(dst=dl_dst, src=dl_src)/ \
154 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos)/ \
155 scapy.ICMP(type=icmp_type, code=icmp_code)
156
157 pkt = pkt/("0" * (pktlen - len(pkt)))
158
159 return pkt
160
Dan Talayco41eae8b2010-03-10 13:57:06 -0800161def do_barrier(ctrl):
162 b = message.barrier_request()
163 ctrl.transact(b)
Dan Talayco92c99122010-06-03 13:53:18 -0700164
165
166def port_config_get(controller, port_no, logger):
167 """
168 Get a port's configuration
169
170 Gets the switch feature configuration and grabs one port's
171 configuration
172
173 @returns (hwaddr, config, advert) The hwaddress, configuration and
174 advertised values
175 """
176 request = message.features_request()
177 reply, pkt = controller.transact(request, timeout=2)
178 logger.debug(reply.show())
179 if reply is None:
180 logger.warn("Get feature request failed")
181 return None, None, None
182 for idx in range(len(reply.ports)):
183 if reply.ports[idx].port_no == port_no:
184 return (reply.ports[idx].hw_addr, reply.ports[idx].config,
185 reply.ports[idx].advertised)
186
187 logger.warn("Did not find port number for port config")
188 return None, None, None
189
190def port_config_set(controller, port_no, config, mask, logger):
191 """
192 Set the port configuration according the given parameters
193
194 Gets the switch feature configuration and updates one port's
195 configuration value according to config and mask
196 """
197 logger.info("Setting port " + str(port_no) + " to config " + str(config))
198 request = message.features_request()
199 reply, pkt = controller.transact(request, timeout=2)
200 if reply is None:
201 return -1
202 logger.debug(reply.show())
203 for idx in range(len(reply.ports)):
204 if reply.ports[idx].port_no == port_no:
205 break
206 if idx >= len(reply.ports):
207 return -1
208 mod = message.port_mod()
209 mod.port_no = port_no
210 mod.hw_addr = reply.ports[idx].hw_addr
211 mod.config = config
212 mod.mask = mask
213 mod.advertise = reply.ports[idx].advertised
214 rv = controller.message_send(mod)
215 return rv
216
217def receive_pkt_check(dataplane, pkt, yes_ports, no_ports, assert_if, logger):
218 """
219 Check for proper receive packets across all ports
220 @param dataplane The dataplane object
221 @param pkt Expected packet; may be None if yes_ports is empty
222 @param yes_ports Set or list of ports that should recieve packet
223 @param no_ports Set or list of ports that should not receive packet
224 @param assert_if Object that implements assertXXX
225 """
226 for ofport in yes_ports:
227 logger.debug("Checking for pkt on port " + str(ofport))
228 (rcv_port, rcv_pkt, pkt_time) = dataplane.poll(
229 port_number=ofport, timeout=1)
230 assert_if.assertTrue(rcv_pkt is not None,
231 "Did not receive pkt on " + str(ofport))
232 assert_if.assertEqual(str(pkt), str(rcv_pkt),
233 "Response packet does not match send packet " +
234 "on port " + str(ofport))
235
236 for ofport in no_ports:
237 logger.debug("Negative check for pkt on port " + str(ofport))
238 (rcv_port, rcv_pkt, pkt_time) = dataplane.poll(
239 port_number=ofport, timeout=1)
240 assert_if.assertTrue(rcv_pkt is None,
241 "Unexpected pkt on port " + str(ofport))
Dan Talayco551befa2010-07-15 17:05:32 -0700242
243
244def receive_pkt_verify(parent, egr_port, exp_pkt):
245 """
246 Receive a packet and verify it matches an expected value
247
248 parent must implement dataplane, assertTrue and assertEqual
249 """
250 (rcv_port, rcv_pkt, pkt_time) = parent.dataplane.poll(port_number=egr_port,
251 timeout=1)
252 if rcv_pkt is None:
253 parent.logger.error("ERROR: No packet received from " + str(egr_port))
254
255 parent.assertTrue(rcv_pkt is not None,
256 "Did not receive packet port " + str(egr_port))
257 parent.logger.debug("Packet len " + str(len(rcv_pkt)) + " in on " +
258 str(rcv_port))
259
260 if str(exp_pkt) != str(rcv_pkt):
261 parent.logger.error("ERROR: Packet match failed.")
262 parent.logger.debug("Expected len " + str(len(exp_pkt)) + ": "
263 + str(exp_pkt).encode('hex'))
264 parent.logger.debug("Received len " + str(len(rcv_pkt)) + ": "
265 + str(rcv_pkt).encode('hex'))
266 parent.assertEqual(str(exp_pkt), str(rcv_pkt),
267 "Packet match error on port " + str(egr_port))
268
269def match_verify(parent, req_match, res_match):
270 """
271 Verify flow matches agree; if they disagree, report where
272
273 parent must implement assertEqual
274 Use str() to ensure content is compared and not pointers
275 """
276
277 parent.assertEqual(req_match.wildcards, res_match.wildcards,
278 'Match failed: wildcards: ' + hex(req_match.wildcards) +
279 " != " + hex(res_match.wildcards))
280 parent.assertEqual(req_match.in_port, res_match.in_port,
281 'Match failed: in_port: ' + str(req_match.in_port) +
282 " != " + str(res_match.in_port))
283 parent.assertEqual(str(req_match.dl_src), str(res_match.dl_src),
284 'Match failed: dl_src: ' + str(req_match.dl_src) +
285 " != " + str(res_match.dl_src))
286 parent.assertEqual(str(req_match.dl_dst), str(res_match.dl_dst),
287 'Match failed: dl_dst: ' + str(req_match.dl_dst) +
288 " != " + str(res_match.dl_dst))
289 parent.assertEqual(req_match.dl_vlan, res_match.dl_vlan,
290 'Match failed: dl_vlan: ' + str(req_match.dl_vlan) +
291 " != " + str(res_match.dl_vlan))
292 parent.assertEqual(req_match.dl_vlan_pcp, res_match.dl_vlan_pcp,
293 'Match failed: dl_vlan_pcp: ' +
294 str(req_match.dl_vlan_pcp) + " != " +
295 str(res_match.dl_vlan_pcp))
296 parent.assertEqual(req_match.dl_type, res_match.dl_type,
297 'Match failed: dl_type: ' + str(req_match.dl_type) +
298 " != " + str(res_match.dl_type))
299
300 if (not(req_match.wildcards & ofp.OFPFW_DL_TYPE)
301 and (req_match.dl_type == IP_ETHERTYPE)):
302 parent.assertEqual(req_match.nw_tos, res_match.nw_tos,
303 'Match failed: nw_tos: ' + str(req_match.nw_tos) +
304 " != " + str(res_match.nw_tos))
305 parent.assertEqual(req_match.nw_proto, res_match.nw_proto,
306 'Match failed: nw_proto: ' + str(req_match.nw_proto) +
307 " != " + str(res_match.nw_proto))
308 parent.assertEqual(req_match.nw_src, res_match.nw_src,
309 'Match failed: nw_src: ' + str(req_match.nw_src) +
310 " != " + str(res_match.nw_src))
311 parent.assertEqual(req_match.nw_dst, res_match.nw_dst,
312 'Match failed: nw_dst: ' + str(req_match.nw_dst) +
313 " != " + str(res_match.nw_dst))
314
315 if (not(req_match.wildcards & ofp.OFPFW_NW_PROTO)
316 and ((req_match.nw_proto == TCP_PROTOCOL)
317 or (req_match.nw_proto == UDP_PROTOCOL))):
318 parent.assertEqual(req_match.tp_src, res_match.tp_src,
319 'Match failed: tp_src: ' +
320 str(req_match.tp_src) +
321 " != " + str(res_match.tp_src))
322 parent.assertEqual(req_match.tp_dst, res_match.tp_dst,
323 'Match failed: tp_dst: ' +
324 str(req_match.tp_dst) +
325 " != " + str(res_match.tp_dst))
326
327def flow_removed_verify(parent, request=None, pkt_count=-1, byte_count=-1):
328 """
329 Receive a flow removed msg and verify it matches expected
330
331 @params parent Must implement controller, assertEqual
332 @param pkt_count If >= 0, verify packet count
333 @param byte_count If >= 0, verify byte count
334 """
335 (response, raw) = parent.controller.poll(ofp.OFPT_FLOW_REMOVED, 2)
336 parent.assertTrue(response is not None, 'No flow removed message received')
337
338 if request is None:
339 return
340
341 parent.assertEqual(request.cookie, response.cookie,
342 "Flow removed cookie error: " +
343 hex(request.cookie) + " != " + hex(response.cookie))
344
345 req_match = request.match
346 res_match = response.match
347 verifyMatchField(req_match, res_match)
348
349 if (req_match.wildcards != 0):
350 parent.assertEqual(request.priority, response.priority,
351 'Flow remove prio mismatch: ' +
352 str(request,priority) + " != " +
353 str(response.priority))
354 parent.assertEqual(response.reason, ofp.OFPRR_HARD_TIMEOUT,
355 'Flow remove reason is not HARD TIMEOUT:' +
356 str(response.reason))
357 if pkt_count >= 0:
358 parent.assertEqual(response.packet_count, pkt_count,
359 'Flow removed failed, packet count: ' +
360 str(response.packet_count) + " != " +
361 str(pkt_count))
362 if byte_count >= 0:
363 parent.assertEqual(response.byte_count, byte_count,
364 'Flow removed failed, byte count: ' +
365 str(response.byte_count) + " != " +
366 str(byte_count))
367
368def flow_msg_create(parent, pkt, ing_port=None, action_list=None, wildcards=0,
369 egr_port=None, egr_queue=None, check_expire=False):
370 """
371 Create a flow message
372
373 Match on packet with given wildcards.
374 See flow_match_test for other parameter descriptoins
375 @param egr_queue if not None, make the output an enqueue action
376 """
377 match = parse.packet_to_flow_match(pkt)
378 parent.assertTrue(match is not None, "Flow match from pkt failed")
379 match.wildcards = wildcards
380 match.in_port = ing_port
381
382 request = message.flow_mod()
383 request.match = match
384 request.buffer_id = 0xffffffff
385 if check_expire:
386 request.flags |= ofp.OFPFF_SEND_FLOW_REM
387 request.hard_timeout = 1
388
389 if action_list is not None:
390 for act in action_list:
391 parent.logger.debug("Adding action " + act.show())
392 rv = request.actions.add(act)
393 parent.assertTrue(rv, "Could not add action" + act.show())
394
395 # Set up output/enqueue action if directed
396 if egr_queue is not None:
397 parent.assertTrue(egr_port is not None, "Egress port not set")
398 act = action.action_enqueue()
399 act.port = egr_port
400 act.queue_id = egr_queue
401 rv = request.actions.add(act)
402 parent.assertTrue(rv, "Could not add enqueue action " +
403 str(egr_port) + " Q: " + str(egr_queue))
404 elif egr_port is not None:
405 act = action.action_output()
406 act.port = egr_port
407 rv = request.actions.add(act)
408 parent.assertTrue(rv, "Could not add output action " + str(egr_port))
409
410 parent.logger.debug(request.show())
411
412 return request
413
414def flow_msg_install(parent, request, clear_table=True):
415 """
416 Install a flow mod message in the switch
417
418 @param parent Must implement controller, assertEqual, assertTrue
419 @param request The request, all set to go
420 @param clear_table If true, clear the flow table before installing
421 """
422 if clear_table:
423 parent.logger.debug("Clear flow table")
424 rc = delete_all_flows(parent.controller, parent.logger)
425 parent.assertEqual(rc, 0, "Failed to delete all flows")
426 do_barrier(parent.controller)
427
428 parent.logger.debug("Insert flow")
429 rv = parent.controller.message_send(request)
430 parent.assertTrue(rv != -1, "Error installing flow mod")
431 do_barrier(parent.controller)
432
433def flow_match_test_port_pair(parent, ing_port, egr_port, wildcards=0,
434 dl_vlan=-1, pkt=None, exp_pkt=None,
435 action_list=None, check_expire=False):
436 """
437 Flow match test on single TCP packet
438
439 Run test with packet through switch from ing_port to egr_port
440 See flow_match_test for parameter descriptions
441 """
442
443 parent.logger.info("Pkt match test: " + str(ing_port) + " to " + str(egr_port))
444 parent.logger.debug(" WC: " + hex(wildcards) + " vlan: " + str(dl_vlan) +
Dan Talayco98fada92010-07-17 00:36:21 -0700445 " expire: " + str(check_expire))
Dan Talayco551befa2010-07-15 17:05:32 -0700446 if pkt is None:
447 pkt = simple_tcp_packet(dl_vlan_enable=(dl_vlan >= 0), dl_vlan=dl_vlan)
448
449 request = flow_msg_create(parent, pkt, ing_port=ing_port,
450 wildcards=wildcards, egr_port=egr_port,
451 action_list=action_list)
452
453 flow_msg_install(parent, request)
454
455 parent.logger.debug("Send packet: " + str(ing_port) + " to " + str(egr_port))
456 parent.dataplane.send(ing_port, str(pkt))
457
458 if exp_pkt is None:
459 exp_pkt = pkt
460 receive_pkt_verify(parent, egr_port, exp_pkt)
461
462 if check_expire:
463 #@todo Not all HW supports both pkt and byte counters
464 flow_removed_verify(parent, request, pkt_count=1, byte_count=len(pkt))
465
466def flow_match_test(parent, port_map, wildcards=0, dl_vlan=-1, pkt=None,
467 exp_pkt=None, action_list=None, check_expire=False,
468 max_test=0):
469 """
470 Run flow_match_test_port_pair on all port pairs
471
472 @param max_test If > 0 no more than this number of tests are executed.
473 @param parent Must implement controller, dataplane, assertTrue, assertEqual
474 and logger
475 @param pkt If not None, use this packet for ingress
476 @param wildcards For flow match entry
477 @param dl_vlan If not -1, and pkt is not None, create a pkt w/ VLAN tag
478 @param exp_pkt If not None, use this as the expected output pkt; els use pkt
479 @param action_list Additional actions to add to flow mod
480 @param check_expire Check for flow expiration message
481 """
482 of_ports = port_map.keys()
483 of_ports.sort()
484 parent.assertTrue(len(of_ports) > 1, "Not enough ports for test")
485 test_count = 0
486
487 for ing_idx in range(len(of_ports)):
488 ingress_port = of_ports[ing_idx]
489 for egr_idx in range(len(of_ports)):
490 if egr_idx == ing_idx:
491 continue
492 egress_port = of_ports[egr_idx]
493 flow_match_test_port_pair(parent, ingress_port, egress_port,
Dan Talayco98fada92010-07-17 00:36:21 -0700494 wildcards=wildcards, dl_vlan=dl_vlan,
495 pkt=pkt, exp_pkt=exp_pkt,
496 action_list=action_list,
Dan Talayco551befa2010-07-15 17:05:32 -0700497 check_expire=check_expire)
498 test_count += 1
499 if (max_test > 0) and (test_count > max_test):
500 parent.logger.info("Ran " + str(test_count) + " tests; exiting")
501 return
502
Dan Talayco4b2bee62010-07-20 14:10:05 -0700503def test_param_get(config, key, default=None):
504 """
505 Return value passed via test-params if present
506
507 @param config The configuration structure for OFTest
508 @param key The lookup key
509 @param default Default value to use if not found
510
511 If the pair 'key=val' appeared in the string passed to --test-params
512 on the command line, return val (as interpreted by exec). Otherwise
513 return default value.
514 """
515 try:
516 exec config["test_params"]
517 except:
518 return default
519
520 s = "val = " + str(key)
521 try:
522 exec s
523 return val
524 except:
525 return default
526
527def action_generate(parent, field_to_mod, mod_field_vals):
528 """
529 Create an action to modify the field indicated in field_to_mod
530
531 @param parent Must implement, assertTrue
532 @param field_to_mod The field to modify as a string name
533 @param mod_field_vals Hash of values to use for modified values
534 """
535
536 act = None
537
538 if field_to_mod in ['pktlen']:
539 return None
540
541 if field_to_mod == 'dl_dst':
542 act = action.action_set_dl_dst()
543 act.dl_addr = parse.parse_mac(mod_field_vals['dl_dst'])
544 elif field_to_mod == 'dl_src':
545 act = action.action_set_dl_src()
546 act.dl_addr = parse.parse_mac(mod_field_vals['dl_src'])
547 elif field_to_mod == 'dl_vlan_enable':
548 if not mod_field_vals['dl_vlan_enable']: # Strip VLAN tag
549 act = action.action_strip_vlan()
550 # Add VLAN tag is handled by dl_vlan field
551 # Will return None in this case
552 elif field_to_mod == 'dl_vlan':
553 act = action.action_set_vlan_vid()
554 act.vlan_vid = mod_field_vals['dl_vlan']
555 elif field_to_mod == 'dl_vlan_pcp':
556 act = action.action_set_vlan_pcp()
557 act.vlan_pcp = mod_field_vals['dl_vlan_pcp']
558 elif field_to_mod == 'ip_src':
559 act = action.action_set_nw_src()
560 act.nw_addr = parse.parse_ip(mod_field_vals['ip_src'])
561 elif field_to_mod == 'ip_dst':
562 act = action.action_set_nw_dst()
563 act.nw_addr = parse.parse_ip(mod_field_vals['ip_dst'])
564 elif field_to_mod == 'ip_tos':
565 act = action.action_set_nw_tos()
566 act.nw_tos = mod_field_vals['ip_tos']
567 elif field_to_mod == 'tcp_sport':
568 act = action.action_set_tp_src()
569 act.tp_port = mod_field_vals['tcp_sport']
570 elif field_to_mod == 'tcp_dport':
571 act = action.action_set_tp_dst()
572 act.tp_port = mod_field_vals['tcp_dport']
573 else:
574 parent.assertTrue(0, "Unknown field to modify: " + str(field_to_mod))
575
576 return act
577
578def pkt_action_setup(parent, start_field_vals={}, mod_field_vals={},
579 mod_fields={}, check_test_params=False):
580 """
581 Set up the ingress and expected packet and action list for a test
582
583 @param parent Must implement, assertTrue, config hash and logger
584 @param start_field_values Field values to use for ingress packet (optional)
585 @param mod_field_values Field values to use for modified packet (optional)
586 @param mod_fields The list of fields to be modified by the switch in the test.
587 @params check_test_params If True, will check the parameters vid, add_vlan
588 and strip_vlan from the command line.
589
590 Returns a triple: pkt-to-send, expected-pkt, action-list
591 """
592
593 new_actions = []
594
595
596 base_pkt_params = {}
597 base_pkt_params['pktlen'] = 100
598 base_pkt_params['dl_dst'] = '00:DE:F0:12:34:56'
599 base_pkt_params['dl_src'] = '00:23:45:67:89:AB'
600 base_pkt_params['dl_vlan_enable'] = False
601 base_pkt_params['dl_vlan'] = 2
602 base_pkt_params['dl_vlan_pcp'] = 0
603 base_pkt_params['ip_src'] = '192.168.0.1'
604 base_pkt_params['ip_dst'] = '192.168.0.2'
605 base_pkt_params['ip_tos'] = 0
606 base_pkt_params['tcp_sport'] = 1234
607 base_pkt_params['tcp_dport'] = 80
608 for keyname in start_field_vals.keys():
609 base_pkt_params[keyname] = start_field_vals[keyname]
610
611 mod_pkt_params = {}
612 mod_pkt_params['pktlen'] = 100
613 mod_pkt_params['dl_dst'] = '00:21:0F:ED:CB:A9'
614 mod_pkt_params['dl_src'] = '00:ED:CB:A9:87:65'
615 mod_pkt_params['dl_vlan_enable'] = False
616 mod_pkt_params['dl_vlan'] = 3
617 mod_pkt_params['dl_vlan_pcp'] = 7
618 mod_pkt_params['ip_src'] = '10.20.30.40'
619 mod_pkt_params['ip_dst'] = '50.60.70.80'
620 mod_pkt_params['ip_tos'] = 0xf0
621 mod_pkt_params['tcp_sport'] = 4321
622 mod_pkt_params['tcp_dport'] = 8765
623 for keyname in mod_field_vals.keys():
624 mod_pkt_params[keyname] = mod_field_vals[keyname]
625
626 # Check for test param modifications
627 strip = False
628 if check_test_params:
629 add_vlan = test_param_get(parent.config, 'add_vlan')
630 strip_vlan = test_param_get(parent.config, 'strip_vlan')
631 vid = test_param_get(parent.config, 'vid')
632
633 if add_vlan and strip_vlan:
634 parent.assertTrue(0, "Add and strip VLAN both specified")
635
636 if vid:
637 base_pkt_params['dl_vlan_enable'] = True
638 base_pkt_params['dl_vlan'] = vid
639 if 'dl_vlan' in mod_fields:
640 mod_pkt_params['dl_vlan'] = vid + 1
641
642 if add_vlan:
643 base_pkt_params['dl_vlan_enable'] = False
644 mod_pkt_params['dl_vlan_enable'] = True
645 mod_pkt_params['pktlen'] = base_pkt_params['pktlen'] + 4
646 mod_fields.append('pktlen')
647 mod_fields.append('dl_vlan_enable')
648 if 'dl_vlan' not in mod_fields:
649 mod_fields.append('dl_vlan')
650 elif strip_vlan:
651 base_pkt_params['dl_vlan_enable'] = True
652 mod_pkt_params['dl_vlan_enable'] = False
653 mod_pkt_params['pktlen'] = base_pkt_params['pktlen'] - 4
654 mod_fields.append('dl_vlan_enable')
655 mod_fields.append('pktlen')
656
657 # Build the ingress packet
658 ingress_pkt = simple_tcp_packet(**base_pkt_params)
659
660 # Build the expected packet, modifying the indicated fields
661 for item in mod_fields:
662 base_pkt_params[item] = mod_pkt_params[item]
663 act = action_generate(parent, item, mod_pkt_params)
664 if act:
665 new_actions.append(act)
666
667 expected_pkt = simple_tcp_packet(**base_pkt_params)
668
669 return (ingress_pkt, expected_pkt, new_actions)
670
Dan Talaycoba3745c2010-07-21 21:51:08 -0700671
672def skip_message_emit(parent, s):
673 """
674 Print out a 'skipped' message to stderr
675
676 @param s The string to print out to the log file
677 @param parent Must implement config and logger objects
678 """
679 global skipped_test_count
680
681 skipped_test_count += 1
682 parent.logger.info("Skipping: " + s)
683 if parent.config["dbg_level"] < logging.WARNING:
684 sys.stderr.write("(skipped) ")
685 else:
686 sys.stderr.write("(S)")