blob: 4bc1de7100ea134f83d75ac1c62f68f4698e6328 [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))
Tatsuya Yabe6a6f38a2010-05-22 23:48:04 -0700578
579class SimpleExactMatch(basic.SimpleDataPlane):
580 """
581 Exercise exact matching for all ports
582
583 Generate a packet
584 Generate and install a matching flow without wildcard mask
585 Add action to forward to a port
586 Send the packet to the port
587 Verify the packet is received at all other ports (one port at a time)
Tatsuya Yabe0718ad32010-05-24 15:22:10 -0700588 Verify flow_expiration message is correct when command option is set
Tatsuya Yabe6a6f38a2010-05-22 23:48:04 -0700589 """
Tatsuya Yabe0718ad32010-05-24 15:22:10 -0700590 IP_ETHTYPE = 0x800
591 TCP_PROTOCOL = 0x6
592 UDP_PROTOCOL = 0x11
593
Tatsuya Yabe6a6f38a2010-05-22 23:48:04 -0700594 def runTest(self):
595 self.flowMatchTest()
596
Tatsuya Yabe0718ad32010-05-24 15:22:10 -0700597 def flowMatchTest(self, wildcards=0, check_expire=False):
Tatsuya Yabe6a6f38a2010-05-22 23:48:04 -0700598 global pa_port_map
599 of_ports = pa_port_map.keys()
600 of_ports.sort()
601 self.assertTrue(len(of_ports) > 1, "Not enough ports for test")
602
603 pkt = simple_tcp_packet()
604 match = parse.packet_to_flow_match(pkt)
605 self.assertTrue(match is not None,
606 "Could not generate flow match from pkt")
Tatsuya Yabe0718ad32010-05-24 15:22:10 -0700607 match.dl_vlan = ofp.OFP_VLAN_NONE
608 match.nw_proto = self.TCP_PROTOCOL
Tatsuya Yabe6a6f38a2010-05-22 23:48:04 -0700609 match.wildcards = wildcards
610
Tatsuya Yabe6a6f38a2010-05-22 23:48:04 -0700611 for idx in range(len(of_ports)):
Tatsuya Yabe6a6f38a2010-05-22 23:48:04 -0700612 ingress_port = of_ports[idx]
613 pa_logger.info("Ingress " + str(ingress_port) + " to all the other ports")
Tatsuya Yabe6a6f38a2010-05-22 23:48:04 -0700614 match.in_port = ingress_port
615
Tatsuya Yabe6a6f38a2010-05-22 23:48:04 -0700616 for egr_idx in range(len(of_ports)):
617 if egr_idx == idx:
618 continue
Tatsuya Yabecdf575e2010-05-25 16:56:38 -0700619
620 rc = delete_all_flows(self.controller, pa_logger)
621 self.assertEqual(rc, 0, "Failed to delete all flows")
622 do_barrier(self.controller)
623
624 request = message.flow_mod()
625 request.match = match
626 request.buffer_id = 0xffffffff
627 #@todo Need UI to setup FLAGS parameter for flow_mod
628 if(check_expire):
629 request.flags |= ofp.OFPFF_SEND_FLOW_REM
630 request.hard_timeout = 1
631
632 act = action.action_output()
Tatsuya Yabe6a6f38a2010-05-22 23:48:04 -0700633 act.port = of_ports[egr_idx]
634 self.assertTrue(request.actions.add(act),
635 "Could not add output action")
636 pa_logger.info(request.show())
637
638 pa_logger.info("Inserting flow")
639 rv = self.controller.message_send(request)
640 self.assertTrue(rv != -1, "Error installing flow mod")
641 do_barrier(self.controller)
642
643 pa_logger.info("Sending packet to dp port " +str(ingress_port))
644 self.dataplane.send(ingress_port, str(pkt))
645
646 ofport = of_ports[egr_idx]
Tatsuya Yabecdf575e2010-05-25 16:56:38 -0700647 self.verifPkt(ofport, pkt)
Tatsuya Yabe6a6f38a2010-05-22 23:48:04 -0700648
Tatsuya Yabe0718ad32010-05-24 15:22:10 -0700649 #@todo Need UI for enabling response-verification
650 if(check_expire):
Tatsuya Yabecdf575e2010-05-25 16:56:38 -0700651 self.verifFlowRemoved(request)
Tatsuya Yabe6a6f38a2010-05-22 23:48:04 -0700652
Tatsuya Yabecdf575e2010-05-25 16:56:38 -0700653 def verifPkt(self, ofport, exp_pkt):
654 (rcv_port, rcv_pkt, pkt_time) = self.dataplane.poll(
655 port_number=ofport, timeout=1)
656 self.assertTrue(rcv_pkt is not None,
657 "Did not receive packet port " + str(ofport))
658 pa_logger.debug("Packet len " + str(len(rcv_pkt)) + " in on "
659 + str(rcv_port))
Tatsuya Yabe6a6f38a2010-05-22 23:48:04 -0700660
Tatsuya Yabecdf575e2010-05-25 16:56:38 -0700661 self.assertEqual(str(exp_pkt), str(rcv_pkt),
662 'Response packet does not match send packet ' +
663 "on port " + str(ofport))
664
665 def verifFlowRemoved(self, request):
666 (response, raw) = self.controller.poll(ofp.OFPT_FLOW_REMOVED, 2)
667 self.assertTrue(response is not None,
668 'Flow removed message not received')
669
670 req_match = request.match
671 res_match = response.match
672 if(req_match != res_match):
673 self.verifMatchField(req_match, res_match)
674
675 self.assertEqual(request.cookie, response.cookie,
676 self.matchErrStr('cookie'))
677 if (req_match.wildcards != 0):
678 self.assertEqual(request.priority, response.priority,
679 self.matchErrStr('priority'))
680 self.assertEqual(response.reason, ofp.OFPRR_HARD_TIMEOUT,
681 'Reason is not HARD TIMEOUT')
682 self.assertEqual(response.packet_count, 1,
683 'Packet count is not correct')
684 self.assertEqual(response.byte_count, len(pkt),
685 'Packet length is not correct')
Tatsuya Yabe6a6f38a2010-05-22 23:48:04 -0700686
687 def verifMatchField(self, req_match, res_match):
688 self.assertEqual(str(req_match.wildcards), str(res_match.wildcards),
689 self.matchErrStr('wildcards'))
690 self.assertEqual(str(req_match.in_port), str(res_match.in_port),
691 self.matchErrStr('in_port'))
692 self.assertEqual(str(req_match.dl_src), str(res_match.dl_src),
693 self.matchErrStr('dl_src'))
694 self.assertEqual(str(req_match.dl_dst), str(res_match.dl_dst),
695 self.matchErrStr('dl_dst'))
696 self.assertEqual(str(req_match.dl_vlan), str(res_match.dl_vlan),
697 self.matchErrStr('dl_vlan'))
698 self.assertEqual(str(req_match.dl_vlan_pcp), str(res_match.dl_vlan_pcp),
699 self.matchErrStr('dl_vlan_pcp'))
700 self.assertEqual(str(req_match.dl_type), str(res_match.dl_type),
701 self.matchErrStr('dl_type'))
Tatsuya Yabe0718ad32010-05-24 15:22:10 -0700702 if(not(req_match.wildcards & ofp.OFPFW_DL_TYPE)
703 and (req_match.dl_type == self.IP_ETHERTYPE)):
704 self.assertEqual(str(req_match.nw_tos), str(res_match.nw_tos),
705 self.matchErrStr('nw_tos'))
706 self.assertEqual(str(req_match.nw_proto), str(res_match.nw_proto),
707 self.matchErrStr('nw_proto'))
708 self.assertEqual(str(req_match.nw_src), str(res_match.nw_src),
709 self.matchErrStr('nw_src'))
710 self.assertEqual(str(req_match.nw_dst), str(res_match.nw_dst),
711 self.matchErrStr('nw_dst'))
712 if(not(req_match.wildcards & ofp.OFPFW_NW_PROTO)
713 and ((req_match.nw_proto == self.TCP_PROTOCOL)
714 or (req_match.nw_proto == self.UDP_PROTOCOL))):
715 self.assertEqual(str(req_match.tp_src), str(res_match.tp_src),
716 self.matchErrStr('tp_src'))
717 self.assertEqual(str(req_match.tp_dst), str(res_match.tp_dst),
718 self.matchErrStr('tp_dst'))
Tatsuya Yabe6a6f38a2010-05-22 23:48:04 -0700719
720 def matchErrStr(self, field):
721 return ('Response Match_' + field + ' does not match send message')
722
723class SingleWildcardMatch(SimpleExactMatch):
724 """
725 Exercise wildcard matching for all ports
726
727 Generate a packet
728 Generate and install a matching flow with wildcard mask
729 Add action to forward to a port
730 Send the packet to the port
731 Verify the packet is received at all other ports (one port at a time)
Tatsuya Yabe0718ad32010-05-24 15:22:10 -0700732 Verify flow_expiration message is correct when command option is set
Tatsuya Yabe6a6f38a2010-05-22 23:48:04 -0700733 """
Tatsuya Yabe0718ad32010-05-24 15:22:10 -0700734 def __init__(self):
735 SimpleExactMatch.__init__(self)
736 self.wildcards = [ofp.OFPFW_IN_PORT,
737 ofp.OFPFW_DL_VLAN,
738 ofp.OFPFW_DL_SRC,
739 ofp.OFPFW_DL_DST,
740 ofp.OFPFW_DL_TYPE,
741 ofp.OFPFW_NW_PROTO,
742 ofp.OFPFW_TP_SRC,
743 ofp.OFPFW_TP_DST,
744 0x3F << ofp.OFPFW_NW_SRC_SHIFT,
745 0x3F << ofp.OFPFW_NW_DST_SHIFT,
746 ofp.OFPFW_DL_VLAN_PCP,
747 ofp.OFPFW_NW_TOS]
Tatsuya Yabe6a6f38a2010-05-22 23:48:04 -0700748
Tatsuya Yabe0718ad32010-05-24 15:22:10 -0700749 def runTest(self):
750 for exec_wildcard in range(len(self.wildcards)):
Tatsuya Yabe6a6f38a2010-05-22 23:48:04 -0700751 self.flowMatchTest(exec_wildcard)
Tatsuya Yabe4fad7e32010-05-24 15:24:50 -0700752
753class AllExceptOneWildcardMatch(SingleWildcardMatch):
754 """
755 Create All-execpt-one-field wildcard and exercise for all ports
756
757 Generate a packet
758 Generate and install a matching flow with wildcard all except one filed
759 Add action to forward to a port
760 Send the packet to the port
761 Verify the packet is received at all other ports (one port at a time)
762 Verify flow_expiration message is correct when command option is set
763 """
764 def runTest(self):
765 for exec_wildcard in range(len(self.wildcards)):
766 all_exp_one_wildcard = ofp.OFPFW_ALL ^ self.wildcards[exec_wildcard]
767 self.flowMatchTest(all_exp_one_wildcard)
Tatsuya Yabee30ebe22010-05-25 09:30:49 -0700768
769class AllWildcardMatch(SingleWildcardMatch):
770 """
771 Create Wildcard-all flow and exercise for all ports
772
773 Generate a packet
774 Generate and install a matching flow with wildcard-all
775 Add action to forward to a port
776 Send the packet to the port
777 Verify the packet is received at all other ports (one port at a time)
778 Verify flow_expiration message is correct when command option is set
779 """
780 def runTest(self):
781 self.flowMatchTest(ofp.OFPFW_ALL)
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -0700782
783class ExactModifyAction(SimpleExactMatch):
784 """
785 Perform Modify action with exact matching for all ports
786
787 Generate a packet for transmit
788 Generate the expected packet
789 Generate and install a matching flow with a modify action and
790 an output action without wildcard mask
791 Send the packet to the port
792 Verify the expected packet is received at all other ports
793 (one port at a time)
794 Verify flow_expiration message is correct when command option is set
795 """
796 def __init__(self):
797 SimpleExactMatch.__init__(self)
798 self.modify_act = [ofp.OFPAT_SET_VLAN_VID,
799 ofp.OFPAT_SET_VLAN_PCP,
800 ofp.OFPAT_STRIP_VLAN,
801 ofp.OFPAT_SET_DL_SRC,
802 ofp.OFPAT_SET_DL_DST,
803 ofp.OFPAT_SET_NW_SRC,
804 ofp.OFPAT_SET_NW_DST,
805 ofp.OFPAT_SET_NW_TOS,
806 ofp.OFPAT_SET_TP_SRC,
807 ofp.OFPAT_SET_TP_DST]
808
809 def runTest(self):
810 self.flowMatchModTest()
811
812 def flowMatchModTest(self, wildcards=0, check_expire=False):
813 global pa_port_map
814 of_ports = pa_port_map.keys()
815 of_ports.sort()
816 self.assertTrue(len(of_ports) > 1, "Not enough ports for test")
817
818 mod_dl_dst = '43:21:0F:ED:CB:A9'
819 mod_dl_src = '7F:ED:CB:A9:87:65'
820 mod_dl_vlan = 4094
821 mod_dl_vlan_pcp = 7
822 mod_ip_src = '10.20.30.40'
823 mod_ip_dst = '50.60.70.80'
824 mod_ip_tos = 0xf0
825 mod_tcp_sport = 4321
826 mod_tcp_dport = 8765
827
Tatsuya Yabef5ffb972010-05-26 15:36:33 -0700828 request = message.features_request()
829 (reply, pkt) = self.controller.transact(request, timeout=2)
830 self.assertTrue(reply is not None, "Did not get response to ftr req")
831 supported_act = reply.actions
832
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -0700833 for idx in range(len(of_ports)):
834 ingress_port = of_ports[idx]
835 pa_logger.info("Ingress " + str(ingress_port) + " to all the other ports")
836
837 for egr_idx in range(len(of_ports)):
838 if egr_idx == idx:
839 continue
840
841 for exec_mod in range(len(self.modify_act)):
842 pkt_len = 100
843 dl_dst = '0C:DE:F0:12:34:56'
844 dl_src = '01:23:45:67:89:AB'
845 dl_vlan_enable = False
846 dl_vlan = 0
847 dl_vlan_pcp = 0
848 ip_src = '192.168.0.1'
849 ip_dst = '192.168.0.2'
850 ip_tos = 0
851 tcp_sport = 1234
852 tcp_dport = 80
853
854 rc = delete_all_flows(self.controller, pa_logger)
855 self.assertEqual(rc, 0, "Failed to delete all flows")
856 do_barrier(self.controller)
857
858 pkt = simple_tcp_packet(pktlen=pkt_len,
859 dl_dst=dl_dst,
860 dl_src=dl_src,
861 dl_vlan_enable=dl_vlan_enable,
862 dl_vlan=dl_vlan,
863 dl_vlan_pcp=dl_vlan_pcp,
864 ip_src=ip_src,
865 ip_dst=ip_dst,
866 ip_tos=ip_tos,
867 tcp_sport=tcp_sport,
868 tcp_dport=tcp_dport)
869
870 match = parse.packet_to_flow_match(pkt)
871 self.assertTrue(match is not None,
872 "Could not generate flow match from pkt")
873 match.in_port = ingress_port
874 match.dl_vlan = ofp.OFP_VLAN_NONE
875 match.nw_proto = self.TCP_PROTOCOL
876 match.wildcards = wildcards
877
878 request = message.flow_mod()
879 request.match = match
880 request.buffer_id = 0xffffffff
881 #@todo Need UI to setup FLAGS parameter for flow_mod
882 if(check_expire):
883 request.flags |= ofp.OFPFF_SEND_FLOW_REM
884 request.hard_timeout = 1
885
886 exec_act = self.modify_act[exec_mod]
887 if exec_act == ofp.OFPAT_SET_VLAN_VID:
Tatsuya Yabef5ffb972010-05-26 15:36:33 -0700888 if not(supported_act & 1<<ofp.OFPAT_SET_VLAN_VID):
889 continue
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -0700890 pkt_len = pkt_len + 4
891 dl_vlan_enable = True
892 dl_vlan = mod_dl_vlan
893 mod_act = action.action_set_vlan_vid()
894 mod_act.vlan_vid = mod_dl_vlan
Tatsuya Yabe17195a02010-05-26 15:29:55 -0700895 elif exec_act == ofp.OFPAT_SET_VLAN_PCP:
Tatsuya Yabef5ffb972010-05-26 15:36:33 -0700896 if not(supported_act & 1<<ofp.OFPAT_SET_VLAN_PCP):
897 continue
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -0700898 pkt_len = pkt_len + 4
899 dl_vlan_enable = True
900 dl_vlan_pcp = mod_dl_vlan_pcp
901 mod_act = action.action_set_vlan_pcp()
902 mod_act.vlan_pcp = mod_dl_vlan_pcp
Tatsuya Yabe17195a02010-05-26 15:29:55 -0700903 elif exec_act == ofp.OFPAT_STRIP_VLAN:
Tatsuya Yabef5ffb972010-05-26 15:36:33 -0700904 if not(supported_act & 1<<ofp.OFPAT_STRIP_VLAN):
905 continue
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -0700906 dl_vlan_enable = False
907 mod_act = action.action_strip_vlan()
Tatsuya Yabe17195a02010-05-26 15:29:55 -0700908 elif exec_act == ofp.OFPAT_SET_DL_SRC:
Tatsuya Yabef5ffb972010-05-26 15:36:33 -0700909 if not(supported_act & 1<<ofp.OFPAT_SET_DL_SRC):
910 continue
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -0700911 dl_src = mod_dl_src
912 mod_act = action.action_set_dl_src()
913 mod_act.dl_addr = parse.parse_mac(mod_dl_src)
Tatsuya Yabe17195a02010-05-26 15:29:55 -0700914 elif exec_act == ofp.OFPAT_SET_DL_DST:
Tatsuya Yabef5ffb972010-05-26 15:36:33 -0700915 if not(supported_act & 1<<ofp.OFPAT_SET_DL_DST):
916 continue
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -0700917 dl_dst = mod_dl_dst
918 mod_act = action.action_set_dl_dst()
919 mod_act.dl_addr = parse.parse_mac(mod_dl_dst)
Tatsuya Yabe17195a02010-05-26 15:29:55 -0700920 elif exec_act == ofp.OFPAT_SET_NW_SRC:
Tatsuya Yabef5ffb972010-05-26 15:36:33 -0700921 if not(supported_act & 1<<ofp.OFPAT_SET_NW_SRC):
922 continue
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -0700923 ip_src = mod_ip_src
924 mod_act = action.action_set_nw_src()
925 mod_act.nw_addr = parse.parse_ip(mod_ip_src)
Tatsuya Yabe17195a02010-05-26 15:29:55 -0700926 elif exec_act == ofp.OFPAT_SET_NW_DST:
Tatsuya Yabef5ffb972010-05-26 15:36:33 -0700927 if not(supported_act & 1<<ofp.OFPAT_SET_NW_DST):
928 continue
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -0700929 ip_dst = mod_ip_dst
930 mod_act = action.action_set_nw_dst()
931 mod_act.nw_addr = parse.parse_ip(mod_ip_dst)
Tatsuya Yabe17195a02010-05-26 15:29:55 -0700932 elif exec_act == ofp.OFPAT_SET_NW_TOS:
Tatsuya Yabef5ffb972010-05-26 15:36:33 -0700933 if not(supported_act & 1<<ofp.OFPAT_SET_NW_TOS):
934 continue
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -0700935 ip_tos = mod_ip_tos
936 mod_act = action.action_set_nw_tos()
937 mod_act.nw_tos = mod_ip_tos
Tatsuya Yabe17195a02010-05-26 15:29:55 -0700938 elif exec_act == ofp.OFPAT_SET_TP_SRC:
Tatsuya Yabef5ffb972010-05-26 15:36:33 -0700939 if not(supported_act & 1<<ofp.OFPAT_SET_TP_SRC):
940 continue
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -0700941 tcp_sport = mod_tcp_sport
942 mod_act = action.action_set_tp_src()
943 mod_act.tp_port = mod_tcp_sport
Tatsuya Yabe17195a02010-05-26 15:29:55 -0700944 elif exec_act == ofp.OFPAT_SET_TP_DST:
Tatsuya Yabef5ffb972010-05-26 15:36:33 -0700945 if not(supported_act & 1<<ofp.OFPAT_SET_TP_DST):
946 continue
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -0700947 tcp_dport = mod_tcp_dport
948 mod_act = action.action_set_tp_dst()
949 mod_act.tp_port = mod_tcp_dport
Tatsuya Yabe17195a02010-05-26 15:29:55 -0700950 else:
951 continue
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -0700952
953 self.assertTrue(request.actions.add(mod_act),
954 "Could not add output action")
955 pa_logger.info(request.show())
956
957 exp_pkt = simple_tcp_packet(pktlen=pkt_len,
958 dl_dst=dl_dst,
959 dl_src=dl_src,
960 dl_vlan_enable=dl_vlan_enable,
961 dl_vlan=dl_vlan,
962 dl_vlan_pcp=dl_vlan_pcp,
963 ip_src=ip_src,
964 ip_dst=ip_dst,
965 ip_tos=ip_tos,
966 tcp_sport=tcp_sport,
967 tcp_dport=tcp_dport)
968
969 act = action.action_output()
970 act.port = of_ports[egr_idx]
971 self.assertTrue(request.actions.add(act),
972 "Could not add output action")
973 pa_logger.info(request.show())
974
975 pa_logger.info("Inserting flow")
976 rv = self.controller.message_send(request)
977 self.assertTrue(rv != -1, "Error installing flow mod")
978 do_barrier(self.controller)
979
980 pa_logger.info("Sending packet to dp port " +str(ingress_port))
981 self.dataplane.send(ingress_port, str(pkt))
982
983 ofport = of_ports[egr_idx]
984 self.verifPkt(ofport, exp_pkt)
985
986 #@todo Need UI for enabling response-verification
987 if(check_expire):
988 self.verifFlowRemoved(request)