blob: dd8c509d3a45bceceff3e749b4fc4d93ba10ea21 [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):
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -070067 self.handleFlow()
68
69 def handleFlow(self, pkttype='TCP'):
70
Dan Talayco5eba8442010-03-10 13:58:43 -080071 global pa_port_map
72 of_ports = pa_port_map.keys()
73 of_ports.sort()
74 self.assertTrue(len(of_ports) > 1, "Not enough ports for test")
75
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -070076 if (pkttype == 'ICMP'):
77 pkt = simple_icmp_packet()
78 else:
79 pkt = simple_tcp_packet()
Dan Talayco5eba8442010-03-10 13:58:43 -080080 match = parse.packet_to_flow_match(pkt)
Dan Talayco7dd6cd62010-03-16 15:02:35 -070081 match.wildcards &= ~ofp.OFPFW_IN_PORT
Dan Talayco5eba8442010-03-10 13:58:43 -080082 self.assertTrue(match is not None,
83 "Could not generate flow match from pkt")
84 act = action.action_output()
85
86 for idx in range(len(of_ports)):
Dan Talayco2e77a842010-05-12 15:39:46 -070087 rc = delete_all_flows(self.controller, pa_logger)
88 self.assertEqual(rc, 0, "Failed to delete all flows")
89
Dan Talayco5eba8442010-03-10 13:58:43 -080090 ingress_port = of_ports[idx]
91 egress_port = of_ports[(idx + 1) % len(of_ports)]
92 pa_logger.info("Ingress " + str(ingress_port) +
93 " to egress " + str(egress_port))
94
95 match.in_port = ingress_port
96
97 request = message.flow_mod()
98 request.match = match
99 request.buffer_id = 0xffffffff
100 act.port = egress_port
101 self.assertTrue(request.actions.add(act), "Could not add action")
102
103 pa_logger.info("Inserting flow")
104 rv = self.controller.message_send(request)
105 self.assertTrue(rv != -1, "Error installing flow mod")
106 do_barrier(self.controller)
107
108 pa_logger.info("Sending packet to dp port " +
109 str(ingress_port))
110 self.dataplane.send(ingress_port, str(pkt))
111 (rcv_port, rcv_pkt, pkt_time) = self.dataplane.poll(timeout=1)
112 self.assertTrue(rcv_pkt is not None, "Did not receive packet")
Dan Talayco2d0d49a2010-05-11 15:29:08 -0700113 pa_logger.debug("Packet len " + str(len(rcv_pkt)) + " in on " +
Dan Talayco5eba8442010-03-10 13:58:43 -0800114 str(rcv_port))
115 self.assertEqual(rcv_port, egress_port, "Unexpected receive port")
116 self.assertEqual(str(pkt), str(rcv_pkt),
117 'Response packet does not match send packet')
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700118
119class DirectPacketICMP(DirectPacket):
120 """
121 Send ICMP packet to single egress port
122
123 Generate a ICMP packet
124 Generate and install a matching flow
125 Add action to direct the packet to an egress port
126 Send the packet to ingress dataplane port
127 Verify the packet is received at the egress port only
128 Difference from DirectPacket test is that sent packet is ICMP
129 """
130 def runTest(self):
131 self.handleFlow(pkttype='ICMP')
132
Dan Talayco2d0d49a2010-05-11 15:29:08 -0700133
134class DirectTwoPorts(basic.SimpleDataPlane):
135 """
136 Send packet to two egress ports
137
138 Generate a packet
139 Generate and install a matching flow
140 Add action to direct the packet to two egress ports
141 Send the packet to ingress dataplane port
142 Verify the packet is received at the two egress ports
143 """
144 def runTest(self):
145 global pa_port_map
146 of_ports = pa_port_map.keys()
147 of_ports.sort()
148 self.assertTrue(len(of_ports) > 2, "Not enough ports for test")
149
Dan Talayco2d0d49a2010-05-11 15:29:08 -0700150 pkt = simple_tcp_packet()
151 match = parse.packet_to_flow_match(pkt)
152 match.wildcards &= ~ofp.OFPFW_IN_PORT
153 self.assertTrue(match is not None,
154 "Could not generate flow match from pkt")
155 act = action.action_output()
156
157 for idx in range(len(of_ports)):
Dan Talayco2e77a842010-05-12 15:39:46 -0700158 rc = delete_all_flows(self.controller, pa_logger)
159 self.assertEqual(rc, 0, "Failed to delete all flows")
160
Dan Talayco2d0d49a2010-05-11 15:29:08 -0700161 ingress_port = of_ports[idx]
162 egress_port1 = of_ports[(idx + 1) % len(of_ports)]
163 egress_port2 = of_ports[(idx + 2) % len(of_ports)]
164 pa_logger.info("Ingress " + str(ingress_port) +
165 " to egress " + str(egress_port1) + " and " +
166 str(egress_port2))
167
168 match.in_port = ingress_port
169
170 request = message.flow_mod()
171 request.match = match
172 request.buffer_id = 0xffffffff
173 act.port = egress_port1
174 self.assertTrue(request.actions.add(act), "Could not add action1")
175 act.port = egress_port2
176 self.assertTrue(request.actions.add(act), "Could not add action2")
Dan Talaycob0b0fdb2010-05-11 15:44:56 -0700177 # pa_logger.info(request.show())
Dan Talayco2d0d49a2010-05-11 15:29:08 -0700178
179 pa_logger.info("Inserting flow")
180 rv = self.controller.message_send(request)
181 self.assertTrue(rv != -1, "Error installing flow mod")
182 do_barrier(self.controller)
183
184 pa_logger.info("Sending packet to dp port " +
185 str(ingress_port))
186 self.dataplane.send(ingress_port, str(pkt))
187 (rcv_port1, rcv_pkt1, pkt_time1) = self.dataplane.poll(timeout=1)
188 (rcv_port2, rcv_pkt2, pkt_time2) = self.dataplane.poll(timeout=1)
189 self.assertTrue(rcv_pkt1 is not None, "Did not receive packet 1")
190 self.assertTrue(rcv_pkt2 is not None, "Did not receive packet 2")
191 pa_logger.debug("Packet len " + str(len(rcv_pkt1)) + " in on " +
192 str(rcv_port1))
193 pa_logger.debug("Packet len " + str(len(rcv_pkt2)) + " in on " +
194 str(rcv_port2))
195
196 # Check if ports swapped
197 if (rcv_port1 == egress_port2 and rcv_port2 == egress_port1):
198 (rcv_port2, rcv_port1) = (rcv_port1, rcv_port2)
199 (rcv_pkt2, rcv_pkt1) = (rcv_pkt1, rcv_pkt2)
200 self.assertEqual(rcv_port1, egress_port1,
201 "Unexpected receive port 1")
202 self.assertEqual(rcv_port2, egress_port2,
203 "Unexpected receive port 2")
204 self.assertEqual(str(pkt), str(rcv_pkt1),
205 'Response packet does not match send packet 1')
206 self.assertEqual(str(pkt), str(rcv_pkt2),
207 'Response packet does not match send packet 2')
Dan Talaycob0b0fdb2010-05-11 15:44:56 -0700208
209class DirectMCNonIngress(basic.SimpleDataPlane):
210 """
211 Multicast to all non-ingress ports
212
213 Generate a packet
214 Generate and install a matching flow
215 Add action to direct the packet to all non-ingress ports
216 Send the packet to ingress dataplane port
217 Verify the packet is received at all non-ingress ports
218
219 Does not use the flood action
220 """
221 def runTest(self):
222 global pa_port_map
223 of_ports = pa_port_map.keys()
224 of_ports.sort()
225 self.assertTrue(len(of_ports) > 2, "Not enough ports for test")
226
Dan Talaycob0b0fdb2010-05-11 15:44:56 -0700227 pkt = simple_tcp_packet()
228 match = parse.packet_to_flow_match(pkt)
229 match.wildcards &= ~ofp.OFPFW_IN_PORT
230 self.assertTrue(match is not None,
231 "Could not generate flow match from pkt")
232 act = action.action_output()
233
234 for idx in range(len(of_ports)):
Dan Talayco2e77a842010-05-12 15:39:46 -0700235 rc = delete_all_flows(self.controller, pa_logger)
236 self.assertEqual(rc, 0, "Failed to delete all flows")
237
Dan Talaycob0b0fdb2010-05-11 15:44:56 -0700238 ingress_port = of_ports[idx]
239 pa_logger.info("Ingress " + str(ingress_port) +
240 " all non-ingress ports")
241
242 match.in_port = ingress_port
243
244 request = message.flow_mod()
245 request.match = match
246 request.buffer_id = 0xffffffff
247 for egr_idx in range(len(of_ports)):
248 if egr_idx == idx:
249 continue
250 egress_port = of_ports[egr_idx]
251 act.port = egress_port
252 self.assertTrue(request.actions.add(act),
253 "Could not add output to " + str(egress_port))
254 pa_logger.info(request.show())
255
256 pa_logger.info("Inserting flow")
257 rv = self.controller.message_send(request)
258 self.assertTrue(rv != -1, "Error installing flow mod")
259 do_barrier(self.controller)
260
261 pa_logger.info("Sending packet to dp port " +
262 str(ingress_port))
263 self.dataplane.send(ingress_port, str(pkt))
264 for egr_idx in range(len(of_ports)):
265 if egr_idx == idx:
266 continue
267 ofport = of_ports[egr_idx]
268 (rcv_port, rcv_pkt, pkt_time) = self.dataplane.poll(
269 port_number=ofport, timeout=1)
270 self.assertTrue(rcv_pkt is not None,
271 "Did not receive packet port " + str(ofport))
272 pa_logger.debug("Packet len " + str(len(rcv_pkt)) + " in on "
273 + str(rcv_port))
274
275 self.assertEqual(str(pkt), str(rcv_pkt),
276 'Response packet does not match send packet ' +
277 "on port " + str(ofport))
Dan Talayco32fa6542010-05-11 15:54:08 -0700278
279class DirectMC(basic.SimpleDataPlane):
280 """
281 Multicast to all ports including ingress
282
283 Generate a packet
284 Generate and install a matching flow
285 Add action to direct the packet to all non-ingress ports
286 Send the packet to ingress dataplane port
287 Verify the packet is received at all ports
288
289 Does not use the flood action
290 """
291 def runTest(self):
292 global pa_port_map
293 of_ports = pa_port_map.keys()
294 of_ports.sort()
295 self.assertTrue(len(of_ports) > 2, "Not enough ports for test")
296
Dan Talayco32fa6542010-05-11 15:54:08 -0700297 pkt = simple_tcp_packet()
298 match = parse.packet_to_flow_match(pkt)
299 match.wildcards &= ~ofp.OFPFW_IN_PORT
300 self.assertTrue(match is not None,
301 "Could not generate flow match from pkt")
302 act = action.action_output()
303
304 for idx in range(len(of_ports)):
Dan Talayco2e77a842010-05-12 15:39:46 -0700305 rc = delete_all_flows(self.controller, pa_logger)
306 self.assertEqual(rc, 0, "Failed to delete all flows")
307
Dan Talayco32fa6542010-05-11 15:54:08 -0700308 ingress_port = of_ports[idx]
309 pa_logger.info("Ingress " + str(ingress_port) + " to all ports")
310
311 match.in_port = ingress_port
312
313 request = message.flow_mod()
314 request.match = match
315 request.buffer_id = 0xffffffff
316 for egr_idx in range(len(of_ports)):
317 egress_port = of_ports[egr_idx]
318 if egr_idx == idx:
319 act.port = ofp.OFPP_IN_PORT
320 else:
321 act.port = egress_port
322 self.assertTrue(request.actions.add(act),
323 "Could not add output to " + str(egress_port))
Dan Talayco2e77a842010-05-12 15:39:46 -0700324 # pa_logger.info(request.show())
325
326 pa_logger.info("Inserting flow")
327 rv = self.controller.message_send(request)
328 self.assertTrue(rv != -1, "Error installing flow mod")
329 do_barrier(self.controller)
330
331 pa_logger.info("Sending packet to dp port " + str(ingress_port))
332 self.dataplane.send(ingress_port, str(pkt))
333 for egr_idx in range(len(of_ports)):
334 ofport = of_ports[egr_idx]
335 (rcv_port, rcv_pkt, pkt_time) = self.dataplane.poll(
336 port_number=ofport, timeout=1)
337 self.assertTrue(rcv_pkt is not None,
338 "Did not receive packet port " + str(ofport))
339 pa_logger.debug("Packet len " + str(len(rcv_pkt)) + " in on "
340 + str(rcv_port))
341
342 self.assertEqual(str(pkt), str(rcv_pkt),
343 'Response packet does not match send packet ' +
344 "on port " + str(ofport))
345
346class Flood(basic.SimpleDataPlane):
347 """
348 Flood to all ports except ingress
349
350 Generate a packet
351 Generate and install a matching flow
352 Add action to flood the packet
353 Send the packet to ingress dataplane port
354 Verify the packet is received at all other ports
355 """
356 def runTest(self):
357 global pa_port_map
358 of_ports = pa_port_map.keys()
359 of_ports.sort()
360 self.assertTrue(len(of_ports) > 1, "Not enough ports for test")
361
362 pkt = simple_tcp_packet()
363 match = parse.packet_to_flow_match(pkt)
364 match.wildcards &= ~ofp.OFPFW_IN_PORT
365 self.assertTrue(match is not None,
366 "Could not generate flow match from pkt")
367 act = action.action_output()
368
369 for idx in range(len(of_ports)):
370 rc = delete_all_flows(self.controller, pa_logger)
371 self.assertEqual(rc, 0, "Failed to delete all flows")
372
373 ingress_port = of_ports[idx]
374 pa_logger.info("Ingress " + str(ingress_port) + " to all ports")
375
376 match.in_port = ingress_port
377
378 request = message.flow_mod()
379 request.match = match
380 request.buffer_id = 0xffffffff
381 act.port = ofp.OFPP_FLOOD
382 self.assertTrue(request.actions.add(act),
Dan Talayco4aa13122010-05-12 15:54:44 -0700383 "Could not add flood port action")
Dan Talayco32fa6542010-05-11 15:54:08 -0700384 pa_logger.info(request.show())
385
386 pa_logger.info("Inserting flow")
387 rv = self.controller.message_send(request)
388 self.assertTrue(rv != -1, "Error installing flow mod")
389 do_barrier(self.controller)
390
391 pa_logger.info("Sending packet to dp port " + str(ingress_port))
392 self.dataplane.send(ingress_port, str(pkt))
393 for egr_idx in range(len(of_ports)):
Dan Talayco2e77a842010-05-12 15:39:46 -0700394 if egr_idx == idx:
395 continue
Dan Talayco32fa6542010-05-11 15:54:08 -0700396 ofport = of_ports[egr_idx]
397 (rcv_port, rcv_pkt, pkt_time) = self.dataplane.poll(
398 port_number=ofport, timeout=1)
399 self.assertTrue(rcv_pkt is not None,
400 "Did not receive packet port " + str(ofport))
401 pa_logger.debug("Packet len " + str(len(rcv_pkt)) + " in on "
402 + str(rcv_port))
403
404 self.assertEqual(str(pkt), str(rcv_pkt),
405 'Response packet does not match send packet ' +
406 "on port " + str(ofport))
Dan Talayco3be5b062010-05-12 15:46:21 -0700407
408
409class FloodPlusIngress(basic.SimpleDataPlane):
410 """
411 Flood to all ports plus send to ingress port
412
413 Generate a packet
414 Generate and install a matching flow
415 Add action to flood the packet
416 Add action to send to ingress port
417 Send the packet to ingress dataplane port
418 Verify the packet is received at all other ports
419 """
420 def runTest(self):
421 global pa_port_map
422 of_ports = pa_port_map.keys()
423 of_ports.sort()
424 self.assertTrue(len(of_ports) > 1, "Not enough ports for test")
425
426 pkt = simple_tcp_packet()
427 match = parse.packet_to_flow_match(pkt)
428 match.wildcards &= ~ofp.OFPFW_IN_PORT
429 self.assertTrue(match is not None,
430 "Could not generate flow match from pkt")
431 act = action.action_output()
432
433 for idx in range(len(of_ports)):
434 rc = delete_all_flows(self.controller, pa_logger)
435 self.assertEqual(rc, 0, "Failed to delete all flows")
436
437 ingress_port = of_ports[idx]
438 pa_logger.info("Ingress " + str(ingress_port) + " to all ports")
439
440 match.in_port = ingress_port
441
442 request = message.flow_mod()
443 request.match = match
444 request.buffer_id = 0xffffffff
445 act.port = ofp.OFPP_FLOOD
446 self.assertTrue(request.actions.add(act),
Dan Talayco4aa13122010-05-12 15:54:44 -0700447 "Could not add flood port action")
448 act.port = ofp.OFPP_IN_PORT
449 self.assertTrue(request.actions.add(act),
450 "Could not add ingress port for output")
451 pa_logger.info(request.show())
452
453 pa_logger.info("Inserting flow")
454 rv = self.controller.message_send(request)
455 self.assertTrue(rv != -1, "Error installing flow mod")
456 do_barrier(self.controller)
457
458 pa_logger.info("Sending packet to dp port " + str(ingress_port))
459 self.dataplane.send(ingress_port, str(pkt))
460 for egr_idx in range(len(of_ports)):
461 ofport = of_ports[egr_idx]
462 (rcv_port, rcv_pkt, pkt_time) = self.dataplane.poll(
463 port_number=ofport, timeout=1)
464 self.assertTrue(rcv_pkt is not None,
465 "Did not receive packet port " + str(ofport))
466 pa_logger.debug("Packet len " + str(len(rcv_pkt)) + " in on "
467 + str(rcv_port))
468
469 self.assertEqual(str(pkt), str(rcv_pkt),
470 'Response packet does not match send packet ' +
471 "on port " + str(ofport))
472
473class All(basic.SimpleDataPlane):
474 """
475 Send to OFPP_ALL port
476
477 Generate a packet
478 Generate and install a matching flow
479 Add action to forward to OFPP_ALL
480 Send the packet to ingress dataplane port
481 Verify the packet is received at all other ports
482 """
483 def runTest(self):
484 global pa_port_map
485 of_ports = pa_port_map.keys()
486 of_ports.sort()
487 self.assertTrue(len(of_ports) > 1, "Not enough ports for test")
488
489 pkt = simple_tcp_packet()
490 match = parse.packet_to_flow_match(pkt)
491 match.wildcards &= ~ofp.OFPFW_IN_PORT
492 self.assertTrue(match is not None,
493 "Could not generate flow match from pkt")
494 act = action.action_output()
495
496 for idx in range(len(of_ports)):
497 rc = delete_all_flows(self.controller, pa_logger)
498 self.assertEqual(rc, 0, "Failed to delete all flows")
499
500 ingress_port = of_ports[idx]
501 pa_logger.info("Ingress " + str(ingress_port) + " to all ports")
502
503 match.in_port = ingress_port
504
505 request = message.flow_mod()
506 request.match = match
507 request.buffer_id = 0xffffffff
508 act.port = ofp.OFPP_ALL
509 self.assertTrue(request.actions.add(act),
510 "Could not add ALL port action")
511 pa_logger.info(request.show())
512
513 pa_logger.info("Inserting flow")
514 rv = self.controller.message_send(request)
515 self.assertTrue(rv != -1, "Error installing flow mod")
516 do_barrier(self.controller)
517
518 pa_logger.info("Sending packet to dp port " + str(ingress_port))
519 self.dataplane.send(ingress_port, str(pkt))
520 for egr_idx in range(len(of_ports)):
521 if egr_idx == idx:
522 continue
523 ofport = of_ports[egr_idx]
524 (rcv_port, rcv_pkt, pkt_time) = self.dataplane.poll(
525 port_number=ofport, timeout=1)
526 self.assertTrue(rcv_pkt is not None,
527 "Did not receive packet port " + str(ofport))
528 pa_logger.debug("Packet len " + str(len(rcv_pkt)) + " in on "
529 + str(rcv_port))
530
531 self.assertEqual(str(pkt), str(rcv_pkt),
532 'Response packet does not match send packet ' +
533 "on port " + str(ofport))
534
535class AllPlusIngress(basic.SimpleDataPlane):
536 """
537 Send to OFPP_ALL port and ingress port
538
539 Generate a packet
540 Generate and install a matching flow
541 Add action to forward to OFPP_ALL
542 Add action to forward to ingress port
543 Send the packet to ingress dataplane port
544 Verify the packet is received at all other ports
545 """
546 def runTest(self):
547 global pa_port_map
548 of_ports = pa_port_map.keys()
549 of_ports.sort()
550 self.assertTrue(len(of_ports) > 1, "Not enough ports for test")
551
552 pkt = simple_tcp_packet()
553 match = parse.packet_to_flow_match(pkt)
554 match.wildcards &= ~ofp.OFPFW_IN_PORT
555 self.assertTrue(match is not None,
556 "Could not generate flow match from pkt")
557 act = action.action_output()
558
559 for idx in range(len(of_ports)):
560 rc = delete_all_flows(self.controller, pa_logger)
561 self.assertEqual(rc, 0, "Failed to delete all flows")
562
563 ingress_port = of_ports[idx]
564 pa_logger.info("Ingress " + str(ingress_port) + " to all ports")
565
566 match.in_port = ingress_port
567
568 request = message.flow_mod()
569 request.match = match
570 request.buffer_id = 0xffffffff
571 act.port = ofp.OFPP_ALL
572 self.assertTrue(request.actions.add(act),
573 "Could not add ALL port action")
Dan Talayco3be5b062010-05-12 15:46:21 -0700574 act.port = ofp.OFPP_IN_PORT
575 self.assertTrue(request.actions.add(act),
576 "Could not add ingress port for output")
577 pa_logger.info(request.show())
578
579 pa_logger.info("Inserting flow")
580 rv = self.controller.message_send(request)
581 self.assertTrue(rv != -1, "Error installing flow mod")
582 do_barrier(self.controller)
583
584 pa_logger.info("Sending packet to dp port " + str(ingress_port))
585 self.dataplane.send(ingress_port, str(pkt))
586 for egr_idx in range(len(of_ports)):
587 ofport = of_ports[egr_idx]
588 (rcv_port, rcv_pkt, pkt_time) = self.dataplane.poll(
589 port_number=ofport, timeout=1)
590 self.assertTrue(rcv_pkt is not None,
591 "Did not receive packet port " + str(ofport))
592 pa_logger.debug("Packet len " + str(len(rcv_pkt)) + " in on "
593 + str(rcv_port))
594
595 self.assertEqual(str(pkt), str(rcv_pkt),
596 'Response packet does not match send packet ' +
597 "on port " + str(ofport))
Tatsuya Yabe6a6f38a2010-05-22 23:48:04 -0700598
599class SimpleExactMatch(basic.SimpleDataPlane):
600 """
601 Exercise exact matching for all ports
602
603 Generate a packet
604 Generate and install a matching flow without wildcard mask
605 Add action to forward to a port
606 Send the packet to the port
607 Verify the packet is received at all other ports (one port at a time)
Tatsuya Yabe0718ad32010-05-24 15:22:10 -0700608 Verify flow_expiration message is correct when command option is set
Tatsuya Yabe6a6f38a2010-05-22 23:48:04 -0700609 """
Tatsuya Yabe0718ad32010-05-24 15:22:10 -0700610 IP_ETHTYPE = 0x800
611 TCP_PROTOCOL = 0x6
612 UDP_PROTOCOL = 0x11
613
Tatsuya Yabe6a6f38a2010-05-22 23:48:04 -0700614 def runTest(self):
615 self.flowMatchTest()
616
Tatsuya Yabe0718ad32010-05-24 15:22:10 -0700617 def flowMatchTest(self, wildcards=0, check_expire=False):
Tatsuya Yabe6a6f38a2010-05-22 23:48:04 -0700618 global pa_port_map
619 of_ports = pa_port_map.keys()
620 of_ports.sort()
621 self.assertTrue(len(of_ports) > 1, "Not enough ports for test")
622
623 pkt = simple_tcp_packet()
624 match = parse.packet_to_flow_match(pkt)
625 self.assertTrue(match is not None,
626 "Could not generate flow match from pkt")
Tatsuya Yabe0718ad32010-05-24 15:22:10 -0700627 match.dl_vlan = ofp.OFP_VLAN_NONE
628 match.nw_proto = self.TCP_PROTOCOL
Tatsuya Yabe6a6f38a2010-05-22 23:48:04 -0700629 match.wildcards = wildcards
630
Tatsuya Yabe6a6f38a2010-05-22 23:48:04 -0700631 for idx in range(len(of_ports)):
Tatsuya Yabe6a6f38a2010-05-22 23:48:04 -0700632 ingress_port = of_ports[idx]
633 pa_logger.info("Ingress " + str(ingress_port) + " to all the other ports")
Tatsuya Yabe6a6f38a2010-05-22 23:48:04 -0700634 match.in_port = ingress_port
635
Tatsuya Yabe6a6f38a2010-05-22 23:48:04 -0700636 for egr_idx in range(len(of_ports)):
637 if egr_idx == idx:
638 continue
Tatsuya Yabecdf575e2010-05-25 16:56:38 -0700639
640 rc = delete_all_flows(self.controller, pa_logger)
641 self.assertEqual(rc, 0, "Failed to delete all flows")
642 do_barrier(self.controller)
643
644 request = message.flow_mod()
645 request.match = match
646 request.buffer_id = 0xffffffff
647 #@todo Need UI to setup FLAGS parameter for flow_mod
648 if(check_expire):
649 request.flags |= ofp.OFPFF_SEND_FLOW_REM
650 request.hard_timeout = 1
651
652 act = action.action_output()
Tatsuya Yabe6a6f38a2010-05-22 23:48:04 -0700653 act.port = of_ports[egr_idx]
654 self.assertTrue(request.actions.add(act),
655 "Could not add output action")
656 pa_logger.info(request.show())
657
658 pa_logger.info("Inserting flow")
659 rv = self.controller.message_send(request)
660 self.assertTrue(rv != -1, "Error installing flow mod")
661 do_barrier(self.controller)
662
663 pa_logger.info("Sending packet to dp port " +str(ingress_port))
664 self.dataplane.send(ingress_port, str(pkt))
665
666 ofport = of_ports[egr_idx]
Tatsuya Yabecdf575e2010-05-25 16:56:38 -0700667 self.verifPkt(ofport, pkt)
Tatsuya Yabe6a6f38a2010-05-22 23:48:04 -0700668
Tatsuya Yabe0718ad32010-05-24 15:22:10 -0700669 #@todo Need UI for enabling response-verification
670 if(check_expire):
Tatsuya Yabecdf575e2010-05-25 16:56:38 -0700671 self.verifFlowRemoved(request)
Tatsuya Yabe6a6f38a2010-05-22 23:48:04 -0700672
Tatsuya Yabecdf575e2010-05-25 16:56:38 -0700673 def verifPkt(self, ofport, exp_pkt):
674 (rcv_port, rcv_pkt, pkt_time) = self.dataplane.poll(
675 port_number=ofport, timeout=1)
676 self.assertTrue(rcv_pkt is not None,
677 "Did not receive packet port " + str(ofport))
678 pa_logger.debug("Packet len " + str(len(rcv_pkt)) + " in on "
679 + str(rcv_port))
Tatsuya Yabe6a6f38a2010-05-22 23:48:04 -0700680
Tatsuya Yabecdf575e2010-05-25 16:56:38 -0700681 self.assertEqual(str(exp_pkt), str(rcv_pkt),
682 'Response packet does not match send packet ' +
683 "on port " + str(ofport))
684
685 def verifFlowRemoved(self, request):
686 (response, raw) = self.controller.poll(ofp.OFPT_FLOW_REMOVED, 2)
687 self.assertTrue(response is not None,
688 'Flow removed message not received')
689
690 req_match = request.match
691 res_match = response.match
692 if(req_match != res_match):
693 self.verifMatchField(req_match, res_match)
694
695 self.assertEqual(request.cookie, response.cookie,
696 self.matchErrStr('cookie'))
697 if (req_match.wildcards != 0):
698 self.assertEqual(request.priority, response.priority,
699 self.matchErrStr('priority'))
700 self.assertEqual(response.reason, ofp.OFPRR_HARD_TIMEOUT,
701 'Reason is not HARD TIMEOUT')
702 self.assertEqual(response.packet_count, 1,
703 'Packet count is not correct')
704 self.assertEqual(response.byte_count, len(pkt),
705 'Packet length is not correct')
Tatsuya Yabe6a6f38a2010-05-22 23:48:04 -0700706
707 def verifMatchField(self, req_match, res_match):
708 self.assertEqual(str(req_match.wildcards), str(res_match.wildcards),
709 self.matchErrStr('wildcards'))
710 self.assertEqual(str(req_match.in_port), str(res_match.in_port),
711 self.matchErrStr('in_port'))
712 self.assertEqual(str(req_match.dl_src), str(res_match.dl_src),
713 self.matchErrStr('dl_src'))
714 self.assertEqual(str(req_match.dl_dst), str(res_match.dl_dst),
715 self.matchErrStr('dl_dst'))
716 self.assertEqual(str(req_match.dl_vlan), str(res_match.dl_vlan),
717 self.matchErrStr('dl_vlan'))
718 self.assertEqual(str(req_match.dl_vlan_pcp), str(res_match.dl_vlan_pcp),
719 self.matchErrStr('dl_vlan_pcp'))
720 self.assertEqual(str(req_match.dl_type), str(res_match.dl_type),
721 self.matchErrStr('dl_type'))
Tatsuya Yabe0718ad32010-05-24 15:22:10 -0700722 if(not(req_match.wildcards & ofp.OFPFW_DL_TYPE)
723 and (req_match.dl_type == self.IP_ETHERTYPE)):
724 self.assertEqual(str(req_match.nw_tos), str(res_match.nw_tos),
725 self.matchErrStr('nw_tos'))
726 self.assertEqual(str(req_match.nw_proto), str(res_match.nw_proto),
727 self.matchErrStr('nw_proto'))
728 self.assertEqual(str(req_match.nw_src), str(res_match.nw_src),
729 self.matchErrStr('nw_src'))
730 self.assertEqual(str(req_match.nw_dst), str(res_match.nw_dst),
731 self.matchErrStr('nw_dst'))
732 if(not(req_match.wildcards & ofp.OFPFW_NW_PROTO)
733 and ((req_match.nw_proto == self.TCP_PROTOCOL)
734 or (req_match.nw_proto == self.UDP_PROTOCOL))):
735 self.assertEqual(str(req_match.tp_src), str(res_match.tp_src),
736 self.matchErrStr('tp_src'))
737 self.assertEqual(str(req_match.tp_dst), str(res_match.tp_dst),
738 self.matchErrStr('tp_dst'))
Tatsuya Yabe6a6f38a2010-05-22 23:48:04 -0700739
740 def matchErrStr(self, field):
741 return ('Response Match_' + field + ' does not match send message')
742
743class SingleWildcardMatch(SimpleExactMatch):
744 """
745 Exercise wildcard matching for all ports
746
747 Generate a packet
748 Generate and install a matching flow with wildcard mask
749 Add action to forward to a port
750 Send the packet to the port
751 Verify the packet is received at all other ports (one port at a time)
Tatsuya Yabe0718ad32010-05-24 15:22:10 -0700752 Verify flow_expiration message is correct when command option is set
Tatsuya Yabe6a6f38a2010-05-22 23:48:04 -0700753 """
Tatsuya Yabe0718ad32010-05-24 15:22:10 -0700754 def __init__(self):
755 SimpleExactMatch.__init__(self)
756 self.wildcards = [ofp.OFPFW_IN_PORT,
757 ofp.OFPFW_DL_VLAN,
758 ofp.OFPFW_DL_SRC,
759 ofp.OFPFW_DL_DST,
760 ofp.OFPFW_DL_TYPE,
761 ofp.OFPFW_NW_PROTO,
762 ofp.OFPFW_TP_SRC,
763 ofp.OFPFW_TP_DST,
764 0x3F << ofp.OFPFW_NW_SRC_SHIFT,
765 0x3F << ofp.OFPFW_NW_DST_SHIFT,
766 ofp.OFPFW_DL_VLAN_PCP,
767 ofp.OFPFW_NW_TOS]
Tatsuya Yabe6a6f38a2010-05-22 23:48:04 -0700768
Tatsuya Yabe0718ad32010-05-24 15:22:10 -0700769 def runTest(self):
770 for exec_wildcard in range(len(self.wildcards)):
Tatsuya Yabe6a6f38a2010-05-22 23:48:04 -0700771 self.flowMatchTest(exec_wildcard)
Tatsuya Yabe4fad7e32010-05-24 15:24:50 -0700772
773class AllExceptOneWildcardMatch(SingleWildcardMatch):
774 """
775 Create All-execpt-one-field wildcard and exercise for all ports
776
777 Generate a packet
778 Generate and install a matching flow with wildcard all except one filed
779 Add action to forward to a port
780 Send the packet to the port
781 Verify the packet is received at all other ports (one port at a time)
782 Verify flow_expiration message is correct when command option is set
783 """
784 def runTest(self):
785 for exec_wildcard in range(len(self.wildcards)):
786 all_exp_one_wildcard = ofp.OFPFW_ALL ^ self.wildcards[exec_wildcard]
787 self.flowMatchTest(all_exp_one_wildcard)
Tatsuya Yabee30ebe22010-05-25 09:30:49 -0700788
789class AllWildcardMatch(SingleWildcardMatch):
790 """
791 Create Wildcard-all flow and exercise for all ports
792
793 Generate a packet
794 Generate and install a matching flow with wildcard-all
795 Add action to forward to a port
796 Send the packet to the port
797 Verify the packet is received at all other ports (one port at a time)
798 Verify flow_expiration message is correct when command option is set
799 """
800 def runTest(self):
801 self.flowMatchTest(ofp.OFPFW_ALL)
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -0700802
803class ExactModifyAction(SimpleExactMatch):
804 """
805 Perform Modify action with exact matching for all ports
806
807 Generate a packet for transmit
808 Generate the expected packet
809 Generate and install a matching flow with a modify action and
810 an output action without wildcard mask
811 Send the packet to the port
812 Verify the expected packet is received at all other ports
813 (one port at a time)
814 Verify flow_expiration message is correct when command option is set
815 """
816 def __init__(self):
817 SimpleExactMatch.__init__(self)
818 self.modify_act = [ofp.OFPAT_SET_VLAN_VID,
819 ofp.OFPAT_SET_VLAN_PCP,
820 ofp.OFPAT_STRIP_VLAN,
821 ofp.OFPAT_SET_DL_SRC,
822 ofp.OFPAT_SET_DL_DST,
823 ofp.OFPAT_SET_NW_SRC,
824 ofp.OFPAT_SET_NW_DST,
825 ofp.OFPAT_SET_NW_TOS,
826 ofp.OFPAT_SET_TP_SRC,
827 ofp.OFPAT_SET_TP_DST]
828
829 def runTest(self):
830 self.flowMatchModTest()
831
832 def flowMatchModTest(self, wildcards=0, check_expire=False):
833 global pa_port_map
834 of_ports = pa_port_map.keys()
835 of_ports.sort()
836 self.assertTrue(len(of_ports) > 1, "Not enough ports for test")
837
838 mod_dl_dst = '43:21:0F:ED:CB:A9'
839 mod_dl_src = '7F:ED:CB:A9:87:65'
840 mod_dl_vlan = 4094
841 mod_dl_vlan_pcp = 7
842 mod_ip_src = '10.20.30.40'
843 mod_ip_dst = '50.60.70.80'
844 mod_ip_tos = 0xf0
845 mod_tcp_sport = 4321
846 mod_tcp_dport = 8765
847
Tatsuya Yabef5ffb972010-05-26 15:36:33 -0700848 request = message.features_request()
849 (reply, pkt) = self.controller.transact(request, timeout=2)
850 self.assertTrue(reply is not None, "Did not get response to ftr req")
851 supported_act = reply.actions
852
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -0700853 for idx in range(len(of_ports)):
854 ingress_port = of_ports[idx]
855 pa_logger.info("Ingress " + str(ingress_port) + " to all the other ports")
856
857 for egr_idx in range(len(of_ports)):
858 if egr_idx == idx:
859 continue
860
861 for exec_mod in range(len(self.modify_act)):
862 pkt_len = 100
863 dl_dst = '0C:DE:F0:12:34:56'
864 dl_src = '01:23:45:67:89:AB'
865 dl_vlan_enable = False
866 dl_vlan = 0
867 dl_vlan_pcp = 0
868 ip_src = '192.168.0.1'
869 ip_dst = '192.168.0.2'
870 ip_tos = 0
871 tcp_sport = 1234
872 tcp_dport = 80
873
874 rc = delete_all_flows(self.controller, pa_logger)
875 self.assertEqual(rc, 0, "Failed to delete all flows")
876 do_barrier(self.controller)
877
878 pkt = simple_tcp_packet(pktlen=pkt_len,
879 dl_dst=dl_dst,
880 dl_src=dl_src,
881 dl_vlan_enable=dl_vlan_enable,
882 dl_vlan=dl_vlan,
883 dl_vlan_pcp=dl_vlan_pcp,
884 ip_src=ip_src,
885 ip_dst=ip_dst,
886 ip_tos=ip_tos,
887 tcp_sport=tcp_sport,
888 tcp_dport=tcp_dport)
889
890 match = parse.packet_to_flow_match(pkt)
891 self.assertTrue(match is not None,
892 "Could not generate flow match from pkt")
893 match.in_port = ingress_port
894 match.dl_vlan = ofp.OFP_VLAN_NONE
895 match.nw_proto = self.TCP_PROTOCOL
896 match.wildcards = wildcards
897
898 request = message.flow_mod()
899 request.match = match
900 request.buffer_id = 0xffffffff
901 #@todo Need UI to setup FLAGS parameter for flow_mod
902 if(check_expire):
903 request.flags |= ofp.OFPFF_SEND_FLOW_REM
904 request.hard_timeout = 1
905
906 exec_act = self.modify_act[exec_mod]
907 if exec_act == ofp.OFPAT_SET_VLAN_VID:
Tatsuya Yabef5ffb972010-05-26 15:36:33 -0700908 if not(supported_act & 1<<ofp.OFPAT_SET_VLAN_VID):
909 continue
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -0700910 pkt_len = pkt_len + 4
911 dl_vlan_enable = True
912 dl_vlan = mod_dl_vlan
913 mod_act = action.action_set_vlan_vid()
914 mod_act.vlan_vid = mod_dl_vlan
Tatsuya Yabe17195a02010-05-26 15:29:55 -0700915 elif exec_act == ofp.OFPAT_SET_VLAN_PCP:
Tatsuya Yabef5ffb972010-05-26 15:36:33 -0700916 if not(supported_act & 1<<ofp.OFPAT_SET_VLAN_PCP):
917 continue
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -0700918 pkt_len = pkt_len + 4
919 dl_vlan_enable = True
920 dl_vlan_pcp = mod_dl_vlan_pcp
921 mod_act = action.action_set_vlan_pcp()
922 mod_act.vlan_pcp = mod_dl_vlan_pcp
Tatsuya Yabe17195a02010-05-26 15:29:55 -0700923 elif exec_act == ofp.OFPAT_STRIP_VLAN:
Tatsuya Yabef5ffb972010-05-26 15:36:33 -0700924 if not(supported_act & 1<<ofp.OFPAT_STRIP_VLAN):
925 continue
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -0700926 dl_vlan_enable = False
927 mod_act = action.action_strip_vlan()
Tatsuya Yabe17195a02010-05-26 15:29:55 -0700928 elif exec_act == ofp.OFPAT_SET_DL_SRC:
Tatsuya Yabef5ffb972010-05-26 15:36:33 -0700929 if not(supported_act & 1<<ofp.OFPAT_SET_DL_SRC):
930 continue
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -0700931 dl_src = mod_dl_src
932 mod_act = action.action_set_dl_src()
933 mod_act.dl_addr = parse.parse_mac(mod_dl_src)
Tatsuya Yabe17195a02010-05-26 15:29:55 -0700934 elif exec_act == ofp.OFPAT_SET_DL_DST:
Tatsuya Yabef5ffb972010-05-26 15:36:33 -0700935 if not(supported_act & 1<<ofp.OFPAT_SET_DL_DST):
936 continue
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -0700937 dl_dst = mod_dl_dst
938 mod_act = action.action_set_dl_dst()
939 mod_act.dl_addr = parse.parse_mac(mod_dl_dst)
Tatsuya Yabe17195a02010-05-26 15:29:55 -0700940 elif exec_act == ofp.OFPAT_SET_NW_SRC:
Tatsuya Yabef5ffb972010-05-26 15:36:33 -0700941 if not(supported_act & 1<<ofp.OFPAT_SET_NW_SRC):
942 continue
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -0700943 ip_src = mod_ip_src
944 mod_act = action.action_set_nw_src()
945 mod_act.nw_addr = parse.parse_ip(mod_ip_src)
Tatsuya Yabe17195a02010-05-26 15:29:55 -0700946 elif exec_act == ofp.OFPAT_SET_NW_DST:
Tatsuya Yabef5ffb972010-05-26 15:36:33 -0700947 if not(supported_act & 1<<ofp.OFPAT_SET_NW_DST):
948 continue
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -0700949 ip_dst = mod_ip_dst
950 mod_act = action.action_set_nw_dst()
951 mod_act.nw_addr = parse.parse_ip(mod_ip_dst)
Tatsuya Yabe17195a02010-05-26 15:29:55 -0700952 elif exec_act == ofp.OFPAT_SET_NW_TOS:
Tatsuya Yabef5ffb972010-05-26 15:36:33 -0700953 if not(supported_act & 1<<ofp.OFPAT_SET_NW_TOS):
954 continue
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -0700955 ip_tos = mod_ip_tos
956 mod_act = action.action_set_nw_tos()
957 mod_act.nw_tos = mod_ip_tos
Tatsuya Yabe17195a02010-05-26 15:29:55 -0700958 elif exec_act == ofp.OFPAT_SET_TP_SRC:
Tatsuya Yabef5ffb972010-05-26 15:36:33 -0700959 if not(supported_act & 1<<ofp.OFPAT_SET_TP_SRC):
960 continue
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -0700961 tcp_sport = mod_tcp_sport
962 mod_act = action.action_set_tp_src()
963 mod_act.tp_port = mod_tcp_sport
Tatsuya Yabe17195a02010-05-26 15:29:55 -0700964 elif exec_act == ofp.OFPAT_SET_TP_DST:
Tatsuya Yabef5ffb972010-05-26 15:36:33 -0700965 if not(supported_act & 1<<ofp.OFPAT_SET_TP_DST):
966 continue
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -0700967 tcp_dport = mod_tcp_dport
968 mod_act = action.action_set_tp_dst()
969 mod_act.tp_port = mod_tcp_dport
Tatsuya Yabe17195a02010-05-26 15:29:55 -0700970 else:
971 continue
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -0700972
973 self.assertTrue(request.actions.add(mod_act),
974 "Could not add output action")
975 pa_logger.info(request.show())
976
977 exp_pkt = simple_tcp_packet(pktlen=pkt_len,
978 dl_dst=dl_dst,
979 dl_src=dl_src,
980 dl_vlan_enable=dl_vlan_enable,
981 dl_vlan=dl_vlan,
982 dl_vlan_pcp=dl_vlan_pcp,
983 ip_src=ip_src,
984 ip_dst=ip_dst,
985 ip_tos=ip_tos,
986 tcp_sport=tcp_sport,
987 tcp_dport=tcp_dport)
988
989 act = action.action_output()
990 act.port = of_ports[egr_idx]
991 self.assertTrue(request.actions.add(act),
992 "Could not add output action")
993 pa_logger.info(request.show())
994
995 pa_logger.info("Inserting flow")
996 rv = self.controller.message_send(request)
997 self.assertTrue(rv != -1, "Error installing flow mod")
998 do_barrier(self.controller)
999
1000 pa_logger.info("Sending packet to dp port " +str(ingress_port))
1001 self.dataplane.send(ingress_port, str(pkt))
1002
1003 ofport = of_ports[egr_idx]
1004 self.verifPkt(ofport, exp_pkt)
1005
1006 #@todo Need UI for enabling response-verification
1007 if(check_expire):
1008 self.verifFlowRemoved(request)