blob: 1bedd29938d7a901ea1691673d7421f1aaaed7b9 [file] [log] [blame]
Dan Talayco5eba8442010-03-10 13:58:43 -08001"""
2Test cases for testing actions taken on packets
3
4See basic.py for other info.
5
6It is recommended that these definitions be kept in their own
7namespace as different groups of tests will likely define
8similar identifiers.
9
10 The function test_set_init is called with a complete configuration
11dictionary prior to the invocation of any tests from this file.
12
13 The switch is actively attempting to contact the controller at the address
14indicated oin oft_config
15
16"""
17
18import logging
19
20import unittest
21
22import oftest.controller as controller
23import oftest.cstruct as ofp
24import oftest.message as message
25import oftest.dataplane as dataplane
26import oftest.action as action
27import oftest.parse as parse
28import basic
29
30from testutils import *
31
32#@var port_map Local copy of the configuration map from OF port
33# numbers to OS interfaces
34pa_port_map = None
35#@var pa_logger Local logger object
36pa_logger = None
37#@var pa_config Local copy of global configuration data
38pa_config = None
39
40def test_set_init(config):
41 """
42 Set up function for packet action test classes
43
44 @param config The configuration dictionary; see oft
45 """
46
47 global pa_port_map
48 global pa_logger
49 global pa_config
50
51 pa_logger = logging.getLogger("pkt_act")
52 pa_logger.info("Initializing test set")
53 pa_port_map = config["port_map"]
54 pa_config = config
55
56class DirectPacket(basic.SimpleDataPlane):
57 """
Dan Talayco2d0d49a2010-05-11 15:29:08 -070058 Send packet to single egress port
Dan Talayco5eba8442010-03-10 13:58:43 -080059
60 Generate a packet
61 Generate and install a matching flow
62 Add action to direct the packet to an egress port
63 Send the packet to ingress dataplane port
64 Verify the packet is received at the egress port only
65 """
66 def runTest(self):
67 global pa_port_map
68 of_ports = pa_port_map.keys()
69 of_ports.sort()
70 self.assertTrue(len(of_ports) > 1, "Not enough ports for test")
71
Dan Talayco5eba8442010-03-10 13:58:43 -080072 pkt = simple_tcp_packet()
73 match = parse.packet_to_flow_match(pkt)
Dan Talayco7dd6cd62010-03-16 15:02:35 -070074 match.wildcards &= ~ofp.OFPFW_IN_PORT
Dan Talayco5eba8442010-03-10 13:58:43 -080075 self.assertTrue(match is not None,
76 "Could not generate flow match from pkt")
77 act = action.action_output()
78
79 for idx in range(len(of_ports)):
Dan Talayco2e77a842010-05-12 15:39:46 -070080 rc = delete_all_flows(self.controller, pa_logger)
81 self.assertEqual(rc, 0, "Failed to delete all flows")
82
Dan Talayco5eba8442010-03-10 13:58:43 -080083 ingress_port = of_ports[idx]
84 egress_port = of_ports[(idx + 1) % len(of_ports)]
85 pa_logger.info("Ingress " + str(ingress_port) +
86 " to egress " + str(egress_port))
87
88 match.in_port = ingress_port
89
90 request = message.flow_mod()
91 request.match = match
92 request.buffer_id = 0xffffffff
93 act.port = egress_port
94 self.assertTrue(request.actions.add(act), "Could not add action")
95
96 pa_logger.info("Inserting flow")
97 rv = self.controller.message_send(request)
98 self.assertTrue(rv != -1, "Error installing flow mod")
99 do_barrier(self.controller)
100
101 pa_logger.info("Sending packet to dp port " +
102 str(ingress_port))
103 self.dataplane.send(ingress_port, str(pkt))
104 (rcv_port, rcv_pkt, pkt_time) = self.dataplane.poll(timeout=1)
105 self.assertTrue(rcv_pkt is not None, "Did not receive packet")
Dan Talayco2d0d49a2010-05-11 15:29:08 -0700106 pa_logger.debug("Packet len " + str(len(rcv_pkt)) + " in on " +
Dan Talayco5eba8442010-03-10 13:58:43 -0800107 str(rcv_port))
108 self.assertEqual(rcv_port, egress_port, "Unexpected receive port")
109 self.assertEqual(str(pkt), str(rcv_pkt),
110 'Response packet does not match send packet')
111
112
Dan Talayco2d0d49a2010-05-11 15:29:08 -0700113
114class DirectTwoPorts(basic.SimpleDataPlane):
115 """
116 Send packet to two egress ports
117
118 Generate a packet
119 Generate and install a matching flow
120 Add action to direct the packet to two egress ports
121 Send the packet to ingress dataplane port
122 Verify the packet is received at the two egress ports
123 """
124 def runTest(self):
125 global pa_port_map
126 of_ports = pa_port_map.keys()
127 of_ports.sort()
128 self.assertTrue(len(of_ports) > 2, "Not enough ports for test")
129
Dan Talayco2d0d49a2010-05-11 15:29:08 -0700130 pkt = simple_tcp_packet()
131 match = parse.packet_to_flow_match(pkt)
132 match.wildcards &= ~ofp.OFPFW_IN_PORT
133 self.assertTrue(match is not None,
134 "Could not generate flow match from pkt")
135 act = action.action_output()
136
137 for idx in range(len(of_ports)):
Dan Talayco2e77a842010-05-12 15:39:46 -0700138 rc = delete_all_flows(self.controller, pa_logger)
139 self.assertEqual(rc, 0, "Failed to delete all flows")
140
Dan Talayco2d0d49a2010-05-11 15:29:08 -0700141 ingress_port = of_ports[idx]
142 egress_port1 = of_ports[(idx + 1) % len(of_ports)]
143 egress_port2 = of_ports[(idx + 2) % len(of_ports)]
144 pa_logger.info("Ingress " + str(ingress_port) +
145 " to egress " + str(egress_port1) + " and " +
146 str(egress_port2))
147
148 match.in_port = ingress_port
149
150 request = message.flow_mod()
151 request.match = match
152 request.buffer_id = 0xffffffff
153 act.port = egress_port1
154 self.assertTrue(request.actions.add(act), "Could not add action1")
155 act.port = egress_port2
156 self.assertTrue(request.actions.add(act), "Could not add action2")
Dan Talaycob0b0fdb2010-05-11 15:44:56 -0700157 # pa_logger.info(request.show())
Dan Talayco2d0d49a2010-05-11 15:29:08 -0700158
159 pa_logger.info("Inserting flow")
160 rv = self.controller.message_send(request)
161 self.assertTrue(rv != -1, "Error installing flow mod")
162 do_barrier(self.controller)
163
164 pa_logger.info("Sending packet to dp port " +
165 str(ingress_port))
166 self.dataplane.send(ingress_port, str(pkt))
167 (rcv_port1, rcv_pkt1, pkt_time1) = self.dataplane.poll(timeout=1)
168 (rcv_port2, rcv_pkt2, pkt_time2) = self.dataplane.poll(timeout=1)
169 self.assertTrue(rcv_pkt1 is not None, "Did not receive packet 1")
170 self.assertTrue(rcv_pkt2 is not None, "Did not receive packet 2")
171 pa_logger.debug("Packet len " + str(len(rcv_pkt1)) + " in on " +
172 str(rcv_port1))
173 pa_logger.debug("Packet len " + str(len(rcv_pkt2)) + " in on " +
174 str(rcv_port2))
175
176 # Check if ports swapped
177 if (rcv_port1 == egress_port2 and rcv_port2 == egress_port1):
178 (rcv_port2, rcv_port1) = (rcv_port1, rcv_port2)
179 (rcv_pkt2, rcv_pkt1) = (rcv_pkt1, rcv_pkt2)
180 self.assertEqual(rcv_port1, egress_port1,
181 "Unexpected receive port 1")
182 self.assertEqual(rcv_port2, egress_port2,
183 "Unexpected receive port 2")
184 self.assertEqual(str(pkt), str(rcv_pkt1),
185 'Response packet does not match send packet 1')
186 self.assertEqual(str(pkt), str(rcv_pkt2),
187 'Response packet does not match send packet 2')
Dan Talaycob0b0fdb2010-05-11 15:44:56 -0700188
189class DirectMCNonIngress(basic.SimpleDataPlane):
190 """
191 Multicast to all non-ingress ports
192
193 Generate a packet
194 Generate and install a matching flow
195 Add action to direct the packet to all non-ingress ports
196 Send the packet to ingress dataplane port
197 Verify the packet is received at all non-ingress ports
198
199 Does not use the flood action
200 """
201 def runTest(self):
202 global pa_port_map
203 of_ports = pa_port_map.keys()
204 of_ports.sort()
205 self.assertTrue(len(of_ports) > 2, "Not enough ports for test")
206
Dan Talaycob0b0fdb2010-05-11 15:44:56 -0700207 pkt = simple_tcp_packet()
208 match = parse.packet_to_flow_match(pkt)
209 match.wildcards &= ~ofp.OFPFW_IN_PORT
210 self.assertTrue(match is not None,
211 "Could not generate flow match from pkt")
212 act = action.action_output()
213
214 for idx in range(len(of_ports)):
Dan Talayco2e77a842010-05-12 15:39:46 -0700215 rc = delete_all_flows(self.controller, pa_logger)
216 self.assertEqual(rc, 0, "Failed to delete all flows")
217
Dan Talaycob0b0fdb2010-05-11 15:44:56 -0700218 ingress_port = of_ports[idx]
219 pa_logger.info("Ingress " + str(ingress_port) +
220 " all non-ingress ports")
221
222 match.in_port = ingress_port
223
224 request = message.flow_mod()
225 request.match = match
226 request.buffer_id = 0xffffffff
227 for egr_idx in range(len(of_ports)):
228 if egr_idx == idx:
229 continue
230 egress_port = of_ports[egr_idx]
231 act.port = egress_port
232 self.assertTrue(request.actions.add(act),
233 "Could not add output to " + str(egress_port))
234 pa_logger.info(request.show())
235
236 pa_logger.info("Inserting flow")
237 rv = self.controller.message_send(request)
238 self.assertTrue(rv != -1, "Error installing flow mod")
239 do_barrier(self.controller)
240
241 pa_logger.info("Sending packet to dp port " +
242 str(ingress_port))
243 self.dataplane.send(ingress_port, str(pkt))
244 for egr_idx in range(len(of_ports)):
245 if egr_idx == idx:
246 continue
247 ofport = of_ports[egr_idx]
248 (rcv_port, rcv_pkt, pkt_time) = self.dataplane.poll(
249 port_number=ofport, timeout=1)
250 self.assertTrue(rcv_pkt is not None,
251 "Did not receive packet port " + str(ofport))
252 pa_logger.debug("Packet len " + str(len(rcv_pkt)) + " in on "
253 + str(rcv_port))
254
255 self.assertEqual(str(pkt), str(rcv_pkt),
256 'Response packet does not match send packet ' +
257 "on port " + str(ofport))
Dan Talayco32fa6542010-05-11 15:54:08 -0700258
259class DirectMC(basic.SimpleDataPlane):
260 """
261 Multicast to all ports including ingress
262
263 Generate a packet
264 Generate and install a matching flow
265 Add action to direct the packet to all non-ingress ports
266 Send the packet to ingress dataplane port
267 Verify the packet is received at all ports
268
269 Does not use the flood action
270 """
271 def runTest(self):
272 global pa_port_map
273 of_ports = pa_port_map.keys()
274 of_ports.sort()
275 self.assertTrue(len(of_ports) > 2, "Not enough ports for test")
276
Dan Talayco32fa6542010-05-11 15:54:08 -0700277 pkt = simple_tcp_packet()
278 match = parse.packet_to_flow_match(pkt)
279 match.wildcards &= ~ofp.OFPFW_IN_PORT
280 self.assertTrue(match is not None,
281 "Could not generate flow match from pkt")
282 act = action.action_output()
283
284 for idx in range(len(of_ports)):
Dan Talayco2e77a842010-05-12 15:39:46 -0700285 rc = delete_all_flows(self.controller, pa_logger)
286 self.assertEqual(rc, 0, "Failed to delete all flows")
287
Dan Talayco32fa6542010-05-11 15:54:08 -0700288 ingress_port = of_ports[idx]
289 pa_logger.info("Ingress " + str(ingress_port) + " to all ports")
290
291 match.in_port = ingress_port
292
293 request = message.flow_mod()
294 request.match = match
295 request.buffer_id = 0xffffffff
296 for egr_idx in range(len(of_ports)):
297 egress_port = of_ports[egr_idx]
298 if egr_idx == idx:
299 act.port = ofp.OFPP_IN_PORT
300 else:
301 act.port = egress_port
302 self.assertTrue(request.actions.add(act),
303 "Could not add output to " + str(egress_port))
Dan Talayco2e77a842010-05-12 15:39:46 -0700304 # pa_logger.info(request.show())
305
306 pa_logger.info("Inserting flow")
307 rv = self.controller.message_send(request)
308 self.assertTrue(rv != -1, "Error installing flow mod")
309 do_barrier(self.controller)
310
311 pa_logger.info("Sending packet to dp port " + str(ingress_port))
312 self.dataplane.send(ingress_port, str(pkt))
313 for egr_idx in range(len(of_ports)):
314 ofport = of_ports[egr_idx]
315 (rcv_port, rcv_pkt, pkt_time) = self.dataplane.poll(
316 port_number=ofport, timeout=1)
317 self.assertTrue(rcv_pkt is not None,
318 "Did not receive packet port " + str(ofport))
319 pa_logger.debug("Packet len " + str(len(rcv_pkt)) + " in on "
320 + str(rcv_port))
321
322 self.assertEqual(str(pkt), str(rcv_pkt),
323 'Response packet does not match send packet ' +
324 "on port " + str(ofport))
325
326class Flood(basic.SimpleDataPlane):
327 """
328 Flood to all ports except ingress
329
330 Generate a packet
331 Generate and install a matching flow
332 Add action to flood the packet
333 Send the packet to ingress dataplane port
334 Verify the packet is received at all other ports
335 """
336 def runTest(self):
337 global pa_port_map
338 of_ports = pa_port_map.keys()
339 of_ports.sort()
340 self.assertTrue(len(of_ports) > 1, "Not enough ports for test")
341
342 pkt = simple_tcp_packet()
343 match = parse.packet_to_flow_match(pkt)
344 match.wildcards &= ~ofp.OFPFW_IN_PORT
345 self.assertTrue(match is not None,
346 "Could not generate flow match from pkt")
347 act = action.action_output()
348
349 for idx in range(len(of_ports)):
350 rc = delete_all_flows(self.controller, pa_logger)
351 self.assertEqual(rc, 0, "Failed to delete all flows")
352
353 ingress_port = of_ports[idx]
354 pa_logger.info("Ingress " + str(ingress_port) + " to all ports")
355
356 match.in_port = ingress_port
357
358 request = message.flow_mod()
359 request.match = match
360 request.buffer_id = 0xffffffff
361 act.port = ofp.OFPP_FLOOD
362 self.assertTrue(request.actions.add(act),
Dan Talayco4aa13122010-05-12 15:54:44 -0700363 "Could not add flood port action")
Dan Talayco32fa6542010-05-11 15:54:08 -0700364 pa_logger.info(request.show())
365
366 pa_logger.info("Inserting flow")
367 rv = self.controller.message_send(request)
368 self.assertTrue(rv != -1, "Error installing flow mod")
369 do_barrier(self.controller)
370
371 pa_logger.info("Sending packet to dp port " + str(ingress_port))
372 self.dataplane.send(ingress_port, str(pkt))
373 for egr_idx in range(len(of_ports)):
Dan Talayco2e77a842010-05-12 15:39:46 -0700374 if egr_idx == idx:
375 continue
Dan Talayco32fa6542010-05-11 15:54:08 -0700376 ofport = of_ports[egr_idx]
377 (rcv_port, rcv_pkt, pkt_time) = self.dataplane.poll(
378 port_number=ofport, timeout=1)
379 self.assertTrue(rcv_pkt is not None,
380 "Did not receive packet port " + str(ofport))
381 pa_logger.debug("Packet len " + str(len(rcv_pkt)) + " in on "
382 + str(rcv_port))
383
384 self.assertEqual(str(pkt), str(rcv_pkt),
385 'Response packet does not match send packet ' +
386 "on port " + str(ofport))
Dan Talayco3be5b062010-05-12 15:46:21 -0700387
388
389class FloodPlusIngress(basic.SimpleDataPlane):
390 """
391 Flood to all ports plus send to ingress port
392
393 Generate a packet
394 Generate and install a matching flow
395 Add action to flood the packet
396 Add action to send to ingress port
397 Send the packet to ingress dataplane port
398 Verify the packet is received at all other ports
399 """
400 def runTest(self):
401 global pa_port_map
402 of_ports = pa_port_map.keys()
403 of_ports.sort()
404 self.assertTrue(len(of_ports) > 1, "Not enough ports for test")
405
406 pkt = simple_tcp_packet()
407 match = parse.packet_to_flow_match(pkt)
408 match.wildcards &= ~ofp.OFPFW_IN_PORT
409 self.assertTrue(match is not None,
410 "Could not generate flow match from pkt")
411 act = action.action_output()
412
413 for idx in range(len(of_ports)):
414 rc = delete_all_flows(self.controller, pa_logger)
415 self.assertEqual(rc, 0, "Failed to delete all flows")
416
417 ingress_port = of_ports[idx]
418 pa_logger.info("Ingress " + str(ingress_port) + " to all ports")
419
420 match.in_port = ingress_port
421
422 request = message.flow_mod()
423 request.match = match
424 request.buffer_id = 0xffffffff
425 act.port = ofp.OFPP_FLOOD
426 self.assertTrue(request.actions.add(act),
Dan Talayco4aa13122010-05-12 15:54:44 -0700427 "Could not add flood port action")
428 act.port = ofp.OFPP_IN_PORT
429 self.assertTrue(request.actions.add(act),
430 "Could not add ingress port for output")
431 pa_logger.info(request.show())
432
433 pa_logger.info("Inserting flow")
434 rv = self.controller.message_send(request)
435 self.assertTrue(rv != -1, "Error installing flow mod")
436 do_barrier(self.controller)
437
438 pa_logger.info("Sending packet to dp port " + str(ingress_port))
439 self.dataplane.send(ingress_port, str(pkt))
440 for egr_idx in range(len(of_ports)):
441 ofport = of_ports[egr_idx]
442 (rcv_port, rcv_pkt, pkt_time) = self.dataplane.poll(
443 port_number=ofport, timeout=1)
444 self.assertTrue(rcv_pkt is not None,
445 "Did not receive packet port " + str(ofport))
446 pa_logger.debug("Packet len " + str(len(rcv_pkt)) + " in on "
447 + str(rcv_port))
448
449 self.assertEqual(str(pkt), str(rcv_pkt),
450 'Response packet does not match send packet ' +
451 "on port " + str(ofport))
452
453class All(basic.SimpleDataPlane):
454 """
455 Send to OFPP_ALL port
456
457 Generate a packet
458 Generate and install a matching flow
459 Add action to forward to OFPP_ALL
460 Send the packet to ingress dataplane port
461 Verify the packet is received at all other ports
462 """
463 def runTest(self):
464 global pa_port_map
465 of_ports = pa_port_map.keys()
466 of_ports.sort()
467 self.assertTrue(len(of_ports) > 1, "Not enough ports for test")
468
469 pkt = simple_tcp_packet()
470 match = parse.packet_to_flow_match(pkt)
471 match.wildcards &= ~ofp.OFPFW_IN_PORT
472 self.assertTrue(match is not None,
473 "Could not generate flow match from pkt")
474 act = action.action_output()
475
476 for idx in range(len(of_ports)):
477 rc = delete_all_flows(self.controller, pa_logger)
478 self.assertEqual(rc, 0, "Failed to delete all flows")
479
480 ingress_port = of_ports[idx]
481 pa_logger.info("Ingress " + str(ingress_port) + " to all ports")
482
483 match.in_port = ingress_port
484
485 request = message.flow_mod()
486 request.match = match
487 request.buffer_id = 0xffffffff
488 act.port = ofp.OFPP_ALL
489 self.assertTrue(request.actions.add(act),
490 "Could not add ALL port action")
491 pa_logger.info(request.show())
492
493 pa_logger.info("Inserting flow")
494 rv = self.controller.message_send(request)
495 self.assertTrue(rv != -1, "Error installing flow mod")
496 do_barrier(self.controller)
497
498 pa_logger.info("Sending packet to dp port " + str(ingress_port))
499 self.dataplane.send(ingress_port, str(pkt))
500 for egr_idx in range(len(of_ports)):
501 if egr_idx == idx:
502 continue
503 ofport = of_ports[egr_idx]
504 (rcv_port, rcv_pkt, pkt_time) = self.dataplane.poll(
505 port_number=ofport, timeout=1)
506 self.assertTrue(rcv_pkt is not None,
507 "Did not receive packet port " + str(ofport))
508 pa_logger.debug("Packet len " + str(len(rcv_pkt)) + " in on "
509 + str(rcv_port))
510
511 self.assertEqual(str(pkt), str(rcv_pkt),
512 'Response packet does not match send packet ' +
513 "on port " + str(ofport))
514
515class AllPlusIngress(basic.SimpleDataPlane):
516 """
517 Send to OFPP_ALL port and ingress port
518
519 Generate a packet
520 Generate and install a matching flow
521 Add action to forward to OFPP_ALL
522 Add action to forward to ingress port
523 Send the packet to ingress dataplane port
524 Verify the packet is received at all other ports
525 """
526 def runTest(self):
527 global pa_port_map
528 of_ports = pa_port_map.keys()
529 of_ports.sort()
530 self.assertTrue(len(of_ports) > 1, "Not enough ports for test")
531
532 pkt = simple_tcp_packet()
533 match = parse.packet_to_flow_match(pkt)
534 match.wildcards &= ~ofp.OFPFW_IN_PORT
535 self.assertTrue(match is not None,
536 "Could not generate flow match from pkt")
537 act = action.action_output()
538
539 for idx in range(len(of_ports)):
540 rc = delete_all_flows(self.controller, pa_logger)
541 self.assertEqual(rc, 0, "Failed to delete all flows")
542
543 ingress_port = of_ports[idx]
544 pa_logger.info("Ingress " + str(ingress_port) + " to all ports")
545
546 match.in_port = ingress_port
547
548 request = message.flow_mod()
549 request.match = match
550 request.buffer_id = 0xffffffff
551 act.port = ofp.OFPP_ALL
552 self.assertTrue(request.actions.add(act),
553 "Could not add ALL port action")
Dan Talayco3be5b062010-05-12 15:46:21 -0700554 act.port = ofp.OFPP_IN_PORT
555 self.assertTrue(request.actions.add(act),
556 "Could not add ingress port for output")
557 pa_logger.info(request.show())
558
559 pa_logger.info("Inserting flow")
560 rv = self.controller.message_send(request)
561 self.assertTrue(rv != -1, "Error installing flow mod")
562 do_barrier(self.controller)
563
564 pa_logger.info("Sending packet to dp port " + str(ingress_port))
565 self.dataplane.send(ingress_port, str(pkt))
566 for egr_idx in range(len(of_ports)):
567 ofport = of_ports[egr_idx]
568 (rcv_port, rcv_pkt, pkt_time) = self.dataplane.poll(
569 port_number=ofport, timeout=1)
570 self.assertTrue(rcv_pkt is not None,
571 "Did not receive packet port " + str(ofport))
572 pa_logger.debug("Packet len " + str(len(rcv_pkt)) + " in on "
573 + str(rcv_port))
574
575 self.assertEqual(str(pkt), str(rcv_pkt),
576 'Response packet does not match send packet ' +
577 "on port " + str(ofport))