blob: 8d886b913189b1c9f0b2542dc4f7ec02ba33dc08 [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
Dan Talayco9f47f4d2010-06-03 13:54:37 -070018import copy
19
Dan Talayco5eba8442010-03-10 13:58:43 -080020import logging
21
22import unittest
23
24import oftest.controller as controller
25import oftest.cstruct as ofp
26import oftest.message as message
27import oftest.dataplane as dataplane
28import oftest.action as action
29import oftest.parse as parse
30import basic
31
32from testutils import *
33
34#@var port_map Local copy of the configuration map from OF port
35# numbers to OS interfaces
36pa_port_map = None
37#@var pa_logger Local logger object
38pa_logger = None
39#@var pa_config Local copy of global configuration data
40pa_config = None
41
42def test_set_init(config):
43 """
44 Set up function for packet action test classes
45
46 @param config The configuration dictionary; see oft
47 """
48
49 global pa_port_map
50 global pa_logger
51 global pa_config
52
53 pa_logger = logging.getLogger("pkt_act")
54 pa_logger.info("Initializing test set")
55 pa_port_map = config["port_map"]
56 pa_config = config
57
58class DirectPacket(basic.SimpleDataPlane):
59 """
Dan Talayco2d0d49a2010-05-11 15:29:08 -070060 Send packet to single egress port
Dan Talayco5eba8442010-03-10 13:58:43 -080061
62 Generate a packet
63 Generate and install a matching flow
64 Add action to direct the packet to an egress port
65 Send the packet to ingress dataplane port
66 Verify the packet is received at the egress port only
67 """
68 def runTest(self):
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -070069 self.handleFlow()
70
71 def handleFlow(self, pkttype='TCP'):
72
Dan Talayco5eba8442010-03-10 13:58:43 -080073 global pa_port_map
74 of_ports = pa_port_map.keys()
75 of_ports.sort()
76 self.assertTrue(len(of_ports) > 1, "Not enough ports for test")
77
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -070078 if (pkttype == 'ICMP'):
79 pkt = simple_icmp_packet()
80 else:
81 pkt = simple_tcp_packet()
Dan Talayco5eba8442010-03-10 13:58:43 -080082 match = parse.packet_to_flow_match(pkt)
Dan Talayco7dd6cd62010-03-16 15:02:35 -070083 match.wildcards &= ~ofp.OFPFW_IN_PORT
Dan Talayco5eba8442010-03-10 13:58:43 -080084 self.assertTrue(match is not None,
85 "Could not generate flow match from pkt")
86 act = action.action_output()
87
88 for idx in range(len(of_ports)):
Dan Talayco9f47f4d2010-06-03 13:54:37 -070089 rv = delete_all_flows(self.controller, pa_logger)
90 self.assertEqual(rv, 0, "Failed to delete all flows")
Dan Talayco2e77a842010-05-12 15:39:46 -070091
Dan Talayco5eba8442010-03-10 13:58:43 -080092 ingress_port = of_ports[idx]
93 egress_port = of_ports[(idx + 1) % len(of_ports)]
94 pa_logger.info("Ingress " + str(ingress_port) +
95 " to egress " + str(egress_port))
96
97 match.in_port = ingress_port
98
99 request = message.flow_mod()
100 request.match = match
101 request.buffer_id = 0xffffffff
102 act.port = egress_port
103 self.assertTrue(request.actions.add(act), "Could not add action")
104
105 pa_logger.info("Inserting flow")
106 rv = self.controller.message_send(request)
107 self.assertTrue(rv != -1, "Error installing flow mod")
108 do_barrier(self.controller)
109
110 pa_logger.info("Sending packet to dp port " +
111 str(ingress_port))
112 self.dataplane.send(ingress_port, str(pkt))
113 (rcv_port, rcv_pkt, pkt_time) = self.dataplane.poll(timeout=1)
114 self.assertTrue(rcv_pkt is not None, "Did not receive packet")
Dan Talayco2d0d49a2010-05-11 15:29:08 -0700115 pa_logger.debug("Packet len " + str(len(rcv_pkt)) + " in on " +
Dan Talayco5eba8442010-03-10 13:58:43 -0800116 str(rcv_port))
117 self.assertEqual(rcv_port, egress_port, "Unexpected receive port")
118 self.assertEqual(str(pkt), str(rcv_pkt),
119 'Response packet does not match send packet')
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700120
121class DirectPacketICMP(DirectPacket):
122 """
123 Send ICMP packet to single egress port
124
125 Generate a ICMP packet
126 Generate and install a matching flow
127 Add action to direct the packet to an egress port
128 Send the packet to ingress dataplane port
129 Verify the packet is received at the egress port only
130 Difference from DirectPacket test is that sent packet is ICMP
131 """
132 def runTest(self):
133 self.handleFlow(pkttype='ICMP')
Dan Talayco2d0d49a2010-05-11 15:29:08 -0700134
135class DirectTwoPorts(basic.SimpleDataPlane):
136 """
137 Send packet to two egress ports
138
139 Generate a packet
140 Generate and install a matching flow
141 Add action to direct the packet to two egress ports
142 Send the packet to ingress dataplane port
143 Verify the packet is received at the two egress ports
144 """
145 def runTest(self):
146 global pa_port_map
147 of_ports = pa_port_map.keys()
148 of_ports.sort()
149 self.assertTrue(len(of_ports) > 2, "Not enough ports for test")
150
Dan Talayco2d0d49a2010-05-11 15:29:08 -0700151 pkt = simple_tcp_packet()
152 match = parse.packet_to_flow_match(pkt)
153 match.wildcards &= ~ofp.OFPFW_IN_PORT
154 self.assertTrue(match is not None,
155 "Could not generate flow match from pkt")
156 act = action.action_output()
157
158 for idx in range(len(of_ports)):
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700159 rv = delete_all_flows(self.controller, pa_logger)
160 self.assertEqual(rv, 0, "Failed to delete all flows")
Dan Talayco2e77a842010-05-12 15:39:46 -0700161
Dan Talayco2d0d49a2010-05-11 15:29:08 -0700162 ingress_port = of_ports[idx]
163 egress_port1 = of_ports[(idx + 1) % len(of_ports)]
164 egress_port2 = of_ports[(idx + 2) % len(of_ports)]
165 pa_logger.info("Ingress " + str(ingress_port) +
166 " to egress " + str(egress_port1) + " and " +
167 str(egress_port2))
168
169 match.in_port = ingress_port
170
171 request = message.flow_mod()
172 request.match = match
173 request.buffer_id = 0xffffffff
174 act.port = egress_port1
175 self.assertTrue(request.actions.add(act), "Could not add action1")
176 act.port = egress_port2
177 self.assertTrue(request.actions.add(act), "Could not add action2")
Dan Talaycob0b0fdb2010-05-11 15:44:56 -0700178 # pa_logger.info(request.show())
Dan Talayco2d0d49a2010-05-11 15:29:08 -0700179
180 pa_logger.info("Inserting flow")
181 rv = self.controller.message_send(request)
182 self.assertTrue(rv != -1, "Error installing flow mod")
183 do_barrier(self.controller)
184
185 pa_logger.info("Sending packet to dp port " +
186 str(ingress_port))
187 self.dataplane.send(ingress_port, str(pkt))
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700188 yes_ports = set([egress_port1, egress_port2])
189 no_ports = set(of_ports).difference(yes_ports)
Dan Talayco2d0d49a2010-05-11 15:29:08 -0700190
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700191 receive_pkt_check(self.dataplane, pkt, yes_ports, no_ports,
192 self, pa_logger)
Dan Talaycob0b0fdb2010-05-11 15:44:56 -0700193
194class DirectMCNonIngress(basic.SimpleDataPlane):
195 """
196 Multicast to all non-ingress ports
197
198 Generate a packet
199 Generate and install a matching flow
200 Add action to direct the packet to all non-ingress ports
201 Send the packet to ingress dataplane port
202 Verify the packet is received at all non-ingress ports
203
204 Does not use the flood action
205 """
206 def runTest(self):
207 global pa_port_map
208 of_ports = pa_port_map.keys()
209 of_ports.sort()
210 self.assertTrue(len(of_ports) > 2, "Not enough ports for test")
211
Dan Talaycob0b0fdb2010-05-11 15:44:56 -0700212 pkt = simple_tcp_packet()
213 match = parse.packet_to_flow_match(pkt)
214 match.wildcards &= ~ofp.OFPFW_IN_PORT
215 self.assertTrue(match is not None,
216 "Could not generate flow match from pkt")
217 act = action.action_output()
218
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700219 for ingress_port in of_ports:
220 rv = delete_all_flows(self.controller, pa_logger)
221 self.assertEqual(rv, 0, "Failed to delete all flows")
Dan Talayco2e77a842010-05-12 15:39:46 -0700222
Dan Talaycob0b0fdb2010-05-11 15:44:56 -0700223 pa_logger.info("Ingress " + str(ingress_port) +
224 " all non-ingress ports")
Dan Talaycob0b0fdb2010-05-11 15:44:56 -0700225 match.in_port = ingress_port
226
227 request = message.flow_mod()
228 request.match = match
229 request.buffer_id = 0xffffffff
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700230 for egress_port in of_ports:
231 if egress_port == ingress_port:
Dan Talaycob0b0fdb2010-05-11 15:44:56 -0700232 continue
Dan Talaycob0b0fdb2010-05-11 15:44:56 -0700233 act.port = egress_port
234 self.assertTrue(request.actions.add(act),
235 "Could not add output to " + str(egress_port))
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700236 pa_logger.debug(request.show())
Dan Talaycob0b0fdb2010-05-11 15:44:56 -0700237
238 pa_logger.info("Inserting flow")
239 rv = self.controller.message_send(request)
240 self.assertTrue(rv != -1, "Error installing flow mod")
241 do_barrier(self.controller)
242
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700243 pa_logger.info("Sending packet to dp port " + str(ingress_port))
Dan Talaycob0b0fdb2010-05-11 15:44:56 -0700244 self.dataplane.send(ingress_port, str(pkt))
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700245 yes_ports = set(of_ports).difference([ingress_port])
246 receive_pkt_check(self.dataplane, pkt, yes_ports, [ingress_port],
247 self, pa_logger)
Dan Talaycob0b0fdb2010-05-11 15:44:56 -0700248
Dan Talayco32fa6542010-05-11 15:54:08 -0700249
250class DirectMC(basic.SimpleDataPlane):
251 """
252 Multicast to all ports including ingress
253
254 Generate a packet
255 Generate and install a matching flow
256 Add action to direct the packet to all non-ingress ports
257 Send the packet to ingress dataplane port
258 Verify the packet is received at all ports
259
260 Does not use the flood action
261 """
262 def runTest(self):
263 global pa_port_map
264 of_ports = pa_port_map.keys()
265 of_ports.sort()
266 self.assertTrue(len(of_ports) > 2, "Not enough ports for test")
267
Dan Talayco32fa6542010-05-11 15:54:08 -0700268 pkt = simple_tcp_packet()
269 match = parse.packet_to_flow_match(pkt)
270 match.wildcards &= ~ofp.OFPFW_IN_PORT
271 self.assertTrue(match is not None,
272 "Could not generate flow match from pkt")
273 act = action.action_output()
274
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700275 for ingress_port in of_ports:
276 rv = delete_all_flows(self.controller, pa_logger)
277 self.assertEqual(rv, 0, "Failed to delete all flows")
Dan Talayco2e77a842010-05-12 15:39:46 -0700278
Dan Talayco32fa6542010-05-11 15:54:08 -0700279 pa_logger.info("Ingress " + str(ingress_port) + " to all ports")
Dan Talayco32fa6542010-05-11 15:54:08 -0700280 match.in_port = ingress_port
281
282 request = message.flow_mod()
283 request.match = match
284 request.buffer_id = 0xffffffff
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700285 for egress_port in of_ports:
286 if egress_port == ingress_port:
Dan Talayco32fa6542010-05-11 15:54:08 -0700287 act.port = ofp.OFPP_IN_PORT
288 else:
289 act.port = egress_port
290 self.assertTrue(request.actions.add(act),
291 "Could not add output to " + str(egress_port))
Dan Talayco2e77a842010-05-12 15:39:46 -0700292 # pa_logger.info(request.show())
293
294 pa_logger.info("Inserting flow")
295 rv = self.controller.message_send(request)
296 self.assertTrue(rv != -1, "Error installing flow mod")
297 do_barrier(self.controller)
298
299 pa_logger.info("Sending packet to dp port " + str(ingress_port))
300 self.dataplane.send(ingress_port, str(pkt))
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700301 receive_pkt_check(self.dataplane, pkt, of_ports, [], self,
302 pa_logger)
Dan Talayco2e77a842010-05-12 15:39:46 -0700303
304class Flood(basic.SimpleDataPlane):
305 """
306 Flood to all ports except ingress
307
308 Generate a packet
309 Generate and install a matching flow
310 Add action to flood the packet
311 Send the packet to ingress dataplane port
312 Verify the packet is received at all other ports
313 """
314 def runTest(self):
315 global pa_port_map
316 of_ports = pa_port_map.keys()
317 of_ports.sort()
318 self.assertTrue(len(of_ports) > 1, "Not enough ports for test")
319
320 pkt = simple_tcp_packet()
321 match = parse.packet_to_flow_match(pkt)
322 match.wildcards &= ~ofp.OFPFW_IN_PORT
323 self.assertTrue(match is not None,
324 "Could not generate flow match from pkt")
325 act = action.action_output()
326
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700327 for ingress_port in of_ports:
328 rv = delete_all_flows(self.controller, pa_logger)
329 self.assertEqual(rv, 0, "Failed to delete all flows")
Dan Talayco2e77a842010-05-12 15:39:46 -0700330
Dan Talayco2e77a842010-05-12 15:39:46 -0700331 pa_logger.info("Ingress " + str(ingress_port) + " to all ports")
Dan Talayco2e77a842010-05-12 15:39:46 -0700332 match.in_port = ingress_port
333
334 request = message.flow_mod()
335 request.match = match
336 request.buffer_id = 0xffffffff
337 act.port = ofp.OFPP_FLOOD
338 self.assertTrue(request.actions.add(act),
Dan Talayco4aa13122010-05-12 15:54:44 -0700339 "Could not add flood port action")
Dan Talayco32fa6542010-05-11 15:54:08 -0700340 pa_logger.info(request.show())
341
342 pa_logger.info("Inserting flow")
343 rv = self.controller.message_send(request)
344 self.assertTrue(rv != -1, "Error installing flow mod")
345 do_barrier(self.controller)
346
347 pa_logger.info("Sending packet to dp port " + str(ingress_port))
348 self.dataplane.send(ingress_port, str(pkt))
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700349 yes_ports = set(of_ports).difference([ingress_port])
350 receive_pkt_check(self.dataplane, pkt, yes_ports, [ingress_port],
351 self, pa_logger)
Dan Talayco3be5b062010-05-12 15:46:21 -0700352
Dan Talayco3be5b062010-05-12 15:46:21 -0700353class FloodPlusIngress(basic.SimpleDataPlane):
354 """
355 Flood to all ports plus send to ingress port
356
357 Generate a packet
358 Generate and install a matching flow
359 Add action to flood the packet
360 Add action to send to ingress port
361 Send the packet to ingress dataplane port
362 Verify the packet is received at all other ports
363 """
364 def runTest(self):
365 global pa_port_map
366 of_ports = pa_port_map.keys()
367 of_ports.sort()
368 self.assertTrue(len(of_ports) > 1, "Not enough ports for test")
369
370 pkt = simple_tcp_packet()
371 match = parse.packet_to_flow_match(pkt)
372 match.wildcards &= ~ofp.OFPFW_IN_PORT
373 self.assertTrue(match is not None,
374 "Could not generate flow match from pkt")
375 act = action.action_output()
376
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700377 for ingress_port in of_ports:
378 rv = delete_all_flows(self.controller, pa_logger)
379 self.assertEqual(rv, 0, "Failed to delete all flows")
Dan Talayco3be5b062010-05-12 15:46:21 -0700380
Dan Talayco3be5b062010-05-12 15:46:21 -0700381 pa_logger.info("Ingress " + str(ingress_port) + " to all ports")
Dan Talayco3be5b062010-05-12 15:46:21 -0700382 match.in_port = ingress_port
383
384 request = message.flow_mod()
385 request.match = match
386 request.buffer_id = 0xffffffff
387 act.port = ofp.OFPP_FLOOD
388 self.assertTrue(request.actions.add(act),
Dan Talayco4aa13122010-05-12 15:54:44 -0700389 "Could not add flood port action")
390 act.port = ofp.OFPP_IN_PORT
391 self.assertTrue(request.actions.add(act),
392 "Could not add ingress port for output")
393 pa_logger.info(request.show())
394
395 pa_logger.info("Inserting flow")
396 rv = self.controller.message_send(request)
397 self.assertTrue(rv != -1, "Error installing flow mod")
398 do_barrier(self.controller)
399
400 pa_logger.info("Sending packet to dp port " + str(ingress_port))
401 self.dataplane.send(ingress_port, str(pkt))
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700402 receive_pkt_check(self.dataplane, pkt, of_ports, [], self,
403 pa_logger)
Dan Talayco4aa13122010-05-12 15:54:44 -0700404
405class All(basic.SimpleDataPlane):
406 """
407 Send to OFPP_ALL port
408
409 Generate a packet
410 Generate and install a matching flow
411 Add action to forward to OFPP_ALL
412 Send the packet to ingress dataplane port
413 Verify the packet is received at all other ports
414 """
415 def runTest(self):
416 global pa_port_map
417 of_ports = pa_port_map.keys()
418 of_ports.sort()
419 self.assertTrue(len(of_ports) > 1, "Not enough ports for test")
420
421 pkt = simple_tcp_packet()
422 match = parse.packet_to_flow_match(pkt)
423 match.wildcards &= ~ofp.OFPFW_IN_PORT
424 self.assertTrue(match is not None,
425 "Could not generate flow match from pkt")
426 act = action.action_output()
427
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700428 for ingress_port in of_ports:
429 rv = delete_all_flows(self.controller, pa_logger)
430 self.assertEqual(rv, 0, "Failed to delete all flows")
Dan Talayco4aa13122010-05-12 15:54:44 -0700431
Dan Talayco4aa13122010-05-12 15:54:44 -0700432 pa_logger.info("Ingress " + str(ingress_port) + " to all ports")
Dan Talayco4aa13122010-05-12 15:54:44 -0700433 match.in_port = ingress_port
434
435 request = message.flow_mod()
436 request.match = match
437 request.buffer_id = 0xffffffff
438 act.port = ofp.OFPP_ALL
439 self.assertTrue(request.actions.add(act),
440 "Could not add ALL port action")
441 pa_logger.info(request.show())
442
443 pa_logger.info("Inserting flow")
444 rv = self.controller.message_send(request)
445 self.assertTrue(rv != -1, "Error installing flow mod")
446 do_barrier(self.controller)
447
448 pa_logger.info("Sending packet to dp port " + str(ingress_port))
449 self.dataplane.send(ingress_port, str(pkt))
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700450 yes_ports = set(of_ports).difference([ingress_port])
451 receive_pkt_check(self.dataplane, pkt, yes_ports, [ingress_port],
452 self, pa_logger)
Dan Talayco4aa13122010-05-12 15:54:44 -0700453
454class AllPlusIngress(basic.SimpleDataPlane):
455 """
456 Send to OFPP_ALL port and ingress port
457
458 Generate a packet
459 Generate and install a matching flow
460 Add action to forward to OFPP_ALL
461 Add action to forward to ingress port
462 Send the packet to ingress dataplane port
463 Verify the packet is received at all other ports
464 """
465 def runTest(self):
466 global pa_port_map
467 of_ports = pa_port_map.keys()
468 of_ports.sort()
469 self.assertTrue(len(of_ports) > 1, "Not enough ports for test")
470
471 pkt = simple_tcp_packet()
472 match = parse.packet_to_flow_match(pkt)
473 match.wildcards &= ~ofp.OFPFW_IN_PORT
474 self.assertTrue(match is not None,
475 "Could not generate flow match from pkt")
476 act = action.action_output()
477
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700478 for ingress_port in of_ports:
479 rv = delete_all_flows(self.controller, pa_logger)
480 self.assertEqual(rv, 0, "Failed to delete all flows")
Dan Talayco4aa13122010-05-12 15:54:44 -0700481
Dan Talayco4aa13122010-05-12 15:54:44 -0700482 pa_logger.info("Ingress " + str(ingress_port) + " to all ports")
Dan Talayco4aa13122010-05-12 15:54:44 -0700483 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")
Dan Talayco3be5b062010-05-12 15:46:21 -0700491 act.port = ofp.OFPP_IN_PORT
492 self.assertTrue(request.actions.add(act),
493 "Could not add ingress port for output")
494 pa_logger.info(request.show())
495
496 pa_logger.info("Inserting flow")
497 rv = self.controller.message_send(request)
498 self.assertTrue(rv != -1, "Error installing flow mod")
499 do_barrier(self.controller)
500
501 pa_logger.info("Sending packet to dp port " + str(ingress_port))
502 self.dataplane.send(ingress_port, str(pkt))
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700503 receive_pkt_check(self.dataplane, pkt, of_ports, [], self,
504 pa_logger)
505
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700506class FloodMinusPort(basic.SimpleDataPlane):
507 """
508 Config port with No_Flood and test Flood action
509
510 Generate a packet
511 Generate a matching flow
512 Add action to forward to OFPP_ALL
513 Set port to no-flood
514 Send the packet to ingress dataplane port
515 Verify the packet is received at all other ports except
516 the ingress port and the no_flood port
517 """
518 def runTest(self):
519 global pa_port_map
520 of_ports = pa_port_map.keys()
521 of_ports.sort()
522 self.assertTrue(len(of_ports) > 2, "Not enough ports for test")
523
524 pkt = simple_tcp_packet()
525 match = parse.packet_to_flow_match(pkt)
526 match.wildcards &= ~ofp.OFPFW_IN_PORT
527 self.assertTrue(match is not None,
528 "Could not generate flow match from pkt")
529 act = action.action_output()
530
531 for idx in range(len(of_ports)):
532 rv = delete_all_flows(self.controller, pa_logger)
533 self.assertEqual(rv, 0, "Failed to delete all flows")
534
535 ingress_port = of_ports[idx]
536 no_flood_idx = (idx + 1) % len(of_ports)
537 no_flood_port = of_ports[no_flood_idx]
538 rv = port_config_set(self.controller, no_flood_port,
539 ofp.OFPPC_NO_FLOOD, ofp.OFPPC_NO_FLOOD,
540 pa_logger)
541 self.assertEqual(rv, 0, "Failed to set port config")
542
543 match.in_port = ingress_port
544
545 request = message.flow_mod()
546 request.match = match
547 request.buffer_id = 0xffffffff
548 act.port = ofp.OFPP_FLOOD
549 self.assertTrue(request.actions.add(act),
550 "Could not add flood port action")
551 pa_logger.info(request.show())
552
553 pa_logger.info("Inserting flow")
554 rv = self.controller.message_send(request)
555 self.assertTrue(rv != -1, "Error installing flow mod")
556 do_barrier(self.controller)
557
558 pa_logger.info("Sending packet to dp port " + str(ingress_port))
559 pa_logger.info("No flood port is " + str(no_flood_port))
560 self.dataplane.send(ingress_port, str(pkt))
561 no_ports = set([ingress_port, no_flood_port])
562 yes_ports = set(of_ports).difference(no_ports)
563 receive_pkt_check(self.dataplane, pkt, yes_ports, no_ports, self,
564 pa_logger)
565
566 # Turn no flood off again
567 rv = port_config_set(self.controller, no_flood_port,
568 0, ofp.OFPPC_NO_FLOOD, pa_logger)
569 self.assertEqual(rv, 0, "Failed to reset port config")
570
571 #@todo Should check no other packets received
572
Tatsuya Yabe6a6f38a2010-05-22 23:48:04 -0700573class SimpleExactMatch(basic.SimpleDataPlane):
574 """
575 Exercise exact matching for all ports
576
577 Generate a packet
578 Generate and install a matching flow without wildcard mask
579 Add action to forward to a port
580 Send the packet to the port
581 Verify the packet is received at all other ports (one port at a time)
Tatsuya Yabe0718ad32010-05-24 15:22:10 -0700582 Verify flow_expiration message is correct when command option is set
Tatsuya Yabe6a6f38a2010-05-22 23:48:04 -0700583 """
Tatsuya Yabe0718ad32010-05-24 15:22:10 -0700584 IP_ETHTYPE = 0x800
585 TCP_PROTOCOL = 0x6
586 UDP_PROTOCOL = 0x11
587
Tatsuya Yabe6a6f38a2010-05-22 23:48:04 -0700588 def runTest(self):
589 self.flowMatchTest()
590
Tatsuya Yabe0718ad32010-05-24 15:22:10 -0700591 def flowMatchTest(self, wildcards=0, check_expire=False):
Tatsuya Yabe6a6f38a2010-05-22 23:48:04 -0700592 global pa_port_map
593 of_ports = pa_port_map.keys()
594 of_ports.sort()
595 self.assertTrue(len(of_ports) > 1, "Not enough ports for test")
596
597 pkt = simple_tcp_packet()
598 match = parse.packet_to_flow_match(pkt)
599 self.assertTrue(match is not None,
600 "Could not generate flow match from pkt")
Tatsuya Yabe0718ad32010-05-24 15:22:10 -0700601 match.dl_vlan = ofp.OFP_VLAN_NONE
602 match.nw_proto = self.TCP_PROTOCOL
Tatsuya Yabe6a6f38a2010-05-22 23:48:04 -0700603 match.wildcards = wildcards
604
Tatsuya Yabe6a6f38a2010-05-22 23:48:04 -0700605 for idx in range(len(of_ports)):
Tatsuya Yabe6a6f38a2010-05-22 23:48:04 -0700606 ingress_port = of_ports[idx]
607 pa_logger.info("Ingress " + str(ingress_port) + " to all the other ports")
Tatsuya Yabe6a6f38a2010-05-22 23:48:04 -0700608 match.in_port = ingress_port
609
Tatsuya Yabe6a6f38a2010-05-22 23:48:04 -0700610 for egr_idx in range(len(of_ports)):
611 if egr_idx == idx:
612 continue
Tatsuya Yabecdf575e2010-05-25 16:56:38 -0700613
614 rc = delete_all_flows(self.controller, pa_logger)
615 self.assertEqual(rc, 0, "Failed to delete all flows")
616 do_barrier(self.controller)
617
618 request = message.flow_mod()
619 request.match = match
620 request.buffer_id = 0xffffffff
621 #@todo Need UI to setup FLAGS parameter for flow_mod
622 if(check_expire):
623 request.flags |= ofp.OFPFF_SEND_FLOW_REM
624 request.hard_timeout = 1
625
626 act = action.action_output()
Tatsuya Yabe6a6f38a2010-05-22 23:48:04 -0700627 act.port = of_ports[egr_idx]
628 self.assertTrue(request.actions.add(act),
629 "Could not add output action")
630 pa_logger.info(request.show())
631
632 pa_logger.info("Inserting flow")
633 rv = self.controller.message_send(request)
634 self.assertTrue(rv != -1, "Error installing flow mod")
635 do_barrier(self.controller)
636
637 pa_logger.info("Sending packet to dp port " +str(ingress_port))
638 self.dataplane.send(ingress_port, str(pkt))
639
640 ofport = of_ports[egr_idx]
Tatsuya Yabecdf575e2010-05-25 16:56:38 -0700641 self.verifPkt(ofport, pkt)
Tatsuya Yabe6a6f38a2010-05-22 23:48:04 -0700642
Tatsuya Yabe0718ad32010-05-24 15:22:10 -0700643 #@todo Need UI for enabling response-verification
644 if(check_expire):
Tatsuya Yabecdf575e2010-05-25 16:56:38 -0700645 self.verifFlowRemoved(request)
Tatsuya Yabe6a6f38a2010-05-22 23:48:04 -0700646
Tatsuya Yabecdf575e2010-05-25 16:56:38 -0700647 def verifPkt(self, ofport, exp_pkt):
648 (rcv_port, rcv_pkt, pkt_time) = self.dataplane.poll(
649 port_number=ofport, timeout=1)
650 self.assertTrue(rcv_pkt is not None,
651 "Did not receive packet port " + str(ofport))
652 pa_logger.debug("Packet len " + str(len(rcv_pkt)) + " in on "
653 + str(rcv_port))
Tatsuya Yabe6a6f38a2010-05-22 23:48:04 -0700654
Tatsuya Yabecdf575e2010-05-25 16:56:38 -0700655 self.assertEqual(str(exp_pkt), str(rcv_pkt),
656 'Response packet does not match send packet ' +
657 "on port " + str(ofport))
658
659 def verifFlowRemoved(self, request):
660 (response, raw) = self.controller.poll(ofp.OFPT_FLOW_REMOVED, 2)
661 self.assertTrue(response is not None,
662 'Flow removed message not received')
663
664 req_match = request.match
665 res_match = response.match
666 if(req_match != res_match):
667 self.verifMatchField(req_match, res_match)
668
669 self.assertEqual(request.cookie, response.cookie,
670 self.matchErrStr('cookie'))
671 if (req_match.wildcards != 0):
672 self.assertEqual(request.priority, response.priority,
673 self.matchErrStr('priority'))
674 self.assertEqual(response.reason, ofp.OFPRR_HARD_TIMEOUT,
675 'Reason is not HARD TIMEOUT')
676 self.assertEqual(response.packet_count, 1,
677 'Packet count is not correct')
678 self.assertEqual(response.byte_count, len(pkt),
679 'Packet length is not correct')
Tatsuya Yabe6a6f38a2010-05-22 23:48:04 -0700680
681 def verifMatchField(self, req_match, res_match):
682 self.assertEqual(str(req_match.wildcards), str(res_match.wildcards),
683 self.matchErrStr('wildcards'))
684 self.assertEqual(str(req_match.in_port), str(res_match.in_port),
685 self.matchErrStr('in_port'))
686 self.assertEqual(str(req_match.dl_src), str(res_match.dl_src),
687 self.matchErrStr('dl_src'))
688 self.assertEqual(str(req_match.dl_dst), str(res_match.dl_dst),
689 self.matchErrStr('dl_dst'))
690 self.assertEqual(str(req_match.dl_vlan), str(res_match.dl_vlan),
691 self.matchErrStr('dl_vlan'))
692 self.assertEqual(str(req_match.dl_vlan_pcp), str(res_match.dl_vlan_pcp),
693 self.matchErrStr('dl_vlan_pcp'))
694 self.assertEqual(str(req_match.dl_type), str(res_match.dl_type),
695 self.matchErrStr('dl_type'))
Tatsuya Yabe0718ad32010-05-24 15:22:10 -0700696 if(not(req_match.wildcards & ofp.OFPFW_DL_TYPE)
697 and (req_match.dl_type == self.IP_ETHERTYPE)):
698 self.assertEqual(str(req_match.nw_tos), str(res_match.nw_tos),
699 self.matchErrStr('nw_tos'))
700 self.assertEqual(str(req_match.nw_proto), str(res_match.nw_proto),
701 self.matchErrStr('nw_proto'))
702 self.assertEqual(str(req_match.nw_src), str(res_match.nw_src),
703 self.matchErrStr('nw_src'))
704 self.assertEqual(str(req_match.nw_dst), str(res_match.nw_dst),
705 self.matchErrStr('nw_dst'))
706 if(not(req_match.wildcards & ofp.OFPFW_NW_PROTO)
707 and ((req_match.nw_proto == self.TCP_PROTOCOL)
708 or (req_match.nw_proto == self.UDP_PROTOCOL))):
709 self.assertEqual(str(req_match.tp_src), str(res_match.tp_src),
710 self.matchErrStr('tp_src'))
711 self.assertEqual(str(req_match.tp_dst), str(res_match.tp_dst),
712 self.matchErrStr('tp_dst'))
Tatsuya Yabe6a6f38a2010-05-22 23:48:04 -0700713
714 def matchErrStr(self, field):
715 return ('Response Match_' + field + ' does not match send message')
716
717class SingleWildcardMatch(SimpleExactMatch):
718 """
719 Exercise wildcard matching for all ports
720
721 Generate a packet
722 Generate and install a matching flow with wildcard mask
723 Add action to forward to a port
724 Send the packet to the port
725 Verify the packet is received at all other ports (one port at a time)
Tatsuya Yabe0718ad32010-05-24 15:22:10 -0700726 Verify flow_expiration message is correct when command option is set
Tatsuya Yabe6a6f38a2010-05-22 23:48:04 -0700727 """
Tatsuya Yabe0718ad32010-05-24 15:22:10 -0700728 def __init__(self):
729 SimpleExactMatch.__init__(self)
730 self.wildcards = [ofp.OFPFW_IN_PORT,
731 ofp.OFPFW_DL_VLAN,
732 ofp.OFPFW_DL_SRC,
733 ofp.OFPFW_DL_DST,
734 ofp.OFPFW_DL_TYPE,
735 ofp.OFPFW_NW_PROTO,
736 ofp.OFPFW_TP_SRC,
737 ofp.OFPFW_TP_DST,
738 0x3F << ofp.OFPFW_NW_SRC_SHIFT,
739 0x3F << ofp.OFPFW_NW_DST_SHIFT,
740 ofp.OFPFW_DL_VLAN_PCP,
741 ofp.OFPFW_NW_TOS]
Tatsuya Yabe6a6f38a2010-05-22 23:48:04 -0700742
Tatsuya Yabe0718ad32010-05-24 15:22:10 -0700743 def runTest(self):
744 for exec_wildcard in range(len(self.wildcards)):
Tatsuya Yabe6a6f38a2010-05-22 23:48:04 -0700745 self.flowMatchTest(exec_wildcard)
Tatsuya Yabe4fad7e32010-05-24 15:24:50 -0700746
747class AllExceptOneWildcardMatch(SingleWildcardMatch):
748 """
749 Create All-execpt-one-field wildcard and exercise for all ports
750
751 Generate a packet
752 Generate and install a matching flow with wildcard all except one filed
753 Add action to forward to a port
754 Send the packet to the port
755 Verify the packet is received at all other ports (one port at a time)
756 Verify flow_expiration message is correct when command option is set
757 """
758 def runTest(self):
759 for exec_wildcard in range(len(self.wildcards)):
760 all_exp_one_wildcard = ofp.OFPFW_ALL ^ self.wildcards[exec_wildcard]
761 self.flowMatchTest(all_exp_one_wildcard)
Tatsuya Yabee30ebe22010-05-25 09:30:49 -0700762
763class AllWildcardMatch(SingleWildcardMatch):
764 """
765 Create Wildcard-all flow and exercise for all ports
766
767 Generate a packet
768 Generate and install a matching flow with wildcard-all
769 Add action to forward to a port
770 Send the packet to the port
771 Verify the packet is received at all other ports (one port at a time)
772 Verify flow_expiration message is correct when command option is set
773 """
774 def runTest(self):
775 self.flowMatchTest(ofp.OFPFW_ALL)
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -0700776
777class ExactModifyAction(SimpleExactMatch):
778 """
779 Perform Modify action with exact matching for all ports
780
781 Generate a packet for transmit
782 Generate the expected packet
783 Generate and install a matching flow with a modify action and
784 an output action without wildcard mask
785 Send the packet to the port
786 Verify the expected packet is received at all other ports
787 (one port at a time)
788 Verify flow_expiration message is correct when command option is set
789 """
790 def __init__(self):
791 SimpleExactMatch.__init__(self)
792 self.modify_act = [ofp.OFPAT_SET_VLAN_VID,
793 ofp.OFPAT_SET_VLAN_PCP,
794 ofp.OFPAT_STRIP_VLAN,
795 ofp.OFPAT_SET_DL_SRC,
796 ofp.OFPAT_SET_DL_DST,
797 ofp.OFPAT_SET_NW_SRC,
798 ofp.OFPAT_SET_NW_DST,
799 ofp.OFPAT_SET_NW_TOS,
800 ofp.OFPAT_SET_TP_SRC,
801 ofp.OFPAT_SET_TP_DST]
802
803 def runTest(self):
804 self.flowMatchModTest()
805
806 def flowMatchModTest(self, wildcards=0, check_expire=False):
807 global pa_port_map
808 of_ports = pa_port_map.keys()
809 of_ports.sort()
810 self.assertTrue(len(of_ports) > 1, "Not enough ports for test")
811
812 mod_dl_dst = '43:21:0F:ED:CB:A9'
813 mod_dl_src = '7F:ED:CB:A9:87:65'
814 mod_dl_vlan = 4094
815 mod_dl_vlan_pcp = 7
816 mod_ip_src = '10.20.30.40'
817 mod_ip_dst = '50.60.70.80'
818 mod_ip_tos = 0xf0
819 mod_tcp_sport = 4321
820 mod_tcp_dport = 8765
821
Tatsuya Yabef5ffb972010-05-26 15:36:33 -0700822 request = message.features_request()
823 (reply, pkt) = self.controller.transact(request, timeout=2)
824 self.assertTrue(reply is not None, "Did not get response to ftr req")
825 supported_act = reply.actions
826
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -0700827 for idx in range(len(of_ports)):
828 ingress_port = of_ports[idx]
829 pa_logger.info("Ingress " + str(ingress_port) + " to all the other ports")
830
831 for egr_idx in range(len(of_ports)):
832 if egr_idx == idx:
833 continue
834
835 for exec_mod in range(len(self.modify_act)):
836 pkt_len = 100
837 dl_dst = '0C:DE:F0:12:34:56'
838 dl_src = '01:23:45:67:89:AB'
839 dl_vlan_enable = False
840 dl_vlan = 0
841 dl_vlan_pcp = 0
842 ip_src = '192.168.0.1'
843 ip_dst = '192.168.0.2'
844 ip_tos = 0
845 tcp_sport = 1234
846 tcp_dport = 80
847
848 rc = delete_all_flows(self.controller, pa_logger)
849 self.assertEqual(rc, 0, "Failed to delete all flows")
850 do_barrier(self.controller)
851
852 pkt = simple_tcp_packet(pktlen=pkt_len,
853 dl_dst=dl_dst,
854 dl_src=dl_src,
855 dl_vlan_enable=dl_vlan_enable,
856 dl_vlan=dl_vlan,
857 dl_vlan_pcp=dl_vlan_pcp,
858 ip_src=ip_src,
859 ip_dst=ip_dst,
860 ip_tos=ip_tos,
861 tcp_sport=tcp_sport,
862 tcp_dport=tcp_dport)
863
864 match = parse.packet_to_flow_match(pkt)
865 self.assertTrue(match is not None,
866 "Could not generate flow match from pkt")
867 match.in_port = ingress_port
868 match.dl_vlan = ofp.OFP_VLAN_NONE
869 match.nw_proto = self.TCP_PROTOCOL
870 match.wildcards = wildcards
871
872 request = message.flow_mod()
873 request.match = match
874 request.buffer_id = 0xffffffff
875 #@todo Need UI to setup FLAGS parameter for flow_mod
876 if(check_expire):
877 request.flags |= ofp.OFPFF_SEND_FLOW_REM
878 request.hard_timeout = 1
879
880 exec_act = self.modify_act[exec_mod]
881 if exec_act == ofp.OFPAT_SET_VLAN_VID:
Tatsuya Yabef5ffb972010-05-26 15:36:33 -0700882 if not(supported_act & 1<<ofp.OFPAT_SET_VLAN_VID):
883 continue
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -0700884 pkt_len = pkt_len + 4
885 dl_vlan_enable = True
886 dl_vlan = mod_dl_vlan
887 mod_act = action.action_set_vlan_vid()
888 mod_act.vlan_vid = mod_dl_vlan
Tatsuya Yabe17195a02010-05-26 15:29:55 -0700889 elif exec_act == ofp.OFPAT_SET_VLAN_PCP:
Tatsuya Yabef5ffb972010-05-26 15:36:33 -0700890 if not(supported_act & 1<<ofp.OFPAT_SET_VLAN_PCP):
891 continue
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -0700892 pkt_len = pkt_len + 4
893 dl_vlan_enable = True
894 dl_vlan_pcp = mod_dl_vlan_pcp
895 mod_act = action.action_set_vlan_pcp()
896 mod_act.vlan_pcp = mod_dl_vlan_pcp
Tatsuya Yabe17195a02010-05-26 15:29:55 -0700897 elif exec_act == ofp.OFPAT_STRIP_VLAN:
Tatsuya Yabef5ffb972010-05-26 15:36:33 -0700898 if not(supported_act & 1<<ofp.OFPAT_STRIP_VLAN):
899 continue
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -0700900 dl_vlan_enable = False
901 mod_act = action.action_strip_vlan()
Tatsuya Yabe17195a02010-05-26 15:29:55 -0700902 elif exec_act == ofp.OFPAT_SET_DL_SRC:
Tatsuya Yabef5ffb972010-05-26 15:36:33 -0700903 if not(supported_act & 1<<ofp.OFPAT_SET_DL_SRC):
904 continue
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -0700905 dl_src = mod_dl_src
906 mod_act = action.action_set_dl_src()
907 mod_act.dl_addr = parse.parse_mac(mod_dl_src)
Tatsuya Yabe17195a02010-05-26 15:29:55 -0700908 elif exec_act == ofp.OFPAT_SET_DL_DST:
Tatsuya Yabef5ffb972010-05-26 15:36:33 -0700909 if not(supported_act & 1<<ofp.OFPAT_SET_DL_DST):
910 continue
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -0700911 dl_dst = mod_dl_dst
912 mod_act = action.action_set_dl_dst()
913 mod_act.dl_addr = parse.parse_mac(mod_dl_dst)
Tatsuya Yabe17195a02010-05-26 15:29:55 -0700914 elif exec_act == ofp.OFPAT_SET_NW_SRC:
Tatsuya Yabef5ffb972010-05-26 15:36:33 -0700915 if not(supported_act & 1<<ofp.OFPAT_SET_NW_SRC):
916 continue
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -0700917 ip_src = mod_ip_src
918 mod_act = action.action_set_nw_src()
919 mod_act.nw_addr = parse.parse_ip(mod_ip_src)
Tatsuya Yabe17195a02010-05-26 15:29:55 -0700920 elif exec_act == ofp.OFPAT_SET_NW_DST:
Tatsuya Yabef5ffb972010-05-26 15:36:33 -0700921 if not(supported_act & 1<<ofp.OFPAT_SET_NW_DST):
922 continue
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -0700923 ip_dst = mod_ip_dst
924 mod_act = action.action_set_nw_dst()
925 mod_act.nw_addr = parse.parse_ip(mod_ip_dst)
Tatsuya Yabe17195a02010-05-26 15:29:55 -0700926 elif exec_act == ofp.OFPAT_SET_NW_TOS:
Tatsuya Yabef5ffb972010-05-26 15:36:33 -0700927 if not(supported_act & 1<<ofp.OFPAT_SET_NW_TOS):
928 continue
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -0700929 ip_tos = mod_ip_tos
930 mod_act = action.action_set_nw_tos()
931 mod_act.nw_tos = mod_ip_tos
Tatsuya Yabe17195a02010-05-26 15:29:55 -0700932 elif exec_act == ofp.OFPAT_SET_TP_SRC:
Tatsuya Yabef5ffb972010-05-26 15:36:33 -0700933 if not(supported_act & 1<<ofp.OFPAT_SET_TP_SRC):
934 continue
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -0700935 tcp_sport = mod_tcp_sport
936 mod_act = action.action_set_tp_src()
937 mod_act.tp_port = mod_tcp_sport
Tatsuya Yabe17195a02010-05-26 15:29:55 -0700938 elif exec_act == ofp.OFPAT_SET_TP_DST:
Tatsuya Yabef5ffb972010-05-26 15:36:33 -0700939 if not(supported_act & 1<<ofp.OFPAT_SET_TP_DST):
940 continue
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -0700941 tcp_dport = mod_tcp_dport
942 mod_act = action.action_set_tp_dst()
943 mod_act.tp_port = mod_tcp_dport
Tatsuya Yabe17195a02010-05-26 15:29:55 -0700944 else:
945 continue
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -0700946
947 self.assertTrue(request.actions.add(mod_act),
948 "Could not add output action")
949 pa_logger.info(request.show())
950
951 exp_pkt = simple_tcp_packet(pktlen=pkt_len,
952 dl_dst=dl_dst,
953 dl_src=dl_src,
954 dl_vlan_enable=dl_vlan_enable,
955 dl_vlan=dl_vlan,
956 dl_vlan_pcp=dl_vlan_pcp,
957 ip_src=ip_src,
958 ip_dst=ip_dst,
959 ip_tos=ip_tos,
960 tcp_sport=tcp_sport,
961 tcp_dport=tcp_dport)
962
963 act = action.action_output()
964 act.port = of_ports[egr_idx]
965 self.assertTrue(request.actions.add(act),
966 "Could not add output action")
967 pa_logger.info(request.show())
968
969 pa_logger.info("Inserting flow")
970 rv = self.controller.message_send(request)
971 self.assertTrue(rv != -1, "Error installing flow mod")
972 do_barrier(self.controller)
973
974 pa_logger.info("Sending packet to dp port " +str(ingress_port))
975 self.dataplane.send(ingress_port, str(pkt))
976
977 ofport = of_ports[egr_idx]
978 self.verifPkt(ofport, exp_pkt)
979
980 #@todo Need UI for enabling response-verification
981 if(check_expire):
982 self.verifFlowRemoved(request)
Tatsuya Yabe9c31e222010-06-16 13:48:02 -0700983
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700984if __name__ == "__main__":
985 print "Please run through oft script: ./oft --test_spec=basic"