blob: 615b02a44e2bf0447f72eb46196816b4e28470af [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")
380
381 act = action.action_enqueue()
382
383 for idx in range(len(of_ports)):
384 ingress_port = of_ports[idx]
385 egress_port = ofp.OFPP_CONTROLLER
386
Rich Lane9a003812012-10-04 17:17:59 -0700387 logging.info("Ingress port " + str(ingress_port)
Ken Chiang899ff8e2012-05-23 18:26:12 -0700388 + ", controller port queues "
389 + str(self.portQueuesGet(queue_stats, egress_port)))
390
391 for egress_queue_id in self.portQueuesGet(queue_stats, egress_port):
Rich Lane9a003812012-10-04 17:17:59 -0700392 logging.info("Ingress " + str(ingress_port)
Ken Chiang899ff8e2012-05-23 18:26:12 -0700393 + " to egress " + str(egress_port)
394 + " queue " + str(egress_queue_id)
395 )
396
Rich Lane9a003812012-10-04 17:17:59 -0700397 rv = delete_all_flows(self.controller)
Ken Chiang899ff8e2012-05-23 18:26:12 -0700398 self.assertEqual(rv, 0, "Failed to delete all flows")
399
400 match.in_port = ingress_port
401
402 request = message.flow_mod()
403 request.match = match
404
405 request.buffer_id = 0xffffffff
406 act.port = egress_port
407 act.queue_id = egress_queue_id
408 self.assertTrue(request.actions.add(act), "Could not add action")
409
Rich Lane9a003812012-10-04 17:17:59 -0700410 logging.info("Inserting flow")
Ken Chiang899ff8e2012-05-23 18:26:12 -0700411 rv = self.controller.message_send(request)
412 self.assertTrue(rv != -1, "Error installing flow mod")
413 self.assertEqual(do_barrier(self.controller), 0, "Barrier failed")
414
415 # Get current stats for selected egress queue
416
417 request = message.queue_stats_request()
418 request.port_no = egress_port
419 request.queue_id = egress_queue_id
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700420 (qs_before, p) = self.controller.transact(request)
Ken Chiang899ff8e2012-05-23 18:26:12 -0700421 self.assertNotEqual(qs_before, None, "Queue stats request failed")
422
Rich Lane9a003812012-10-04 17:17:59 -0700423 logging.info("Sending packet to dp port " +
Ken Chiang899ff8e2012-05-23 18:26:12 -0700424 str(ingress_port))
425 self.dataplane.send(ingress_port, str(pkt))
426
427 exp_pkt_arg = None
428 exp_port = None
429
Rich Lanee5779d32012-10-05 17:56:04 -0700430 count = 0
Ken Chiang899ff8e2012-05-23 18:26:12 -0700431 while True:
Dan Talaycoc689a792012-09-28 14:22:53 -0700432 (response, raw) = self.controller.poll(ofp.OFPT_PACKET_IN)
Ken Chiang899ff8e2012-05-23 18:26:12 -0700433 if not response: # Timeout
434 break
435 if dataplane.match_exp_pkt(pkt, response.data): # Got match
436 break
Rich Lane477f4812012-10-04 22:49:00 -0700437 if not config["relax"]: # Only one attempt to match
Ken Chiang899ff8e2012-05-23 18:26:12 -0700438 break
439 count += 1
440 if count > 10: # Too many tries
441 break
442
443 self.assertTrue(response is not None,
444 'Packet in message not received by controller')
445 if not dataplane.match_exp_pkt(pkt, response.data):
Rich Lane9a003812012-10-04 17:17:59 -0700446 logging.debug("Sent %s" % format_packet(pkt))
447 logging.debug("Resp %s" % format_packet(response.data))
Ken Chiang899ff8e2012-05-23 18:26:12 -0700448 self.assertTrue(False,
449 'Response packet does not match send packet' +
450 ' for controller port')
451
452 # FIXME: instead of sleeping, keep requesting queue stats until
453 # the expected queue counter increases or some large timeout is
454 # reached
455 time.sleep(2)
456
457 # Get current stats for selected egress queue again
458
459 request = message.queue_stats_request()
460 request.port_no = egress_port
461 request.queue_id = egress_queue_id
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700462 (qs_after, p) = self.controller.transact(request)
Ken Chiang899ff8e2012-05-23 18:26:12 -0700463 self.assertNotEqual(qs_after, None, "Queue stats request failed")
464
465 # Make sure that tx packet counter for selected egress queue was
466 # incremented
467
468 self.assertEqual(qs_after.stats[0].tx_packets, \
469 qs_before.stats[0].tx_packets + 1, \
470 "Verification of egress queue tx packet count failed"
471 )
472
Howard Pershf97840f2012-04-10 16:30:42 -0700473
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700474class DirectPacketICMP(DirectPacket):
475 """
476 Send ICMP packet to single egress port
477
478 Generate a ICMP packet
479 Generate and install a matching flow
480 Add action to direct the packet to an egress port
481 Send the packet to ingress dataplane port
482 Verify the packet is received at the egress port only
483 Difference from DirectPacket test is that sent packet is ICMP
484 """
485 def runTest(self):
486 self.handleFlow(pkttype='ICMP')
Dan Talayco2d0d49a2010-05-11 15:29:08 -0700487
Rich Laneb90a1c42012-10-05 09:16:05 -0700488class DirectTwoPorts(base_tests.SimpleDataPlane):
Dan Talayco2d0d49a2010-05-11 15:29:08 -0700489 """
490 Send packet to two egress ports
491
492 Generate a packet
493 Generate and install a matching flow
494 Add action to direct the packet to two egress ports
495 Send the packet to ingress dataplane port
496 Verify the packet is received at the two egress ports
497 """
498 def runTest(self):
Rich Lane477f4812012-10-04 22:49:00 -0700499 of_ports = config["port_map"].keys()
Dan Talayco2d0d49a2010-05-11 15:29:08 -0700500 of_ports.sort()
501 self.assertTrue(len(of_ports) > 2, "Not enough ports for test")
502
Dan Talayco2d0d49a2010-05-11 15:29:08 -0700503 pkt = simple_tcp_packet()
Ed Swierk99a74de2012-08-22 06:40:54 -0700504 match = packet_to_flow_match(self, pkt)
Dan Talayco2d0d49a2010-05-11 15:29:08 -0700505 match.wildcards &= ~ofp.OFPFW_IN_PORT
506 self.assertTrue(match is not None,
507 "Could not generate flow match from pkt")
508 act = action.action_output()
509
510 for idx in range(len(of_ports)):
Rich Lane9a003812012-10-04 17:17:59 -0700511 rv = delete_all_flows(self.controller)
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700512 self.assertEqual(rv, 0, "Failed to delete all flows")
Dan Talayco2e77a842010-05-12 15:39:46 -0700513
Dan Talayco2d0d49a2010-05-11 15:29:08 -0700514 ingress_port = of_ports[idx]
515 egress_port1 = of_ports[(idx + 1) % len(of_ports)]
516 egress_port2 = of_ports[(idx + 2) % len(of_ports)]
Rich Lane9a003812012-10-04 17:17:59 -0700517 logging.info("Ingress " + str(ingress_port) +
Dan Talayco2d0d49a2010-05-11 15:29:08 -0700518 " to egress " + str(egress_port1) + " and " +
519 str(egress_port2))
520
521 match.in_port = ingress_port
522
523 request = message.flow_mod()
524 request.match = match
525 request.buffer_id = 0xffffffff
526 act.port = egress_port1
527 self.assertTrue(request.actions.add(act), "Could not add action1")
528 act.port = egress_port2
529 self.assertTrue(request.actions.add(act), "Could not add action2")
Rich Lane9a003812012-10-04 17:17:59 -0700530 # logging.info(request.show())
Dan Talayco2d0d49a2010-05-11 15:29:08 -0700531
Rich Lane9a003812012-10-04 17:17:59 -0700532 logging.info("Inserting flow")
Dan Talayco2d0d49a2010-05-11 15:29:08 -0700533 rv = self.controller.message_send(request)
534 self.assertTrue(rv != -1, "Error installing flow mod")
Dan Talayco0fc08bd2012-04-09 16:56:18 -0700535 self.assertEqual(do_barrier(self.controller), 0, "Barrier failed")
Dan Talayco2d0d49a2010-05-11 15:29:08 -0700536
Rich Lane9a003812012-10-04 17:17:59 -0700537 logging.info("Sending packet to dp port " +
Dan Talayco2d0d49a2010-05-11 15:29:08 -0700538 str(ingress_port))
539 self.dataplane.send(ingress_port, str(pkt))
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700540 yes_ports = set([egress_port1, egress_port2])
541 no_ports = set(of_ports).difference(yes_ports)
Dan Talayco2d0d49a2010-05-11 15:29:08 -0700542
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700543 receive_pkt_check(self.dataplane, pkt, yes_ports, no_ports,
Rich Lane2014f9b2012-10-05 15:29:40 -0700544 self)
Dan Talaycob0b0fdb2010-05-11 15:44:56 -0700545
Rich Laneb90a1c42012-10-05 09:16:05 -0700546class DirectMCNonIngress(base_tests.SimpleDataPlane):
Dan Talaycob0b0fdb2010-05-11 15:44:56 -0700547 """
548 Multicast to all non-ingress ports
549
550 Generate a packet
551 Generate and install a matching flow
552 Add action to direct the packet to all non-ingress ports
553 Send the packet to ingress dataplane port
554 Verify the packet is received at all non-ingress ports
555
556 Does not use the flood action
557 """
558 def runTest(self):
Rich Lane477f4812012-10-04 22:49:00 -0700559 of_ports = config["port_map"].keys()
Dan Talaycob0b0fdb2010-05-11 15:44:56 -0700560 of_ports.sort()
561 self.assertTrue(len(of_ports) > 2, "Not enough ports for test")
562
Dan Talaycob0b0fdb2010-05-11 15:44:56 -0700563 pkt = simple_tcp_packet()
Ed Swierk99a74de2012-08-22 06:40:54 -0700564 match = packet_to_flow_match(self, pkt)
Dan Talaycob0b0fdb2010-05-11 15:44:56 -0700565 match.wildcards &= ~ofp.OFPFW_IN_PORT
566 self.assertTrue(match is not None,
567 "Could not generate flow match from pkt")
568 act = action.action_output()
569
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700570 for ingress_port in of_ports:
Rich Lane9a003812012-10-04 17:17:59 -0700571 rv = delete_all_flows(self.controller)
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700572 self.assertEqual(rv, 0, "Failed to delete all flows")
Dan Talayco2e77a842010-05-12 15:39:46 -0700573
Rich Lane9a003812012-10-04 17:17:59 -0700574 logging.info("Ingress " + str(ingress_port) +
Dan Talaycob0b0fdb2010-05-11 15:44:56 -0700575 " all non-ingress ports")
Dan Talaycob0b0fdb2010-05-11 15:44:56 -0700576 match.in_port = ingress_port
577
578 request = message.flow_mod()
579 request.match = match
580 request.buffer_id = 0xffffffff
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700581 for egress_port in of_ports:
582 if egress_port == ingress_port:
Dan Talaycob0b0fdb2010-05-11 15:44:56 -0700583 continue
Dan Talaycob0b0fdb2010-05-11 15:44:56 -0700584 act.port = egress_port
585 self.assertTrue(request.actions.add(act),
586 "Could not add output to " + str(egress_port))
Rich Lane9a003812012-10-04 17:17:59 -0700587 logging.debug(request.show())
Dan Talaycob0b0fdb2010-05-11 15:44:56 -0700588
Rich Lane9a003812012-10-04 17:17:59 -0700589 logging.info("Inserting flow")
Dan Talaycob0b0fdb2010-05-11 15:44:56 -0700590 rv = self.controller.message_send(request)
591 self.assertTrue(rv != -1, "Error installing flow mod")
Dan Talayco0fc08bd2012-04-09 16:56:18 -0700592 self.assertEqual(do_barrier(self.controller), 0, "Barrier failed")
Dan Talaycob0b0fdb2010-05-11 15:44:56 -0700593
Rich Lane9a003812012-10-04 17:17:59 -0700594 logging.info("Sending packet to dp port " + str(ingress_port))
Dan Talaycob0b0fdb2010-05-11 15:44:56 -0700595 self.dataplane.send(ingress_port, str(pkt))
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700596 yes_ports = set(of_ports).difference([ingress_port])
597 receive_pkt_check(self.dataplane, pkt, yes_ports, [ingress_port],
Rich Lane2014f9b2012-10-05 15:29:40 -0700598 self)
Dan Talaycob0b0fdb2010-05-11 15:44:56 -0700599
Dan Talayco32fa6542010-05-11 15:54:08 -0700600
Rich Laneb90a1c42012-10-05 09:16:05 -0700601class DirectMC(base_tests.SimpleDataPlane):
Dan Talayco32fa6542010-05-11 15:54:08 -0700602 """
603 Multicast to all ports including ingress
604
605 Generate a packet
606 Generate and install a matching flow
607 Add action to direct the packet to all non-ingress ports
608 Send the packet to ingress dataplane port
609 Verify the packet is received at all ports
610
611 Does not use the flood action
612 """
613 def runTest(self):
Rich Lane477f4812012-10-04 22:49:00 -0700614 of_ports = config["port_map"].keys()
Dan Talayco32fa6542010-05-11 15:54:08 -0700615 of_ports.sort()
616 self.assertTrue(len(of_ports) > 2, "Not enough ports for test")
617
Dan Talayco32fa6542010-05-11 15:54:08 -0700618 pkt = simple_tcp_packet()
Ed Swierk99a74de2012-08-22 06:40:54 -0700619 match = packet_to_flow_match(self, pkt)
Dan Talayco32fa6542010-05-11 15:54:08 -0700620 match.wildcards &= ~ofp.OFPFW_IN_PORT
621 self.assertTrue(match is not None,
622 "Could not generate flow match from pkt")
623 act = action.action_output()
624
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700625 for ingress_port in of_ports:
Rich Lane9a003812012-10-04 17:17:59 -0700626 rv = delete_all_flows(self.controller)
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700627 self.assertEqual(rv, 0, "Failed to delete all flows")
Dan Talayco2e77a842010-05-12 15:39:46 -0700628
Rich Lane9a003812012-10-04 17:17:59 -0700629 logging.info("Ingress " + str(ingress_port) + " to all ports")
Dan Talayco32fa6542010-05-11 15:54:08 -0700630 match.in_port = ingress_port
631
632 request = message.flow_mod()
633 request.match = match
634 request.buffer_id = 0xffffffff
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700635 for egress_port in of_ports:
636 if egress_port == ingress_port:
Dan Talayco32fa6542010-05-11 15:54:08 -0700637 act.port = ofp.OFPP_IN_PORT
638 else:
639 act.port = egress_port
640 self.assertTrue(request.actions.add(act),
641 "Could not add output to " + str(egress_port))
Rich Lane9a003812012-10-04 17:17:59 -0700642 # logging.info(request.show())
Dan Talayco2e77a842010-05-12 15:39:46 -0700643
Rich Lane9a003812012-10-04 17:17:59 -0700644 logging.info("Inserting flow")
Dan Talayco2e77a842010-05-12 15:39:46 -0700645 rv = self.controller.message_send(request)
646 self.assertTrue(rv != -1, "Error installing flow mod")
Dan Talayco0fc08bd2012-04-09 16:56:18 -0700647 self.assertEqual(do_barrier(self.controller), 0, "Barrier failed")
Dan Talayco2e77a842010-05-12 15:39:46 -0700648
Rich Lane9a003812012-10-04 17:17:59 -0700649 logging.info("Sending packet to dp port " + str(ingress_port))
Dan Talayco2e77a842010-05-12 15:39:46 -0700650 self.dataplane.send(ingress_port, str(pkt))
Rich Lane2014f9b2012-10-05 15:29:40 -0700651 receive_pkt_check(self.dataplane, pkt, of_ports, [], self)
Dan Talayco2e77a842010-05-12 15:39:46 -0700652
Rich Laneb90a1c42012-10-05 09:16:05 -0700653class Flood(base_tests.SimpleDataPlane):
Dan Talayco2e77a842010-05-12 15:39:46 -0700654 """
655 Flood to all ports except ingress
656
657 Generate a packet
658 Generate and install a matching flow
659 Add action to flood the packet
660 Send the packet to ingress dataplane port
661 Verify the packet is received at all other ports
662 """
663 def runTest(self):
Rich Lane477f4812012-10-04 22:49:00 -0700664 of_ports = config["port_map"].keys()
Dan Talayco2e77a842010-05-12 15:39:46 -0700665 of_ports.sort()
666 self.assertTrue(len(of_ports) > 1, "Not enough ports for test")
667
668 pkt = simple_tcp_packet()
Ed Swierk99a74de2012-08-22 06:40:54 -0700669 match = packet_to_flow_match(self, pkt)
Dan Talayco2e77a842010-05-12 15:39:46 -0700670 match.wildcards &= ~ofp.OFPFW_IN_PORT
671 self.assertTrue(match is not None,
672 "Could not generate flow match from pkt")
673 act = action.action_output()
674
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700675 for ingress_port in of_ports:
Rich Lane9a003812012-10-04 17:17:59 -0700676 rv = delete_all_flows(self.controller)
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700677 self.assertEqual(rv, 0, "Failed to delete all flows")
Dan Talayco2e77a842010-05-12 15:39:46 -0700678
Rich Lane9a003812012-10-04 17:17:59 -0700679 logging.info("Ingress " + str(ingress_port) + " to all ports")
Dan Talayco2e77a842010-05-12 15:39:46 -0700680 match.in_port = ingress_port
681
682 request = message.flow_mod()
683 request.match = match
684 request.buffer_id = 0xffffffff
685 act.port = ofp.OFPP_FLOOD
686 self.assertTrue(request.actions.add(act),
Dan Talayco4aa13122010-05-12 15:54:44 -0700687 "Could not add flood port action")
Rich Lane9a003812012-10-04 17:17:59 -0700688 logging.info(request.show())
Dan Talayco32fa6542010-05-11 15:54:08 -0700689
Rich Lane9a003812012-10-04 17:17:59 -0700690 logging.info("Inserting flow")
Dan Talayco32fa6542010-05-11 15:54:08 -0700691 rv = self.controller.message_send(request)
692 self.assertTrue(rv != -1, "Error installing flow mod")
Dan Talayco0fc08bd2012-04-09 16:56:18 -0700693 self.assertEqual(do_barrier(self.controller), 0, "Barrier failed")
Dan Talayco32fa6542010-05-11 15:54:08 -0700694
Rich Lane9a003812012-10-04 17:17:59 -0700695 logging.info("Sending packet to dp port " + str(ingress_port))
Dan Talayco32fa6542010-05-11 15:54:08 -0700696 self.dataplane.send(ingress_port, str(pkt))
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700697 yes_ports = set(of_ports).difference([ingress_port])
698 receive_pkt_check(self.dataplane, pkt, yes_ports, [ingress_port],
Rich Lane2014f9b2012-10-05 15:29:40 -0700699 self)
Dan Talayco3be5b062010-05-12 15:46:21 -0700700
Rich Laneb90a1c42012-10-05 09:16:05 -0700701class FloodPlusIngress(base_tests.SimpleDataPlane):
Dan Talayco3be5b062010-05-12 15:46:21 -0700702 """
703 Flood to all ports plus send to ingress port
704
705 Generate a packet
706 Generate and install a matching flow
707 Add action to flood the packet
708 Add action to send to ingress port
709 Send the packet to ingress dataplane port
710 Verify the packet is received at all other ports
711 """
712 def runTest(self):
Rich Lane477f4812012-10-04 22:49:00 -0700713 of_ports = config["port_map"].keys()
Dan Talayco3be5b062010-05-12 15:46:21 -0700714 of_ports.sort()
715 self.assertTrue(len(of_ports) > 1, "Not enough ports for test")
716
717 pkt = simple_tcp_packet()
Ed Swierk99a74de2012-08-22 06:40:54 -0700718 match = packet_to_flow_match(self, pkt)
Dan Talayco3be5b062010-05-12 15:46:21 -0700719 match.wildcards &= ~ofp.OFPFW_IN_PORT
720 self.assertTrue(match is not None,
721 "Could not generate flow match from pkt")
722 act = action.action_output()
723
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700724 for ingress_port in of_ports:
Rich Lane9a003812012-10-04 17:17:59 -0700725 rv = delete_all_flows(self.controller)
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700726 self.assertEqual(rv, 0, "Failed to delete all flows")
Dan Talayco3be5b062010-05-12 15:46:21 -0700727
Rich Lane9a003812012-10-04 17:17:59 -0700728 logging.info("Ingress " + str(ingress_port) + " to all ports")
Dan Talayco3be5b062010-05-12 15:46:21 -0700729 match.in_port = ingress_port
730
731 request = message.flow_mod()
732 request.match = match
733 request.buffer_id = 0xffffffff
734 act.port = ofp.OFPP_FLOOD
735 self.assertTrue(request.actions.add(act),
Dan Talayco4aa13122010-05-12 15:54:44 -0700736 "Could not add flood port action")
737 act.port = ofp.OFPP_IN_PORT
738 self.assertTrue(request.actions.add(act),
739 "Could not add ingress port for output")
Rich Lane9a003812012-10-04 17:17:59 -0700740 logging.info(request.show())
Dan Talayco4aa13122010-05-12 15:54:44 -0700741
Rich Lane9a003812012-10-04 17:17:59 -0700742 logging.info("Inserting flow")
Dan Talayco4aa13122010-05-12 15:54:44 -0700743 rv = self.controller.message_send(request)
744 self.assertTrue(rv != -1, "Error installing flow mod")
Dan Talayco0fc08bd2012-04-09 16:56:18 -0700745 self.assertEqual(do_barrier(self.controller), 0, "Barrier failed")
Dan Talayco4aa13122010-05-12 15:54:44 -0700746
Rich Lane9a003812012-10-04 17:17:59 -0700747 logging.info("Sending packet to dp port " + str(ingress_port))
Dan Talayco4aa13122010-05-12 15:54:44 -0700748 self.dataplane.send(ingress_port, str(pkt))
Rich Lane2014f9b2012-10-05 15:29:40 -0700749 receive_pkt_check(self.dataplane, pkt, of_ports, [], self)
Dan Talayco4aa13122010-05-12 15:54:44 -0700750
Rich Laneb90a1c42012-10-05 09:16:05 -0700751class All(base_tests.SimpleDataPlane):
Dan Talayco4aa13122010-05-12 15:54:44 -0700752 """
753 Send to OFPP_ALL port
754
755 Generate a packet
756 Generate and install a matching flow
757 Add action to forward to OFPP_ALL
758 Send the packet to ingress dataplane port
759 Verify the packet is received at all other ports
760 """
761 def runTest(self):
Rich Lane477f4812012-10-04 22:49:00 -0700762 of_ports = config["port_map"].keys()
Dan Talayco4aa13122010-05-12 15:54:44 -0700763 of_ports.sort()
764 self.assertTrue(len(of_ports) > 1, "Not enough ports for test")
765
766 pkt = simple_tcp_packet()
Ed Swierk99a74de2012-08-22 06:40:54 -0700767 match = packet_to_flow_match(self, pkt)
Dan Talayco4aa13122010-05-12 15:54:44 -0700768 match.wildcards &= ~ofp.OFPFW_IN_PORT
769 self.assertTrue(match is not None,
770 "Could not generate flow match from pkt")
771 act = action.action_output()
772
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700773 for ingress_port in of_ports:
Rich Lane9a003812012-10-04 17:17:59 -0700774 rv = delete_all_flows(self.controller)
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700775 self.assertEqual(rv, 0, "Failed to delete all flows")
Dan Talayco4aa13122010-05-12 15:54:44 -0700776
Rich Lane9a003812012-10-04 17:17:59 -0700777 logging.info("Ingress " + str(ingress_port) + " to all ports")
Dan Talayco4aa13122010-05-12 15:54:44 -0700778 match.in_port = ingress_port
779
780 request = message.flow_mod()
781 request.match = match
782 request.buffer_id = 0xffffffff
783 act.port = ofp.OFPP_ALL
784 self.assertTrue(request.actions.add(act),
785 "Could not add ALL port action")
Rich Lane9a003812012-10-04 17:17:59 -0700786 logging.info(request.show())
Dan Talayco4aa13122010-05-12 15:54:44 -0700787
Rich Lane9a003812012-10-04 17:17:59 -0700788 logging.info("Inserting flow")
Dan Talayco4aa13122010-05-12 15:54:44 -0700789 rv = self.controller.message_send(request)
790 self.assertTrue(rv != -1, "Error installing flow mod")
Dan Talayco0fc08bd2012-04-09 16:56:18 -0700791 self.assertEqual(do_barrier(self.controller), 0, "Barrier failed")
Dan Talayco4aa13122010-05-12 15:54:44 -0700792
Rich Lane9a003812012-10-04 17:17:59 -0700793 logging.info("Sending packet to dp port " + str(ingress_port))
Dan Talayco4aa13122010-05-12 15:54:44 -0700794 self.dataplane.send(ingress_port, str(pkt))
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700795 yes_ports = set(of_ports).difference([ingress_port])
796 receive_pkt_check(self.dataplane, pkt, yes_ports, [ingress_port],
Rich Lane2014f9b2012-10-05 15:29:40 -0700797 self)
Dan Talayco4aa13122010-05-12 15:54:44 -0700798
Rich Laneb90a1c42012-10-05 09:16:05 -0700799class AllPlusIngress(base_tests.SimpleDataPlane):
Dan Talayco4aa13122010-05-12 15:54:44 -0700800 """
801 Send to OFPP_ALL port and ingress port
802
803 Generate a packet
804 Generate and install a matching flow
805 Add action to forward to OFPP_ALL
806 Add action to forward to ingress port
807 Send the packet to ingress dataplane port
808 Verify the packet is received at all other ports
809 """
810 def runTest(self):
Rich Lane477f4812012-10-04 22:49:00 -0700811 of_ports = config["port_map"].keys()
Dan Talayco4aa13122010-05-12 15:54:44 -0700812 of_ports.sort()
813 self.assertTrue(len(of_ports) > 1, "Not enough ports for test")
814
815 pkt = simple_tcp_packet()
Ed Swierk99a74de2012-08-22 06:40:54 -0700816 match = packet_to_flow_match(self, pkt)
Dan Talayco4aa13122010-05-12 15:54:44 -0700817 match.wildcards &= ~ofp.OFPFW_IN_PORT
818 self.assertTrue(match is not None,
819 "Could not generate flow match from pkt")
820 act = action.action_output()
821
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700822 for ingress_port in of_ports:
Rich Lane9a003812012-10-04 17:17:59 -0700823 rv = delete_all_flows(self.controller)
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700824 self.assertEqual(rv, 0, "Failed to delete all flows")
Dan Talayco4aa13122010-05-12 15:54:44 -0700825
Rich Lane9a003812012-10-04 17:17:59 -0700826 logging.info("Ingress " + str(ingress_port) + " to all ports")
Dan Talayco4aa13122010-05-12 15:54:44 -0700827 match.in_port = ingress_port
828
829 request = message.flow_mod()
830 request.match = match
831 request.buffer_id = 0xffffffff
832 act.port = ofp.OFPP_ALL
833 self.assertTrue(request.actions.add(act),
834 "Could not add ALL port action")
Dan Talayco3be5b062010-05-12 15:46:21 -0700835 act.port = ofp.OFPP_IN_PORT
836 self.assertTrue(request.actions.add(act),
837 "Could not add ingress port for output")
Rich Lane9a003812012-10-04 17:17:59 -0700838 logging.info(request.show())
Dan Talayco3be5b062010-05-12 15:46:21 -0700839
Rich Lane9a003812012-10-04 17:17:59 -0700840 logging.info("Inserting flow")
Dan Talayco3be5b062010-05-12 15:46:21 -0700841 rv = self.controller.message_send(request)
842 self.assertTrue(rv != -1, "Error installing flow mod")
Dan Talayco0fc08bd2012-04-09 16:56:18 -0700843 self.assertEqual(do_barrier(self.controller), 0, "Barrier failed")
Dan Talayco3be5b062010-05-12 15:46:21 -0700844
Rich Lane9a003812012-10-04 17:17:59 -0700845 logging.info("Sending packet to dp port " + str(ingress_port))
Dan Talayco3be5b062010-05-12 15:46:21 -0700846 self.dataplane.send(ingress_port, str(pkt))
Rich Lane2014f9b2012-10-05 15:29:40 -0700847 receive_pkt_check(self.dataplane, pkt, of_ports, [], self)
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700848
Rich Laneb90a1c42012-10-05 09:16:05 -0700849class FloodMinusPort(base_tests.SimpleDataPlane):
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700850 """
851 Config port with No_Flood and test Flood action
852
853 Generate a packet
854 Generate a matching flow
855 Add action to forward to OFPP_ALL
856 Set port to no-flood
857 Send the packet to ingress dataplane port
858 Verify the packet is received at all other ports except
859 the ingress port and the no_flood port
860 """
861 def runTest(self):
Rich Lane477f4812012-10-04 22:49:00 -0700862 of_ports = config["port_map"].keys()
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700863 of_ports.sort()
864 self.assertTrue(len(of_ports) > 2, "Not enough ports for test")
865
866 pkt = simple_tcp_packet()
Ed Swierk99a74de2012-08-22 06:40:54 -0700867 match = packet_to_flow_match(self, pkt)
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700868 match.wildcards &= ~ofp.OFPFW_IN_PORT
869 self.assertTrue(match is not None,
870 "Could not generate flow match from pkt")
871 act = action.action_output()
872
Rich Lane4b9e38c2012-12-06 16:33:20 -0800873 # Clear OFPPC_NO_FLOOD on each port
874 for of_port in of_ports:
875 rv = port_config_set(self.controller, of_port,
876 0, ofp.OFPPC_NO_FLOOD)
877 self.assertEqual(rv, 0, "Failed to set port config")
878
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700879 for idx in range(len(of_ports)):
Rich Lane9a003812012-10-04 17:17:59 -0700880 rv = delete_all_flows(self.controller)
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700881 self.assertEqual(rv, 0, "Failed to delete all flows")
882
883 ingress_port = of_ports[idx]
884 no_flood_idx = (idx + 1) % len(of_ports)
885 no_flood_port = of_ports[no_flood_idx]
886 rv = port_config_set(self.controller, no_flood_port,
Rich Lane9a003812012-10-04 17:17:59 -0700887 ofp.OFPPC_NO_FLOOD, ofp.OFPPC_NO_FLOOD)
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700888 self.assertEqual(rv, 0, "Failed to set port config")
889
890 match.in_port = ingress_port
891
892 request = message.flow_mod()
893 request.match = match
894 request.buffer_id = 0xffffffff
895 act.port = ofp.OFPP_FLOOD
896 self.assertTrue(request.actions.add(act),
897 "Could not add flood port action")
Rich Lane9a003812012-10-04 17:17:59 -0700898 logging.info(request.show())
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700899
Rich Lane9a003812012-10-04 17:17:59 -0700900 logging.info("Inserting flow")
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700901 rv = self.controller.message_send(request)
902 self.assertTrue(rv != -1, "Error installing flow mod")
Dan Talayco0fc08bd2012-04-09 16:56:18 -0700903 self.assertEqual(do_barrier(self.controller), 0, "Barrier failed")
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700904
Rich Lane9a003812012-10-04 17:17:59 -0700905 logging.info("Sending packet to dp port " + str(ingress_port))
906 logging.info("No flood port is " + str(no_flood_port))
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700907 self.dataplane.send(ingress_port, str(pkt))
908 no_ports = set([ingress_port, no_flood_port])
909 yes_ports = set(of_ports).difference(no_ports)
Rich Lane2014f9b2012-10-05 15:29:40 -0700910 receive_pkt_check(self.dataplane, pkt, yes_ports, no_ports, self)
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700911
912 # Turn no flood off again
913 rv = port_config_set(self.controller, no_flood_port,
Rich Lane9a003812012-10-04 17:17:59 -0700914 0, ofp.OFPPC_NO_FLOOD)
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700915 self.assertEqual(rv, 0, "Failed to reset port config")
Rich Lane4ecc1f42012-12-06 16:35:24 -0800916 self.assertEqual(do_barrier(self.controller), 0, "Barrier failed")
917
918 # Check that packets are now flooded to no_flood_port
919 logging.info("Sending packet to dp port " + str(ingress_port))
920 self.dataplane.send(ingress_port, str(pkt))
921 no_ports = set([ingress_port])
922 yes_ports = set(of_ports).difference(no_ports)
923 receive_pkt_check(self.dataplane, pkt, yes_ports, no_ports, self)
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700924
925 #@todo Should check no other packets received
926
Dan Talayco21381562010-07-17 00:34:47 -0700927
928
Dan Talayco551befa2010-07-15 17:05:32 -0700929################################################################
930
Rich Laneb90a1c42012-10-05 09:16:05 -0700931class BaseMatchCase(base_tests.SimpleDataPlane):
Dan Talayco551befa2010-07-15 17:05:32 -0700932 def setUp(self):
Rich Laneb90a1c42012-10-05 09:16:05 -0700933 base_tests.SimpleDataPlane.setUp(self)
Dan Talayco551befa2010-07-15 17:05:32 -0700934 def runTest(self):
Rich Lane9a003812012-10-04 17:17:59 -0700935 logging.info("BaseMatchCase")
Dan Talayco551befa2010-07-15 17:05:32 -0700936
937class ExactMatch(BaseMatchCase):
Tatsuya Yabe6a6f38a2010-05-22 23:48:04 -0700938 """
Dan Talayco551befa2010-07-15 17:05:32 -0700939 Exercise exact matching for all port pairs
Tatsuya Yabe6a6f38a2010-05-22 23:48:04 -0700940
941 Generate a packet
942 Generate and install a matching flow without wildcard mask
943 Add action to forward to a port
944 Send the packet to the port
945 Verify the packet is received at all other ports (one port at a time)
Tatsuya Yabe6a6f38a2010-05-22 23:48:04 -0700946 """
Tatsuya Yabe0718ad32010-05-24 15:22:10 -0700947
Tatsuya Yabe6a6f38a2010-05-22 23:48:04 -0700948 def runTest(self):
Rich Lane477f4812012-10-04 22:49:00 -0700949 flow_match_test(self, config["port_map"])
Tatsuya Yabe6a6f38a2010-05-22 23:48:04 -0700950
Dan Talayco551befa2010-07-15 17:05:32 -0700951class ExactMatchTagged(BaseMatchCase):
952 """
953 Exact match for all port pairs with tagged pkts
954 """
Tatsuya Yabe6a6f38a2010-05-22 23:48:04 -0700955
Dan Talayco551befa2010-07-15 17:05:32 -0700956 def runTest(self):
Rich Lane2014f9b2012-10-05 15:29:40 -0700957 vid = test_param_get('vid', default=TEST_VID_DEFAULT)
Rich Lane477f4812012-10-04 22:49:00 -0700958 flow_match_test(self, config["port_map"], dl_vlan=vid)
Tatsuya Yabe6a6f38a2010-05-22 23:48:04 -0700959
Dan Talayco551befa2010-07-15 17:05:32 -0700960class ExactMatchTaggedMany(BaseMatchCase):
961 """
962 ExactMatchTagged with many VLANS
963 """
Tatsuya Yabe6a6f38a2010-05-22 23:48:04 -0700964
Rich Laned1d9c282012-10-04 22:07:10 -0700965 priority = -1
966
Dan Talayco551befa2010-07-15 17:05:32 -0700967 def runTest(self):
Dan Talayco21381562010-07-17 00:34:47 -0700968 for vid in range(2,100,10):
Rich Lane477f4812012-10-04 22:49:00 -0700969 flow_match_test(self, config["port_map"], dl_vlan=vid, max_test=5)
Dan Talayco551befa2010-07-15 17:05:32 -0700970 for vid in range(100,4000,389):
Rich Lane477f4812012-10-04 22:49:00 -0700971 flow_match_test(self, config["port_map"], dl_vlan=vid, max_test=5)
972 flow_match_test(self, config["port_map"], dl_vlan=4094, max_test=5)
Tatsuya Yabecdf575e2010-05-25 16:56:38 -0700973
Jeffrey Townsend2a300e42012-03-28 17:24:02 -0700974class SingleWildcardMatchPriority(BaseMatchCase):
Jeffrey Townsend50c82462012-03-28 18:26:14 -0700975 """
976 SingleWildcardMatchPriority
977 """
Jeffrey Townsend2a300e42012-03-28 17:24:02 -0700978
Jeffrey Townsend50c82462012-03-28 18:26:14 -0700979 def _Init(self):
Jeffrey Townsend2a300e42012-03-28 17:24:02 -0700980 self.pkt = simple_tcp_packet()
981 self.flowMsgs = {}
982
Jeffrey Townsend50c82462012-03-28 18:26:14 -0700983 def _ClearTable(self):
Rich Lane9a003812012-10-04 17:17:59 -0700984 rc = delete_all_flows(self.controller)
Jeffrey Townsend50c82462012-03-28 18:26:14 -0700985 self.assertEqual(rc, 0, "Failed to delete all flows")
Dan Talayco0fc08bd2012-04-09 16:56:18 -0700986 self.assertEqual(do_barrier(self.controller), 0, "Barrier failed")
Jeffrey Townsend50c82462012-03-28 18:26:14 -0700987
988 def runTest(self):
989
990 self._Init()
Rich Lane477f4812012-10-04 22:49:00 -0700991 of_ports = config["port_map"].keys()
Jeffrey Townsend2a300e42012-03-28 17:24:02 -0700992 of_ports.sort()
993
994 # Delete the initial flow table
Jeffrey Townsend50c82462012-03-28 18:26:14 -0700995 self._ClearTable()
Jeffrey Townsend2a300e42012-03-28 17:24:02 -0700996
997 # Run several combinations, each at lower priority settings.
998 # At the end of each call to runPrioFlows(), the table should
999 # be empty. If its not, we'll catch it as the priorities decreases
1000 portA = of_ports[0]
1001 portB = of_ports[1]
1002 portC = of_ports[2]
1003
1004 # TODO -- these priority numbers should be validated somehow?
1005 self.runPrioFlows(portA, portB, portC, 1000, 999)
1006 self.runPrioFlows(portB, portC, portA, 998, 997)
1007 self.runPrioFlows(portC, portA, portB, 996, 995)
1008 self.runPrioFlows(portA, portC, portB, 994, 993)
1009
1010
Jeffrey Townsend50c82462012-03-28 18:26:14 -07001011
1012 def runPrioFlows(self, portA, portB, portC, prioHigher, prioLower,
1013 clearTable=False):
Jeffrey Townsend2a300e42012-03-28 17:24:02 -07001014
Jeffrey Townsend50c82462012-03-28 18:26:14 -07001015 if clearTable:
1016 self._ClearTable()
Jeffrey Townsend2a300e42012-03-28 17:24:02 -07001017
1018 # Sanity check flow at lower priority from pA to pB
Rich Lane9a003812012-10-04 17:17:59 -07001019 logging.info("runPrioFlows(pA=%d,pB=%d,pC=%d,ph=%d,pl=%d"
Jeffrey Townsend2a300e42012-03-28 17:24:02 -07001020 % (portA, portB, portC, prioHigher, prioLower))
1021
Jeffrey Townsend2a300e42012-03-28 17:24:02 -07001022 # Sanity check flow at lower priority from pA to pC
1023 self.installFlow(prioLower, portA, portC)
1024 self.verifyFlow(portA, portC)
1025 self.removeFlow(prioLower)
1026
1027 # Install and verify pA->pB @ prioLower
1028 self.installFlow(prioLower, portA, portB)
1029 self.verifyFlow(portA, portB)
1030
1031 # Install and verify pA->pC @ prioHigher, should override pA->pB
1032 self.installFlow(prioHigher, portA, portC)
1033 self.verifyFlow(portA, portC)
1034 # remove pA->pC
1035 self.removeFlow(prioHigher)
Jeffrey Townsend2a300e42012-03-28 17:24:02 -07001036 # Old flow pA -> pB @ prioLower should still be active
1037 self.verifyFlow(portA, portB)
1038 self.removeFlow(prioLower)
1039
1040 # Table should be empty at this point, leave it alone as
1041 # an assumption for future test runs
1042
1043
1044
Ed Swierk99a74de2012-08-22 06:40:54 -07001045 def installFlow(self, prio, inp, egp,
Jeffrey Townsend8364b162012-04-12 13:45:40 -07001046 wildcards=ofp.OFPFW_DL_SRC):
Ed Swierk99a74de2012-08-22 06:40:54 -07001047 wildcards |= required_wildcards(self)
Jeffrey Townsend2a300e42012-03-28 17:24:02 -07001048 request = flow_msg_create(self, self.pkt, ing_port=inp,
Jeffrey Townsend8364b162012-04-12 13:45:40 -07001049 wildcards=wildcards,
Jeffrey Townsend2a300e42012-03-28 17:24:02 -07001050 egr_ports=egp)
1051 request.priority = prio
Rich Lane9a003812012-10-04 17:17:59 -07001052 logging.debug("Install flow with priority " + str(prio))
Jeffrey Townsend50c82462012-03-28 18:26:14 -07001053 flow_msg_install(self, request, clear_table_override=False)
Jeffrey Townsend2a300e42012-03-28 17:24:02 -07001054 self.flowMsgs[prio] = request
1055
1056 def removeFlow(self, prio):
1057 if self.flowMsgs.has_key(prio):
1058 msg = self.flowMsgs[prio]
1059 msg.command = ofp.OFPFC_DELETE_STRICT
1060 # This *must* be set for DELETE
1061 msg.out_port = ofp.OFPP_NONE
Rich Lane9a003812012-10-04 17:17:59 -07001062 logging.debug("Remove flow with priority " + str(prio))
Jeffrey Townsend2a300e42012-03-28 17:24:02 -07001063 self.controller.message_send(msg)
Dan Talayco0fc08bd2012-04-09 16:56:18 -07001064 self.assertEqual(do_barrier(self.controller), 0, "Barrier failed")
Jeffrey Townsend50c82462012-03-28 18:26:14 -07001065 else:
1066 raise Exception("Not initialized")
Jeffrey Townsend2a300e42012-03-28 17:24:02 -07001067
1068
Jeffrey Townsend8364b162012-04-12 13:45:40 -07001069 def verifyFlow(self, inp, egp, pkt=None):
1070 if pkt == None:
1071 pkt = self.pkt
1072
Rich Lane9a003812012-10-04 17:17:59 -07001073 logging.info("Pkt match test: " + str(inp) + " to " + str(egp))
1074 logging.debug("Send packet: " + str(inp) + " to " + str(egp))
Jeffrey Townsend8364b162012-04-12 13:45:40 -07001075 self.dataplane.send(inp, str(pkt))
1076 receive_pkt_verify(self, egp, pkt, inp)
Jeffrey Townsend2a300e42012-03-28 17:24:02 -07001077
1078
1079
Jeffrey Townsend50c82462012-03-28 18:26:14 -07001080class SingleWildcardMatchPriorityInsertModifyDelete(SingleWildcardMatchPriority):
1081
1082 def runTest(self):
1083
1084 self._Init()
1085
Rich Lane477f4812012-10-04 22:49:00 -07001086 of_ports = config["port_map"].keys()
Jeffrey Townsend50c82462012-03-28 18:26:14 -07001087 of_ports.sort()
1088
1089 # Install an entry from 0 -> 1 @ prio 1000
1090 self._ClearTable()
1091 self.installFlow(1000, of_ports[0], of_ports[1])
1092 self.verifyFlow(of_ports[0], of_ports[1])
1093 self.installFlow(1000, of_ports[1], of_ports[0])
1094 self.verifyFlow(of_ports[1], of_ports[0])
1095 self.installFlow(1001, of_ports[0], of_ports[1])
1096 self.verifyFlow(of_ports[0], of_ports[1])
1097 self.installFlow(1001, of_ports[1], of_ports[0])
1098 self.verifyFlow(of_ports[1], of_ports[0])
1099 self.removeFlow(1001)
1100 self.verifyFlow(of_ports[0], of_ports[1])
1101 self.removeFlow(1000)
1102
1103
1104
Jeffrey Townsend8364b162012-04-12 13:45:40 -07001105class WildcardPriority(SingleWildcardMatchPriority):
Ken Chiang38d7a152012-05-24 15:33:50 -07001106 """
1107 1. Add wildcard flow, verify packet received.
Rich Lane0a78fbd2012-12-31 16:25:04 -08001108 2. Add wildcard flow with higher priority, verify packet received
Ken Chiang38d7a152012-05-24 15:33:50 -07001109 on port specified by this flow.
Rich Lane0a78fbd2012-12-31 16:25:04 -08001110 3. Add wildcard flow with lower priority, verify packet received
Rich Laneb8392082012-11-21 15:52:54 -08001111 on port specified by the highest priority flow.
Ken Chiang38d7a152012-05-24 15:33:50 -07001112 """
Jeffrey Townsend8364b162012-04-12 13:45:40 -07001113
1114 def runTest(self):
Jeffrey Townsend50c82462012-03-28 18:26:14 -07001115
Jeffrey Townsend8364b162012-04-12 13:45:40 -07001116 self._Init()
1117
Rich Lane477f4812012-10-04 22:49:00 -07001118 of_ports = config["port_map"].keys()
Jeffrey Townsend8364b162012-04-12 13:45:40 -07001119 of_ports.sort()
1120
1121 self._ClearTable()
Ken Chiang38d7a152012-05-24 15:33:50 -07001122
1123 # Install a flow with wildcards
1124 self.installFlow(999, of_ports[0], of_ports[1],
1125 wildcards=ofp.OFPFW_DL_DST)
Jeffrey Townsend8364b162012-04-12 13:45:40 -07001126 self.verifyFlow(of_ports[0], of_ports[1])
Rich Lane0a78fbd2012-12-31 16:25:04 -08001127 # Install a flow with wildcards with higher priority
1128 self.installFlow(1000, of_ports[0], of_ports[2],
1129 wildcards=ofp.OFPFW_DL_DST)
Jeffrey Townsend8364b162012-04-12 13:45:40 -07001130 self.verifyFlow(of_ports[0], of_ports[2])
Rich Lane0a78fbd2012-12-31 16:25:04 -08001131 # Install a flow with wildcards with lower priority
Rich Laneb8392082012-11-21 15:52:54 -08001132 self.installFlow(999, of_ports[0], of_ports[1],
1133 wildcards=ofp.OFPFW_DL_SRC)
Rich Lane0a78fbd2012-12-31 16:25:04 -08001134 self.verifyFlow(of_ports[0], of_ports[2])
Jeffrey Townsend8364b162012-04-12 13:45:40 -07001135
1136
Ken Chiang3978f242012-06-13 14:14:09 -07001137class WildcardPriorityWithDelete(SingleWildcardMatchPriority):
Ken Chiang38d7a152012-05-24 15:33:50 -07001138 """
Rich Lane0a78fbd2012-12-31 16:25:04 -08001139 1. Add wildcard match flow, verify packet received.
Ken Chiang38d7a152012-05-24 15:33:50 -07001140 2. Add wildcard flow with higher priority, verify packet received on port
1141 specified by this flow.
Rich Lane0a78fbd2012-12-31 16:25:04 -08001142 3. Add wildcard flow with even higher priority, verify packet received
Ken Chiang38d7a152012-05-24 15:33:50 -07001143 on port specified by this flow.
1144 4. Delete lowest priority flow, verify packet received on port specified
1145 by highest priority flow.
1146 5. Delete highest priority flow, verify packet received on port specified
1147 by remaining flow.
1148 """
1149
1150 def runTest(self):
1151
1152 self._Init()
1153
Rich Lane477f4812012-10-04 22:49:00 -07001154 of_ports = config["port_map"].keys()
Ken Chiang38d7a152012-05-24 15:33:50 -07001155 of_ports.sort()
1156
1157 self._ClearTable()
1158
Rich Lane0a78fbd2012-12-31 16:25:04 -08001159 # Install a flow with wildcards
1160 self.installFlow(250, of_ports[0], of_ports[1],
1161 wildcards=ofp.OFPFW_DL_DST)
Ken Chiang38d7a152012-05-24 15:33:50 -07001162 self.verifyFlow(of_ports[0], of_ports[1])
1163 # Install a flow with wildcards of higher priority
1164 self.installFlow(1250, of_ports[0], of_ports[2],
1165 wildcards=ofp.OFPFW_DL_DST)
1166 self.verifyFlow(of_ports[0], of_ports[2])
Rich Lane0a78fbd2012-12-31 16:25:04 -08001167 # Install a flow with wildcards with even higher priority
1168 self.installFlow(2001, of_ports[0], of_ports[3],
1169 wildcards=ofp.OFPFW_DL_DST)
Ken Chiang38d7a152012-05-24 15:33:50 -07001170 self.verifyFlow(of_ports[0], of_ports[3])
1171 # Delete lowest priority flow
1172 self.removeFlow(250)
1173 self.verifyFlow(of_ports[0], of_ports[3])
1174 # Delete highest priority flow
1175 self.removeFlow(2001)
1176 self.verifyFlow(of_ports[0], of_ports[2])
1177
Jeffrey Townsend8364b162012-04-12 13:45:40 -07001178
Dan Talayco551befa2010-07-15 17:05:32 -07001179class SingleWildcardMatch(BaseMatchCase):
Tatsuya Yabe6a6f38a2010-05-22 23:48:04 -07001180 """
1181 Exercise wildcard matching for all ports
1182
1183 Generate a packet
1184 Generate and install a matching flow with wildcard mask
1185 Add action to forward to a port
1186 Send the packet to the port
1187 Verify the packet is received at all other ports (one port at a time)
Tatsuya Yabe0718ad32010-05-24 15:22:10 -07001188 Verify flow_expiration message is correct when command option is set
Tatsuya Yabe6a6f38a2010-05-22 23:48:04 -07001189 """
Tatsuya Yabe0718ad32010-05-24 15:22:10 -07001190 def runTest(self):
Rich Lane2014f9b2012-10-05 15:29:40 -07001191 vid = test_param_get('vid', default=TEST_VID_DEFAULT)
Dan Talayco551befa2010-07-15 17:05:32 -07001192 for wc in WILDCARD_VALUES:
Ed Swierk99a74de2012-08-22 06:40:54 -07001193 wc |= required_wildcards(self)
Dan Talayco4431d542012-03-21 16:42:16 -07001194 if wc & ofp.OFPFW_DL_VLAN:
Ken Chiang5be06dd2012-04-03 10:03:50 -07001195 # Set nonzero VLAN id to avoid sending priority-tagged packet
1196 dl_vlan = vid
Dan Talayco4431d542012-03-21 16:42:16 -07001197 else:
1198 dl_vlan = -1
Rich Lane477f4812012-10-04 22:49:00 -07001199 flow_match_test(self, config["port_map"], wildcards=wc,
Dan Talayco4431d542012-03-21 16:42:16 -07001200 dl_vlan=dl_vlan, max_test=10)
Tatsuya Yabe4fad7e32010-05-24 15:24:50 -07001201
Dan Talayco551befa2010-07-15 17:05:32 -07001202class SingleWildcardMatchTagged(BaseMatchCase):
1203 """
1204 SingleWildcardMatch with tagged packets
1205 """
1206 def runTest(self):
Rich Lane2014f9b2012-10-05 15:29:40 -07001207 vid = test_param_get('vid', default=TEST_VID_DEFAULT)
Dan Talayco551befa2010-07-15 17:05:32 -07001208 for wc in WILDCARD_VALUES:
Ed Swierk99a74de2012-08-22 06:40:54 -07001209 wc |= required_wildcards(self)
Rich Lane477f4812012-10-04 22:49:00 -07001210 flow_match_test(self, config["port_map"], wildcards=wc, dl_vlan=vid,
Dan Talayco551befa2010-07-15 17:05:32 -07001211 max_test=10)
1212
1213class AllExceptOneWildcardMatch(BaseMatchCase):
Tatsuya Yabe4fad7e32010-05-24 15:24:50 -07001214 """
Dan Talayco80b54ed2010-07-13 09:48:35 -07001215 Match exactly one field
Tatsuya Yabe4fad7e32010-05-24 15:24:50 -07001216
1217 Generate a packet
1218 Generate and install a matching flow with wildcard all except one filed
1219 Add action to forward to a port
1220 Send the packet to the port
1221 Verify the packet is received at all other ports (one port at a time)
1222 Verify flow_expiration message is correct when command option is set
1223 """
1224 def runTest(self):
Rich Lane2014f9b2012-10-05 15:29:40 -07001225 vid = test_param_get('vid', default=TEST_VID_DEFAULT)
Dan Talayco488fbc52012-04-09 16:30:41 -07001226 for all_exp_one_wildcard in NO_WILDCARD_VALUES:
Ed Swierk99a74de2012-08-22 06:40:54 -07001227 all_exp_one_wildcard |= required_wildcards(self)
Dan Talayco4431d542012-03-21 16:42:16 -07001228 if all_exp_one_wildcard & ofp.OFPFW_DL_VLAN:
Ken Chiang5be06dd2012-04-03 10:03:50 -07001229 # Set nonzero VLAN id to avoid sending priority-tagged packet
1230 dl_vlan = vid
Dan Talayco4431d542012-03-21 16:42:16 -07001231 else:
1232 dl_vlan = -1
Rich Lane477f4812012-10-04 22:49:00 -07001233 flow_match_test(self, config["port_map"], wildcards=all_exp_one_wildcard,
Dan Talayco4431d542012-03-21 16:42:16 -07001234 dl_vlan=dl_vlan)
Tatsuya Yabee30ebe22010-05-25 09:30:49 -07001235
Dan Talayco551befa2010-07-15 17:05:32 -07001236class AllExceptOneWildcardMatchTagged(BaseMatchCase):
1237 """
1238 Match one field with tagged packets
1239 """
1240 def runTest(self):
Rich Lane2014f9b2012-10-05 15:29:40 -07001241 vid = test_param_get('vid', default=TEST_VID_DEFAULT)
Dan Talayco488fbc52012-04-09 16:30:41 -07001242 for all_exp_one_wildcard in NO_WILDCARD_VALUES:
Ed Swierk99a74de2012-08-22 06:40:54 -07001243 all_exp_one_wildcard |= required_wildcards(self)
Rich Lane477f4812012-10-04 22:49:00 -07001244 flow_match_test(self, config["port_map"], wildcards=all_exp_one_wildcard,
Dan Talayco21381562010-07-17 00:34:47 -07001245 dl_vlan=vid)
Dan Talayco551befa2010-07-15 17:05:32 -07001246
1247class AllWildcardMatch(BaseMatchCase):
Tatsuya Yabee30ebe22010-05-25 09:30:49 -07001248 """
1249 Create Wildcard-all flow and exercise for all ports
1250
1251 Generate a packet
1252 Generate and install a matching flow with wildcard-all
1253 Add action to forward to a port
1254 Send the packet to the port
1255 Verify the packet is received at all other ports (one port at a time)
1256 Verify flow_expiration message is correct when command option is set
1257 """
1258 def runTest(self):
Rich Lane477f4812012-10-04 22:49:00 -07001259 flow_match_test(self, config["port_map"], wildcards=ofp.OFPFW_ALL)
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -07001260
Dan Talayco551befa2010-07-15 17:05:32 -07001261class AllWildcardMatchTagged(BaseMatchCase):
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -07001262 """
Dan Talayco551befa2010-07-15 17:05:32 -07001263 AllWildcardMatch with tagged packets
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -07001264 """
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -07001265 def runTest(self):
Rich Lane2014f9b2012-10-05 15:29:40 -07001266 vid = test_param_get('vid', default=TEST_VID_DEFAULT)
Rich Lane477f4812012-10-04 22:49:00 -07001267 flow_match_test(self, config["port_map"], wildcards=ofp.OFPFW_ALL,
Dan Talayco21381562010-07-17 00:34:47 -07001268 dl_vlan=vid)
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -07001269
Dan Talaycoba3745c2010-07-21 21:51:08 -07001270
Dan Talayco551befa2010-07-15 17:05:32 -07001271class AddVLANTag(BaseMatchCase):
1272 """
1273 Add a VLAN tag to an untagged packet
1274 """
1275 def runTest(self):
1276 new_vid = 2
Ed Swierkc7193a22012-08-22 06:51:02 -07001277 sup_acts = self.supported_actions
Dan Talayco551befa2010-07-15 17:05:32 -07001278 if not(sup_acts & 1<<ofp.OFPAT_SET_VLAN_VID):
Dan Talaycoba3745c2010-07-21 21:51:08 -07001279 skip_message_emit(self, "Add VLAN tag test")
Dan Talaycof36f1082010-07-13 13:57:17 -07001280 return
Tatsuya Yabef5ffb972010-05-26 15:36:33 -07001281
Dan Talayco551befa2010-07-15 17:05:32 -07001282 len = 100
1283 len_w_vid = 104
1284 pkt = simple_tcp_packet(pktlen=len)
1285 exp_pkt = simple_tcp_packet(pktlen=len_w_vid, dl_vlan_enable=True,
1286 dl_vlan=new_vid)
1287 vid_act = action.action_set_vlan_vid()
1288 vid_act.vlan_vid = new_vid
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -07001289
Rich Lane477f4812012-10-04 22:49:00 -07001290 flow_match_test(self, config["port_map"], pkt=pkt,
Dan Talayco551befa2010-07-15 17:05:32 -07001291 exp_pkt=exp_pkt, action_list=[vid_act])
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -07001292
Rich Laneb90a1c42012-10-05 09:16:05 -07001293class PacketOnly(base_tests.DataPlaneOnly):
Dan Talayco551befa2010-07-15 17:05:32 -07001294 """
1295 Just send a packet thru the switch
1296 """
Rich Laned1d9c282012-10-04 22:07:10 -07001297
1298 priority = -1
1299
Dan Talayco551befa2010-07-15 17:05:32 -07001300 def runTest(self):
1301 pkt = simple_tcp_packet()
Rich Lane477f4812012-10-04 22:49:00 -07001302 of_ports = config["port_map"].keys()
Dan Talayco551befa2010-07-15 17:05:32 -07001303 of_ports.sort()
1304 ing_port = of_ports[0]
Rich Lane9a003812012-10-04 17:17:59 -07001305 logging.info("Sending packet to " + str(ing_port))
1306 logging.debug("Data: " + str(pkt).encode('hex'))
Dan Talayco551befa2010-07-15 17:05:32 -07001307 self.dataplane.send(ing_port, str(pkt))
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -07001308
Rich Laneb90a1c42012-10-05 09:16:05 -07001309class PacketOnlyTagged(base_tests.DataPlaneOnly):
Dan Talayco551befa2010-07-15 17:05:32 -07001310 """
1311 Just send a packet thru the switch
1312 """
Rich Laned1d9c282012-10-04 22:07:10 -07001313
1314 priority = -1
1315
Dan Talayco551befa2010-07-15 17:05:32 -07001316 def runTest(self):
Rich Lane2014f9b2012-10-05 15:29:40 -07001317 vid = test_param_get('vid', default=TEST_VID_DEFAULT)
Dan Talayco551befa2010-07-15 17:05:32 -07001318 pkt = simple_tcp_packet(dl_vlan_enable=True, dl_vlan=vid)
Rich Lane477f4812012-10-04 22:49:00 -07001319 of_ports = config["port_map"].keys()
Dan Talayco551befa2010-07-15 17:05:32 -07001320 of_ports.sort()
1321 ing_port = of_ports[0]
Rich Lane9a003812012-10-04 17:17:59 -07001322 logging.info("Sending packet to " + str(ing_port))
1323 logging.debug("Data: " + str(pkt).encode('hex'))
Dan Talayco551befa2010-07-15 17:05:32 -07001324 self.dataplane.send(ing_port, str(pkt))
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -07001325
Dan Talayco551befa2010-07-15 17:05:32 -07001326class ModifyVID(BaseMatchCase):
Dan Talayco4b2bee62010-07-20 14:10:05 -07001327 """
1328 Modify the VLAN ID in the VLAN tag of a tagged packet
1329 """
Dan Talaycoaf669322012-09-12 22:51:22 -07001330 def setUp(self):
1331 BaseMatchCase.setUp(self)
1332 self.ing_port=False
1333
Dan Talayco551befa2010-07-15 17:05:32 -07001334 def runTest(self):
1335 old_vid = 2
1336 new_vid = 3
Ed Swierkc7193a22012-08-22 06:51:02 -07001337 sup_acts = self.supported_actions
Dan Talayco4b2bee62010-07-20 14:10:05 -07001338 if not (sup_acts & 1 << ofp.OFPAT_SET_VLAN_VID):
Dan Talaycoba3745c2010-07-21 21:51:08 -07001339 skip_message_emit(self, "Modify VLAN tag test")
Dan Talayco551befa2010-07-15 17:05:32 -07001340 return
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -07001341
Dan Talayco551befa2010-07-15 17:05:32 -07001342 pkt = simple_tcp_packet(dl_vlan_enable=True, dl_vlan=old_vid)
1343 exp_pkt = simple_tcp_packet(dl_vlan_enable=True, dl_vlan=new_vid)
1344 vid_act = action.action_set_vlan_vid()
1345 vid_act.vlan_vid = new_vid
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -07001346
Rich Lane477f4812012-10-04 22:49:00 -07001347 flow_match_test(self, config["port_map"], pkt=pkt, exp_pkt=exp_pkt,
Dan Talaycoaf669322012-09-12 22:51:22 -07001348 action_list=[vid_act], ing_port=self.ing_port)
1349
1350class ModifyVIDToIngress(ModifyVID):
1351 """
1352 Modify the VLAN ID in the VLAN tag of a tagged packet and send to
1353 ingress port
1354 """
1355 def setUp(self):
1356 BaseMatchCase.setUp(self)
1357 self.ing_port=True
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -07001358
Ken Chiange9a211d2012-04-20 14:52:11 -07001359class ModifyVIDWithTagMatchWildcarded(BaseMatchCase):
1360 """
1361 With vlan ID and priority wildcarded, perform SET_VLAN_VID action.
1362 The same flow should match on both untagged and tagged packets.
1363 """
1364 def runTest(self):
1365 old_vid = 2
1366 new_vid = 3
Ed Swierkc7193a22012-08-22 06:51:02 -07001367 sup_acts = self.supported_actions
Ken Chiange9a211d2012-04-20 14:52:11 -07001368 if not (sup_acts & 1 << ofp.OFPAT_SET_VLAN_VID):
1369 skip_message_emit(self, "ModifyVIDWithTagWildcarded test")
1370 return
1371
Rich Lane477f4812012-10-04 22:49:00 -07001372 of_ports = config["port_map"].keys()
Ken Chiange9a211d2012-04-20 14:52:11 -07001373 self.assertTrue(len(of_ports) > 1, "Not enough ports for test")
1374 ing_port = of_ports[0]
1375 egr_ports = of_ports[1]
1376
Rich Lane9a003812012-10-04 17:17:59 -07001377 rv = delete_all_flows(self.controller)
Ken Chiange9a211d2012-04-20 14:52:11 -07001378 self.assertEqual(rv, 0, "Failed to delete all flows")
1379
1380 len_untagged = 100
1381 len_w_vid = 104
1382 untagged_pkt = simple_tcp_packet(pktlen=len_untagged)
1383 tagged_pkt = simple_tcp_packet(pktlen=len_w_vid,
1384 dl_vlan_enable=True, dl_vlan=old_vid)
1385 exp_pkt = simple_tcp_packet(pktlen=len_w_vid, dl_vlan_enable=True,
1386 dl_vlan=new_vid)
Ed Swierk99a74de2012-08-22 06:40:54 -07001387 wildcards = (required_wildcards(self) | ofp.OFPFW_DL_VLAN |
1388 ofp.OFPFW_DL_VLAN_PCP)
Ken Chiange9a211d2012-04-20 14:52:11 -07001389 vid_act = action.action_set_vlan_vid()
1390 vid_act.vlan_vid = new_vid
1391 request = flow_msg_create(self, untagged_pkt, ing_port=ing_port,
1392 wildcards=wildcards, egr_ports=egr_ports,
1393 action_list=[vid_act])
1394 flow_msg_install(self, request)
1395
Rich Lane9a003812012-10-04 17:17:59 -07001396 logging.debug("Send untagged packet: " + str(ing_port) + " to " +
Ken Chiange9a211d2012-04-20 14:52:11 -07001397 str(egr_ports))
1398 self.dataplane.send(ing_port, str(untagged_pkt))
1399 receive_pkt_verify(self, egr_ports, exp_pkt, ing_port)
1400
Rich Lane9a003812012-10-04 17:17:59 -07001401 logging.debug("Send tagged packet: " + str(ing_port) + " to " +
Ken Chiange9a211d2012-04-20 14:52:11 -07001402 str(egr_ports))
1403 self.dataplane.send(ing_port, str(tagged_pkt))
1404 receive_pkt_verify(self, egr_ports, exp_pkt, ing_port)
1405
Howard Pershc1199d52012-04-11 14:21:32 -07001406class ModifyVlanPcp(BaseMatchCase):
1407 """
1408 Modify the priority field of the VLAN tag of a tagged packet
1409 """
1410 def runTest(self):
1411 vid = 123
1412 old_vlan_pcp = 2
1413 new_vlan_pcp = 3
Ed Swierkc7193a22012-08-22 06:51:02 -07001414 sup_acts = self.supported_actions
Ed Swierk8c3af7f2012-04-24 14:19:17 -07001415 if not (sup_acts & 1 << ofp.OFPAT_SET_VLAN_PCP):
1416 skip_message_emit(self, "Modify VLAN priority test")
Howard Pershc1199d52012-04-11 14:21:32 -07001417 return
1418
1419 pkt = simple_tcp_packet(dl_vlan_enable=True, dl_vlan=vid, dl_vlan_pcp=old_vlan_pcp)
1420 exp_pkt = simple_tcp_packet(dl_vlan_enable=True, dl_vlan=vid, dl_vlan_pcp=new_vlan_pcp)
1421 vid_act = action.action_set_vlan_pcp()
1422 vid_act.vlan_pcp = new_vlan_pcp
1423
Rich Lane477f4812012-10-04 22:49:00 -07001424 flow_match_test(self, config["port_map"], pkt=pkt, exp_pkt=exp_pkt,
Howard Pershc1199d52012-04-11 14:21:32 -07001425 action_list=[vid_act])
1426
Dan Talayco551befa2010-07-15 17:05:32 -07001427class StripVLANTag(BaseMatchCase):
Dan Talayco4b2bee62010-07-20 14:10:05 -07001428 """
1429 Strip the VLAN tag from a tagged packet
1430 """
Dan Talayco551befa2010-07-15 17:05:32 -07001431 def runTest(self):
1432 old_vid = 2
Ed Swierkc7193a22012-08-22 06:51:02 -07001433 sup_acts = self.supported_actions
Dan Talayco4b2bee62010-07-20 14:10:05 -07001434 if not (sup_acts & 1 << ofp.OFPAT_STRIP_VLAN):
Dan Talaycoba3745c2010-07-21 21:51:08 -07001435 skip_message_emit(self, "Strip VLAN tag test")
Dan Talayco551befa2010-07-15 17:05:32 -07001436 return
Dan Talaycof36f1082010-07-13 13:57:17 -07001437
Dan Talayco551befa2010-07-15 17:05:32 -07001438 len_w_vid = 104
1439 len = 100
1440 pkt = simple_tcp_packet(pktlen=len_w_vid, dl_vlan_enable=True,
1441 dl_vlan=old_vid)
1442 exp_pkt = simple_tcp_packet(pktlen=len)
1443 vid_act = action.action_strip_vlan()
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -07001444
Rich Lane477f4812012-10-04 22:49:00 -07001445 flow_match_test(self, config["port_map"], pkt=pkt, exp_pkt=exp_pkt,
Dan Talayco551befa2010-07-15 17:05:32 -07001446 action_list=[vid_act])
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -07001447
Ken Chiange9a211d2012-04-20 14:52:11 -07001448class StripVLANTagWithTagMatchWildcarded(BaseMatchCase):
1449 """
1450 Strip the VLAN tag from a tagged packet.
1451 Differs from StripVLANTag in that VID and PCP are both wildcarded.
1452 """
1453 def runTest(self):
1454 old_vid = 2
Ed Swierkc7193a22012-08-22 06:51:02 -07001455 sup_acts = self.supported_actions
Ken Chiange9a211d2012-04-20 14:52:11 -07001456 if not (sup_acts & 1 << ofp.OFPAT_STRIP_VLAN):
1457 skip_message_emit(self, "StripVLANTagWithTagWildcarded test")
1458 return
1459
1460 len_w_vid = 104
1461 len_untagged = 100
1462 pkt = simple_tcp_packet(pktlen=len_w_vid, dl_vlan_enable=True,
1463 dl_vlan=old_vid)
1464 exp_pkt = simple_tcp_packet(pktlen=len_untagged)
Ed Swierk99a74de2012-08-22 06:40:54 -07001465 wildcards = (required_wildcards(self) | ofp.OFPFW_DL_VLAN |
1466 ofp.OFPFW_DL_VLAN_PCP)
Ken Chiange9a211d2012-04-20 14:52:11 -07001467 vid_act = action.action_strip_vlan()
1468
Rich Lane477f4812012-10-04 22:49:00 -07001469 flow_match_test(self, config["port_map"],
Ed Swierk99a74de2012-08-22 06:40:54 -07001470 wildcards=wildcards,
Ken Chiange9a211d2012-04-20 14:52:11 -07001471 pkt=pkt, exp_pkt=exp_pkt,
1472 action_list=[vid_act])
1473
Dan Talayco4b2bee62010-07-20 14:10:05 -07001474def init_pkt_args():
1475 """
1476 Pass back a dictionary with default packet arguments
1477 """
1478 args = {}
1479 args["dl_src"] = '00:23:45:67:89:AB'
1480
1481 dl_vlan_enable=False
1482 dl_vlan=-1
Rich Lane477f4812012-10-04 22:49:00 -07001483 if config["test-params"]["vid"]:
Dan Talayco4b2bee62010-07-20 14:10:05 -07001484 dl_vlan_enable=True
Rich Lane477f4812012-10-04 22:49:00 -07001485 dl_vlan = config["test-params"]["vid"]
Dan Talayco4b2bee62010-07-20 14:10:05 -07001486
1487# Unpack operator is ** on a dictionary
1488
1489 return args
1490
Dan Talayco551befa2010-07-15 17:05:32 -07001491class ModifyL2Src(BaseMatchCase):
Dan Talayco4b2bee62010-07-20 14:10:05 -07001492 """
1493 Modify the source MAC address (TP1)
1494 """
Dan Talayco551befa2010-07-15 17:05:32 -07001495 def runTest(self):
Ed Swierkc7193a22012-08-22 06:51:02 -07001496 sup_acts = self.supported_actions
Dan Talayco4b2bee62010-07-20 14:10:05 -07001497 if not (sup_acts & 1 << ofp.OFPAT_SET_DL_SRC):
Dan Talaycoba3745c2010-07-21 21:51:08 -07001498 skip_message_emit(self, "ModifyL2Src test")
Dan Talayco4b2bee62010-07-20 14:10:05 -07001499 return
1500
1501 (pkt, exp_pkt, acts) = pkt_action_setup(self, mod_fields=['dl_src'],
1502 check_test_params=True)
Rich Lane477f4812012-10-04 22:49:00 -07001503 flow_match_test(self, config["port_map"], pkt=pkt, exp_pkt=exp_pkt,
Dan Talayco4b2bee62010-07-20 14:10:05 -07001504 action_list=acts, max_test=2)
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -07001505
Dan Talayco551befa2010-07-15 17:05:32 -07001506class ModifyL2Dst(BaseMatchCase):
Dan Talayco4b2bee62010-07-20 14:10:05 -07001507 """
1508 Modify the dest MAC address (TP1)
1509 """
Dan Talayco551befa2010-07-15 17:05:32 -07001510 def runTest(self):
Ed Swierkc7193a22012-08-22 06:51:02 -07001511 sup_acts = self.supported_actions
Dan Talayco4b2bee62010-07-20 14:10:05 -07001512 if not (sup_acts & 1 << ofp.OFPAT_SET_DL_DST):
Dan Talaycoba3745c2010-07-21 21:51:08 -07001513 skip_message_emit(self, "ModifyL2dst test")
Dan Talayco4b2bee62010-07-20 14:10:05 -07001514 return
1515
1516 (pkt, exp_pkt, acts) = pkt_action_setup(self, mod_fields=['dl_dst'],
1517 check_test_params=True)
Rich Lane477f4812012-10-04 22:49:00 -07001518 flow_match_test(self, config["port_map"], pkt=pkt, exp_pkt=exp_pkt,
Dan Talayco4b2bee62010-07-20 14:10:05 -07001519 action_list=acts, max_test=2)
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -07001520
Dan Talayco551befa2010-07-15 17:05:32 -07001521class ModifyL3Src(BaseMatchCase):
Dan Talayco4b2bee62010-07-20 14:10:05 -07001522 """
1523 Modify the source IP address of an IP packet (TP1)
1524 """
Dan Talayco551befa2010-07-15 17:05:32 -07001525 def runTest(self):
Ed Swierkc7193a22012-08-22 06:51:02 -07001526 sup_acts = self.supported_actions
Dan Talayco4b2bee62010-07-20 14:10:05 -07001527 if not (sup_acts & 1 << ofp.OFPAT_SET_NW_SRC):
Dan Talaycoba3745c2010-07-21 21:51:08 -07001528 skip_message_emit(self, "ModifyL3Src test")
Dan Talayco4b2bee62010-07-20 14:10:05 -07001529 return
1530
1531 (pkt, exp_pkt, acts) = pkt_action_setup(self, mod_fields=['ip_src'],
1532 check_test_params=True)
Rich Lane477f4812012-10-04 22:49:00 -07001533 flow_match_test(self, config["port_map"], pkt=pkt, exp_pkt=exp_pkt,
Dan Talayco4b2bee62010-07-20 14:10:05 -07001534 action_list=acts, max_test=2)
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -07001535
Dan Talayco551befa2010-07-15 17:05:32 -07001536class ModifyL3Dst(BaseMatchCase):
Dan Talayco4b2bee62010-07-20 14:10:05 -07001537 """
1538 Modify the dest IP address of an IP packet (TP1)
1539 """
Dan Talayco551befa2010-07-15 17:05:32 -07001540 def runTest(self):
Ed Swierkc7193a22012-08-22 06:51:02 -07001541 sup_acts = self.supported_actions
Dan Talayco4b2bee62010-07-20 14:10:05 -07001542 if not (sup_acts & 1 << ofp.OFPAT_SET_NW_DST):
Dan Talaycoba3745c2010-07-21 21:51:08 -07001543 skip_message_emit(self, "ModifyL3Dst test")
Dan Talayco4b2bee62010-07-20 14:10:05 -07001544 return
1545
1546 (pkt, exp_pkt, acts) = pkt_action_setup(self, mod_fields=['ip_dst'],
1547 check_test_params=True)
Rich Lane477f4812012-10-04 22:49:00 -07001548 flow_match_test(self, config["port_map"], pkt=pkt, exp_pkt=exp_pkt,
Dan Talayco4b2bee62010-07-20 14:10:05 -07001549 action_list=acts, max_test=2)
Dan Talayco551befa2010-07-15 17:05:32 -07001550
1551class ModifyL4Src(BaseMatchCase):
Dan Talayco4b2bee62010-07-20 14:10:05 -07001552 """
1553 Modify the source TCP port of a TCP packet (TP1)
1554 """
Dan Talayco551befa2010-07-15 17:05:32 -07001555 def runTest(self):
Ed Swierkc7193a22012-08-22 06:51:02 -07001556 sup_acts = self.supported_actions
Dan Talayco4b2bee62010-07-20 14:10:05 -07001557 if not (sup_acts & 1 << ofp.OFPAT_SET_TP_SRC):
Dan Talaycoba3745c2010-07-21 21:51:08 -07001558 skip_message_emit(self, "ModifyL4Src test")
Dan Talayco4b2bee62010-07-20 14:10:05 -07001559 return
1560
1561 (pkt, exp_pkt, acts) = pkt_action_setup(self, mod_fields=['tcp_sport'],
1562 check_test_params=True)
Rich Lane477f4812012-10-04 22:49:00 -07001563 flow_match_test(self, config["port_map"], pkt=pkt, exp_pkt=exp_pkt,
Dan Talayco4b2bee62010-07-20 14:10:05 -07001564 action_list=acts, max_test=2)
Dan Talayco551befa2010-07-15 17:05:32 -07001565
Rich Lane01c2b862012-10-26 16:26:25 -07001566class ModifyL4SrcUdp(BaseMatchCase):
1567 """
1568 Modify the source UDP port of a UDP packet
1569 """
1570 def runTest(self):
1571 sup_acts = self.supported_actions
1572 if not (sup_acts & 1 << ofp.OFPAT_SET_TP_DST):
1573 skip_message_emit(self, "ModifyL4SrcUdp test")
1574 return
1575
1576 (pkt, exp_pkt, acts) = pkt_action_setup(self, mod_fields=['udp_sport'],
1577 check_test_params=True, tp="udp")
1578 flow_match_test(self, config["port_map"], pkt=pkt, exp_pkt=exp_pkt,
1579 action_list=acts, max_test=2)
1580
Dan Talayco551befa2010-07-15 17:05:32 -07001581class ModifyL4Dst(BaseMatchCase):
Dan Talayco4b2bee62010-07-20 14:10:05 -07001582 """
1583 Modify the dest TCP port of a TCP packet (TP1)
1584 """
Dan Talayco551befa2010-07-15 17:05:32 -07001585 def runTest(self):
Ed Swierkc7193a22012-08-22 06:51:02 -07001586 sup_acts = self.supported_actions
Dan Talayco4b2bee62010-07-20 14:10:05 -07001587 if not (sup_acts & 1 << ofp.OFPAT_SET_TP_DST):
Dan Talaycoba3745c2010-07-21 21:51:08 -07001588 skip_message_emit(self, "ModifyL4Dst test")
Dan Talayco4b2bee62010-07-20 14:10:05 -07001589 return
1590
1591 (pkt, exp_pkt, acts) = pkt_action_setup(self, mod_fields=['tcp_dport'],
1592 check_test_params=True)
Rich Lane477f4812012-10-04 22:49:00 -07001593 flow_match_test(self, config["port_map"], pkt=pkt, exp_pkt=exp_pkt,
Dan Talayco4b2bee62010-07-20 14:10:05 -07001594 action_list=acts, max_test=2)
Dan Talayco551befa2010-07-15 17:05:32 -07001595
Rich Lane01c2b862012-10-26 16:26:25 -07001596class ModifyL4DstUdp(BaseMatchCase):
1597 """
1598 Modify the dest UDP port of a UDP packet
1599 """
1600 def runTest(self):
1601 sup_acts = self.supported_actions
1602 if not (sup_acts & 1 << ofp.OFPAT_SET_TP_DST):
1603 skip_message_emit(self, "ModifyL4DstUdp test")
1604 return
1605
1606 (pkt, exp_pkt, acts) = pkt_action_setup(self, mod_fields=['udp_dport'],
1607 check_test_params=True, tp="udp")
1608 flow_match_test(self, config["port_map"], pkt=pkt, exp_pkt=exp_pkt,
1609 action_list=acts, max_test=2)
1610
Dan Talayco551befa2010-07-15 17:05:32 -07001611class ModifyTOS(BaseMatchCase):
Dan Talayco4b2bee62010-07-20 14:10:05 -07001612 """
1613 Modify the IP type of service of an IP packet (TP1)
1614 """
Dan Talayco551befa2010-07-15 17:05:32 -07001615 def runTest(self):
Ed Swierkc7193a22012-08-22 06:51:02 -07001616 sup_acts = self.supported_actions
Dan Talayco4b2bee62010-07-20 14:10:05 -07001617 if not (sup_acts & 1 << ofp.OFPAT_SET_NW_TOS):
Dan Talaycoba3745c2010-07-21 21:51:08 -07001618 skip_message_emit(self, "ModifyTOS test")
Dan Talayco4b2bee62010-07-20 14:10:05 -07001619 return
Dan Talayco551befa2010-07-15 17:05:32 -07001620
Dan Talayco4b2bee62010-07-20 14:10:05 -07001621 (pkt, exp_pkt, acts) = pkt_action_setup(self, mod_fields=['ip_tos'],
1622 check_test_params=True)
Rich Lane477f4812012-10-04 22:49:00 -07001623 flow_match_test(self, config["port_map"], pkt=pkt, exp_pkt=exp_pkt,
Dan Talaycocfa172f2012-03-23 12:03:00 -07001624 action_list=acts, max_test=2, egr_count=-1)
Dan Talayco551befa2010-07-15 17:05:32 -07001625
Dan Talaycof6e76c02012-03-23 10:56:12 -07001626class ModifyL2DstMC(BaseMatchCase):
1627 """
1628 Modify the L2 dest and send to 2 ports
Dan Talaycof6e76c02012-03-23 10:56:12 -07001629 """
1630 def runTest(self):
Ed Swierkc7193a22012-08-22 06:51:02 -07001631 sup_acts = self.supported_actions
Dan Talaycof6e76c02012-03-23 10:56:12 -07001632 if not (sup_acts & 1 << ofp.OFPAT_SET_DL_DST):
Dan Talaycocfa172f2012-03-23 12:03:00 -07001633 skip_message_emit(self, "ModifyL2dstMC test")
Dan Talaycof6e76c02012-03-23 10:56:12 -07001634 return
1635
Dan Talaycof6e76c02012-03-23 10:56:12 -07001636 (pkt, exp_pkt, acts) = pkt_action_setup(self, mod_fields=['dl_dst'],
1637 check_test_params=True)
Rich Lane477f4812012-10-04 22:49:00 -07001638 flow_match_test(self, config["port_map"], pkt=pkt, exp_pkt=exp_pkt,
Dan Talaycocfa172f2012-03-23 12:03:00 -07001639 action_list=acts, max_test=2, egr_count=-1)
Dan Talaycof6e76c02012-03-23 10:56:12 -07001640
Dan Talaycoc948d0b2012-03-23 12:17:54 -07001641class ModifyL2DstIngress(BaseMatchCase):
1642 """
1643 Modify the L2 dest and send to the ingress port
1644 """
1645 def runTest(self):
Ed Swierkc7193a22012-08-22 06:51:02 -07001646 sup_acts = self.supported_actions
Dan Talaycoc948d0b2012-03-23 12:17:54 -07001647 if not (sup_acts & 1 << ofp.OFPAT_SET_DL_DST):
Dan Talaycoabbfdbb2012-04-05 10:29:26 -07001648 skip_message_emit(self, "ModifyL2dstIngress test")
Dan Talaycoc948d0b2012-03-23 12:17:54 -07001649 return
1650
1651 (pkt, exp_pkt, acts) = pkt_action_setup(self, mod_fields=['dl_dst'],
1652 check_test_params=True)
Rich Lane477f4812012-10-04 22:49:00 -07001653 flow_match_test(self, config["port_map"], pkt=pkt, exp_pkt=exp_pkt,
Dan Talaycoc948d0b2012-03-23 12:17:54 -07001654 action_list=acts, max_test=2, egr_count=0,
1655 ing_port=True)
1656
Dan Talaycod8ae7582012-03-23 12:24:56 -07001657class ModifyL2DstIngressMC(BaseMatchCase):
1658 """
1659 Modify the L2 dest and send to the ingress port
1660 """
1661 def runTest(self):
Ed Swierkc7193a22012-08-22 06:51:02 -07001662 sup_acts = self.supported_actions
Dan Talaycod8ae7582012-03-23 12:24:56 -07001663 if not (sup_acts & 1 << ofp.OFPAT_SET_DL_DST):
1664 skip_message_emit(self, "ModifyL2dstMC test")
1665 return
1666
1667 (pkt, exp_pkt, acts) = pkt_action_setup(self, mod_fields=['dl_dst'],
1668 check_test_params=True)
Rich Lane477f4812012-10-04 22:49:00 -07001669 flow_match_test(self, config["port_map"], pkt=pkt, exp_pkt=exp_pkt,
Dan Talaycod8ae7582012-03-23 12:24:56 -07001670 action_list=acts, max_test=2, egr_count=-1,
1671 ing_port=True)
1672
Dan Talaycof6e76c02012-03-23 10:56:12 -07001673class ModifyL2SrcMC(BaseMatchCase):
1674 """
1675 Modify the source MAC address (TP1) and send to multiple
Dan Talaycof6e76c02012-03-23 10:56:12 -07001676 """
1677 def runTest(self):
Ed Swierkc7193a22012-08-22 06:51:02 -07001678 sup_acts = self.supported_actions
Dan Talaycof6e76c02012-03-23 10:56:12 -07001679 if not (sup_acts & 1 << ofp.OFPAT_SET_DL_SRC):
Dan Talaycocfa172f2012-03-23 12:03:00 -07001680 skip_message_emit(self, "ModifyL2SrcMC test")
Dan Talaycof6e76c02012-03-23 10:56:12 -07001681 return
1682
Dan Talaycof6e76c02012-03-23 10:56:12 -07001683 (pkt, exp_pkt, acts) = pkt_action_setup(self, mod_fields=['dl_src'],
1684 check_test_params=True)
Rich Lane477f4812012-10-04 22:49:00 -07001685 flow_match_test(self, config["port_map"], pkt=pkt, exp_pkt=exp_pkt,
Dan Talaycocfa172f2012-03-23 12:03:00 -07001686 action_list=acts, max_test=2, egr_count=-1)
Dan Talaycof6e76c02012-03-23 10:56:12 -07001687
1688class ModifyL2SrcDstMC(BaseMatchCase):
1689 """
1690 Modify the L2 source and dest and send to 2 ports
Dan Talaycof6e76c02012-03-23 10:56:12 -07001691 """
1692 def runTest(self):
Ed Swierkc7193a22012-08-22 06:51:02 -07001693 sup_acts = self.supported_actions
Dan Talaycocfa172f2012-03-23 12:03:00 -07001694 if (not (sup_acts & 1 << ofp.OFPAT_SET_DL_DST) or
1695 not (sup_acts & 1 << ofp.OFPAT_SET_DL_SRC)):
1696 skip_message_emit(self, "ModifyL2SrcDstMC test")
Dan Talaycof6e76c02012-03-23 10:56:12 -07001697 return
1698
Dan Talaycof6e76c02012-03-23 10:56:12 -07001699 mod_fields = ['dl_dst', 'dl_src']
1700 (pkt, exp_pkt, acts) = pkt_action_setup(self, mod_fields=mod_fields,
1701 check_test_params=True)
Rich Lane477f4812012-10-04 22:49:00 -07001702 flow_match_test(self, config["port_map"], pkt=pkt, exp_pkt=exp_pkt,
Dan Talaycocfa172f2012-03-23 12:03:00 -07001703 action_list=acts, max_test=2, egr_count=-1)
1704
1705class ModifyL2DstVIDMC(BaseMatchCase):
1706 """
1707 Modify the L2 dest and send to 2 ports
1708 """
1709 def runTest(self):
Ed Swierkc7193a22012-08-22 06:51:02 -07001710 sup_acts = self.supported_actions
Dan Talaycocfa172f2012-03-23 12:03:00 -07001711 if (not (sup_acts & 1 << ofp.OFPAT_SET_DL_DST) or
1712 not (sup_acts & 1 << ofp.OFPAT_SET_VLAN_VID)):
1713 skip_message_emit(self, "ModifyL2DstVIDMC test")
1714 return
1715
1716 mod_fields = ['dl_dst', 'dl_vlan']
1717 (pkt, exp_pkt, acts) = pkt_action_setup(self,
1718 start_field_vals={'dl_vlan_enable':True}, mod_fields=mod_fields,
1719 check_test_params=True)
Rich Lane477f4812012-10-04 22:49:00 -07001720 flow_match_test(self, config["port_map"], pkt=pkt, exp_pkt=exp_pkt,
Dan Talaycocfa172f2012-03-23 12:03:00 -07001721 action_list=acts, max_test=2, egr_count=-1)
Dan Talaycof6e76c02012-03-23 10:56:12 -07001722
Rich Lane22e74c12012-11-12 15:06:06 -08001723class ModifyAll(BaseMatchCase):
1724 """
1725 Modify all supported fields and output to a port
1726 """
1727 def runTest(self):
1728 sup_acts = self.supported_actions
1729
1730 sup_map = {
1731 "dl_dst" : ofp.OFPAT_SET_DL_DST,
1732 "dl_src" : ofp.OFPAT_SET_DL_SRC,
1733 "dl_vlan_enable" : ofp.OFPAT_SET_VLAN_VID,
1734 "dl_vlan" : ofp.OFPAT_SET_VLAN_VID,
1735 "dl_vlan_pcp" : ofp.OFPAT_SET_VLAN_PCP,
1736 "ip_src" : ofp.OFPAT_SET_NW_SRC,
1737 "ip_dst" : ofp.OFPAT_SET_NW_DST,
1738 "ip_tos" : ofp.OFPAT_SET_NW_TOS,
1739 "tcp_sport" : ofp.OFPAT_SET_TP_SRC,
1740 "tcp_dport" : ofp.OFPAT_SET_TP_DST,
1741 }
1742
1743 mod_fields = [field for (field, bit) in sup_map.items() if (sup_acts & 1 << bit)]
1744 random.shuffle(mod_fields)
1745 start_field_vals = { "dl_vlan_enable" : True }
1746 mod_field_vals = { "dl_vlan_enable" : True }
1747 logging.info("modifying fields: %s" % repr(mod_fields))
1748
1749 (pkt, exp_pkt, acts) = pkt_action_setup(self,
1750 mod_fields=mod_fields,
1751 start_field_vals=start_field_vals,
1752 mod_field_vals=mod_field_vals,
1753 check_test_params=True)
1754 flow_match_test(self, config["port_map"], pkt=pkt, exp_pkt=exp_pkt,
1755 action_list=acts, max_test=2)
1756
Dan Talaycofa6454f2012-04-05 10:04:13 -07001757class FlowToggle(BaseMatchCase):
1758 """
1759 Add flows to the table and modify them repeatedly
Dan Talaycof7c41312012-07-23 12:53:19 -07001760
1761 This is done by using only "add" flow messages. Since the check overlap
1762 flag is not set, the switch is supposed to modify the existing flow if
1763 the match already exists.
1764
1765 Would probably be better to exercise more of the flow modify commands
1766 (add, modify, delete +/- strict).
Dan Talaycofa6454f2012-04-05 10:04:13 -07001767 """
1768 def runTest(self):
Rich Lane2014f9b2012-10-05 15:29:40 -07001769 flow_count = test_param_get('ft_flow_count', default=20)
1770 iter_count = test_param_get('ft_iter_count', default=10)
Dan Talaycofa6454f2012-04-05 10:04:13 -07001771
Rich Lane9a003812012-10-04 17:17:59 -07001772 logging.info("Running flow toggle with %d flows, %d iterations" %
Dan Talaycofa6454f2012-04-05 10:04:13 -07001773 (flow_count, iter_count))
1774 acts = []
1775 acts.append(action.action_output())
1776 acts.append(action.action_output())
1777
Rich Lane477f4812012-10-04 22:49:00 -07001778 of_ports = config["port_map"].keys()
Dan Talaycofa6454f2012-04-05 10:04:13 -07001779 if len(of_ports) < 3:
1780 self.assertTrue(False, "Too few ports for test")
1781
1782 for idx in range(2):
1783 acts[idx].port = of_ports[idx]
1784
1785 flows = []
1786 flows.append([])
1787 flows.append([])
1788
Ed Swierk99a74de2012-08-22 06:40:54 -07001789 wildcards = (required_wildcards(self) | ofp.OFPFW_DL_SRC |
1790 ofp.OFPFW_DL_DST)
Dan Talaycofa6454f2012-04-05 10:04:13 -07001791 # Create up the flows in an array
1792 for toggle in range(2):
1793 for f_idx in range(flow_count):
1794 pkt = simple_tcp_packet(tcp_sport=f_idx)
1795 msg = message.flow_mod()
Ed Swierk99a74de2012-08-22 06:40:54 -07001796 match = packet_to_flow_match(self, pkt)
Shudong Zhou031373c2012-07-19 17:37:42 -07001797 match.in_port = of_ports[2]
Dan Talayco50be7672012-04-05 11:38:08 -07001798 match.wildcards = wildcards
Dan Talaycofa6454f2012-04-05 10:04:13 -07001799 msg.match = match
1800 msg.buffer_id = 0xffffffff
Dan Talaycof7c41312012-07-23 12:53:19 -07001801 msg.command = ofp.OFPFC_ADD
Dan Talaycofa6454f2012-04-05 10:04:13 -07001802 msg.actions.add(acts[toggle])
1803 flows[toggle].append(msg)
Dan Talayco50be7672012-04-05 11:38:08 -07001804
1805 # Show two sample flows
Rich Lane9a003812012-10-04 17:17:59 -07001806 logging.debug(flows[0][0].show())
1807 logging.debug(flows[1][0].show())
Dan Talayco50be7672012-04-05 11:38:08 -07001808
Dan Talaycofa6454f2012-04-05 10:04:13 -07001809 # Install the first set of flows
1810 for f_idx in range(flow_count):
1811 rv = self.controller.message_send(flows[0][f_idx])
1812 self.assertTrue(rv != -1, "Error installing flow %d" % f_idx)
Dan Talayco0fc08bd2012-04-09 16:56:18 -07001813 self.assertEqual(do_barrier(self.controller), 0, "Barrier failed")
Dan Talaycofa6454f2012-04-05 10:04:13 -07001814
Rich Lane9a003812012-10-04 17:17:59 -07001815 logging.info("Installed %d flows" % flow_count)
Dan Talaycofa6454f2012-04-05 10:04:13 -07001816
1817 # Repeatedly modify all the flows back and forth
1818 updates = 0
1819 # Report status about 5 times
1820 mod_val = (iter_count / 4) + 1
Dan Talaycoabbfdbb2012-04-05 10:29:26 -07001821 start = time.time()
1822 for iter_idx in range(iter_count):
1823 if not iter_idx % mod_val:
Rich Lane9a003812012-10-04 17:17:59 -07001824 logging.info("Flow Toggle: iter %d of %d. " %
Dan Talaycoabbfdbb2012-04-05 10:29:26 -07001825 (iter_idx, iter_count) +
1826 "%d updates in %d secs" %
1827 (updates, time.time() - start))
Dan Talaycofa6454f2012-04-05 10:04:13 -07001828 for toggle in range(2):
1829 t_idx = 1 - toggle
1830 for f_idx in range(flow_count):
1831 rv = self.controller.message_send(flows[t_idx][f_idx])
1832 updates += 1
1833 self.assertTrue(rv != -1, "Error modifying flow %d" %
1834 f_idx)
Dan Talayco0fc08bd2012-04-09 16:56:18 -07001835 self.assertEqual(do_barrier(self.controller), 0,
1836 "Barrier failed")
Dan Talaycoabbfdbb2012-04-05 10:29:26 -07001837
1838 end = time.time()
1839 divisor = end - start or (end - start + 1)
Rich Lane9a003812012-10-04 17:17:59 -07001840 logging.info("Flow toggle: %d iterations" % iter_count)
1841 logging.info(" %d flow mods in %d secs, %d mods/sec" %
Dan Talaycoabbfdbb2012-04-05 10:29:26 -07001842 (updates, end - start, updates/divisor))
Dan Talaycofa6454f2012-04-05 10:04:13 -07001843
1844
Dan Talayco8a64e332012-03-28 14:53:20 -07001845# You can pick and choose these by commenting tests in or out
1846iter_classes = [
1847 basic.PacketIn,
1848 basic.PacketOut,
1849 DirectPacket,
Dan Talaycofa6454f2012-04-05 10:04:13 -07001850 FlowToggle,
Dan Talayco8a64e332012-03-28 14:53:20 -07001851 DirectTwoPorts,
Dan Talaycofa6454f2012-04-05 10:04:13 -07001852 DirectMCNonIngress,
Dan Talayco8a64e332012-03-28 14:53:20 -07001853 AllWildcardMatch,
1854 AllWildcardMatchTagged,
1855 SingleWildcardMatch,
1856 SingleWildcardMatchTagged,
1857 ExactMatch,
1858 ExactMatchTagged,
1859 SingleWildcardMatch,
1860 ModifyL2Src,
1861 ModifyL2Dst,
1862 ModifyL2SrcMC,
1863 ModifyL2DstMC,
1864 ModifyL2SrcDstMC
1865 ]
1866
1867class IterCases(BaseMatchCase):
Dan Talaycofa6454f2012-04-05 10:04:13 -07001868 """
1869 Iterate over a bunch of test cases
1870
1871 The cases come from the list above
1872 """
1873
Rich Laned1d9c282012-10-04 22:07:10 -07001874 priority = -1
1875
Dan Talayco8a64e332012-03-28 14:53:20 -07001876 def runTest(self):
Rich Lane2014f9b2012-10-05 15:29:40 -07001877 count = test_param_get('iter_count', default=10)
Dan Talayco8a64e332012-03-28 14:53:20 -07001878 tests_done = 0
Rich Lane9a003812012-10-04 17:17:59 -07001879 logging.info("Running iteration test " + str(count) + " times")
Dan Talayco8a64e332012-03-28 14:53:20 -07001880 start = time.time()
1881 last = start
1882 for idx in range(count):
Rich Lane9a003812012-10-04 17:17:59 -07001883 logging.info("Iteration " + str(idx + 1))
Dan Talayco8a64e332012-03-28 14:53:20 -07001884 for cls in iter_classes:
1885 test = cls()
1886 test.inheritSetup(self)
1887 test.runTest()
1888 tests_done += 1
Dan Talaycofa6454f2012-04-05 10:04:13 -07001889 # Report update about every minute, between tests
Dan Talayco8a64e332012-03-28 14:53:20 -07001890 if time.time() - last > 60:
1891 last = time.time()
Rich Lane9a003812012-10-04 17:17:59 -07001892 logging.info(
Dan Talaycofa6454f2012-04-05 10:04:13 -07001893 "IterCases: Iter %d of %d; Ran %d tests in %d " %
1894 (idx, count, tests_done, last - start) +
1895 "seconds so far")
Dan Talayco8a64e332012-03-28 14:53:20 -07001896 stats = all_stats_get(self)
1897 last = time.time()
Rich Lane9a003812012-10-04 17:17:59 -07001898 logging.info("\nIterCases ran %d tests in %d seconds." %
Dan Talayco8a64e332012-03-28 14:53:20 -07001899 (tests_done, last - start))
Rich Lane9a003812012-10-04 17:17:59 -07001900 logging.info(" flows: %d. packets: %d. bytes: %d" %
Dan Talayco8a64e332012-03-28 14:53:20 -07001901 (stats["flows"], stats["packets"], stats["bytes"]))
Rich Lane9a003812012-10-04 17:17:59 -07001902 logging.info(" active: %d. lookups: %d. matched %d." %
Dan Talayco8a64e332012-03-28 14:53:20 -07001903 (stats["active"], stats["lookups"], stats["matched"]))
1904
Dan Talayco4b2bee62010-07-20 14:10:05 -07001905#@todo Need to implement tagged versions of the above tests
1906#
1907#@todo Implement a test case that strips tag 2, adds tag 3
1908# and modifies tag 4 to tag 5. Then verify (in addition) that
1909# tag 6 does not get modified.
1910
1911class MixedVLAN(BaseMatchCase):
1912 """
1913 Test mixture of VLAN tag actions
1914
1915 Strip tag 2 on port 1, send to port 2
1916 Add tag 3 on port 1, send to port 2
1917 Modify tag 4 to 5 on port 1, send to port 2
1918 All other traffic from port 1, send to port 3
1919 All traffic from port 2 sent to port 4
1920 Use exact matches with different packets for all mods
1921 Verify the following: (port, vid)
1922 (port 1, vid 2) => VLAN tag stripped, out port 2
1923 (port 1, no tag) => tagged packet w/ vid 2 out port 2
1924 (port 1, vid 4) => tagged packet w/ vid 5 out port 2
1925 (port 1, vid 5) => tagged packet w/ vid 5 out port 2
1926 (port 1, vid 6) => tagged packet w/ vid 6 out port 2
1927 (port 2, no tag) => untagged packet out port 4
1928 (port 2, vid 2-6) => unmodified packet out port 4
1929
1930 Variation: Might try sending VID 5 to port 3 and check.
1931 If only VID 5 distinguishes pkt, this will fail on some platforms
1932 """
1933
Rich Laned1d9c282012-10-04 22:07:10 -07001934 priority = -1
Rich Lane8d6ab272012-09-23 18:06:20 -07001935
Rich Laneb90a1c42012-10-05 09:16:05 -07001936class MatchEach(base_tests.SimpleDataPlane):
Rich Lane8d6ab272012-09-23 18:06:20 -07001937 """
1938 Check that each match field is actually matched on.
1939 Installs two flows that differ in one field. The flow that should not
1940 match has a higher priority, so if that field is ignored during matching
1941 the packet will be sent out the wrong port.
1942
1943 TODO test UDP, ARP, ICMP, etc.
1944 """
1945 def runTest(self):
Rich Lane477f4812012-10-04 22:49:00 -07001946 of_ports = config["port_map"].keys()
Rich Lane8d6ab272012-09-23 18:06:20 -07001947 of_ports.sort()
1948 self.assertTrue(len(of_ports) > 1, "Not enough ports for test")
1949
Rich Lane9a003812012-10-04 17:17:59 -07001950 delete_all_flows(self.controller)
Rich Lane8d6ab272012-09-23 18:06:20 -07001951
Ed Swierk7040a8d2012-12-11 16:30:13 -08001952 pkt = simple_tcp_packet(dl_vlan_enable=True, dl_vlan=2)
Rich Lane8d6ab272012-09-23 18:06:20 -07001953 ingress_port = of_ports[0]
1954 egress_port = of_ports[1]
1955
1956 def testField(field, mask):
Rich Lane9a003812012-10-04 17:17:59 -07001957 logging.info("Testing field %s" % field)
Rich Lane8d6ab272012-09-23 18:06:20 -07001958
1959 def addFlow(matching, priority, output_port):
1960 match = packet_to_flow_match(self, pkt)
1961 self.assertTrue(match is not None, "Could not generate flow match from pkt")
1962 match.wildcards &= ~ofp.OFPFW_IN_PORT
1963 match.in_port = ingress_port
1964 if not matching:
1965 # Make sure flow doesn't match
1966 orig = getattr(match, field)
1967 if isinstance(orig, list):
1968 new = map(lambda a: ~a[0] & a[1], zip(orig, mask))
1969 else:
1970 new = ~orig & mask
1971 setattr(match, field, new)
1972 request = message.flow_mod()
1973 request.match = match
1974 request.buffer_id = 0xffffffff
1975 request.priority = priority
1976 act = action.action_output()
1977 act.port = output_port
1978 self.assertTrue(request.actions.add(act), "Could not add action")
Rich Lane9a003812012-10-04 17:17:59 -07001979 logging.info("Inserting flow")
Rich Lane8d6ab272012-09-23 18:06:20 -07001980 self.controller.message_send(request)
1981
1982 # This flow should match.
1983 addFlow(matching=True, priority=0, output_port=egress_port)
1984 # This flow should not match, but it has a higher priority.
1985 addFlow(matching=False, priority=1, output_port=ofp.OFPP_IN_PORT)
1986
1987 self.assertEqual(do_barrier(self.controller), 0, "Barrier failed")
1988
Rich Lane9a003812012-10-04 17:17:59 -07001989 logging.info("Sending packet to dp port " + str(ingress_port))
Rich Lane8d6ab272012-09-23 18:06:20 -07001990 self.dataplane.send(ingress_port, str(pkt))
1991
1992 exp_pkt_arg = None
1993 exp_port = None
Rich Lane477f4812012-10-04 22:49:00 -07001994 if config["relax"]:
Rich Lane8d6ab272012-09-23 18:06:20 -07001995 exp_pkt_arg = pkt
1996 exp_port = egress_port
1997
1998 (rcv_port, rcv_pkt, pkt_time) = self.dataplane.poll(port_number=exp_port,
1999 exp_pkt=exp_pkt_arg)
2000 self.assertTrue(rcv_pkt is not None, "Did not receive packet")
Rich Lane9a003812012-10-04 17:17:59 -07002001 logging.debug("Packet len " + str(len(rcv_pkt)) + " in on " + str(rcv_port))
Rich Lane8d6ab272012-09-23 18:06:20 -07002002 self.assertEqual(rcv_port, egress_port, "Unexpected receive port")
2003 self.assertEqual(str(pkt), str(rcv_pkt), 'Response packet does not match send packet')
2004
Ed Swierkb603b192012-12-12 15:38:49 -08002005 wildcards = required_wildcards(self)
Rich Lane8d6ab272012-09-23 18:06:20 -07002006 # TODO in_port
Ed Swierkb603b192012-12-12 15:38:49 -08002007 if not (wildcards & ofp.OFPFW_DL_SRC):
2008 testField("dl_src", [0xff]*6)
2009 if not (wildcards & ofp.OFPFW_DL_DST):
2010 testField("dl_dst", [0xff]*6)
2011 if not (wildcards & ofp.OFPFW_DL_TYPE):
2012 testField("dl_type", 0xffff)
2013 if not (wildcards & ofp.OFPFW_DL_VLAN):
2014 testField("dl_vlan", 0xfff)
Rich Lane8d6ab272012-09-23 18:06:20 -07002015 # TODO dl_vlan_pcp
Ed Swierkb603b192012-12-12 15:38:49 -08002016 if not (wildcards & ofp.OFPFW_NW_SRC_ALL):
2017 testField("nw_src", 0xffffffff)
2018 if not (wildcards & ofp.OFPFW_NW_DST_ALL):
2019 testField("nw_dst", 0xffffffff)
2020 if not (wildcards & ofp.OFPFW_NW_TOS):
2021 testField("nw_tos", 0x3f)
2022 if not (wildcards & ofp.OFPFW_NW_PROTO):
2023 testField("nw_proto", 0xff)
2024 if not (wildcards & ofp.OFPFW_TP_SRC):
2025 testField("tp_src", 0xffff)
2026 if not (wildcards & ofp.OFPFW_TP_DST):
2027 testField("tp_dst", 0xffff)
Rich Lane8d6ab272012-09-23 18:06:20 -07002028
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002029class DirectBadPacketBase(base_tests.SimpleDataPlane):
2030 """
2031 Base class for sending single packets with single flow table entries.
2032 Used to verify matching of unusual packets and parsing/matching of
2033 corrupted packets.
2034
2035 The idea is to generate packets that may either be totally malformed or
2036 malformed just enough to trick the flow matcher into making mistakes.
2037
2038 Generate a 'bad' packet
2039 Generate and install a matching flow
2040 Add action to direct the packet to an egress port
2041 Send the packet to ingress dataplane port
2042 Verify the packet is received at the egress port only
2043 """
2044
2045 RESULT_MATCH = "MATCH"
2046 RESULT_NOMATCH = "NO MATCH"
2047 RESULT_ANY = "ANY MATCH"
2048
2049 def runTest(self):
2050 pass
2051 # TODO:
2052 # - ICMP?
2053 # - VLAN?
2054 # - action
2055
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002056 def createMatch(self, **kwargs):
2057 match = ofp.ofp_match()
2058 match.wildcards = ofp.OFPFW_ALL
2059 fields = {
2060 'dl_dst': ofp.OFPFW_DL_DST,
2061 'dl_src': ofp.OFPFW_DL_SRC,
2062 'dl_type': ofp.OFPFW_DL_TYPE,
2063 'dl_vlan': ofp.OFPFW_DL_VLAN,
2064 'nw_src': ofp.OFPFW_NW_SRC_MASK,
2065 'nw_dst': ofp.OFPFW_NW_DST_MASK,
2066 'nw_tos': ofp.OFPFW_NW_TOS,
2067 'nw_proto': ofp.OFPFW_NW_PROTO,
2068 'tp_src': ofp.OFPFW_TP_SRC,
2069 'tp_dst': ofp.OFPFW_TP_DST,
2070 }
2071 for key in kwargs:
2072 setattr(match, key, kwargs[key])
2073 match.wildcards &= ~fields[key]
2074 return match
2075
2076 def testPktsAgainstFlow(self, pkts, acts, match):
2077 if type(acts) != list:
2078 acts = [acts]
2079 for info in pkts:
2080 title, pkt, expected_result = info
2081 self.testPktAgainstFlow(title, pkt, acts, match, expected_result)
2082
2083 def testPktAgainstFlow(self, title, pkt, acts, match, expected_result):
2084 of_ports = config["port_map"].keys()
2085 of_ports.sort()
2086 self.assertTrue(len(of_ports) > 1, "Not enough ports for test")
2087
2088 rv = delete_all_flows(self.controller)
2089 self.assertEqual(rv, 0, "Failed to delete all flows")
2090
2091 ingress_port = of_ports[0]
2092 egress_port = of_ports[1]
2093
2094 logging.info("Testing packet '%s', expect result %s" %
2095 (title, expected_result))
2096 logging.info("Ingress %s to egress %s" %
2097 (str(ingress_port), str(egress_port)))
2098 logging.info("Packet:")
Rich Lane5d7e89a2012-10-26 16:43:13 -07002099 logging.info(inspect_packet(pkt))
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002100
2101 match.in_port = ingress_port
2102
2103 request = message.flow_mod()
2104 request.match = match
Rich Lane44cf12d2012-10-15 11:10:45 -07002105 request.priority = 1
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002106
2107 request.buffer_id = 0xffffffff
2108 for act in acts:
2109 act.port = egress_port
2110 rv = request.actions.add(act)
2111 self.assertTrue(rv, "Could not add action")
2112
2113 logging.info("Inserting flow")
2114 rv = self.controller.message_send(request)
2115 self.assertTrue(rv != -1, "Error installing flow mod")
Rich Lane44cf12d2012-10-15 11:10:45 -07002116
2117 # This flow speeds up negative tests
2118 logging.info("Inserting catch-all flow")
2119 request2 = message.flow_mod()
2120 request2.match = self.createMatch()
2121 request2.priority = 0
2122 act = action.action_output()
2123 act.port = ofp.OFPP_IN_PORT
2124 request2.actions.add(act)
2125 rv = self.controller.message_send(request2)
2126 self.assertTrue(rv != -1, "Error installing flow mod")
2127
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002128 self.assertEqual(do_barrier(self.controller), 0, "Barrier failed")
2129
2130 logging.info("Sending packet to dp port " +
2131 str(ingress_port))
2132 self.dataplane.send(ingress_port, str(pkt))
2133
2134 exp_pkt_arg = None
2135 exp_port = None
2136 if config["relax"]:
2137 exp_pkt_arg = pkt
2138 exp_port = egress_port
2139
Rich Lane44cf12d2012-10-15 11:10:45 -07002140 if expected_result == self.RESULT_MATCH:
2141 timeout = -1 # default timeout
2142 else:
2143 timeout = 1 # short timeout for negative tests
2144
2145 (rcv_port, rcv_pkt, pkt_time) = self.dataplane.poll(exp_pkt=exp_pkt_arg,
2146 timeout=timeout)
2147 if rcv_port == ingress_port:
2148 logging.debug("Packet matched catch-all flow")
2149 rcv_pkt = None
2150
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002151 if expected_result == self.RESULT_MATCH:
2152 self.assertTrue(rcv_pkt is not None,
2153 "Did not receive packet, expected a match")
2154 logging.debug("Packet len " + str(len(rcv_pkt)) + " in on " +
2155 str(rcv_port))
2156 self.assertEqual(rcv_port, egress_port, "Unexpected receive port")
2157 str_pkt = str(pkt)
2158 str_rcv_pkt = str(rcv_pkt)
2159 str_rcv_pkt = str_rcv_pkt[0:len(str_pkt)]
2160 if str_pkt != str_rcv_pkt:
2161 logging.error("Response packet does not match send packet")
2162 logging.info("Response:")
Rich Lane5d7e89a2012-10-26 16:43:13 -07002163 logging.info(inspect_packet(scapy.Ether(rcv_pkt)))
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002164 self.assertEqual(str_pkt, str_rcv_pkt,
2165 'Response packet does not match send packet')
2166 elif expected_result == self.RESULT_NOMATCH:
2167 self.assertTrue(rcv_pkt is None, "Received packet, expected drop")
2168 else:
2169 logging.debug("Match or drop accepted. Result = %s" %
2170 ("match" if rcv_pkt is not None else "drop"))
2171
2172
2173class DirectBadIpTcpPacketsBase(DirectBadPacketBase):
2174 """
2175 Base class for TCP and UDP parsing/matching verification under corruptions
2176 """
2177 def runTest(self):
2178 pass
2179
2180 def runTestWithProto(self, protoName = 'TCP'):
2181 dl_dst='00:01:02:03:04:05'
2182 dl_src='00:06:07:08:09:0a'
2183 ip_src='192.168.0.1'
2184 ip_dst='192.168.0.2'
2185 ip_tos=0
2186 tcp_sport=1234
2187 tcp_dport=80
2188
2189 # Generate a proper packet for constructing a match
2190 tp = None
2191 if protoName == 'TCP':
2192 tp = scapy.TCP
2193 proto = 6
2194 elif protoName == 'UDP':
2195 tp = scapy.UDP
2196 proto = 17
2197 else:
2198 raise Exception("Passed in unknown proto name")
2199
2200 match_pkt = scapy.Ether(dst=dl_dst, src=dl_src)/ \
2201 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos)/ \
2202 tp(sport=tcp_sport, dport=tcp_dport)
2203 match = packet_to_flow_match(self, match_pkt)
2204 self.assertTrue(match is not None,
2205 "Could not generate flow match from pkt")
2206 match.wildcards &= ~ofp.OFPFW_IN_PORT
2207
2208 def testPacket(title, pkt, result):
2209 act = action.action_output()
2210 pkts = [
2211 [title, pkt, result]
2212 ]
2213 self.testPktsAgainstFlow(pkts, act, match)
2214
2215 # Try incomplete IP headers
2216 testPacket("Incomplete IP header (1 bytes)",
2217 scapy.Ether(dst=dl_dst, src=dl_src)/ \
2218 str(scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, proto=proto))[0:1],
2219 self.RESULT_NOMATCH,
2220 )
2221 testPacket("Incomplete IP header (2 bytes)",
2222 scapy.Ether(dst=dl_dst, src=dl_src)/ \
2223 str(scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, proto=proto))[0:2],
2224 self.RESULT_NOMATCH,
2225 )
2226 testPacket("Incomplete IP header (3 bytes)",
2227 scapy.Ether(dst=dl_dst, src=dl_src)/ \
2228 str(scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, proto=proto))[0:3],
2229 self.RESULT_NOMATCH,
2230 )
2231 testPacket("Incomplete IP header (12 bytes)",
2232 scapy.Ether(dst=dl_dst, src=dl_src)/ \
2233 str(scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, proto=proto))[0:12],
2234 self.RESULT_NOMATCH,
2235 )
2236 testPacket("Incomplete IP header (16 bytes)",
2237 scapy.Ether(dst=dl_dst, src=dl_src)/ \
2238 str(scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, proto=proto))[0:16],
2239 self.RESULT_NOMATCH,
2240 )
2241 testPacket("Incomplete IP header (19 bytes)",
2242 scapy.Ether(dst=dl_dst, src=dl_src)/ \
2243 str(scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, proto=proto))[0:19],
2244 self.RESULT_NOMATCH,
2245 )
2246
2247 # Try variations where the TCP header is missing or incomplete. As we
2248 # saw bugs before where buffers were reused and lengths weren't honored,
2249 # we initiatlize once with a non-matching full packet and once with a
2250 # matching full packet.
2251 testPacket("Non-Matching TCP packet, warming buffer",
2252 scapy.Ether(dst=dl_dst, src=dl_src)/ \
2253 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, proto=proto)/ \
2254 tp(sport=tcp_sport, dport=tcp_dport + 1),
2255 self.RESULT_NOMATCH,
2256 )
2257 testPacket("Missing TCP header, buffer warmed with non-match",
2258 scapy.Ether(dst=dl_dst, src=dl_src)/ \
2259 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, proto=proto),
2260 self.RESULT_NOMATCH,
2261 )
2262 testPacket("Matching TCP packet, warming buffer",
2263 scapy.Ether(dst=dl_dst, src=dl_src)/ \
2264 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, proto=proto)/ \
2265 tp(sport=tcp_sport, dport=tcp_dport),
2266 self.RESULT_MATCH,
2267 )
2268 testPacket("Missing TCP header, buffer warmed with match",
2269 scapy.Ether(dst=dl_dst, src=dl_src)/ \
2270 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, proto=proto),
2271 self.RESULT_NOMATCH,
2272 )
2273 testPacket("Truncated TCP header: 2 bytes",
2274 scapy.Ether(dst=dl_dst, src=dl_src)/ \
2275 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, proto=proto)/ \
2276 (str(tp(sport=tcp_sport, dport=tcp_dport))[0:2]),
2277 self.RESULT_NOMATCH,
2278 )
2279
2280 # Play with IP header length values that put the start of TCP either
2281 # inside the generated TCP header or beyond. In some cases it may even
2282 # be beyond the packet boundary. Also play with IP options and more
2283 # importantly IP total length corruptions.
2284 testPacket("TCP packet, corrupt ihl (0x6)",
2285 simple_tcp_packet(ip_ihl=6),
2286 self.RESULT_NOMATCH,
2287 )
2288 testPacket("TCP packet, corrupt ihl (0xf)",
2289 simple_tcp_packet(ip_ihl=0xf), # ihl = 15 * 4 = 60
2290 self.RESULT_NOMATCH,
2291 )
2292 testPacket("TCP packet, corrupt ihl and total length",
2293 simple_tcp_packet(ip_ihl=0xf, pktlen=56), # ihl = 15 * 4 = 60,
2294 self.RESULT_NOMATCH,
2295 )
2296 testPacket("Corrupt IPoption: First 4 bytes of matching TCP header",
2297 simple_tcp_packet(
2298 ip_options=scapy.IPOption('\x04\xd2\x00\x50'),
2299 tcp_dport=2, tcp_sport=2
2300 ),
2301 self.RESULT_NOMATCH,
2302 )
2303 testPacket("Missing TCP header, corrupt ihl",
2304 scapy.Ether(dst=dl_dst, src=dl_src)/ \
2305 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ihl=0xf, proto=proto),
2306 self.RESULT_NOMATCH,
2307 )
2308 testPacket("Missing TCP header, corrupt total length",
2309 scapy.Ether(dst=dl_dst, src=dl_src)/ \
2310 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, proto=proto, len= 100),
2311 self.RESULT_NOMATCH,
2312 )
2313 testPacket("Missing TCP header, corrupt ihl and total length",
2314 scapy.Ether(dst=dl_dst, src=dl_src)/ \
2315 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ihl=0xf, proto=proto, len=43),
2316 self.RESULT_NOMATCH,
2317 )
2318 testPacket("Incomplete IP header (12 bytes), corrupt ihl and total length",
2319 scapy.Ether(dst=dl_dst, src=dl_src)/ \
2320 str(scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, proto=proto, ihl=10, len=43))[0:12],
2321 self.RESULT_NOMATCH,
2322 )
2323 testPacket("Incomplete IP header (16 bytes), corrupt ihl and total length",
2324 scapy.Ether(dst=dl_dst, src=dl_src)/ \
2325 str(scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, proto=proto, ihl=10, len=43))[0:16],
2326 self.RESULT_NOMATCH,
2327 )
2328
2329 # Try an incomplete TCP header that has enough bytes to carry source and
2330 # destination ports. As that is all we care about during matching, some
2331 # implementations may match and some may drop the packet
2332 testPacket("Incomplete TCP header: src/dst port present",
2333 scapy.Ether(dst=dl_dst, src=dl_src)/ \
2334 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, proto=proto)/ \
2335 (str(tp(sport=tcp_sport, dport=tcp_dport))[0:4]),
2336 self.RESULT_ANY,
2337 )
2338
2339 for i in range(1):
2340 for length in range(40 / 4): # IPv4 options are a maximum of 40 in length
2341 bytes = "".join([("%c" % random.randint(0, 255)) for x in range(length * 4)])
2342 eth = scapy.Ether(dst=dl_dst, src=dl_src)
2343 ip = scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ihl=5 + length, proto=proto)
2344 tcp = tp(sport=tcp_sport, dport=tcp_dport+1)
2345 pkt = eth / ip
2346 pkt = pkt / bytes
2347 pkt = pkt / str(tcp)
2348 testPacket("Random IP options len = %d - TP match must fail" % length * 4,
2349 pkt,
2350 self.RESULT_NOMATCH
2351 )
2352
2353 eth = scapy.Ether(dst=dl_dst, src=dl_src)
2354 ip = scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ihl=5 + length, proto=proto)
2355 tcp = tp(sport=tcp_sport, dport=tcp_dport)
2356 pkt = eth / ip
2357 pkt = pkt / bytes
2358 pkt = pkt / str(tcp)
2359
2360 testPacket("Random IP options len = %d - May match",
2361 pkt,
2362 self.RESULT_ANY
2363 )
2364
2365
2366class DirectBadIpTcpPackets(DirectBadIpTcpPacketsBase):
2367 """
2368 Verify IP/TCP parsing and matching. Focus on packet corruptions
2369 """
2370 def runTest(self):
2371 self.runTestWithProto(protoName = 'TCP')
2372
2373class DirectBadIpUdpPackets(DirectBadIpTcpPacketsBase):
2374 """
2375 Verify IP/UDP parsing and matching. Focus on packet corruptions
2376 """
2377 def runTest(self):
2378 self.runTestWithProto(protoName = 'UDP')
2379
2380class DirectBadLlcPackets(DirectBadPacketBase):
2381 """
2382 Verify LLC/SNAP parsing and matching. Focus on packet corruptions
2383 """
2384 def runTest(self):
2385 dl_dst='00:01:02:03:04:05'
2386 dl_src='00:06:07:08:09:0a'
2387 ip_src='192.168.0.1'
2388 ip_dst='192.168.0.2'
2389 ip_tos=0
2390 tcp_sport=1234
2391 tcp_dport=80
2392
2393 IS_SNAP_IP = 1
2394 IS_SNAP_IP_CORRUPT = 2
2395 IS_NOT_SNAP_IP = 3
2396
2397 def testPacketTcpMatch(title, llc):
2398 match_pkt = scapy.Ether(dst=dl_dst, src=dl_src)/ \
2399 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos)/ \
2400 scapy.TCP(sport=tcp_sport, dport=tcp_dport)
2401 match = packet_to_flow_match(self, match_pkt)
2402 self.assertTrue(match is not None,
2403 "Could not generate flow match from pkt")
2404 match.wildcards &= ~ofp.OFPFW_IN_PORT
2405 act = action.action_output()
2406
2407 self.testPktsAgainstFlow(
2408 [[
2409 "TCP match - LLC frame correct length - %s" % title,
2410 scapy.Ether(dst=dl_dst, src=dl_src, type=len(llc)) / llc,
2411 self.RESULT_ANY,
2412 ]],
2413 act, match
2414 )
2415
2416 # Corrupt length field
2417 ethLen = random.randint(0, 1535)
2418 self.testPktsAgainstFlow(
2419 [[
2420 "TCP match - LLC frame corrupted length - %s" % title,
2421 scapy.Ether(dst=dl_dst, src=dl_src, type=ethLen) / llc,
2422 self.RESULT_ANY,
2423 ]],
2424 act, match
2425 )
2426
2427 def testPacketEthSrcDstMatch(title, llc):
2428 # Matching based on Ethernet source and destination
2429 match_pkt = scapy.Ether(dst=dl_dst, src=dl_src)
2430 match = packet_to_flow_match(self, match_pkt)
2431 self.assertTrue(match is not None,
2432 "Could not generate flow match from pkt")
2433 match.wildcards &= ~ofp.OFPFW_IN_PORT
2434 match.wildcards |= ofp.OFPFW_DL_TYPE
2435 self.testPktsAgainstFlow(
2436 [[
2437 "Eth addr match - LLC frame correct length- %s" % title,
2438 scapy.Ether(dst=dl_dst, src=dl_src, type=len(llc)) / llc,
2439 self.RESULT_MATCH,
2440 ]],
2441 action.action_output(), match
2442 )
2443
2444 # Corrupt length field
2445 ethLen = random.randint(0, 1535)
2446 self.testPktsAgainstFlow(
2447 [[
2448 "Eth addr match - LLC frame corrupted length- %s" % title,
2449 scapy.Ether(dst=dl_dst, src=dl_src, type=ethLen) / llc,
2450 self.RESULT_ANY,
2451 ]],
2452 action.action_output(), match
2453 )
2454
2455 def testPacketEthSrcDstTypeMatch(title, llc, is_snap_ip):
2456 # Matching based on Ethernet source, destination and type
2457 match_pkt = scapy.Ether(dst=dl_dst, src=dl_src, type=0x800)
2458 match = packet_to_flow_match(self, match_pkt)
2459 self.assertTrue(match is not None,
2460 "Could not generate flow match from pkt")
2461 match.wildcards &= ~ofp.OFPFW_IN_PORT
2462 if is_snap_ip == IS_SNAP_IP:
2463 is_match = self.RESULT_MATCH
2464 elif is_snap_ip == IS_SNAP_IP_CORRUPT:
2465 is_match = self.RESULT_ANY
2466 else:
2467 is_match = self.RESULT_NOMATCH
2468 self.testPktsAgainstFlow(
2469 [[
2470 "Eth addr+type match - LLC frame correct length - %s" % title,
2471 scapy.Ether(dst=dl_dst, src=dl_src, type=len(llc)) / llc,
2472 is_match,
2473 ]],
2474 action.action_output(), match
2475 )
2476
2477 # Corrupt length field
2478 ethLen = random.randint(0, 1535)
2479 self.testPktsAgainstFlow(
2480 [[
2481 "Eth addr+type match - LLC frame corrupted length - %s" % title,
2482 scapy.Ether(dst=dl_dst, src=dl_src, type=ethLen) / llc,
Christian Dickmanne9b6d252012-10-08 22:56:50 -07002483 self.RESULT_ANY,
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002484 ]],
2485 action.action_output(), match
2486 )
2487
2488 def testPacket(title, llc, is_snap_ip):
2489 testPacketTcpMatch(title, llc)
2490 testPacketEthSrcDstMatch(title, llc)
2491 testPacketEthSrcDstTypeMatch(title, llc, is_snap_ip)
2492
2493 testPacket("LLC - No SNAP - No Payload",
Rich Lane6508ea02012-10-12 15:27:11 -07002494 scapy.LLC(dsap=0x33, ssap=0x44, ctrl=0x03),
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002495 IS_NOT_SNAP_IP,
2496 )
2497 testPacket("LLC - No SNAP - Small Payload",
Rich Lane6508ea02012-10-12 15:27:11 -07002498 scapy.LLC(dsap=0x33, ssap=0x44, ctrl=0x03) / ("S" * 10),
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002499 IS_NOT_SNAP_IP,
2500 )
2501 testPacket("LLC - No SNAP - Max -1 Payload",
Rich Lane6508ea02012-10-12 15:27:11 -07002502 scapy.LLC(dsap=0x33, ssap=0x44, ctrl=0x03) / ("S" * (1500 - 3 - 1)),
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002503 IS_NOT_SNAP_IP,
2504 )
2505 testPacket("LLC - No SNAP - Max Payload",
Rich Lane6508ea02012-10-12 15:27:11 -07002506 scapy.LLC(dsap=0x33, ssap=0x44, ctrl=0x03) / ("S" * (1500 - 3)),
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002507 IS_NOT_SNAP_IP,
2508 )
2509 testPacket("LLC - SNAP - Small bogus payload",
2510 scapy.LLC(dsap=0xaa, ssap=0xaa, ctrl=0x03)/ \
2511 scapy.SNAP(OUI=0x000000, code=0x800) / ("S" * 10),
2512 IS_SNAP_IP_CORRUPT,
2513 )
2514 testPacket("LLC - SNAP - Max -1 bogus payload",
2515 scapy.LLC(dsap=0xaa, ssap=0xaa, ctrl=0x03)/ \
2516 scapy.SNAP(OUI=0x000000, code=0x3) / ("S" * (1500 - 3 - 5 - 1)),
2517 IS_NOT_SNAP_IP,
2518 )
2519 testPacket("LLC - SNAP - Max bogus payload",
2520 scapy.LLC(dsap=0xaa, ssap=0xaa, ctrl=0x03)/ \
2521 scapy.SNAP(OUI=0x000000, code=0x3) / ("S" * (1500 - 3 - 5)),
2522 IS_NOT_SNAP_IP,
2523 )
2524 testPacket("LLC - SNAP - IP - TCP",
2525 scapy.LLC(dsap=0xaa, ssap=0xaa, ctrl=0x03)/ \
2526 scapy.SNAP(OUI=0x000000, code=0x800)/ \
2527 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, proto=6)/ \
2528 scapy.TCP(sport=tcp_sport, dport=tcp_dport),
2529 IS_SNAP_IP,
2530 )
2531
2532
2533class DirectLlcPackets(DirectBadPacketBase):
2534 """
2535 Verify LLC/SNAP parsing (valid and corrupted packets) and matching
2536 """
2537 def runTest(self):
2538 dl_dst='00:01:02:03:04:05'
2539 dl_src='00:06:07:08:09:0a'
2540 ip_src='192.168.0.1'
2541 ip_dst='192.168.0.2'
2542 ip_tos=0
2543 tcp_sport=1234
2544 tcp_dport=80
2545
2546 # Test ethertype in face of LLC/SNAP and OFP_DL_TYPE_NOT_ETH_TYPE
2547 IS_SNAP_NOT_IP = 1
2548 IS_SNAP_AND_IP = 2
2549 IS_NOT_SNAP = 3
2550
2551 def testPacketEthTypeIP(title, llc, is_snap):
2552 match_pkt = scapy.Ether(dst=dl_dst, src=dl_src, type=0x800)
2553 match = packet_to_flow_match(self, match_pkt)
2554 self.assertTrue(match is not None,
2555 "Could not generate flow match from pkt")
2556 match.wildcards &= ~ofp.OFPFW_IN_PORT
2557 pkts = []
2558 if is_snap == IS_NOT_SNAP or is_snap == IS_SNAP_NOT_IP:
2559 result = self.RESULT_NOMATCH
2560 else:
2561 result = self.RESULT_MATCH
2562 pkts.append([
2563 "Ether type 0x800 match - %s" % title,
2564 scapy.Ether(dst=dl_dst, src=dl_src, type=len(llc)) / llc,
2565 result,
2566 ])
2567 act = action.action_output()
2568 self.testPktsAgainstFlow(pkts, act, match)
2569
2570 def testPacketEthTypeNotEth(title, llc, is_snap):
2571 match_pkt = scapy.Ether(dst = dl_dst, src = dl_src,
2572 type = ofp.OFP_DL_TYPE_NOT_ETH_TYPE)
2573 match = packet_to_flow_match(self, match_pkt)
2574 self.assertTrue(match is not None,
2575 "Could not generate flow match from pkt")
2576 match.wildcards &= ~ofp.OFPFW_IN_PORT
2577 pkts = []
2578 if is_snap == IS_NOT_SNAP:
2579 result = self.RESULT_MATCH
2580 else:
2581 result = self.RESULT_NOMATCH
2582 pkts.append([
2583 "Ether type OFP_DL_TYPE_NOT_ETH_TYPE match - %s" % title,
2584 scapy.Ether(dst=dl_dst, src=dl_src, type=len(llc)) / llc,
2585 result,
2586 ])
2587 act = action.action_output()
2588 self.testPktsAgainstFlow(pkts, act, match)
2589
2590 def testPacket(title, llc, is_snap):
2591 testPacketEthTypeIP(title, llc, is_snap)
2592 testPacketEthTypeNotEth(title, llc, is_snap)
2593
2594 testPacket("LLC - No SNAP - No Payload",
Rich Lane6508ea02012-10-12 15:27:11 -07002595 scapy.LLC(dsap=0x33, ssap=0x44, ctrl=0x03),
2596 IS_NOT_SNAP,
2597 )
2598 testPacket("LLC (with information field) - No SNAP - No Payload",
2599 scapy.LLC(dsap=0x33, ssap=0x44, ctrl=0x12) / "S",
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002600 IS_NOT_SNAP,
2601 )
2602 testPacket("LLC - No SNAP - Small Payload",
Rich Lane6508ea02012-10-12 15:27:11 -07002603 scapy.LLC(dsap=0x33, ssap=0x44, ctrl=0x03) / ("S" * 10),
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002604 IS_NOT_SNAP,
2605 )
2606 testPacket("LLC - No SNAP - Max -1 Payload",
Rich Lane6508ea02012-10-12 15:27:11 -07002607 scapy.LLC(dsap=0x33, ssap=0x44, ctrl=0x03) / ("S" * (1500 - 3 - 1)),
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002608 IS_NOT_SNAP,
2609 )
2610 testPacket("LLC - No SNAP - Max Payload",
Rich Lane6508ea02012-10-12 15:27:11 -07002611 scapy.LLC(dsap=0x33, ssap=0x44, ctrl=0x03) / ("S" * (1500 - 3)),
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002612 IS_NOT_SNAP,
2613 )
2614 testPacket("LLC - SNAP - Non-default OUI",
2615 scapy.LLC(dsap=0xaa, ssap=0xaa, ctrl=0x03)/ \
2616 scapy.SNAP(OUI=0x000001, code=0x800) / ("S" * 10),
2617 IS_NOT_SNAP,
2618 )
2619 testPacket("LLC - SNAP - Default OUI",
2620 scapy.LLC(dsap=0xaa, ssap=0xaa, ctrl=0x03)/ \
2621 scapy.SNAP(OUI=0x000000, code=0x800) / ("S" * 10),
2622 IS_SNAP_AND_IP,
2623 )
2624 testPacket("LLC - SNAP - Max -1 bogus payload",
2625 scapy.LLC(dsap=0xaa, ssap=0xaa, ctrl=0x03)/ \
2626 scapy.SNAP(OUI=0x000000, code=0x3) / ("S" * (1500 - 3 - 5 - 1)),
2627 IS_SNAP_NOT_IP,
2628 )
2629 testPacket("LLC - SNAP - Max bogus payload",
2630 scapy.LLC(dsap=0xaa, ssap=0xaa, ctrl=0x03)/ \
2631 scapy.SNAP(OUI=0x000000, code=0x3) / ("S" * (1500 - 3 - 5)),
2632 IS_SNAP_NOT_IP,
2633 )
2634 testPacket("LLC - SNAP - IP - TCP",
2635 scapy.LLC(dsap=0xaa, ssap=0xaa, ctrl=0x03)/ \
2636 scapy.SNAP(OUI=0x000000, code=0x800)/ \
2637 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, proto=6)/ \
2638 scapy.TCP(sport=tcp_sport, dport=tcp_dport),
2639 IS_SNAP_AND_IP,
2640 )
2641
2642
2643class DirectArpPackets(DirectBadPacketBase):
2644 """
2645 Verify ARP parsing (valid and corrupted packets) and ARP matching
2646 """
2647 def runTest(self):
2648 self.testArpHandling()
2649
2650 def testArpHandling(self):
2651 dl_dst='00:01:02:03:04:05'
2652 dl_src='00:06:07:08:09:0a'
2653 ip_src='192.168.0.1'
2654 ip_dst='192.168.0.2'
2655 ip_src2='192.168.1.1'
2656 ip_dst2='192.168.1.2'
2657 ip_tos=0
2658 tcp_sport=1234
2659 tcp_dport=80
2660
2661 def testPacket(title, arp_match, arp_pkt, result):
2662 pkts = []
2663
2664 match_pkt = scapy.Ether(dst=dl_dst, src=dl_src) / arp_match
2665 match = packet_to_flow_match(self, match_pkt)
2666 self.assertTrue(match is not None,
2667 "Could not generate flow match from pkt")
2668 match.wildcards &= ~ofp.OFPFW_IN_PORT
2669
2670 pkts.append([
2671 title,
2672 scapy.Ether(dst=dl_dst, src=dl_src) / arp_pkt,
2673 result,
2674 ])
2675
2676 act = action.action_output()
2677 self.testPktsAgainstFlow(pkts, act, match)
2678
2679 testPacket("Basic ARP",
2680 scapy.ARP(psrc=ip_src, pdst=ip_dst, op = 1),
2681 scapy.ARP(hwdst = '00:00:00:00:00:00', hwsrc = dl_src,
2682 psrc = ip_src, pdst = ip_dst, hwlen = 6, plen = 4,
2683 ptype = 0x800, hwtype = 1, op = 1),
2684 self.RESULT_MATCH
2685 )
2686 # More stuff:
2687 # - Non matches on any property
2688 # - Corrupted hwlen and plen
2689 # - Other hwtype, ptype
2690 # - Truncated ARP pkt
2691
2692
2693class DirectVlanPackets(DirectBadPacketBase):
2694 """
2695 Verify VLAN parsing (valid and corrupted packets) and ARP matching
2696 """
2697 def runTest(self):
2698 dl_dst='00:01:02:03:04:05'
2699 dl_src='00:06:07:08:09:0a'
2700 ip_src='192.168.0.1'
2701 ip_dst='192.168.0.2'
2702 ip_src2='192.168.1.1'
2703 ip_dst2='192.168.1.2'
2704 ip_tos=0
2705 tcp_sport=1234
2706 tcp_dport=80
2707
2708 def testPacket(title, match, pkt, result):
2709 pkts = []
2710
2711 self.assertTrue(match is not None,
2712 "Could not generate flow match from pkt")
2713 match.wildcards &= ~ofp.OFPFW_IN_PORT
2714
2715 pkts.append([
2716 "%s" % title,
2717 pkt,
2718 result,
2719 ])
2720
2721 act = action.action_output()
2722 self.testPktsAgainstFlow(pkts, act, match)
2723
2724 testPacket("Basic MAC matching - IPv4 payload",
2725 self.createMatch(dl_dst=parse_mac(dl_dst), dl_src=parse_mac(dl_src)),
2726 scapy.Ether(dst=dl_dst, src=dl_src, type=0x800) / scapy.IP(),
2727 self.RESULT_MATCH
2728 )
2729 testPacket("Basic MAC matching - VMware beacon - no payload",
2730 self.createMatch(dl_dst=parse_mac(dl_dst), dl_src=parse_mac(dl_src)),
2731 scapy.Ether(dst=dl_dst, src=dl_src, type=0x8922),
2732 self.RESULT_MATCH
2733 )
2734 testPacket("Basic MAC matching - VMware beacon - with payload",
2735 self.createMatch(dl_dst=parse_mac(dl_dst), dl_src=parse_mac(dl_src)),
2736 scapy.Ether(dst=dl_dst, src=dl_src, type=0x8922)/ ("X" * 1),
2737 self.RESULT_MATCH
2738 )
2739 testPacket("Basic MAC matching - IPv6 payload",
2740 self.createMatch(dl_dst=parse_mac(dl_dst), dl_src=parse_mac(dl_src)),
2741 scapy.Ether(dst=dl_dst, src=dl_src) / scapy.IPv6(),
2742 self.RESULT_MATCH
2743 )
2744 testPacket("Basic MAC matching with VLAN tag present",
2745 self.createMatch(dl_dst=parse_mac(dl_dst), dl_src=parse_mac(dl_src)),
2746 scapy.Ether(dst=dl_dst, src=dl_src)/ \
Christian Dickmann8ac55252012-10-08 22:53:49 -07002747 scapy.Dot1Q(prio=5, vlan=1000)/ \
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002748 scapy.IP(),
2749 self.RESULT_MATCH
2750 )
2751 testPacket("Basic MAC matching with VLAN tag present",
2752 self.createMatch(dl_dst=parse_mac(dl_dst), dl_src=parse_mac(dl_src),
2753 dl_type=0x800),
2754 scapy.Ether(dst=dl_dst, src=dl_src)/ \
Christian Dickmann8ac55252012-10-08 22:53:49 -07002755 scapy.Dot1Q(prio=5, vlan=1000)/ \
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002756 scapy.IP(),
2757 self.RESULT_MATCH
2758 )
2759 testPacket("Ether matching with VLAN tag present - No type match",
2760 self.createMatch(dl_dst=parse_mac(dl_dst), dl_src=parse_mac(dl_src),
2761 dl_type=0x801),
2762 scapy.Ether(dst=dl_dst, src=dl_src)/ \
Christian Dickmann8ac55252012-10-08 22:53:49 -07002763 scapy.Dot1Q(prio=5, vlan=1000)/ \
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002764 scapy.IP(),
2765 self.RESULT_NOMATCH
2766 )
2767 testPacket("Ether matching with VLAN tag present - No type match 0x8100",
2768 self.createMatch(dl_dst=parse_mac(dl_dst), dl_src=parse_mac(dl_src),
2769 dl_type=0x8100),
2770 scapy.Ether(dst=dl_dst, src=dl_src)/ \
Christian Dickmann8ac55252012-10-08 22:53:49 -07002771 scapy.Dot1Q(prio=5, vlan=1000)/ \
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002772 scapy.IP(),
2773 self.RESULT_NOMATCH
2774 )
2775 testPacket("Ether matching with double VLAN tag - Wrong type match",
2776 self.createMatch(dl_dst=parse_mac(dl_dst), dl_src=parse_mac(dl_src),
2777 dl_type=0x800),
2778 scapy.Ether(dst=dl_dst, src=dl_src)/ \
Christian Dickmann8ac55252012-10-08 22:53:49 -07002779 scapy.Dot1Q(prio=5, vlan=1000)/ \
2780 scapy.Dot1Q(prio=3, vlan=1005)/ \
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002781 scapy.IP(),
2782 self.RESULT_NOMATCH
2783 )
2784 testPacket("Ether matching with double VLAN tag - Type match",
2785 self.createMatch(dl_dst=parse_mac(dl_dst), dl_src=parse_mac(dl_src),
2786 dl_type=0x8100),
2787 scapy.Ether(dst=dl_dst, src=dl_src)/ \
Christian Dickmann8ac55252012-10-08 22:53:49 -07002788 scapy.Dot1Q(prio=5, vlan=1000)/ \
2789 scapy.Dot1Q(prio=3, vlan=1005)/ \
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002790 scapy.IP(),
2791 self.RESULT_MATCH
2792 )
2793 testPacket("IP matching - VLAN tag",
2794 self.createMatch(dl_dst=parse_mac(dl_dst), dl_src=parse_mac(dl_src),
2795 dl_type=0x0800,
2796 nw_src=parse_ip(ip_src), nw_dst=parse_ip(ip_dst)),
2797 scapy.Ether(dst=dl_dst, src=dl_src)/ \
Christian Dickmann8ac55252012-10-08 22:53:49 -07002798 scapy.Dot1Q(prio=5, vlan=1000)/ \
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002799 scapy.IP(src=ip_src, dst=ip_dst),
2800 self.RESULT_MATCH
2801 )
2802 # XXX:
2803 # - Matching on VLAN ID and Prio
2804 # - Actions
2805
2806
2807
Dan Talayco9f47f4d2010-06-03 13:54:37 -07002808if __name__ == "__main__":
2809 print "Please run through oft script: ./oft --test_spec=basic"