blob: 450b330f19a527260774633a5e6f23e70dac6e3e [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
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700217def receive_pkt_check(dataplane, pkt, yes_ports, no_ports, assert_if, logger,
218 config):
Dan Talayco92c99122010-06-03 13:53:18 -0700219 """
220 Check for proper receive packets across all ports
221 @param dataplane The dataplane object
222 @param pkt Expected packet; may be None if yes_ports is empty
223 @param yes_ports Set or list of ports that should recieve packet
224 @param no_ports Set or list of ports that should not receive packet
225 @param assert_if Object that implements assertXXX
226 """
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700227 exp_pkt_arg = None
228 if config and config["relax"]:
229 exp_pkt_arg = pkt
230
Dan Talayco92c99122010-06-03 13:53:18 -0700231 for ofport in yes_ports:
232 logger.debug("Checking for pkt on port " + str(ofport))
233 (rcv_port, rcv_pkt, pkt_time) = dataplane.poll(
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700234 port_number=ofport, timeout=1, exp_pkt=exp_pkt_arg)
Dan Talayco92c99122010-06-03 13:53:18 -0700235 assert_if.assertTrue(rcv_pkt is not None,
236 "Did not receive pkt on " + str(ofport))
237 assert_if.assertEqual(str(pkt), str(rcv_pkt),
238 "Response packet does not match send packet " +
239 "on port " + str(ofport))
240
241 for ofport in no_ports:
242 logger.debug("Negative check for pkt on port " + str(ofport))
243 (rcv_port, rcv_pkt, pkt_time) = dataplane.poll(
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700244 port_number=ofport, timeout=1, exp_pkt=exp_pkt_arg)
Dan Talayco92c99122010-06-03 13:53:18 -0700245 assert_if.assertTrue(rcv_pkt is None,
246 "Unexpected pkt on port " + str(ofport))
Dan Talayco551befa2010-07-15 17:05:32 -0700247
248
249def receive_pkt_verify(parent, egr_port, exp_pkt):
250 """
251 Receive a packet and verify it matches an expected value
252
253 parent must implement dataplane, assertTrue and assertEqual
254 """
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700255 exp_pkt_arg = None
256 if parent.config["relax"]:
257 exp_pkt_arg = exp_pkt
258
Dan Talayco551befa2010-07-15 17:05:32 -0700259 (rcv_port, rcv_pkt, pkt_time) = parent.dataplane.poll(port_number=egr_port,
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700260 timeout=1,
261 exp_pkt=exp_pkt_arg)
262
Dan Talayco551befa2010-07-15 17:05:32 -0700263 if rcv_pkt is None:
264 parent.logger.error("ERROR: No packet received from " + str(egr_port))
265
266 parent.assertTrue(rcv_pkt is not None,
267 "Did not receive packet port " + str(egr_port))
268 parent.logger.debug("Packet len " + str(len(rcv_pkt)) + " in on " +
269 str(rcv_port))
270
271 if str(exp_pkt) != str(rcv_pkt):
272 parent.logger.error("ERROR: Packet match failed.")
273 parent.logger.debug("Expected len " + str(len(exp_pkt)) + ": "
274 + str(exp_pkt).encode('hex'))
275 parent.logger.debug("Received len " + str(len(rcv_pkt)) + ": "
276 + str(rcv_pkt).encode('hex'))
277 parent.assertEqual(str(exp_pkt), str(rcv_pkt),
278 "Packet match error on port " + str(egr_port))
279
280def match_verify(parent, req_match, res_match):
281 """
282 Verify flow matches agree; if they disagree, report where
283
284 parent must implement assertEqual
285 Use str() to ensure content is compared and not pointers
286 """
287
288 parent.assertEqual(req_match.wildcards, res_match.wildcards,
289 'Match failed: wildcards: ' + hex(req_match.wildcards) +
290 " != " + hex(res_match.wildcards))
291 parent.assertEqual(req_match.in_port, res_match.in_port,
292 'Match failed: in_port: ' + str(req_match.in_port) +
293 " != " + str(res_match.in_port))
294 parent.assertEqual(str(req_match.dl_src), str(res_match.dl_src),
295 'Match failed: dl_src: ' + str(req_match.dl_src) +
296 " != " + str(res_match.dl_src))
297 parent.assertEqual(str(req_match.dl_dst), str(res_match.dl_dst),
298 'Match failed: dl_dst: ' + str(req_match.dl_dst) +
299 " != " + str(res_match.dl_dst))
300 parent.assertEqual(req_match.dl_vlan, res_match.dl_vlan,
301 'Match failed: dl_vlan: ' + str(req_match.dl_vlan) +
302 " != " + str(res_match.dl_vlan))
303 parent.assertEqual(req_match.dl_vlan_pcp, res_match.dl_vlan_pcp,
304 'Match failed: dl_vlan_pcp: ' +
305 str(req_match.dl_vlan_pcp) + " != " +
306 str(res_match.dl_vlan_pcp))
307 parent.assertEqual(req_match.dl_type, res_match.dl_type,
308 'Match failed: dl_type: ' + str(req_match.dl_type) +
309 " != " + str(res_match.dl_type))
310
311 if (not(req_match.wildcards & ofp.OFPFW_DL_TYPE)
312 and (req_match.dl_type == IP_ETHERTYPE)):
313 parent.assertEqual(req_match.nw_tos, res_match.nw_tos,
314 'Match failed: nw_tos: ' + str(req_match.nw_tos) +
315 " != " + str(res_match.nw_tos))
316 parent.assertEqual(req_match.nw_proto, res_match.nw_proto,
317 'Match failed: nw_proto: ' + str(req_match.nw_proto) +
318 " != " + str(res_match.nw_proto))
319 parent.assertEqual(req_match.nw_src, res_match.nw_src,
320 'Match failed: nw_src: ' + str(req_match.nw_src) +
321 " != " + str(res_match.nw_src))
322 parent.assertEqual(req_match.nw_dst, res_match.nw_dst,
323 'Match failed: nw_dst: ' + str(req_match.nw_dst) +
324 " != " + str(res_match.nw_dst))
325
326 if (not(req_match.wildcards & ofp.OFPFW_NW_PROTO)
327 and ((req_match.nw_proto == TCP_PROTOCOL)
328 or (req_match.nw_proto == UDP_PROTOCOL))):
329 parent.assertEqual(req_match.tp_src, res_match.tp_src,
330 'Match failed: tp_src: ' +
331 str(req_match.tp_src) +
332 " != " + str(res_match.tp_src))
333 parent.assertEqual(req_match.tp_dst, res_match.tp_dst,
334 'Match failed: tp_dst: ' +
335 str(req_match.tp_dst) +
336 " != " + str(res_match.tp_dst))
337
338def flow_removed_verify(parent, request=None, pkt_count=-1, byte_count=-1):
339 """
340 Receive a flow removed msg and verify it matches expected
341
342 @params parent Must implement controller, assertEqual
343 @param pkt_count If >= 0, verify packet count
344 @param byte_count If >= 0, verify byte count
345 """
346 (response, raw) = parent.controller.poll(ofp.OFPT_FLOW_REMOVED, 2)
347 parent.assertTrue(response is not None, 'No flow removed message received')
348
349 if request is None:
350 return
351
352 parent.assertEqual(request.cookie, response.cookie,
353 "Flow removed cookie error: " +
354 hex(request.cookie) + " != " + hex(response.cookie))
355
356 req_match = request.match
357 res_match = response.match
358 verifyMatchField(req_match, res_match)
359
360 if (req_match.wildcards != 0):
361 parent.assertEqual(request.priority, response.priority,
362 'Flow remove prio mismatch: ' +
363 str(request,priority) + " != " +
364 str(response.priority))
365 parent.assertEqual(response.reason, ofp.OFPRR_HARD_TIMEOUT,
366 'Flow remove reason is not HARD TIMEOUT:' +
367 str(response.reason))
368 if pkt_count >= 0:
369 parent.assertEqual(response.packet_count, pkt_count,
370 'Flow removed failed, packet count: ' +
371 str(response.packet_count) + " != " +
372 str(pkt_count))
373 if byte_count >= 0:
374 parent.assertEqual(response.byte_count, byte_count,
375 'Flow removed failed, byte count: ' +
376 str(response.byte_count) + " != " +
377 str(byte_count))
378
379def flow_msg_create(parent, pkt, ing_port=None, action_list=None, wildcards=0,
380 egr_port=None, egr_queue=None, check_expire=False):
381 """
382 Create a flow message
383
384 Match on packet with given wildcards.
385 See flow_match_test for other parameter descriptoins
386 @param egr_queue if not None, make the output an enqueue action
387 """
388 match = parse.packet_to_flow_match(pkt)
389 parent.assertTrue(match is not None, "Flow match from pkt failed")
390 match.wildcards = wildcards
391 match.in_port = ing_port
392
393 request = message.flow_mod()
394 request.match = match
395 request.buffer_id = 0xffffffff
396 if check_expire:
397 request.flags |= ofp.OFPFF_SEND_FLOW_REM
398 request.hard_timeout = 1
399
400 if action_list is not None:
401 for act in action_list:
402 parent.logger.debug("Adding action " + act.show())
403 rv = request.actions.add(act)
404 parent.assertTrue(rv, "Could not add action" + act.show())
405
406 # Set up output/enqueue action if directed
407 if egr_queue is not None:
408 parent.assertTrue(egr_port is not None, "Egress port not set")
409 act = action.action_enqueue()
410 act.port = egr_port
411 act.queue_id = egr_queue
412 rv = request.actions.add(act)
413 parent.assertTrue(rv, "Could not add enqueue action " +
414 str(egr_port) + " Q: " + str(egr_queue))
415 elif egr_port is not None:
416 act = action.action_output()
417 act.port = egr_port
418 rv = request.actions.add(act)
419 parent.assertTrue(rv, "Could not add output action " + str(egr_port))
420
421 parent.logger.debug(request.show())
422
423 return request
424
425def flow_msg_install(parent, request, clear_table=True):
426 """
427 Install a flow mod message in the switch
428
429 @param parent Must implement controller, assertEqual, assertTrue
430 @param request The request, all set to go
431 @param clear_table If true, clear the flow table before installing
432 """
433 if clear_table:
434 parent.logger.debug("Clear flow table")
435 rc = delete_all_flows(parent.controller, parent.logger)
436 parent.assertEqual(rc, 0, "Failed to delete all flows")
437 do_barrier(parent.controller)
438
439 parent.logger.debug("Insert flow")
440 rv = parent.controller.message_send(request)
441 parent.assertTrue(rv != -1, "Error installing flow mod")
442 do_barrier(parent.controller)
443
444def flow_match_test_port_pair(parent, ing_port, egr_port, wildcards=0,
445 dl_vlan=-1, pkt=None, exp_pkt=None,
446 action_list=None, check_expire=False):
447 """
448 Flow match test on single TCP packet
449
450 Run test with packet through switch from ing_port to egr_port
451 See flow_match_test for parameter descriptions
452 """
453
454 parent.logger.info("Pkt match test: " + str(ing_port) + " to " + str(egr_port))
455 parent.logger.debug(" WC: " + hex(wildcards) + " vlan: " + str(dl_vlan) +
Dan Talayco98fada92010-07-17 00:36:21 -0700456 " expire: " + str(check_expire))
Dan Talayco551befa2010-07-15 17:05:32 -0700457 if pkt is None:
458 pkt = simple_tcp_packet(dl_vlan_enable=(dl_vlan >= 0), dl_vlan=dl_vlan)
459
460 request = flow_msg_create(parent, pkt, ing_port=ing_port,
461 wildcards=wildcards, egr_port=egr_port,
462 action_list=action_list)
463
464 flow_msg_install(parent, request)
465
466 parent.logger.debug("Send packet: " + str(ing_port) + " to " + str(egr_port))
467 parent.dataplane.send(ing_port, str(pkt))
468
469 if exp_pkt is None:
470 exp_pkt = pkt
471 receive_pkt_verify(parent, egr_port, exp_pkt)
472
473 if check_expire:
474 #@todo Not all HW supports both pkt and byte counters
475 flow_removed_verify(parent, request, pkt_count=1, byte_count=len(pkt))
476
477def flow_match_test(parent, port_map, wildcards=0, dl_vlan=-1, pkt=None,
478 exp_pkt=None, action_list=None, check_expire=False,
479 max_test=0):
480 """
481 Run flow_match_test_port_pair on all port pairs
482
483 @param max_test If > 0 no more than this number of tests are executed.
484 @param parent Must implement controller, dataplane, assertTrue, assertEqual
485 and logger
486 @param pkt If not None, use this packet for ingress
487 @param wildcards For flow match entry
Dan Talayco79184222010-11-01 12:24:29 -0700488 @param dl_vlan If not -1, and pkt is None, create a pkt w/ VLAN tag
Dan Talayco551befa2010-07-15 17:05:32 -0700489 @param exp_pkt If not None, use this as the expected output pkt; els use pkt
490 @param action_list Additional actions to add to flow mod
491 @param check_expire Check for flow expiration message
492 """
493 of_ports = port_map.keys()
494 of_ports.sort()
495 parent.assertTrue(len(of_ports) > 1, "Not enough ports for test")
496 test_count = 0
497
498 for ing_idx in range(len(of_ports)):
499 ingress_port = of_ports[ing_idx]
500 for egr_idx in range(len(of_ports)):
501 if egr_idx == ing_idx:
502 continue
503 egress_port = of_ports[egr_idx]
504 flow_match_test_port_pair(parent, ingress_port, egress_port,
Dan Talayco98fada92010-07-17 00:36:21 -0700505 wildcards=wildcards, dl_vlan=dl_vlan,
506 pkt=pkt, exp_pkt=exp_pkt,
507 action_list=action_list,
Dan Talayco551befa2010-07-15 17:05:32 -0700508 check_expire=check_expire)
509 test_count += 1
510 if (max_test > 0) and (test_count > max_test):
511 parent.logger.info("Ran " + str(test_count) + " tests; exiting")
512 return
513
Dan Talayco4b2bee62010-07-20 14:10:05 -0700514def test_param_get(config, key, default=None):
515 """
516 Return value passed via test-params if present
517
518 @param config The configuration structure for OFTest
519 @param key The lookup key
520 @param default Default value to use if not found
521
522 If the pair 'key=val' appeared in the string passed to --test-params
523 on the command line, return val (as interpreted by exec). Otherwise
524 return default value.
525 """
526 try:
527 exec config["test_params"]
528 except:
529 return default
530
531 s = "val = " + str(key)
532 try:
533 exec s
534 return val
535 except:
536 return default
537
538def action_generate(parent, field_to_mod, mod_field_vals):
539 """
540 Create an action to modify the field indicated in field_to_mod
541
542 @param parent Must implement, assertTrue
543 @param field_to_mod The field to modify as a string name
544 @param mod_field_vals Hash of values to use for modified values
545 """
546
547 act = None
548
549 if field_to_mod in ['pktlen']:
550 return None
551
552 if field_to_mod == 'dl_dst':
553 act = action.action_set_dl_dst()
554 act.dl_addr = parse.parse_mac(mod_field_vals['dl_dst'])
555 elif field_to_mod == 'dl_src':
556 act = action.action_set_dl_src()
557 act.dl_addr = parse.parse_mac(mod_field_vals['dl_src'])
558 elif field_to_mod == 'dl_vlan_enable':
559 if not mod_field_vals['dl_vlan_enable']: # Strip VLAN tag
560 act = action.action_strip_vlan()
561 # Add VLAN tag is handled by dl_vlan field
562 # Will return None in this case
563 elif field_to_mod == 'dl_vlan':
564 act = action.action_set_vlan_vid()
565 act.vlan_vid = mod_field_vals['dl_vlan']
566 elif field_to_mod == 'dl_vlan_pcp':
567 act = action.action_set_vlan_pcp()
568 act.vlan_pcp = mod_field_vals['dl_vlan_pcp']
569 elif field_to_mod == 'ip_src':
570 act = action.action_set_nw_src()
571 act.nw_addr = parse.parse_ip(mod_field_vals['ip_src'])
572 elif field_to_mod == 'ip_dst':
573 act = action.action_set_nw_dst()
574 act.nw_addr = parse.parse_ip(mod_field_vals['ip_dst'])
575 elif field_to_mod == 'ip_tos':
576 act = action.action_set_nw_tos()
577 act.nw_tos = mod_field_vals['ip_tos']
578 elif field_to_mod == 'tcp_sport':
579 act = action.action_set_tp_src()
580 act.tp_port = mod_field_vals['tcp_sport']
581 elif field_to_mod == 'tcp_dport':
582 act = action.action_set_tp_dst()
583 act.tp_port = mod_field_vals['tcp_dport']
584 else:
585 parent.assertTrue(0, "Unknown field to modify: " + str(field_to_mod))
586
587 return act
588
589def pkt_action_setup(parent, start_field_vals={}, mod_field_vals={},
590 mod_fields={}, check_test_params=False):
591 """
592 Set up the ingress and expected packet and action list for a test
593
594 @param parent Must implement, assertTrue, config hash and logger
595 @param start_field_values Field values to use for ingress packet (optional)
596 @param mod_field_values Field values to use for modified packet (optional)
597 @param mod_fields The list of fields to be modified by the switch in the test.
598 @params check_test_params If True, will check the parameters vid, add_vlan
599 and strip_vlan from the command line.
600
601 Returns a triple: pkt-to-send, expected-pkt, action-list
602 """
603
604 new_actions = []
605
Dan Talayco4b2bee62010-07-20 14:10:05 -0700606 base_pkt_params = {}
607 base_pkt_params['pktlen'] = 100
608 base_pkt_params['dl_dst'] = '00:DE:F0:12:34:56'
609 base_pkt_params['dl_src'] = '00:23:45:67:89:AB'
610 base_pkt_params['dl_vlan_enable'] = False
611 base_pkt_params['dl_vlan'] = 2
612 base_pkt_params['dl_vlan_pcp'] = 0
613 base_pkt_params['ip_src'] = '192.168.0.1'
614 base_pkt_params['ip_dst'] = '192.168.0.2'
615 base_pkt_params['ip_tos'] = 0
616 base_pkt_params['tcp_sport'] = 1234
617 base_pkt_params['tcp_dport'] = 80
618 for keyname in start_field_vals.keys():
619 base_pkt_params[keyname] = start_field_vals[keyname]
620
621 mod_pkt_params = {}
622 mod_pkt_params['pktlen'] = 100
623 mod_pkt_params['dl_dst'] = '00:21:0F:ED:CB:A9'
624 mod_pkt_params['dl_src'] = '00:ED:CB:A9:87:65'
625 mod_pkt_params['dl_vlan_enable'] = False
626 mod_pkt_params['dl_vlan'] = 3
627 mod_pkt_params['dl_vlan_pcp'] = 7
628 mod_pkt_params['ip_src'] = '10.20.30.40'
629 mod_pkt_params['ip_dst'] = '50.60.70.80'
630 mod_pkt_params['ip_tos'] = 0xf0
631 mod_pkt_params['tcp_sport'] = 4321
632 mod_pkt_params['tcp_dport'] = 8765
633 for keyname in mod_field_vals.keys():
634 mod_pkt_params[keyname] = mod_field_vals[keyname]
635
636 # Check for test param modifications
637 strip = False
638 if check_test_params:
639 add_vlan = test_param_get(parent.config, 'add_vlan')
640 strip_vlan = test_param_get(parent.config, 'strip_vlan')
641 vid = test_param_get(parent.config, 'vid')
642
643 if add_vlan and strip_vlan:
644 parent.assertTrue(0, "Add and strip VLAN both specified")
645
646 if vid:
647 base_pkt_params['dl_vlan_enable'] = True
648 base_pkt_params['dl_vlan'] = vid
649 if 'dl_vlan' in mod_fields:
650 mod_pkt_params['dl_vlan'] = vid + 1
651
652 if add_vlan:
653 base_pkt_params['dl_vlan_enable'] = False
654 mod_pkt_params['dl_vlan_enable'] = True
655 mod_pkt_params['pktlen'] = base_pkt_params['pktlen'] + 4
656 mod_fields.append('pktlen')
657 mod_fields.append('dl_vlan_enable')
658 if 'dl_vlan' not in mod_fields:
659 mod_fields.append('dl_vlan')
660 elif strip_vlan:
661 base_pkt_params['dl_vlan_enable'] = True
662 mod_pkt_params['dl_vlan_enable'] = False
663 mod_pkt_params['pktlen'] = base_pkt_params['pktlen'] - 4
664 mod_fields.append('dl_vlan_enable')
665 mod_fields.append('pktlen')
666
667 # Build the ingress packet
668 ingress_pkt = simple_tcp_packet(**base_pkt_params)
669
670 # Build the expected packet, modifying the indicated fields
671 for item in mod_fields:
672 base_pkt_params[item] = mod_pkt_params[item]
673 act = action_generate(parent, item, mod_pkt_params)
674 if act:
675 new_actions.append(act)
676
677 expected_pkt = simple_tcp_packet(**base_pkt_params)
678
679 return (ingress_pkt, expected_pkt, new_actions)
680
Dan Talaycoba3745c2010-07-21 21:51:08 -0700681
682def skip_message_emit(parent, s):
683 """
684 Print out a 'skipped' message to stderr
685
686 @param s The string to print out to the log file
687 @param parent Must implement config and logger objects
688 """
689 global skipped_test_count
690
691 skipped_test_count += 1
692 parent.logger.info("Skipping: " + s)
693 if parent.config["dbg_level"] < logging.WARNING:
694 sys.stderr.write("(skipped) ")
695 else:
696 sys.stderr.write("(S)")