blob: 0b04c56b856ded963337955a7c37f329972fdea1 [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
Rich Lane477f4812012-10-04 22:49:00 -070010The switch is actively attempting to contact the controller at the address
11indicated in config.
Dan Talayco5eba8442010-03-10 13:58:43 -080012
13"""
14
Dan Talayco9f47f4d2010-06-03 13:54:37 -070015import copy
Dan Talayco5eba8442010-03-10 13:58:43 -080016import logging
Rich Laneb90a1c42012-10-05 09:16:05 -070017import time
Dan Talayco5eba8442010-03-10 13:58:43 -080018import unittest
Christian Dickmann8b59b4b2012-09-23 16:48:30 -070019import random
Dan Talayco5eba8442010-03-10 13:58:43 -080020
Rich Lane477f4812012-10-04 22:49:00 -070021from oftest import config
Dan Talayco5eba8442010-03-10 13:58:43 -080022import 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
Rich Laneb90a1c42012-10-05 09:16:05 -070028import oftest.base_tests as base_tests
29import basic # for IterCases
Dan Talayco5eba8442010-03-10 13:58:43 -080030
Christian Dickmann8b59b4b2012-09-23 16:48:30 -070031from oftest.parse import parse_mac, parse_ip
32
Rich Laneda3b5ad2012-10-03 09:05:32 -070033from oftest.testutils import *
Dan Talayco5eba8442010-03-10 13:58:43 -080034
Dan Talayco551befa2010-07-15 17:05:32 -070035WILDCARD_VALUES = [ofp.OFPFW_IN_PORT,
Dan Talayco488fbc52012-04-09 16:30:41 -070036 ofp.OFPFW_DL_VLAN | ofp.OFPFW_DL_VLAN_PCP,
Dan Talayco551befa2010-07-15 17:05:32 -070037 ofp.OFPFW_DL_SRC,
38 ofp.OFPFW_DL_DST,
Dan Talayco488fbc52012-04-09 16:30:41 -070039 (ofp.OFPFW_DL_TYPE | ofp.OFPFW_NW_SRC_ALL |
40 ofp.OFPFW_NW_DST_ALL | ofp.OFPFW_NW_TOS | ofp.OFPFW_NW_PROTO |
41 ofp.OFPFW_TP_SRC | ofp.OFPFW_TP_DST),
42 (ofp.OFPFW_NW_PROTO | ofp.OFPFW_TP_SRC | ofp.OFPFW_TP_DST),
Dan Talayco551befa2010-07-15 17:05:32 -070043 ofp.OFPFW_TP_SRC,
44 ofp.OFPFW_TP_DST,
Dan Talayco488fbc52012-04-09 16:30:41 -070045 ofp.OFPFW_NW_SRC_MASK,
46 ofp.OFPFW_NW_DST_MASK,
Dan Talayco551befa2010-07-15 17:05:32 -070047 ofp.OFPFW_DL_VLAN_PCP,
48 ofp.OFPFW_NW_TOS]
49
Dan Talayco488fbc52012-04-09 16:30:41 -070050NO_WILDCARD_VALUES = [(ofp.OFPFW_ALL ^ ofp.OFPFW_IN_PORT),
51 (ofp.OFPFW_ALL ^ ofp.OFPFW_DL_VLAN),
52 (ofp.OFPFW_ALL ^ ofp.OFPFW_DL_SRC),
53 (ofp.OFPFW_ALL ^ ofp.OFPFW_DL_DST),
54 (ofp.OFPFW_ALL ^ ofp.OFPFW_DL_TYPE),
55 (ofp.OFPFW_ALL ^ ofp.OFPFW_DL_TYPE ^ ofp.OFPFW_NW_PROTO),
56 (ofp.OFPFW_ALL ^ ofp.OFPFW_DL_TYPE ^ ofp.OFPFW_NW_PROTO ^
57 ofp.OFPFW_TP_SRC),
58 (ofp.OFPFW_ALL ^ ofp.OFPFW_DL_TYPE ^ ofp.OFPFW_NW_PROTO ^
59 ofp.OFPFW_TP_DST),
60 (ofp.OFPFW_ALL ^ ofp.OFPFW_DL_TYPE ^ ofp.OFPFW_NW_PROTO ^
61 ofp.OFPFW_NW_SRC_MASK),
62 (ofp.OFPFW_ALL ^ ofp.OFPFW_DL_TYPE ^ ofp.OFPFW_NW_PROTO ^
63 ofp.OFPFW_NW_DST_MASK),
64 (ofp.OFPFW_ALL ^ ofp.OFPFW_DL_VLAN ^ ofp.OFPFW_DL_VLAN_PCP),
65 (ofp.OFPFW_ALL ^ ofp.OFPFW_DL_TYPE ^ ofp.OFPFW_NW_PROTO ^
66 ofp.OFPFW_NW_TOS)]
67
Dan Talayco551befa2010-07-15 17:05:32 -070068MODIFY_ACTION_VALUES = [ofp.OFPAT_SET_VLAN_VID,
69 ofp.OFPAT_SET_VLAN_PCP,
70 ofp.OFPAT_STRIP_VLAN,
71 ofp.OFPAT_SET_DL_SRC,
72 ofp.OFPAT_SET_DL_DST,
73 ofp.OFPAT_SET_NW_SRC,
74 ofp.OFPAT_SET_NW_DST,
75 ofp.OFPAT_SET_NW_TOS,
76 ofp.OFPAT_SET_TP_SRC,
77 ofp.OFPAT_SET_TP_DST]
78
Dan Talayco21381562010-07-17 00:34:47 -070079TEST_VID_DEFAULT = 2
80
Rich Laneb90a1c42012-10-05 09:16:05 -070081class DirectPacket(base_tests.SimpleDataPlane):
Dan Talayco5eba8442010-03-10 13:58:43 -080082 """
Dan Talayco2d0d49a2010-05-11 15:29:08 -070083 Send packet to single egress port
Dan Talayco5eba8442010-03-10 13:58:43 -080084
85 Generate a packet
86 Generate and install a matching flow
87 Add action to direct the packet to an egress port
88 Send the packet to ingress dataplane port
89 Verify the packet is received at the egress port only
90 """
91 def runTest(self):
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -070092 self.handleFlow()
93
94 def handleFlow(self, pkttype='TCP'):
Rich Lane477f4812012-10-04 22:49:00 -070095 of_ports = config["port_map"].keys()
Dan Talayco5eba8442010-03-10 13:58:43 -080096 of_ports.sort()
97 self.assertTrue(len(of_ports) > 1, "Not enough ports for test")
98
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -070099 if (pkttype == 'ICMP'):
100 pkt = simple_icmp_packet()
101 else:
102 pkt = simple_tcp_packet()
Ed Swierk99a74de2012-08-22 06:40:54 -0700103 match = packet_to_flow_match(self, pkt)
Dan Talayco7dd6cd62010-03-16 15:02:35 -0700104 match.wildcards &= ~ofp.OFPFW_IN_PORT
Dan Talayco5eba8442010-03-10 13:58:43 -0800105 self.assertTrue(match is not None,
106 "Could not generate flow match from pkt")
107 act = action.action_output()
108
109 for idx in range(len(of_ports)):
Rich Lane9a003812012-10-04 17:17:59 -0700110 rv = delete_all_flows(self.controller)
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700111 self.assertEqual(rv, 0, "Failed to delete all flows")
Dan Talayco2e77a842010-05-12 15:39:46 -0700112
Dan Talayco5eba8442010-03-10 13:58:43 -0800113 ingress_port = of_ports[idx]
114 egress_port = of_ports[(idx + 1) % len(of_ports)]
Rich Lane9a003812012-10-04 17:17:59 -0700115 logging.info("Ingress " + str(ingress_port) +
Dan Talayco551befa2010-07-15 17:05:32 -0700116 " to egress " + str(egress_port))
Dan Talayco5eba8442010-03-10 13:58:43 -0800117
118 match.in_port = ingress_port
119
120 request = message.flow_mod()
121 request.match = match
Jeffrey Townsend2a300e42012-03-28 17:24:02 -0700122
Dan Talayco5eba8442010-03-10 13:58:43 -0800123 request.buffer_id = 0xffffffff
124 act.port = egress_port
125 self.assertTrue(request.actions.add(act), "Could not add action")
126
Rich Lane9a003812012-10-04 17:17:59 -0700127 logging.info("Inserting flow")
Dan Talayco5eba8442010-03-10 13:58:43 -0800128 rv = self.controller.message_send(request)
129 self.assertTrue(rv != -1, "Error installing flow mod")
Dan Talayco0fc08bd2012-04-09 16:56:18 -0700130 self.assertEqual(do_barrier(self.controller), 0, "Barrier failed")
Dan Talayco5eba8442010-03-10 13:58:43 -0800131
Rich Lane9a003812012-10-04 17:17:59 -0700132 logging.info("Sending packet to dp port " +
Dan Talayco5eba8442010-03-10 13:58:43 -0800133 str(ingress_port))
134 self.dataplane.send(ingress_port, str(pkt))
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700135
136 exp_pkt_arg = None
137 exp_port = None
Rich Lane477f4812012-10-04 22:49:00 -0700138 if config["relax"]:
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700139 exp_pkt_arg = pkt
140 exp_port = egress_port
141
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700142 (rcv_port, rcv_pkt, pkt_time) = self.dataplane.poll(port_number=exp_port,
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700143 exp_pkt=exp_pkt_arg)
Dan Talayco5eba8442010-03-10 13:58:43 -0800144 self.assertTrue(rcv_pkt is not None, "Did not receive packet")
Rich Lane9a003812012-10-04 17:17:59 -0700145 logging.debug("Packet len " + str(len(rcv_pkt)) + " in on " +
Dan Talayco5eba8442010-03-10 13:58:43 -0800146 str(rcv_port))
147 self.assertEqual(rcv_port, egress_port, "Unexpected receive port")
148 self.assertEqual(str(pkt), str(rcv_pkt),
149 'Response packet does not match send packet')
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700150
Rich Laneb90a1c42012-10-05 09:16:05 -0700151class DirectPacketController(base_tests.SimpleDataPlane):
Rich Lane51c23b32012-07-27 16:37:25 -0700152 """
153 Send packet to the controller port
154
155 Generate a packet
156 Generate and install a matching flow
157 Add action to direct the packet to the controller port
158 Send the packet to ingress dataplane port
159 Verify the packet is received at the controller port
160 """
161 def runTest(self):
162 self.handleFlow()
163
164 def handleFlow(self, pkttype='TCP'):
Rich Lane477f4812012-10-04 22:49:00 -0700165 of_ports = config["port_map"].keys()
Rich Lane51c23b32012-07-27 16:37:25 -0700166 of_ports.sort()
167 self.assertTrue(len(of_ports) > 0, "Not enough ports for test")
168
169 if (pkttype == 'ICMP'):
170 pkt = simple_icmp_packet()
171 else:
172 pkt = simple_tcp_packet()
Ed Swierk99a74de2012-08-22 06:40:54 -0700173 match = packet_to_flow_match(self, pkt)
Rich Lane51c23b32012-07-27 16:37:25 -0700174 match.wildcards &= ~ofp.OFPFW_IN_PORT
175 self.assertTrue(match is not None,
176 "Could not generate flow match from pkt")
177 act = action.action_output()
178
Rich Lane9a003812012-10-04 17:17:59 -0700179 rv = delete_all_flows(self.controller)
Rich Lane51c23b32012-07-27 16:37:25 -0700180 self.assertEqual(rv, 0, "Failed to delete all flows")
181
182 ingress_port = of_ports[0]
183 match.in_port = ingress_port
184
185 request = message.flow_mod()
186 request.match = match
187
188 request.buffer_id = 0xffffffff
189 act.port = ofp.OFPP_CONTROLLER
190 act.max_len = 65535
191 self.assertTrue(request.actions.add(act), "Could not add action")
192
Rich Lane9a003812012-10-04 17:17:59 -0700193 logging.info("Inserting flow")
Rich Lane51c23b32012-07-27 16:37:25 -0700194 rv = self.controller.message_send(request)
195 self.assertTrue(rv != -1, "Error installing flow mod")
196 self.assertEqual(do_barrier(self.controller), 0, "Barrier failed")
197
Rich Lane9a003812012-10-04 17:17:59 -0700198 logging.info("Sending packet to dp port " +
Rich Lane51c23b32012-07-27 16:37:25 -0700199 str(ingress_port))
200 self.dataplane.send(ingress_port, str(pkt))
201
202 (response, raw) = self.controller.poll(ofp.OFPT_PACKET_IN)
203
204 self.assertTrue(response is not None,
205 'Packet in message not received by controller')
206 if not dataplane.match_exp_pkt(pkt, response.data):
Rich Lane9a003812012-10-04 17:17:59 -0700207 logging.debug("Sent %s" % format_packet(pkt))
208 logging.debug("Resp %s" % format_packet(response.data))
Rich Lane51c23b32012-07-27 16:37:25 -0700209 self.assertTrue(False,
210 'Response packet does not match send packet' +
211 ' for controller port')
212
Howard Pershf97840f2012-04-10 16:30:42 -0700213
Rich Laneb90a1c42012-10-05 09:16:05 -0700214class DirectPacketQueue(base_tests.SimpleDataPlane):
Howard Pershf97840f2012-04-10 16:30:42 -0700215 """
216 Send packet to single queue on single egress port
217
218 Generate a packet
219 Generate and install a matching flow
220 Add action to direct the packet to an egress port and queue
221 Send the packet to ingress dataplane port
222 Verify the packet is received at the egress port only
223 """
224 def runTest(self):
225 self.handleFlow()
226
Howard Persh670b5672012-04-13 09:08:29 -0700227 def portQueuesGet(self, queue_stats, port_num):
228 result = []
229 for qs in queue_stats.stats:
230 if qs.port_no != port_num:
231 continue
232 result.append(qs.queue_id)
233 return result
234
Howard Pershf97840f2012-04-10 16:30:42 -0700235 def handleFlow(self, pkttype='TCP'):
Rich Lane477f4812012-10-04 22:49:00 -0700236 of_ports = config["port_map"].keys()
Howard Pershf97840f2012-04-10 16:30:42 -0700237 of_ports.sort()
238 self.assertTrue(len(of_ports) > 1, "Not enough ports for test")
239
240 if (pkttype == 'ICMP'):
241 pkt = simple_icmp_packet()
242 else:
243 pkt = simple_tcp_packet()
Ed Swierk99a74de2012-08-22 06:40:54 -0700244 match = packet_to_flow_match(self, pkt)
Howard Pershf97840f2012-04-10 16:30:42 -0700245 match.wildcards &= ~ofp.OFPFW_IN_PORT
246 self.assertTrue(match is not None,
247 "Could not generate flow match from pkt")
248
Howard Persh670b5672012-04-13 09:08:29 -0700249 # Get queue stats from switch
250
251 request = message.queue_stats_request()
252 request.port_no = ofp.OFPP_ALL
253 request.queue_id = ofp.OFPQ_ALL
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700254 (queue_stats, p) = self.controller.transact(request)
Howard Persh670b5672012-04-13 09:08:29 -0700255 self.assertNotEqual(queue_stats, None, "Queue stats request failed")
256
257 act = action.action_enqueue()
Howard Pershf97840f2012-04-10 16:30:42 -0700258
259 for idx in range(len(of_ports)):
Howard Pershf97840f2012-04-10 16:30:42 -0700260 ingress_port = of_ports[idx]
261 egress_port = of_ports[(idx + 1) % len(of_ports)]
Howard Pershf97840f2012-04-10 16:30:42 -0700262
Howard Persh670b5672012-04-13 09:08:29 -0700263 for egress_queue_id in self.portQueuesGet(queue_stats, egress_port):
Rich Lane9a003812012-10-04 17:17:59 -0700264 logging.info("Ingress " + str(ingress_port)
Howard Persh670b5672012-04-13 09:08:29 -0700265 + " to egress " + str(egress_port)
266 + " queue " + str(egress_queue_id)
267 )
Howard Pershf97840f2012-04-10 16:30:42 -0700268
Rich Lane9a003812012-10-04 17:17:59 -0700269 rv = delete_all_flows(self.controller)
Howard Persh670b5672012-04-13 09:08:29 -0700270 self.assertEqual(rv, 0, "Failed to delete all flows")
Howard Pershf97840f2012-04-10 16:30:42 -0700271
Howard Persh670b5672012-04-13 09:08:29 -0700272 match.in_port = ingress_port
273
274 request = message.flow_mod()
275 request.match = match
Howard Pershf97840f2012-04-10 16:30:42 -0700276
Howard Persh670b5672012-04-13 09:08:29 -0700277 request.buffer_id = 0xffffffff
278 act.port = egress_port
279 act.queue_id = egress_queue_id
280 self.assertTrue(request.actions.add(act), "Could not add action")
Howard Pershf97840f2012-04-10 16:30:42 -0700281
Rich Lane9a003812012-10-04 17:17:59 -0700282 logging.info("Inserting flow")
Howard Persh670b5672012-04-13 09:08:29 -0700283 rv = self.controller.message_send(request)
284 self.assertTrue(rv != -1, "Error installing flow mod")
285 self.assertEqual(do_barrier(self.controller), 0, "Barrier failed")
Howard Pershf97840f2012-04-10 16:30:42 -0700286
Howard Persh670b5672012-04-13 09:08:29 -0700287 # Get current stats for selected egress queue
Howard Pershf97840f2012-04-10 16:30:42 -0700288
Howard Persh670b5672012-04-13 09:08:29 -0700289 request = message.queue_stats_request()
290 request.port_no = egress_port
291 request.queue_id = egress_queue_id
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700292 (qs_before, p) = self.controller.transact(request)
Howard Persh670b5672012-04-13 09:08:29 -0700293 self.assertNotEqual(qs_before, None, "Queue stats request failed")
294
Rich Lane9a003812012-10-04 17:17:59 -0700295 logging.info("Sending packet to dp port " +
Howard Persh670b5672012-04-13 09:08:29 -0700296 str(ingress_port))
297 self.dataplane.send(ingress_port, str(pkt))
298
299 exp_pkt_arg = None
300 exp_port = None
Rich Lane477f4812012-10-04 22:49:00 -0700301 if config["relax"]:
Howard Persh670b5672012-04-13 09:08:29 -0700302 exp_pkt_arg = pkt
303 exp_port = egress_port
304
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700305 (rcv_port, rcv_pkt, pkt_time) = self.dataplane.poll(port_number=exp_port,
Howard Persh670b5672012-04-13 09:08:29 -0700306 exp_pkt=exp_pkt_arg)
307 self.assertTrue(rcv_pkt is not None, "Did not receive packet")
Rich Lane9a003812012-10-04 17:17:59 -0700308 logging.debug("Packet len " + str(len(rcv_pkt)) + " in on " +
Howard Persh670b5672012-04-13 09:08:29 -0700309 str(rcv_port))
310 self.assertEqual(rcv_port, egress_port, "Unexpected receive port")
311 self.assertEqual(str(pkt), str(rcv_pkt),
312 'Response packet does not match send packet')
313
Ed Swierkb8a86512012-04-18 18:45:58 -0700314 # FIXME: instead of sleeping, keep requesting queue stats until
315 # the expected queue counter increases or some large timeout is
316 # reached
317 time.sleep(2)
318
Howard Persh670b5672012-04-13 09:08:29 -0700319 # Get current stats for selected egress queue again
320
321 request = message.queue_stats_request()
322 request.port_no = egress_port
323 request.queue_id = egress_queue_id
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700324 (qs_after, p) = self.controller.transact(request)
Howard Persh670b5672012-04-13 09:08:29 -0700325 self.assertNotEqual(qs_after, None, "Queue stats request failed")
326
327 # Make sure that tx packet counter for selected egress queue was
328 # incremented
329
Ed Swierk22f59152012-04-17 16:36:47 -0700330 self.assertEqual(qs_after.stats[0].tx_packets, \
331 qs_before.stats[0].tx_packets + 1, \
Howard Persh670b5672012-04-13 09:08:29 -0700332 "Verification of egress queue tx packet count failed"
333 )
334
335
Rich Laneb90a1c42012-10-05 09:16:05 -0700336class DirectPacketControllerQueue(base_tests.SimpleDataPlane):
Ken Chiang899ff8e2012-05-23 18:26:12 -0700337 """
338 Send a packet from each of the openflow ports
339 to each of the queues configured on the controller port.
340 If no queues have been configured, no packets are sent.
Howard Pershf97840f2012-04-10 16:30:42 -0700341
Ken Chiang899ff8e2012-05-23 18:26:12 -0700342 Generate a packet
343 Generate and install a matching flow
344 Add action to direct the packet to one of the controller port queues
345 Send the packet to ingress dataplane port
346 Verify the packet is received on the controller port queue
347 """
348 def runTest(self):
349 self.handleFlow()
350
351 def portQueuesGet(self, queue_stats, port_num):
352 result = []
353 for qs in queue_stats.stats:
354 if qs.port_no != port_num:
355 continue
356 result.append(qs.queue_id)
357 return result
358
359 def handleFlow(self, pkttype='TCP'):
Rich Lane477f4812012-10-04 22:49:00 -0700360 of_ports = config["port_map"].keys()
Ken Chiang899ff8e2012-05-23 18:26:12 -0700361 of_ports.sort()
362 self.assertTrue(len(of_ports) > 1, "Not enough ports for test")
363
364 if (pkttype == 'ICMP'):
365 pkt = simple_icmp_packet()
366 else:
367 pkt = simple_tcp_packet()
Ed Swierk99a74de2012-08-22 06:40:54 -0700368 match = packet_to_flow_match(self, pkt)
Ken Chiang899ff8e2012-05-23 18:26:12 -0700369 match.wildcards &= ~ofp.OFPFW_IN_PORT
370 self.assertTrue(match is not None,
371 "Could not generate flow match from pkt")
372
373 # Get queue stats from switch
374
375 request = message.queue_stats_request()
376 request.port_no = ofp.OFPP_CONTROLLER
377 request.queue_id = ofp.OFPQ_ALL
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700378 (queue_stats, p) = self.controller.transact(request)
Ken Chiang899ff8e2012-05-23 18:26:12 -0700379 self.assertNotEqual(queue_stats, None, "Queue stats request failed")
Rich Laneb8c845a2012-12-31 17:23:51 -0800380 if queue_stats.header.type == ofp.OFPT_ERROR:
381 skip_message_emit(self, "Enqueue packet to controller")
382 return
Ken Chiang899ff8e2012-05-23 18:26:12 -0700383
384 act = action.action_enqueue()
385
386 for idx in range(len(of_ports)):
387 ingress_port = of_ports[idx]
388 egress_port = ofp.OFPP_CONTROLLER
389
Rich Lane9a003812012-10-04 17:17:59 -0700390 logging.info("Ingress port " + str(ingress_port)
Ken Chiang899ff8e2012-05-23 18:26:12 -0700391 + ", controller port queues "
392 + str(self.portQueuesGet(queue_stats, egress_port)))
393
394 for egress_queue_id in self.portQueuesGet(queue_stats, egress_port):
Rich Lane9a003812012-10-04 17:17:59 -0700395 logging.info("Ingress " + str(ingress_port)
Ken Chiang899ff8e2012-05-23 18:26:12 -0700396 + " to egress " + str(egress_port)
397 + " queue " + str(egress_queue_id)
398 )
399
Rich Lane9a003812012-10-04 17:17:59 -0700400 rv = delete_all_flows(self.controller)
Ken Chiang899ff8e2012-05-23 18:26:12 -0700401 self.assertEqual(rv, 0, "Failed to delete all flows")
402
403 match.in_port = ingress_port
404
405 request = message.flow_mod()
406 request.match = match
407
408 request.buffer_id = 0xffffffff
409 act.port = egress_port
410 act.queue_id = egress_queue_id
411 self.assertTrue(request.actions.add(act), "Could not add action")
412
Rich Lane9a003812012-10-04 17:17:59 -0700413 logging.info("Inserting flow")
Ken Chiang899ff8e2012-05-23 18:26:12 -0700414 rv = self.controller.message_send(request)
415 self.assertTrue(rv != -1, "Error installing flow mod")
416 self.assertEqual(do_barrier(self.controller), 0, "Barrier failed")
417
418 # Get current stats for selected egress queue
419
420 request = message.queue_stats_request()
421 request.port_no = egress_port
422 request.queue_id = egress_queue_id
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700423 (qs_before, p) = self.controller.transact(request)
Ken Chiang899ff8e2012-05-23 18:26:12 -0700424 self.assertNotEqual(qs_before, None, "Queue stats request failed")
425
Rich Lane9a003812012-10-04 17:17:59 -0700426 logging.info("Sending packet to dp port " +
Ken Chiang899ff8e2012-05-23 18:26:12 -0700427 str(ingress_port))
428 self.dataplane.send(ingress_port, str(pkt))
429
430 exp_pkt_arg = None
431 exp_port = None
432
Rich Lanee5779d32012-10-05 17:56:04 -0700433 count = 0
Ken Chiang899ff8e2012-05-23 18:26:12 -0700434 while True:
Dan Talaycoc689a792012-09-28 14:22:53 -0700435 (response, raw) = self.controller.poll(ofp.OFPT_PACKET_IN)
Ken Chiang899ff8e2012-05-23 18:26:12 -0700436 if not response: # Timeout
437 break
438 if dataplane.match_exp_pkt(pkt, response.data): # Got match
439 break
Rich Lane477f4812012-10-04 22:49:00 -0700440 if not config["relax"]: # Only one attempt to match
Ken Chiang899ff8e2012-05-23 18:26:12 -0700441 break
442 count += 1
443 if count > 10: # Too many tries
444 break
445
446 self.assertTrue(response is not None,
447 'Packet in message not received by controller')
448 if not dataplane.match_exp_pkt(pkt, response.data):
Rich Lane9a003812012-10-04 17:17:59 -0700449 logging.debug("Sent %s" % format_packet(pkt))
450 logging.debug("Resp %s" % format_packet(response.data))
Ken Chiang899ff8e2012-05-23 18:26:12 -0700451 self.assertTrue(False,
452 'Response packet does not match send packet' +
453 ' for controller port')
454
455 # FIXME: instead of sleeping, keep requesting queue stats until
456 # the expected queue counter increases or some large timeout is
457 # reached
458 time.sleep(2)
459
460 # Get current stats for selected egress queue again
461
462 request = message.queue_stats_request()
463 request.port_no = egress_port
464 request.queue_id = egress_queue_id
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700465 (qs_after, p) = self.controller.transact(request)
Ken Chiang899ff8e2012-05-23 18:26:12 -0700466 self.assertNotEqual(qs_after, None, "Queue stats request failed")
467
468 # Make sure that tx packet counter for selected egress queue was
469 # incremented
470
471 self.assertEqual(qs_after.stats[0].tx_packets, \
472 qs_before.stats[0].tx_packets + 1, \
473 "Verification of egress queue tx packet count failed"
474 )
475
Howard Pershf97840f2012-04-10 16:30:42 -0700476
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700477class DirectPacketICMP(DirectPacket):
478 """
479 Send ICMP packet to single egress port
480
481 Generate a ICMP packet
482 Generate and install a matching flow
483 Add action to direct the packet to an egress port
484 Send the packet to ingress dataplane port
485 Verify the packet is received at the egress port only
486 Difference from DirectPacket test is that sent packet is ICMP
487 """
488 def runTest(self):
489 self.handleFlow(pkttype='ICMP')
Dan Talayco2d0d49a2010-05-11 15:29:08 -0700490
Rich Laneb90a1c42012-10-05 09:16:05 -0700491class DirectTwoPorts(base_tests.SimpleDataPlane):
Dan Talayco2d0d49a2010-05-11 15:29:08 -0700492 """
493 Send packet to two egress ports
494
495 Generate a packet
496 Generate and install a matching flow
497 Add action to direct the packet to two egress ports
498 Send the packet to ingress dataplane port
499 Verify the packet is received at the two egress ports
500 """
501 def runTest(self):
Rich Lane477f4812012-10-04 22:49:00 -0700502 of_ports = config["port_map"].keys()
Dan Talayco2d0d49a2010-05-11 15:29:08 -0700503 of_ports.sort()
504 self.assertTrue(len(of_ports) > 2, "Not enough ports for test")
505
Dan Talayco2d0d49a2010-05-11 15:29:08 -0700506 pkt = simple_tcp_packet()
Ed Swierk99a74de2012-08-22 06:40:54 -0700507 match = packet_to_flow_match(self, pkt)
Dan Talayco2d0d49a2010-05-11 15:29:08 -0700508 match.wildcards &= ~ofp.OFPFW_IN_PORT
509 self.assertTrue(match is not None,
510 "Could not generate flow match from pkt")
511 act = action.action_output()
512
513 for idx in range(len(of_ports)):
Rich Lane9a003812012-10-04 17:17:59 -0700514 rv = delete_all_flows(self.controller)
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700515 self.assertEqual(rv, 0, "Failed to delete all flows")
Dan Talayco2e77a842010-05-12 15:39:46 -0700516
Dan Talayco2d0d49a2010-05-11 15:29:08 -0700517 ingress_port = of_ports[idx]
518 egress_port1 = of_ports[(idx + 1) % len(of_ports)]
519 egress_port2 = of_ports[(idx + 2) % len(of_ports)]
Rich Lane9a003812012-10-04 17:17:59 -0700520 logging.info("Ingress " + str(ingress_port) +
Dan Talayco2d0d49a2010-05-11 15:29:08 -0700521 " to egress " + str(egress_port1) + " and " +
522 str(egress_port2))
523
524 match.in_port = ingress_port
525
526 request = message.flow_mod()
527 request.match = match
528 request.buffer_id = 0xffffffff
529 act.port = egress_port1
530 self.assertTrue(request.actions.add(act), "Could not add action1")
531 act.port = egress_port2
532 self.assertTrue(request.actions.add(act), "Could not add action2")
Rich Lane9a003812012-10-04 17:17:59 -0700533 # logging.info(request.show())
Dan Talayco2d0d49a2010-05-11 15:29:08 -0700534
Rich Lane9a003812012-10-04 17:17:59 -0700535 logging.info("Inserting flow")
Dan Talayco2d0d49a2010-05-11 15:29:08 -0700536 rv = self.controller.message_send(request)
537 self.assertTrue(rv != -1, "Error installing flow mod")
Dan Talayco0fc08bd2012-04-09 16:56:18 -0700538 self.assertEqual(do_barrier(self.controller), 0, "Barrier failed")
Dan Talayco2d0d49a2010-05-11 15:29:08 -0700539
Rich Lane9a003812012-10-04 17:17:59 -0700540 logging.info("Sending packet to dp port " +
Dan Talayco2d0d49a2010-05-11 15:29:08 -0700541 str(ingress_port))
542 self.dataplane.send(ingress_port, str(pkt))
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700543 yes_ports = set([egress_port1, egress_port2])
544 no_ports = set(of_ports).difference(yes_ports)
Dan Talayco2d0d49a2010-05-11 15:29:08 -0700545
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700546 receive_pkt_check(self.dataplane, pkt, yes_ports, no_ports,
Rich Lane2014f9b2012-10-05 15:29:40 -0700547 self)
Dan Talaycob0b0fdb2010-05-11 15:44:56 -0700548
Rich Laneb90a1c42012-10-05 09:16:05 -0700549class DirectMCNonIngress(base_tests.SimpleDataPlane):
Dan Talaycob0b0fdb2010-05-11 15:44:56 -0700550 """
551 Multicast to all non-ingress ports
552
553 Generate a packet
554 Generate and install a matching flow
555 Add action to direct the packet to all non-ingress ports
556 Send the packet to ingress dataplane port
557 Verify the packet is received at all non-ingress ports
558
559 Does not use the flood action
560 """
561 def runTest(self):
Rich Lane477f4812012-10-04 22:49:00 -0700562 of_ports = config["port_map"].keys()
Dan Talaycob0b0fdb2010-05-11 15:44:56 -0700563 of_ports.sort()
564 self.assertTrue(len(of_ports) > 2, "Not enough ports for test")
565
Dan Talaycob0b0fdb2010-05-11 15:44:56 -0700566 pkt = simple_tcp_packet()
Ed Swierk99a74de2012-08-22 06:40:54 -0700567 match = packet_to_flow_match(self, pkt)
Dan Talaycob0b0fdb2010-05-11 15:44:56 -0700568 match.wildcards &= ~ofp.OFPFW_IN_PORT
569 self.assertTrue(match is not None,
570 "Could not generate flow match from pkt")
571 act = action.action_output()
572
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700573 for ingress_port in of_ports:
Rich Lane9a003812012-10-04 17:17:59 -0700574 rv = delete_all_flows(self.controller)
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700575 self.assertEqual(rv, 0, "Failed to delete all flows")
Dan Talayco2e77a842010-05-12 15:39:46 -0700576
Rich Lane9a003812012-10-04 17:17:59 -0700577 logging.info("Ingress " + str(ingress_port) +
Dan Talaycob0b0fdb2010-05-11 15:44:56 -0700578 " all non-ingress ports")
Dan Talaycob0b0fdb2010-05-11 15:44:56 -0700579 match.in_port = ingress_port
580
581 request = message.flow_mod()
582 request.match = match
583 request.buffer_id = 0xffffffff
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700584 for egress_port in of_ports:
585 if egress_port == ingress_port:
Dan Talaycob0b0fdb2010-05-11 15:44:56 -0700586 continue
Dan Talaycob0b0fdb2010-05-11 15:44:56 -0700587 act.port = egress_port
588 self.assertTrue(request.actions.add(act),
589 "Could not add output to " + str(egress_port))
Rich Lane9a003812012-10-04 17:17:59 -0700590 logging.debug(request.show())
Dan Talaycob0b0fdb2010-05-11 15:44:56 -0700591
Rich Lane9a003812012-10-04 17:17:59 -0700592 logging.info("Inserting flow")
Dan Talaycob0b0fdb2010-05-11 15:44:56 -0700593 rv = self.controller.message_send(request)
594 self.assertTrue(rv != -1, "Error installing flow mod")
Dan Talayco0fc08bd2012-04-09 16:56:18 -0700595 self.assertEqual(do_barrier(self.controller), 0, "Barrier failed")
Dan Talaycob0b0fdb2010-05-11 15:44:56 -0700596
Rich Lane9a003812012-10-04 17:17:59 -0700597 logging.info("Sending packet to dp port " + str(ingress_port))
Dan Talaycob0b0fdb2010-05-11 15:44:56 -0700598 self.dataplane.send(ingress_port, str(pkt))
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700599 yes_ports = set(of_ports).difference([ingress_port])
600 receive_pkt_check(self.dataplane, pkt, yes_ports, [ingress_port],
Rich Lane2014f9b2012-10-05 15:29:40 -0700601 self)
Dan Talaycob0b0fdb2010-05-11 15:44:56 -0700602
Dan Talayco32fa6542010-05-11 15:54:08 -0700603
Rich Laneb90a1c42012-10-05 09:16:05 -0700604class DirectMC(base_tests.SimpleDataPlane):
Dan Talayco32fa6542010-05-11 15:54:08 -0700605 """
606 Multicast to all ports including ingress
607
608 Generate a packet
609 Generate and install a matching flow
610 Add action to direct the packet to all non-ingress ports
611 Send the packet to ingress dataplane port
612 Verify the packet is received at all ports
613
614 Does not use the flood action
615 """
616 def runTest(self):
Rich Lane477f4812012-10-04 22:49:00 -0700617 of_ports = config["port_map"].keys()
Dan Talayco32fa6542010-05-11 15:54:08 -0700618 of_ports.sort()
619 self.assertTrue(len(of_ports) > 2, "Not enough ports for test")
620
Dan Talayco32fa6542010-05-11 15:54:08 -0700621 pkt = simple_tcp_packet()
Ed Swierk99a74de2012-08-22 06:40:54 -0700622 match = packet_to_flow_match(self, pkt)
Dan Talayco32fa6542010-05-11 15:54:08 -0700623 match.wildcards &= ~ofp.OFPFW_IN_PORT
624 self.assertTrue(match is not None,
625 "Could not generate flow match from pkt")
626 act = action.action_output()
627
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700628 for ingress_port in of_ports:
Rich Lane9a003812012-10-04 17:17:59 -0700629 rv = delete_all_flows(self.controller)
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700630 self.assertEqual(rv, 0, "Failed to delete all flows")
Dan Talayco2e77a842010-05-12 15:39:46 -0700631
Rich Lane9a003812012-10-04 17:17:59 -0700632 logging.info("Ingress " + str(ingress_port) + " to all ports")
Dan Talayco32fa6542010-05-11 15:54:08 -0700633 match.in_port = ingress_port
634
635 request = message.flow_mod()
636 request.match = match
637 request.buffer_id = 0xffffffff
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700638 for egress_port in of_ports:
639 if egress_port == ingress_port:
Dan Talayco32fa6542010-05-11 15:54:08 -0700640 act.port = ofp.OFPP_IN_PORT
641 else:
642 act.port = egress_port
643 self.assertTrue(request.actions.add(act),
644 "Could not add output to " + str(egress_port))
Rich Lane9a003812012-10-04 17:17:59 -0700645 # logging.info(request.show())
Dan Talayco2e77a842010-05-12 15:39:46 -0700646
Rich Lane9a003812012-10-04 17:17:59 -0700647 logging.info("Inserting flow")
Dan Talayco2e77a842010-05-12 15:39:46 -0700648 rv = self.controller.message_send(request)
649 self.assertTrue(rv != -1, "Error installing flow mod")
Dan Talayco0fc08bd2012-04-09 16:56:18 -0700650 self.assertEqual(do_barrier(self.controller), 0, "Barrier failed")
Dan Talayco2e77a842010-05-12 15:39:46 -0700651
Rich Lane9a003812012-10-04 17:17:59 -0700652 logging.info("Sending packet to dp port " + str(ingress_port))
Dan Talayco2e77a842010-05-12 15:39:46 -0700653 self.dataplane.send(ingress_port, str(pkt))
Rich Lane2014f9b2012-10-05 15:29:40 -0700654 receive_pkt_check(self.dataplane, pkt, of_ports, [], self)
Dan Talayco2e77a842010-05-12 15:39:46 -0700655
Rich Laneb90a1c42012-10-05 09:16:05 -0700656class Flood(base_tests.SimpleDataPlane):
Dan Talayco2e77a842010-05-12 15:39:46 -0700657 """
658 Flood to all ports except ingress
659
660 Generate a packet
661 Generate and install a matching flow
662 Add action to flood the packet
663 Send the packet to ingress dataplane port
664 Verify the packet is received at all other ports
665 """
666 def runTest(self):
Rich Lane477f4812012-10-04 22:49:00 -0700667 of_ports = config["port_map"].keys()
Dan Talayco2e77a842010-05-12 15:39:46 -0700668 of_ports.sort()
669 self.assertTrue(len(of_ports) > 1, "Not enough ports for test")
670
671 pkt = simple_tcp_packet()
Ed Swierk99a74de2012-08-22 06:40:54 -0700672 match = packet_to_flow_match(self, pkt)
Dan Talayco2e77a842010-05-12 15:39:46 -0700673 match.wildcards &= ~ofp.OFPFW_IN_PORT
674 self.assertTrue(match is not None,
675 "Could not generate flow match from pkt")
676 act = action.action_output()
677
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700678 for ingress_port in of_ports:
Rich Lane9a003812012-10-04 17:17:59 -0700679 rv = delete_all_flows(self.controller)
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700680 self.assertEqual(rv, 0, "Failed to delete all flows")
Dan Talayco2e77a842010-05-12 15:39:46 -0700681
Rich Lane9a003812012-10-04 17:17:59 -0700682 logging.info("Ingress " + str(ingress_port) + " to all ports")
Dan Talayco2e77a842010-05-12 15:39:46 -0700683 match.in_port = ingress_port
684
685 request = message.flow_mod()
686 request.match = match
687 request.buffer_id = 0xffffffff
688 act.port = ofp.OFPP_FLOOD
689 self.assertTrue(request.actions.add(act),
Dan Talayco4aa13122010-05-12 15:54:44 -0700690 "Could not add flood port action")
Rich Lane9a003812012-10-04 17:17:59 -0700691 logging.info(request.show())
Dan Talayco32fa6542010-05-11 15:54:08 -0700692
Rich Lane9a003812012-10-04 17:17:59 -0700693 logging.info("Inserting flow")
Dan Talayco32fa6542010-05-11 15:54:08 -0700694 rv = self.controller.message_send(request)
695 self.assertTrue(rv != -1, "Error installing flow mod")
Dan Talayco0fc08bd2012-04-09 16:56:18 -0700696 self.assertEqual(do_barrier(self.controller), 0, "Barrier failed")
Dan Talayco32fa6542010-05-11 15:54:08 -0700697
Rich Lane9a003812012-10-04 17:17:59 -0700698 logging.info("Sending packet to dp port " + str(ingress_port))
Dan Talayco32fa6542010-05-11 15:54:08 -0700699 self.dataplane.send(ingress_port, str(pkt))
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700700 yes_ports = set(of_ports).difference([ingress_port])
701 receive_pkt_check(self.dataplane, pkt, yes_ports, [ingress_port],
Rich Lane2014f9b2012-10-05 15:29:40 -0700702 self)
Dan Talayco3be5b062010-05-12 15:46:21 -0700703
Rich Laneb90a1c42012-10-05 09:16:05 -0700704class FloodPlusIngress(base_tests.SimpleDataPlane):
Dan Talayco3be5b062010-05-12 15:46:21 -0700705 """
706 Flood to all ports plus send to ingress port
707
708 Generate a packet
709 Generate and install a matching flow
710 Add action to flood the packet
711 Add action to send to ingress port
712 Send the packet to ingress dataplane port
713 Verify the packet is received at all other ports
714 """
715 def runTest(self):
Rich Lane477f4812012-10-04 22:49:00 -0700716 of_ports = config["port_map"].keys()
Dan Talayco3be5b062010-05-12 15:46:21 -0700717 of_ports.sort()
718 self.assertTrue(len(of_ports) > 1, "Not enough ports for test")
719
720 pkt = simple_tcp_packet()
Ed Swierk99a74de2012-08-22 06:40:54 -0700721 match = packet_to_flow_match(self, pkt)
Dan Talayco3be5b062010-05-12 15:46:21 -0700722 match.wildcards &= ~ofp.OFPFW_IN_PORT
723 self.assertTrue(match is not None,
724 "Could not generate flow match from pkt")
725 act = action.action_output()
726
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700727 for ingress_port in of_ports:
Rich Lane9a003812012-10-04 17:17:59 -0700728 rv = delete_all_flows(self.controller)
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700729 self.assertEqual(rv, 0, "Failed to delete all flows")
Dan Talayco3be5b062010-05-12 15:46:21 -0700730
Rich Lane9a003812012-10-04 17:17:59 -0700731 logging.info("Ingress " + str(ingress_port) + " to all ports")
Dan Talayco3be5b062010-05-12 15:46:21 -0700732 match.in_port = ingress_port
733
734 request = message.flow_mod()
735 request.match = match
736 request.buffer_id = 0xffffffff
737 act.port = ofp.OFPP_FLOOD
738 self.assertTrue(request.actions.add(act),
Dan Talayco4aa13122010-05-12 15:54:44 -0700739 "Could not add flood port action")
740 act.port = ofp.OFPP_IN_PORT
741 self.assertTrue(request.actions.add(act),
742 "Could not add ingress port for output")
Rich Lane9a003812012-10-04 17:17:59 -0700743 logging.info(request.show())
Dan Talayco4aa13122010-05-12 15:54:44 -0700744
Rich Lane9a003812012-10-04 17:17:59 -0700745 logging.info("Inserting flow")
Dan Talayco4aa13122010-05-12 15:54:44 -0700746 rv = self.controller.message_send(request)
747 self.assertTrue(rv != -1, "Error installing flow mod")
Dan Talayco0fc08bd2012-04-09 16:56:18 -0700748 self.assertEqual(do_barrier(self.controller), 0, "Barrier failed")
Dan Talayco4aa13122010-05-12 15:54:44 -0700749
Rich Lane9a003812012-10-04 17:17:59 -0700750 logging.info("Sending packet to dp port " + str(ingress_port))
Dan Talayco4aa13122010-05-12 15:54:44 -0700751 self.dataplane.send(ingress_port, str(pkt))
Rich Lane2014f9b2012-10-05 15:29:40 -0700752 receive_pkt_check(self.dataplane, pkt, of_ports, [], self)
Dan Talayco4aa13122010-05-12 15:54:44 -0700753
Rich Laneb90a1c42012-10-05 09:16:05 -0700754class All(base_tests.SimpleDataPlane):
Dan Talayco4aa13122010-05-12 15:54:44 -0700755 """
756 Send to OFPP_ALL port
757
758 Generate a packet
759 Generate and install a matching flow
760 Add action to forward to OFPP_ALL
761 Send the packet to ingress dataplane port
762 Verify the packet is received at all other ports
763 """
764 def runTest(self):
Rich Lane477f4812012-10-04 22:49:00 -0700765 of_ports = config["port_map"].keys()
Dan Talayco4aa13122010-05-12 15:54:44 -0700766 of_ports.sort()
767 self.assertTrue(len(of_ports) > 1, "Not enough ports for test")
768
769 pkt = simple_tcp_packet()
Ed Swierk99a74de2012-08-22 06:40:54 -0700770 match = packet_to_flow_match(self, pkt)
Dan Talayco4aa13122010-05-12 15:54:44 -0700771 match.wildcards &= ~ofp.OFPFW_IN_PORT
772 self.assertTrue(match is not None,
773 "Could not generate flow match from pkt")
774 act = action.action_output()
775
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700776 for ingress_port in of_ports:
Rich Lane9a003812012-10-04 17:17:59 -0700777 rv = delete_all_flows(self.controller)
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700778 self.assertEqual(rv, 0, "Failed to delete all flows")
Dan Talayco4aa13122010-05-12 15:54:44 -0700779
Rich Lane9a003812012-10-04 17:17:59 -0700780 logging.info("Ingress " + str(ingress_port) + " to all ports")
Dan Talayco4aa13122010-05-12 15:54:44 -0700781 match.in_port = ingress_port
782
783 request = message.flow_mod()
784 request.match = match
785 request.buffer_id = 0xffffffff
786 act.port = ofp.OFPP_ALL
787 self.assertTrue(request.actions.add(act),
788 "Could not add ALL port action")
Rich Lane9a003812012-10-04 17:17:59 -0700789 logging.info(request.show())
Dan Talayco4aa13122010-05-12 15:54:44 -0700790
Rich Lane9a003812012-10-04 17:17:59 -0700791 logging.info("Inserting flow")
Dan Talayco4aa13122010-05-12 15:54:44 -0700792 rv = self.controller.message_send(request)
793 self.assertTrue(rv != -1, "Error installing flow mod")
Dan Talayco0fc08bd2012-04-09 16:56:18 -0700794 self.assertEqual(do_barrier(self.controller), 0, "Barrier failed")
Dan Talayco4aa13122010-05-12 15:54:44 -0700795
Rich Lane9a003812012-10-04 17:17:59 -0700796 logging.info("Sending packet to dp port " + str(ingress_port))
Dan Talayco4aa13122010-05-12 15:54:44 -0700797 self.dataplane.send(ingress_port, str(pkt))
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700798 yes_ports = set(of_ports).difference([ingress_port])
799 receive_pkt_check(self.dataplane, pkt, yes_ports, [ingress_port],
Rich Lane2014f9b2012-10-05 15:29:40 -0700800 self)
Dan Talayco4aa13122010-05-12 15:54:44 -0700801
Rich Laneb90a1c42012-10-05 09:16:05 -0700802class AllPlusIngress(base_tests.SimpleDataPlane):
Dan Talayco4aa13122010-05-12 15:54:44 -0700803 """
804 Send to OFPP_ALL port and ingress port
805
806 Generate a packet
807 Generate and install a matching flow
808 Add action to forward to OFPP_ALL
809 Add action to forward to ingress port
810 Send the packet to ingress dataplane port
811 Verify the packet is received at all other ports
812 """
813 def runTest(self):
Rich Lane477f4812012-10-04 22:49:00 -0700814 of_ports = config["port_map"].keys()
Dan Talayco4aa13122010-05-12 15:54:44 -0700815 of_ports.sort()
816 self.assertTrue(len(of_ports) > 1, "Not enough ports for test")
817
818 pkt = simple_tcp_packet()
Ed Swierk99a74de2012-08-22 06:40:54 -0700819 match = packet_to_flow_match(self, pkt)
Dan Talayco4aa13122010-05-12 15:54:44 -0700820 match.wildcards &= ~ofp.OFPFW_IN_PORT
821 self.assertTrue(match is not None,
822 "Could not generate flow match from pkt")
823 act = action.action_output()
824
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700825 for ingress_port in of_ports:
Rich Lane9a003812012-10-04 17:17:59 -0700826 rv = delete_all_flows(self.controller)
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700827 self.assertEqual(rv, 0, "Failed to delete all flows")
Dan Talayco4aa13122010-05-12 15:54:44 -0700828
Rich Lane9a003812012-10-04 17:17:59 -0700829 logging.info("Ingress " + str(ingress_port) + " to all ports")
Dan Talayco4aa13122010-05-12 15:54:44 -0700830 match.in_port = ingress_port
831
832 request = message.flow_mod()
833 request.match = match
834 request.buffer_id = 0xffffffff
835 act.port = ofp.OFPP_ALL
836 self.assertTrue(request.actions.add(act),
837 "Could not add ALL port action")
Dan Talayco3be5b062010-05-12 15:46:21 -0700838 act.port = ofp.OFPP_IN_PORT
839 self.assertTrue(request.actions.add(act),
840 "Could not add ingress port for output")
Rich Lane9a003812012-10-04 17:17:59 -0700841 logging.info(request.show())
Dan Talayco3be5b062010-05-12 15:46:21 -0700842
Rich Lane9a003812012-10-04 17:17:59 -0700843 logging.info("Inserting flow")
Dan Talayco3be5b062010-05-12 15:46:21 -0700844 rv = self.controller.message_send(request)
845 self.assertTrue(rv != -1, "Error installing flow mod")
Dan Talayco0fc08bd2012-04-09 16:56:18 -0700846 self.assertEqual(do_barrier(self.controller), 0, "Barrier failed")
Dan Talayco3be5b062010-05-12 15:46:21 -0700847
Rich Lane9a003812012-10-04 17:17:59 -0700848 logging.info("Sending packet to dp port " + str(ingress_port))
Dan Talayco3be5b062010-05-12 15:46:21 -0700849 self.dataplane.send(ingress_port, str(pkt))
Rich Lane2014f9b2012-10-05 15:29:40 -0700850 receive_pkt_check(self.dataplane, pkt, of_ports, [], self)
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700851
Rich Laneb90a1c42012-10-05 09:16:05 -0700852class FloodMinusPort(base_tests.SimpleDataPlane):
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700853 """
854 Config port with No_Flood and test Flood action
855
856 Generate a packet
857 Generate a matching flow
858 Add action to forward to OFPP_ALL
859 Set port to no-flood
860 Send the packet to ingress dataplane port
861 Verify the packet is received at all other ports except
862 the ingress port and the no_flood port
863 """
864 def runTest(self):
Rich Lane477f4812012-10-04 22:49:00 -0700865 of_ports = config["port_map"].keys()
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700866 of_ports.sort()
867 self.assertTrue(len(of_ports) > 2, "Not enough ports for test")
868
869 pkt = simple_tcp_packet()
Ed Swierk99a74de2012-08-22 06:40:54 -0700870 match = packet_to_flow_match(self, pkt)
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700871 match.wildcards &= ~ofp.OFPFW_IN_PORT
872 self.assertTrue(match is not None,
873 "Could not generate flow match from pkt")
874 act = action.action_output()
875
Rich Lane4b9e38c2012-12-06 16:33:20 -0800876 # Clear OFPPC_NO_FLOOD on each port
877 for of_port in of_ports:
878 rv = port_config_set(self.controller, of_port,
879 0, ofp.OFPPC_NO_FLOOD)
880 self.assertEqual(rv, 0, "Failed to set port config")
881
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700882 for idx in range(len(of_ports)):
Rich Lane9a003812012-10-04 17:17:59 -0700883 rv = delete_all_flows(self.controller)
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700884 self.assertEqual(rv, 0, "Failed to delete all flows")
885
886 ingress_port = of_ports[idx]
887 no_flood_idx = (idx + 1) % len(of_ports)
888 no_flood_port = of_ports[no_flood_idx]
889 rv = port_config_set(self.controller, no_flood_port,
Rich Lane9a003812012-10-04 17:17:59 -0700890 ofp.OFPPC_NO_FLOOD, ofp.OFPPC_NO_FLOOD)
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700891 self.assertEqual(rv, 0, "Failed to set port config")
892
893 match.in_port = ingress_port
894
895 request = message.flow_mod()
896 request.match = match
897 request.buffer_id = 0xffffffff
898 act.port = ofp.OFPP_FLOOD
899 self.assertTrue(request.actions.add(act),
900 "Could not add flood port action")
Rich Lane9a003812012-10-04 17:17:59 -0700901 logging.info(request.show())
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700902
Rich Lane9a003812012-10-04 17:17:59 -0700903 logging.info("Inserting flow")
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700904 rv = self.controller.message_send(request)
905 self.assertTrue(rv != -1, "Error installing flow mod")
Dan Talayco0fc08bd2012-04-09 16:56:18 -0700906 self.assertEqual(do_barrier(self.controller), 0, "Barrier failed")
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700907
Rich Lane9a003812012-10-04 17:17:59 -0700908 logging.info("Sending packet to dp port " + str(ingress_port))
909 logging.info("No flood port is " + str(no_flood_port))
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700910 self.dataplane.send(ingress_port, str(pkt))
911 no_ports = set([ingress_port, no_flood_port])
912 yes_ports = set(of_ports).difference(no_ports)
Rich Lane2014f9b2012-10-05 15:29:40 -0700913 receive_pkt_check(self.dataplane, pkt, yes_ports, no_ports, self)
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700914
915 # Turn no flood off again
916 rv = port_config_set(self.controller, no_flood_port,
Rich Lane9a003812012-10-04 17:17:59 -0700917 0, ofp.OFPPC_NO_FLOOD)
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700918 self.assertEqual(rv, 0, "Failed to reset port config")
Rich Lane4ecc1f42012-12-06 16:35:24 -0800919 self.assertEqual(do_barrier(self.controller), 0, "Barrier failed")
920
921 # Check that packets are now flooded to no_flood_port
922 logging.info("Sending packet to dp port " + str(ingress_port))
923 self.dataplane.send(ingress_port, str(pkt))
924 no_ports = set([ingress_port])
925 yes_ports = set(of_ports).difference(no_ports)
926 receive_pkt_check(self.dataplane, pkt, yes_ports, no_ports, self)
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700927
928 #@todo Should check no other packets received
929
Dan Talayco21381562010-07-17 00:34:47 -0700930
931
Dan Talayco551befa2010-07-15 17:05:32 -0700932################################################################
933
Rich Laneb90a1c42012-10-05 09:16:05 -0700934class BaseMatchCase(base_tests.SimpleDataPlane):
Dan Talayco551befa2010-07-15 17:05:32 -0700935 def setUp(self):
Rich Laneb90a1c42012-10-05 09:16:05 -0700936 base_tests.SimpleDataPlane.setUp(self)
Dan Talayco551befa2010-07-15 17:05:32 -0700937 def runTest(self):
Rich Lane9a003812012-10-04 17:17:59 -0700938 logging.info("BaseMatchCase")
Dan Talayco551befa2010-07-15 17:05:32 -0700939
940class ExactMatch(BaseMatchCase):
Tatsuya Yabe6a6f38a2010-05-22 23:48:04 -0700941 """
Dan Talayco551befa2010-07-15 17:05:32 -0700942 Exercise exact matching for all port pairs
Tatsuya Yabe6a6f38a2010-05-22 23:48:04 -0700943
944 Generate a packet
945 Generate and install a matching flow without wildcard mask
946 Add action to forward to a port
947 Send the packet to the port
948 Verify the packet is received at all other ports (one port at a time)
Tatsuya Yabe6a6f38a2010-05-22 23:48:04 -0700949 """
Tatsuya Yabe0718ad32010-05-24 15:22:10 -0700950
Tatsuya Yabe6a6f38a2010-05-22 23:48:04 -0700951 def runTest(self):
Rich Lane477f4812012-10-04 22:49:00 -0700952 flow_match_test(self, config["port_map"])
Tatsuya Yabe6a6f38a2010-05-22 23:48:04 -0700953
Dan Talayco551befa2010-07-15 17:05:32 -0700954class ExactMatchTagged(BaseMatchCase):
955 """
956 Exact match for all port pairs with tagged pkts
957 """
Tatsuya Yabe6a6f38a2010-05-22 23:48:04 -0700958
Dan Talayco551befa2010-07-15 17:05:32 -0700959 def runTest(self):
Rich Lane2014f9b2012-10-05 15:29:40 -0700960 vid = test_param_get('vid', default=TEST_VID_DEFAULT)
Rich Lane477f4812012-10-04 22:49:00 -0700961 flow_match_test(self, config["port_map"], dl_vlan=vid)
Tatsuya Yabe6a6f38a2010-05-22 23:48:04 -0700962
Rich Lane0a4f6372013-01-02 14:40:22 -0800963@disabled
Dan Talayco551befa2010-07-15 17:05:32 -0700964class ExactMatchTaggedMany(BaseMatchCase):
965 """
966 ExactMatchTagged with many VLANS
967 """
Tatsuya Yabe6a6f38a2010-05-22 23:48:04 -0700968
Dan Talayco551befa2010-07-15 17:05:32 -0700969 def runTest(self):
Dan Talayco21381562010-07-17 00:34:47 -0700970 for vid in range(2,100,10):
Rich Lane477f4812012-10-04 22:49:00 -0700971 flow_match_test(self, config["port_map"], dl_vlan=vid, max_test=5)
Dan Talayco551befa2010-07-15 17:05:32 -0700972 for vid in range(100,4000,389):
Rich Lane477f4812012-10-04 22:49:00 -0700973 flow_match_test(self, config["port_map"], dl_vlan=vid, max_test=5)
974 flow_match_test(self, config["port_map"], dl_vlan=4094, max_test=5)
Tatsuya Yabecdf575e2010-05-25 16:56:38 -0700975
Jeffrey Townsend2a300e42012-03-28 17:24:02 -0700976class SingleWildcardMatchPriority(BaseMatchCase):
Jeffrey Townsend50c82462012-03-28 18:26:14 -0700977 """
978 SingleWildcardMatchPriority
979 """
Jeffrey Townsend2a300e42012-03-28 17:24:02 -0700980
Jeffrey Townsend50c82462012-03-28 18:26:14 -0700981 def _Init(self):
Jeffrey Townsend2a300e42012-03-28 17:24:02 -0700982 self.pkt = simple_tcp_packet()
983 self.flowMsgs = {}
984
Jeffrey Townsend50c82462012-03-28 18:26:14 -0700985 def _ClearTable(self):
Rich Lane9a003812012-10-04 17:17:59 -0700986 rc = delete_all_flows(self.controller)
Jeffrey Townsend50c82462012-03-28 18:26:14 -0700987 self.assertEqual(rc, 0, "Failed to delete all flows")
Dan Talayco0fc08bd2012-04-09 16:56:18 -0700988 self.assertEqual(do_barrier(self.controller), 0, "Barrier failed")
Jeffrey Townsend50c82462012-03-28 18:26:14 -0700989
990 def runTest(self):
991
992 self._Init()
Rich Lane477f4812012-10-04 22:49:00 -0700993 of_ports = config["port_map"].keys()
Jeffrey Townsend2a300e42012-03-28 17:24:02 -0700994 of_ports.sort()
995
996 # Delete the initial flow table
Jeffrey Townsend50c82462012-03-28 18:26:14 -0700997 self._ClearTable()
Jeffrey Townsend2a300e42012-03-28 17:24:02 -0700998
999 # Run several combinations, each at lower priority settings.
1000 # At the end of each call to runPrioFlows(), the table should
1001 # be empty. If its not, we'll catch it as the priorities decreases
1002 portA = of_ports[0]
1003 portB = of_ports[1]
1004 portC = of_ports[2]
1005
1006 # TODO -- these priority numbers should be validated somehow?
1007 self.runPrioFlows(portA, portB, portC, 1000, 999)
1008 self.runPrioFlows(portB, portC, portA, 998, 997)
1009 self.runPrioFlows(portC, portA, portB, 996, 995)
1010 self.runPrioFlows(portA, portC, portB, 994, 993)
1011
1012
Jeffrey Townsend50c82462012-03-28 18:26:14 -07001013
1014 def runPrioFlows(self, portA, portB, portC, prioHigher, prioLower,
1015 clearTable=False):
Jeffrey Townsend2a300e42012-03-28 17:24:02 -07001016
Jeffrey Townsend50c82462012-03-28 18:26:14 -07001017 if clearTable:
1018 self._ClearTable()
Jeffrey Townsend2a300e42012-03-28 17:24:02 -07001019
1020 # Sanity check flow at lower priority from pA to pB
Rich Lane9a003812012-10-04 17:17:59 -07001021 logging.info("runPrioFlows(pA=%d,pB=%d,pC=%d,ph=%d,pl=%d"
Jeffrey Townsend2a300e42012-03-28 17:24:02 -07001022 % (portA, portB, portC, prioHigher, prioLower))
1023
Jeffrey Townsend2a300e42012-03-28 17:24:02 -07001024 # Sanity check flow at lower priority from pA to pC
1025 self.installFlow(prioLower, portA, portC)
1026 self.verifyFlow(portA, portC)
1027 self.removeFlow(prioLower)
1028
1029 # Install and verify pA->pB @ prioLower
1030 self.installFlow(prioLower, portA, portB)
1031 self.verifyFlow(portA, portB)
1032
1033 # Install and verify pA->pC @ prioHigher, should override pA->pB
1034 self.installFlow(prioHigher, portA, portC)
1035 self.verifyFlow(portA, portC)
1036 # remove pA->pC
1037 self.removeFlow(prioHigher)
Jeffrey Townsend2a300e42012-03-28 17:24:02 -07001038 # Old flow pA -> pB @ prioLower should still be active
1039 self.verifyFlow(portA, portB)
1040 self.removeFlow(prioLower)
1041
1042 # Table should be empty at this point, leave it alone as
1043 # an assumption for future test runs
1044
1045
1046
Ed Swierk99a74de2012-08-22 06:40:54 -07001047 def installFlow(self, prio, inp, egp,
Jeffrey Townsend8364b162012-04-12 13:45:40 -07001048 wildcards=ofp.OFPFW_DL_SRC):
Ed Swierk99a74de2012-08-22 06:40:54 -07001049 wildcards |= required_wildcards(self)
Jeffrey Townsend2a300e42012-03-28 17:24:02 -07001050 request = flow_msg_create(self, self.pkt, ing_port=inp,
Jeffrey Townsend8364b162012-04-12 13:45:40 -07001051 wildcards=wildcards,
Jeffrey Townsend2a300e42012-03-28 17:24:02 -07001052 egr_ports=egp)
1053 request.priority = prio
Rich Lane9a003812012-10-04 17:17:59 -07001054 logging.debug("Install flow with priority " + str(prio))
Jeffrey Townsend50c82462012-03-28 18:26:14 -07001055 flow_msg_install(self, request, clear_table_override=False)
Jeffrey Townsend2a300e42012-03-28 17:24:02 -07001056 self.flowMsgs[prio] = request
1057
1058 def removeFlow(self, prio):
1059 if self.flowMsgs.has_key(prio):
1060 msg = self.flowMsgs[prio]
1061 msg.command = ofp.OFPFC_DELETE_STRICT
1062 # This *must* be set for DELETE
1063 msg.out_port = ofp.OFPP_NONE
Rich Lane9a003812012-10-04 17:17:59 -07001064 logging.debug("Remove flow with priority " + str(prio))
Jeffrey Townsend2a300e42012-03-28 17:24:02 -07001065 self.controller.message_send(msg)
Dan Talayco0fc08bd2012-04-09 16:56:18 -07001066 self.assertEqual(do_barrier(self.controller), 0, "Barrier failed")
Jeffrey Townsend50c82462012-03-28 18:26:14 -07001067 else:
1068 raise Exception("Not initialized")
Jeffrey Townsend2a300e42012-03-28 17:24:02 -07001069
1070
Jeffrey Townsend8364b162012-04-12 13:45:40 -07001071 def verifyFlow(self, inp, egp, pkt=None):
1072 if pkt == None:
1073 pkt = self.pkt
1074
Rich Lane9a003812012-10-04 17:17:59 -07001075 logging.info("Pkt match test: " + str(inp) + " to " + str(egp))
1076 logging.debug("Send packet: " + str(inp) + " to " + str(egp))
Jeffrey Townsend8364b162012-04-12 13:45:40 -07001077 self.dataplane.send(inp, str(pkt))
1078 receive_pkt_verify(self, egp, pkt, inp)
Jeffrey Townsend2a300e42012-03-28 17:24:02 -07001079
1080
1081
Jeffrey Townsend50c82462012-03-28 18:26:14 -07001082class SingleWildcardMatchPriorityInsertModifyDelete(SingleWildcardMatchPriority):
1083
1084 def runTest(self):
1085
1086 self._Init()
1087
Rich Lane477f4812012-10-04 22:49:00 -07001088 of_ports = config["port_map"].keys()
Jeffrey Townsend50c82462012-03-28 18:26:14 -07001089 of_ports.sort()
1090
1091 # Install an entry from 0 -> 1 @ prio 1000
1092 self._ClearTable()
1093 self.installFlow(1000, of_ports[0], of_ports[1])
1094 self.verifyFlow(of_ports[0], of_ports[1])
1095 self.installFlow(1000, of_ports[1], of_ports[0])
1096 self.verifyFlow(of_ports[1], of_ports[0])
1097 self.installFlow(1001, of_ports[0], of_ports[1])
1098 self.verifyFlow(of_ports[0], of_ports[1])
1099 self.installFlow(1001, of_ports[1], of_ports[0])
1100 self.verifyFlow(of_ports[1], of_ports[0])
1101 self.removeFlow(1001)
1102 self.verifyFlow(of_ports[0], of_ports[1])
1103 self.removeFlow(1000)
1104
1105
1106
Jeffrey Townsend8364b162012-04-12 13:45:40 -07001107class WildcardPriority(SingleWildcardMatchPriority):
Ken Chiang38d7a152012-05-24 15:33:50 -07001108 """
1109 1. Add wildcard flow, verify packet received.
Rich Lane0a78fbd2012-12-31 16:25:04 -08001110 2. Add wildcard flow with higher priority, verify packet received
Ken Chiang38d7a152012-05-24 15:33:50 -07001111 on port specified by this flow.
Rich Lane0a78fbd2012-12-31 16:25:04 -08001112 3. Add wildcard flow with lower priority, verify packet received
Rich Laneb8392082012-11-21 15:52:54 -08001113 on port specified by the highest priority flow.
Ken Chiang38d7a152012-05-24 15:33:50 -07001114 """
Jeffrey Townsend8364b162012-04-12 13:45:40 -07001115
1116 def runTest(self):
Jeffrey Townsend50c82462012-03-28 18:26:14 -07001117
Jeffrey Townsend8364b162012-04-12 13:45:40 -07001118 self._Init()
1119
Rich Lane477f4812012-10-04 22:49:00 -07001120 of_ports = config["port_map"].keys()
Jeffrey Townsend8364b162012-04-12 13:45:40 -07001121 of_ports.sort()
1122
1123 self._ClearTable()
Ken Chiang38d7a152012-05-24 15:33:50 -07001124
1125 # Install a flow with wildcards
1126 self.installFlow(999, of_ports[0], of_ports[1],
1127 wildcards=ofp.OFPFW_DL_DST)
Jeffrey Townsend8364b162012-04-12 13:45:40 -07001128 self.verifyFlow(of_ports[0], of_ports[1])
Rich Lane0a78fbd2012-12-31 16:25:04 -08001129 # Install a flow with wildcards with higher priority
1130 self.installFlow(1000, of_ports[0], of_ports[2],
1131 wildcards=ofp.OFPFW_DL_DST)
Jeffrey Townsend8364b162012-04-12 13:45:40 -07001132 self.verifyFlow(of_ports[0], of_ports[2])
Rich Lane0a78fbd2012-12-31 16:25:04 -08001133 # Install a flow with wildcards with lower priority
Rich Laneb8392082012-11-21 15:52:54 -08001134 self.installFlow(999, of_ports[0], of_ports[1],
1135 wildcards=ofp.OFPFW_DL_SRC)
Rich Lane0a78fbd2012-12-31 16:25:04 -08001136 self.verifyFlow(of_ports[0], of_ports[2])
Jeffrey Townsend8364b162012-04-12 13:45:40 -07001137
1138
Ken Chiang3978f242012-06-13 14:14:09 -07001139class WildcardPriorityWithDelete(SingleWildcardMatchPriority):
Ken Chiang38d7a152012-05-24 15:33:50 -07001140 """
Rich Lane0a78fbd2012-12-31 16:25:04 -08001141 1. Add wildcard match flow, verify packet received.
Ken Chiang38d7a152012-05-24 15:33:50 -07001142 2. Add wildcard flow with higher priority, verify packet received on port
1143 specified by this flow.
Rich Lane0a78fbd2012-12-31 16:25:04 -08001144 3. Add wildcard flow with even higher priority, verify packet received
Ken Chiang38d7a152012-05-24 15:33:50 -07001145 on port specified by this flow.
1146 4. Delete lowest priority flow, verify packet received on port specified
1147 by highest priority flow.
1148 5. Delete highest priority flow, verify packet received on port specified
1149 by remaining flow.
1150 """
1151
1152 def runTest(self):
1153
1154 self._Init()
1155
Rich Lane477f4812012-10-04 22:49:00 -07001156 of_ports = config["port_map"].keys()
Ken Chiang38d7a152012-05-24 15:33:50 -07001157 of_ports.sort()
1158
1159 self._ClearTable()
1160
Rich Lane0a78fbd2012-12-31 16:25:04 -08001161 # Install a flow with wildcards
1162 self.installFlow(250, of_ports[0], of_ports[1],
1163 wildcards=ofp.OFPFW_DL_DST)
Ken Chiang38d7a152012-05-24 15:33:50 -07001164 self.verifyFlow(of_ports[0], of_ports[1])
1165 # Install a flow with wildcards of higher priority
1166 self.installFlow(1250, of_ports[0], of_ports[2],
1167 wildcards=ofp.OFPFW_DL_DST)
1168 self.verifyFlow(of_ports[0], of_ports[2])
Rich Lane0a78fbd2012-12-31 16:25:04 -08001169 # Install a flow with wildcards with even higher priority
1170 self.installFlow(2001, of_ports[0], of_ports[3],
1171 wildcards=ofp.OFPFW_DL_DST)
Ken Chiang38d7a152012-05-24 15:33:50 -07001172 self.verifyFlow(of_ports[0], of_ports[3])
1173 # Delete lowest priority flow
1174 self.removeFlow(250)
1175 self.verifyFlow(of_ports[0], of_ports[3])
1176 # Delete highest priority flow
1177 self.removeFlow(2001)
1178 self.verifyFlow(of_ports[0], of_ports[2])
1179
Jeffrey Townsend8364b162012-04-12 13:45:40 -07001180
Dan Talayco551befa2010-07-15 17:05:32 -07001181class SingleWildcardMatch(BaseMatchCase):
Tatsuya Yabe6a6f38a2010-05-22 23:48:04 -07001182 """
1183 Exercise wildcard matching for all ports
1184
1185 Generate a packet
1186 Generate and install a matching flow with wildcard mask
1187 Add action to forward to a port
1188 Send the packet to the port
1189 Verify the packet is received at all other ports (one port at a time)
Tatsuya Yabe0718ad32010-05-24 15:22:10 -07001190 Verify flow_expiration message is correct when command option is set
Tatsuya Yabe6a6f38a2010-05-22 23:48:04 -07001191 """
Tatsuya Yabe0718ad32010-05-24 15:22:10 -07001192 def runTest(self):
Rich Lane2014f9b2012-10-05 15:29:40 -07001193 vid = test_param_get('vid', default=TEST_VID_DEFAULT)
Dan Talayco551befa2010-07-15 17:05:32 -07001194 for wc in WILDCARD_VALUES:
Ed Swierk99a74de2012-08-22 06:40:54 -07001195 wc |= required_wildcards(self)
Dan Talayco4431d542012-03-21 16:42:16 -07001196 if wc & ofp.OFPFW_DL_VLAN:
Ken Chiang5be06dd2012-04-03 10:03:50 -07001197 # Set nonzero VLAN id to avoid sending priority-tagged packet
1198 dl_vlan = vid
Dan Talayco4431d542012-03-21 16:42:16 -07001199 else:
1200 dl_vlan = -1
Rich Lane477f4812012-10-04 22:49:00 -07001201 flow_match_test(self, config["port_map"], wildcards=wc,
Dan Talayco4431d542012-03-21 16:42:16 -07001202 dl_vlan=dl_vlan, max_test=10)
Tatsuya Yabe4fad7e32010-05-24 15:24:50 -07001203
Dan Talayco551befa2010-07-15 17:05:32 -07001204class SingleWildcardMatchTagged(BaseMatchCase):
1205 """
1206 SingleWildcardMatch with tagged packets
1207 """
1208 def runTest(self):
Rich Lane2014f9b2012-10-05 15:29:40 -07001209 vid = test_param_get('vid', default=TEST_VID_DEFAULT)
Dan Talayco551befa2010-07-15 17:05:32 -07001210 for wc in WILDCARD_VALUES:
Ed Swierk99a74de2012-08-22 06:40:54 -07001211 wc |= required_wildcards(self)
Rich Lane477f4812012-10-04 22:49:00 -07001212 flow_match_test(self, config["port_map"], wildcards=wc, dl_vlan=vid,
Dan Talayco551befa2010-07-15 17:05:32 -07001213 max_test=10)
1214
1215class AllExceptOneWildcardMatch(BaseMatchCase):
Tatsuya Yabe4fad7e32010-05-24 15:24:50 -07001216 """
Dan Talayco80b54ed2010-07-13 09:48:35 -07001217 Match exactly one field
Tatsuya Yabe4fad7e32010-05-24 15:24:50 -07001218
1219 Generate a packet
1220 Generate and install a matching flow with wildcard all except one filed
1221 Add action to forward to a port
1222 Send the packet to the port
1223 Verify the packet is received at all other ports (one port at a time)
1224 Verify flow_expiration message is correct when command option is set
1225 """
1226 def runTest(self):
Rich Lane2014f9b2012-10-05 15:29:40 -07001227 vid = test_param_get('vid', default=TEST_VID_DEFAULT)
Dan Talayco488fbc52012-04-09 16:30:41 -07001228 for all_exp_one_wildcard in NO_WILDCARD_VALUES:
Ed Swierk99a74de2012-08-22 06:40:54 -07001229 all_exp_one_wildcard |= required_wildcards(self)
Dan Talayco4431d542012-03-21 16:42:16 -07001230 if all_exp_one_wildcard & ofp.OFPFW_DL_VLAN:
Ken Chiang5be06dd2012-04-03 10:03:50 -07001231 # Set nonzero VLAN id to avoid sending priority-tagged packet
1232 dl_vlan = vid
Dan Talayco4431d542012-03-21 16:42:16 -07001233 else:
1234 dl_vlan = -1
Rich Lane477f4812012-10-04 22:49:00 -07001235 flow_match_test(self, config["port_map"], wildcards=all_exp_one_wildcard,
Dan Talayco4431d542012-03-21 16:42:16 -07001236 dl_vlan=dl_vlan)
Tatsuya Yabee30ebe22010-05-25 09:30:49 -07001237
Dan Talayco551befa2010-07-15 17:05:32 -07001238class AllExceptOneWildcardMatchTagged(BaseMatchCase):
1239 """
1240 Match one field with tagged packets
1241 """
1242 def runTest(self):
Rich Lane2014f9b2012-10-05 15:29:40 -07001243 vid = test_param_get('vid', default=TEST_VID_DEFAULT)
Dan Talayco488fbc52012-04-09 16:30:41 -07001244 for all_exp_one_wildcard in NO_WILDCARD_VALUES:
Ed Swierk99a74de2012-08-22 06:40:54 -07001245 all_exp_one_wildcard |= required_wildcards(self)
Rich Lane477f4812012-10-04 22:49:00 -07001246 flow_match_test(self, config["port_map"], wildcards=all_exp_one_wildcard,
Dan Talayco21381562010-07-17 00:34:47 -07001247 dl_vlan=vid)
Dan Talayco551befa2010-07-15 17:05:32 -07001248
1249class AllWildcardMatch(BaseMatchCase):
Tatsuya Yabee30ebe22010-05-25 09:30:49 -07001250 """
1251 Create Wildcard-all flow and exercise for all ports
1252
1253 Generate a packet
1254 Generate and install a matching flow with wildcard-all
1255 Add action to forward to a port
1256 Send the packet to the port
1257 Verify the packet is received at all other ports (one port at a time)
1258 Verify flow_expiration message is correct when command option is set
1259 """
1260 def runTest(self):
Rich Lane477f4812012-10-04 22:49:00 -07001261 flow_match_test(self, config["port_map"], wildcards=ofp.OFPFW_ALL)
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -07001262
Dan Talayco551befa2010-07-15 17:05:32 -07001263class AllWildcardMatchTagged(BaseMatchCase):
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -07001264 """
Dan Talayco551befa2010-07-15 17:05:32 -07001265 AllWildcardMatch with tagged packets
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -07001266 """
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -07001267 def runTest(self):
Rich Lane2014f9b2012-10-05 15:29:40 -07001268 vid = test_param_get('vid', default=TEST_VID_DEFAULT)
Rich Lane477f4812012-10-04 22:49:00 -07001269 flow_match_test(self, config["port_map"], wildcards=ofp.OFPFW_ALL,
Dan Talayco21381562010-07-17 00:34:47 -07001270 dl_vlan=vid)
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -07001271
Dan Talaycoba3745c2010-07-21 21:51:08 -07001272
Dan Talayco551befa2010-07-15 17:05:32 -07001273class AddVLANTag(BaseMatchCase):
1274 """
1275 Add a VLAN tag to an untagged packet
1276 """
1277 def runTest(self):
1278 new_vid = 2
Ed Swierkc7193a22012-08-22 06:51:02 -07001279 sup_acts = self.supported_actions
Dan Talayco551befa2010-07-15 17:05:32 -07001280 if not(sup_acts & 1<<ofp.OFPAT_SET_VLAN_VID):
Dan Talaycoba3745c2010-07-21 21:51:08 -07001281 skip_message_emit(self, "Add VLAN tag test")
Dan Talaycof36f1082010-07-13 13:57:17 -07001282 return
Tatsuya Yabef5ffb972010-05-26 15:36:33 -07001283
Dan Talayco551befa2010-07-15 17:05:32 -07001284 len = 100
1285 len_w_vid = 104
1286 pkt = simple_tcp_packet(pktlen=len)
1287 exp_pkt = simple_tcp_packet(pktlen=len_w_vid, dl_vlan_enable=True,
1288 dl_vlan=new_vid)
1289 vid_act = action.action_set_vlan_vid()
1290 vid_act.vlan_vid = new_vid
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -07001291
Rich Lane477f4812012-10-04 22:49:00 -07001292 flow_match_test(self, config["port_map"], pkt=pkt,
Dan Talayco551befa2010-07-15 17:05:32 -07001293 exp_pkt=exp_pkt, action_list=[vid_act])
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -07001294
Rich Lane0a4f6372013-01-02 14:40:22 -08001295@disabled
Rich Laneb90a1c42012-10-05 09:16:05 -07001296class PacketOnly(base_tests.DataPlaneOnly):
Dan Talayco551befa2010-07-15 17:05:32 -07001297 """
1298 Just send a packet thru the switch
1299 """
Rich Laned1d9c282012-10-04 22:07:10 -07001300
Dan Talayco551befa2010-07-15 17:05:32 -07001301 def runTest(self):
1302 pkt = simple_tcp_packet()
Rich Lane477f4812012-10-04 22:49:00 -07001303 of_ports = config["port_map"].keys()
Dan Talayco551befa2010-07-15 17:05:32 -07001304 of_ports.sort()
1305 ing_port = of_ports[0]
Rich Lane9a003812012-10-04 17:17:59 -07001306 logging.info("Sending packet to " + str(ing_port))
1307 logging.debug("Data: " + str(pkt).encode('hex'))
Dan Talayco551befa2010-07-15 17:05:32 -07001308 self.dataplane.send(ing_port, str(pkt))
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -07001309
Rich Lane0a4f6372013-01-02 14:40:22 -08001310@disabled
Rich Laneb90a1c42012-10-05 09:16:05 -07001311class PacketOnlyTagged(base_tests.DataPlaneOnly):
Dan Talayco551befa2010-07-15 17:05:32 -07001312 """
1313 Just send a packet thru the switch
1314 """
Rich Laned1d9c282012-10-04 22:07:10 -07001315
Dan Talayco551befa2010-07-15 17:05:32 -07001316 def runTest(self):
Rich Lane2014f9b2012-10-05 15:29:40 -07001317 vid = test_param_get('vid', default=TEST_VID_DEFAULT)
Dan Talayco551befa2010-07-15 17:05:32 -07001318 pkt = simple_tcp_packet(dl_vlan_enable=True, dl_vlan=vid)
Rich Lane477f4812012-10-04 22:49:00 -07001319 of_ports = config["port_map"].keys()
Dan Talayco551befa2010-07-15 17:05:32 -07001320 of_ports.sort()
1321 ing_port = of_ports[0]
Rich Lane9a003812012-10-04 17:17:59 -07001322 logging.info("Sending packet to " + str(ing_port))
1323 logging.debug("Data: " + str(pkt).encode('hex'))
Dan Talayco551befa2010-07-15 17:05:32 -07001324 self.dataplane.send(ing_port, str(pkt))
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -07001325
Dan Talayco551befa2010-07-15 17:05:32 -07001326class ModifyVID(BaseMatchCase):
Dan Talayco4b2bee62010-07-20 14:10:05 -07001327 """
1328 Modify the VLAN ID in the VLAN tag of a tagged packet
1329 """
Dan Talaycoaf669322012-09-12 22:51:22 -07001330 def setUp(self):
1331 BaseMatchCase.setUp(self)
1332 self.ing_port=False
1333
Dan Talayco551befa2010-07-15 17:05:32 -07001334 def runTest(self):
1335 old_vid = 2
1336 new_vid = 3
Ed Swierkc7193a22012-08-22 06:51:02 -07001337 sup_acts = self.supported_actions
Dan Talayco4b2bee62010-07-20 14:10:05 -07001338 if not (sup_acts & 1 << ofp.OFPAT_SET_VLAN_VID):
Dan Talaycoba3745c2010-07-21 21:51:08 -07001339 skip_message_emit(self, "Modify VLAN tag test")
Dan Talayco551befa2010-07-15 17:05:32 -07001340 return
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -07001341
Dan Talayco551befa2010-07-15 17:05:32 -07001342 pkt = simple_tcp_packet(dl_vlan_enable=True, dl_vlan=old_vid)
1343 exp_pkt = simple_tcp_packet(dl_vlan_enable=True, dl_vlan=new_vid)
1344 vid_act = action.action_set_vlan_vid()
1345 vid_act.vlan_vid = new_vid
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -07001346
Rich Lane477f4812012-10-04 22:49:00 -07001347 flow_match_test(self, config["port_map"], pkt=pkt, exp_pkt=exp_pkt,
Dan Talaycoaf669322012-09-12 22:51:22 -07001348 action_list=[vid_act], ing_port=self.ing_port)
1349
1350class ModifyVIDToIngress(ModifyVID):
1351 """
1352 Modify the VLAN ID in the VLAN tag of a tagged packet and send to
1353 ingress port
1354 """
1355 def setUp(self):
1356 BaseMatchCase.setUp(self)
1357 self.ing_port=True
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -07001358
Ken Chiange9a211d2012-04-20 14:52:11 -07001359class ModifyVIDWithTagMatchWildcarded(BaseMatchCase):
1360 """
1361 With vlan ID and priority wildcarded, perform SET_VLAN_VID action.
1362 The same flow should match on both untagged and tagged packets.
1363 """
1364 def runTest(self):
1365 old_vid = 2
1366 new_vid = 3
Ed Swierkc7193a22012-08-22 06:51:02 -07001367 sup_acts = self.supported_actions
Ken Chiange9a211d2012-04-20 14:52:11 -07001368 if not (sup_acts & 1 << ofp.OFPAT_SET_VLAN_VID):
1369 skip_message_emit(self, "ModifyVIDWithTagWildcarded test")
1370 return
1371
Rich Lane477f4812012-10-04 22:49:00 -07001372 of_ports = config["port_map"].keys()
Ken Chiange9a211d2012-04-20 14:52:11 -07001373 self.assertTrue(len(of_ports) > 1, "Not enough ports for test")
1374 ing_port = of_ports[0]
1375 egr_ports = of_ports[1]
1376
Rich Lane9a003812012-10-04 17:17:59 -07001377 rv = delete_all_flows(self.controller)
Ken Chiange9a211d2012-04-20 14:52:11 -07001378 self.assertEqual(rv, 0, "Failed to delete all flows")
1379
1380 len_untagged = 100
1381 len_w_vid = 104
1382 untagged_pkt = simple_tcp_packet(pktlen=len_untagged)
1383 tagged_pkt = simple_tcp_packet(pktlen=len_w_vid,
1384 dl_vlan_enable=True, dl_vlan=old_vid)
1385 exp_pkt = simple_tcp_packet(pktlen=len_w_vid, dl_vlan_enable=True,
1386 dl_vlan=new_vid)
Ed Swierk99a74de2012-08-22 06:40:54 -07001387 wildcards = (required_wildcards(self) | ofp.OFPFW_DL_VLAN |
1388 ofp.OFPFW_DL_VLAN_PCP)
Ken Chiange9a211d2012-04-20 14:52:11 -07001389 vid_act = action.action_set_vlan_vid()
1390 vid_act.vlan_vid = new_vid
1391 request = flow_msg_create(self, untagged_pkt, ing_port=ing_port,
1392 wildcards=wildcards, egr_ports=egr_ports,
1393 action_list=[vid_act])
1394 flow_msg_install(self, request)
1395
Rich Lane9a003812012-10-04 17:17:59 -07001396 logging.debug("Send untagged packet: " + str(ing_port) + " to " +
Ken Chiange9a211d2012-04-20 14:52:11 -07001397 str(egr_ports))
1398 self.dataplane.send(ing_port, str(untagged_pkt))
1399 receive_pkt_verify(self, egr_ports, exp_pkt, ing_port)
1400
Rich Lane9a003812012-10-04 17:17:59 -07001401 logging.debug("Send tagged packet: " + str(ing_port) + " to " +
Ken Chiange9a211d2012-04-20 14:52:11 -07001402 str(egr_ports))
1403 self.dataplane.send(ing_port, str(tagged_pkt))
1404 receive_pkt_verify(self, egr_ports, exp_pkt, ing_port)
1405
Howard Pershc1199d52012-04-11 14:21:32 -07001406class ModifyVlanPcp(BaseMatchCase):
1407 """
1408 Modify the priority field of the VLAN tag of a tagged packet
1409 """
1410 def runTest(self):
1411 vid = 123
1412 old_vlan_pcp = 2
1413 new_vlan_pcp = 3
Ed Swierkc7193a22012-08-22 06:51:02 -07001414 sup_acts = self.supported_actions
Ed Swierk8c3af7f2012-04-24 14:19:17 -07001415 if not (sup_acts & 1 << ofp.OFPAT_SET_VLAN_PCP):
1416 skip_message_emit(self, "Modify VLAN priority test")
Howard Pershc1199d52012-04-11 14:21:32 -07001417 return
1418
1419 pkt = simple_tcp_packet(dl_vlan_enable=True, dl_vlan=vid, dl_vlan_pcp=old_vlan_pcp)
1420 exp_pkt = simple_tcp_packet(dl_vlan_enable=True, dl_vlan=vid, dl_vlan_pcp=new_vlan_pcp)
1421 vid_act = action.action_set_vlan_pcp()
1422 vid_act.vlan_pcp = new_vlan_pcp
1423
Rich Lane477f4812012-10-04 22:49:00 -07001424 flow_match_test(self, config["port_map"], pkt=pkt, exp_pkt=exp_pkt,
Howard Pershc1199d52012-04-11 14:21:32 -07001425 action_list=[vid_act])
1426
Dan Talayco551befa2010-07-15 17:05:32 -07001427class StripVLANTag(BaseMatchCase):
Dan Talayco4b2bee62010-07-20 14:10:05 -07001428 """
1429 Strip the VLAN tag from a tagged packet
1430 """
Dan Talayco551befa2010-07-15 17:05:32 -07001431 def runTest(self):
1432 old_vid = 2
Ed Swierkc7193a22012-08-22 06:51:02 -07001433 sup_acts = self.supported_actions
Dan Talayco4b2bee62010-07-20 14:10:05 -07001434 if not (sup_acts & 1 << ofp.OFPAT_STRIP_VLAN):
Dan Talaycoba3745c2010-07-21 21:51:08 -07001435 skip_message_emit(self, "Strip VLAN tag test")
Dan Talayco551befa2010-07-15 17:05:32 -07001436 return
Dan Talaycof36f1082010-07-13 13:57:17 -07001437
Dan Talayco551befa2010-07-15 17:05:32 -07001438 len_w_vid = 104
1439 len = 100
1440 pkt = simple_tcp_packet(pktlen=len_w_vid, dl_vlan_enable=True,
1441 dl_vlan=old_vid)
1442 exp_pkt = simple_tcp_packet(pktlen=len)
1443 vid_act = action.action_strip_vlan()
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -07001444
Rich Lane477f4812012-10-04 22:49:00 -07001445 flow_match_test(self, config["port_map"], pkt=pkt, exp_pkt=exp_pkt,
Dan Talayco551befa2010-07-15 17:05:32 -07001446 action_list=[vid_act])
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -07001447
Ken Chiange9a211d2012-04-20 14:52:11 -07001448class StripVLANTagWithTagMatchWildcarded(BaseMatchCase):
1449 """
1450 Strip the VLAN tag from a tagged packet.
1451 Differs from StripVLANTag in that VID and PCP are both wildcarded.
1452 """
1453 def runTest(self):
1454 old_vid = 2
Ed Swierkc7193a22012-08-22 06:51:02 -07001455 sup_acts = self.supported_actions
Ken Chiange9a211d2012-04-20 14:52:11 -07001456 if not (sup_acts & 1 << ofp.OFPAT_STRIP_VLAN):
1457 skip_message_emit(self, "StripVLANTagWithTagWildcarded test")
1458 return
1459
1460 len_w_vid = 104
1461 len_untagged = 100
1462 pkt = simple_tcp_packet(pktlen=len_w_vid, dl_vlan_enable=True,
1463 dl_vlan=old_vid)
1464 exp_pkt = simple_tcp_packet(pktlen=len_untagged)
Ed Swierk99a74de2012-08-22 06:40:54 -07001465 wildcards = (required_wildcards(self) | ofp.OFPFW_DL_VLAN |
1466 ofp.OFPFW_DL_VLAN_PCP)
Ken Chiange9a211d2012-04-20 14:52:11 -07001467 vid_act = action.action_strip_vlan()
1468
Rich Lane477f4812012-10-04 22:49:00 -07001469 flow_match_test(self, config["port_map"],
Ed Swierk99a74de2012-08-22 06:40:54 -07001470 wildcards=wildcards,
Ken Chiange9a211d2012-04-20 14:52:11 -07001471 pkt=pkt, exp_pkt=exp_pkt,
1472 action_list=[vid_act])
1473
Dan Talayco4b2bee62010-07-20 14:10:05 -07001474def init_pkt_args():
1475 """
1476 Pass back a dictionary with default packet arguments
1477 """
1478 args = {}
1479 args["dl_src"] = '00:23:45:67:89:AB'
1480
1481 dl_vlan_enable=False
1482 dl_vlan=-1
Rich Lane477f4812012-10-04 22:49:00 -07001483 if config["test-params"]["vid"]:
Dan Talayco4b2bee62010-07-20 14:10:05 -07001484 dl_vlan_enable=True
Rich Lane477f4812012-10-04 22:49:00 -07001485 dl_vlan = config["test-params"]["vid"]
Dan Talayco4b2bee62010-07-20 14:10:05 -07001486
1487# Unpack operator is ** on a dictionary
1488
1489 return args
1490
Dan Talayco551befa2010-07-15 17:05:32 -07001491class ModifyL2Src(BaseMatchCase):
Dan Talayco4b2bee62010-07-20 14:10:05 -07001492 """
1493 Modify the source MAC address (TP1)
1494 """
Dan Talayco551befa2010-07-15 17:05:32 -07001495 def runTest(self):
Ed Swierkc7193a22012-08-22 06:51:02 -07001496 sup_acts = self.supported_actions
Dan Talayco4b2bee62010-07-20 14:10:05 -07001497 if not (sup_acts & 1 << ofp.OFPAT_SET_DL_SRC):
Dan Talaycoba3745c2010-07-21 21:51:08 -07001498 skip_message_emit(self, "ModifyL2Src test")
Dan Talayco4b2bee62010-07-20 14:10:05 -07001499 return
1500
1501 (pkt, exp_pkt, acts) = pkt_action_setup(self, mod_fields=['dl_src'],
1502 check_test_params=True)
Rich Lane477f4812012-10-04 22:49:00 -07001503 flow_match_test(self, config["port_map"], pkt=pkt, exp_pkt=exp_pkt,
Dan Talayco4b2bee62010-07-20 14:10:05 -07001504 action_list=acts, max_test=2)
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -07001505
Dan Talayco551befa2010-07-15 17:05:32 -07001506class ModifyL2Dst(BaseMatchCase):
Dan Talayco4b2bee62010-07-20 14:10:05 -07001507 """
1508 Modify the dest MAC address (TP1)
1509 """
Dan Talayco551befa2010-07-15 17:05:32 -07001510 def runTest(self):
Ed Swierkc7193a22012-08-22 06:51:02 -07001511 sup_acts = self.supported_actions
Dan Talayco4b2bee62010-07-20 14:10:05 -07001512 if not (sup_acts & 1 << ofp.OFPAT_SET_DL_DST):
Dan Talaycoba3745c2010-07-21 21:51:08 -07001513 skip_message_emit(self, "ModifyL2dst test")
Dan Talayco4b2bee62010-07-20 14:10:05 -07001514 return
1515
1516 (pkt, exp_pkt, acts) = pkt_action_setup(self, mod_fields=['dl_dst'],
1517 check_test_params=True)
Rich Lane477f4812012-10-04 22:49:00 -07001518 flow_match_test(self, config["port_map"], pkt=pkt, exp_pkt=exp_pkt,
Dan Talayco4b2bee62010-07-20 14:10:05 -07001519 action_list=acts, max_test=2)
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -07001520
Dan Talayco551befa2010-07-15 17:05:32 -07001521class ModifyL3Src(BaseMatchCase):
Dan Talayco4b2bee62010-07-20 14:10:05 -07001522 """
1523 Modify the source IP address of an IP packet (TP1)
1524 """
Dan Talayco551befa2010-07-15 17:05:32 -07001525 def runTest(self):
Ed Swierkc7193a22012-08-22 06:51:02 -07001526 sup_acts = self.supported_actions
Dan Talayco4b2bee62010-07-20 14:10:05 -07001527 if not (sup_acts & 1 << ofp.OFPAT_SET_NW_SRC):
Dan Talaycoba3745c2010-07-21 21:51:08 -07001528 skip_message_emit(self, "ModifyL3Src test")
Dan Talayco4b2bee62010-07-20 14:10:05 -07001529 return
1530
1531 (pkt, exp_pkt, acts) = pkt_action_setup(self, mod_fields=['ip_src'],
1532 check_test_params=True)
Rich Lane477f4812012-10-04 22:49:00 -07001533 flow_match_test(self, config["port_map"], pkt=pkt, exp_pkt=exp_pkt,
Dan Talayco4b2bee62010-07-20 14:10:05 -07001534 action_list=acts, max_test=2)
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -07001535
Dan Talayco551befa2010-07-15 17:05:32 -07001536class ModifyL3Dst(BaseMatchCase):
Dan Talayco4b2bee62010-07-20 14:10:05 -07001537 """
1538 Modify the dest IP address of an IP packet (TP1)
1539 """
Dan Talayco551befa2010-07-15 17:05:32 -07001540 def runTest(self):
Ed Swierkc7193a22012-08-22 06:51:02 -07001541 sup_acts = self.supported_actions
Dan Talayco4b2bee62010-07-20 14:10:05 -07001542 if not (sup_acts & 1 << ofp.OFPAT_SET_NW_DST):
Dan Talaycoba3745c2010-07-21 21:51:08 -07001543 skip_message_emit(self, "ModifyL3Dst test")
Dan Talayco4b2bee62010-07-20 14:10:05 -07001544 return
1545
1546 (pkt, exp_pkt, acts) = pkt_action_setup(self, mod_fields=['ip_dst'],
1547 check_test_params=True)
Rich Lane477f4812012-10-04 22:49:00 -07001548 flow_match_test(self, config["port_map"], pkt=pkt, exp_pkt=exp_pkt,
Dan Talayco4b2bee62010-07-20 14:10:05 -07001549 action_list=acts, max_test=2)
Dan Talayco551befa2010-07-15 17:05:32 -07001550
1551class ModifyL4Src(BaseMatchCase):
Dan Talayco4b2bee62010-07-20 14:10:05 -07001552 """
1553 Modify the source TCP port of a TCP packet (TP1)
1554 """
Dan Talayco551befa2010-07-15 17:05:32 -07001555 def runTest(self):
Ed Swierkc7193a22012-08-22 06:51:02 -07001556 sup_acts = self.supported_actions
Dan Talayco4b2bee62010-07-20 14:10:05 -07001557 if not (sup_acts & 1 << ofp.OFPAT_SET_TP_SRC):
Dan Talaycoba3745c2010-07-21 21:51:08 -07001558 skip_message_emit(self, "ModifyL4Src test")
Dan Talayco4b2bee62010-07-20 14:10:05 -07001559 return
1560
1561 (pkt, exp_pkt, acts) = pkt_action_setup(self, mod_fields=['tcp_sport'],
1562 check_test_params=True)
Rich Lane477f4812012-10-04 22:49:00 -07001563 flow_match_test(self, config["port_map"], pkt=pkt, exp_pkt=exp_pkt,
Dan Talayco4b2bee62010-07-20 14:10:05 -07001564 action_list=acts, max_test=2)
Dan Talayco551befa2010-07-15 17:05:32 -07001565
Rich Lane01c2b862012-10-26 16:26:25 -07001566class ModifyL4SrcUdp(BaseMatchCase):
1567 """
1568 Modify the source UDP port of a UDP packet
1569 """
1570 def runTest(self):
1571 sup_acts = self.supported_actions
1572 if not (sup_acts & 1 << ofp.OFPAT_SET_TP_DST):
1573 skip_message_emit(self, "ModifyL4SrcUdp test")
1574 return
1575
1576 (pkt, exp_pkt, acts) = pkt_action_setup(self, mod_fields=['udp_sport'],
1577 check_test_params=True, tp="udp")
1578 flow_match_test(self, config["port_map"], pkt=pkt, exp_pkt=exp_pkt,
1579 action_list=acts, max_test=2)
1580
Dan Talayco551befa2010-07-15 17:05:32 -07001581class ModifyL4Dst(BaseMatchCase):
Dan Talayco4b2bee62010-07-20 14:10:05 -07001582 """
1583 Modify the dest TCP port of a TCP packet (TP1)
1584 """
Dan Talayco551befa2010-07-15 17:05:32 -07001585 def runTest(self):
Ed Swierkc7193a22012-08-22 06:51:02 -07001586 sup_acts = self.supported_actions
Dan Talayco4b2bee62010-07-20 14:10:05 -07001587 if not (sup_acts & 1 << ofp.OFPAT_SET_TP_DST):
Dan Talaycoba3745c2010-07-21 21:51:08 -07001588 skip_message_emit(self, "ModifyL4Dst test")
Dan Talayco4b2bee62010-07-20 14:10:05 -07001589 return
1590
1591 (pkt, exp_pkt, acts) = pkt_action_setup(self, mod_fields=['tcp_dport'],
1592 check_test_params=True)
Rich Lane477f4812012-10-04 22:49:00 -07001593 flow_match_test(self, config["port_map"], pkt=pkt, exp_pkt=exp_pkt,
Dan Talayco4b2bee62010-07-20 14:10:05 -07001594 action_list=acts, max_test=2)
Dan Talayco551befa2010-07-15 17:05:32 -07001595
Rich Lane01c2b862012-10-26 16:26:25 -07001596class ModifyL4DstUdp(BaseMatchCase):
1597 """
1598 Modify the dest UDP port of a UDP packet
1599 """
1600 def runTest(self):
1601 sup_acts = self.supported_actions
1602 if not (sup_acts & 1 << ofp.OFPAT_SET_TP_DST):
1603 skip_message_emit(self, "ModifyL4DstUdp test")
1604 return
1605
1606 (pkt, exp_pkt, acts) = pkt_action_setup(self, mod_fields=['udp_dport'],
1607 check_test_params=True, tp="udp")
1608 flow_match_test(self, config["port_map"], pkt=pkt, exp_pkt=exp_pkt,
1609 action_list=acts, max_test=2)
1610
Dan Talayco551befa2010-07-15 17:05:32 -07001611class ModifyTOS(BaseMatchCase):
Dan Talayco4b2bee62010-07-20 14:10:05 -07001612 """
1613 Modify the IP type of service of an IP packet (TP1)
1614 """
Dan Talayco551befa2010-07-15 17:05:32 -07001615 def runTest(self):
Ed Swierkc7193a22012-08-22 06:51:02 -07001616 sup_acts = self.supported_actions
Dan Talayco4b2bee62010-07-20 14:10:05 -07001617 if not (sup_acts & 1 << ofp.OFPAT_SET_NW_TOS):
Dan Talaycoba3745c2010-07-21 21:51:08 -07001618 skip_message_emit(self, "ModifyTOS test")
Dan Talayco4b2bee62010-07-20 14:10:05 -07001619 return
Dan Talayco551befa2010-07-15 17:05:32 -07001620
Dan Talayco4b2bee62010-07-20 14:10:05 -07001621 (pkt, exp_pkt, acts) = pkt_action_setup(self, mod_fields=['ip_tos'],
1622 check_test_params=True)
Rich Lane477f4812012-10-04 22:49:00 -07001623 flow_match_test(self, config["port_map"], pkt=pkt, exp_pkt=exp_pkt,
Dan Talaycocfa172f2012-03-23 12:03:00 -07001624 action_list=acts, max_test=2, egr_count=-1)
Dan Talayco551befa2010-07-15 17:05:32 -07001625
Dan Talaycof6e76c02012-03-23 10:56:12 -07001626class ModifyL2DstMC(BaseMatchCase):
1627 """
1628 Modify the L2 dest and send to 2 ports
Dan Talaycof6e76c02012-03-23 10:56:12 -07001629 """
1630 def runTest(self):
Ed Swierkc7193a22012-08-22 06:51:02 -07001631 sup_acts = self.supported_actions
Dan Talaycof6e76c02012-03-23 10:56:12 -07001632 if not (sup_acts & 1 << ofp.OFPAT_SET_DL_DST):
Dan Talaycocfa172f2012-03-23 12:03:00 -07001633 skip_message_emit(self, "ModifyL2dstMC test")
Dan Talaycof6e76c02012-03-23 10:56:12 -07001634 return
1635
Dan Talaycof6e76c02012-03-23 10:56:12 -07001636 (pkt, exp_pkt, acts) = pkt_action_setup(self, mod_fields=['dl_dst'],
1637 check_test_params=True)
Rich Lane477f4812012-10-04 22:49:00 -07001638 flow_match_test(self, config["port_map"], pkt=pkt, exp_pkt=exp_pkt,
Dan Talaycocfa172f2012-03-23 12:03:00 -07001639 action_list=acts, max_test=2, egr_count=-1)
Dan Talaycof6e76c02012-03-23 10:56:12 -07001640
Dan Talaycoc948d0b2012-03-23 12:17:54 -07001641class ModifyL2DstIngress(BaseMatchCase):
1642 """
1643 Modify the L2 dest and send to the ingress port
1644 """
1645 def runTest(self):
Ed Swierkc7193a22012-08-22 06:51:02 -07001646 sup_acts = self.supported_actions
Dan Talaycoc948d0b2012-03-23 12:17:54 -07001647 if not (sup_acts & 1 << ofp.OFPAT_SET_DL_DST):
Dan Talaycoabbfdbb2012-04-05 10:29:26 -07001648 skip_message_emit(self, "ModifyL2dstIngress test")
Dan Talaycoc948d0b2012-03-23 12:17:54 -07001649 return
1650
1651 (pkt, exp_pkt, acts) = pkt_action_setup(self, mod_fields=['dl_dst'],
1652 check_test_params=True)
Rich Lane477f4812012-10-04 22:49:00 -07001653 flow_match_test(self, config["port_map"], pkt=pkt, exp_pkt=exp_pkt,
Dan Talaycoc948d0b2012-03-23 12:17:54 -07001654 action_list=acts, max_test=2, egr_count=0,
1655 ing_port=True)
1656
Dan Talaycod8ae7582012-03-23 12:24:56 -07001657class ModifyL2DstIngressMC(BaseMatchCase):
1658 """
1659 Modify the L2 dest and send to the ingress port
1660 """
1661 def runTest(self):
Ed Swierkc7193a22012-08-22 06:51:02 -07001662 sup_acts = self.supported_actions
Dan Talaycod8ae7582012-03-23 12:24:56 -07001663 if not (sup_acts & 1 << ofp.OFPAT_SET_DL_DST):
1664 skip_message_emit(self, "ModifyL2dstMC test")
1665 return
1666
1667 (pkt, exp_pkt, acts) = pkt_action_setup(self, mod_fields=['dl_dst'],
1668 check_test_params=True)
Rich Lane477f4812012-10-04 22:49:00 -07001669 flow_match_test(self, config["port_map"], pkt=pkt, exp_pkt=exp_pkt,
Dan Talaycod8ae7582012-03-23 12:24:56 -07001670 action_list=acts, max_test=2, egr_count=-1,
1671 ing_port=True)
1672
Dan Talaycof6e76c02012-03-23 10:56:12 -07001673class ModifyL2SrcMC(BaseMatchCase):
1674 """
1675 Modify the source MAC address (TP1) and send to multiple
Dan Talaycof6e76c02012-03-23 10:56:12 -07001676 """
1677 def runTest(self):
Ed Swierkc7193a22012-08-22 06:51:02 -07001678 sup_acts = self.supported_actions
Dan Talaycof6e76c02012-03-23 10:56:12 -07001679 if not (sup_acts & 1 << ofp.OFPAT_SET_DL_SRC):
Dan Talaycocfa172f2012-03-23 12:03:00 -07001680 skip_message_emit(self, "ModifyL2SrcMC test")
Dan Talaycof6e76c02012-03-23 10:56:12 -07001681 return
1682
Dan Talaycof6e76c02012-03-23 10:56:12 -07001683 (pkt, exp_pkt, acts) = pkt_action_setup(self, mod_fields=['dl_src'],
1684 check_test_params=True)
Rich Lane477f4812012-10-04 22:49:00 -07001685 flow_match_test(self, config["port_map"], pkt=pkt, exp_pkt=exp_pkt,
Dan Talaycocfa172f2012-03-23 12:03:00 -07001686 action_list=acts, max_test=2, egr_count=-1)
Dan Talaycof6e76c02012-03-23 10:56:12 -07001687
1688class ModifyL2SrcDstMC(BaseMatchCase):
1689 """
1690 Modify the L2 source and dest and send to 2 ports
Dan Talaycof6e76c02012-03-23 10:56:12 -07001691 """
1692 def runTest(self):
Ed Swierkc7193a22012-08-22 06:51:02 -07001693 sup_acts = self.supported_actions
Dan Talaycocfa172f2012-03-23 12:03:00 -07001694 if (not (sup_acts & 1 << ofp.OFPAT_SET_DL_DST) or
1695 not (sup_acts & 1 << ofp.OFPAT_SET_DL_SRC)):
1696 skip_message_emit(self, "ModifyL2SrcDstMC test")
Dan Talaycof6e76c02012-03-23 10:56:12 -07001697 return
1698
Dan Talaycof6e76c02012-03-23 10:56:12 -07001699 mod_fields = ['dl_dst', 'dl_src']
1700 (pkt, exp_pkt, acts) = pkt_action_setup(self, mod_fields=mod_fields,
1701 check_test_params=True)
Rich Lane477f4812012-10-04 22:49:00 -07001702 flow_match_test(self, config["port_map"], pkt=pkt, exp_pkt=exp_pkt,
Dan Talaycocfa172f2012-03-23 12:03:00 -07001703 action_list=acts, max_test=2, egr_count=-1)
1704
1705class ModifyL2DstVIDMC(BaseMatchCase):
1706 """
1707 Modify the L2 dest and send to 2 ports
1708 """
1709 def runTest(self):
Ed Swierkc7193a22012-08-22 06:51:02 -07001710 sup_acts = self.supported_actions
Dan Talaycocfa172f2012-03-23 12:03:00 -07001711 if (not (sup_acts & 1 << ofp.OFPAT_SET_DL_DST) or
1712 not (sup_acts & 1 << ofp.OFPAT_SET_VLAN_VID)):
1713 skip_message_emit(self, "ModifyL2DstVIDMC test")
1714 return
1715
1716 mod_fields = ['dl_dst', 'dl_vlan']
1717 (pkt, exp_pkt, acts) = pkt_action_setup(self,
1718 start_field_vals={'dl_vlan_enable':True}, mod_fields=mod_fields,
1719 check_test_params=True)
Rich Lane477f4812012-10-04 22:49:00 -07001720 flow_match_test(self, config["port_map"], pkt=pkt, exp_pkt=exp_pkt,
Dan Talaycocfa172f2012-03-23 12:03:00 -07001721 action_list=acts, max_test=2, egr_count=-1)
Dan Talaycof6e76c02012-03-23 10:56:12 -07001722
Rich Lane22e74c12012-11-12 15:06:06 -08001723class ModifyAll(BaseMatchCase):
1724 """
1725 Modify all supported fields and output to a port
1726 """
1727 def runTest(self):
1728 sup_acts = self.supported_actions
1729
1730 sup_map = {
1731 "dl_dst" : ofp.OFPAT_SET_DL_DST,
1732 "dl_src" : ofp.OFPAT_SET_DL_SRC,
1733 "dl_vlan_enable" : ofp.OFPAT_SET_VLAN_VID,
1734 "dl_vlan" : ofp.OFPAT_SET_VLAN_VID,
1735 "dl_vlan_pcp" : ofp.OFPAT_SET_VLAN_PCP,
1736 "ip_src" : ofp.OFPAT_SET_NW_SRC,
1737 "ip_dst" : ofp.OFPAT_SET_NW_DST,
1738 "ip_tos" : ofp.OFPAT_SET_NW_TOS,
1739 "tcp_sport" : ofp.OFPAT_SET_TP_SRC,
1740 "tcp_dport" : ofp.OFPAT_SET_TP_DST,
1741 }
1742
1743 mod_fields = [field for (field, bit) in sup_map.items() if (sup_acts & 1 << bit)]
1744 random.shuffle(mod_fields)
1745 start_field_vals = { "dl_vlan_enable" : True }
1746 mod_field_vals = { "dl_vlan_enable" : True }
1747 logging.info("modifying fields: %s" % repr(mod_fields))
1748
1749 (pkt, exp_pkt, acts) = pkt_action_setup(self,
1750 mod_fields=mod_fields,
1751 start_field_vals=start_field_vals,
1752 mod_field_vals=mod_field_vals,
1753 check_test_params=True)
1754 flow_match_test(self, config["port_map"], pkt=pkt, exp_pkt=exp_pkt,
1755 action_list=acts, max_test=2)
1756
Dan Talaycofa6454f2012-04-05 10:04:13 -07001757class FlowToggle(BaseMatchCase):
1758 """
1759 Add flows to the table and modify them repeatedly
Dan Talaycof7c41312012-07-23 12:53:19 -07001760
1761 This is done by using only "add" flow messages. Since the check overlap
1762 flag is not set, the switch is supposed to modify the existing flow if
1763 the match already exists.
1764
1765 Would probably be better to exercise more of the flow modify commands
1766 (add, modify, delete +/- strict).
Dan Talaycofa6454f2012-04-05 10:04:13 -07001767 """
1768 def runTest(self):
Rich Lane2014f9b2012-10-05 15:29:40 -07001769 flow_count = test_param_get('ft_flow_count', default=20)
1770 iter_count = test_param_get('ft_iter_count', default=10)
Dan Talaycofa6454f2012-04-05 10:04:13 -07001771
Rich Lane9a003812012-10-04 17:17:59 -07001772 logging.info("Running flow toggle with %d flows, %d iterations" %
Dan Talaycofa6454f2012-04-05 10:04:13 -07001773 (flow_count, iter_count))
1774 acts = []
1775 acts.append(action.action_output())
1776 acts.append(action.action_output())
1777
Rich Lane477f4812012-10-04 22:49:00 -07001778 of_ports = config["port_map"].keys()
Dan Talaycofa6454f2012-04-05 10:04:13 -07001779 if len(of_ports) < 3:
1780 self.assertTrue(False, "Too few ports for test")
1781
1782 for idx in range(2):
1783 acts[idx].port = of_ports[idx]
1784
1785 flows = []
1786 flows.append([])
1787 flows.append([])
1788
Ed Swierk99a74de2012-08-22 06:40:54 -07001789 wildcards = (required_wildcards(self) | ofp.OFPFW_DL_SRC |
1790 ofp.OFPFW_DL_DST)
Dan Talaycofa6454f2012-04-05 10:04:13 -07001791 # Create up the flows in an array
1792 for toggle in range(2):
1793 for f_idx in range(flow_count):
1794 pkt = simple_tcp_packet(tcp_sport=f_idx)
1795 msg = message.flow_mod()
Ed Swierk99a74de2012-08-22 06:40:54 -07001796 match = packet_to_flow_match(self, pkt)
Shudong Zhou031373c2012-07-19 17:37:42 -07001797 match.in_port = of_ports[2]
Dan Talayco50be7672012-04-05 11:38:08 -07001798 match.wildcards = wildcards
Dan Talaycofa6454f2012-04-05 10:04:13 -07001799 msg.match = match
1800 msg.buffer_id = 0xffffffff
Dan Talaycof7c41312012-07-23 12:53:19 -07001801 msg.command = ofp.OFPFC_ADD
Dan Talaycofa6454f2012-04-05 10:04:13 -07001802 msg.actions.add(acts[toggle])
1803 flows[toggle].append(msg)
Dan Talayco50be7672012-04-05 11:38:08 -07001804
1805 # Show two sample flows
Rich Lane9a003812012-10-04 17:17:59 -07001806 logging.debug(flows[0][0].show())
1807 logging.debug(flows[1][0].show())
Dan Talayco50be7672012-04-05 11:38:08 -07001808
Dan Talaycofa6454f2012-04-05 10:04:13 -07001809 # Install the first set of flows
1810 for f_idx in range(flow_count):
1811 rv = self.controller.message_send(flows[0][f_idx])
1812 self.assertTrue(rv != -1, "Error installing flow %d" % f_idx)
Dan Talayco0fc08bd2012-04-09 16:56:18 -07001813 self.assertEqual(do_barrier(self.controller), 0, "Barrier failed")
Dan Talaycofa6454f2012-04-05 10:04:13 -07001814
Rich Lane9a003812012-10-04 17:17:59 -07001815 logging.info("Installed %d flows" % flow_count)
Dan Talaycofa6454f2012-04-05 10:04:13 -07001816
1817 # Repeatedly modify all the flows back and forth
1818 updates = 0
1819 # Report status about 5 times
1820 mod_val = (iter_count / 4) + 1
Dan Talaycoabbfdbb2012-04-05 10:29:26 -07001821 start = time.time()
1822 for iter_idx in range(iter_count):
1823 if not iter_idx % mod_val:
Rich Lane9a003812012-10-04 17:17:59 -07001824 logging.info("Flow Toggle: iter %d of %d. " %
Dan Talaycoabbfdbb2012-04-05 10:29:26 -07001825 (iter_idx, iter_count) +
1826 "%d updates in %d secs" %
1827 (updates, time.time() - start))
Dan Talaycofa6454f2012-04-05 10:04:13 -07001828 for toggle in range(2):
1829 t_idx = 1 - toggle
1830 for f_idx in range(flow_count):
1831 rv = self.controller.message_send(flows[t_idx][f_idx])
1832 updates += 1
1833 self.assertTrue(rv != -1, "Error modifying flow %d" %
1834 f_idx)
Dan Talayco0fc08bd2012-04-09 16:56:18 -07001835 self.assertEqual(do_barrier(self.controller), 0,
1836 "Barrier failed")
Dan Talaycoabbfdbb2012-04-05 10:29:26 -07001837
1838 end = time.time()
1839 divisor = end - start or (end - start + 1)
Rich Lane9a003812012-10-04 17:17:59 -07001840 logging.info("Flow toggle: %d iterations" % iter_count)
1841 logging.info(" %d flow mods in %d secs, %d mods/sec" %
Dan Talaycoabbfdbb2012-04-05 10:29:26 -07001842 (updates, end - start, updates/divisor))
Dan Talaycofa6454f2012-04-05 10:04:13 -07001843
1844
Dan Talayco8a64e332012-03-28 14:53:20 -07001845# You can pick and choose these by commenting tests in or out
1846iter_classes = [
1847 basic.PacketIn,
1848 basic.PacketOut,
1849 DirectPacket,
Dan Talaycofa6454f2012-04-05 10:04:13 -07001850 FlowToggle,
Dan Talayco8a64e332012-03-28 14:53:20 -07001851 DirectTwoPorts,
Dan Talaycofa6454f2012-04-05 10:04:13 -07001852 DirectMCNonIngress,
Dan Talayco8a64e332012-03-28 14:53:20 -07001853 AllWildcardMatch,
1854 AllWildcardMatchTagged,
1855 SingleWildcardMatch,
1856 SingleWildcardMatchTagged,
1857 ExactMatch,
1858 ExactMatchTagged,
1859 SingleWildcardMatch,
1860 ModifyL2Src,
1861 ModifyL2Dst,
1862 ModifyL2SrcMC,
1863 ModifyL2DstMC,
1864 ModifyL2SrcDstMC
1865 ]
1866
Rich Lane0a4f6372013-01-02 14:40:22 -08001867@disabled
Dan Talayco8a64e332012-03-28 14:53:20 -07001868class IterCases(BaseMatchCase):
Dan Talaycofa6454f2012-04-05 10:04:13 -07001869 """
1870 Iterate over a bunch of test cases
1871
1872 The cases come from the list above
1873 """
1874
Dan Talayco8a64e332012-03-28 14:53:20 -07001875 def runTest(self):
Rich Lane2014f9b2012-10-05 15:29:40 -07001876 count = test_param_get('iter_count', default=10)
Dan Talayco8a64e332012-03-28 14:53:20 -07001877 tests_done = 0
Rich Lane9a003812012-10-04 17:17:59 -07001878 logging.info("Running iteration test " + str(count) + " times")
Dan Talayco8a64e332012-03-28 14:53:20 -07001879 start = time.time()
1880 last = start
1881 for idx in range(count):
Rich Lane9a003812012-10-04 17:17:59 -07001882 logging.info("Iteration " + str(idx + 1))
Dan Talayco8a64e332012-03-28 14:53:20 -07001883 for cls in iter_classes:
1884 test = cls()
1885 test.inheritSetup(self)
1886 test.runTest()
1887 tests_done += 1
Dan Talaycofa6454f2012-04-05 10:04:13 -07001888 # Report update about every minute, between tests
Dan Talayco8a64e332012-03-28 14:53:20 -07001889 if time.time() - last > 60:
1890 last = time.time()
Rich Lane9a003812012-10-04 17:17:59 -07001891 logging.info(
Dan Talaycofa6454f2012-04-05 10:04:13 -07001892 "IterCases: Iter %d of %d; Ran %d tests in %d " %
1893 (idx, count, tests_done, last - start) +
1894 "seconds so far")
Dan Talayco8a64e332012-03-28 14:53:20 -07001895 stats = all_stats_get(self)
1896 last = time.time()
Rich Lane9a003812012-10-04 17:17:59 -07001897 logging.info("\nIterCases ran %d tests in %d seconds." %
Dan Talayco8a64e332012-03-28 14:53:20 -07001898 (tests_done, last - start))
Rich Lane9a003812012-10-04 17:17:59 -07001899 logging.info(" flows: %d. packets: %d. bytes: %d" %
Dan Talayco8a64e332012-03-28 14:53:20 -07001900 (stats["flows"], stats["packets"], stats["bytes"]))
Rich Lane9a003812012-10-04 17:17:59 -07001901 logging.info(" active: %d. lookups: %d. matched %d." %
Dan Talayco8a64e332012-03-28 14:53:20 -07001902 (stats["active"], stats["lookups"], stats["matched"]))
1903
Dan Talayco4b2bee62010-07-20 14:10:05 -07001904#@todo Need to implement tagged versions of the above tests
1905#
1906#@todo Implement a test case that strips tag 2, adds tag 3
1907# and modifies tag 4 to tag 5. Then verify (in addition) that
1908# tag 6 does not get modified.
1909
Rich Lane0a4f6372013-01-02 14:40:22 -08001910@disabled
Dan Talayco4b2bee62010-07-20 14:10:05 -07001911class MixedVLAN(BaseMatchCase):
1912 """
1913 Test mixture of VLAN tag actions
1914
1915 Strip tag 2 on port 1, send to port 2
1916 Add tag 3 on port 1, send to port 2
1917 Modify tag 4 to 5 on port 1, send to port 2
1918 All other traffic from port 1, send to port 3
1919 All traffic from port 2 sent to port 4
1920 Use exact matches with different packets for all mods
1921 Verify the following: (port, vid)
1922 (port 1, vid 2) => VLAN tag stripped, out port 2
1923 (port 1, no tag) => tagged packet w/ vid 2 out port 2
1924 (port 1, vid 4) => tagged packet w/ vid 5 out port 2
1925 (port 1, vid 5) => tagged packet w/ vid 5 out port 2
1926 (port 1, vid 6) => tagged packet w/ vid 6 out port 2
1927 (port 2, no tag) => untagged packet out port 4
1928 (port 2, vid 2-6) => unmodified packet out port 4
1929
1930 Variation: Might try sending VID 5 to port 3 and check.
1931 If only VID 5 distinguishes pkt, this will fail on some platforms
1932 """
1933
Rich Laneb90a1c42012-10-05 09:16:05 -07001934class MatchEach(base_tests.SimpleDataPlane):
Rich Lane8d6ab272012-09-23 18:06:20 -07001935 """
1936 Check that each match field is actually matched on.
1937 Installs two flows that differ in one field. The flow that should not
1938 match has a higher priority, so if that field is ignored during matching
1939 the packet will be sent out the wrong port.
1940
1941 TODO test UDP, ARP, ICMP, etc.
1942 """
1943 def runTest(self):
Rich Lane477f4812012-10-04 22:49:00 -07001944 of_ports = config["port_map"].keys()
Rich Lane8d6ab272012-09-23 18:06:20 -07001945 of_ports.sort()
1946 self.assertTrue(len(of_ports) > 1, "Not enough ports for test")
1947
Rich Lane9a003812012-10-04 17:17:59 -07001948 delete_all_flows(self.controller)
Rich Lane8d6ab272012-09-23 18:06:20 -07001949
Ed Swierk7040a8d2012-12-11 16:30:13 -08001950 pkt = simple_tcp_packet(dl_vlan_enable=True, dl_vlan=2)
Rich Lane8d6ab272012-09-23 18:06:20 -07001951 ingress_port = of_ports[0]
1952 egress_port = of_ports[1]
1953
1954 def testField(field, mask):
Rich Lane9a003812012-10-04 17:17:59 -07001955 logging.info("Testing field %s" % field)
Rich Lane8d6ab272012-09-23 18:06:20 -07001956
1957 def addFlow(matching, priority, output_port):
1958 match = packet_to_flow_match(self, pkt)
1959 self.assertTrue(match is not None, "Could not generate flow match from pkt")
1960 match.wildcards &= ~ofp.OFPFW_IN_PORT
1961 match.in_port = ingress_port
1962 if not matching:
1963 # Make sure flow doesn't match
1964 orig = getattr(match, field)
1965 if isinstance(orig, list):
1966 new = map(lambda a: ~a[0] & a[1], zip(orig, mask))
1967 else:
1968 new = ~orig & mask
1969 setattr(match, field, new)
1970 request = message.flow_mod()
1971 request.match = match
1972 request.buffer_id = 0xffffffff
1973 request.priority = priority
1974 act = action.action_output()
1975 act.port = output_port
1976 self.assertTrue(request.actions.add(act), "Could not add action")
Rich Lane9a003812012-10-04 17:17:59 -07001977 logging.info("Inserting flow")
Rich Lane8d6ab272012-09-23 18:06:20 -07001978 self.controller.message_send(request)
1979
1980 # This flow should match.
1981 addFlow(matching=True, priority=0, output_port=egress_port)
1982 # This flow should not match, but it has a higher priority.
1983 addFlow(matching=False, priority=1, output_port=ofp.OFPP_IN_PORT)
1984
1985 self.assertEqual(do_barrier(self.controller), 0, "Barrier failed")
1986
Rich Lane9a003812012-10-04 17:17:59 -07001987 logging.info("Sending packet to dp port " + str(ingress_port))
Rich Lane8d6ab272012-09-23 18:06:20 -07001988 self.dataplane.send(ingress_port, str(pkt))
1989
1990 exp_pkt_arg = None
1991 exp_port = None
Rich Lane477f4812012-10-04 22:49:00 -07001992 if config["relax"]:
Rich Lane8d6ab272012-09-23 18:06:20 -07001993 exp_pkt_arg = pkt
1994 exp_port = egress_port
1995
1996 (rcv_port, rcv_pkt, pkt_time) = self.dataplane.poll(port_number=exp_port,
1997 exp_pkt=exp_pkt_arg)
1998 self.assertTrue(rcv_pkt is not None, "Did not receive packet")
Rich Lane9a003812012-10-04 17:17:59 -07001999 logging.debug("Packet len " + str(len(rcv_pkt)) + " in on " + str(rcv_port))
Rich Lane8d6ab272012-09-23 18:06:20 -07002000 self.assertEqual(rcv_port, egress_port, "Unexpected receive port")
2001 self.assertEqual(str(pkt), str(rcv_pkt), 'Response packet does not match send packet')
2002
Ed Swierkb603b192012-12-12 15:38:49 -08002003 wildcards = required_wildcards(self)
Rich Lane8d6ab272012-09-23 18:06:20 -07002004 # TODO in_port
Ed Swierkb603b192012-12-12 15:38:49 -08002005 if not (wildcards & ofp.OFPFW_DL_SRC):
2006 testField("dl_src", [0xff]*6)
2007 if not (wildcards & ofp.OFPFW_DL_DST):
2008 testField("dl_dst", [0xff]*6)
2009 if not (wildcards & ofp.OFPFW_DL_TYPE):
2010 testField("dl_type", 0xffff)
2011 if not (wildcards & ofp.OFPFW_DL_VLAN):
2012 testField("dl_vlan", 0xfff)
Rich Lane8d6ab272012-09-23 18:06:20 -07002013 # TODO dl_vlan_pcp
Ed Swierkb603b192012-12-12 15:38:49 -08002014 if not (wildcards & ofp.OFPFW_NW_SRC_ALL):
2015 testField("nw_src", 0xffffffff)
2016 if not (wildcards & ofp.OFPFW_NW_DST_ALL):
2017 testField("nw_dst", 0xffffffff)
2018 if not (wildcards & ofp.OFPFW_NW_TOS):
2019 testField("nw_tos", 0x3f)
2020 if not (wildcards & ofp.OFPFW_NW_PROTO):
2021 testField("nw_proto", 0xff)
2022 if not (wildcards & ofp.OFPFW_TP_SRC):
2023 testField("tp_src", 0xffff)
2024 if not (wildcards & ofp.OFPFW_TP_DST):
2025 testField("tp_dst", 0xffff)
Rich Lane8d6ab272012-09-23 18:06:20 -07002026
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002027class DirectBadPacketBase(base_tests.SimpleDataPlane):
2028 """
2029 Base class for sending single packets with single flow table entries.
2030 Used to verify matching of unusual packets and parsing/matching of
2031 corrupted packets.
2032
2033 The idea is to generate packets that may either be totally malformed or
2034 malformed just enough to trick the flow matcher into making mistakes.
2035
2036 Generate a 'bad' packet
2037 Generate and install a matching flow
2038 Add action to direct the packet to an egress port
2039 Send the packet to ingress dataplane port
2040 Verify the packet is received at the egress port only
2041 """
2042
2043 RESULT_MATCH = "MATCH"
2044 RESULT_NOMATCH = "NO MATCH"
2045 RESULT_ANY = "ANY MATCH"
2046
2047 def runTest(self):
2048 pass
2049 # TODO:
2050 # - ICMP?
2051 # - VLAN?
2052 # - action
2053
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002054 def createMatch(self, **kwargs):
2055 match = ofp.ofp_match()
2056 match.wildcards = ofp.OFPFW_ALL
2057 fields = {
2058 'dl_dst': ofp.OFPFW_DL_DST,
2059 'dl_src': ofp.OFPFW_DL_SRC,
2060 'dl_type': ofp.OFPFW_DL_TYPE,
2061 'dl_vlan': ofp.OFPFW_DL_VLAN,
2062 'nw_src': ofp.OFPFW_NW_SRC_MASK,
2063 'nw_dst': ofp.OFPFW_NW_DST_MASK,
2064 'nw_tos': ofp.OFPFW_NW_TOS,
2065 'nw_proto': ofp.OFPFW_NW_PROTO,
2066 'tp_src': ofp.OFPFW_TP_SRC,
2067 'tp_dst': ofp.OFPFW_TP_DST,
2068 }
2069 for key in kwargs:
2070 setattr(match, key, kwargs[key])
2071 match.wildcards &= ~fields[key]
2072 return match
2073
2074 def testPktsAgainstFlow(self, pkts, acts, match):
2075 if type(acts) != list:
2076 acts = [acts]
2077 for info in pkts:
2078 title, pkt, expected_result = info
2079 self.testPktAgainstFlow(title, pkt, acts, match, expected_result)
2080
2081 def testPktAgainstFlow(self, title, pkt, acts, match, expected_result):
2082 of_ports = config["port_map"].keys()
2083 of_ports.sort()
2084 self.assertTrue(len(of_ports) > 1, "Not enough ports for test")
2085
2086 rv = delete_all_flows(self.controller)
2087 self.assertEqual(rv, 0, "Failed to delete all flows")
2088
2089 ingress_port = of_ports[0]
2090 egress_port = of_ports[1]
2091
2092 logging.info("Testing packet '%s', expect result %s" %
2093 (title, expected_result))
2094 logging.info("Ingress %s to egress %s" %
2095 (str(ingress_port), str(egress_port)))
2096 logging.info("Packet:")
Rich Lane5d7e89a2012-10-26 16:43:13 -07002097 logging.info(inspect_packet(pkt))
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002098
2099 match.in_port = ingress_port
2100
2101 request = message.flow_mod()
2102 request.match = match
Rich Lane44cf12d2012-10-15 11:10:45 -07002103 request.priority = 1
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002104
2105 request.buffer_id = 0xffffffff
2106 for act in acts:
2107 act.port = egress_port
2108 rv = request.actions.add(act)
2109 self.assertTrue(rv, "Could not add action")
2110
2111 logging.info("Inserting flow")
2112 rv = self.controller.message_send(request)
2113 self.assertTrue(rv != -1, "Error installing flow mod")
Rich Lane44cf12d2012-10-15 11:10:45 -07002114
2115 # This flow speeds up negative tests
2116 logging.info("Inserting catch-all flow")
2117 request2 = message.flow_mod()
2118 request2.match = self.createMatch()
2119 request2.priority = 0
2120 act = action.action_output()
2121 act.port = ofp.OFPP_IN_PORT
2122 request2.actions.add(act)
2123 rv = self.controller.message_send(request2)
2124 self.assertTrue(rv != -1, "Error installing flow mod")
2125
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002126 self.assertEqual(do_barrier(self.controller), 0, "Barrier failed")
2127
2128 logging.info("Sending packet to dp port " +
2129 str(ingress_port))
2130 self.dataplane.send(ingress_port, str(pkt))
2131
2132 exp_pkt_arg = None
2133 exp_port = None
2134 if config["relax"]:
2135 exp_pkt_arg = pkt
2136 exp_port = egress_port
2137
Rich Lane44cf12d2012-10-15 11:10:45 -07002138 if expected_result == self.RESULT_MATCH:
2139 timeout = -1 # default timeout
2140 else:
2141 timeout = 1 # short timeout for negative tests
2142
2143 (rcv_port, rcv_pkt, pkt_time) = self.dataplane.poll(exp_pkt=exp_pkt_arg,
2144 timeout=timeout)
2145 if rcv_port == ingress_port:
2146 logging.debug("Packet matched catch-all flow")
2147 rcv_pkt = None
2148
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002149 if expected_result == self.RESULT_MATCH:
2150 self.assertTrue(rcv_pkt is not None,
2151 "Did not receive packet, expected a match")
2152 logging.debug("Packet len " + str(len(rcv_pkt)) + " in on " +
2153 str(rcv_port))
2154 self.assertEqual(rcv_port, egress_port, "Unexpected receive port")
2155 str_pkt = str(pkt)
2156 str_rcv_pkt = str(rcv_pkt)
2157 str_rcv_pkt = str_rcv_pkt[0:len(str_pkt)]
2158 if str_pkt != str_rcv_pkt:
2159 logging.error("Response packet does not match send packet")
2160 logging.info("Response:")
Rich Lane5d7e89a2012-10-26 16:43:13 -07002161 logging.info(inspect_packet(scapy.Ether(rcv_pkt)))
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002162 self.assertEqual(str_pkt, str_rcv_pkt,
2163 'Response packet does not match send packet')
2164 elif expected_result == self.RESULT_NOMATCH:
2165 self.assertTrue(rcv_pkt is None, "Received packet, expected drop")
2166 else:
2167 logging.debug("Match or drop accepted. Result = %s" %
2168 ("match" if rcv_pkt is not None else "drop"))
2169
2170
2171class DirectBadIpTcpPacketsBase(DirectBadPacketBase):
2172 """
2173 Base class for TCP and UDP parsing/matching verification under corruptions
2174 """
2175 def runTest(self):
2176 pass
2177
2178 def runTestWithProto(self, protoName = 'TCP'):
2179 dl_dst='00:01:02:03:04:05'
2180 dl_src='00:06:07:08:09:0a'
2181 ip_src='192.168.0.1'
2182 ip_dst='192.168.0.2'
2183 ip_tos=0
2184 tcp_sport=1234
2185 tcp_dport=80
2186
2187 # Generate a proper packet for constructing a match
2188 tp = None
2189 if protoName == 'TCP':
2190 tp = scapy.TCP
2191 proto = 6
2192 elif protoName == 'UDP':
2193 tp = scapy.UDP
2194 proto = 17
2195 else:
2196 raise Exception("Passed in unknown proto name")
2197
2198 match_pkt = scapy.Ether(dst=dl_dst, src=dl_src)/ \
2199 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos)/ \
2200 tp(sport=tcp_sport, dport=tcp_dport)
2201 match = packet_to_flow_match(self, match_pkt)
2202 self.assertTrue(match is not None,
2203 "Could not generate flow match from pkt")
2204 match.wildcards &= ~ofp.OFPFW_IN_PORT
2205
2206 def testPacket(title, pkt, result):
2207 act = action.action_output()
2208 pkts = [
2209 [title, pkt, result]
2210 ]
2211 self.testPktsAgainstFlow(pkts, act, match)
2212
2213 # Try incomplete IP headers
2214 testPacket("Incomplete IP header (1 bytes)",
2215 scapy.Ether(dst=dl_dst, src=dl_src)/ \
2216 str(scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, proto=proto))[0:1],
2217 self.RESULT_NOMATCH,
2218 )
2219 testPacket("Incomplete IP header (2 bytes)",
2220 scapy.Ether(dst=dl_dst, src=dl_src)/ \
2221 str(scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, proto=proto))[0:2],
2222 self.RESULT_NOMATCH,
2223 )
2224 testPacket("Incomplete IP header (3 bytes)",
2225 scapy.Ether(dst=dl_dst, src=dl_src)/ \
2226 str(scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, proto=proto))[0:3],
2227 self.RESULT_NOMATCH,
2228 )
2229 testPacket("Incomplete IP header (12 bytes)",
2230 scapy.Ether(dst=dl_dst, src=dl_src)/ \
2231 str(scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, proto=proto))[0:12],
2232 self.RESULT_NOMATCH,
2233 )
2234 testPacket("Incomplete IP header (16 bytes)",
2235 scapy.Ether(dst=dl_dst, src=dl_src)/ \
2236 str(scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, proto=proto))[0:16],
2237 self.RESULT_NOMATCH,
2238 )
2239 testPacket("Incomplete IP header (19 bytes)",
2240 scapy.Ether(dst=dl_dst, src=dl_src)/ \
2241 str(scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, proto=proto))[0:19],
2242 self.RESULT_NOMATCH,
2243 )
2244
2245 # Try variations where the TCP header is missing or incomplete. As we
2246 # saw bugs before where buffers were reused and lengths weren't honored,
2247 # we initiatlize once with a non-matching full packet and once with a
2248 # matching full packet.
2249 testPacket("Non-Matching TCP packet, warming buffer",
2250 scapy.Ether(dst=dl_dst, src=dl_src)/ \
2251 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, proto=proto)/ \
2252 tp(sport=tcp_sport, dport=tcp_dport + 1),
2253 self.RESULT_NOMATCH,
2254 )
2255 testPacket("Missing TCP header, buffer warmed with non-match",
2256 scapy.Ether(dst=dl_dst, src=dl_src)/ \
2257 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, proto=proto),
2258 self.RESULT_NOMATCH,
2259 )
2260 testPacket("Matching TCP packet, warming buffer",
2261 scapy.Ether(dst=dl_dst, src=dl_src)/ \
2262 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, proto=proto)/ \
2263 tp(sport=tcp_sport, dport=tcp_dport),
2264 self.RESULT_MATCH,
2265 )
2266 testPacket("Missing TCP header, buffer warmed with match",
2267 scapy.Ether(dst=dl_dst, src=dl_src)/ \
2268 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, proto=proto),
2269 self.RESULT_NOMATCH,
2270 )
2271 testPacket("Truncated TCP header: 2 bytes",
2272 scapy.Ether(dst=dl_dst, src=dl_src)/ \
2273 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, proto=proto)/ \
2274 (str(tp(sport=tcp_sport, dport=tcp_dport))[0:2]),
2275 self.RESULT_NOMATCH,
2276 )
2277
2278 # Play with IP header length values that put the start of TCP either
2279 # inside the generated TCP header or beyond. In some cases it may even
2280 # be beyond the packet boundary. Also play with IP options and more
2281 # importantly IP total length corruptions.
2282 testPacket("TCP packet, corrupt ihl (0x6)",
2283 simple_tcp_packet(ip_ihl=6),
2284 self.RESULT_NOMATCH,
2285 )
2286 testPacket("TCP packet, corrupt ihl (0xf)",
2287 simple_tcp_packet(ip_ihl=0xf), # ihl = 15 * 4 = 60
2288 self.RESULT_NOMATCH,
2289 )
2290 testPacket("TCP packet, corrupt ihl and total length",
2291 simple_tcp_packet(ip_ihl=0xf, pktlen=56), # ihl = 15 * 4 = 60,
2292 self.RESULT_NOMATCH,
2293 )
2294 testPacket("Corrupt IPoption: First 4 bytes of matching TCP header",
2295 simple_tcp_packet(
2296 ip_options=scapy.IPOption('\x04\xd2\x00\x50'),
2297 tcp_dport=2, tcp_sport=2
2298 ),
2299 self.RESULT_NOMATCH,
2300 )
2301 testPacket("Missing TCP header, corrupt ihl",
2302 scapy.Ether(dst=dl_dst, src=dl_src)/ \
2303 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ihl=0xf, proto=proto),
2304 self.RESULT_NOMATCH,
2305 )
2306 testPacket("Missing TCP header, corrupt total length",
2307 scapy.Ether(dst=dl_dst, src=dl_src)/ \
2308 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, proto=proto, len= 100),
2309 self.RESULT_NOMATCH,
2310 )
2311 testPacket("Missing TCP header, corrupt ihl and total length",
2312 scapy.Ether(dst=dl_dst, src=dl_src)/ \
2313 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ihl=0xf, proto=proto, len=43),
2314 self.RESULT_NOMATCH,
2315 )
2316 testPacket("Incomplete IP header (12 bytes), corrupt ihl and total length",
2317 scapy.Ether(dst=dl_dst, src=dl_src)/ \
2318 str(scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, proto=proto, ihl=10, len=43))[0:12],
2319 self.RESULT_NOMATCH,
2320 )
2321 testPacket("Incomplete IP header (16 bytes), corrupt ihl and total length",
2322 scapy.Ether(dst=dl_dst, src=dl_src)/ \
2323 str(scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, proto=proto, ihl=10, len=43))[0:16],
2324 self.RESULT_NOMATCH,
2325 )
2326
2327 # Try an incomplete TCP header that has enough bytes to carry source and
2328 # destination ports. As that is all we care about during matching, some
2329 # implementations may match and some may drop the packet
2330 testPacket("Incomplete TCP header: src/dst port present",
2331 scapy.Ether(dst=dl_dst, src=dl_src)/ \
2332 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, proto=proto)/ \
2333 (str(tp(sport=tcp_sport, dport=tcp_dport))[0:4]),
2334 self.RESULT_ANY,
2335 )
2336
2337 for i in range(1):
2338 for length in range(40 / 4): # IPv4 options are a maximum of 40 in length
2339 bytes = "".join([("%c" % random.randint(0, 255)) for x in range(length * 4)])
2340 eth = scapy.Ether(dst=dl_dst, src=dl_src)
2341 ip = scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ihl=5 + length, proto=proto)
2342 tcp = tp(sport=tcp_sport, dport=tcp_dport+1)
2343 pkt = eth / ip
2344 pkt = pkt / bytes
2345 pkt = pkt / str(tcp)
2346 testPacket("Random IP options len = %d - TP match must fail" % length * 4,
2347 pkt,
2348 self.RESULT_NOMATCH
2349 )
2350
2351 eth = scapy.Ether(dst=dl_dst, src=dl_src)
2352 ip = scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ihl=5 + length, proto=proto)
2353 tcp = tp(sport=tcp_sport, dport=tcp_dport)
2354 pkt = eth / ip
2355 pkt = pkt / bytes
2356 pkt = pkt / str(tcp)
2357
2358 testPacket("Random IP options len = %d - May match",
2359 pkt,
2360 self.RESULT_ANY
2361 )
2362
2363
2364class DirectBadIpTcpPackets(DirectBadIpTcpPacketsBase):
2365 """
2366 Verify IP/TCP parsing and matching. Focus on packet corruptions
2367 """
2368 def runTest(self):
2369 self.runTestWithProto(protoName = 'TCP')
2370
2371class DirectBadIpUdpPackets(DirectBadIpTcpPacketsBase):
2372 """
2373 Verify IP/UDP parsing and matching. Focus on packet corruptions
2374 """
2375 def runTest(self):
2376 self.runTestWithProto(protoName = 'UDP')
2377
2378class DirectBadLlcPackets(DirectBadPacketBase):
2379 """
2380 Verify LLC/SNAP parsing and matching. Focus on packet corruptions
2381 """
2382 def runTest(self):
2383 dl_dst='00:01:02:03:04:05'
2384 dl_src='00:06:07:08:09:0a'
2385 ip_src='192.168.0.1'
2386 ip_dst='192.168.0.2'
2387 ip_tos=0
2388 tcp_sport=1234
2389 tcp_dport=80
2390
2391 IS_SNAP_IP = 1
2392 IS_SNAP_IP_CORRUPT = 2
2393 IS_NOT_SNAP_IP = 3
2394
2395 def testPacketTcpMatch(title, llc):
2396 match_pkt = scapy.Ether(dst=dl_dst, src=dl_src)/ \
2397 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos)/ \
2398 scapy.TCP(sport=tcp_sport, dport=tcp_dport)
2399 match = packet_to_flow_match(self, match_pkt)
2400 self.assertTrue(match is not None,
2401 "Could not generate flow match from pkt")
2402 match.wildcards &= ~ofp.OFPFW_IN_PORT
2403 act = action.action_output()
2404
2405 self.testPktsAgainstFlow(
2406 [[
2407 "TCP match - LLC frame correct length - %s" % title,
2408 scapy.Ether(dst=dl_dst, src=dl_src, type=len(llc)) / llc,
2409 self.RESULT_ANY,
2410 ]],
2411 act, match
2412 )
2413
2414 # Corrupt length field
2415 ethLen = random.randint(0, 1535)
2416 self.testPktsAgainstFlow(
2417 [[
2418 "TCP match - LLC frame corrupted length - %s" % title,
2419 scapy.Ether(dst=dl_dst, src=dl_src, type=ethLen) / llc,
2420 self.RESULT_ANY,
2421 ]],
2422 act, match
2423 )
2424
2425 def testPacketEthSrcDstMatch(title, llc):
2426 # Matching based on Ethernet source and destination
2427 match_pkt = scapy.Ether(dst=dl_dst, src=dl_src)
2428 match = packet_to_flow_match(self, match_pkt)
2429 self.assertTrue(match is not None,
2430 "Could not generate flow match from pkt")
2431 match.wildcards &= ~ofp.OFPFW_IN_PORT
2432 match.wildcards |= ofp.OFPFW_DL_TYPE
2433 self.testPktsAgainstFlow(
2434 [[
2435 "Eth addr match - LLC frame correct length- %s" % title,
2436 scapy.Ether(dst=dl_dst, src=dl_src, type=len(llc)) / llc,
2437 self.RESULT_MATCH,
2438 ]],
2439 action.action_output(), match
2440 )
2441
2442 # Corrupt length field
2443 ethLen = random.randint(0, 1535)
2444 self.testPktsAgainstFlow(
2445 [[
2446 "Eth addr match - LLC frame corrupted length- %s" % title,
2447 scapy.Ether(dst=dl_dst, src=dl_src, type=ethLen) / llc,
2448 self.RESULT_ANY,
2449 ]],
2450 action.action_output(), match
2451 )
2452
2453 def testPacketEthSrcDstTypeMatch(title, llc, is_snap_ip):
2454 # Matching based on Ethernet source, destination and type
2455 match_pkt = scapy.Ether(dst=dl_dst, src=dl_src, type=0x800)
2456 match = packet_to_flow_match(self, match_pkt)
2457 self.assertTrue(match is not None,
2458 "Could not generate flow match from pkt")
2459 match.wildcards &= ~ofp.OFPFW_IN_PORT
2460 if is_snap_ip == IS_SNAP_IP:
2461 is_match = self.RESULT_MATCH
2462 elif is_snap_ip == IS_SNAP_IP_CORRUPT:
2463 is_match = self.RESULT_ANY
2464 else:
2465 is_match = self.RESULT_NOMATCH
2466 self.testPktsAgainstFlow(
2467 [[
2468 "Eth addr+type match - LLC frame correct length - %s" % title,
2469 scapy.Ether(dst=dl_dst, src=dl_src, type=len(llc)) / llc,
2470 is_match,
2471 ]],
2472 action.action_output(), match
2473 )
2474
2475 # Corrupt length field
2476 ethLen = random.randint(0, 1535)
2477 self.testPktsAgainstFlow(
2478 [[
2479 "Eth addr+type match - LLC frame corrupted length - %s" % title,
2480 scapy.Ether(dst=dl_dst, src=dl_src, type=ethLen) / llc,
Christian Dickmanne9b6d252012-10-08 22:56:50 -07002481 self.RESULT_ANY,
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002482 ]],
2483 action.action_output(), match
2484 )
2485
2486 def testPacket(title, llc, is_snap_ip):
2487 testPacketTcpMatch(title, llc)
2488 testPacketEthSrcDstMatch(title, llc)
2489 testPacketEthSrcDstTypeMatch(title, llc, is_snap_ip)
2490
2491 testPacket("LLC - No SNAP - No Payload",
Rich Lane6508ea02012-10-12 15:27:11 -07002492 scapy.LLC(dsap=0x33, ssap=0x44, ctrl=0x03),
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002493 IS_NOT_SNAP_IP,
2494 )
2495 testPacket("LLC - No SNAP - Small Payload",
Rich Lane6508ea02012-10-12 15:27:11 -07002496 scapy.LLC(dsap=0x33, ssap=0x44, ctrl=0x03) / ("S" * 10),
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002497 IS_NOT_SNAP_IP,
2498 )
2499 testPacket("LLC - No SNAP - Max -1 Payload",
Rich Lane6508ea02012-10-12 15:27:11 -07002500 scapy.LLC(dsap=0x33, ssap=0x44, ctrl=0x03) / ("S" * (1500 - 3 - 1)),
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002501 IS_NOT_SNAP_IP,
2502 )
2503 testPacket("LLC - No SNAP - Max Payload",
Rich Lane6508ea02012-10-12 15:27:11 -07002504 scapy.LLC(dsap=0x33, ssap=0x44, ctrl=0x03) / ("S" * (1500 - 3)),
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002505 IS_NOT_SNAP_IP,
2506 )
2507 testPacket("LLC - SNAP - Small bogus payload",
2508 scapy.LLC(dsap=0xaa, ssap=0xaa, ctrl=0x03)/ \
2509 scapy.SNAP(OUI=0x000000, code=0x800) / ("S" * 10),
2510 IS_SNAP_IP_CORRUPT,
2511 )
2512 testPacket("LLC - SNAP - Max -1 bogus payload",
2513 scapy.LLC(dsap=0xaa, ssap=0xaa, ctrl=0x03)/ \
2514 scapy.SNAP(OUI=0x000000, code=0x3) / ("S" * (1500 - 3 - 5 - 1)),
2515 IS_NOT_SNAP_IP,
2516 )
2517 testPacket("LLC - SNAP - Max bogus payload",
2518 scapy.LLC(dsap=0xaa, ssap=0xaa, ctrl=0x03)/ \
2519 scapy.SNAP(OUI=0x000000, code=0x3) / ("S" * (1500 - 3 - 5)),
2520 IS_NOT_SNAP_IP,
2521 )
2522 testPacket("LLC - SNAP - IP - TCP",
2523 scapy.LLC(dsap=0xaa, ssap=0xaa, ctrl=0x03)/ \
2524 scapy.SNAP(OUI=0x000000, code=0x800)/ \
2525 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, proto=6)/ \
2526 scapy.TCP(sport=tcp_sport, dport=tcp_dport),
2527 IS_SNAP_IP,
2528 )
2529
2530
2531class DirectLlcPackets(DirectBadPacketBase):
2532 """
2533 Verify LLC/SNAP parsing (valid and corrupted packets) and matching
2534 """
2535 def runTest(self):
2536 dl_dst='00:01:02:03:04:05'
2537 dl_src='00:06:07:08:09:0a'
2538 ip_src='192.168.0.1'
2539 ip_dst='192.168.0.2'
2540 ip_tos=0
2541 tcp_sport=1234
2542 tcp_dport=80
2543
2544 # Test ethertype in face of LLC/SNAP and OFP_DL_TYPE_NOT_ETH_TYPE
2545 IS_SNAP_NOT_IP = 1
2546 IS_SNAP_AND_IP = 2
2547 IS_NOT_SNAP = 3
2548
2549 def testPacketEthTypeIP(title, llc, is_snap):
2550 match_pkt = scapy.Ether(dst=dl_dst, src=dl_src, type=0x800)
2551 match = packet_to_flow_match(self, match_pkt)
2552 self.assertTrue(match is not None,
2553 "Could not generate flow match from pkt")
2554 match.wildcards &= ~ofp.OFPFW_IN_PORT
2555 pkts = []
2556 if is_snap == IS_NOT_SNAP or is_snap == IS_SNAP_NOT_IP:
2557 result = self.RESULT_NOMATCH
2558 else:
2559 result = self.RESULT_MATCH
2560 pkts.append([
2561 "Ether type 0x800 match - %s" % title,
2562 scapy.Ether(dst=dl_dst, src=dl_src, type=len(llc)) / llc,
2563 result,
2564 ])
2565 act = action.action_output()
2566 self.testPktsAgainstFlow(pkts, act, match)
2567
2568 def testPacketEthTypeNotEth(title, llc, is_snap):
2569 match_pkt = scapy.Ether(dst = dl_dst, src = dl_src,
2570 type = ofp.OFP_DL_TYPE_NOT_ETH_TYPE)
2571 match = packet_to_flow_match(self, match_pkt)
2572 self.assertTrue(match is not None,
2573 "Could not generate flow match from pkt")
2574 match.wildcards &= ~ofp.OFPFW_IN_PORT
2575 pkts = []
2576 if is_snap == IS_NOT_SNAP:
2577 result = self.RESULT_MATCH
2578 else:
2579 result = self.RESULT_NOMATCH
2580 pkts.append([
2581 "Ether type OFP_DL_TYPE_NOT_ETH_TYPE match - %s" % title,
2582 scapy.Ether(dst=dl_dst, src=dl_src, type=len(llc)) / llc,
2583 result,
2584 ])
2585 act = action.action_output()
2586 self.testPktsAgainstFlow(pkts, act, match)
2587
2588 def testPacket(title, llc, is_snap):
2589 testPacketEthTypeIP(title, llc, is_snap)
2590 testPacketEthTypeNotEth(title, llc, is_snap)
2591
2592 testPacket("LLC - No SNAP - No Payload",
Rich Lane6508ea02012-10-12 15:27:11 -07002593 scapy.LLC(dsap=0x33, ssap=0x44, ctrl=0x03),
2594 IS_NOT_SNAP,
2595 )
2596 testPacket("LLC (with information field) - No SNAP - No Payload",
2597 scapy.LLC(dsap=0x33, ssap=0x44, ctrl=0x12) / "S",
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002598 IS_NOT_SNAP,
2599 )
2600 testPacket("LLC - No SNAP - Small Payload",
Rich Lane6508ea02012-10-12 15:27:11 -07002601 scapy.LLC(dsap=0x33, ssap=0x44, ctrl=0x03) / ("S" * 10),
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002602 IS_NOT_SNAP,
2603 )
2604 testPacket("LLC - No SNAP - Max -1 Payload",
Rich Lane6508ea02012-10-12 15:27:11 -07002605 scapy.LLC(dsap=0x33, ssap=0x44, ctrl=0x03) / ("S" * (1500 - 3 - 1)),
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002606 IS_NOT_SNAP,
2607 )
2608 testPacket("LLC - No SNAP - Max Payload",
Rich Lane6508ea02012-10-12 15:27:11 -07002609 scapy.LLC(dsap=0x33, ssap=0x44, ctrl=0x03) / ("S" * (1500 - 3)),
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002610 IS_NOT_SNAP,
2611 )
2612 testPacket("LLC - SNAP - Non-default OUI",
2613 scapy.LLC(dsap=0xaa, ssap=0xaa, ctrl=0x03)/ \
2614 scapy.SNAP(OUI=0x000001, code=0x800) / ("S" * 10),
2615 IS_NOT_SNAP,
2616 )
2617 testPacket("LLC - SNAP - Default OUI",
2618 scapy.LLC(dsap=0xaa, ssap=0xaa, ctrl=0x03)/ \
2619 scapy.SNAP(OUI=0x000000, code=0x800) / ("S" * 10),
2620 IS_SNAP_AND_IP,
2621 )
2622 testPacket("LLC - SNAP - Max -1 bogus payload",
2623 scapy.LLC(dsap=0xaa, ssap=0xaa, ctrl=0x03)/ \
2624 scapy.SNAP(OUI=0x000000, code=0x3) / ("S" * (1500 - 3 - 5 - 1)),
2625 IS_SNAP_NOT_IP,
2626 )
2627 testPacket("LLC - SNAP - Max bogus payload",
2628 scapy.LLC(dsap=0xaa, ssap=0xaa, ctrl=0x03)/ \
2629 scapy.SNAP(OUI=0x000000, code=0x3) / ("S" * (1500 - 3 - 5)),
2630 IS_SNAP_NOT_IP,
2631 )
2632 testPacket("LLC - SNAP - IP - TCP",
2633 scapy.LLC(dsap=0xaa, ssap=0xaa, ctrl=0x03)/ \
2634 scapy.SNAP(OUI=0x000000, code=0x800)/ \
2635 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, proto=6)/ \
2636 scapy.TCP(sport=tcp_sport, dport=tcp_dport),
2637 IS_SNAP_AND_IP,
2638 )
2639
2640
2641class DirectArpPackets(DirectBadPacketBase):
2642 """
2643 Verify ARP parsing (valid and corrupted packets) and ARP matching
2644 """
2645 def runTest(self):
2646 self.testArpHandling()
2647
2648 def testArpHandling(self):
2649 dl_dst='00:01:02:03:04:05'
2650 dl_src='00:06:07:08:09:0a'
2651 ip_src='192.168.0.1'
2652 ip_dst='192.168.0.2'
2653 ip_src2='192.168.1.1'
2654 ip_dst2='192.168.1.2'
2655 ip_tos=0
2656 tcp_sport=1234
2657 tcp_dport=80
2658
2659 def testPacket(title, arp_match, arp_pkt, result):
2660 pkts = []
2661
2662 match_pkt = scapy.Ether(dst=dl_dst, src=dl_src) / arp_match
2663 match = packet_to_flow_match(self, match_pkt)
2664 self.assertTrue(match is not None,
2665 "Could not generate flow match from pkt")
2666 match.wildcards &= ~ofp.OFPFW_IN_PORT
2667
2668 pkts.append([
2669 title,
2670 scapy.Ether(dst=dl_dst, src=dl_src) / arp_pkt,
2671 result,
2672 ])
2673
2674 act = action.action_output()
2675 self.testPktsAgainstFlow(pkts, act, match)
2676
2677 testPacket("Basic ARP",
2678 scapy.ARP(psrc=ip_src, pdst=ip_dst, op = 1),
2679 scapy.ARP(hwdst = '00:00:00:00:00:00', hwsrc = dl_src,
2680 psrc = ip_src, pdst = ip_dst, hwlen = 6, plen = 4,
2681 ptype = 0x800, hwtype = 1, op = 1),
2682 self.RESULT_MATCH
2683 )
2684 # More stuff:
2685 # - Non matches on any property
2686 # - Corrupted hwlen and plen
2687 # - Other hwtype, ptype
2688 # - Truncated ARP pkt
2689
2690
2691class DirectVlanPackets(DirectBadPacketBase):
2692 """
2693 Verify VLAN parsing (valid and corrupted packets) and ARP matching
2694 """
2695 def runTest(self):
2696 dl_dst='00:01:02:03:04:05'
2697 dl_src='00:06:07:08:09:0a'
2698 ip_src='192.168.0.1'
2699 ip_dst='192.168.0.2'
2700 ip_src2='192.168.1.1'
2701 ip_dst2='192.168.1.2'
2702 ip_tos=0
2703 tcp_sport=1234
2704 tcp_dport=80
2705
2706 def testPacket(title, match, pkt, result):
2707 pkts = []
2708
2709 self.assertTrue(match is not None,
2710 "Could not generate flow match from pkt")
2711 match.wildcards &= ~ofp.OFPFW_IN_PORT
2712
2713 pkts.append([
2714 "%s" % title,
2715 pkt,
2716 result,
2717 ])
2718
2719 act = action.action_output()
2720 self.testPktsAgainstFlow(pkts, act, match)
2721
2722 testPacket("Basic MAC matching - IPv4 payload",
2723 self.createMatch(dl_dst=parse_mac(dl_dst), dl_src=parse_mac(dl_src)),
2724 scapy.Ether(dst=dl_dst, src=dl_src, type=0x800) / scapy.IP(),
2725 self.RESULT_MATCH
2726 )
2727 testPacket("Basic MAC matching - VMware beacon - no payload",
2728 self.createMatch(dl_dst=parse_mac(dl_dst), dl_src=parse_mac(dl_src)),
2729 scapy.Ether(dst=dl_dst, src=dl_src, type=0x8922),
2730 self.RESULT_MATCH
2731 )
2732 testPacket("Basic MAC matching - VMware beacon - with payload",
2733 self.createMatch(dl_dst=parse_mac(dl_dst), dl_src=parse_mac(dl_src)),
2734 scapy.Ether(dst=dl_dst, src=dl_src, type=0x8922)/ ("X" * 1),
2735 self.RESULT_MATCH
2736 )
2737 testPacket("Basic MAC matching - IPv6 payload",
2738 self.createMatch(dl_dst=parse_mac(dl_dst), dl_src=parse_mac(dl_src)),
2739 scapy.Ether(dst=dl_dst, src=dl_src) / scapy.IPv6(),
2740 self.RESULT_MATCH
2741 )
2742 testPacket("Basic MAC matching with VLAN tag present",
2743 self.createMatch(dl_dst=parse_mac(dl_dst), dl_src=parse_mac(dl_src)),
2744 scapy.Ether(dst=dl_dst, src=dl_src)/ \
Christian Dickmann8ac55252012-10-08 22:53:49 -07002745 scapy.Dot1Q(prio=5, vlan=1000)/ \
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002746 scapy.IP(),
2747 self.RESULT_MATCH
2748 )
2749 testPacket("Basic MAC matching with VLAN tag present",
2750 self.createMatch(dl_dst=parse_mac(dl_dst), dl_src=parse_mac(dl_src),
2751 dl_type=0x800),
2752 scapy.Ether(dst=dl_dst, src=dl_src)/ \
Christian Dickmann8ac55252012-10-08 22:53:49 -07002753 scapy.Dot1Q(prio=5, vlan=1000)/ \
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002754 scapy.IP(),
2755 self.RESULT_MATCH
2756 )
2757 testPacket("Ether matching with VLAN tag present - No type match",
2758 self.createMatch(dl_dst=parse_mac(dl_dst), dl_src=parse_mac(dl_src),
2759 dl_type=0x801),
2760 scapy.Ether(dst=dl_dst, src=dl_src)/ \
Christian Dickmann8ac55252012-10-08 22:53:49 -07002761 scapy.Dot1Q(prio=5, vlan=1000)/ \
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002762 scapy.IP(),
2763 self.RESULT_NOMATCH
2764 )
2765 testPacket("Ether matching with VLAN tag present - No type match 0x8100",
2766 self.createMatch(dl_dst=parse_mac(dl_dst), dl_src=parse_mac(dl_src),
2767 dl_type=0x8100),
2768 scapy.Ether(dst=dl_dst, src=dl_src)/ \
Christian Dickmann8ac55252012-10-08 22:53:49 -07002769 scapy.Dot1Q(prio=5, vlan=1000)/ \
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002770 scapy.IP(),
2771 self.RESULT_NOMATCH
2772 )
2773 testPacket("Ether matching with double VLAN tag - Wrong type match",
2774 self.createMatch(dl_dst=parse_mac(dl_dst), dl_src=parse_mac(dl_src),
2775 dl_type=0x800),
2776 scapy.Ether(dst=dl_dst, src=dl_src)/ \
Christian Dickmann8ac55252012-10-08 22:53:49 -07002777 scapy.Dot1Q(prio=5, vlan=1000)/ \
2778 scapy.Dot1Q(prio=3, vlan=1005)/ \
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002779 scapy.IP(),
2780 self.RESULT_NOMATCH
2781 )
2782 testPacket("Ether matching with double VLAN tag - Type match",
2783 self.createMatch(dl_dst=parse_mac(dl_dst), dl_src=parse_mac(dl_src),
2784 dl_type=0x8100),
2785 scapy.Ether(dst=dl_dst, src=dl_src)/ \
Christian Dickmann8ac55252012-10-08 22:53:49 -07002786 scapy.Dot1Q(prio=5, vlan=1000)/ \
2787 scapy.Dot1Q(prio=3, vlan=1005)/ \
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002788 scapy.IP(),
2789 self.RESULT_MATCH
2790 )
2791 testPacket("IP matching - VLAN tag",
2792 self.createMatch(dl_dst=parse_mac(dl_dst), dl_src=parse_mac(dl_src),
2793 dl_type=0x0800,
2794 nw_src=parse_ip(ip_src), nw_dst=parse_ip(ip_dst)),
2795 scapy.Ether(dst=dl_dst, src=dl_src)/ \
Christian Dickmann8ac55252012-10-08 22:53:49 -07002796 scapy.Dot1Q(prio=5, vlan=1000)/ \
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002797 scapy.IP(src=ip_src, dst=ip_dst),
2798 self.RESULT_MATCH
2799 )
2800 # XXX:
2801 # - Matching on VLAN ID and Prio
2802 # - Actions
2803
2804
2805
Dan Talayco9f47f4d2010-06-03 13:54:37 -07002806if __name__ == "__main__":
2807 print "Please run through oft script: ./oft --test_spec=basic"