blob: be7d7ed7ad496a8c9321046aa11bf214da16cbbf [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
Dan Talayco551befa2010-07-15 17:05:32 -070042# For test priority
43#@var test_prio Set test priority for local tests
44test_prio = {}
45
46WILDCARD_VALUES = [ofp.OFPFW_IN_PORT,
47 ofp.OFPFW_DL_VLAN,
48 ofp.OFPFW_DL_SRC,
49 ofp.OFPFW_DL_DST,
50 ofp.OFPFW_DL_TYPE,
51 ofp.OFPFW_NW_PROTO,
52 ofp.OFPFW_TP_SRC,
53 ofp.OFPFW_TP_DST,
54 0x3F << ofp.OFPFW_NW_SRC_SHIFT,
55 0x3F << ofp.OFPFW_NW_DST_SHIFT,
56 ofp.OFPFW_DL_VLAN_PCP,
57 ofp.OFPFW_NW_TOS]
58
59MODIFY_ACTION_VALUES = [ofp.OFPAT_SET_VLAN_VID,
60 ofp.OFPAT_SET_VLAN_PCP,
61 ofp.OFPAT_STRIP_VLAN,
62 ofp.OFPAT_SET_DL_SRC,
63 ofp.OFPAT_SET_DL_DST,
64 ofp.OFPAT_SET_NW_SRC,
65 ofp.OFPAT_SET_NW_DST,
66 ofp.OFPAT_SET_NW_TOS,
67 ofp.OFPAT_SET_TP_SRC,
68 ofp.OFPAT_SET_TP_DST]
69
70# Cache supported features to avoid transaction overhead
71cached_supported_actions = None
72
Dan Talayco21381562010-07-17 00:34:47 -070073TEST_VID_DEFAULT = 2
74
Dan Talayco5eba8442010-03-10 13:58:43 -080075def test_set_init(config):
76 """
77 Set up function for packet action test classes
78
79 @param config The configuration dictionary; see oft
80 """
81
82 global pa_port_map
83 global pa_logger
84 global pa_config
85
86 pa_logger = logging.getLogger("pkt_act")
87 pa_logger.info("Initializing test set")
88 pa_port_map = config["port_map"]
89 pa_config = config
90
91class DirectPacket(basic.SimpleDataPlane):
92 """
Dan Talayco2d0d49a2010-05-11 15:29:08 -070093 Send packet to single egress port
Dan Talayco5eba8442010-03-10 13:58:43 -080094
95 Generate a packet
96 Generate and install a matching flow
97 Add action to direct the packet to an egress port
98 Send the packet to ingress dataplane port
99 Verify the packet is received at the egress port only
100 """
101 def runTest(self):
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700102 self.handleFlow()
103
104 def handleFlow(self, pkttype='TCP'):
Dan Talayco5eba8442010-03-10 13:58:43 -0800105 of_ports = pa_port_map.keys()
106 of_ports.sort()
107 self.assertTrue(len(of_ports) > 1, "Not enough ports for test")
108
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700109 if (pkttype == 'ICMP'):
110 pkt = simple_icmp_packet()
111 else:
112 pkt = simple_tcp_packet()
Dan Talayco5eba8442010-03-10 13:58:43 -0800113 match = parse.packet_to_flow_match(pkt)
Dan Talayco7dd6cd62010-03-16 15:02:35 -0700114 match.wildcards &= ~ofp.OFPFW_IN_PORT
Dan Talayco5eba8442010-03-10 13:58:43 -0800115 self.assertTrue(match is not None,
116 "Could not generate flow match from pkt")
117 act = action.action_output()
118
119 for idx in range(len(of_ports)):
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700120 rv = delete_all_flows(self.controller, pa_logger)
121 self.assertEqual(rv, 0, "Failed to delete all flows")
Dan Talayco2e77a842010-05-12 15:39:46 -0700122
Dan Talayco5eba8442010-03-10 13:58:43 -0800123 ingress_port = of_ports[idx]
124 egress_port = of_ports[(idx + 1) % len(of_ports)]
125 pa_logger.info("Ingress " + str(ingress_port) +
Dan Talayco551befa2010-07-15 17:05:32 -0700126 " to egress " + str(egress_port))
Dan Talayco5eba8442010-03-10 13:58:43 -0800127
128 match.in_port = ingress_port
129
130 request = message.flow_mod()
131 request.match = match
132 request.buffer_id = 0xffffffff
133 act.port = egress_port
134 self.assertTrue(request.actions.add(act), "Could not add action")
135
136 pa_logger.info("Inserting flow")
137 rv = self.controller.message_send(request)
138 self.assertTrue(rv != -1, "Error installing flow mod")
139 do_barrier(self.controller)
140
141 pa_logger.info("Sending packet to dp port " +
142 str(ingress_port))
143 self.dataplane.send(ingress_port, str(pkt))
144 (rcv_port, rcv_pkt, pkt_time) = self.dataplane.poll(timeout=1)
145 self.assertTrue(rcv_pkt is not None, "Did not receive packet")
Dan Talayco2d0d49a2010-05-11 15:29:08 -0700146 pa_logger.debug("Packet len " + str(len(rcv_pkt)) + " in on " +
Dan Talayco5eba8442010-03-10 13:58:43 -0800147 str(rcv_port))
148 self.assertEqual(rcv_port, egress_port, "Unexpected receive port")
149 self.assertEqual(str(pkt), str(rcv_pkt),
150 'Response packet does not match send packet')
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700151
152class DirectPacketICMP(DirectPacket):
153 """
154 Send ICMP packet to single egress port
155
156 Generate a ICMP packet
157 Generate and install a matching flow
158 Add action to direct the packet to an egress port
159 Send the packet to ingress dataplane port
160 Verify the packet is received at the egress port only
161 Difference from DirectPacket test is that sent packet is ICMP
162 """
163 def runTest(self):
164 self.handleFlow(pkttype='ICMP')
Dan Talayco2d0d49a2010-05-11 15:29:08 -0700165
166class DirectTwoPorts(basic.SimpleDataPlane):
167 """
168 Send packet to two egress ports
169
170 Generate a packet
171 Generate and install a matching flow
172 Add action to direct the packet to two egress ports
173 Send the packet to ingress dataplane port
174 Verify the packet is received at the two egress ports
175 """
176 def runTest(self):
Dan Talayco2d0d49a2010-05-11 15:29:08 -0700177 of_ports = pa_port_map.keys()
178 of_ports.sort()
179 self.assertTrue(len(of_ports) > 2, "Not enough ports for test")
180
Dan Talayco2d0d49a2010-05-11 15:29:08 -0700181 pkt = simple_tcp_packet()
182 match = parse.packet_to_flow_match(pkt)
183 match.wildcards &= ~ofp.OFPFW_IN_PORT
184 self.assertTrue(match is not None,
185 "Could not generate flow match from pkt")
186 act = action.action_output()
187
188 for idx in range(len(of_ports)):
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700189 rv = delete_all_flows(self.controller, pa_logger)
190 self.assertEqual(rv, 0, "Failed to delete all flows")
Dan Talayco2e77a842010-05-12 15:39:46 -0700191
Dan Talayco2d0d49a2010-05-11 15:29:08 -0700192 ingress_port = of_ports[idx]
193 egress_port1 = of_ports[(idx + 1) % len(of_ports)]
194 egress_port2 = of_ports[(idx + 2) % len(of_ports)]
195 pa_logger.info("Ingress " + str(ingress_port) +
196 " to egress " + str(egress_port1) + " and " +
197 str(egress_port2))
198
199 match.in_port = ingress_port
200
201 request = message.flow_mod()
202 request.match = match
203 request.buffer_id = 0xffffffff
204 act.port = egress_port1
205 self.assertTrue(request.actions.add(act), "Could not add action1")
206 act.port = egress_port2
207 self.assertTrue(request.actions.add(act), "Could not add action2")
Dan Talaycob0b0fdb2010-05-11 15:44:56 -0700208 # pa_logger.info(request.show())
Dan Talayco2d0d49a2010-05-11 15:29:08 -0700209
210 pa_logger.info("Inserting flow")
211 rv = self.controller.message_send(request)
212 self.assertTrue(rv != -1, "Error installing flow mod")
213 do_barrier(self.controller)
214
215 pa_logger.info("Sending packet to dp port " +
216 str(ingress_port))
217 self.dataplane.send(ingress_port, str(pkt))
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700218 yes_ports = set([egress_port1, egress_port2])
219 no_ports = set(of_ports).difference(yes_ports)
Dan Talayco2d0d49a2010-05-11 15:29:08 -0700220
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700221 receive_pkt_check(self.dataplane, pkt, yes_ports, no_ports,
222 self, pa_logger)
Dan Talaycob0b0fdb2010-05-11 15:44:56 -0700223
224class DirectMCNonIngress(basic.SimpleDataPlane):
225 """
226 Multicast to all non-ingress ports
227
228 Generate a packet
229 Generate and install a matching flow
230 Add action to direct the packet to all non-ingress ports
231 Send the packet to ingress dataplane port
232 Verify the packet is received at all non-ingress ports
233
234 Does not use the flood action
235 """
236 def runTest(self):
Dan Talaycob0b0fdb2010-05-11 15:44:56 -0700237 of_ports = pa_port_map.keys()
238 of_ports.sort()
239 self.assertTrue(len(of_ports) > 2, "Not enough ports for test")
240
Dan Talaycob0b0fdb2010-05-11 15:44:56 -0700241 pkt = simple_tcp_packet()
242 match = parse.packet_to_flow_match(pkt)
243 match.wildcards &= ~ofp.OFPFW_IN_PORT
244 self.assertTrue(match is not None,
245 "Could not generate flow match from pkt")
246 act = action.action_output()
247
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700248 for ingress_port in of_ports:
249 rv = delete_all_flows(self.controller, pa_logger)
250 self.assertEqual(rv, 0, "Failed to delete all flows")
Dan Talayco2e77a842010-05-12 15:39:46 -0700251
Dan Talaycob0b0fdb2010-05-11 15:44:56 -0700252 pa_logger.info("Ingress " + str(ingress_port) +
253 " all non-ingress ports")
Dan Talaycob0b0fdb2010-05-11 15:44:56 -0700254 match.in_port = ingress_port
255
256 request = message.flow_mod()
257 request.match = match
258 request.buffer_id = 0xffffffff
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700259 for egress_port in of_ports:
260 if egress_port == ingress_port:
Dan Talaycob0b0fdb2010-05-11 15:44:56 -0700261 continue
Dan Talaycob0b0fdb2010-05-11 15:44:56 -0700262 act.port = egress_port
263 self.assertTrue(request.actions.add(act),
264 "Could not add output to " + str(egress_port))
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700265 pa_logger.debug(request.show())
Dan Talaycob0b0fdb2010-05-11 15:44:56 -0700266
267 pa_logger.info("Inserting flow")
268 rv = self.controller.message_send(request)
269 self.assertTrue(rv != -1, "Error installing flow mod")
270 do_barrier(self.controller)
271
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700272 pa_logger.info("Sending packet to dp port " + str(ingress_port))
Dan Talaycob0b0fdb2010-05-11 15:44:56 -0700273 self.dataplane.send(ingress_port, str(pkt))
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700274 yes_ports = set(of_ports).difference([ingress_port])
275 receive_pkt_check(self.dataplane, pkt, yes_ports, [ingress_port],
276 self, pa_logger)
Dan Talaycob0b0fdb2010-05-11 15:44:56 -0700277
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):
Dan Talayco32fa6542010-05-11 15:54:08 -0700292 of_ports = pa_port_map.keys()
293 of_ports.sort()
294 self.assertTrue(len(of_ports) > 2, "Not enough ports for test")
295
Dan Talayco32fa6542010-05-11 15:54:08 -0700296 pkt = simple_tcp_packet()
297 match = parse.packet_to_flow_match(pkt)
298 match.wildcards &= ~ofp.OFPFW_IN_PORT
299 self.assertTrue(match is not None,
300 "Could not generate flow match from pkt")
301 act = action.action_output()
302
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700303 for ingress_port in of_ports:
304 rv = delete_all_flows(self.controller, pa_logger)
305 self.assertEqual(rv, 0, "Failed to delete all flows")
Dan Talayco2e77a842010-05-12 15:39:46 -0700306
Dan Talayco32fa6542010-05-11 15:54:08 -0700307 pa_logger.info("Ingress " + str(ingress_port) + " to all ports")
Dan Talayco32fa6542010-05-11 15:54:08 -0700308 match.in_port = ingress_port
309
310 request = message.flow_mod()
311 request.match = match
312 request.buffer_id = 0xffffffff
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700313 for egress_port in of_ports:
314 if egress_port == ingress_port:
Dan Talayco32fa6542010-05-11 15:54:08 -0700315 act.port = ofp.OFPP_IN_PORT
316 else:
317 act.port = egress_port
318 self.assertTrue(request.actions.add(act),
319 "Could not add output to " + str(egress_port))
Dan Talayco2e77a842010-05-12 15:39:46 -0700320 # pa_logger.info(request.show())
321
322 pa_logger.info("Inserting flow")
323 rv = self.controller.message_send(request)
324 self.assertTrue(rv != -1, "Error installing flow mod")
325 do_barrier(self.controller)
326
327 pa_logger.info("Sending packet to dp port " + str(ingress_port))
328 self.dataplane.send(ingress_port, str(pkt))
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700329 receive_pkt_check(self.dataplane, pkt, of_ports, [], self,
330 pa_logger)
Dan Talayco2e77a842010-05-12 15:39:46 -0700331
332class Flood(basic.SimpleDataPlane):
333 """
334 Flood to all ports except ingress
335
336 Generate a packet
337 Generate and install a matching flow
338 Add action to flood the packet
339 Send the packet to ingress dataplane port
340 Verify the packet is received at all other ports
341 """
342 def runTest(self):
Dan Talayco2e77a842010-05-12 15:39:46 -0700343 of_ports = pa_port_map.keys()
344 of_ports.sort()
345 self.assertTrue(len(of_ports) > 1, "Not enough ports for test")
346
347 pkt = simple_tcp_packet()
348 match = parse.packet_to_flow_match(pkt)
349 match.wildcards &= ~ofp.OFPFW_IN_PORT
350 self.assertTrue(match is not None,
351 "Could not generate flow match from pkt")
352 act = action.action_output()
353
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700354 for ingress_port in of_ports:
355 rv = delete_all_flows(self.controller, pa_logger)
356 self.assertEqual(rv, 0, "Failed to delete all flows")
Dan Talayco2e77a842010-05-12 15:39:46 -0700357
Dan Talayco2e77a842010-05-12 15:39:46 -0700358 pa_logger.info("Ingress " + str(ingress_port) + " to all ports")
Dan Talayco2e77a842010-05-12 15:39:46 -0700359 match.in_port = ingress_port
360
361 request = message.flow_mod()
362 request.match = match
363 request.buffer_id = 0xffffffff
364 act.port = ofp.OFPP_FLOOD
365 self.assertTrue(request.actions.add(act),
Dan Talayco4aa13122010-05-12 15:54:44 -0700366 "Could not add flood port action")
Dan Talayco32fa6542010-05-11 15:54:08 -0700367 pa_logger.info(request.show())
368
369 pa_logger.info("Inserting flow")
370 rv = self.controller.message_send(request)
371 self.assertTrue(rv != -1, "Error installing flow mod")
372 do_barrier(self.controller)
373
374 pa_logger.info("Sending packet to dp port " + str(ingress_port))
375 self.dataplane.send(ingress_port, str(pkt))
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700376 yes_ports = set(of_ports).difference([ingress_port])
377 receive_pkt_check(self.dataplane, pkt, yes_ports, [ingress_port],
378 self, pa_logger)
Dan Talayco3be5b062010-05-12 15:46:21 -0700379
Dan Talayco3be5b062010-05-12 15:46:21 -0700380class FloodPlusIngress(basic.SimpleDataPlane):
381 """
382 Flood to all ports plus send to ingress port
383
384 Generate a packet
385 Generate and install a matching flow
386 Add action to flood the packet
387 Add action to send to ingress port
388 Send the packet to ingress dataplane port
389 Verify the packet is received at all other ports
390 """
391 def runTest(self):
Dan Talayco3be5b062010-05-12 15:46:21 -0700392 of_ports = pa_port_map.keys()
393 of_ports.sort()
394 self.assertTrue(len(of_ports) > 1, "Not enough ports for test")
395
396 pkt = simple_tcp_packet()
397 match = parse.packet_to_flow_match(pkt)
398 match.wildcards &= ~ofp.OFPFW_IN_PORT
399 self.assertTrue(match is not None,
400 "Could not generate flow match from pkt")
401 act = action.action_output()
402
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700403 for ingress_port in of_ports:
404 rv = delete_all_flows(self.controller, pa_logger)
405 self.assertEqual(rv, 0, "Failed to delete all flows")
Dan Talayco3be5b062010-05-12 15:46:21 -0700406
Dan Talayco3be5b062010-05-12 15:46:21 -0700407 pa_logger.info("Ingress " + str(ingress_port) + " to all ports")
Dan Talayco3be5b062010-05-12 15:46:21 -0700408 match.in_port = ingress_port
409
410 request = message.flow_mod()
411 request.match = match
412 request.buffer_id = 0xffffffff
413 act.port = ofp.OFPP_FLOOD
414 self.assertTrue(request.actions.add(act),
Dan Talayco4aa13122010-05-12 15:54:44 -0700415 "Could not add flood port action")
416 act.port = ofp.OFPP_IN_PORT
417 self.assertTrue(request.actions.add(act),
418 "Could not add ingress port for output")
419 pa_logger.info(request.show())
420
421 pa_logger.info("Inserting flow")
422 rv = self.controller.message_send(request)
423 self.assertTrue(rv != -1, "Error installing flow mod")
424 do_barrier(self.controller)
425
426 pa_logger.info("Sending packet to dp port " + str(ingress_port))
427 self.dataplane.send(ingress_port, str(pkt))
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700428 receive_pkt_check(self.dataplane, pkt, of_ports, [], self,
429 pa_logger)
Dan Talayco4aa13122010-05-12 15:54:44 -0700430
431class All(basic.SimpleDataPlane):
432 """
433 Send to OFPP_ALL port
434
435 Generate a packet
436 Generate and install a matching flow
437 Add action to forward to OFPP_ALL
438 Send the packet to ingress dataplane port
439 Verify the packet is received at all other ports
440 """
441 def runTest(self):
Dan Talayco4aa13122010-05-12 15:54:44 -0700442 of_ports = pa_port_map.keys()
443 of_ports.sort()
444 self.assertTrue(len(of_ports) > 1, "Not enough ports for test")
445
446 pkt = simple_tcp_packet()
447 match = parse.packet_to_flow_match(pkt)
448 match.wildcards &= ~ofp.OFPFW_IN_PORT
449 self.assertTrue(match is not None,
450 "Could not generate flow match from pkt")
451 act = action.action_output()
452
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700453 for ingress_port in of_ports:
454 rv = delete_all_flows(self.controller, pa_logger)
455 self.assertEqual(rv, 0, "Failed to delete all flows")
Dan Talayco4aa13122010-05-12 15:54:44 -0700456
Dan Talayco4aa13122010-05-12 15:54:44 -0700457 pa_logger.info("Ingress " + str(ingress_port) + " to all ports")
Dan Talayco4aa13122010-05-12 15:54:44 -0700458 match.in_port = ingress_port
459
460 request = message.flow_mod()
461 request.match = match
462 request.buffer_id = 0xffffffff
463 act.port = ofp.OFPP_ALL
464 self.assertTrue(request.actions.add(act),
465 "Could not add ALL port action")
466 pa_logger.info(request.show())
467
468 pa_logger.info("Inserting flow")
469 rv = self.controller.message_send(request)
470 self.assertTrue(rv != -1, "Error installing flow mod")
471 do_barrier(self.controller)
472
473 pa_logger.info("Sending packet to dp port " + str(ingress_port))
474 self.dataplane.send(ingress_port, str(pkt))
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700475 yes_ports = set(of_ports).difference([ingress_port])
476 receive_pkt_check(self.dataplane, pkt, yes_ports, [ingress_port],
477 self, pa_logger)
Dan Talayco4aa13122010-05-12 15:54:44 -0700478
479class AllPlusIngress(basic.SimpleDataPlane):
480 """
481 Send to OFPP_ALL port and ingress port
482
483 Generate a packet
484 Generate and install a matching flow
485 Add action to forward to OFPP_ALL
486 Add action to forward to ingress port
487 Send the packet to ingress dataplane port
488 Verify the packet is received at all other ports
489 """
490 def runTest(self):
Dan Talayco4aa13122010-05-12 15:54:44 -0700491 of_ports = pa_port_map.keys()
492 of_ports.sort()
493 self.assertTrue(len(of_ports) > 1, "Not enough ports for test")
494
495 pkt = simple_tcp_packet()
496 match = parse.packet_to_flow_match(pkt)
497 match.wildcards &= ~ofp.OFPFW_IN_PORT
498 self.assertTrue(match is not None,
499 "Could not generate flow match from pkt")
500 act = action.action_output()
501
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700502 for ingress_port in of_ports:
503 rv = delete_all_flows(self.controller, pa_logger)
504 self.assertEqual(rv, 0, "Failed to delete all flows")
Dan Talayco4aa13122010-05-12 15:54:44 -0700505
Dan Talayco4aa13122010-05-12 15:54:44 -0700506 pa_logger.info("Ingress " + str(ingress_port) + " to all ports")
Dan Talayco4aa13122010-05-12 15:54:44 -0700507 match.in_port = ingress_port
508
509 request = message.flow_mod()
510 request.match = match
511 request.buffer_id = 0xffffffff
512 act.port = ofp.OFPP_ALL
513 self.assertTrue(request.actions.add(act),
514 "Could not add ALL port action")
Dan Talayco3be5b062010-05-12 15:46:21 -0700515 act.port = ofp.OFPP_IN_PORT
516 self.assertTrue(request.actions.add(act),
517 "Could not add ingress port for output")
518 pa_logger.info(request.show())
519
520 pa_logger.info("Inserting flow")
521 rv = self.controller.message_send(request)
522 self.assertTrue(rv != -1, "Error installing flow mod")
523 do_barrier(self.controller)
524
525 pa_logger.info("Sending packet to dp port " + str(ingress_port))
526 self.dataplane.send(ingress_port, str(pkt))
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700527 receive_pkt_check(self.dataplane, pkt, of_ports, [], self,
528 pa_logger)
529
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700530class FloodMinusPort(basic.SimpleDataPlane):
531 """
532 Config port with No_Flood and test Flood action
533
534 Generate a packet
535 Generate a matching flow
536 Add action to forward to OFPP_ALL
537 Set port to no-flood
538 Send the packet to ingress dataplane port
539 Verify the packet is received at all other ports except
540 the ingress port and the no_flood port
541 """
542 def runTest(self):
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700543 of_ports = pa_port_map.keys()
544 of_ports.sort()
545 self.assertTrue(len(of_ports) > 2, "Not enough ports for test")
546
547 pkt = simple_tcp_packet()
548 match = parse.packet_to_flow_match(pkt)
549 match.wildcards &= ~ofp.OFPFW_IN_PORT
550 self.assertTrue(match is not None,
551 "Could not generate flow match from pkt")
552 act = action.action_output()
553
554 for idx in range(len(of_ports)):
555 rv = delete_all_flows(self.controller, pa_logger)
556 self.assertEqual(rv, 0, "Failed to delete all flows")
557
558 ingress_port = of_ports[idx]
559 no_flood_idx = (idx + 1) % len(of_ports)
560 no_flood_port = of_ports[no_flood_idx]
561 rv = port_config_set(self.controller, no_flood_port,
562 ofp.OFPPC_NO_FLOOD, ofp.OFPPC_NO_FLOOD,
563 pa_logger)
564 self.assertEqual(rv, 0, "Failed to set port config")
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_FLOOD
572 self.assertTrue(request.actions.add(act),
573 "Could not add flood port action")
574 pa_logger.info(request.show())
575
576 pa_logger.info("Inserting flow")
577 rv = self.controller.message_send(request)
578 self.assertTrue(rv != -1, "Error installing flow mod")
579 do_barrier(self.controller)
580
581 pa_logger.info("Sending packet to dp port " + str(ingress_port))
582 pa_logger.info("No flood port is " + str(no_flood_port))
583 self.dataplane.send(ingress_port, str(pkt))
584 no_ports = set([ingress_port, no_flood_port])
585 yes_ports = set(of_ports).difference(no_ports)
586 receive_pkt_check(self.dataplane, pkt, yes_ports, no_ports, self,
587 pa_logger)
588
589 # Turn no flood off again
590 rv = port_config_set(self.controller, no_flood_port,
591 0, ofp.OFPPC_NO_FLOOD, pa_logger)
592 self.assertEqual(rv, 0, "Failed to reset port config")
593
594 #@todo Should check no other packets received
595
Dan Talayco21381562010-07-17 00:34:47 -0700596
597
Dan Talayco551befa2010-07-15 17:05:32 -0700598################################################################
599
600class BaseMatchCase(basic.SimpleDataPlane):
601 def setUp(self):
602 basic.SimpleDataPlane.setUp(self)
603 self.logger = pa_logger
604 def runTest(self):
605 self.logger.info("BaseMatchCase")
606
607class ExactMatch(BaseMatchCase):
Tatsuya Yabe6a6f38a2010-05-22 23:48:04 -0700608 """
Dan Talayco551befa2010-07-15 17:05:32 -0700609 Exercise exact matching for all port pairs
Tatsuya Yabe6a6f38a2010-05-22 23:48:04 -0700610
611 Generate a packet
612 Generate and install a matching flow without wildcard mask
613 Add action to forward to a port
614 Send the packet to the port
615 Verify the packet is received at all other ports (one port at a time)
Tatsuya Yabe6a6f38a2010-05-22 23:48:04 -0700616 """
Tatsuya Yabe0718ad32010-05-24 15:22:10 -0700617
Tatsuya Yabe6a6f38a2010-05-22 23:48:04 -0700618 def runTest(self):
Dan Talayco551befa2010-07-15 17:05:32 -0700619 flow_match_test(self, pa_port_map)
Tatsuya Yabe6a6f38a2010-05-22 23:48:04 -0700620
Dan Talayco551befa2010-07-15 17:05:32 -0700621class ExactMatchTagged(BaseMatchCase):
622 """
623 Exact match for all port pairs with tagged pkts
624 """
Tatsuya Yabe6a6f38a2010-05-22 23:48:04 -0700625
Dan Talayco551befa2010-07-15 17:05:32 -0700626 def runTest(self):
Dan Talayco21381562010-07-17 00:34:47 -0700627 vid = TEST_VID_DEFAULT
628 if pa_config["param"] is not None:
629 vid = pa_config["param"]
630 flow_match_test(self, pa_port_map, dl_vlan=vid)
Tatsuya Yabe6a6f38a2010-05-22 23:48:04 -0700631
Dan Talayco551befa2010-07-15 17:05:32 -0700632class ExactMatchTaggedMany(BaseMatchCase):
633 """
634 ExactMatchTagged with many VLANS
635 """
Tatsuya Yabe6a6f38a2010-05-22 23:48:04 -0700636
Dan Talayco551befa2010-07-15 17:05:32 -0700637 def runTest(self):
Dan Talayco21381562010-07-17 00:34:47 -0700638 for vid in range(2,100,10):
Dan Talayco551befa2010-07-15 17:05:32 -0700639 flow_match_test(self, pa_port_map, dl_vlan=vid, max_test=5)
640 for vid in range(100,4000,389):
641 flow_match_test(self, pa_port_map, dl_vlan=vid, max_test=5)
642 flow_match_test(self, pa_port_map, dl_vlan=4094, max_test=5)
Tatsuya Yabecdf575e2010-05-25 16:56:38 -0700643
Dan Talayco551befa2010-07-15 17:05:32 -0700644# Don't run by default
645test_prio["ExactMatchTaggedMany"] = -1
Tatsuya Yabecdf575e2010-05-25 16:56:38 -0700646
Tatsuya Yabecdf575e2010-05-25 16:56:38 -0700647
Dan Talayco551befa2010-07-15 17:05:32 -0700648class SingleWildcardMatch(BaseMatchCase):
Tatsuya Yabe6a6f38a2010-05-22 23:48:04 -0700649 """
650 Exercise wildcard matching for all ports
651
652 Generate a packet
653 Generate and install a matching flow with wildcard mask
654 Add action to forward to a port
655 Send the packet to the port
656 Verify the packet is received at all other ports (one port at a time)
Tatsuya Yabe0718ad32010-05-24 15:22:10 -0700657 Verify flow_expiration message is correct when command option is set
Tatsuya Yabe6a6f38a2010-05-22 23:48:04 -0700658 """
Tatsuya Yabe0718ad32010-05-24 15:22:10 -0700659 def runTest(self):
Dan Talayco551befa2010-07-15 17:05:32 -0700660 for wc in WILDCARD_VALUES:
Dan Talayco21381562010-07-17 00:34:47 -0700661 flow_match_test(self, pa_port_map, wildcards=wc, max_test=10)
Tatsuya Yabe4fad7e32010-05-24 15:24:50 -0700662
Dan Talayco551befa2010-07-15 17:05:32 -0700663class SingleWildcardMatchTagged(BaseMatchCase):
664 """
665 SingleWildcardMatch with tagged packets
666 """
667 def runTest(self):
Dan Talayco21381562010-07-17 00:34:47 -0700668 vid = TEST_VID_DEFAULT
669 if pa_config["param"] is not None:
670 vid = pa_config["param"]
Dan Talayco551befa2010-07-15 17:05:32 -0700671 for wc in WILDCARD_VALUES:
Dan Talayco21381562010-07-17 00:34:47 -0700672 flow_match_test(self, pa_port_map, wildcards=wc, dl_vlan=vid,
Dan Talayco551befa2010-07-15 17:05:32 -0700673 max_test=10)
674
675class AllExceptOneWildcardMatch(BaseMatchCase):
Tatsuya Yabe4fad7e32010-05-24 15:24:50 -0700676 """
Dan Talayco80b54ed2010-07-13 09:48:35 -0700677 Match exactly one field
Tatsuya Yabe4fad7e32010-05-24 15:24:50 -0700678
679 Generate a packet
680 Generate and install a matching flow with wildcard all except one filed
681 Add action to forward to a port
682 Send the packet to the port
683 Verify the packet is received at all other ports (one port at a time)
684 Verify flow_expiration message is correct when command option is set
685 """
686 def runTest(self):
Dan Talayco551befa2010-07-15 17:05:32 -0700687 for wc in WILDCARD_VALUES:
688 all_exp_one_wildcard = ofp.OFPFW_ALL ^ wc
Dan Talayco21381562010-07-17 00:34:47 -0700689 flow_match_test(self, pa_port_map, wildcards=all_exp_one_wildcard)
Tatsuya Yabee30ebe22010-05-25 09:30:49 -0700690
Dan Talayco551befa2010-07-15 17:05:32 -0700691class AllExceptOneWildcardMatchTagged(BaseMatchCase):
692 """
693 Match one field with tagged packets
694 """
695 def runTest(self):
Dan Talayco21381562010-07-17 00:34:47 -0700696 vid = TEST_VID_DEFAULT
697 if pa_config["param"] is not None:
698 vid = pa_config["param"]
Dan Talayco551befa2010-07-15 17:05:32 -0700699 for wc in WILDCARD_VALUES:
700 all_exp_one_wildcard = ofp.OFPFW_ALL ^ wc
Dan Talayco21381562010-07-17 00:34:47 -0700701 flow_match_test(self, pa_port_map, wildcards=all_exp_one_wildcard,
702 dl_vlan=vid)
Dan Talayco551befa2010-07-15 17:05:32 -0700703
704class AllWildcardMatch(BaseMatchCase):
Tatsuya Yabee30ebe22010-05-25 09:30:49 -0700705 """
706 Create Wildcard-all flow and exercise for all ports
707
708 Generate a packet
709 Generate and install a matching flow with wildcard-all
710 Add action to forward to a port
711 Send the packet to the port
712 Verify the packet is received at all other ports (one port at a time)
713 Verify flow_expiration message is correct when command option is set
714 """
715 def runTest(self):
Dan Talayco21381562010-07-17 00:34:47 -0700716 flow_match_test(self, pa_port_map, wildcards=ofp.OFPFW_ALL)
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -0700717
Dan Talayco551befa2010-07-15 17:05:32 -0700718class AllWildcardMatchTagged(BaseMatchCase):
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -0700719 """
Dan Talayco551befa2010-07-15 17:05:32 -0700720 AllWildcardMatch with tagged packets
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -0700721 """
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -0700722 def runTest(self):
Dan Talayco21381562010-07-17 00:34:47 -0700723 vid = TEST_VID_DEFAULT
724 if pa_config["param"] is not None:
725 vid = pa_config["param"]
726 flow_match_test(self, pa_port_map, wildcards=ofp.OFPFW_ALL,
727 dl_vlan=vid)
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -0700728
Dan Talayco551befa2010-07-15 17:05:32 -0700729class AddVLANTag(BaseMatchCase):
730 """
731 Add a VLAN tag to an untagged packet
732 """
733 def runTest(self):
734 new_vid = 2
735 sup_acts = supported_actions_get(self)
736 if not(sup_acts & 1<<ofp.OFPAT_SET_VLAN_VID):
737 pa_logger.info("Skipping add VLAN tag test")
Dan Talaycof36f1082010-07-13 13:57:17 -0700738 return
Tatsuya Yabef5ffb972010-05-26 15:36:33 -0700739
Dan Talayco551befa2010-07-15 17:05:32 -0700740 len = 100
741 len_w_vid = 104
742 pkt = simple_tcp_packet(pktlen=len)
743 exp_pkt = simple_tcp_packet(pktlen=len_w_vid, dl_vlan_enable=True,
744 dl_vlan=new_vid)
745 vid_act = action.action_set_vlan_vid()
746 vid_act.vlan_vid = new_vid
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -0700747
Dan Talayco551befa2010-07-15 17:05:32 -0700748 flow_match_test(self, pa_port_map, pkt=pkt,
749 exp_pkt=exp_pkt, action_list=[vid_act])
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -0700750
Dan Talayco551befa2010-07-15 17:05:32 -0700751class PacketOnly(basic.DataPlaneOnly):
752 """
753 Just send a packet thru the switch
754 """
755 def runTest(self):
756 pkt = simple_tcp_packet()
757 of_ports = pa_port_map.keys()
758 of_ports.sort()
759 ing_port = of_ports[0]
760 pa_logger.info("Sending packet to " + str(ing_port))
761 pa_logger.debug("Data: " + str(pkt).encode('hex'))
762 self.dataplane.send(ing_port, str(pkt))
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -0700763
Dan Talayco551befa2010-07-15 17:05:32 -0700764class PacketOnlyTagged(basic.DataPlaneOnly):
765 """
766 Just send a packet thru the switch
767 """
768 def runTest(self):
Dan Talayco21381562010-07-17 00:34:47 -0700769 vid = TEST_VID_DEFAULT
Dan Talayco551befa2010-07-15 17:05:32 -0700770 if pa_config["param"] is not None:
771 vid = pa_config["param"]
772 print "Param is " + str(pa_config["param"])
773 pkt = simple_tcp_packet(dl_vlan_enable=True, dl_vlan=vid)
774 of_ports = pa_port_map.keys()
775 of_ports.sort()
776 ing_port = of_ports[0]
777 pa_logger.info("Sending packet to " + str(ing_port))
778 pa_logger.debug("Data: " + str(pkt).encode('hex'))
779 self.dataplane.send(ing_port, str(pkt))
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -0700780
Dan Talayco551befa2010-07-15 17:05:32 -0700781test_prio["PacketOnly"] = -1
782test_prio["PacketOnlyTagged"] = -1
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -0700783
Dan Talayco551befa2010-07-15 17:05:32 -0700784class ModifyVID(BaseMatchCase):
785 def runTest(self):
786 old_vid = 2
787 new_vid = 3
788 sup_acts = supported_actions_get(self)
789 if not(sup_acts & 1<<ofp.OFPAT_SET_VLAN_VID):
790 pa_logger.info("Skipping modify VLAN tag test")
791 return
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -0700792
Dan Talayco551befa2010-07-15 17:05:32 -0700793 pkt = simple_tcp_packet(dl_vlan_enable=True, dl_vlan=old_vid)
794 exp_pkt = simple_tcp_packet(dl_vlan_enable=True, dl_vlan=new_vid)
795 vid_act = action.action_set_vlan_vid()
796 vid_act.vlan_vid = new_vid
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -0700797
Dan Talayco551befa2010-07-15 17:05:32 -0700798 flow_match_test(self, pa_port_map, pkt=pkt, exp_pkt=exp_pkt,
799 action_list=[vid_act])
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -0700800
Dan Talayco551befa2010-07-15 17:05:32 -0700801class StripVLANTag(BaseMatchCase):
802 def runTest(self):
803 old_vid = 2
804 sup_acts = supported_actions_get(self)
805 if not(sup_acts & 1<<ofp.OFPAT_STRIP_VLAN):
806 pa_logger.info("Skipping strip VLAN tag test")
807 return
Dan Talaycof36f1082010-07-13 13:57:17 -0700808
Dan Talayco551befa2010-07-15 17:05:32 -0700809 len_w_vid = 104
810 len = 100
811 pkt = simple_tcp_packet(pktlen=len_w_vid, dl_vlan_enable=True,
812 dl_vlan=old_vid)
813 exp_pkt = simple_tcp_packet(pktlen=len)
814 vid_act = action.action_strip_vlan()
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -0700815
Dan Talayco551befa2010-07-15 17:05:32 -0700816 flow_match_test(self, pa_port_map, pkt=pkt, exp_pkt=exp_pkt,
817 action_list=[vid_act])
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -0700818
Dan Talayco551befa2010-07-15 17:05:32 -0700819class ModifyL2Src(BaseMatchCase):
820 def runTest(self):
821 pa_logger("To be implemented")
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -0700822
Dan Talayco551befa2010-07-15 17:05:32 -0700823class ModifyL2Dst(BaseMatchCase):
824 def runTest(self):
825 pa_logger("To be implemented")
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -0700826
Dan Talayco551befa2010-07-15 17:05:32 -0700827class ModifyL3Src(BaseMatchCase):
828 def runTest(self):
829 pa_logger("To be implemented")
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -0700830
Dan Talayco551befa2010-07-15 17:05:32 -0700831class ModifyL3Dst(BaseMatchCase):
832 def runTest(self):
833 pa_logger("To be implemented")
834
835class ModifyL4Src(BaseMatchCase):
836 def runTest(self):
837 pa_logger("To be implemented")
838
839class ModifyL4Dst(BaseMatchCase):
840 def runTest(self):
841 pa_logger("To be implemented")
842
843class ModifyTOS(BaseMatchCase):
844 def runTest(self):
845 pa_logger("To be implemented")
846
847test_prio["ModifyL2Src"] = -1
848test_prio["ModifyL2Dst"] = -1
849test_prio["ModifyL3Src"] = -1
850test_prio["ModifyL3Dst"] = -1
851test_prio["ModifyL4Src"] = -1
852test_prio["ModifyL4Dst"] = -1
853test_prio["ModifyTOS"] = -1
854
855def supported_actions_get(parent, use_cache=True):
856 """
857 Get the bitmap of supported actions from the switch
858 If use_cache is false, the cached value will be updated
859 """
860 global cached_supported_actions
861 if cached_supported_actions is None or not use_cache:
862 request = message.features_request()
863 (reply, pkt) = parent.controller.transact(request, timeout=2)
864 parent.assertTrue(reply is not None, "Did not get response to ftr req")
865 cached_supported_actions = reply.actions
866 pa_logger.info("Supported actions: " + hex(cached_supported_actions))
867
868 return cached_supported_actions
Tatsuya Yabe9c31e222010-06-16 13:48:02 -0700869
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700870if __name__ == "__main__":
871 print "Please run through oft script: ./oft --test_spec=basic"