blob: dff44201d57018b2e0aaea0285ca335f086f6ea2 [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
Dan Talayco551befa2010-07-15 17:05:32 -0700963class ExactMatchTaggedMany(BaseMatchCase):
964 """
965 ExactMatchTagged with many VLANS
966 """
Tatsuya Yabe6a6f38a2010-05-22 23:48:04 -0700967
Rich Laned1d9c282012-10-04 22:07:10 -0700968 priority = -1
969
Dan Talayco551befa2010-07-15 17:05:32 -0700970 def runTest(self):
Dan Talayco21381562010-07-17 00:34:47 -0700971 for vid in range(2,100,10):
Rich Lane477f4812012-10-04 22:49:00 -0700972 flow_match_test(self, config["port_map"], dl_vlan=vid, max_test=5)
Dan Talayco551befa2010-07-15 17:05:32 -0700973 for vid in range(100,4000,389):
Rich Lane477f4812012-10-04 22:49:00 -0700974 flow_match_test(self, config["port_map"], dl_vlan=vid, max_test=5)
975 flow_match_test(self, config["port_map"], dl_vlan=4094, max_test=5)
Tatsuya Yabecdf575e2010-05-25 16:56:38 -0700976
Jeffrey Townsend2a300e42012-03-28 17:24:02 -0700977class SingleWildcardMatchPriority(BaseMatchCase):
Jeffrey Townsend50c82462012-03-28 18:26:14 -0700978 """
979 SingleWildcardMatchPriority
980 """
Jeffrey Townsend2a300e42012-03-28 17:24:02 -0700981
Jeffrey Townsend50c82462012-03-28 18:26:14 -0700982 def _Init(self):
Jeffrey Townsend2a300e42012-03-28 17:24:02 -0700983 self.pkt = simple_tcp_packet()
984 self.flowMsgs = {}
985
Jeffrey Townsend50c82462012-03-28 18:26:14 -0700986 def _ClearTable(self):
Rich Lane9a003812012-10-04 17:17:59 -0700987 rc = delete_all_flows(self.controller)
Jeffrey Townsend50c82462012-03-28 18:26:14 -0700988 self.assertEqual(rc, 0, "Failed to delete all flows")
Dan Talayco0fc08bd2012-04-09 16:56:18 -0700989 self.assertEqual(do_barrier(self.controller), 0, "Barrier failed")
Jeffrey Townsend50c82462012-03-28 18:26:14 -0700990
991 def runTest(self):
992
993 self._Init()
Rich Lane477f4812012-10-04 22:49:00 -0700994 of_ports = config["port_map"].keys()
Jeffrey Townsend2a300e42012-03-28 17:24:02 -0700995 of_ports.sort()
996
997 # Delete the initial flow table
Jeffrey Townsend50c82462012-03-28 18:26:14 -0700998 self._ClearTable()
Jeffrey Townsend2a300e42012-03-28 17:24:02 -0700999
1000 # Run several combinations, each at lower priority settings.
1001 # At the end of each call to runPrioFlows(), the table should
1002 # be empty. If its not, we'll catch it as the priorities decreases
1003 portA = of_ports[0]
1004 portB = of_ports[1]
1005 portC = of_ports[2]
1006
1007 # TODO -- these priority numbers should be validated somehow?
1008 self.runPrioFlows(portA, portB, portC, 1000, 999)
1009 self.runPrioFlows(portB, portC, portA, 998, 997)
1010 self.runPrioFlows(portC, portA, portB, 996, 995)
1011 self.runPrioFlows(portA, portC, portB, 994, 993)
1012
1013
Jeffrey Townsend50c82462012-03-28 18:26:14 -07001014
1015 def runPrioFlows(self, portA, portB, portC, prioHigher, prioLower,
1016 clearTable=False):
Jeffrey Townsend2a300e42012-03-28 17:24:02 -07001017
Jeffrey Townsend50c82462012-03-28 18:26:14 -07001018 if clearTable:
1019 self._ClearTable()
Jeffrey Townsend2a300e42012-03-28 17:24:02 -07001020
1021 # Sanity check flow at lower priority from pA to pB
Rich Lane9a003812012-10-04 17:17:59 -07001022 logging.info("runPrioFlows(pA=%d,pB=%d,pC=%d,ph=%d,pl=%d"
Jeffrey Townsend2a300e42012-03-28 17:24:02 -07001023 % (portA, portB, portC, prioHigher, prioLower))
1024
Jeffrey Townsend2a300e42012-03-28 17:24:02 -07001025 # Sanity check flow at lower priority from pA to pC
1026 self.installFlow(prioLower, portA, portC)
1027 self.verifyFlow(portA, portC)
1028 self.removeFlow(prioLower)
1029
1030 # Install and verify pA->pB @ prioLower
1031 self.installFlow(prioLower, portA, portB)
1032 self.verifyFlow(portA, portB)
1033
1034 # Install and verify pA->pC @ prioHigher, should override pA->pB
1035 self.installFlow(prioHigher, portA, portC)
1036 self.verifyFlow(portA, portC)
1037 # remove pA->pC
1038 self.removeFlow(prioHigher)
Jeffrey Townsend2a300e42012-03-28 17:24:02 -07001039 # Old flow pA -> pB @ prioLower should still be active
1040 self.verifyFlow(portA, portB)
1041 self.removeFlow(prioLower)
1042
1043 # Table should be empty at this point, leave it alone as
1044 # an assumption for future test runs
1045
1046
1047
Ed Swierk99a74de2012-08-22 06:40:54 -07001048 def installFlow(self, prio, inp, egp,
Jeffrey Townsend8364b162012-04-12 13:45:40 -07001049 wildcards=ofp.OFPFW_DL_SRC):
Ed Swierk99a74de2012-08-22 06:40:54 -07001050 wildcards |= required_wildcards(self)
Jeffrey Townsend2a300e42012-03-28 17:24:02 -07001051 request = flow_msg_create(self, self.pkt, ing_port=inp,
Jeffrey Townsend8364b162012-04-12 13:45:40 -07001052 wildcards=wildcards,
Jeffrey Townsend2a300e42012-03-28 17:24:02 -07001053 egr_ports=egp)
1054 request.priority = prio
Rich Lane9a003812012-10-04 17:17:59 -07001055 logging.debug("Install flow with priority " + str(prio))
Jeffrey Townsend50c82462012-03-28 18:26:14 -07001056 flow_msg_install(self, request, clear_table_override=False)
Jeffrey Townsend2a300e42012-03-28 17:24:02 -07001057 self.flowMsgs[prio] = request
1058
1059 def removeFlow(self, prio):
1060 if self.flowMsgs.has_key(prio):
1061 msg = self.flowMsgs[prio]
1062 msg.command = ofp.OFPFC_DELETE_STRICT
1063 # This *must* be set for DELETE
1064 msg.out_port = ofp.OFPP_NONE
Rich Lane9a003812012-10-04 17:17:59 -07001065 logging.debug("Remove flow with priority " + str(prio))
Jeffrey Townsend2a300e42012-03-28 17:24:02 -07001066 self.controller.message_send(msg)
Dan Talayco0fc08bd2012-04-09 16:56:18 -07001067 self.assertEqual(do_barrier(self.controller), 0, "Barrier failed")
Jeffrey Townsend50c82462012-03-28 18:26:14 -07001068 else:
1069 raise Exception("Not initialized")
Jeffrey Townsend2a300e42012-03-28 17:24:02 -07001070
1071
Jeffrey Townsend8364b162012-04-12 13:45:40 -07001072 def verifyFlow(self, inp, egp, pkt=None):
1073 if pkt == None:
1074 pkt = self.pkt
1075
Rich Lane9a003812012-10-04 17:17:59 -07001076 logging.info("Pkt match test: " + str(inp) + " to " + str(egp))
1077 logging.debug("Send packet: " + str(inp) + " to " + str(egp))
Jeffrey Townsend8364b162012-04-12 13:45:40 -07001078 self.dataplane.send(inp, str(pkt))
1079 receive_pkt_verify(self, egp, pkt, inp)
Jeffrey Townsend2a300e42012-03-28 17:24:02 -07001080
1081
1082
Jeffrey Townsend50c82462012-03-28 18:26:14 -07001083class SingleWildcardMatchPriorityInsertModifyDelete(SingleWildcardMatchPriority):
1084
1085 def runTest(self):
1086
1087 self._Init()
1088
Rich Lane477f4812012-10-04 22:49:00 -07001089 of_ports = config["port_map"].keys()
Jeffrey Townsend50c82462012-03-28 18:26:14 -07001090 of_ports.sort()
1091
1092 # Install an entry from 0 -> 1 @ prio 1000
1093 self._ClearTable()
1094 self.installFlow(1000, of_ports[0], of_ports[1])
1095 self.verifyFlow(of_ports[0], of_ports[1])
1096 self.installFlow(1000, of_ports[1], of_ports[0])
1097 self.verifyFlow(of_ports[1], of_ports[0])
1098 self.installFlow(1001, of_ports[0], of_ports[1])
1099 self.verifyFlow(of_ports[0], of_ports[1])
1100 self.installFlow(1001, of_ports[1], of_ports[0])
1101 self.verifyFlow(of_ports[1], of_ports[0])
1102 self.removeFlow(1001)
1103 self.verifyFlow(of_ports[0], of_ports[1])
1104 self.removeFlow(1000)
1105
1106
1107
Jeffrey Townsend8364b162012-04-12 13:45:40 -07001108class WildcardPriority(SingleWildcardMatchPriority):
Ken Chiang38d7a152012-05-24 15:33:50 -07001109 """
1110 1. Add wildcard flow, verify packet received.
Rich Lane0a78fbd2012-12-31 16:25:04 -08001111 2. Add wildcard flow with higher priority, verify packet received
Ken Chiang38d7a152012-05-24 15:33:50 -07001112 on port specified by this flow.
Rich Lane0a78fbd2012-12-31 16:25:04 -08001113 3. Add wildcard flow with lower priority, verify packet received
Rich Laneb8392082012-11-21 15:52:54 -08001114 on port specified by the highest priority flow.
Ken Chiang38d7a152012-05-24 15:33:50 -07001115 """
Jeffrey Townsend8364b162012-04-12 13:45:40 -07001116
1117 def runTest(self):
Jeffrey Townsend50c82462012-03-28 18:26:14 -07001118
Jeffrey Townsend8364b162012-04-12 13:45:40 -07001119 self._Init()
1120
Rich Lane477f4812012-10-04 22:49:00 -07001121 of_ports = config["port_map"].keys()
Jeffrey Townsend8364b162012-04-12 13:45:40 -07001122 of_ports.sort()
1123
1124 self._ClearTable()
Ken Chiang38d7a152012-05-24 15:33:50 -07001125
1126 # Install a flow with wildcards
1127 self.installFlow(999, of_ports[0], of_ports[1],
1128 wildcards=ofp.OFPFW_DL_DST)
Jeffrey Townsend8364b162012-04-12 13:45:40 -07001129 self.verifyFlow(of_ports[0], of_ports[1])
Rich Lane0a78fbd2012-12-31 16:25:04 -08001130 # Install a flow with wildcards with higher priority
1131 self.installFlow(1000, of_ports[0], of_ports[2],
1132 wildcards=ofp.OFPFW_DL_DST)
Jeffrey Townsend8364b162012-04-12 13:45:40 -07001133 self.verifyFlow(of_ports[0], of_ports[2])
Rich Lane0a78fbd2012-12-31 16:25:04 -08001134 # Install a flow with wildcards with lower priority
Rich Laneb8392082012-11-21 15:52:54 -08001135 self.installFlow(999, of_ports[0], of_ports[1],
1136 wildcards=ofp.OFPFW_DL_SRC)
Rich Lane0a78fbd2012-12-31 16:25:04 -08001137 self.verifyFlow(of_ports[0], of_ports[2])
Jeffrey Townsend8364b162012-04-12 13:45:40 -07001138
1139
Ken Chiang3978f242012-06-13 14:14:09 -07001140class WildcardPriorityWithDelete(SingleWildcardMatchPriority):
Ken Chiang38d7a152012-05-24 15:33:50 -07001141 """
Rich Lane0a78fbd2012-12-31 16:25:04 -08001142 1. Add wildcard match flow, verify packet received.
Ken Chiang38d7a152012-05-24 15:33:50 -07001143 2. Add wildcard flow with higher priority, verify packet received on port
1144 specified by this flow.
Rich Lane0a78fbd2012-12-31 16:25:04 -08001145 3. Add wildcard flow with even higher priority, verify packet received
Ken Chiang38d7a152012-05-24 15:33:50 -07001146 on port specified by this flow.
1147 4. Delete lowest priority flow, verify packet received on port specified
1148 by highest priority flow.
1149 5. Delete highest priority flow, verify packet received on port specified
1150 by remaining flow.
1151 """
1152
1153 def runTest(self):
1154
1155 self._Init()
1156
Rich Lane477f4812012-10-04 22:49:00 -07001157 of_ports = config["port_map"].keys()
Ken Chiang38d7a152012-05-24 15:33:50 -07001158 of_ports.sort()
1159
1160 self._ClearTable()
1161
Rich Lane0a78fbd2012-12-31 16:25:04 -08001162 # Install a flow with wildcards
1163 self.installFlow(250, of_ports[0], of_ports[1],
1164 wildcards=ofp.OFPFW_DL_DST)
Ken Chiang38d7a152012-05-24 15:33:50 -07001165 self.verifyFlow(of_ports[0], of_ports[1])
1166 # Install a flow with wildcards of higher priority
1167 self.installFlow(1250, of_ports[0], of_ports[2],
1168 wildcards=ofp.OFPFW_DL_DST)
1169 self.verifyFlow(of_ports[0], of_ports[2])
Rich Lane0a78fbd2012-12-31 16:25:04 -08001170 # Install a flow with wildcards with even higher priority
1171 self.installFlow(2001, of_ports[0], of_ports[3],
1172 wildcards=ofp.OFPFW_DL_DST)
Ken Chiang38d7a152012-05-24 15:33:50 -07001173 self.verifyFlow(of_ports[0], of_ports[3])
1174 # Delete lowest priority flow
1175 self.removeFlow(250)
1176 self.verifyFlow(of_ports[0], of_ports[3])
1177 # Delete highest priority flow
1178 self.removeFlow(2001)
1179 self.verifyFlow(of_ports[0], of_ports[2])
1180
Jeffrey Townsend8364b162012-04-12 13:45:40 -07001181
Dan Talayco551befa2010-07-15 17:05:32 -07001182class SingleWildcardMatch(BaseMatchCase):
Tatsuya Yabe6a6f38a2010-05-22 23:48:04 -07001183 """
1184 Exercise wildcard matching for all ports
1185
1186 Generate a packet
1187 Generate and install a matching flow with wildcard mask
1188 Add action to forward to a port
1189 Send the packet to the port
1190 Verify the packet is received at all other ports (one port at a time)
Tatsuya Yabe0718ad32010-05-24 15:22:10 -07001191 Verify flow_expiration message is correct when command option is set
Tatsuya Yabe6a6f38a2010-05-22 23:48:04 -07001192 """
Tatsuya Yabe0718ad32010-05-24 15:22:10 -07001193 def runTest(self):
Rich Lane2014f9b2012-10-05 15:29:40 -07001194 vid = test_param_get('vid', default=TEST_VID_DEFAULT)
Dan Talayco551befa2010-07-15 17:05:32 -07001195 for wc in WILDCARD_VALUES:
Ed Swierk99a74de2012-08-22 06:40:54 -07001196 wc |= required_wildcards(self)
Dan Talayco4431d542012-03-21 16:42:16 -07001197 if wc & ofp.OFPFW_DL_VLAN:
Ken Chiang5be06dd2012-04-03 10:03:50 -07001198 # Set nonzero VLAN id to avoid sending priority-tagged packet
1199 dl_vlan = vid
Dan Talayco4431d542012-03-21 16:42:16 -07001200 else:
1201 dl_vlan = -1
Rich Lane477f4812012-10-04 22:49:00 -07001202 flow_match_test(self, config["port_map"], wildcards=wc,
Dan Talayco4431d542012-03-21 16:42:16 -07001203 dl_vlan=dl_vlan, max_test=10)
Tatsuya Yabe4fad7e32010-05-24 15:24:50 -07001204
Dan Talayco551befa2010-07-15 17:05:32 -07001205class SingleWildcardMatchTagged(BaseMatchCase):
1206 """
1207 SingleWildcardMatch with tagged packets
1208 """
1209 def runTest(self):
Rich Lane2014f9b2012-10-05 15:29:40 -07001210 vid = test_param_get('vid', default=TEST_VID_DEFAULT)
Dan Talayco551befa2010-07-15 17:05:32 -07001211 for wc in WILDCARD_VALUES:
Ed Swierk99a74de2012-08-22 06:40:54 -07001212 wc |= required_wildcards(self)
Rich Lane477f4812012-10-04 22:49:00 -07001213 flow_match_test(self, config["port_map"], wildcards=wc, dl_vlan=vid,
Dan Talayco551befa2010-07-15 17:05:32 -07001214 max_test=10)
1215
1216class AllExceptOneWildcardMatch(BaseMatchCase):
Tatsuya Yabe4fad7e32010-05-24 15:24:50 -07001217 """
Dan Talayco80b54ed2010-07-13 09:48:35 -07001218 Match exactly one field
Tatsuya Yabe4fad7e32010-05-24 15:24:50 -07001219
1220 Generate a packet
1221 Generate and install a matching flow with wildcard all except one filed
1222 Add action to forward to a port
1223 Send the packet to the port
1224 Verify the packet is received at all other ports (one port at a time)
1225 Verify flow_expiration message is correct when command option is set
1226 """
1227 def runTest(self):
Rich Lane2014f9b2012-10-05 15:29:40 -07001228 vid = test_param_get('vid', default=TEST_VID_DEFAULT)
Dan Talayco488fbc52012-04-09 16:30:41 -07001229 for all_exp_one_wildcard in NO_WILDCARD_VALUES:
Ed Swierk99a74de2012-08-22 06:40:54 -07001230 all_exp_one_wildcard |= required_wildcards(self)
Dan Talayco4431d542012-03-21 16:42:16 -07001231 if all_exp_one_wildcard & ofp.OFPFW_DL_VLAN:
Ken Chiang5be06dd2012-04-03 10:03:50 -07001232 # Set nonzero VLAN id to avoid sending priority-tagged packet
1233 dl_vlan = vid
Dan Talayco4431d542012-03-21 16:42:16 -07001234 else:
1235 dl_vlan = -1
Rich Lane477f4812012-10-04 22:49:00 -07001236 flow_match_test(self, config["port_map"], wildcards=all_exp_one_wildcard,
Dan Talayco4431d542012-03-21 16:42:16 -07001237 dl_vlan=dl_vlan)
Tatsuya Yabee30ebe22010-05-25 09:30:49 -07001238
Dan Talayco551befa2010-07-15 17:05:32 -07001239class AllExceptOneWildcardMatchTagged(BaseMatchCase):
1240 """
1241 Match one field with tagged packets
1242 """
1243 def runTest(self):
Rich Lane2014f9b2012-10-05 15:29:40 -07001244 vid = test_param_get('vid', default=TEST_VID_DEFAULT)
Dan Talayco488fbc52012-04-09 16:30:41 -07001245 for all_exp_one_wildcard in NO_WILDCARD_VALUES:
Ed Swierk99a74de2012-08-22 06:40:54 -07001246 all_exp_one_wildcard |= required_wildcards(self)
Rich Lane477f4812012-10-04 22:49:00 -07001247 flow_match_test(self, config["port_map"], wildcards=all_exp_one_wildcard,
Dan Talayco21381562010-07-17 00:34:47 -07001248 dl_vlan=vid)
Dan Talayco551befa2010-07-15 17:05:32 -07001249
1250class AllWildcardMatch(BaseMatchCase):
Tatsuya Yabee30ebe22010-05-25 09:30:49 -07001251 """
1252 Create Wildcard-all flow and exercise for all ports
1253
1254 Generate a packet
1255 Generate and install a matching flow with wildcard-all
1256 Add action to forward to a port
1257 Send the packet to the port
1258 Verify the packet is received at all other ports (one port at a time)
1259 Verify flow_expiration message is correct when command option is set
1260 """
1261 def runTest(self):
Rich Lane477f4812012-10-04 22:49:00 -07001262 flow_match_test(self, config["port_map"], wildcards=ofp.OFPFW_ALL)
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -07001263
Dan Talayco551befa2010-07-15 17:05:32 -07001264class AllWildcardMatchTagged(BaseMatchCase):
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -07001265 """
Dan Talayco551befa2010-07-15 17:05:32 -07001266 AllWildcardMatch with tagged packets
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -07001267 """
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -07001268 def runTest(self):
Rich Lane2014f9b2012-10-05 15:29:40 -07001269 vid = test_param_get('vid', default=TEST_VID_DEFAULT)
Rich Lane477f4812012-10-04 22:49:00 -07001270 flow_match_test(self, config["port_map"], wildcards=ofp.OFPFW_ALL,
Dan Talayco21381562010-07-17 00:34:47 -07001271 dl_vlan=vid)
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -07001272
Dan Talaycoba3745c2010-07-21 21:51:08 -07001273
Dan Talayco551befa2010-07-15 17:05:32 -07001274class AddVLANTag(BaseMatchCase):
1275 """
1276 Add a VLAN tag to an untagged packet
1277 """
1278 def runTest(self):
1279 new_vid = 2
Ed Swierkc7193a22012-08-22 06:51:02 -07001280 sup_acts = self.supported_actions
Dan Talayco551befa2010-07-15 17:05:32 -07001281 if not(sup_acts & 1<<ofp.OFPAT_SET_VLAN_VID):
Dan Talaycoba3745c2010-07-21 21:51:08 -07001282 skip_message_emit(self, "Add VLAN tag test")
Dan Talaycof36f1082010-07-13 13:57:17 -07001283 return
Tatsuya Yabef5ffb972010-05-26 15:36:33 -07001284
Dan Talayco551befa2010-07-15 17:05:32 -07001285 len = 100
1286 len_w_vid = 104
1287 pkt = simple_tcp_packet(pktlen=len)
1288 exp_pkt = simple_tcp_packet(pktlen=len_w_vid, dl_vlan_enable=True,
1289 dl_vlan=new_vid)
1290 vid_act = action.action_set_vlan_vid()
1291 vid_act.vlan_vid = new_vid
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -07001292
Rich Lane477f4812012-10-04 22:49:00 -07001293 flow_match_test(self, config["port_map"], pkt=pkt,
Dan Talayco551befa2010-07-15 17:05:32 -07001294 exp_pkt=exp_pkt, action_list=[vid_act])
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -07001295
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
1301 priority = -1
1302
Dan Talayco551befa2010-07-15 17:05:32 -07001303 def runTest(self):
1304 pkt = simple_tcp_packet()
Rich Lane477f4812012-10-04 22:49:00 -07001305 of_ports = config["port_map"].keys()
Dan Talayco551befa2010-07-15 17:05:32 -07001306 of_ports.sort()
1307 ing_port = of_ports[0]
Rich Lane9a003812012-10-04 17:17:59 -07001308 logging.info("Sending packet to " + str(ing_port))
1309 logging.debug("Data: " + str(pkt).encode('hex'))
Dan Talayco551befa2010-07-15 17:05:32 -07001310 self.dataplane.send(ing_port, str(pkt))
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -07001311
Rich Laneb90a1c42012-10-05 09:16:05 -07001312class PacketOnlyTagged(base_tests.DataPlaneOnly):
Dan Talayco551befa2010-07-15 17:05:32 -07001313 """
1314 Just send a packet thru the switch
1315 """
Rich Laned1d9c282012-10-04 22:07:10 -07001316
1317 priority = -1
1318
Dan Talayco551befa2010-07-15 17:05:32 -07001319 def runTest(self):
Rich Lane2014f9b2012-10-05 15:29:40 -07001320 vid = test_param_get('vid', default=TEST_VID_DEFAULT)
Dan Talayco551befa2010-07-15 17:05:32 -07001321 pkt = simple_tcp_packet(dl_vlan_enable=True, dl_vlan=vid)
Rich Lane477f4812012-10-04 22:49:00 -07001322 of_ports = config["port_map"].keys()
Dan Talayco551befa2010-07-15 17:05:32 -07001323 of_ports.sort()
1324 ing_port = of_ports[0]
Rich Lane9a003812012-10-04 17:17:59 -07001325 logging.info("Sending packet to " + str(ing_port))
1326 logging.debug("Data: " + str(pkt).encode('hex'))
Dan Talayco551befa2010-07-15 17:05:32 -07001327 self.dataplane.send(ing_port, str(pkt))
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -07001328
Dan Talayco551befa2010-07-15 17:05:32 -07001329class ModifyVID(BaseMatchCase):
Dan Talayco4b2bee62010-07-20 14:10:05 -07001330 """
1331 Modify the VLAN ID in the VLAN tag of a tagged packet
1332 """
Dan Talaycoaf669322012-09-12 22:51:22 -07001333 def setUp(self):
1334 BaseMatchCase.setUp(self)
1335 self.ing_port=False
1336
Dan Talayco551befa2010-07-15 17:05:32 -07001337 def runTest(self):
1338 old_vid = 2
1339 new_vid = 3
Ed Swierkc7193a22012-08-22 06:51:02 -07001340 sup_acts = self.supported_actions
Dan Talayco4b2bee62010-07-20 14:10:05 -07001341 if not (sup_acts & 1 << ofp.OFPAT_SET_VLAN_VID):
Dan Talaycoba3745c2010-07-21 21:51:08 -07001342 skip_message_emit(self, "Modify VLAN tag test")
Dan Talayco551befa2010-07-15 17:05:32 -07001343 return
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -07001344
Dan Talayco551befa2010-07-15 17:05:32 -07001345 pkt = simple_tcp_packet(dl_vlan_enable=True, dl_vlan=old_vid)
1346 exp_pkt = simple_tcp_packet(dl_vlan_enable=True, dl_vlan=new_vid)
1347 vid_act = action.action_set_vlan_vid()
1348 vid_act.vlan_vid = new_vid
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -07001349
Rich Lane477f4812012-10-04 22:49:00 -07001350 flow_match_test(self, config["port_map"], pkt=pkt, exp_pkt=exp_pkt,
Dan Talaycoaf669322012-09-12 22:51:22 -07001351 action_list=[vid_act], ing_port=self.ing_port)
1352
1353class ModifyVIDToIngress(ModifyVID):
1354 """
1355 Modify the VLAN ID in the VLAN tag of a tagged packet and send to
1356 ingress port
1357 """
1358 def setUp(self):
1359 BaseMatchCase.setUp(self)
1360 self.ing_port=True
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -07001361
Ken Chiange9a211d2012-04-20 14:52:11 -07001362class ModifyVIDWithTagMatchWildcarded(BaseMatchCase):
1363 """
1364 With vlan ID and priority wildcarded, perform SET_VLAN_VID action.
1365 The same flow should match on both untagged and tagged packets.
1366 """
1367 def runTest(self):
1368 old_vid = 2
1369 new_vid = 3
Ed Swierkc7193a22012-08-22 06:51:02 -07001370 sup_acts = self.supported_actions
Ken Chiange9a211d2012-04-20 14:52:11 -07001371 if not (sup_acts & 1 << ofp.OFPAT_SET_VLAN_VID):
1372 skip_message_emit(self, "ModifyVIDWithTagWildcarded test")
1373 return
1374
Rich Lane477f4812012-10-04 22:49:00 -07001375 of_ports = config["port_map"].keys()
Ken Chiange9a211d2012-04-20 14:52:11 -07001376 self.assertTrue(len(of_ports) > 1, "Not enough ports for test")
1377 ing_port = of_ports[0]
1378 egr_ports = of_ports[1]
1379
Rich Lane9a003812012-10-04 17:17:59 -07001380 rv = delete_all_flows(self.controller)
Ken Chiange9a211d2012-04-20 14:52:11 -07001381 self.assertEqual(rv, 0, "Failed to delete all flows")
1382
1383 len_untagged = 100
1384 len_w_vid = 104
1385 untagged_pkt = simple_tcp_packet(pktlen=len_untagged)
1386 tagged_pkt = simple_tcp_packet(pktlen=len_w_vid,
1387 dl_vlan_enable=True, dl_vlan=old_vid)
1388 exp_pkt = simple_tcp_packet(pktlen=len_w_vid, dl_vlan_enable=True,
1389 dl_vlan=new_vid)
Ed Swierk99a74de2012-08-22 06:40:54 -07001390 wildcards = (required_wildcards(self) | ofp.OFPFW_DL_VLAN |
1391 ofp.OFPFW_DL_VLAN_PCP)
Ken Chiange9a211d2012-04-20 14:52:11 -07001392 vid_act = action.action_set_vlan_vid()
1393 vid_act.vlan_vid = new_vid
1394 request = flow_msg_create(self, untagged_pkt, ing_port=ing_port,
1395 wildcards=wildcards, egr_ports=egr_ports,
1396 action_list=[vid_act])
1397 flow_msg_install(self, request)
1398
Rich Lane9a003812012-10-04 17:17:59 -07001399 logging.debug("Send untagged packet: " + str(ing_port) + " to " +
Ken Chiange9a211d2012-04-20 14:52:11 -07001400 str(egr_ports))
1401 self.dataplane.send(ing_port, str(untagged_pkt))
1402 receive_pkt_verify(self, egr_ports, exp_pkt, ing_port)
1403
Rich Lane9a003812012-10-04 17:17:59 -07001404 logging.debug("Send tagged packet: " + str(ing_port) + " to " +
Ken Chiange9a211d2012-04-20 14:52:11 -07001405 str(egr_ports))
1406 self.dataplane.send(ing_port, str(tagged_pkt))
1407 receive_pkt_verify(self, egr_ports, exp_pkt, ing_port)
1408
Howard Pershc1199d52012-04-11 14:21:32 -07001409class ModifyVlanPcp(BaseMatchCase):
1410 """
1411 Modify the priority field of the VLAN tag of a tagged packet
1412 """
1413 def runTest(self):
1414 vid = 123
1415 old_vlan_pcp = 2
1416 new_vlan_pcp = 3
Ed Swierkc7193a22012-08-22 06:51:02 -07001417 sup_acts = self.supported_actions
Ed Swierk8c3af7f2012-04-24 14:19:17 -07001418 if not (sup_acts & 1 << ofp.OFPAT_SET_VLAN_PCP):
1419 skip_message_emit(self, "Modify VLAN priority test")
Howard Pershc1199d52012-04-11 14:21:32 -07001420 return
1421
1422 pkt = simple_tcp_packet(dl_vlan_enable=True, dl_vlan=vid, dl_vlan_pcp=old_vlan_pcp)
1423 exp_pkt = simple_tcp_packet(dl_vlan_enable=True, dl_vlan=vid, dl_vlan_pcp=new_vlan_pcp)
1424 vid_act = action.action_set_vlan_pcp()
1425 vid_act.vlan_pcp = new_vlan_pcp
1426
Rich Lane477f4812012-10-04 22:49:00 -07001427 flow_match_test(self, config["port_map"], pkt=pkt, exp_pkt=exp_pkt,
Howard Pershc1199d52012-04-11 14:21:32 -07001428 action_list=[vid_act])
1429
Dan Talayco551befa2010-07-15 17:05:32 -07001430class StripVLANTag(BaseMatchCase):
Dan Talayco4b2bee62010-07-20 14:10:05 -07001431 """
1432 Strip the VLAN tag from a tagged packet
1433 """
Dan Talayco551befa2010-07-15 17:05:32 -07001434 def runTest(self):
1435 old_vid = 2
Ed Swierkc7193a22012-08-22 06:51:02 -07001436 sup_acts = self.supported_actions
Dan Talayco4b2bee62010-07-20 14:10:05 -07001437 if not (sup_acts & 1 << ofp.OFPAT_STRIP_VLAN):
Dan Talaycoba3745c2010-07-21 21:51:08 -07001438 skip_message_emit(self, "Strip VLAN tag test")
Dan Talayco551befa2010-07-15 17:05:32 -07001439 return
Dan Talaycof36f1082010-07-13 13:57:17 -07001440
Dan Talayco551befa2010-07-15 17:05:32 -07001441 len_w_vid = 104
1442 len = 100
1443 pkt = simple_tcp_packet(pktlen=len_w_vid, dl_vlan_enable=True,
1444 dl_vlan=old_vid)
1445 exp_pkt = simple_tcp_packet(pktlen=len)
1446 vid_act = action.action_strip_vlan()
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -07001447
Rich Lane477f4812012-10-04 22:49:00 -07001448 flow_match_test(self, config["port_map"], pkt=pkt, exp_pkt=exp_pkt,
Dan Talayco551befa2010-07-15 17:05:32 -07001449 action_list=[vid_act])
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -07001450
Ken Chiange9a211d2012-04-20 14:52:11 -07001451class StripVLANTagWithTagMatchWildcarded(BaseMatchCase):
1452 """
1453 Strip the VLAN tag from a tagged packet.
1454 Differs from StripVLANTag in that VID and PCP are both wildcarded.
1455 """
1456 def runTest(self):
1457 old_vid = 2
Ed Swierkc7193a22012-08-22 06:51:02 -07001458 sup_acts = self.supported_actions
Ken Chiange9a211d2012-04-20 14:52:11 -07001459 if not (sup_acts & 1 << ofp.OFPAT_STRIP_VLAN):
1460 skip_message_emit(self, "StripVLANTagWithTagWildcarded test")
1461 return
1462
1463 len_w_vid = 104
1464 len_untagged = 100
1465 pkt = simple_tcp_packet(pktlen=len_w_vid, dl_vlan_enable=True,
1466 dl_vlan=old_vid)
1467 exp_pkt = simple_tcp_packet(pktlen=len_untagged)
Ed Swierk99a74de2012-08-22 06:40:54 -07001468 wildcards = (required_wildcards(self) | ofp.OFPFW_DL_VLAN |
1469 ofp.OFPFW_DL_VLAN_PCP)
Ken Chiange9a211d2012-04-20 14:52:11 -07001470 vid_act = action.action_strip_vlan()
1471
Rich Lane477f4812012-10-04 22:49:00 -07001472 flow_match_test(self, config["port_map"],
Ed Swierk99a74de2012-08-22 06:40:54 -07001473 wildcards=wildcards,
Ken Chiange9a211d2012-04-20 14:52:11 -07001474 pkt=pkt, exp_pkt=exp_pkt,
1475 action_list=[vid_act])
1476
Dan Talayco4b2bee62010-07-20 14:10:05 -07001477def init_pkt_args():
1478 """
1479 Pass back a dictionary with default packet arguments
1480 """
1481 args = {}
1482 args["dl_src"] = '00:23:45:67:89:AB'
1483
1484 dl_vlan_enable=False
1485 dl_vlan=-1
Rich Lane477f4812012-10-04 22:49:00 -07001486 if config["test-params"]["vid"]:
Dan Talayco4b2bee62010-07-20 14:10:05 -07001487 dl_vlan_enable=True
Rich Lane477f4812012-10-04 22:49:00 -07001488 dl_vlan = config["test-params"]["vid"]
Dan Talayco4b2bee62010-07-20 14:10:05 -07001489
1490# Unpack operator is ** on a dictionary
1491
1492 return args
1493
Dan Talayco551befa2010-07-15 17:05:32 -07001494class ModifyL2Src(BaseMatchCase):
Dan Talayco4b2bee62010-07-20 14:10:05 -07001495 """
1496 Modify the source MAC address (TP1)
1497 """
Dan Talayco551befa2010-07-15 17:05:32 -07001498 def runTest(self):
Ed Swierkc7193a22012-08-22 06:51:02 -07001499 sup_acts = self.supported_actions
Dan Talayco4b2bee62010-07-20 14:10:05 -07001500 if not (sup_acts & 1 << ofp.OFPAT_SET_DL_SRC):
Dan Talaycoba3745c2010-07-21 21:51:08 -07001501 skip_message_emit(self, "ModifyL2Src test")
Dan Talayco4b2bee62010-07-20 14:10:05 -07001502 return
1503
1504 (pkt, exp_pkt, acts) = pkt_action_setup(self, mod_fields=['dl_src'],
1505 check_test_params=True)
Rich Lane477f4812012-10-04 22:49:00 -07001506 flow_match_test(self, config["port_map"], pkt=pkt, exp_pkt=exp_pkt,
Dan Talayco4b2bee62010-07-20 14:10:05 -07001507 action_list=acts, max_test=2)
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -07001508
Dan Talayco551befa2010-07-15 17:05:32 -07001509class ModifyL2Dst(BaseMatchCase):
Dan Talayco4b2bee62010-07-20 14:10:05 -07001510 """
1511 Modify the dest MAC address (TP1)
1512 """
Dan Talayco551befa2010-07-15 17:05:32 -07001513 def runTest(self):
Ed Swierkc7193a22012-08-22 06:51:02 -07001514 sup_acts = self.supported_actions
Dan Talayco4b2bee62010-07-20 14:10:05 -07001515 if not (sup_acts & 1 << ofp.OFPAT_SET_DL_DST):
Dan Talaycoba3745c2010-07-21 21:51:08 -07001516 skip_message_emit(self, "ModifyL2dst test")
Dan Talayco4b2bee62010-07-20 14:10:05 -07001517 return
1518
1519 (pkt, exp_pkt, acts) = pkt_action_setup(self, mod_fields=['dl_dst'],
1520 check_test_params=True)
Rich Lane477f4812012-10-04 22:49:00 -07001521 flow_match_test(self, config["port_map"], pkt=pkt, exp_pkt=exp_pkt,
Dan Talayco4b2bee62010-07-20 14:10:05 -07001522 action_list=acts, max_test=2)
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -07001523
Dan Talayco551befa2010-07-15 17:05:32 -07001524class ModifyL3Src(BaseMatchCase):
Dan Talayco4b2bee62010-07-20 14:10:05 -07001525 """
1526 Modify the source IP address of an IP packet (TP1)
1527 """
Dan Talayco551befa2010-07-15 17:05:32 -07001528 def runTest(self):
Ed Swierkc7193a22012-08-22 06:51:02 -07001529 sup_acts = self.supported_actions
Dan Talayco4b2bee62010-07-20 14:10:05 -07001530 if not (sup_acts & 1 << ofp.OFPAT_SET_NW_SRC):
Dan Talaycoba3745c2010-07-21 21:51:08 -07001531 skip_message_emit(self, "ModifyL3Src test")
Dan Talayco4b2bee62010-07-20 14:10:05 -07001532 return
1533
1534 (pkt, exp_pkt, acts) = pkt_action_setup(self, mod_fields=['ip_src'],
1535 check_test_params=True)
Rich Lane477f4812012-10-04 22:49:00 -07001536 flow_match_test(self, config["port_map"], pkt=pkt, exp_pkt=exp_pkt,
Dan Talayco4b2bee62010-07-20 14:10:05 -07001537 action_list=acts, max_test=2)
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -07001538
Dan Talayco551befa2010-07-15 17:05:32 -07001539class ModifyL3Dst(BaseMatchCase):
Dan Talayco4b2bee62010-07-20 14:10:05 -07001540 """
1541 Modify the dest IP address of an IP packet (TP1)
1542 """
Dan Talayco551befa2010-07-15 17:05:32 -07001543 def runTest(self):
Ed Swierkc7193a22012-08-22 06:51:02 -07001544 sup_acts = self.supported_actions
Dan Talayco4b2bee62010-07-20 14:10:05 -07001545 if not (sup_acts & 1 << ofp.OFPAT_SET_NW_DST):
Dan Talaycoba3745c2010-07-21 21:51:08 -07001546 skip_message_emit(self, "ModifyL3Dst test")
Dan Talayco4b2bee62010-07-20 14:10:05 -07001547 return
1548
1549 (pkt, exp_pkt, acts) = pkt_action_setup(self, mod_fields=['ip_dst'],
1550 check_test_params=True)
Rich Lane477f4812012-10-04 22:49:00 -07001551 flow_match_test(self, config["port_map"], pkt=pkt, exp_pkt=exp_pkt,
Dan Talayco4b2bee62010-07-20 14:10:05 -07001552 action_list=acts, max_test=2)
Dan Talayco551befa2010-07-15 17:05:32 -07001553
1554class ModifyL4Src(BaseMatchCase):
Dan Talayco4b2bee62010-07-20 14:10:05 -07001555 """
1556 Modify the source TCP port of a TCP packet (TP1)
1557 """
Dan Talayco551befa2010-07-15 17:05:32 -07001558 def runTest(self):
Ed Swierkc7193a22012-08-22 06:51:02 -07001559 sup_acts = self.supported_actions
Dan Talayco4b2bee62010-07-20 14:10:05 -07001560 if not (sup_acts & 1 << ofp.OFPAT_SET_TP_SRC):
Dan Talaycoba3745c2010-07-21 21:51:08 -07001561 skip_message_emit(self, "ModifyL4Src test")
Dan Talayco4b2bee62010-07-20 14:10:05 -07001562 return
1563
1564 (pkt, exp_pkt, acts) = pkt_action_setup(self, mod_fields=['tcp_sport'],
1565 check_test_params=True)
Rich Lane477f4812012-10-04 22:49:00 -07001566 flow_match_test(self, config["port_map"], pkt=pkt, exp_pkt=exp_pkt,
Dan Talayco4b2bee62010-07-20 14:10:05 -07001567 action_list=acts, max_test=2)
Dan Talayco551befa2010-07-15 17:05:32 -07001568
Rich Lane01c2b862012-10-26 16:26:25 -07001569class ModifyL4SrcUdp(BaseMatchCase):
1570 """
1571 Modify the source UDP port of a UDP packet
1572 """
1573 def runTest(self):
1574 sup_acts = self.supported_actions
1575 if not (sup_acts & 1 << ofp.OFPAT_SET_TP_DST):
1576 skip_message_emit(self, "ModifyL4SrcUdp test")
1577 return
1578
1579 (pkt, exp_pkt, acts) = pkt_action_setup(self, mod_fields=['udp_sport'],
1580 check_test_params=True, tp="udp")
1581 flow_match_test(self, config["port_map"], pkt=pkt, exp_pkt=exp_pkt,
1582 action_list=acts, max_test=2)
1583
Dan Talayco551befa2010-07-15 17:05:32 -07001584class ModifyL4Dst(BaseMatchCase):
Dan Talayco4b2bee62010-07-20 14:10:05 -07001585 """
1586 Modify the dest TCP port of a TCP packet (TP1)
1587 """
Dan Talayco551befa2010-07-15 17:05:32 -07001588 def runTest(self):
Ed Swierkc7193a22012-08-22 06:51:02 -07001589 sup_acts = self.supported_actions
Dan Talayco4b2bee62010-07-20 14:10:05 -07001590 if not (sup_acts & 1 << ofp.OFPAT_SET_TP_DST):
Dan Talaycoba3745c2010-07-21 21:51:08 -07001591 skip_message_emit(self, "ModifyL4Dst test")
Dan Talayco4b2bee62010-07-20 14:10:05 -07001592 return
1593
1594 (pkt, exp_pkt, acts) = pkt_action_setup(self, mod_fields=['tcp_dport'],
1595 check_test_params=True)
Rich Lane477f4812012-10-04 22:49:00 -07001596 flow_match_test(self, config["port_map"], pkt=pkt, exp_pkt=exp_pkt,
Dan Talayco4b2bee62010-07-20 14:10:05 -07001597 action_list=acts, max_test=2)
Dan Talayco551befa2010-07-15 17:05:32 -07001598
Rich Lane01c2b862012-10-26 16:26:25 -07001599class ModifyL4DstUdp(BaseMatchCase):
1600 """
1601 Modify the dest UDP port of a UDP packet
1602 """
1603 def runTest(self):
1604 sup_acts = self.supported_actions
1605 if not (sup_acts & 1 << ofp.OFPAT_SET_TP_DST):
1606 skip_message_emit(self, "ModifyL4DstUdp test")
1607 return
1608
1609 (pkt, exp_pkt, acts) = pkt_action_setup(self, mod_fields=['udp_dport'],
1610 check_test_params=True, tp="udp")
1611 flow_match_test(self, config["port_map"], pkt=pkt, exp_pkt=exp_pkt,
1612 action_list=acts, max_test=2)
1613
Dan Talayco551befa2010-07-15 17:05:32 -07001614class ModifyTOS(BaseMatchCase):
Dan Talayco4b2bee62010-07-20 14:10:05 -07001615 """
1616 Modify the IP type of service of an IP packet (TP1)
1617 """
Dan Talayco551befa2010-07-15 17:05:32 -07001618 def runTest(self):
Ed Swierkc7193a22012-08-22 06:51:02 -07001619 sup_acts = self.supported_actions
Dan Talayco4b2bee62010-07-20 14:10:05 -07001620 if not (sup_acts & 1 << ofp.OFPAT_SET_NW_TOS):
Dan Talaycoba3745c2010-07-21 21:51:08 -07001621 skip_message_emit(self, "ModifyTOS test")
Dan Talayco4b2bee62010-07-20 14:10:05 -07001622 return
Dan Talayco551befa2010-07-15 17:05:32 -07001623
Dan Talayco4b2bee62010-07-20 14:10:05 -07001624 (pkt, exp_pkt, acts) = pkt_action_setup(self, mod_fields=['ip_tos'],
1625 check_test_params=True)
Rich Lane477f4812012-10-04 22:49:00 -07001626 flow_match_test(self, config["port_map"], pkt=pkt, exp_pkt=exp_pkt,
Dan Talaycocfa172f2012-03-23 12:03:00 -07001627 action_list=acts, max_test=2, egr_count=-1)
Dan Talayco551befa2010-07-15 17:05:32 -07001628
Dan Talaycof6e76c02012-03-23 10:56:12 -07001629class ModifyL2DstMC(BaseMatchCase):
1630 """
1631 Modify the L2 dest and send to 2 ports
Dan Talaycof6e76c02012-03-23 10:56:12 -07001632 """
1633 def runTest(self):
Ed Swierkc7193a22012-08-22 06:51:02 -07001634 sup_acts = self.supported_actions
Dan Talaycof6e76c02012-03-23 10:56:12 -07001635 if not (sup_acts & 1 << ofp.OFPAT_SET_DL_DST):
Dan Talaycocfa172f2012-03-23 12:03:00 -07001636 skip_message_emit(self, "ModifyL2dstMC test")
Dan Talaycof6e76c02012-03-23 10:56:12 -07001637 return
1638
Dan Talaycof6e76c02012-03-23 10:56:12 -07001639 (pkt, exp_pkt, acts) = pkt_action_setup(self, mod_fields=['dl_dst'],
1640 check_test_params=True)
Rich Lane477f4812012-10-04 22:49:00 -07001641 flow_match_test(self, config["port_map"], pkt=pkt, exp_pkt=exp_pkt,
Dan Talaycocfa172f2012-03-23 12:03:00 -07001642 action_list=acts, max_test=2, egr_count=-1)
Dan Talaycof6e76c02012-03-23 10:56:12 -07001643
Dan Talaycoc948d0b2012-03-23 12:17:54 -07001644class ModifyL2DstIngress(BaseMatchCase):
1645 """
1646 Modify the L2 dest and send to the ingress port
1647 """
1648 def runTest(self):
Ed Swierkc7193a22012-08-22 06:51:02 -07001649 sup_acts = self.supported_actions
Dan Talaycoc948d0b2012-03-23 12:17:54 -07001650 if not (sup_acts & 1 << ofp.OFPAT_SET_DL_DST):
Dan Talaycoabbfdbb2012-04-05 10:29:26 -07001651 skip_message_emit(self, "ModifyL2dstIngress test")
Dan Talaycoc948d0b2012-03-23 12:17:54 -07001652 return
1653
1654 (pkt, exp_pkt, acts) = pkt_action_setup(self, mod_fields=['dl_dst'],
1655 check_test_params=True)
Rich Lane477f4812012-10-04 22:49:00 -07001656 flow_match_test(self, config["port_map"], pkt=pkt, exp_pkt=exp_pkt,
Dan Talaycoc948d0b2012-03-23 12:17:54 -07001657 action_list=acts, max_test=2, egr_count=0,
1658 ing_port=True)
1659
Dan Talaycod8ae7582012-03-23 12:24:56 -07001660class ModifyL2DstIngressMC(BaseMatchCase):
1661 """
1662 Modify the L2 dest and send to the ingress port
1663 """
1664 def runTest(self):
Ed Swierkc7193a22012-08-22 06:51:02 -07001665 sup_acts = self.supported_actions
Dan Talaycod8ae7582012-03-23 12:24:56 -07001666 if not (sup_acts & 1 << ofp.OFPAT_SET_DL_DST):
1667 skip_message_emit(self, "ModifyL2dstMC test")
1668 return
1669
1670 (pkt, exp_pkt, acts) = pkt_action_setup(self, mod_fields=['dl_dst'],
1671 check_test_params=True)
Rich Lane477f4812012-10-04 22:49:00 -07001672 flow_match_test(self, config["port_map"], pkt=pkt, exp_pkt=exp_pkt,
Dan Talaycod8ae7582012-03-23 12:24:56 -07001673 action_list=acts, max_test=2, egr_count=-1,
1674 ing_port=True)
1675
Dan Talaycof6e76c02012-03-23 10:56:12 -07001676class ModifyL2SrcMC(BaseMatchCase):
1677 """
1678 Modify the source MAC address (TP1) and send to multiple
Dan Talaycof6e76c02012-03-23 10:56:12 -07001679 """
1680 def runTest(self):
Ed Swierkc7193a22012-08-22 06:51:02 -07001681 sup_acts = self.supported_actions
Dan Talaycof6e76c02012-03-23 10:56:12 -07001682 if not (sup_acts & 1 << ofp.OFPAT_SET_DL_SRC):
Dan Talaycocfa172f2012-03-23 12:03:00 -07001683 skip_message_emit(self, "ModifyL2SrcMC test")
Dan Talaycof6e76c02012-03-23 10:56:12 -07001684 return
1685
Dan Talaycof6e76c02012-03-23 10:56:12 -07001686 (pkt, exp_pkt, acts) = pkt_action_setup(self, mod_fields=['dl_src'],
1687 check_test_params=True)
Rich Lane477f4812012-10-04 22:49:00 -07001688 flow_match_test(self, config["port_map"], pkt=pkt, exp_pkt=exp_pkt,
Dan Talaycocfa172f2012-03-23 12:03:00 -07001689 action_list=acts, max_test=2, egr_count=-1)
Dan Talaycof6e76c02012-03-23 10:56:12 -07001690
1691class ModifyL2SrcDstMC(BaseMatchCase):
1692 """
1693 Modify the L2 source and dest and send to 2 ports
Dan Talaycof6e76c02012-03-23 10:56:12 -07001694 """
1695 def runTest(self):
Ed Swierkc7193a22012-08-22 06:51:02 -07001696 sup_acts = self.supported_actions
Dan Talaycocfa172f2012-03-23 12:03:00 -07001697 if (not (sup_acts & 1 << ofp.OFPAT_SET_DL_DST) or
1698 not (sup_acts & 1 << ofp.OFPAT_SET_DL_SRC)):
1699 skip_message_emit(self, "ModifyL2SrcDstMC test")
Dan Talaycof6e76c02012-03-23 10:56:12 -07001700 return
1701
Dan Talaycof6e76c02012-03-23 10:56:12 -07001702 mod_fields = ['dl_dst', 'dl_src']
1703 (pkt, exp_pkt, acts) = pkt_action_setup(self, mod_fields=mod_fields,
1704 check_test_params=True)
Rich Lane477f4812012-10-04 22:49:00 -07001705 flow_match_test(self, config["port_map"], pkt=pkt, exp_pkt=exp_pkt,
Dan Talaycocfa172f2012-03-23 12:03:00 -07001706 action_list=acts, max_test=2, egr_count=-1)
1707
1708class ModifyL2DstVIDMC(BaseMatchCase):
1709 """
1710 Modify the L2 dest and send to 2 ports
1711 """
1712 def runTest(self):
Ed Swierkc7193a22012-08-22 06:51:02 -07001713 sup_acts = self.supported_actions
Dan Talaycocfa172f2012-03-23 12:03:00 -07001714 if (not (sup_acts & 1 << ofp.OFPAT_SET_DL_DST) or
1715 not (sup_acts & 1 << ofp.OFPAT_SET_VLAN_VID)):
1716 skip_message_emit(self, "ModifyL2DstVIDMC test")
1717 return
1718
1719 mod_fields = ['dl_dst', 'dl_vlan']
1720 (pkt, exp_pkt, acts) = pkt_action_setup(self,
1721 start_field_vals={'dl_vlan_enable':True}, mod_fields=mod_fields,
1722 check_test_params=True)
Rich Lane477f4812012-10-04 22:49:00 -07001723 flow_match_test(self, config["port_map"], pkt=pkt, exp_pkt=exp_pkt,
Dan Talaycocfa172f2012-03-23 12:03:00 -07001724 action_list=acts, max_test=2, egr_count=-1)
Dan Talaycof6e76c02012-03-23 10:56:12 -07001725
Rich Lane22e74c12012-11-12 15:06:06 -08001726class ModifyAll(BaseMatchCase):
1727 """
1728 Modify all supported fields and output to a port
1729 """
1730 def runTest(self):
1731 sup_acts = self.supported_actions
1732
1733 sup_map = {
1734 "dl_dst" : ofp.OFPAT_SET_DL_DST,
1735 "dl_src" : ofp.OFPAT_SET_DL_SRC,
1736 "dl_vlan_enable" : ofp.OFPAT_SET_VLAN_VID,
1737 "dl_vlan" : ofp.OFPAT_SET_VLAN_VID,
1738 "dl_vlan_pcp" : ofp.OFPAT_SET_VLAN_PCP,
1739 "ip_src" : ofp.OFPAT_SET_NW_SRC,
1740 "ip_dst" : ofp.OFPAT_SET_NW_DST,
1741 "ip_tos" : ofp.OFPAT_SET_NW_TOS,
1742 "tcp_sport" : ofp.OFPAT_SET_TP_SRC,
1743 "tcp_dport" : ofp.OFPAT_SET_TP_DST,
1744 }
1745
1746 mod_fields = [field for (field, bit) in sup_map.items() if (sup_acts & 1 << bit)]
1747 random.shuffle(mod_fields)
1748 start_field_vals = { "dl_vlan_enable" : True }
1749 mod_field_vals = { "dl_vlan_enable" : True }
1750 logging.info("modifying fields: %s" % repr(mod_fields))
1751
1752 (pkt, exp_pkt, acts) = pkt_action_setup(self,
1753 mod_fields=mod_fields,
1754 start_field_vals=start_field_vals,
1755 mod_field_vals=mod_field_vals,
1756 check_test_params=True)
1757 flow_match_test(self, config["port_map"], pkt=pkt, exp_pkt=exp_pkt,
1758 action_list=acts, max_test=2)
1759
Dan Talaycofa6454f2012-04-05 10:04:13 -07001760class FlowToggle(BaseMatchCase):
1761 """
1762 Add flows to the table and modify them repeatedly
Dan Talaycof7c41312012-07-23 12:53:19 -07001763
1764 This is done by using only "add" flow messages. Since the check overlap
1765 flag is not set, the switch is supposed to modify the existing flow if
1766 the match already exists.
1767
1768 Would probably be better to exercise more of the flow modify commands
1769 (add, modify, delete +/- strict).
Dan Talaycofa6454f2012-04-05 10:04:13 -07001770 """
1771 def runTest(self):
Rich Lane2014f9b2012-10-05 15:29:40 -07001772 flow_count = test_param_get('ft_flow_count', default=20)
1773 iter_count = test_param_get('ft_iter_count', default=10)
Dan Talaycofa6454f2012-04-05 10:04:13 -07001774
Rich Lane9a003812012-10-04 17:17:59 -07001775 logging.info("Running flow toggle with %d flows, %d iterations" %
Dan Talaycofa6454f2012-04-05 10:04:13 -07001776 (flow_count, iter_count))
1777 acts = []
1778 acts.append(action.action_output())
1779 acts.append(action.action_output())
1780
Rich Lane477f4812012-10-04 22:49:00 -07001781 of_ports = config["port_map"].keys()
Dan Talaycofa6454f2012-04-05 10:04:13 -07001782 if len(of_ports) < 3:
1783 self.assertTrue(False, "Too few ports for test")
1784
1785 for idx in range(2):
1786 acts[idx].port = of_ports[idx]
1787
1788 flows = []
1789 flows.append([])
1790 flows.append([])
1791
Ed Swierk99a74de2012-08-22 06:40:54 -07001792 wildcards = (required_wildcards(self) | ofp.OFPFW_DL_SRC |
1793 ofp.OFPFW_DL_DST)
Dan Talaycofa6454f2012-04-05 10:04:13 -07001794 # Create up the flows in an array
1795 for toggle in range(2):
1796 for f_idx in range(flow_count):
1797 pkt = simple_tcp_packet(tcp_sport=f_idx)
1798 msg = message.flow_mod()
Ed Swierk99a74de2012-08-22 06:40:54 -07001799 match = packet_to_flow_match(self, pkt)
Shudong Zhou031373c2012-07-19 17:37:42 -07001800 match.in_port = of_ports[2]
Dan Talayco50be7672012-04-05 11:38:08 -07001801 match.wildcards = wildcards
Dan Talaycofa6454f2012-04-05 10:04:13 -07001802 msg.match = match
1803 msg.buffer_id = 0xffffffff
Dan Talaycof7c41312012-07-23 12:53:19 -07001804 msg.command = ofp.OFPFC_ADD
Dan Talaycofa6454f2012-04-05 10:04:13 -07001805 msg.actions.add(acts[toggle])
1806 flows[toggle].append(msg)
Dan Talayco50be7672012-04-05 11:38:08 -07001807
1808 # Show two sample flows
Rich Lane9a003812012-10-04 17:17:59 -07001809 logging.debug(flows[0][0].show())
1810 logging.debug(flows[1][0].show())
Dan Talayco50be7672012-04-05 11:38:08 -07001811
Dan Talaycofa6454f2012-04-05 10:04:13 -07001812 # Install the first set of flows
1813 for f_idx in range(flow_count):
1814 rv = self.controller.message_send(flows[0][f_idx])
1815 self.assertTrue(rv != -1, "Error installing flow %d" % f_idx)
Dan Talayco0fc08bd2012-04-09 16:56:18 -07001816 self.assertEqual(do_barrier(self.controller), 0, "Barrier failed")
Dan Talaycofa6454f2012-04-05 10:04:13 -07001817
Rich Lane9a003812012-10-04 17:17:59 -07001818 logging.info("Installed %d flows" % flow_count)
Dan Talaycofa6454f2012-04-05 10:04:13 -07001819
1820 # Repeatedly modify all the flows back and forth
1821 updates = 0
1822 # Report status about 5 times
1823 mod_val = (iter_count / 4) + 1
Dan Talaycoabbfdbb2012-04-05 10:29:26 -07001824 start = time.time()
1825 for iter_idx in range(iter_count):
1826 if not iter_idx % mod_val:
Rich Lane9a003812012-10-04 17:17:59 -07001827 logging.info("Flow Toggle: iter %d of %d. " %
Dan Talaycoabbfdbb2012-04-05 10:29:26 -07001828 (iter_idx, iter_count) +
1829 "%d updates in %d secs" %
1830 (updates, time.time() - start))
Dan Talaycofa6454f2012-04-05 10:04:13 -07001831 for toggle in range(2):
1832 t_idx = 1 - toggle
1833 for f_idx in range(flow_count):
1834 rv = self.controller.message_send(flows[t_idx][f_idx])
1835 updates += 1
1836 self.assertTrue(rv != -1, "Error modifying flow %d" %
1837 f_idx)
Dan Talayco0fc08bd2012-04-09 16:56:18 -07001838 self.assertEqual(do_barrier(self.controller), 0,
1839 "Barrier failed")
Dan Talaycoabbfdbb2012-04-05 10:29:26 -07001840
1841 end = time.time()
1842 divisor = end - start or (end - start + 1)
Rich Lane9a003812012-10-04 17:17:59 -07001843 logging.info("Flow toggle: %d iterations" % iter_count)
1844 logging.info(" %d flow mods in %d secs, %d mods/sec" %
Dan Talaycoabbfdbb2012-04-05 10:29:26 -07001845 (updates, end - start, updates/divisor))
Dan Talaycofa6454f2012-04-05 10:04:13 -07001846
1847
Dan Talayco8a64e332012-03-28 14:53:20 -07001848# You can pick and choose these by commenting tests in or out
1849iter_classes = [
1850 basic.PacketIn,
1851 basic.PacketOut,
1852 DirectPacket,
Dan Talaycofa6454f2012-04-05 10:04:13 -07001853 FlowToggle,
Dan Talayco8a64e332012-03-28 14:53:20 -07001854 DirectTwoPorts,
Dan Talaycofa6454f2012-04-05 10:04:13 -07001855 DirectMCNonIngress,
Dan Talayco8a64e332012-03-28 14:53:20 -07001856 AllWildcardMatch,
1857 AllWildcardMatchTagged,
1858 SingleWildcardMatch,
1859 SingleWildcardMatchTagged,
1860 ExactMatch,
1861 ExactMatchTagged,
1862 SingleWildcardMatch,
1863 ModifyL2Src,
1864 ModifyL2Dst,
1865 ModifyL2SrcMC,
1866 ModifyL2DstMC,
1867 ModifyL2SrcDstMC
1868 ]
1869
1870class IterCases(BaseMatchCase):
Dan Talaycofa6454f2012-04-05 10:04:13 -07001871 """
1872 Iterate over a bunch of test cases
1873
1874 The cases come from the list above
1875 """
1876
Rich Laned1d9c282012-10-04 22:07:10 -07001877 priority = -1
1878
Dan Talayco8a64e332012-03-28 14:53:20 -07001879 def runTest(self):
Rich Lane2014f9b2012-10-05 15:29:40 -07001880 count = test_param_get('iter_count', default=10)
Dan Talayco8a64e332012-03-28 14:53:20 -07001881 tests_done = 0
Rich Lane9a003812012-10-04 17:17:59 -07001882 logging.info("Running iteration test " + str(count) + " times")
Dan Talayco8a64e332012-03-28 14:53:20 -07001883 start = time.time()
1884 last = start
1885 for idx in range(count):
Rich Lane9a003812012-10-04 17:17:59 -07001886 logging.info("Iteration " + str(idx + 1))
Dan Talayco8a64e332012-03-28 14:53:20 -07001887 for cls in iter_classes:
1888 test = cls()
1889 test.inheritSetup(self)
1890 test.runTest()
1891 tests_done += 1
Dan Talaycofa6454f2012-04-05 10:04:13 -07001892 # Report update about every minute, between tests
Dan Talayco8a64e332012-03-28 14:53:20 -07001893 if time.time() - last > 60:
1894 last = time.time()
Rich Lane9a003812012-10-04 17:17:59 -07001895 logging.info(
Dan Talaycofa6454f2012-04-05 10:04:13 -07001896 "IterCases: Iter %d of %d; Ran %d tests in %d " %
1897 (idx, count, tests_done, last - start) +
1898 "seconds so far")
Dan Talayco8a64e332012-03-28 14:53:20 -07001899 stats = all_stats_get(self)
1900 last = time.time()
Rich Lane9a003812012-10-04 17:17:59 -07001901 logging.info("\nIterCases ran %d tests in %d seconds." %
Dan Talayco8a64e332012-03-28 14:53:20 -07001902 (tests_done, last - start))
Rich Lane9a003812012-10-04 17:17:59 -07001903 logging.info(" flows: %d. packets: %d. bytes: %d" %
Dan Talayco8a64e332012-03-28 14:53:20 -07001904 (stats["flows"], stats["packets"], stats["bytes"]))
Rich Lane9a003812012-10-04 17:17:59 -07001905 logging.info(" active: %d. lookups: %d. matched %d." %
Dan Talayco8a64e332012-03-28 14:53:20 -07001906 (stats["active"], stats["lookups"], stats["matched"]))
1907
Dan Talayco4b2bee62010-07-20 14:10:05 -07001908#@todo Need to implement tagged versions of the above tests
1909#
1910#@todo Implement a test case that strips tag 2, adds tag 3
1911# and modifies tag 4 to tag 5. Then verify (in addition) that
1912# tag 6 does not get modified.
1913
1914class MixedVLAN(BaseMatchCase):
1915 """
1916 Test mixture of VLAN tag actions
1917
1918 Strip tag 2 on port 1, send to port 2
1919 Add tag 3 on port 1, send to port 2
1920 Modify tag 4 to 5 on port 1, send to port 2
1921 All other traffic from port 1, send to port 3
1922 All traffic from port 2 sent to port 4
1923 Use exact matches with different packets for all mods
1924 Verify the following: (port, vid)
1925 (port 1, vid 2) => VLAN tag stripped, out port 2
1926 (port 1, no tag) => tagged packet w/ vid 2 out port 2
1927 (port 1, vid 4) => tagged packet w/ vid 5 out port 2
1928 (port 1, vid 5) => tagged packet w/ vid 5 out port 2
1929 (port 1, vid 6) => tagged packet w/ vid 6 out port 2
1930 (port 2, no tag) => untagged packet out port 4
1931 (port 2, vid 2-6) => unmodified packet out port 4
1932
1933 Variation: Might try sending VID 5 to port 3 and check.
1934 If only VID 5 distinguishes pkt, this will fail on some platforms
1935 """
1936
Rich Laned1d9c282012-10-04 22:07:10 -07001937 priority = -1
Rich Lane8d6ab272012-09-23 18:06:20 -07001938
Rich Laneb90a1c42012-10-05 09:16:05 -07001939class MatchEach(base_tests.SimpleDataPlane):
Rich Lane8d6ab272012-09-23 18:06:20 -07001940 """
1941 Check that each match field is actually matched on.
1942 Installs two flows that differ in one field. The flow that should not
1943 match has a higher priority, so if that field is ignored during matching
1944 the packet will be sent out the wrong port.
1945
1946 TODO test UDP, ARP, ICMP, etc.
1947 """
1948 def runTest(self):
Rich Lane477f4812012-10-04 22:49:00 -07001949 of_ports = config["port_map"].keys()
Rich Lane8d6ab272012-09-23 18:06:20 -07001950 of_ports.sort()
1951 self.assertTrue(len(of_ports) > 1, "Not enough ports for test")
1952
Rich Lane9a003812012-10-04 17:17:59 -07001953 delete_all_flows(self.controller)
Rich Lane8d6ab272012-09-23 18:06:20 -07001954
Ed Swierk7040a8d2012-12-11 16:30:13 -08001955 pkt = simple_tcp_packet(dl_vlan_enable=True, dl_vlan=2)
Rich Lane8d6ab272012-09-23 18:06:20 -07001956 ingress_port = of_ports[0]
1957 egress_port = of_ports[1]
1958
1959 def testField(field, mask):
Rich Lane9a003812012-10-04 17:17:59 -07001960 logging.info("Testing field %s" % field)
Rich Lane8d6ab272012-09-23 18:06:20 -07001961
1962 def addFlow(matching, priority, output_port):
1963 match = packet_to_flow_match(self, pkt)
1964 self.assertTrue(match is not None, "Could not generate flow match from pkt")
1965 match.wildcards &= ~ofp.OFPFW_IN_PORT
1966 match.in_port = ingress_port
1967 if not matching:
1968 # Make sure flow doesn't match
1969 orig = getattr(match, field)
1970 if isinstance(orig, list):
1971 new = map(lambda a: ~a[0] & a[1], zip(orig, mask))
1972 else:
1973 new = ~orig & mask
1974 setattr(match, field, new)
1975 request = message.flow_mod()
1976 request.match = match
1977 request.buffer_id = 0xffffffff
1978 request.priority = priority
1979 act = action.action_output()
1980 act.port = output_port
1981 self.assertTrue(request.actions.add(act), "Could not add action")
Rich Lane9a003812012-10-04 17:17:59 -07001982 logging.info("Inserting flow")
Rich Lane8d6ab272012-09-23 18:06:20 -07001983 self.controller.message_send(request)
1984
1985 # This flow should match.
1986 addFlow(matching=True, priority=0, output_port=egress_port)
1987 # This flow should not match, but it has a higher priority.
1988 addFlow(matching=False, priority=1, output_port=ofp.OFPP_IN_PORT)
1989
1990 self.assertEqual(do_barrier(self.controller), 0, "Barrier failed")
1991
Rich Lane9a003812012-10-04 17:17:59 -07001992 logging.info("Sending packet to dp port " + str(ingress_port))
Rich Lane8d6ab272012-09-23 18:06:20 -07001993 self.dataplane.send(ingress_port, str(pkt))
1994
1995 exp_pkt_arg = None
1996 exp_port = None
Rich Lane477f4812012-10-04 22:49:00 -07001997 if config["relax"]:
Rich Lane8d6ab272012-09-23 18:06:20 -07001998 exp_pkt_arg = pkt
1999 exp_port = egress_port
2000
2001 (rcv_port, rcv_pkt, pkt_time) = self.dataplane.poll(port_number=exp_port,
2002 exp_pkt=exp_pkt_arg)
2003 self.assertTrue(rcv_pkt is not None, "Did not receive packet")
Rich Lane9a003812012-10-04 17:17:59 -07002004 logging.debug("Packet len " + str(len(rcv_pkt)) + " in on " + str(rcv_port))
Rich Lane8d6ab272012-09-23 18:06:20 -07002005 self.assertEqual(rcv_port, egress_port, "Unexpected receive port")
2006 self.assertEqual(str(pkt), str(rcv_pkt), 'Response packet does not match send packet')
2007
Ed Swierkb603b192012-12-12 15:38:49 -08002008 wildcards = required_wildcards(self)
Rich Lane8d6ab272012-09-23 18:06:20 -07002009 # TODO in_port
Ed Swierkb603b192012-12-12 15:38:49 -08002010 if not (wildcards & ofp.OFPFW_DL_SRC):
2011 testField("dl_src", [0xff]*6)
2012 if not (wildcards & ofp.OFPFW_DL_DST):
2013 testField("dl_dst", [0xff]*6)
2014 if not (wildcards & ofp.OFPFW_DL_TYPE):
2015 testField("dl_type", 0xffff)
2016 if not (wildcards & ofp.OFPFW_DL_VLAN):
2017 testField("dl_vlan", 0xfff)
Rich Lane8d6ab272012-09-23 18:06:20 -07002018 # TODO dl_vlan_pcp
Ed Swierkb603b192012-12-12 15:38:49 -08002019 if not (wildcards & ofp.OFPFW_NW_SRC_ALL):
2020 testField("nw_src", 0xffffffff)
2021 if not (wildcards & ofp.OFPFW_NW_DST_ALL):
2022 testField("nw_dst", 0xffffffff)
2023 if not (wildcards & ofp.OFPFW_NW_TOS):
2024 testField("nw_tos", 0x3f)
2025 if not (wildcards & ofp.OFPFW_NW_PROTO):
2026 testField("nw_proto", 0xff)
2027 if not (wildcards & ofp.OFPFW_TP_SRC):
2028 testField("tp_src", 0xffff)
2029 if not (wildcards & ofp.OFPFW_TP_DST):
2030 testField("tp_dst", 0xffff)
Rich Lane8d6ab272012-09-23 18:06:20 -07002031
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002032class DirectBadPacketBase(base_tests.SimpleDataPlane):
2033 """
2034 Base class for sending single packets with single flow table entries.
2035 Used to verify matching of unusual packets and parsing/matching of
2036 corrupted packets.
2037
2038 The idea is to generate packets that may either be totally malformed or
2039 malformed just enough to trick the flow matcher into making mistakes.
2040
2041 Generate a 'bad' packet
2042 Generate and install a matching flow
2043 Add action to direct the packet to an egress port
2044 Send the packet to ingress dataplane port
2045 Verify the packet is received at the egress port only
2046 """
2047
2048 RESULT_MATCH = "MATCH"
2049 RESULT_NOMATCH = "NO MATCH"
2050 RESULT_ANY = "ANY MATCH"
2051
2052 def runTest(self):
2053 pass
2054 # TODO:
2055 # - ICMP?
2056 # - VLAN?
2057 # - action
2058
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002059 def createMatch(self, **kwargs):
2060 match = ofp.ofp_match()
2061 match.wildcards = ofp.OFPFW_ALL
2062 fields = {
2063 'dl_dst': ofp.OFPFW_DL_DST,
2064 'dl_src': ofp.OFPFW_DL_SRC,
2065 'dl_type': ofp.OFPFW_DL_TYPE,
2066 'dl_vlan': ofp.OFPFW_DL_VLAN,
2067 'nw_src': ofp.OFPFW_NW_SRC_MASK,
2068 'nw_dst': ofp.OFPFW_NW_DST_MASK,
2069 'nw_tos': ofp.OFPFW_NW_TOS,
2070 'nw_proto': ofp.OFPFW_NW_PROTO,
2071 'tp_src': ofp.OFPFW_TP_SRC,
2072 'tp_dst': ofp.OFPFW_TP_DST,
2073 }
2074 for key in kwargs:
2075 setattr(match, key, kwargs[key])
2076 match.wildcards &= ~fields[key]
2077 return match
2078
2079 def testPktsAgainstFlow(self, pkts, acts, match):
2080 if type(acts) != list:
2081 acts = [acts]
2082 for info in pkts:
2083 title, pkt, expected_result = info
2084 self.testPktAgainstFlow(title, pkt, acts, match, expected_result)
2085
2086 def testPktAgainstFlow(self, title, pkt, acts, match, expected_result):
2087 of_ports = config["port_map"].keys()
2088 of_ports.sort()
2089 self.assertTrue(len(of_ports) > 1, "Not enough ports for test")
2090
2091 rv = delete_all_flows(self.controller)
2092 self.assertEqual(rv, 0, "Failed to delete all flows")
2093
2094 ingress_port = of_ports[0]
2095 egress_port = of_ports[1]
2096
2097 logging.info("Testing packet '%s', expect result %s" %
2098 (title, expected_result))
2099 logging.info("Ingress %s to egress %s" %
2100 (str(ingress_port), str(egress_port)))
2101 logging.info("Packet:")
Rich Lane5d7e89a2012-10-26 16:43:13 -07002102 logging.info(inspect_packet(pkt))
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002103
2104 match.in_port = ingress_port
2105
2106 request = message.flow_mod()
2107 request.match = match
Rich Lane44cf12d2012-10-15 11:10:45 -07002108 request.priority = 1
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002109
2110 request.buffer_id = 0xffffffff
2111 for act in acts:
2112 act.port = egress_port
2113 rv = request.actions.add(act)
2114 self.assertTrue(rv, "Could not add action")
2115
2116 logging.info("Inserting flow")
2117 rv = self.controller.message_send(request)
2118 self.assertTrue(rv != -1, "Error installing flow mod")
Rich Lane44cf12d2012-10-15 11:10:45 -07002119
2120 # This flow speeds up negative tests
2121 logging.info("Inserting catch-all flow")
2122 request2 = message.flow_mod()
2123 request2.match = self.createMatch()
2124 request2.priority = 0
2125 act = action.action_output()
2126 act.port = ofp.OFPP_IN_PORT
2127 request2.actions.add(act)
2128 rv = self.controller.message_send(request2)
2129 self.assertTrue(rv != -1, "Error installing flow mod")
2130
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002131 self.assertEqual(do_barrier(self.controller), 0, "Barrier failed")
2132
2133 logging.info("Sending packet to dp port " +
2134 str(ingress_port))
2135 self.dataplane.send(ingress_port, str(pkt))
2136
2137 exp_pkt_arg = None
2138 exp_port = None
2139 if config["relax"]:
2140 exp_pkt_arg = pkt
2141 exp_port = egress_port
2142
Rich Lane44cf12d2012-10-15 11:10:45 -07002143 if expected_result == self.RESULT_MATCH:
2144 timeout = -1 # default timeout
2145 else:
2146 timeout = 1 # short timeout for negative tests
2147
2148 (rcv_port, rcv_pkt, pkt_time) = self.dataplane.poll(exp_pkt=exp_pkt_arg,
2149 timeout=timeout)
2150 if rcv_port == ingress_port:
2151 logging.debug("Packet matched catch-all flow")
2152 rcv_pkt = None
2153
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002154 if expected_result == self.RESULT_MATCH:
2155 self.assertTrue(rcv_pkt is not None,
2156 "Did not receive packet, expected a match")
2157 logging.debug("Packet len " + str(len(rcv_pkt)) + " in on " +
2158 str(rcv_port))
2159 self.assertEqual(rcv_port, egress_port, "Unexpected receive port")
2160 str_pkt = str(pkt)
2161 str_rcv_pkt = str(rcv_pkt)
2162 str_rcv_pkt = str_rcv_pkt[0:len(str_pkt)]
2163 if str_pkt != str_rcv_pkt:
2164 logging.error("Response packet does not match send packet")
2165 logging.info("Response:")
Rich Lane5d7e89a2012-10-26 16:43:13 -07002166 logging.info(inspect_packet(scapy.Ether(rcv_pkt)))
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002167 self.assertEqual(str_pkt, str_rcv_pkt,
2168 'Response packet does not match send packet')
2169 elif expected_result == self.RESULT_NOMATCH:
2170 self.assertTrue(rcv_pkt is None, "Received packet, expected drop")
2171 else:
2172 logging.debug("Match or drop accepted. Result = %s" %
2173 ("match" if rcv_pkt is not None else "drop"))
2174
2175
2176class DirectBadIpTcpPacketsBase(DirectBadPacketBase):
2177 """
2178 Base class for TCP and UDP parsing/matching verification under corruptions
2179 """
2180 def runTest(self):
2181 pass
2182
2183 def runTestWithProto(self, protoName = 'TCP'):
2184 dl_dst='00:01:02:03:04:05'
2185 dl_src='00:06:07:08:09:0a'
2186 ip_src='192.168.0.1'
2187 ip_dst='192.168.0.2'
2188 ip_tos=0
2189 tcp_sport=1234
2190 tcp_dport=80
2191
2192 # Generate a proper packet for constructing a match
2193 tp = None
2194 if protoName == 'TCP':
2195 tp = scapy.TCP
2196 proto = 6
2197 elif protoName == 'UDP':
2198 tp = scapy.UDP
2199 proto = 17
2200 else:
2201 raise Exception("Passed in unknown proto name")
2202
2203 match_pkt = scapy.Ether(dst=dl_dst, src=dl_src)/ \
2204 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos)/ \
2205 tp(sport=tcp_sport, dport=tcp_dport)
2206 match = packet_to_flow_match(self, match_pkt)
2207 self.assertTrue(match is not None,
2208 "Could not generate flow match from pkt")
2209 match.wildcards &= ~ofp.OFPFW_IN_PORT
2210
2211 def testPacket(title, pkt, result):
2212 act = action.action_output()
2213 pkts = [
2214 [title, pkt, result]
2215 ]
2216 self.testPktsAgainstFlow(pkts, act, match)
2217
2218 # Try incomplete IP headers
2219 testPacket("Incomplete IP header (1 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:1],
2222 self.RESULT_NOMATCH,
2223 )
2224 testPacket("Incomplete IP header (2 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:2],
2227 self.RESULT_NOMATCH,
2228 )
2229 testPacket("Incomplete IP header (3 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:3],
2232 self.RESULT_NOMATCH,
2233 )
2234 testPacket("Incomplete IP header (12 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:12],
2237 self.RESULT_NOMATCH,
2238 )
2239 testPacket("Incomplete IP header (16 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:16],
2242 self.RESULT_NOMATCH,
2243 )
2244 testPacket("Incomplete IP header (19 bytes)",
2245 scapy.Ether(dst=dl_dst, src=dl_src)/ \
2246 str(scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, proto=proto))[0:19],
2247 self.RESULT_NOMATCH,
2248 )
2249
2250 # Try variations where the TCP header is missing or incomplete. As we
2251 # saw bugs before where buffers were reused and lengths weren't honored,
2252 # we initiatlize once with a non-matching full packet and once with a
2253 # matching full packet.
2254 testPacket("Non-Matching TCP packet, warming buffer",
2255 scapy.Ether(dst=dl_dst, src=dl_src)/ \
2256 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, proto=proto)/ \
2257 tp(sport=tcp_sport, dport=tcp_dport + 1),
2258 self.RESULT_NOMATCH,
2259 )
2260 testPacket("Missing TCP header, buffer warmed with non-match",
2261 scapy.Ether(dst=dl_dst, src=dl_src)/ \
2262 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, proto=proto),
2263 self.RESULT_NOMATCH,
2264 )
2265 testPacket("Matching TCP packet, warming buffer",
2266 scapy.Ether(dst=dl_dst, src=dl_src)/ \
2267 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, proto=proto)/ \
2268 tp(sport=tcp_sport, dport=tcp_dport),
2269 self.RESULT_MATCH,
2270 )
2271 testPacket("Missing TCP header, buffer warmed with match",
2272 scapy.Ether(dst=dl_dst, src=dl_src)/ \
2273 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, proto=proto),
2274 self.RESULT_NOMATCH,
2275 )
2276 testPacket("Truncated TCP header: 2 bytes",
2277 scapy.Ether(dst=dl_dst, src=dl_src)/ \
2278 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, proto=proto)/ \
2279 (str(tp(sport=tcp_sport, dport=tcp_dport))[0:2]),
2280 self.RESULT_NOMATCH,
2281 )
2282
2283 # Play with IP header length values that put the start of TCP either
2284 # inside the generated TCP header or beyond. In some cases it may even
2285 # be beyond the packet boundary. Also play with IP options and more
2286 # importantly IP total length corruptions.
2287 testPacket("TCP packet, corrupt ihl (0x6)",
2288 simple_tcp_packet(ip_ihl=6),
2289 self.RESULT_NOMATCH,
2290 )
2291 testPacket("TCP packet, corrupt ihl (0xf)",
2292 simple_tcp_packet(ip_ihl=0xf), # ihl = 15 * 4 = 60
2293 self.RESULT_NOMATCH,
2294 )
2295 testPacket("TCP packet, corrupt ihl and total length",
2296 simple_tcp_packet(ip_ihl=0xf, pktlen=56), # ihl = 15 * 4 = 60,
2297 self.RESULT_NOMATCH,
2298 )
2299 testPacket("Corrupt IPoption: First 4 bytes of matching TCP header",
2300 simple_tcp_packet(
2301 ip_options=scapy.IPOption('\x04\xd2\x00\x50'),
2302 tcp_dport=2, tcp_sport=2
2303 ),
2304 self.RESULT_NOMATCH,
2305 )
2306 testPacket("Missing TCP header, corrupt ihl",
2307 scapy.Ether(dst=dl_dst, src=dl_src)/ \
2308 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ihl=0xf, proto=proto),
2309 self.RESULT_NOMATCH,
2310 )
2311 testPacket("Missing TCP header, corrupt total length",
2312 scapy.Ether(dst=dl_dst, src=dl_src)/ \
2313 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, proto=proto, len= 100),
2314 self.RESULT_NOMATCH,
2315 )
2316 testPacket("Missing TCP header, corrupt ihl and total length",
2317 scapy.Ether(dst=dl_dst, src=dl_src)/ \
2318 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ihl=0xf, proto=proto, len=43),
2319 self.RESULT_NOMATCH,
2320 )
2321 testPacket("Incomplete IP header (12 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:12],
2324 self.RESULT_NOMATCH,
2325 )
2326 testPacket("Incomplete IP header (16 bytes), corrupt ihl and total length",
2327 scapy.Ether(dst=dl_dst, src=dl_src)/ \
2328 str(scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, proto=proto, ihl=10, len=43))[0:16],
2329 self.RESULT_NOMATCH,
2330 )
2331
2332 # Try an incomplete TCP header that has enough bytes to carry source and
2333 # destination ports. As that is all we care about during matching, some
2334 # implementations may match and some may drop the packet
2335 testPacket("Incomplete TCP header: src/dst port present",
2336 scapy.Ether(dst=dl_dst, src=dl_src)/ \
2337 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, proto=proto)/ \
2338 (str(tp(sport=tcp_sport, dport=tcp_dport))[0:4]),
2339 self.RESULT_ANY,
2340 )
2341
2342 for i in range(1):
2343 for length in range(40 / 4): # IPv4 options are a maximum of 40 in length
2344 bytes = "".join([("%c" % random.randint(0, 255)) for x in range(length * 4)])
2345 eth = scapy.Ether(dst=dl_dst, src=dl_src)
2346 ip = scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ihl=5 + length, proto=proto)
2347 tcp = tp(sport=tcp_sport, dport=tcp_dport+1)
2348 pkt = eth / ip
2349 pkt = pkt / bytes
2350 pkt = pkt / str(tcp)
2351 testPacket("Random IP options len = %d - TP match must fail" % length * 4,
2352 pkt,
2353 self.RESULT_NOMATCH
2354 )
2355
2356 eth = scapy.Ether(dst=dl_dst, src=dl_src)
2357 ip = scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ihl=5 + length, proto=proto)
2358 tcp = tp(sport=tcp_sport, dport=tcp_dport)
2359 pkt = eth / ip
2360 pkt = pkt / bytes
2361 pkt = pkt / str(tcp)
2362
2363 testPacket("Random IP options len = %d - May match",
2364 pkt,
2365 self.RESULT_ANY
2366 )
2367
2368
2369class DirectBadIpTcpPackets(DirectBadIpTcpPacketsBase):
2370 """
2371 Verify IP/TCP parsing and matching. Focus on packet corruptions
2372 """
2373 def runTest(self):
2374 self.runTestWithProto(protoName = 'TCP')
2375
2376class DirectBadIpUdpPackets(DirectBadIpTcpPacketsBase):
2377 """
2378 Verify IP/UDP parsing and matching. Focus on packet corruptions
2379 """
2380 def runTest(self):
2381 self.runTestWithProto(protoName = 'UDP')
2382
2383class DirectBadLlcPackets(DirectBadPacketBase):
2384 """
2385 Verify LLC/SNAP parsing and matching. Focus on packet corruptions
2386 """
2387 def runTest(self):
2388 dl_dst='00:01:02:03:04:05'
2389 dl_src='00:06:07:08:09:0a'
2390 ip_src='192.168.0.1'
2391 ip_dst='192.168.0.2'
2392 ip_tos=0
2393 tcp_sport=1234
2394 tcp_dport=80
2395
2396 IS_SNAP_IP = 1
2397 IS_SNAP_IP_CORRUPT = 2
2398 IS_NOT_SNAP_IP = 3
2399
2400 def testPacketTcpMatch(title, llc):
2401 match_pkt = scapy.Ether(dst=dl_dst, src=dl_src)/ \
2402 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos)/ \
2403 scapy.TCP(sport=tcp_sport, dport=tcp_dport)
2404 match = packet_to_flow_match(self, match_pkt)
2405 self.assertTrue(match is not None,
2406 "Could not generate flow match from pkt")
2407 match.wildcards &= ~ofp.OFPFW_IN_PORT
2408 act = action.action_output()
2409
2410 self.testPktsAgainstFlow(
2411 [[
2412 "TCP match - LLC frame correct length - %s" % title,
2413 scapy.Ether(dst=dl_dst, src=dl_src, type=len(llc)) / llc,
2414 self.RESULT_ANY,
2415 ]],
2416 act, match
2417 )
2418
2419 # Corrupt length field
2420 ethLen = random.randint(0, 1535)
2421 self.testPktsAgainstFlow(
2422 [[
2423 "TCP match - LLC frame corrupted length - %s" % title,
2424 scapy.Ether(dst=dl_dst, src=dl_src, type=ethLen) / llc,
2425 self.RESULT_ANY,
2426 ]],
2427 act, match
2428 )
2429
2430 def testPacketEthSrcDstMatch(title, llc):
2431 # Matching based on Ethernet source and destination
2432 match_pkt = scapy.Ether(dst=dl_dst, src=dl_src)
2433 match = packet_to_flow_match(self, match_pkt)
2434 self.assertTrue(match is not None,
2435 "Could not generate flow match from pkt")
2436 match.wildcards &= ~ofp.OFPFW_IN_PORT
2437 match.wildcards |= ofp.OFPFW_DL_TYPE
2438 self.testPktsAgainstFlow(
2439 [[
2440 "Eth addr match - LLC frame correct length- %s" % title,
2441 scapy.Ether(dst=dl_dst, src=dl_src, type=len(llc)) / llc,
2442 self.RESULT_MATCH,
2443 ]],
2444 action.action_output(), match
2445 )
2446
2447 # Corrupt length field
2448 ethLen = random.randint(0, 1535)
2449 self.testPktsAgainstFlow(
2450 [[
2451 "Eth addr match - LLC frame corrupted length- %s" % title,
2452 scapy.Ether(dst=dl_dst, src=dl_src, type=ethLen) / llc,
2453 self.RESULT_ANY,
2454 ]],
2455 action.action_output(), match
2456 )
2457
2458 def testPacketEthSrcDstTypeMatch(title, llc, is_snap_ip):
2459 # Matching based on Ethernet source, destination and type
2460 match_pkt = scapy.Ether(dst=dl_dst, src=dl_src, type=0x800)
2461 match = packet_to_flow_match(self, match_pkt)
2462 self.assertTrue(match is not None,
2463 "Could not generate flow match from pkt")
2464 match.wildcards &= ~ofp.OFPFW_IN_PORT
2465 if is_snap_ip == IS_SNAP_IP:
2466 is_match = self.RESULT_MATCH
2467 elif is_snap_ip == IS_SNAP_IP_CORRUPT:
2468 is_match = self.RESULT_ANY
2469 else:
2470 is_match = self.RESULT_NOMATCH
2471 self.testPktsAgainstFlow(
2472 [[
2473 "Eth addr+type match - LLC frame correct length - %s" % title,
2474 scapy.Ether(dst=dl_dst, src=dl_src, type=len(llc)) / llc,
2475 is_match,
2476 ]],
2477 action.action_output(), match
2478 )
2479
2480 # Corrupt length field
2481 ethLen = random.randint(0, 1535)
2482 self.testPktsAgainstFlow(
2483 [[
2484 "Eth addr+type match - LLC frame corrupted length - %s" % title,
2485 scapy.Ether(dst=dl_dst, src=dl_src, type=ethLen) / llc,
Christian Dickmanne9b6d252012-10-08 22:56:50 -07002486 self.RESULT_ANY,
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002487 ]],
2488 action.action_output(), match
2489 )
2490
2491 def testPacket(title, llc, is_snap_ip):
2492 testPacketTcpMatch(title, llc)
2493 testPacketEthSrcDstMatch(title, llc)
2494 testPacketEthSrcDstTypeMatch(title, llc, is_snap_ip)
2495
2496 testPacket("LLC - No SNAP - No Payload",
Rich Lane6508ea02012-10-12 15:27:11 -07002497 scapy.LLC(dsap=0x33, ssap=0x44, ctrl=0x03),
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002498 IS_NOT_SNAP_IP,
2499 )
2500 testPacket("LLC - No SNAP - Small Payload",
Rich Lane6508ea02012-10-12 15:27:11 -07002501 scapy.LLC(dsap=0x33, ssap=0x44, ctrl=0x03) / ("S" * 10),
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002502 IS_NOT_SNAP_IP,
2503 )
2504 testPacket("LLC - No SNAP - Max -1 Payload",
Rich Lane6508ea02012-10-12 15:27:11 -07002505 scapy.LLC(dsap=0x33, ssap=0x44, ctrl=0x03) / ("S" * (1500 - 3 - 1)),
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002506 IS_NOT_SNAP_IP,
2507 )
2508 testPacket("LLC - No SNAP - Max Payload",
Rich Lane6508ea02012-10-12 15:27:11 -07002509 scapy.LLC(dsap=0x33, ssap=0x44, ctrl=0x03) / ("S" * (1500 - 3)),
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002510 IS_NOT_SNAP_IP,
2511 )
2512 testPacket("LLC - SNAP - Small bogus payload",
2513 scapy.LLC(dsap=0xaa, ssap=0xaa, ctrl=0x03)/ \
2514 scapy.SNAP(OUI=0x000000, code=0x800) / ("S" * 10),
2515 IS_SNAP_IP_CORRUPT,
2516 )
2517 testPacket("LLC - SNAP - Max -1 bogus payload",
2518 scapy.LLC(dsap=0xaa, ssap=0xaa, ctrl=0x03)/ \
2519 scapy.SNAP(OUI=0x000000, code=0x3) / ("S" * (1500 - 3 - 5 - 1)),
2520 IS_NOT_SNAP_IP,
2521 )
2522 testPacket("LLC - SNAP - Max bogus payload",
2523 scapy.LLC(dsap=0xaa, ssap=0xaa, ctrl=0x03)/ \
2524 scapy.SNAP(OUI=0x000000, code=0x3) / ("S" * (1500 - 3 - 5)),
2525 IS_NOT_SNAP_IP,
2526 )
2527 testPacket("LLC - SNAP - IP - TCP",
2528 scapy.LLC(dsap=0xaa, ssap=0xaa, ctrl=0x03)/ \
2529 scapy.SNAP(OUI=0x000000, code=0x800)/ \
2530 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, proto=6)/ \
2531 scapy.TCP(sport=tcp_sport, dport=tcp_dport),
2532 IS_SNAP_IP,
2533 )
2534
2535
2536class DirectLlcPackets(DirectBadPacketBase):
2537 """
2538 Verify LLC/SNAP parsing (valid and corrupted packets) and matching
2539 """
2540 def runTest(self):
2541 dl_dst='00:01:02:03:04:05'
2542 dl_src='00:06:07:08:09:0a'
2543 ip_src='192.168.0.1'
2544 ip_dst='192.168.0.2'
2545 ip_tos=0
2546 tcp_sport=1234
2547 tcp_dport=80
2548
2549 # Test ethertype in face of LLC/SNAP and OFP_DL_TYPE_NOT_ETH_TYPE
2550 IS_SNAP_NOT_IP = 1
2551 IS_SNAP_AND_IP = 2
2552 IS_NOT_SNAP = 3
2553
2554 def testPacketEthTypeIP(title, llc, is_snap):
2555 match_pkt = scapy.Ether(dst=dl_dst, src=dl_src, type=0x800)
2556 match = packet_to_flow_match(self, match_pkt)
2557 self.assertTrue(match is not None,
2558 "Could not generate flow match from pkt")
2559 match.wildcards &= ~ofp.OFPFW_IN_PORT
2560 pkts = []
2561 if is_snap == IS_NOT_SNAP or is_snap == IS_SNAP_NOT_IP:
2562 result = self.RESULT_NOMATCH
2563 else:
2564 result = self.RESULT_MATCH
2565 pkts.append([
2566 "Ether type 0x800 match - %s" % title,
2567 scapy.Ether(dst=dl_dst, src=dl_src, type=len(llc)) / llc,
2568 result,
2569 ])
2570 act = action.action_output()
2571 self.testPktsAgainstFlow(pkts, act, match)
2572
2573 def testPacketEthTypeNotEth(title, llc, is_snap):
2574 match_pkt = scapy.Ether(dst = dl_dst, src = dl_src,
2575 type = ofp.OFP_DL_TYPE_NOT_ETH_TYPE)
2576 match = packet_to_flow_match(self, match_pkt)
2577 self.assertTrue(match is not None,
2578 "Could not generate flow match from pkt")
2579 match.wildcards &= ~ofp.OFPFW_IN_PORT
2580 pkts = []
2581 if is_snap == IS_NOT_SNAP:
2582 result = self.RESULT_MATCH
2583 else:
2584 result = self.RESULT_NOMATCH
2585 pkts.append([
2586 "Ether type OFP_DL_TYPE_NOT_ETH_TYPE match - %s" % title,
2587 scapy.Ether(dst=dl_dst, src=dl_src, type=len(llc)) / llc,
2588 result,
2589 ])
2590 act = action.action_output()
2591 self.testPktsAgainstFlow(pkts, act, match)
2592
2593 def testPacket(title, llc, is_snap):
2594 testPacketEthTypeIP(title, llc, is_snap)
2595 testPacketEthTypeNotEth(title, llc, is_snap)
2596
2597 testPacket("LLC - No SNAP - No Payload",
Rich Lane6508ea02012-10-12 15:27:11 -07002598 scapy.LLC(dsap=0x33, ssap=0x44, ctrl=0x03),
2599 IS_NOT_SNAP,
2600 )
2601 testPacket("LLC (with information field) - No SNAP - No Payload",
2602 scapy.LLC(dsap=0x33, ssap=0x44, ctrl=0x12) / "S",
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002603 IS_NOT_SNAP,
2604 )
2605 testPacket("LLC - No SNAP - Small Payload",
Rich Lane6508ea02012-10-12 15:27:11 -07002606 scapy.LLC(dsap=0x33, ssap=0x44, ctrl=0x03) / ("S" * 10),
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002607 IS_NOT_SNAP,
2608 )
2609 testPacket("LLC - No SNAP - Max -1 Payload",
Rich Lane6508ea02012-10-12 15:27:11 -07002610 scapy.LLC(dsap=0x33, ssap=0x44, ctrl=0x03) / ("S" * (1500 - 3 - 1)),
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002611 IS_NOT_SNAP,
2612 )
2613 testPacket("LLC - No SNAP - Max Payload",
Rich Lane6508ea02012-10-12 15:27:11 -07002614 scapy.LLC(dsap=0x33, ssap=0x44, ctrl=0x03) / ("S" * (1500 - 3)),
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002615 IS_NOT_SNAP,
2616 )
2617 testPacket("LLC - SNAP - Non-default OUI",
2618 scapy.LLC(dsap=0xaa, ssap=0xaa, ctrl=0x03)/ \
2619 scapy.SNAP(OUI=0x000001, code=0x800) / ("S" * 10),
2620 IS_NOT_SNAP,
2621 )
2622 testPacket("LLC - SNAP - Default OUI",
2623 scapy.LLC(dsap=0xaa, ssap=0xaa, ctrl=0x03)/ \
2624 scapy.SNAP(OUI=0x000000, code=0x800) / ("S" * 10),
2625 IS_SNAP_AND_IP,
2626 )
2627 testPacket("LLC - SNAP - Max -1 bogus payload",
2628 scapy.LLC(dsap=0xaa, ssap=0xaa, ctrl=0x03)/ \
2629 scapy.SNAP(OUI=0x000000, code=0x3) / ("S" * (1500 - 3 - 5 - 1)),
2630 IS_SNAP_NOT_IP,
2631 )
2632 testPacket("LLC - SNAP - Max bogus payload",
2633 scapy.LLC(dsap=0xaa, ssap=0xaa, ctrl=0x03)/ \
2634 scapy.SNAP(OUI=0x000000, code=0x3) / ("S" * (1500 - 3 - 5)),
2635 IS_SNAP_NOT_IP,
2636 )
2637 testPacket("LLC - SNAP - IP - TCP",
2638 scapy.LLC(dsap=0xaa, ssap=0xaa, ctrl=0x03)/ \
2639 scapy.SNAP(OUI=0x000000, code=0x800)/ \
2640 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, proto=6)/ \
2641 scapy.TCP(sport=tcp_sport, dport=tcp_dport),
2642 IS_SNAP_AND_IP,
2643 )
2644
2645
2646class DirectArpPackets(DirectBadPacketBase):
2647 """
2648 Verify ARP parsing (valid and corrupted packets) and ARP matching
2649 """
2650 def runTest(self):
2651 self.testArpHandling()
2652
2653 def testArpHandling(self):
2654 dl_dst='00:01:02:03:04:05'
2655 dl_src='00:06:07:08:09:0a'
2656 ip_src='192.168.0.1'
2657 ip_dst='192.168.0.2'
2658 ip_src2='192.168.1.1'
2659 ip_dst2='192.168.1.2'
2660 ip_tos=0
2661 tcp_sport=1234
2662 tcp_dport=80
2663
2664 def testPacket(title, arp_match, arp_pkt, result):
2665 pkts = []
2666
2667 match_pkt = scapy.Ether(dst=dl_dst, src=dl_src) / arp_match
2668 match = packet_to_flow_match(self, match_pkt)
2669 self.assertTrue(match is not None,
2670 "Could not generate flow match from pkt")
2671 match.wildcards &= ~ofp.OFPFW_IN_PORT
2672
2673 pkts.append([
2674 title,
2675 scapy.Ether(dst=dl_dst, src=dl_src) / arp_pkt,
2676 result,
2677 ])
2678
2679 act = action.action_output()
2680 self.testPktsAgainstFlow(pkts, act, match)
2681
2682 testPacket("Basic ARP",
2683 scapy.ARP(psrc=ip_src, pdst=ip_dst, op = 1),
2684 scapy.ARP(hwdst = '00:00:00:00:00:00', hwsrc = dl_src,
2685 psrc = ip_src, pdst = ip_dst, hwlen = 6, plen = 4,
2686 ptype = 0x800, hwtype = 1, op = 1),
2687 self.RESULT_MATCH
2688 )
2689 # More stuff:
2690 # - Non matches on any property
2691 # - Corrupted hwlen and plen
2692 # - Other hwtype, ptype
2693 # - Truncated ARP pkt
2694
2695
2696class DirectVlanPackets(DirectBadPacketBase):
2697 """
2698 Verify VLAN parsing (valid and corrupted packets) and ARP matching
2699 """
2700 def runTest(self):
2701 dl_dst='00:01:02:03:04:05'
2702 dl_src='00:06:07:08:09:0a'
2703 ip_src='192.168.0.1'
2704 ip_dst='192.168.0.2'
2705 ip_src2='192.168.1.1'
2706 ip_dst2='192.168.1.2'
2707 ip_tos=0
2708 tcp_sport=1234
2709 tcp_dport=80
2710
2711 def testPacket(title, match, pkt, result):
2712 pkts = []
2713
2714 self.assertTrue(match is not None,
2715 "Could not generate flow match from pkt")
2716 match.wildcards &= ~ofp.OFPFW_IN_PORT
2717
2718 pkts.append([
2719 "%s" % title,
2720 pkt,
2721 result,
2722 ])
2723
2724 act = action.action_output()
2725 self.testPktsAgainstFlow(pkts, act, match)
2726
2727 testPacket("Basic MAC matching - IPv4 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=0x800) / scapy.IP(),
2730 self.RESULT_MATCH
2731 )
2732 testPacket("Basic MAC matching - VMware beacon - no 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),
2735 self.RESULT_MATCH
2736 )
2737 testPacket("Basic MAC matching - VMware beacon - with 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, type=0x8922)/ ("X" * 1),
2740 self.RESULT_MATCH
2741 )
2742 testPacket("Basic MAC matching - IPv6 payload",
2743 self.createMatch(dl_dst=parse_mac(dl_dst), dl_src=parse_mac(dl_src)),
2744 scapy.Ether(dst=dl_dst, src=dl_src) / scapy.IPv6(),
2745 self.RESULT_MATCH
2746 )
2747 testPacket("Basic MAC matching with VLAN tag present",
2748 self.createMatch(dl_dst=parse_mac(dl_dst), dl_src=parse_mac(dl_src)),
2749 scapy.Ether(dst=dl_dst, src=dl_src)/ \
Christian Dickmann8ac55252012-10-08 22:53:49 -07002750 scapy.Dot1Q(prio=5, vlan=1000)/ \
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002751 scapy.IP(),
2752 self.RESULT_MATCH
2753 )
2754 testPacket("Basic MAC matching with VLAN tag present",
2755 self.createMatch(dl_dst=parse_mac(dl_dst), dl_src=parse_mac(dl_src),
2756 dl_type=0x800),
2757 scapy.Ether(dst=dl_dst, src=dl_src)/ \
Christian Dickmann8ac55252012-10-08 22:53:49 -07002758 scapy.Dot1Q(prio=5, vlan=1000)/ \
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002759 scapy.IP(),
2760 self.RESULT_MATCH
2761 )
2762 testPacket("Ether matching with VLAN tag present - No type match",
2763 self.createMatch(dl_dst=parse_mac(dl_dst), dl_src=parse_mac(dl_src),
2764 dl_type=0x801),
2765 scapy.Ether(dst=dl_dst, src=dl_src)/ \
Christian Dickmann8ac55252012-10-08 22:53:49 -07002766 scapy.Dot1Q(prio=5, vlan=1000)/ \
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002767 scapy.IP(),
2768 self.RESULT_NOMATCH
2769 )
2770 testPacket("Ether matching with VLAN tag present - No type match 0x8100",
2771 self.createMatch(dl_dst=parse_mac(dl_dst), dl_src=parse_mac(dl_src),
2772 dl_type=0x8100),
2773 scapy.Ether(dst=dl_dst, src=dl_src)/ \
Christian Dickmann8ac55252012-10-08 22:53:49 -07002774 scapy.Dot1Q(prio=5, vlan=1000)/ \
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002775 scapy.IP(),
2776 self.RESULT_NOMATCH
2777 )
2778 testPacket("Ether matching with double VLAN tag - Wrong type match",
2779 self.createMatch(dl_dst=parse_mac(dl_dst), dl_src=parse_mac(dl_src),
2780 dl_type=0x800),
2781 scapy.Ether(dst=dl_dst, src=dl_src)/ \
Christian Dickmann8ac55252012-10-08 22:53:49 -07002782 scapy.Dot1Q(prio=5, vlan=1000)/ \
2783 scapy.Dot1Q(prio=3, vlan=1005)/ \
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002784 scapy.IP(),
2785 self.RESULT_NOMATCH
2786 )
2787 testPacket("Ether matching with double VLAN tag - Type match",
2788 self.createMatch(dl_dst=parse_mac(dl_dst), dl_src=parse_mac(dl_src),
2789 dl_type=0x8100),
2790 scapy.Ether(dst=dl_dst, src=dl_src)/ \
Christian Dickmann8ac55252012-10-08 22:53:49 -07002791 scapy.Dot1Q(prio=5, vlan=1000)/ \
2792 scapy.Dot1Q(prio=3, vlan=1005)/ \
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002793 scapy.IP(),
2794 self.RESULT_MATCH
2795 )
2796 testPacket("IP matching - VLAN tag",
2797 self.createMatch(dl_dst=parse_mac(dl_dst), dl_src=parse_mac(dl_src),
2798 dl_type=0x0800,
2799 nw_src=parse_ip(ip_src), nw_dst=parse_ip(ip_dst)),
2800 scapy.Ether(dst=dl_dst, src=dl_src)/ \
Christian Dickmann8ac55252012-10-08 22:53:49 -07002801 scapy.Dot1Q(prio=5, vlan=1000)/ \
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002802 scapy.IP(src=ip_src, dst=ip_dst),
2803 self.RESULT_MATCH
2804 )
2805 # XXX:
2806 # - Matching on VLAN ID and Prio
2807 # - Actions
2808
2809
2810
Dan Talayco9f47f4d2010-06-03 13:54:37 -07002811if __name__ == "__main__":
2812 print "Please run through oft script: ./oft --test_spec=basic"