blob: 7c7f1d79295bd808e4a397a040641e4943e7c8a1 [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
873 for idx in range(len(of_ports)):
Rich Lane9a003812012-10-04 17:17:59 -0700874 rv = delete_all_flows(self.controller)
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700875 self.assertEqual(rv, 0, "Failed to delete all flows")
876
877 ingress_port = of_ports[idx]
878 no_flood_idx = (idx + 1) % len(of_ports)
879 no_flood_port = of_ports[no_flood_idx]
880 rv = port_config_set(self.controller, no_flood_port,
Rich Lane9a003812012-10-04 17:17:59 -0700881 ofp.OFPPC_NO_FLOOD, ofp.OFPPC_NO_FLOOD)
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700882 self.assertEqual(rv, 0, "Failed to set port config")
883
884 match.in_port = ingress_port
885
886 request = message.flow_mod()
887 request.match = match
888 request.buffer_id = 0xffffffff
889 act.port = ofp.OFPP_FLOOD
890 self.assertTrue(request.actions.add(act),
891 "Could not add flood port action")
Rich Lane9a003812012-10-04 17:17:59 -0700892 logging.info(request.show())
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700893
Rich Lane9a003812012-10-04 17:17:59 -0700894 logging.info("Inserting flow")
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700895 rv = self.controller.message_send(request)
896 self.assertTrue(rv != -1, "Error installing flow mod")
Dan Talayco0fc08bd2012-04-09 16:56:18 -0700897 self.assertEqual(do_barrier(self.controller), 0, "Barrier failed")
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700898
Rich Lane9a003812012-10-04 17:17:59 -0700899 logging.info("Sending packet to dp port " + str(ingress_port))
900 logging.info("No flood port is " + str(no_flood_port))
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700901 self.dataplane.send(ingress_port, str(pkt))
902 no_ports = set([ingress_port, no_flood_port])
903 yes_ports = set(of_ports).difference(no_ports)
Rich Lane2014f9b2012-10-05 15:29:40 -0700904 receive_pkt_check(self.dataplane, pkt, yes_ports, no_ports, self)
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700905
906 # Turn no flood off again
907 rv = port_config_set(self.controller, no_flood_port,
Rich Lane9a003812012-10-04 17:17:59 -0700908 0, ofp.OFPPC_NO_FLOOD)
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700909 self.assertEqual(rv, 0, "Failed to reset port config")
910
911 #@todo Should check no other packets received
912
Dan Talayco21381562010-07-17 00:34:47 -0700913
914
Dan Talayco551befa2010-07-15 17:05:32 -0700915################################################################
916
Rich Laneb90a1c42012-10-05 09:16:05 -0700917class BaseMatchCase(base_tests.SimpleDataPlane):
Dan Talayco551befa2010-07-15 17:05:32 -0700918 def setUp(self):
Rich Laneb90a1c42012-10-05 09:16:05 -0700919 base_tests.SimpleDataPlane.setUp(self)
Dan Talayco551befa2010-07-15 17:05:32 -0700920 def runTest(self):
Rich Lane9a003812012-10-04 17:17:59 -0700921 logging.info("BaseMatchCase")
Dan Talayco551befa2010-07-15 17:05:32 -0700922
923class ExactMatch(BaseMatchCase):
Tatsuya Yabe6a6f38a2010-05-22 23:48:04 -0700924 """
Dan Talayco551befa2010-07-15 17:05:32 -0700925 Exercise exact matching for all port pairs
Tatsuya Yabe6a6f38a2010-05-22 23:48:04 -0700926
927 Generate a packet
928 Generate and install a matching flow without wildcard mask
929 Add action to forward to a port
930 Send the packet to the port
931 Verify the packet is received at all other ports (one port at a time)
Tatsuya Yabe6a6f38a2010-05-22 23:48:04 -0700932 """
Tatsuya Yabe0718ad32010-05-24 15:22:10 -0700933
Tatsuya Yabe6a6f38a2010-05-22 23:48:04 -0700934 def runTest(self):
Rich Lane477f4812012-10-04 22:49:00 -0700935 flow_match_test(self, config["port_map"])
Tatsuya Yabe6a6f38a2010-05-22 23:48:04 -0700936
Dan Talayco551befa2010-07-15 17:05:32 -0700937class ExactMatchTagged(BaseMatchCase):
938 """
939 Exact match for all port pairs with tagged pkts
940 """
Tatsuya Yabe6a6f38a2010-05-22 23:48:04 -0700941
Dan Talayco551befa2010-07-15 17:05:32 -0700942 def runTest(self):
Rich Lane2014f9b2012-10-05 15:29:40 -0700943 vid = test_param_get('vid', default=TEST_VID_DEFAULT)
Rich Lane477f4812012-10-04 22:49:00 -0700944 flow_match_test(self, config["port_map"], dl_vlan=vid)
Tatsuya Yabe6a6f38a2010-05-22 23:48:04 -0700945
Dan Talayco551befa2010-07-15 17:05:32 -0700946class ExactMatchTaggedMany(BaseMatchCase):
947 """
948 ExactMatchTagged with many VLANS
949 """
Tatsuya Yabe6a6f38a2010-05-22 23:48:04 -0700950
Rich Laned1d9c282012-10-04 22:07:10 -0700951 priority = -1
952
Dan Talayco551befa2010-07-15 17:05:32 -0700953 def runTest(self):
Dan Talayco21381562010-07-17 00:34:47 -0700954 for vid in range(2,100,10):
Rich Lane477f4812012-10-04 22:49:00 -0700955 flow_match_test(self, config["port_map"], dl_vlan=vid, max_test=5)
Dan Talayco551befa2010-07-15 17:05:32 -0700956 for vid in range(100,4000,389):
Rich Lane477f4812012-10-04 22:49:00 -0700957 flow_match_test(self, config["port_map"], dl_vlan=vid, max_test=5)
958 flow_match_test(self, config["port_map"], dl_vlan=4094, max_test=5)
Tatsuya Yabecdf575e2010-05-25 16:56:38 -0700959
Jeffrey Townsend2a300e42012-03-28 17:24:02 -0700960class SingleWildcardMatchPriority(BaseMatchCase):
Jeffrey Townsend50c82462012-03-28 18:26:14 -0700961 """
962 SingleWildcardMatchPriority
963 """
Jeffrey Townsend2a300e42012-03-28 17:24:02 -0700964
Jeffrey Townsend50c82462012-03-28 18:26:14 -0700965 def _Init(self):
Jeffrey Townsend2a300e42012-03-28 17:24:02 -0700966 self.pkt = simple_tcp_packet()
967 self.flowMsgs = {}
968
Jeffrey Townsend50c82462012-03-28 18:26:14 -0700969 def _ClearTable(self):
Rich Lane9a003812012-10-04 17:17:59 -0700970 rc = delete_all_flows(self.controller)
Jeffrey Townsend50c82462012-03-28 18:26:14 -0700971 self.assertEqual(rc, 0, "Failed to delete all flows")
Dan Talayco0fc08bd2012-04-09 16:56:18 -0700972 self.assertEqual(do_barrier(self.controller), 0, "Barrier failed")
Jeffrey Townsend50c82462012-03-28 18:26:14 -0700973
974 def runTest(self):
975
976 self._Init()
Rich Lane477f4812012-10-04 22:49:00 -0700977 of_ports = config["port_map"].keys()
Jeffrey Townsend2a300e42012-03-28 17:24:02 -0700978 of_ports.sort()
979
980 # Delete the initial flow table
Jeffrey Townsend50c82462012-03-28 18:26:14 -0700981 self._ClearTable()
Jeffrey Townsend2a300e42012-03-28 17:24:02 -0700982
983 # Run several combinations, each at lower priority settings.
984 # At the end of each call to runPrioFlows(), the table should
985 # be empty. If its not, we'll catch it as the priorities decreases
986 portA = of_ports[0]
987 portB = of_ports[1]
988 portC = of_ports[2]
989
990 # TODO -- these priority numbers should be validated somehow?
991 self.runPrioFlows(portA, portB, portC, 1000, 999)
992 self.runPrioFlows(portB, portC, portA, 998, 997)
993 self.runPrioFlows(portC, portA, portB, 996, 995)
994 self.runPrioFlows(portA, portC, portB, 994, 993)
995
996
Jeffrey Townsend50c82462012-03-28 18:26:14 -0700997
998 def runPrioFlows(self, portA, portB, portC, prioHigher, prioLower,
999 clearTable=False):
Jeffrey Townsend2a300e42012-03-28 17:24:02 -07001000
Jeffrey Townsend50c82462012-03-28 18:26:14 -07001001 if clearTable:
1002 self._ClearTable()
Jeffrey Townsend2a300e42012-03-28 17:24:02 -07001003
1004 # Sanity check flow at lower priority from pA to pB
Rich Lane9a003812012-10-04 17:17:59 -07001005 logging.info("runPrioFlows(pA=%d,pB=%d,pC=%d,ph=%d,pl=%d"
Jeffrey Townsend2a300e42012-03-28 17:24:02 -07001006 % (portA, portB, portC, prioHigher, prioLower))
1007
Jeffrey Townsend2a300e42012-03-28 17:24:02 -07001008 # Sanity check flow at lower priority from pA to pC
1009 self.installFlow(prioLower, portA, portC)
1010 self.verifyFlow(portA, portC)
1011 self.removeFlow(prioLower)
1012
1013 # Install and verify pA->pB @ prioLower
1014 self.installFlow(prioLower, portA, portB)
1015 self.verifyFlow(portA, portB)
1016
1017 # Install and verify pA->pC @ prioHigher, should override pA->pB
1018 self.installFlow(prioHigher, portA, portC)
1019 self.verifyFlow(portA, portC)
1020 # remove pA->pC
1021 self.removeFlow(prioHigher)
Jeffrey Townsend2a300e42012-03-28 17:24:02 -07001022 # Old flow pA -> pB @ prioLower should still be active
1023 self.verifyFlow(portA, portB)
1024 self.removeFlow(prioLower)
1025
1026 # Table should be empty at this point, leave it alone as
1027 # an assumption for future test runs
1028
1029
1030
Ed Swierk99a74de2012-08-22 06:40:54 -07001031 def installFlow(self, prio, inp, egp,
Jeffrey Townsend8364b162012-04-12 13:45:40 -07001032 wildcards=ofp.OFPFW_DL_SRC):
Ed Swierk99a74de2012-08-22 06:40:54 -07001033 wildcards |= required_wildcards(self)
Jeffrey Townsend2a300e42012-03-28 17:24:02 -07001034 request = flow_msg_create(self, self.pkt, ing_port=inp,
Jeffrey Townsend8364b162012-04-12 13:45:40 -07001035 wildcards=wildcards,
Jeffrey Townsend2a300e42012-03-28 17:24:02 -07001036 egr_ports=egp)
1037 request.priority = prio
Rich Lane9a003812012-10-04 17:17:59 -07001038 logging.debug("Install flow with priority " + str(prio))
Jeffrey Townsend50c82462012-03-28 18:26:14 -07001039 flow_msg_install(self, request, clear_table_override=False)
Jeffrey Townsend2a300e42012-03-28 17:24:02 -07001040 self.flowMsgs[prio] = request
1041
1042 def removeFlow(self, prio):
1043 if self.flowMsgs.has_key(prio):
1044 msg = self.flowMsgs[prio]
1045 msg.command = ofp.OFPFC_DELETE_STRICT
1046 # This *must* be set for DELETE
1047 msg.out_port = ofp.OFPP_NONE
Rich Lane9a003812012-10-04 17:17:59 -07001048 logging.debug("Remove flow with priority " + str(prio))
Jeffrey Townsend2a300e42012-03-28 17:24:02 -07001049 self.controller.message_send(msg)
Dan Talayco0fc08bd2012-04-09 16:56:18 -07001050 self.assertEqual(do_barrier(self.controller), 0, "Barrier failed")
Jeffrey Townsend50c82462012-03-28 18:26:14 -07001051 else:
1052 raise Exception("Not initialized")
Jeffrey Townsend2a300e42012-03-28 17:24:02 -07001053
1054
Jeffrey Townsend8364b162012-04-12 13:45:40 -07001055 def verifyFlow(self, inp, egp, pkt=None):
1056 if pkt == None:
1057 pkt = self.pkt
1058
Rich Lane9a003812012-10-04 17:17:59 -07001059 logging.info("Pkt match test: " + str(inp) + " to " + str(egp))
1060 logging.debug("Send packet: " + str(inp) + " to " + str(egp))
Jeffrey Townsend8364b162012-04-12 13:45:40 -07001061 self.dataplane.send(inp, str(pkt))
1062 receive_pkt_verify(self, egp, pkt, inp)
Jeffrey Townsend2a300e42012-03-28 17:24:02 -07001063
1064
1065
Jeffrey Townsend50c82462012-03-28 18:26:14 -07001066class SingleWildcardMatchPriorityInsertModifyDelete(SingleWildcardMatchPriority):
1067
1068 def runTest(self):
1069
1070 self._Init()
1071
Rich Lane477f4812012-10-04 22:49:00 -07001072 of_ports = config["port_map"].keys()
Jeffrey Townsend50c82462012-03-28 18:26:14 -07001073 of_ports.sort()
1074
1075 # Install an entry from 0 -> 1 @ prio 1000
1076 self._ClearTable()
1077 self.installFlow(1000, of_ports[0], of_ports[1])
1078 self.verifyFlow(of_ports[0], of_ports[1])
1079 self.installFlow(1000, of_ports[1], of_ports[0])
1080 self.verifyFlow(of_ports[1], of_ports[0])
1081 self.installFlow(1001, of_ports[0], of_ports[1])
1082 self.verifyFlow(of_ports[0], of_ports[1])
1083 self.installFlow(1001, of_ports[1], of_ports[0])
1084 self.verifyFlow(of_ports[1], of_ports[0])
1085 self.removeFlow(1001)
1086 self.verifyFlow(of_ports[0], of_ports[1])
1087 self.removeFlow(1000)
1088
1089
1090
Jeffrey Townsend8364b162012-04-12 13:45:40 -07001091class WildcardPriority(SingleWildcardMatchPriority):
Ken Chiang38d7a152012-05-24 15:33:50 -07001092 """
1093 1. Add wildcard flow, verify packet received.
1094 2. Add exact match flow with higher priority, verify packet received
1095 on port specified by this flow.
1096 3. Add wildcard flow with even higher priority, verify packet received
1097 on port specified by this flow.
1098 """
Jeffrey Townsend8364b162012-04-12 13:45:40 -07001099
1100 def runTest(self):
Jeffrey Townsend50c82462012-03-28 18:26:14 -07001101
Jeffrey Townsend8364b162012-04-12 13:45:40 -07001102 self._Init()
1103
Rich Lane477f4812012-10-04 22:49:00 -07001104 of_ports = config["port_map"].keys()
Jeffrey Townsend8364b162012-04-12 13:45:40 -07001105 of_ports.sort()
1106
1107 self._ClearTable()
Ken Chiang38d7a152012-05-24 15:33:50 -07001108
1109 # Install a flow with wildcards
1110 self.installFlow(999, of_ports[0], of_ports[1],
1111 wildcards=ofp.OFPFW_DL_DST)
Jeffrey Townsend8364b162012-04-12 13:45:40 -07001112 self.verifyFlow(of_ports[0], of_ports[1])
Ken Chiang38d7a152012-05-24 15:33:50 -07001113 # Install a flow with no wildcards for our packet
1114 self.installFlow(1000, of_ports[0], of_ports[2], wildcards=0)
Jeffrey Townsend8364b162012-04-12 13:45:40 -07001115 self.verifyFlow(of_ports[0], of_ports[2])
Ken Chiang38d7a152012-05-24 15:33:50 -07001116 # Install a flow with wildcards for our packet with higher
1117 # priority
1118 self.installFlow(1001, of_ports[0], of_ports[3])
1119 self.verifyFlow(of_ports[0], of_ports[3])
Jeffrey Townsend8364b162012-04-12 13:45:40 -07001120
1121
Ken Chiang3978f242012-06-13 14:14:09 -07001122class WildcardPriorityWithDelete(SingleWildcardMatchPriority):
Ken Chiang38d7a152012-05-24 15:33:50 -07001123 """
1124 1. Add exact match flow, verify packet received.
1125 2. Add wildcard flow with higher priority, verify packet received on port
1126 specified by this flow.
1127 3. Add exact match flow with even higher priority, verify packet received
1128 on port specified by this flow.
1129 4. Delete lowest priority flow, verify packet received on port specified
1130 by highest priority flow.
1131 5. Delete highest priority flow, verify packet received on port specified
1132 by remaining flow.
1133 """
1134
1135 def runTest(self):
1136
1137 self._Init()
1138
Rich Lane477f4812012-10-04 22:49:00 -07001139 of_ports = config["port_map"].keys()
Ken Chiang38d7a152012-05-24 15:33:50 -07001140 of_ports.sort()
1141
1142 self._ClearTable()
1143
1144 # Install an exact match flow
1145 self.installFlow(250, of_ports[0], of_ports[1], wildcards=0)
1146 self.verifyFlow(of_ports[0], of_ports[1])
1147 # Install a flow with wildcards of higher priority
1148 self.installFlow(1250, of_ports[0], of_ports[2],
1149 wildcards=ofp.OFPFW_DL_DST)
1150 self.verifyFlow(of_ports[0], of_ports[2])
1151 # Install an exact match flow with even higher priority
1152 self.installFlow(2001, of_ports[0], of_ports[3], wildcards=0)
1153 self.verifyFlow(of_ports[0], of_ports[3])
1154 # Delete lowest priority flow
1155 self.removeFlow(250)
1156 self.verifyFlow(of_ports[0], of_ports[3])
1157 # Delete highest priority flow
1158 self.removeFlow(2001)
1159 self.verifyFlow(of_ports[0], of_ports[2])
1160
Jeffrey Townsend8364b162012-04-12 13:45:40 -07001161
Dan Talayco551befa2010-07-15 17:05:32 -07001162class SingleWildcardMatch(BaseMatchCase):
Tatsuya Yabe6a6f38a2010-05-22 23:48:04 -07001163 """
1164 Exercise wildcard matching for all ports
1165
1166 Generate a packet
1167 Generate and install a matching flow with wildcard mask
1168 Add action to forward to a port
1169 Send the packet to the port
1170 Verify the packet is received at all other ports (one port at a time)
Tatsuya Yabe0718ad32010-05-24 15:22:10 -07001171 Verify flow_expiration message is correct when command option is set
Tatsuya Yabe6a6f38a2010-05-22 23:48:04 -07001172 """
Tatsuya Yabe0718ad32010-05-24 15:22:10 -07001173 def runTest(self):
Rich Lane2014f9b2012-10-05 15:29:40 -07001174 vid = test_param_get('vid', default=TEST_VID_DEFAULT)
Dan Talayco551befa2010-07-15 17:05:32 -07001175 for wc in WILDCARD_VALUES:
Ed Swierk99a74de2012-08-22 06:40:54 -07001176 wc |= required_wildcards(self)
Dan Talayco4431d542012-03-21 16:42:16 -07001177 if wc & ofp.OFPFW_DL_VLAN:
Ken Chiang5be06dd2012-04-03 10:03:50 -07001178 # Set nonzero VLAN id to avoid sending priority-tagged packet
1179 dl_vlan = vid
Dan Talayco4431d542012-03-21 16:42:16 -07001180 else:
1181 dl_vlan = -1
Rich Lane477f4812012-10-04 22:49:00 -07001182 flow_match_test(self, config["port_map"], wildcards=wc,
Dan Talayco4431d542012-03-21 16:42:16 -07001183 dl_vlan=dl_vlan, max_test=10)
Tatsuya Yabe4fad7e32010-05-24 15:24:50 -07001184
Dan Talayco551befa2010-07-15 17:05:32 -07001185class SingleWildcardMatchTagged(BaseMatchCase):
1186 """
1187 SingleWildcardMatch with tagged packets
1188 """
1189 def runTest(self):
Rich Lane2014f9b2012-10-05 15:29:40 -07001190 vid = test_param_get('vid', default=TEST_VID_DEFAULT)
Dan Talayco551befa2010-07-15 17:05:32 -07001191 for wc in WILDCARD_VALUES:
Ed Swierk99a74de2012-08-22 06:40:54 -07001192 wc |= required_wildcards(self)
Rich Lane477f4812012-10-04 22:49:00 -07001193 flow_match_test(self, config["port_map"], wildcards=wc, dl_vlan=vid,
Dan Talayco551befa2010-07-15 17:05:32 -07001194 max_test=10)
1195
1196class AllExceptOneWildcardMatch(BaseMatchCase):
Tatsuya Yabe4fad7e32010-05-24 15:24:50 -07001197 """
Dan Talayco80b54ed2010-07-13 09:48:35 -07001198 Match exactly one field
Tatsuya Yabe4fad7e32010-05-24 15:24:50 -07001199
1200 Generate a packet
1201 Generate and install a matching flow with wildcard all except one filed
1202 Add action to forward to a port
1203 Send the packet to the port
1204 Verify the packet is received at all other ports (one port at a time)
1205 Verify flow_expiration message is correct when command option is set
1206 """
1207 def runTest(self):
Rich Lane2014f9b2012-10-05 15:29:40 -07001208 vid = test_param_get('vid', default=TEST_VID_DEFAULT)
Dan Talayco488fbc52012-04-09 16:30:41 -07001209 for all_exp_one_wildcard in NO_WILDCARD_VALUES:
Ed Swierk99a74de2012-08-22 06:40:54 -07001210 all_exp_one_wildcard |= required_wildcards(self)
Dan Talayco4431d542012-03-21 16:42:16 -07001211 if all_exp_one_wildcard & ofp.OFPFW_DL_VLAN:
Ken Chiang5be06dd2012-04-03 10:03:50 -07001212 # Set nonzero VLAN id to avoid sending priority-tagged packet
1213 dl_vlan = vid
Dan Talayco4431d542012-03-21 16:42:16 -07001214 else:
1215 dl_vlan = -1
Rich Lane477f4812012-10-04 22:49:00 -07001216 flow_match_test(self, config["port_map"], wildcards=all_exp_one_wildcard,
Dan Talayco4431d542012-03-21 16:42:16 -07001217 dl_vlan=dl_vlan)
Tatsuya Yabee30ebe22010-05-25 09:30:49 -07001218
Dan Talayco551befa2010-07-15 17:05:32 -07001219class AllExceptOneWildcardMatchTagged(BaseMatchCase):
1220 """
1221 Match one field with tagged packets
1222 """
1223 def runTest(self):
Rich Lane2014f9b2012-10-05 15:29:40 -07001224 vid = test_param_get('vid', default=TEST_VID_DEFAULT)
Dan Talayco488fbc52012-04-09 16:30:41 -07001225 for all_exp_one_wildcard in NO_WILDCARD_VALUES:
Ed Swierk99a74de2012-08-22 06:40:54 -07001226 all_exp_one_wildcard |= required_wildcards(self)
Rich Lane477f4812012-10-04 22:49:00 -07001227 flow_match_test(self, config["port_map"], wildcards=all_exp_one_wildcard,
Dan Talayco21381562010-07-17 00:34:47 -07001228 dl_vlan=vid)
Dan Talayco551befa2010-07-15 17:05:32 -07001229
1230class AllWildcardMatch(BaseMatchCase):
Tatsuya Yabee30ebe22010-05-25 09:30:49 -07001231 """
1232 Create Wildcard-all flow and exercise for all ports
1233
1234 Generate a packet
1235 Generate and install a matching flow with wildcard-all
1236 Add action to forward to a port
1237 Send the packet to the port
1238 Verify the packet is received at all other ports (one port at a time)
1239 Verify flow_expiration message is correct when command option is set
1240 """
1241 def runTest(self):
Rich Lane477f4812012-10-04 22:49:00 -07001242 flow_match_test(self, config["port_map"], wildcards=ofp.OFPFW_ALL)
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -07001243
Dan Talayco551befa2010-07-15 17:05:32 -07001244class AllWildcardMatchTagged(BaseMatchCase):
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -07001245 """
Dan Talayco551befa2010-07-15 17:05:32 -07001246 AllWildcardMatch with tagged packets
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -07001247 """
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -07001248 def runTest(self):
Rich Lane2014f9b2012-10-05 15:29:40 -07001249 vid = test_param_get('vid', default=TEST_VID_DEFAULT)
Rich Lane477f4812012-10-04 22:49:00 -07001250 flow_match_test(self, config["port_map"], wildcards=ofp.OFPFW_ALL,
Dan Talayco21381562010-07-17 00:34:47 -07001251 dl_vlan=vid)
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -07001252
Dan Talaycoba3745c2010-07-21 21:51:08 -07001253
Dan Talayco551befa2010-07-15 17:05:32 -07001254class AddVLANTag(BaseMatchCase):
1255 """
1256 Add a VLAN tag to an untagged packet
1257 """
1258 def runTest(self):
1259 new_vid = 2
Ed Swierkc7193a22012-08-22 06:51:02 -07001260 sup_acts = self.supported_actions
Dan Talayco551befa2010-07-15 17:05:32 -07001261 if not(sup_acts & 1<<ofp.OFPAT_SET_VLAN_VID):
Dan Talaycoba3745c2010-07-21 21:51:08 -07001262 skip_message_emit(self, "Add VLAN tag test")
Dan Talaycof36f1082010-07-13 13:57:17 -07001263 return
Tatsuya Yabef5ffb972010-05-26 15:36:33 -07001264
Dan Talayco551befa2010-07-15 17:05:32 -07001265 len = 100
1266 len_w_vid = 104
1267 pkt = simple_tcp_packet(pktlen=len)
1268 exp_pkt = simple_tcp_packet(pktlen=len_w_vid, dl_vlan_enable=True,
1269 dl_vlan=new_vid)
1270 vid_act = action.action_set_vlan_vid()
1271 vid_act.vlan_vid = new_vid
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -07001272
Rich Lane477f4812012-10-04 22:49:00 -07001273 flow_match_test(self, config["port_map"], pkt=pkt,
Dan Talayco551befa2010-07-15 17:05:32 -07001274 exp_pkt=exp_pkt, action_list=[vid_act])
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -07001275
Rich Laneb90a1c42012-10-05 09:16:05 -07001276class PacketOnly(base_tests.DataPlaneOnly):
Dan Talayco551befa2010-07-15 17:05:32 -07001277 """
1278 Just send a packet thru the switch
1279 """
Rich Laned1d9c282012-10-04 22:07:10 -07001280
1281 priority = -1
1282
Dan Talayco551befa2010-07-15 17:05:32 -07001283 def runTest(self):
1284 pkt = simple_tcp_packet()
Rich Lane477f4812012-10-04 22:49:00 -07001285 of_ports = config["port_map"].keys()
Dan Talayco551befa2010-07-15 17:05:32 -07001286 of_ports.sort()
1287 ing_port = of_ports[0]
Rich Lane9a003812012-10-04 17:17:59 -07001288 logging.info("Sending packet to " + str(ing_port))
1289 logging.debug("Data: " + str(pkt).encode('hex'))
Dan Talayco551befa2010-07-15 17:05:32 -07001290 self.dataplane.send(ing_port, str(pkt))
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -07001291
Rich Laneb90a1c42012-10-05 09:16:05 -07001292class PacketOnlyTagged(base_tests.DataPlaneOnly):
Dan Talayco551befa2010-07-15 17:05:32 -07001293 """
1294 Just send a packet thru the switch
1295 """
Rich Laned1d9c282012-10-04 22:07:10 -07001296
1297 priority = -1
1298
Dan Talayco551befa2010-07-15 17:05:32 -07001299 def runTest(self):
Rich Lane2014f9b2012-10-05 15:29:40 -07001300 vid = test_param_get('vid', default=TEST_VID_DEFAULT)
Dan Talayco551befa2010-07-15 17:05:32 -07001301 pkt = simple_tcp_packet(dl_vlan_enable=True, dl_vlan=vid)
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
Dan Talayco551befa2010-07-15 17:05:32 -07001309class ModifyVID(BaseMatchCase):
Dan Talayco4b2bee62010-07-20 14:10:05 -07001310 """
1311 Modify the VLAN ID in the VLAN tag of a tagged packet
1312 """
Dan Talaycoaf669322012-09-12 22:51:22 -07001313 def setUp(self):
1314 BaseMatchCase.setUp(self)
1315 self.ing_port=False
1316
Dan Talayco551befa2010-07-15 17:05:32 -07001317 def runTest(self):
1318 old_vid = 2
1319 new_vid = 3
Ed Swierkc7193a22012-08-22 06:51:02 -07001320 sup_acts = self.supported_actions
Dan Talayco4b2bee62010-07-20 14:10:05 -07001321 if not (sup_acts & 1 << ofp.OFPAT_SET_VLAN_VID):
Dan Talaycoba3745c2010-07-21 21:51:08 -07001322 skip_message_emit(self, "Modify VLAN tag test")
Dan Talayco551befa2010-07-15 17:05:32 -07001323 return
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -07001324
Dan Talayco551befa2010-07-15 17:05:32 -07001325 pkt = simple_tcp_packet(dl_vlan_enable=True, dl_vlan=old_vid)
1326 exp_pkt = simple_tcp_packet(dl_vlan_enable=True, dl_vlan=new_vid)
1327 vid_act = action.action_set_vlan_vid()
1328 vid_act.vlan_vid = new_vid
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -07001329
Rich Lane477f4812012-10-04 22:49:00 -07001330 flow_match_test(self, config["port_map"], pkt=pkt, exp_pkt=exp_pkt,
Dan Talaycoaf669322012-09-12 22:51:22 -07001331 action_list=[vid_act], ing_port=self.ing_port)
1332
1333class ModifyVIDToIngress(ModifyVID):
1334 """
1335 Modify the VLAN ID in the VLAN tag of a tagged packet and send to
1336 ingress port
1337 """
1338 def setUp(self):
1339 BaseMatchCase.setUp(self)
1340 self.ing_port=True
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -07001341
Ken Chiange9a211d2012-04-20 14:52:11 -07001342class ModifyVIDWithTagMatchWildcarded(BaseMatchCase):
1343 """
1344 With vlan ID and priority wildcarded, perform SET_VLAN_VID action.
1345 The same flow should match on both untagged and tagged packets.
1346 """
1347 def runTest(self):
1348 old_vid = 2
1349 new_vid = 3
Ed Swierkc7193a22012-08-22 06:51:02 -07001350 sup_acts = self.supported_actions
Ken Chiange9a211d2012-04-20 14:52:11 -07001351 if not (sup_acts & 1 << ofp.OFPAT_SET_VLAN_VID):
1352 skip_message_emit(self, "ModifyVIDWithTagWildcarded test")
1353 return
1354
Rich Lane477f4812012-10-04 22:49:00 -07001355 of_ports = config["port_map"].keys()
Ken Chiange9a211d2012-04-20 14:52:11 -07001356 self.assertTrue(len(of_ports) > 1, "Not enough ports for test")
1357 ing_port = of_ports[0]
1358 egr_ports = of_ports[1]
1359
Rich Lane9a003812012-10-04 17:17:59 -07001360 rv = delete_all_flows(self.controller)
Ken Chiange9a211d2012-04-20 14:52:11 -07001361 self.assertEqual(rv, 0, "Failed to delete all flows")
1362
1363 len_untagged = 100
1364 len_w_vid = 104
1365 untagged_pkt = simple_tcp_packet(pktlen=len_untagged)
1366 tagged_pkt = simple_tcp_packet(pktlen=len_w_vid,
1367 dl_vlan_enable=True, dl_vlan=old_vid)
1368 exp_pkt = simple_tcp_packet(pktlen=len_w_vid, dl_vlan_enable=True,
1369 dl_vlan=new_vid)
Ed Swierk99a74de2012-08-22 06:40:54 -07001370 wildcards = (required_wildcards(self) | ofp.OFPFW_DL_VLAN |
1371 ofp.OFPFW_DL_VLAN_PCP)
Ken Chiange9a211d2012-04-20 14:52:11 -07001372 vid_act = action.action_set_vlan_vid()
1373 vid_act.vlan_vid = new_vid
1374 request = flow_msg_create(self, untagged_pkt, ing_port=ing_port,
1375 wildcards=wildcards, egr_ports=egr_ports,
1376 action_list=[vid_act])
1377 flow_msg_install(self, request)
1378
Rich Lane9a003812012-10-04 17:17:59 -07001379 logging.debug("Send untagged packet: " + str(ing_port) + " to " +
Ken Chiange9a211d2012-04-20 14:52:11 -07001380 str(egr_ports))
1381 self.dataplane.send(ing_port, str(untagged_pkt))
1382 receive_pkt_verify(self, egr_ports, exp_pkt, ing_port)
1383
Rich Lane9a003812012-10-04 17:17:59 -07001384 logging.debug("Send tagged packet: " + str(ing_port) + " to " +
Ken Chiange9a211d2012-04-20 14:52:11 -07001385 str(egr_ports))
1386 self.dataplane.send(ing_port, str(tagged_pkt))
1387 receive_pkt_verify(self, egr_ports, exp_pkt, ing_port)
1388
Howard Pershc1199d52012-04-11 14:21:32 -07001389class ModifyVlanPcp(BaseMatchCase):
1390 """
1391 Modify the priority field of the VLAN tag of a tagged packet
1392 """
1393 def runTest(self):
1394 vid = 123
1395 old_vlan_pcp = 2
1396 new_vlan_pcp = 3
Ed Swierkc7193a22012-08-22 06:51:02 -07001397 sup_acts = self.supported_actions
Ed Swierk8c3af7f2012-04-24 14:19:17 -07001398 if not (sup_acts & 1 << ofp.OFPAT_SET_VLAN_PCP):
1399 skip_message_emit(self, "Modify VLAN priority test")
Howard Pershc1199d52012-04-11 14:21:32 -07001400 return
1401
1402 pkt = simple_tcp_packet(dl_vlan_enable=True, dl_vlan=vid, dl_vlan_pcp=old_vlan_pcp)
1403 exp_pkt = simple_tcp_packet(dl_vlan_enable=True, dl_vlan=vid, dl_vlan_pcp=new_vlan_pcp)
1404 vid_act = action.action_set_vlan_pcp()
1405 vid_act.vlan_pcp = new_vlan_pcp
1406
Rich Lane477f4812012-10-04 22:49:00 -07001407 flow_match_test(self, config["port_map"], pkt=pkt, exp_pkt=exp_pkt,
Howard Pershc1199d52012-04-11 14:21:32 -07001408 action_list=[vid_act])
1409
Dan Talayco551befa2010-07-15 17:05:32 -07001410class StripVLANTag(BaseMatchCase):
Dan Talayco4b2bee62010-07-20 14:10:05 -07001411 """
1412 Strip the VLAN tag from a tagged packet
1413 """
Dan Talayco551befa2010-07-15 17:05:32 -07001414 def runTest(self):
1415 old_vid = 2
Ed Swierkc7193a22012-08-22 06:51:02 -07001416 sup_acts = self.supported_actions
Dan Talayco4b2bee62010-07-20 14:10:05 -07001417 if not (sup_acts & 1 << ofp.OFPAT_STRIP_VLAN):
Dan Talaycoba3745c2010-07-21 21:51:08 -07001418 skip_message_emit(self, "Strip VLAN tag test")
Dan Talayco551befa2010-07-15 17:05:32 -07001419 return
Dan Talaycof36f1082010-07-13 13:57:17 -07001420
Dan Talayco551befa2010-07-15 17:05:32 -07001421 len_w_vid = 104
1422 len = 100
1423 pkt = simple_tcp_packet(pktlen=len_w_vid, dl_vlan_enable=True,
1424 dl_vlan=old_vid)
1425 exp_pkt = simple_tcp_packet(pktlen=len)
1426 vid_act = action.action_strip_vlan()
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -07001427
Rich Lane477f4812012-10-04 22:49:00 -07001428 flow_match_test(self, config["port_map"], pkt=pkt, exp_pkt=exp_pkt,
Dan Talayco551befa2010-07-15 17:05:32 -07001429 action_list=[vid_act])
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -07001430
Ken Chiange9a211d2012-04-20 14:52:11 -07001431class StripVLANTagWithTagMatchWildcarded(BaseMatchCase):
1432 """
1433 Strip the VLAN tag from a tagged packet.
1434 Differs from StripVLANTag in that VID and PCP are both wildcarded.
1435 """
1436 def runTest(self):
1437 old_vid = 2
Ed Swierkc7193a22012-08-22 06:51:02 -07001438 sup_acts = self.supported_actions
Ken Chiange9a211d2012-04-20 14:52:11 -07001439 if not (sup_acts & 1 << ofp.OFPAT_STRIP_VLAN):
1440 skip_message_emit(self, "StripVLANTagWithTagWildcarded test")
1441 return
1442
1443 len_w_vid = 104
1444 len_untagged = 100
1445 pkt = simple_tcp_packet(pktlen=len_w_vid, dl_vlan_enable=True,
1446 dl_vlan=old_vid)
1447 exp_pkt = simple_tcp_packet(pktlen=len_untagged)
Ed Swierk99a74de2012-08-22 06:40:54 -07001448 wildcards = (required_wildcards(self) | ofp.OFPFW_DL_VLAN |
1449 ofp.OFPFW_DL_VLAN_PCP)
Ken Chiange9a211d2012-04-20 14:52:11 -07001450 vid_act = action.action_strip_vlan()
1451
Rich Lane477f4812012-10-04 22:49:00 -07001452 flow_match_test(self, config["port_map"],
Ed Swierk99a74de2012-08-22 06:40:54 -07001453 wildcards=wildcards,
Ken Chiange9a211d2012-04-20 14:52:11 -07001454 pkt=pkt, exp_pkt=exp_pkt,
1455 action_list=[vid_act])
1456
Dan Talayco4b2bee62010-07-20 14:10:05 -07001457def init_pkt_args():
1458 """
1459 Pass back a dictionary with default packet arguments
1460 """
1461 args = {}
1462 args["dl_src"] = '00:23:45:67:89:AB'
1463
1464 dl_vlan_enable=False
1465 dl_vlan=-1
Rich Lane477f4812012-10-04 22:49:00 -07001466 if config["test-params"]["vid"]:
Dan Talayco4b2bee62010-07-20 14:10:05 -07001467 dl_vlan_enable=True
Rich Lane477f4812012-10-04 22:49:00 -07001468 dl_vlan = config["test-params"]["vid"]
Dan Talayco4b2bee62010-07-20 14:10:05 -07001469
1470# Unpack operator is ** on a dictionary
1471
1472 return args
1473
Dan Talayco551befa2010-07-15 17:05:32 -07001474class ModifyL2Src(BaseMatchCase):
Dan Talayco4b2bee62010-07-20 14:10:05 -07001475 """
1476 Modify the source MAC address (TP1)
1477 """
Dan Talayco551befa2010-07-15 17:05:32 -07001478 def runTest(self):
Ed Swierkc7193a22012-08-22 06:51:02 -07001479 sup_acts = self.supported_actions
Dan Talayco4b2bee62010-07-20 14:10:05 -07001480 if not (sup_acts & 1 << ofp.OFPAT_SET_DL_SRC):
Dan Talaycoba3745c2010-07-21 21:51:08 -07001481 skip_message_emit(self, "ModifyL2Src test")
Dan Talayco4b2bee62010-07-20 14:10:05 -07001482 return
1483
1484 (pkt, exp_pkt, acts) = pkt_action_setup(self, mod_fields=['dl_src'],
1485 check_test_params=True)
Rich Lane477f4812012-10-04 22:49:00 -07001486 flow_match_test(self, config["port_map"], pkt=pkt, exp_pkt=exp_pkt,
Dan Talayco4b2bee62010-07-20 14:10:05 -07001487 action_list=acts, max_test=2)
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -07001488
Dan Talayco551befa2010-07-15 17:05:32 -07001489class ModifyL2Dst(BaseMatchCase):
Dan Talayco4b2bee62010-07-20 14:10:05 -07001490 """
1491 Modify the dest MAC address (TP1)
1492 """
Dan Talayco551befa2010-07-15 17:05:32 -07001493 def runTest(self):
Ed Swierkc7193a22012-08-22 06:51:02 -07001494 sup_acts = self.supported_actions
Dan Talayco4b2bee62010-07-20 14:10:05 -07001495 if not (sup_acts & 1 << ofp.OFPAT_SET_DL_DST):
Dan Talaycoba3745c2010-07-21 21:51:08 -07001496 skip_message_emit(self, "ModifyL2dst test")
Dan Talayco4b2bee62010-07-20 14:10:05 -07001497 return
1498
1499 (pkt, exp_pkt, acts) = pkt_action_setup(self, mod_fields=['dl_dst'],
1500 check_test_params=True)
Rich Lane477f4812012-10-04 22:49:00 -07001501 flow_match_test(self, config["port_map"], pkt=pkt, exp_pkt=exp_pkt,
Dan Talayco4b2bee62010-07-20 14:10:05 -07001502 action_list=acts, max_test=2)
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -07001503
Dan Talayco551befa2010-07-15 17:05:32 -07001504class ModifyL3Src(BaseMatchCase):
Dan Talayco4b2bee62010-07-20 14:10:05 -07001505 """
1506 Modify the source IP address of an IP packet (TP1)
1507 """
Dan Talayco551befa2010-07-15 17:05:32 -07001508 def runTest(self):
Ed Swierkc7193a22012-08-22 06:51:02 -07001509 sup_acts = self.supported_actions
Dan Talayco4b2bee62010-07-20 14:10:05 -07001510 if not (sup_acts & 1 << ofp.OFPAT_SET_NW_SRC):
Dan Talaycoba3745c2010-07-21 21:51:08 -07001511 skip_message_emit(self, "ModifyL3Src test")
Dan Talayco4b2bee62010-07-20 14:10:05 -07001512 return
1513
1514 (pkt, exp_pkt, acts) = pkt_action_setup(self, mod_fields=['ip_src'],
1515 check_test_params=True)
Rich Lane477f4812012-10-04 22:49:00 -07001516 flow_match_test(self, config["port_map"], pkt=pkt, exp_pkt=exp_pkt,
Dan Talayco4b2bee62010-07-20 14:10:05 -07001517 action_list=acts, max_test=2)
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -07001518
Dan Talayco551befa2010-07-15 17:05:32 -07001519class ModifyL3Dst(BaseMatchCase):
Dan Talayco4b2bee62010-07-20 14:10:05 -07001520 """
1521 Modify the dest IP address of an IP packet (TP1)
1522 """
Dan Talayco551befa2010-07-15 17:05:32 -07001523 def runTest(self):
Ed Swierkc7193a22012-08-22 06:51:02 -07001524 sup_acts = self.supported_actions
Dan Talayco4b2bee62010-07-20 14:10:05 -07001525 if not (sup_acts & 1 << ofp.OFPAT_SET_NW_DST):
Dan Talaycoba3745c2010-07-21 21:51:08 -07001526 skip_message_emit(self, "ModifyL3Dst test")
Dan Talayco4b2bee62010-07-20 14:10:05 -07001527 return
1528
1529 (pkt, exp_pkt, acts) = pkt_action_setup(self, mod_fields=['ip_dst'],
1530 check_test_params=True)
Rich Lane477f4812012-10-04 22:49:00 -07001531 flow_match_test(self, config["port_map"], pkt=pkt, exp_pkt=exp_pkt,
Dan Talayco4b2bee62010-07-20 14:10:05 -07001532 action_list=acts, max_test=2)
Dan Talayco551befa2010-07-15 17:05:32 -07001533
1534class ModifyL4Src(BaseMatchCase):
Dan Talayco4b2bee62010-07-20 14:10:05 -07001535 """
1536 Modify the source TCP port of a TCP packet (TP1)
1537 """
Dan Talayco551befa2010-07-15 17:05:32 -07001538 def runTest(self):
Ed Swierkc7193a22012-08-22 06:51:02 -07001539 sup_acts = self.supported_actions
Dan Talayco4b2bee62010-07-20 14:10:05 -07001540 if not (sup_acts & 1 << ofp.OFPAT_SET_TP_SRC):
Dan Talaycoba3745c2010-07-21 21:51:08 -07001541 skip_message_emit(self, "ModifyL4Src test")
Dan Talayco4b2bee62010-07-20 14:10:05 -07001542 return
1543
1544 (pkt, exp_pkt, acts) = pkt_action_setup(self, mod_fields=['tcp_sport'],
1545 check_test_params=True)
Rich Lane477f4812012-10-04 22:49:00 -07001546 flow_match_test(self, config["port_map"], pkt=pkt, exp_pkt=exp_pkt,
Dan Talayco4b2bee62010-07-20 14:10:05 -07001547 action_list=acts, max_test=2)
Dan Talayco551befa2010-07-15 17:05:32 -07001548
Rich Lane01c2b862012-10-26 16:26:25 -07001549class ModifyL4SrcUdp(BaseMatchCase):
1550 """
1551 Modify the source UDP port of a UDP packet
1552 """
1553 def runTest(self):
1554 sup_acts = self.supported_actions
1555 if not (sup_acts & 1 << ofp.OFPAT_SET_TP_DST):
1556 skip_message_emit(self, "ModifyL4SrcUdp test")
1557 return
1558
1559 (pkt, exp_pkt, acts) = pkt_action_setup(self, mod_fields=['udp_sport'],
1560 check_test_params=True, tp="udp")
1561 flow_match_test(self, config["port_map"], pkt=pkt, exp_pkt=exp_pkt,
1562 action_list=acts, max_test=2)
1563
Dan Talayco551befa2010-07-15 17:05:32 -07001564class ModifyL4Dst(BaseMatchCase):
Dan Talayco4b2bee62010-07-20 14:10:05 -07001565 """
1566 Modify the dest TCP port of a TCP packet (TP1)
1567 """
Dan Talayco551befa2010-07-15 17:05:32 -07001568 def runTest(self):
Ed Swierkc7193a22012-08-22 06:51:02 -07001569 sup_acts = self.supported_actions
Dan Talayco4b2bee62010-07-20 14:10:05 -07001570 if not (sup_acts & 1 << ofp.OFPAT_SET_TP_DST):
Dan Talaycoba3745c2010-07-21 21:51:08 -07001571 skip_message_emit(self, "ModifyL4Dst test")
Dan Talayco4b2bee62010-07-20 14:10:05 -07001572 return
1573
1574 (pkt, exp_pkt, acts) = pkt_action_setup(self, mod_fields=['tcp_dport'],
1575 check_test_params=True)
Rich Lane477f4812012-10-04 22:49:00 -07001576 flow_match_test(self, config["port_map"], pkt=pkt, exp_pkt=exp_pkt,
Dan Talayco4b2bee62010-07-20 14:10:05 -07001577 action_list=acts, max_test=2)
Dan Talayco551befa2010-07-15 17:05:32 -07001578
Rich Lane01c2b862012-10-26 16:26:25 -07001579class ModifyL4DstUdp(BaseMatchCase):
1580 """
1581 Modify the dest UDP port of a UDP packet
1582 """
1583 def runTest(self):
1584 sup_acts = self.supported_actions
1585 if not (sup_acts & 1 << ofp.OFPAT_SET_TP_DST):
1586 skip_message_emit(self, "ModifyL4DstUdp test")
1587 return
1588
1589 (pkt, exp_pkt, acts) = pkt_action_setup(self, mod_fields=['udp_dport'],
1590 check_test_params=True, tp="udp")
1591 flow_match_test(self, config["port_map"], pkt=pkt, exp_pkt=exp_pkt,
1592 action_list=acts, max_test=2)
1593
Dan Talayco551befa2010-07-15 17:05:32 -07001594class ModifyTOS(BaseMatchCase):
Dan Talayco4b2bee62010-07-20 14:10:05 -07001595 """
1596 Modify the IP type of service of an IP packet (TP1)
1597 """
Dan Talayco551befa2010-07-15 17:05:32 -07001598 def runTest(self):
Ed Swierkc7193a22012-08-22 06:51:02 -07001599 sup_acts = self.supported_actions
Dan Talayco4b2bee62010-07-20 14:10:05 -07001600 if not (sup_acts & 1 << ofp.OFPAT_SET_NW_TOS):
Dan Talaycoba3745c2010-07-21 21:51:08 -07001601 skip_message_emit(self, "ModifyTOS test")
Dan Talayco4b2bee62010-07-20 14:10:05 -07001602 return
Dan Talayco551befa2010-07-15 17:05:32 -07001603
Dan Talayco4b2bee62010-07-20 14:10:05 -07001604 (pkt, exp_pkt, acts) = pkt_action_setup(self, mod_fields=['ip_tos'],
1605 check_test_params=True)
Rich Lane477f4812012-10-04 22:49:00 -07001606 flow_match_test(self, config["port_map"], pkt=pkt, exp_pkt=exp_pkt,
Dan Talaycocfa172f2012-03-23 12:03:00 -07001607 action_list=acts, max_test=2, egr_count=-1)
Dan Talayco551befa2010-07-15 17:05:32 -07001608
Dan Talaycof6e76c02012-03-23 10:56:12 -07001609class ModifyL2DstMC(BaseMatchCase):
1610 """
1611 Modify the L2 dest and send to 2 ports
Dan Talaycof6e76c02012-03-23 10:56:12 -07001612 """
1613 def runTest(self):
Ed Swierkc7193a22012-08-22 06:51:02 -07001614 sup_acts = self.supported_actions
Dan Talaycof6e76c02012-03-23 10:56:12 -07001615 if not (sup_acts & 1 << ofp.OFPAT_SET_DL_DST):
Dan Talaycocfa172f2012-03-23 12:03:00 -07001616 skip_message_emit(self, "ModifyL2dstMC test")
Dan Talaycof6e76c02012-03-23 10:56:12 -07001617 return
1618
Dan Talaycof6e76c02012-03-23 10:56:12 -07001619 (pkt, exp_pkt, acts) = pkt_action_setup(self, mod_fields=['dl_dst'],
1620 check_test_params=True)
Rich Lane477f4812012-10-04 22:49:00 -07001621 flow_match_test(self, config["port_map"], pkt=pkt, exp_pkt=exp_pkt,
Dan Talaycocfa172f2012-03-23 12:03:00 -07001622 action_list=acts, max_test=2, egr_count=-1)
Dan Talaycof6e76c02012-03-23 10:56:12 -07001623
Dan Talaycoc948d0b2012-03-23 12:17:54 -07001624class ModifyL2DstIngress(BaseMatchCase):
1625 """
1626 Modify the L2 dest and send to the ingress port
1627 """
1628 def runTest(self):
Ed Swierkc7193a22012-08-22 06:51:02 -07001629 sup_acts = self.supported_actions
Dan Talaycoc948d0b2012-03-23 12:17:54 -07001630 if not (sup_acts & 1 << ofp.OFPAT_SET_DL_DST):
Dan Talaycoabbfdbb2012-04-05 10:29:26 -07001631 skip_message_emit(self, "ModifyL2dstIngress test")
Dan Talaycoc948d0b2012-03-23 12:17:54 -07001632 return
1633
1634 (pkt, exp_pkt, acts) = pkt_action_setup(self, mod_fields=['dl_dst'],
1635 check_test_params=True)
Rich Lane477f4812012-10-04 22:49:00 -07001636 flow_match_test(self, config["port_map"], pkt=pkt, exp_pkt=exp_pkt,
Dan Talaycoc948d0b2012-03-23 12:17:54 -07001637 action_list=acts, max_test=2, egr_count=0,
1638 ing_port=True)
1639
Dan Talaycod8ae7582012-03-23 12:24:56 -07001640class ModifyL2DstIngressMC(BaseMatchCase):
1641 """
1642 Modify the L2 dest and send to the ingress port
1643 """
1644 def runTest(self):
Ed Swierkc7193a22012-08-22 06:51:02 -07001645 sup_acts = self.supported_actions
Dan Talaycod8ae7582012-03-23 12:24:56 -07001646 if not (sup_acts & 1 << ofp.OFPAT_SET_DL_DST):
1647 skip_message_emit(self, "ModifyL2dstMC test")
1648 return
1649
1650 (pkt, exp_pkt, acts) = pkt_action_setup(self, mod_fields=['dl_dst'],
1651 check_test_params=True)
Rich Lane477f4812012-10-04 22:49:00 -07001652 flow_match_test(self, config["port_map"], pkt=pkt, exp_pkt=exp_pkt,
Dan Talaycod8ae7582012-03-23 12:24:56 -07001653 action_list=acts, max_test=2, egr_count=-1,
1654 ing_port=True)
1655
Dan Talaycof6e76c02012-03-23 10:56:12 -07001656class ModifyL2SrcMC(BaseMatchCase):
1657 """
1658 Modify the source MAC address (TP1) and send to multiple
Dan Talaycof6e76c02012-03-23 10:56:12 -07001659 """
1660 def runTest(self):
Ed Swierkc7193a22012-08-22 06:51:02 -07001661 sup_acts = self.supported_actions
Dan Talaycof6e76c02012-03-23 10:56:12 -07001662 if not (sup_acts & 1 << ofp.OFPAT_SET_DL_SRC):
Dan Talaycocfa172f2012-03-23 12:03:00 -07001663 skip_message_emit(self, "ModifyL2SrcMC test")
Dan Talaycof6e76c02012-03-23 10:56:12 -07001664 return
1665
Dan Talaycof6e76c02012-03-23 10:56:12 -07001666 (pkt, exp_pkt, acts) = pkt_action_setup(self, mod_fields=['dl_src'],
1667 check_test_params=True)
Rich Lane477f4812012-10-04 22:49:00 -07001668 flow_match_test(self, config["port_map"], pkt=pkt, exp_pkt=exp_pkt,
Dan Talaycocfa172f2012-03-23 12:03:00 -07001669 action_list=acts, max_test=2, egr_count=-1)
Dan Talaycof6e76c02012-03-23 10:56:12 -07001670
1671class ModifyL2SrcDstMC(BaseMatchCase):
1672 """
1673 Modify the L2 source and dest and send to 2 ports
Dan Talaycof6e76c02012-03-23 10:56:12 -07001674 """
1675 def runTest(self):
Ed Swierkc7193a22012-08-22 06:51:02 -07001676 sup_acts = self.supported_actions
Dan Talaycocfa172f2012-03-23 12:03:00 -07001677 if (not (sup_acts & 1 << ofp.OFPAT_SET_DL_DST) or
1678 not (sup_acts & 1 << ofp.OFPAT_SET_DL_SRC)):
1679 skip_message_emit(self, "ModifyL2SrcDstMC test")
Dan Talaycof6e76c02012-03-23 10:56:12 -07001680 return
1681
Dan Talaycof6e76c02012-03-23 10:56:12 -07001682 mod_fields = ['dl_dst', 'dl_src']
1683 (pkt, exp_pkt, acts) = pkt_action_setup(self, mod_fields=mod_fields,
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)
1687
1688class ModifyL2DstVIDMC(BaseMatchCase):
1689 """
1690 Modify the L2 dest and send to 2 ports
1691 """
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_VLAN_VID)):
1696 skip_message_emit(self, "ModifyL2DstVIDMC test")
1697 return
1698
1699 mod_fields = ['dl_dst', 'dl_vlan']
1700 (pkt, exp_pkt, acts) = pkt_action_setup(self,
1701 start_field_vals={'dl_vlan_enable':True}, mod_fields=mod_fields,
1702 check_test_params=True)
Rich Lane477f4812012-10-04 22:49:00 -07001703 flow_match_test(self, config["port_map"], pkt=pkt, exp_pkt=exp_pkt,
Dan Talaycocfa172f2012-03-23 12:03:00 -07001704 action_list=acts, max_test=2, egr_count=-1)
Dan Talaycof6e76c02012-03-23 10:56:12 -07001705
Rich Lane22e74c12012-11-12 15:06:06 -08001706class ModifyAll(BaseMatchCase):
1707 """
1708 Modify all supported fields and output to a port
1709 """
1710 def runTest(self):
1711 sup_acts = self.supported_actions
1712
1713 sup_map = {
1714 "dl_dst" : ofp.OFPAT_SET_DL_DST,
1715 "dl_src" : ofp.OFPAT_SET_DL_SRC,
1716 "dl_vlan_enable" : ofp.OFPAT_SET_VLAN_VID,
1717 "dl_vlan" : ofp.OFPAT_SET_VLAN_VID,
1718 "dl_vlan_pcp" : ofp.OFPAT_SET_VLAN_PCP,
1719 "ip_src" : ofp.OFPAT_SET_NW_SRC,
1720 "ip_dst" : ofp.OFPAT_SET_NW_DST,
1721 "ip_tos" : ofp.OFPAT_SET_NW_TOS,
1722 "tcp_sport" : ofp.OFPAT_SET_TP_SRC,
1723 "tcp_dport" : ofp.OFPAT_SET_TP_DST,
1724 }
1725
1726 mod_fields = [field for (field, bit) in sup_map.items() if (sup_acts & 1 << bit)]
1727 random.shuffle(mod_fields)
1728 start_field_vals = { "dl_vlan_enable" : True }
1729 mod_field_vals = { "dl_vlan_enable" : True }
1730 logging.info("modifying fields: %s" % repr(mod_fields))
1731
1732 (pkt, exp_pkt, acts) = pkt_action_setup(self,
1733 mod_fields=mod_fields,
1734 start_field_vals=start_field_vals,
1735 mod_field_vals=mod_field_vals,
1736 check_test_params=True)
1737 flow_match_test(self, config["port_map"], pkt=pkt, exp_pkt=exp_pkt,
1738 action_list=acts, max_test=2)
1739
Dan Talaycofa6454f2012-04-05 10:04:13 -07001740class FlowToggle(BaseMatchCase):
1741 """
1742 Add flows to the table and modify them repeatedly
Dan Talaycof7c41312012-07-23 12:53:19 -07001743
1744 This is done by using only "add" flow messages. Since the check overlap
1745 flag is not set, the switch is supposed to modify the existing flow if
1746 the match already exists.
1747
1748 Would probably be better to exercise more of the flow modify commands
1749 (add, modify, delete +/- strict).
Dan Talaycofa6454f2012-04-05 10:04:13 -07001750 """
1751 def runTest(self):
Rich Lane2014f9b2012-10-05 15:29:40 -07001752 flow_count = test_param_get('ft_flow_count', default=20)
1753 iter_count = test_param_get('ft_iter_count', default=10)
Dan Talaycofa6454f2012-04-05 10:04:13 -07001754
Rich Lane9a003812012-10-04 17:17:59 -07001755 logging.info("Running flow toggle with %d flows, %d iterations" %
Dan Talaycofa6454f2012-04-05 10:04:13 -07001756 (flow_count, iter_count))
1757 acts = []
1758 acts.append(action.action_output())
1759 acts.append(action.action_output())
1760
Rich Lane477f4812012-10-04 22:49:00 -07001761 of_ports = config["port_map"].keys()
Dan Talaycofa6454f2012-04-05 10:04:13 -07001762 if len(of_ports) < 3:
1763 self.assertTrue(False, "Too few ports for test")
1764
1765 for idx in range(2):
1766 acts[idx].port = of_ports[idx]
1767
1768 flows = []
1769 flows.append([])
1770 flows.append([])
1771
Ed Swierk99a74de2012-08-22 06:40:54 -07001772 wildcards = (required_wildcards(self) | ofp.OFPFW_DL_SRC |
1773 ofp.OFPFW_DL_DST)
Dan Talaycofa6454f2012-04-05 10:04:13 -07001774 # Create up the flows in an array
1775 for toggle in range(2):
1776 for f_idx in range(flow_count):
1777 pkt = simple_tcp_packet(tcp_sport=f_idx)
1778 msg = message.flow_mod()
Ed Swierk99a74de2012-08-22 06:40:54 -07001779 match = packet_to_flow_match(self, pkt)
Shudong Zhou031373c2012-07-19 17:37:42 -07001780 match.in_port = of_ports[2]
Dan Talayco50be7672012-04-05 11:38:08 -07001781 match.wildcards = wildcards
Dan Talaycofa6454f2012-04-05 10:04:13 -07001782 msg.match = match
1783 msg.buffer_id = 0xffffffff
Dan Talaycof7c41312012-07-23 12:53:19 -07001784 msg.command = ofp.OFPFC_ADD
Dan Talaycofa6454f2012-04-05 10:04:13 -07001785 msg.actions.add(acts[toggle])
1786 flows[toggle].append(msg)
Dan Talayco50be7672012-04-05 11:38:08 -07001787
1788 # Show two sample flows
Rich Lane9a003812012-10-04 17:17:59 -07001789 logging.debug(flows[0][0].show())
1790 logging.debug(flows[1][0].show())
Dan Talayco50be7672012-04-05 11:38:08 -07001791
Dan Talaycofa6454f2012-04-05 10:04:13 -07001792 # Install the first set of flows
1793 for f_idx in range(flow_count):
1794 rv = self.controller.message_send(flows[0][f_idx])
1795 self.assertTrue(rv != -1, "Error installing flow %d" % f_idx)
Dan Talayco0fc08bd2012-04-09 16:56:18 -07001796 self.assertEqual(do_barrier(self.controller), 0, "Barrier failed")
Dan Talaycofa6454f2012-04-05 10:04:13 -07001797
Rich Lane9a003812012-10-04 17:17:59 -07001798 logging.info("Installed %d flows" % flow_count)
Dan Talaycofa6454f2012-04-05 10:04:13 -07001799
1800 # Repeatedly modify all the flows back and forth
1801 updates = 0
1802 # Report status about 5 times
1803 mod_val = (iter_count / 4) + 1
Dan Talaycoabbfdbb2012-04-05 10:29:26 -07001804 start = time.time()
1805 for iter_idx in range(iter_count):
1806 if not iter_idx % mod_val:
Rich Lane9a003812012-10-04 17:17:59 -07001807 logging.info("Flow Toggle: iter %d of %d. " %
Dan Talaycoabbfdbb2012-04-05 10:29:26 -07001808 (iter_idx, iter_count) +
1809 "%d updates in %d secs" %
1810 (updates, time.time() - start))
Dan Talaycofa6454f2012-04-05 10:04:13 -07001811 for toggle in range(2):
1812 t_idx = 1 - toggle
1813 for f_idx in range(flow_count):
1814 rv = self.controller.message_send(flows[t_idx][f_idx])
1815 updates += 1
1816 self.assertTrue(rv != -1, "Error modifying flow %d" %
1817 f_idx)
Dan Talayco0fc08bd2012-04-09 16:56:18 -07001818 self.assertEqual(do_barrier(self.controller), 0,
1819 "Barrier failed")
Dan Talaycoabbfdbb2012-04-05 10:29:26 -07001820
1821 end = time.time()
1822 divisor = end - start or (end - start + 1)
Rich Lane9a003812012-10-04 17:17:59 -07001823 logging.info("Flow toggle: %d iterations" % iter_count)
1824 logging.info(" %d flow mods in %d secs, %d mods/sec" %
Dan Talaycoabbfdbb2012-04-05 10:29:26 -07001825 (updates, end - start, updates/divisor))
Dan Talaycofa6454f2012-04-05 10:04:13 -07001826
1827
Dan Talayco8a64e332012-03-28 14:53:20 -07001828# You can pick and choose these by commenting tests in or out
1829iter_classes = [
1830 basic.PacketIn,
1831 basic.PacketOut,
1832 DirectPacket,
Dan Talaycofa6454f2012-04-05 10:04:13 -07001833 FlowToggle,
Dan Talayco8a64e332012-03-28 14:53:20 -07001834 DirectTwoPorts,
Dan Talaycofa6454f2012-04-05 10:04:13 -07001835 DirectMCNonIngress,
Dan Talayco8a64e332012-03-28 14:53:20 -07001836 AllWildcardMatch,
1837 AllWildcardMatchTagged,
1838 SingleWildcardMatch,
1839 SingleWildcardMatchTagged,
1840 ExactMatch,
1841 ExactMatchTagged,
1842 SingleWildcardMatch,
1843 ModifyL2Src,
1844 ModifyL2Dst,
1845 ModifyL2SrcMC,
1846 ModifyL2DstMC,
1847 ModifyL2SrcDstMC
1848 ]
1849
1850class IterCases(BaseMatchCase):
Dan Talaycofa6454f2012-04-05 10:04:13 -07001851 """
1852 Iterate over a bunch of test cases
1853
1854 The cases come from the list above
1855 """
1856
Rich Laned1d9c282012-10-04 22:07:10 -07001857 priority = -1
1858
Dan Talayco8a64e332012-03-28 14:53:20 -07001859 def runTest(self):
Rich Lane2014f9b2012-10-05 15:29:40 -07001860 count = test_param_get('iter_count', default=10)
Dan Talayco8a64e332012-03-28 14:53:20 -07001861 tests_done = 0
Rich Lane9a003812012-10-04 17:17:59 -07001862 logging.info("Running iteration test " + str(count) + " times")
Dan Talayco8a64e332012-03-28 14:53:20 -07001863 start = time.time()
1864 last = start
1865 for idx in range(count):
Rich Lane9a003812012-10-04 17:17:59 -07001866 logging.info("Iteration " + str(idx + 1))
Dan Talayco8a64e332012-03-28 14:53:20 -07001867 for cls in iter_classes:
1868 test = cls()
1869 test.inheritSetup(self)
1870 test.runTest()
1871 tests_done += 1
Dan Talaycofa6454f2012-04-05 10:04:13 -07001872 # Report update about every minute, between tests
Dan Talayco8a64e332012-03-28 14:53:20 -07001873 if time.time() - last > 60:
1874 last = time.time()
Rich Lane9a003812012-10-04 17:17:59 -07001875 logging.info(
Dan Talaycofa6454f2012-04-05 10:04:13 -07001876 "IterCases: Iter %d of %d; Ran %d tests in %d " %
1877 (idx, count, tests_done, last - start) +
1878 "seconds so far")
Dan Talayco8a64e332012-03-28 14:53:20 -07001879 stats = all_stats_get(self)
1880 last = time.time()
Rich Lane9a003812012-10-04 17:17:59 -07001881 logging.info("\nIterCases ran %d tests in %d seconds." %
Dan Talayco8a64e332012-03-28 14:53:20 -07001882 (tests_done, last - start))
Rich Lane9a003812012-10-04 17:17:59 -07001883 logging.info(" flows: %d. packets: %d. bytes: %d" %
Dan Talayco8a64e332012-03-28 14:53:20 -07001884 (stats["flows"], stats["packets"], stats["bytes"]))
Rich Lane9a003812012-10-04 17:17:59 -07001885 logging.info(" active: %d. lookups: %d. matched %d." %
Dan Talayco8a64e332012-03-28 14:53:20 -07001886 (stats["active"], stats["lookups"], stats["matched"]))
1887
Dan Talayco4b2bee62010-07-20 14:10:05 -07001888#@todo Need to implement tagged versions of the above tests
1889#
1890#@todo Implement a test case that strips tag 2, adds tag 3
1891# and modifies tag 4 to tag 5. Then verify (in addition) that
1892# tag 6 does not get modified.
1893
1894class MixedVLAN(BaseMatchCase):
1895 """
1896 Test mixture of VLAN tag actions
1897
1898 Strip tag 2 on port 1, send to port 2
1899 Add tag 3 on port 1, send to port 2
1900 Modify tag 4 to 5 on port 1, send to port 2
1901 All other traffic from port 1, send to port 3
1902 All traffic from port 2 sent to port 4
1903 Use exact matches with different packets for all mods
1904 Verify the following: (port, vid)
1905 (port 1, vid 2) => VLAN tag stripped, out port 2
1906 (port 1, no tag) => tagged packet w/ vid 2 out port 2
1907 (port 1, vid 4) => tagged packet w/ vid 5 out port 2
1908 (port 1, vid 5) => tagged packet w/ vid 5 out port 2
1909 (port 1, vid 6) => tagged packet w/ vid 6 out port 2
1910 (port 2, no tag) => untagged packet out port 4
1911 (port 2, vid 2-6) => unmodified packet out port 4
1912
1913 Variation: Might try sending VID 5 to port 3 and check.
1914 If only VID 5 distinguishes pkt, this will fail on some platforms
1915 """
1916
Rich Laned1d9c282012-10-04 22:07:10 -07001917 priority = -1
Rich Lane8d6ab272012-09-23 18:06:20 -07001918
Rich Laneb90a1c42012-10-05 09:16:05 -07001919class MatchEach(base_tests.SimpleDataPlane):
Rich Lane8d6ab272012-09-23 18:06:20 -07001920 """
1921 Check that each match field is actually matched on.
1922 Installs two flows that differ in one field. The flow that should not
1923 match has a higher priority, so if that field is ignored during matching
1924 the packet will be sent out the wrong port.
1925
1926 TODO test UDP, ARP, ICMP, etc.
1927 """
1928 def runTest(self):
Rich Lane477f4812012-10-04 22:49:00 -07001929 of_ports = config["port_map"].keys()
Rich Lane8d6ab272012-09-23 18:06:20 -07001930 of_ports.sort()
1931 self.assertTrue(len(of_ports) > 1, "Not enough ports for test")
1932
Rich Lane9a003812012-10-04 17:17:59 -07001933 delete_all_flows(self.controller)
Rich Lane8d6ab272012-09-23 18:06:20 -07001934
1935 pkt = simple_tcp_packet()
1936 ingress_port = of_ports[0]
1937 egress_port = of_ports[1]
1938
1939 def testField(field, mask):
Rich Lane9a003812012-10-04 17:17:59 -07001940 logging.info("Testing field %s" % field)
Rich Lane8d6ab272012-09-23 18:06:20 -07001941
1942 def addFlow(matching, priority, output_port):
1943 match = packet_to_flow_match(self, pkt)
1944 self.assertTrue(match is not None, "Could not generate flow match from pkt")
1945 match.wildcards &= ~ofp.OFPFW_IN_PORT
1946 match.in_port = ingress_port
1947 if not matching:
1948 # Make sure flow doesn't match
1949 orig = getattr(match, field)
1950 if isinstance(orig, list):
1951 new = map(lambda a: ~a[0] & a[1], zip(orig, mask))
1952 else:
1953 new = ~orig & mask
1954 setattr(match, field, new)
1955 request = message.flow_mod()
1956 request.match = match
1957 request.buffer_id = 0xffffffff
1958 request.priority = priority
1959 act = action.action_output()
1960 act.port = output_port
1961 self.assertTrue(request.actions.add(act), "Could not add action")
Rich Lane9a003812012-10-04 17:17:59 -07001962 logging.info("Inserting flow")
Rich Lane8d6ab272012-09-23 18:06:20 -07001963 self.controller.message_send(request)
1964
1965 # This flow should match.
1966 addFlow(matching=True, priority=0, output_port=egress_port)
1967 # This flow should not match, but it has a higher priority.
1968 addFlow(matching=False, priority=1, output_port=ofp.OFPP_IN_PORT)
1969
1970 self.assertEqual(do_barrier(self.controller), 0, "Barrier failed")
1971
Rich Lane9a003812012-10-04 17:17:59 -07001972 logging.info("Sending packet to dp port " + str(ingress_port))
Rich Lane8d6ab272012-09-23 18:06:20 -07001973 self.dataplane.send(ingress_port, str(pkt))
1974
1975 exp_pkt_arg = None
1976 exp_port = None
Rich Lane477f4812012-10-04 22:49:00 -07001977 if config["relax"]:
Rich Lane8d6ab272012-09-23 18:06:20 -07001978 exp_pkt_arg = pkt
1979 exp_port = egress_port
1980
1981 (rcv_port, rcv_pkt, pkt_time) = self.dataplane.poll(port_number=exp_port,
1982 exp_pkt=exp_pkt_arg)
1983 self.assertTrue(rcv_pkt is not None, "Did not receive packet")
Rich Lane9a003812012-10-04 17:17:59 -07001984 logging.debug("Packet len " + str(len(rcv_pkt)) + " in on " + str(rcv_port))
Rich Lane8d6ab272012-09-23 18:06:20 -07001985 self.assertEqual(rcv_port, egress_port, "Unexpected receive port")
1986 self.assertEqual(str(pkt), str(rcv_pkt), 'Response packet does not match send packet')
1987
1988 # TODO in_port
1989 testField("dl_src", [0xff]*6)
1990 testField("dl_dst", [0xff]*6)
1991 testField("dl_type", 0xffff)
1992 testField("dl_vlan", 0xfff)
1993 # TODO dl_vlan_pcp
1994 testField("nw_src", 0xffffffff)
1995 testField("nw_dst", 0xffffffff)
1996 testField("nw_tos", 0x3f)
1997 testField("nw_proto", 0xff)
1998 testField("tp_src", 0xffff)
1999 testField("tp_dst", 0xffff)
2000
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002001class DirectBadPacketBase(base_tests.SimpleDataPlane):
2002 """
2003 Base class for sending single packets with single flow table entries.
2004 Used to verify matching of unusual packets and parsing/matching of
2005 corrupted packets.
2006
2007 The idea is to generate packets that may either be totally malformed or
2008 malformed just enough to trick the flow matcher into making mistakes.
2009
2010 Generate a 'bad' packet
2011 Generate and install a matching flow
2012 Add action to direct the packet to an egress port
2013 Send the packet to ingress dataplane port
2014 Verify the packet is received at the egress port only
2015 """
2016
2017 RESULT_MATCH = "MATCH"
2018 RESULT_NOMATCH = "NO MATCH"
2019 RESULT_ANY = "ANY MATCH"
2020
2021 def runTest(self):
2022 pass
2023 # TODO:
2024 # - ICMP?
2025 # - VLAN?
2026 # - action
2027
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002028 def createMatch(self, **kwargs):
2029 match = ofp.ofp_match()
2030 match.wildcards = ofp.OFPFW_ALL
2031 fields = {
2032 'dl_dst': ofp.OFPFW_DL_DST,
2033 'dl_src': ofp.OFPFW_DL_SRC,
2034 'dl_type': ofp.OFPFW_DL_TYPE,
2035 'dl_vlan': ofp.OFPFW_DL_VLAN,
2036 'nw_src': ofp.OFPFW_NW_SRC_MASK,
2037 'nw_dst': ofp.OFPFW_NW_DST_MASK,
2038 'nw_tos': ofp.OFPFW_NW_TOS,
2039 'nw_proto': ofp.OFPFW_NW_PROTO,
2040 'tp_src': ofp.OFPFW_TP_SRC,
2041 'tp_dst': ofp.OFPFW_TP_DST,
2042 }
2043 for key in kwargs:
2044 setattr(match, key, kwargs[key])
2045 match.wildcards &= ~fields[key]
2046 return match
2047
2048 def testPktsAgainstFlow(self, pkts, acts, match):
2049 if type(acts) != list:
2050 acts = [acts]
2051 for info in pkts:
2052 title, pkt, expected_result = info
2053 self.testPktAgainstFlow(title, pkt, acts, match, expected_result)
2054
2055 def testPktAgainstFlow(self, title, pkt, acts, match, expected_result):
2056 of_ports = config["port_map"].keys()
2057 of_ports.sort()
2058 self.assertTrue(len(of_ports) > 1, "Not enough ports for test")
2059
2060 rv = delete_all_flows(self.controller)
2061 self.assertEqual(rv, 0, "Failed to delete all flows")
2062
2063 ingress_port = of_ports[0]
2064 egress_port = of_ports[1]
2065
2066 logging.info("Testing packet '%s', expect result %s" %
2067 (title, expected_result))
2068 logging.info("Ingress %s to egress %s" %
2069 (str(ingress_port), str(egress_port)))
2070 logging.info("Packet:")
Rich Lane5d7e89a2012-10-26 16:43:13 -07002071 logging.info(inspect_packet(pkt))
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002072
2073 match.in_port = ingress_port
2074
2075 request = message.flow_mod()
2076 request.match = match
Rich Lane44cf12d2012-10-15 11:10:45 -07002077 request.priority = 1
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002078
2079 request.buffer_id = 0xffffffff
2080 for act in acts:
2081 act.port = egress_port
2082 rv = request.actions.add(act)
2083 self.assertTrue(rv, "Could not add action")
2084
2085 logging.info("Inserting flow")
2086 rv = self.controller.message_send(request)
2087 self.assertTrue(rv != -1, "Error installing flow mod")
Rich Lane44cf12d2012-10-15 11:10:45 -07002088
2089 # This flow speeds up negative tests
2090 logging.info("Inserting catch-all flow")
2091 request2 = message.flow_mod()
2092 request2.match = self.createMatch()
2093 request2.priority = 0
2094 act = action.action_output()
2095 act.port = ofp.OFPP_IN_PORT
2096 request2.actions.add(act)
2097 rv = self.controller.message_send(request2)
2098 self.assertTrue(rv != -1, "Error installing flow mod")
2099
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002100 self.assertEqual(do_barrier(self.controller), 0, "Barrier failed")
2101
2102 logging.info("Sending packet to dp port " +
2103 str(ingress_port))
2104 self.dataplane.send(ingress_port, str(pkt))
2105
2106 exp_pkt_arg = None
2107 exp_port = None
2108 if config["relax"]:
2109 exp_pkt_arg = pkt
2110 exp_port = egress_port
2111
Rich Lane44cf12d2012-10-15 11:10:45 -07002112 if expected_result == self.RESULT_MATCH:
2113 timeout = -1 # default timeout
2114 else:
2115 timeout = 1 # short timeout for negative tests
2116
2117 (rcv_port, rcv_pkt, pkt_time) = self.dataplane.poll(exp_pkt=exp_pkt_arg,
2118 timeout=timeout)
2119 if rcv_port == ingress_port:
2120 logging.debug("Packet matched catch-all flow")
2121 rcv_pkt = None
2122
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002123 if expected_result == self.RESULT_MATCH:
2124 self.assertTrue(rcv_pkt is not None,
2125 "Did not receive packet, expected a match")
2126 logging.debug("Packet len " + str(len(rcv_pkt)) + " in on " +
2127 str(rcv_port))
2128 self.assertEqual(rcv_port, egress_port, "Unexpected receive port")
2129 str_pkt = str(pkt)
2130 str_rcv_pkt = str(rcv_pkt)
2131 str_rcv_pkt = str_rcv_pkt[0:len(str_pkt)]
2132 if str_pkt != str_rcv_pkt:
2133 logging.error("Response packet does not match send packet")
2134 logging.info("Response:")
Rich Lane5d7e89a2012-10-26 16:43:13 -07002135 logging.info(inspect_packet(scapy.Ether(rcv_pkt)))
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002136 self.assertEqual(str_pkt, str_rcv_pkt,
2137 'Response packet does not match send packet')
2138 elif expected_result == self.RESULT_NOMATCH:
2139 self.assertTrue(rcv_pkt is None, "Received packet, expected drop")
2140 else:
2141 logging.debug("Match or drop accepted. Result = %s" %
2142 ("match" if rcv_pkt is not None else "drop"))
2143
2144
2145class DirectBadIpTcpPacketsBase(DirectBadPacketBase):
2146 """
2147 Base class for TCP and UDP parsing/matching verification under corruptions
2148 """
2149 def runTest(self):
2150 pass
2151
2152 def runTestWithProto(self, protoName = 'TCP'):
2153 dl_dst='00:01:02:03:04:05'
2154 dl_src='00:06:07:08:09:0a'
2155 ip_src='192.168.0.1'
2156 ip_dst='192.168.0.2'
2157 ip_tos=0
2158 tcp_sport=1234
2159 tcp_dport=80
2160
2161 # Generate a proper packet for constructing a match
2162 tp = None
2163 if protoName == 'TCP':
2164 tp = scapy.TCP
2165 proto = 6
2166 elif protoName == 'UDP':
2167 tp = scapy.UDP
2168 proto = 17
2169 else:
2170 raise Exception("Passed in unknown proto name")
2171
2172 match_pkt = scapy.Ether(dst=dl_dst, src=dl_src)/ \
2173 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos)/ \
2174 tp(sport=tcp_sport, dport=tcp_dport)
2175 match = packet_to_flow_match(self, match_pkt)
2176 self.assertTrue(match is not None,
2177 "Could not generate flow match from pkt")
2178 match.wildcards &= ~ofp.OFPFW_IN_PORT
2179
2180 def testPacket(title, pkt, result):
2181 act = action.action_output()
2182 pkts = [
2183 [title, pkt, result]
2184 ]
2185 self.testPktsAgainstFlow(pkts, act, match)
2186
2187 # Try incomplete IP headers
2188 testPacket("Incomplete IP header (1 bytes)",
2189 scapy.Ether(dst=dl_dst, src=dl_src)/ \
2190 str(scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, proto=proto))[0:1],
2191 self.RESULT_NOMATCH,
2192 )
2193 testPacket("Incomplete IP header (2 bytes)",
2194 scapy.Ether(dst=dl_dst, src=dl_src)/ \
2195 str(scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, proto=proto))[0:2],
2196 self.RESULT_NOMATCH,
2197 )
2198 testPacket("Incomplete IP header (3 bytes)",
2199 scapy.Ether(dst=dl_dst, src=dl_src)/ \
2200 str(scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, proto=proto))[0:3],
2201 self.RESULT_NOMATCH,
2202 )
2203 testPacket("Incomplete IP header (12 bytes)",
2204 scapy.Ether(dst=dl_dst, src=dl_src)/ \
2205 str(scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, proto=proto))[0:12],
2206 self.RESULT_NOMATCH,
2207 )
2208 testPacket("Incomplete IP header (16 bytes)",
2209 scapy.Ether(dst=dl_dst, src=dl_src)/ \
2210 str(scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, proto=proto))[0:16],
2211 self.RESULT_NOMATCH,
2212 )
2213 testPacket("Incomplete IP header (19 bytes)",
2214 scapy.Ether(dst=dl_dst, src=dl_src)/ \
2215 str(scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, proto=proto))[0:19],
2216 self.RESULT_NOMATCH,
2217 )
2218
2219 # Try variations where the TCP header is missing or incomplete. As we
2220 # saw bugs before where buffers were reused and lengths weren't honored,
2221 # we initiatlize once with a non-matching full packet and once with a
2222 # matching full packet.
2223 testPacket("Non-Matching TCP packet, warming buffer",
2224 scapy.Ether(dst=dl_dst, src=dl_src)/ \
2225 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, proto=proto)/ \
2226 tp(sport=tcp_sport, dport=tcp_dport + 1),
2227 self.RESULT_NOMATCH,
2228 )
2229 testPacket("Missing TCP header, buffer warmed with non-match",
2230 scapy.Ether(dst=dl_dst, src=dl_src)/ \
2231 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, proto=proto),
2232 self.RESULT_NOMATCH,
2233 )
2234 testPacket("Matching TCP packet, warming buffer",
2235 scapy.Ether(dst=dl_dst, src=dl_src)/ \
2236 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, proto=proto)/ \
2237 tp(sport=tcp_sport, dport=tcp_dport),
2238 self.RESULT_MATCH,
2239 )
2240 testPacket("Missing TCP header, buffer warmed with match",
2241 scapy.Ether(dst=dl_dst, src=dl_src)/ \
2242 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, proto=proto),
2243 self.RESULT_NOMATCH,
2244 )
2245 testPacket("Truncated TCP header: 2 bytes",
2246 scapy.Ether(dst=dl_dst, src=dl_src)/ \
2247 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, proto=proto)/ \
2248 (str(tp(sport=tcp_sport, dport=tcp_dport))[0:2]),
2249 self.RESULT_NOMATCH,
2250 )
2251
2252 # Play with IP header length values that put the start of TCP either
2253 # inside the generated TCP header or beyond. In some cases it may even
2254 # be beyond the packet boundary. Also play with IP options and more
2255 # importantly IP total length corruptions.
2256 testPacket("TCP packet, corrupt ihl (0x6)",
2257 simple_tcp_packet(ip_ihl=6),
2258 self.RESULT_NOMATCH,
2259 )
2260 testPacket("TCP packet, corrupt ihl (0xf)",
2261 simple_tcp_packet(ip_ihl=0xf), # ihl = 15 * 4 = 60
2262 self.RESULT_NOMATCH,
2263 )
2264 testPacket("TCP packet, corrupt ihl and total length",
2265 simple_tcp_packet(ip_ihl=0xf, pktlen=56), # ihl = 15 * 4 = 60,
2266 self.RESULT_NOMATCH,
2267 )
2268 testPacket("Corrupt IPoption: First 4 bytes of matching TCP header",
2269 simple_tcp_packet(
2270 ip_options=scapy.IPOption('\x04\xd2\x00\x50'),
2271 tcp_dport=2, tcp_sport=2
2272 ),
2273 self.RESULT_NOMATCH,
2274 )
2275 testPacket("Missing TCP header, corrupt ihl",
2276 scapy.Ether(dst=dl_dst, src=dl_src)/ \
2277 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ihl=0xf, proto=proto),
2278 self.RESULT_NOMATCH,
2279 )
2280 testPacket("Missing TCP header, corrupt total length",
2281 scapy.Ether(dst=dl_dst, src=dl_src)/ \
2282 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, proto=proto, len= 100),
2283 self.RESULT_NOMATCH,
2284 )
2285 testPacket("Missing TCP header, corrupt ihl and total length",
2286 scapy.Ether(dst=dl_dst, src=dl_src)/ \
2287 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ihl=0xf, proto=proto, len=43),
2288 self.RESULT_NOMATCH,
2289 )
2290 testPacket("Incomplete IP header (12 bytes), corrupt ihl and total length",
2291 scapy.Ether(dst=dl_dst, src=dl_src)/ \
2292 str(scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, proto=proto, ihl=10, len=43))[0:12],
2293 self.RESULT_NOMATCH,
2294 )
2295 testPacket("Incomplete IP header (16 bytes), corrupt ihl and total length",
2296 scapy.Ether(dst=dl_dst, src=dl_src)/ \
2297 str(scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, proto=proto, ihl=10, len=43))[0:16],
2298 self.RESULT_NOMATCH,
2299 )
2300
2301 # Try an incomplete TCP header that has enough bytes to carry source and
2302 # destination ports. As that is all we care about during matching, some
2303 # implementations may match and some may drop the packet
2304 testPacket("Incomplete TCP header: src/dst port present",
2305 scapy.Ether(dst=dl_dst, src=dl_src)/ \
2306 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, proto=proto)/ \
2307 (str(tp(sport=tcp_sport, dport=tcp_dport))[0:4]),
2308 self.RESULT_ANY,
2309 )
2310
2311 for i in range(1):
2312 for length in range(40 / 4): # IPv4 options are a maximum of 40 in length
2313 bytes = "".join([("%c" % random.randint(0, 255)) for x in range(length * 4)])
2314 eth = scapy.Ether(dst=dl_dst, src=dl_src)
2315 ip = scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ihl=5 + length, proto=proto)
2316 tcp = tp(sport=tcp_sport, dport=tcp_dport+1)
2317 pkt = eth / ip
2318 pkt = pkt / bytes
2319 pkt = pkt / str(tcp)
2320 testPacket("Random IP options len = %d - TP match must fail" % length * 4,
2321 pkt,
2322 self.RESULT_NOMATCH
2323 )
2324
2325 eth = scapy.Ether(dst=dl_dst, src=dl_src)
2326 ip = scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ihl=5 + length, proto=proto)
2327 tcp = tp(sport=tcp_sport, dport=tcp_dport)
2328 pkt = eth / ip
2329 pkt = pkt / bytes
2330 pkt = pkt / str(tcp)
2331
2332 testPacket("Random IP options len = %d - May match",
2333 pkt,
2334 self.RESULT_ANY
2335 )
2336
2337
2338class DirectBadIpTcpPackets(DirectBadIpTcpPacketsBase):
2339 """
2340 Verify IP/TCP parsing and matching. Focus on packet corruptions
2341 """
2342 def runTest(self):
2343 self.runTestWithProto(protoName = 'TCP')
2344
2345class DirectBadIpUdpPackets(DirectBadIpTcpPacketsBase):
2346 """
2347 Verify IP/UDP parsing and matching. Focus on packet corruptions
2348 """
2349 def runTest(self):
2350 self.runTestWithProto(protoName = 'UDP')
2351
2352class DirectBadLlcPackets(DirectBadPacketBase):
2353 """
2354 Verify LLC/SNAP parsing and matching. Focus on packet corruptions
2355 """
2356 def runTest(self):
2357 dl_dst='00:01:02:03:04:05'
2358 dl_src='00:06:07:08:09:0a'
2359 ip_src='192.168.0.1'
2360 ip_dst='192.168.0.2'
2361 ip_tos=0
2362 tcp_sport=1234
2363 tcp_dport=80
2364
2365 IS_SNAP_IP = 1
2366 IS_SNAP_IP_CORRUPT = 2
2367 IS_NOT_SNAP_IP = 3
2368
2369 def testPacketTcpMatch(title, llc):
2370 match_pkt = scapy.Ether(dst=dl_dst, src=dl_src)/ \
2371 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos)/ \
2372 scapy.TCP(sport=tcp_sport, dport=tcp_dport)
2373 match = packet_to_flow_match(self, match_pkt)
2374 self.assertTrue(match is not None,
2375 "Could not generate flow match from pkt")
2376 match.wildcards &= ~ofp.OFPFW_IN_PORT
2377 act = action.action_output()
2378
2379 self.testPktsAgainstFlow(
2380 [[
2381 "TCP match - LLC frame correct length - %s" % title,
2382 scapy.Ether(dst=dl_dst, src=dl_src, type=len(llc)) / llc,
2383 self.RESULT_ANY,
2384 ]],
2385 act, match
2386 )
2387
2388 # Corrupt length field
2389 ethLen = random.randint(0, 1535)
2390 self.testPktsAgainstFlow(
2391 [[
2392 "TCP match - LLC frame corrupted length - %s" % title,
2393 scapy.Ether(dst=dl_dst, src=dl_src, type=ethLen) / llc,
2394 self.RESULT_ANY,
2395 ]],
2396 act, match
2397 )
2398
2399 def testPacketEthSrcDstMatch(title, llc):
2400 # Matching based on Ethernet source and destination
2401 match_pkt = scapy.Ether(dst=dl_dst, src=dl_src)
2402 match = packet_to_flow_match(self, match_pkt)
2403 self.assertTrue(match is not None,
2404 "Could not generate flow match from pkt")
2405 match.wildcards &= ~ofp.OFPFW_IN_PORT
2406 match.wildcards |= ofp.OFPFW_DL_TYPE
2407 self.testPktsAgainstFlow(
2408 [[
2409 "Eth addr match - LLC frame correct length- %s" % title,
2410 scapy.Ether(dst=dl_dst, src=dl_src, type=len(llc)) / llc,
2411 self.RESULT_MATCH,
2412 ]],
2413 action.action_output(), match
2414 )
2415
2416 # Corrupt length field
2417 ethLen = random.randint(0, 1535)
2418 self.testPktsAgainstFlow(
2419 [[
2420 "Eth addr 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 action.action_output(), match
2425 )
2426
2427 def testPacketEthSrcDstTypeMatch(title, llc, is_snap_ip):
2428 # Matching based on Ethernet source, destination and type
2429 match_pkt = scapy.Ether(dst=dl_dst, src=dl_src, type=0x800)
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 if is_snap_ip == IS_SNAP_IP:
2435 is_match = self.RESULT_MATCH
2436 elif is_snap_ip == IS_SNAP_IP_CORRUPT:
2437 is_match = self.RESULT_ANY
2438 else:
2439 is_match = self.RESULT_NOMATCH
2440 self.testPktsAgainstFlow(
2441 [[
2442 "Eth addr+type match - LLC frame correct length - %s" % title,
2443 scapy.Ether(dst=dl_dst, src=dl_src, type=len(llc)) / llc,
2444 is_match,
2445 ]],
2446 action.action_output(), match
2447 )
2448
2449 # Corrupt length field
2450 ethLen = random.randint(0, 1535)
2451 self.testPktsAgainstFlow(
2452 [[
2453 "Eth addr+type match - LLC frame corrupted length - %s" % title,
2454 scapy.Ether(dst=dl_dst, src=dl_src, type=ethLen) / llc,
Christian Dickmanne9b6d252012-10-08 22:56:50 -07002455 self.RESULT_ANY,
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002456 ]],
2457 action.action_output(), match
2458 )
2459
2460 def testPacket(title, llc, is_snap_ip):
2461 testPacketTcpMatch(title, llc)
2462 testPacketEthSrcDstMatch(title, llc)
2463 testPacketEthSrcDstTypeMatch(title, llc, is_snap_ip)
2464
2465 testPacket("LLC - No SNAP - No Payload",
Rich Lane6508ea02012-10-12 15:27:11 -07002466 scapy.LLC(dsap=0x33, ssap=0x44, ctrl=0x03),
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002467 IS_NOT_SNAP_IP,
2468 )
2469 testPacket("LLC - No SNAP - Small Payload",
Rich Lane6508ea02012-10-12 15:27:11 -07002470 scapy.LLC(dsap=0x33, ssap=0x44, ctrl=0x03) / ("S" * 10),
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002471 IS_NOT_SNAP_IP,
2472 )
2473 testPacket("LLC - No SNAP - Max -1 Payload",
Rich Lane6508ea02012-10-12 15:27:11 -07002474 scapy.LLC(dsap=0x33, ssap=0x44, ctrl=0x03) / ("S" * (1500 - 3 - 1)),
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002475 IS_NOT_SNAP_IP,
2476 )
2477 testPacket("LLC - No SNAP - Max Payload",
Rich Lane6508ea02012-10-12 15:27:11 -07002478 scapy.LLC(dsap=0x33, ssap=0x44, ctrl=0x03) / ("S" * (1500 - 3)),
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002479 IS_NOT_SNAP_IP,
2480 )
2481 testPacket("LLC - SNAP - Small bogus payload",
2482 scapy.LLC(dsap=0xaa, ssap=0xaa, ctrl=0x03)/ \
2483 scapy.SNAP(OUI=0x000000, code=0x800) / ("S" * 10),
2484 IS_SNAP_IP_CORRUPT,
2485 )
2486 testPacket("LLC - SNAP - Max -1 bogus payload",
2487 scapy.LLC(dsap=0xaa, ssap=0xaa, ctrl=0x03)/ \
2488 scapy.SNAP(OUI=0x000000, code=0x3) / ("S" * (1500 - 3 - 5 - 1)),
2489 IS_NOT_SNAP_IP,
2490 )
2491 testPacket("LLC - SNAP - Max bogus payload",
2492 scapy.LLC(dsap=0xaa, ssap=0xaa, ctrl=0x03)/ \
2493 scapy.SNAP(OUI=0x000000, code=0x3) / ("S" * (1500 - 3 - 5)),
2494 IS_NOT_SNAP_IP,
2495 )
2496 testPacket("LLC - SNAP - IP - TCP",
2497 scapy.LLC(dsap=0xaa, ssap=0xaa, ctrl=0x03)/ \
2498 scapy.SNAP(OUI=0x000000, code=0x800)/ \
2499 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, proto=6)/ \
2500 scapy.TCP(sport=tcp_sport, dport=tcp_dport),
2501 IS_SNAP_IP,
2502 )
2503
2504
2505class DirectLlcPackets(DirectBadPacketBase):
2506 """
2507 Verify LLC/SNAP parsing (valid and corrupted packets) and matching
2508 """
2509 def runTest(self):
2510 dl_dst='00:01:02:03:04:05'
2511 dl_src='00:06:07:08:09:0a'
2512 ip_src='192.168.0.1'
2513 ip_dst='192.168.0.2'
2514 ip_tos=0
2515 tcp_sport=1234
2516 tcp_dport=80
2517
2518 # Test ethertype in face of LLC/SNAP and OFP_DL_TYPE_NOT_ETH_TYPE
2519 IS_SNAP_NOT_IP = 1
2520 IS_SNAP_AND_IP = 2
2521 IS_NOT_SNAP = 3
2522
2523 def testPacketEthTypeIP(title, llc, is_snap):
2524 match_pkt = scapy.Ether(dst=dl_dst, src=dl_src, type=0x800)
2525 match = packet_to_flow_match(self, match_pkt)
2526 self.assertTrue(match is not None,
2527 "Could not generate flow match from pkt")
2528 match.wildcards &= ~ofp.OFPFW_IN_PORT
2529 pkts = []
2530 if is_snap == IS_NOT_SNAP or is_snap == IS_SNAP_NOT_IP:
2531 result = self.RESULT_NOMATCH
2532 else:
2533 result = self.RESULT_MATCH
2534 pkts.append([
2535 "Ether type 0x800 match - %s" % title,
2536 scapy.Ether(dst=dl_dst, src=dl_src, type=len(llc)) / llc,
2537 result,
2538 ])
2539 act = action.action_output()
2540 self.testPktsAgainstFlow(pkts, act, match)
2541
2542 def testPacketEthTypeNotEth(title, llc, is_snap):
2543 match_pkt = scapy.Ether(dst = dl_dst, src = dl_src,
2544 type = ofp.OFP_DL_TYPE_NOT_ETH_TYPE)
2545 match = packet_to_flow_match(self, match_pkt)
2546 self.assertTrue(match is not None,
2547 "Could not generate flow match from pkt")
2548 match.wildcards &= ~ofp.OFPFW_IN_PORT
2549 pkts = []
2550 if is_snap == IS_NOT_SNAP:
2551 result = self.RESULT_MATCH
2552 else:
2553 result = self.RESULT_NOMATCH
2554 pkts.append([
2555 "Ether type OFP_DL_TYPE_NOT_ETH_TYPE match - %s" % title,
2556 scapy.Ether(dst=dl_dst, src=dl_src, type=len(llc)) / llc,
2557 result,
2558 ])
2559 act = action.action_output()
2560 self.testPktsAgainstFlow(pkts, act, match)
2561
2562 def testPacket(title, llc, is_snap):
2563 testPacketEthTypeIP(title, llc, is_snap)
2564 testPacketEthTypeNotEth(title, llc, is_snap)
2565
2566 testPacket("LLC - No SNAP - No Payload",
Rich Lane6508ea02012-10-12 15:27:11 -07002567 scapy.LLC(dsap=0x33, ssap=0x44, ctrl=0x03),
2568 IS_NOT_SNAP,
2569 )
2570 testPacket("LLC (with information field) - No SNAP - No Payload",
2571 scapy.LLC(dsap=0x33, ssap=0x44, ctrl=0x12) / "S",
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002572 IS_NOT_SNAP,
2573 )
2574 testPacket("LLC - No SNAP - Small Payload",
Rich Lane6508ea02012-10-12 15:27:11 -07002575 scapy.LLC(dsap=0x33, ssap=0x44, ctrl=0x03) / ("S" * 10),
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002576 IS_NOT_SNAP,
2577 )
2578 testPacket("LLC - No SNAP - Max -1 Payload",
Rich Lane6508ea02012-10-12 15:27:11 -07002579 scapy.LLC(dsap=0x33, ssap=0x44, ctrl=0x03) / ("S" * (1500 - 3 - 1)),
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002580 IS_NOT_SNAP,
2581 )
2582 testPacket("LLC - No SNAP - Max Payload",
Rich Lane6508ea02012-10-12 15:27:11 -07002583 scapy.LLC(dsap=0x33, ssap=0x44, ctrl=0x03) / ("S" * (1500 - 3)),
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002584 IS_NOT_SNAP,
2585 )
2586 testPacket("LLC - SNAP - Non-default OUI",
2587 scapy.LLC(dsap=0xaa, ssap=0xaa, ctrl=0x03)/ \
2588 scapy.SNAP(OUI=0x000001, code=0x800) / ("S" * 10),
2589 IS_NOT_SNAP,
2590 )
2591 testPacket("LLC - SNAP - Default OUI",
2592 scapy.LLC(dsap=0xaa, ssap=0xaa, ctrl=0x03)/ \
2593 scapy.SNAP(OUI=0x000000, code=0x800) / ("S" * 10),
2594 IS_SNAP_AND_IP,
2595 )
2596 testPacket("LLC - SNAP - Max -1 bogus payload",
2597 scapy.LLC(dsap=0xaa, ssap=0xaa, ctrl=0x03)/ \
2598 scapy.SNAP(OUI=0x000000, code=0x3) / ("S" * (1500 - 3 - 5 - 1)),
2599 IS_SNAP_NOT_IP,
2600 )
2601 testPacket("LLC - SNAP - Max bogus payload",
2602 scapy.LLC(dsap=0xaa, ssap=0xaa, ctrl=0x03)/ \
2603 scapy.SNAP(OUI=0x000000, code=0x3) / ("S" * (1500 - 3 - 5)),
2604 IS_SNAP_NOT_IP,
2605 )
2606 testPacket("LLC - SNAP - IP - TCP",
2607 scapy.LLC(dsap=0xaa, ssap=0xaa, ctrl=0x03)/ \
2608 scapy.SNAP(OUI=0x000000, code=0x800)/ \
2609 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, proto=6)/ \
2610 scapy.TCP(sport=tcp_sport, dport=tcp_dport),
2611 IS_SNAP_AND_IP,
2612 )
2613
2614
2615class DirectArpPackets(DirectBadPacketBase):
2616 """
2617 Verify ARP parsing (valid and corrupted packets) and ARP matching
2618 """
2619 def runTest(self):
2620 self.testArpHandling()
2621
2622 def testArpHandling(self):
2623 dl_dst='00:01:02:03:04:05'
2624 dl_src='00:06:07:08:09:0a'
2625 ip_src='192.168.0.1'
2626 ip_dst='192.168.0.2'
2627 ip_src2='192.168.1.1'
2628 ip_dst2='192.168.1.2'
2629 ip_tos=0
2630 tcp_sport=1234
2631 tcp_dport=80
2632
2633 def testPacket(title, arp_match, arp_pkt, result):
2634 pkts = []
2635
2636 match_pkt = scapy.Ether(dst=dl_dst, src=dl_src) / arp_match
2637 match = packet_to_flow_match(self, match_pkt)
2638 self.assertTrue(match is not None,
2639 "Could not generate flow match from pkt")
2640 match.wildcards &= ~ofp.OFPFW_IN_PORT
2641
2642 pkts.append([
2643 title,
2644 scapy.Ether(dst=dl_dst, src=dl_src) / arp_pkt,
2645 result,
2646 ])
2647
2648 act = action.action_output()
2649 self.testPktsAgainstFlow(pkts, act, match)
2650
2651 testPacket("Basic ARP",
2652 scapy.ARP(psrc=ip_src, pdst=ip_dst, op = 1),
2653 scapy.ARP(hwdst = '00:00:00:00:00:00', hwsrc = dl_src,
2654 psrc = ip_src, pdst = ip_dst, hwlen = 6, plen = 4,
2655 ptype = 0x800, hwtype = 1, op = 1),
2656 self.RESULT_MATCH
2657 )
2658 # More stuff:
2659 # - Non matches on any property
2660 # - Corrupted hwlen and plen
2661 # - Other hwtype, ptype
2662 # - Truncated ARP pkt
2663
2664
2665class DirectVlanPackets(DirectBadPacketBase):
2666 """
2667 Verify VLAN parsing (valid and corrupted packets) and ARP matching
2668 """
2669 def runTest(self):
2670 dl_dst='00:01:02:03:04:05'
2671 dl_src='00:06:07:08:09:0a'
2672 ip_src='192.168.0.1'
2673 ip_dst='192.168.0.2'
2674 ip_src2='192.168.1.1'
2675 ip_dst2='192.168.1.2'
2676 ip_tos=0
2677 tcp_sport=1234
2678 tcp_dport=80
2679
2680 def testPacket(title, match, pkt, result):
2681 pkts = []
2682
2683 self.assertTrue(match is not None,
2684 "Could not generate flow match from pkt")
2685 match.wildcards &= ~ofp.OFPFW_IN_PORT
2686
2687 pkts.append([
2688 "%s" % title,
2689 pkt,
2690 result,
2691 ])
2692
2693 act = action.action_output()
2694 self.testPktsAgainstFlow(pkts, act, match)
2695
2696 testPacket("Basic MAC matching - IPv4 payload",
2697 self.createMatch(dl_dst=parse_mac(dl_dst), dl_src=parse_mac(dl_src)),
2698 scapy.Ether(dst=dl_dst, src=dl_src, type=0x800) / scapy.IP(),
2699 self.RESULT_MATCH
2700 )
2701 testPacket("Basic MAC matching - VMware beacon - no payload",
2702 self.createMatch(dl_dst=parse_mac(dl_dst), dl_src=parse_mac(dl_src)),
2703 scapy.Ether(dst=dl_dst, src=dl_src, type=0x8922),
2704 self.RESULT_MATCH
2705 )
2706 testPacket("Basic MAC matching - VMware beacon - with payload",
2707 self.createMatch(dl_dst=parse_mac(dl_dst), dl_src=parse_mac(dl_src)),
2708 scapy.Ether(dst=dl_dst, src=dl_src, type=0x8922)/ ("X" * 1),
2709 self.RESULT_MATCH
2710 )
2711 testPacket("Basic MAC matching - IPv6 payload",
2712 self.createMatch(dl_dst=parse_mac(dl_dst), dl_src=parse_mac(dl_src)),
2713 scapy.Ether(dst=dl_dst, src=dl_src) / scapy.IPv6(),
2714 self.RESULT_MATCH
2715 )
2716 testPacket("Basic MAC matching with VLAN tag present",
2717 self.createMatch(dl_dst=parse_mac(dl_dst), dl_src=parse_mac(dl_src)),
2718 scapy.Ether(dst=dl_dst, src=dl_src)/ \
Christian Dickmann8ac55252012-10-08 22:53:49 -07002719 scapy.Dot1Q(prio=5, vlan=1000)/ \
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002720 scapy.IP(),
2721 self.RESULT_MATCH
2722 )
2723 testPacket("Basic MAC matching with VLAN tag present",
2724 self.createMatch(dl_dst=parse_mac(dl_dst), dl_src=parse_mac(dl_src),
2725 dl_type=0x800),
2726 scapy.Ether(dst=dl_dst, src=dl_src)/ \
Christian Dickmann8ac55252012-10-08 22:53:49 -07002727 scapy.Dot1Q(prio=5, vlan=1000)/ \
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002728 scapy.IP(),
2729 self.RESULT_MATCH
2730 )
2731 testPacket("Ether matching with VLAN tag present - No type match",
2732 self.createMatch(dl_dst=parse_mac(dl_dst), dl_src=parse_mac(dl_src),
2733 dl_type=0x801),
2734 scapy.Ether(dst=dl_dst, src=dl_src)/ \
Christian Dickmann8ac55252012-10-08 22:53:49 -07002735 scapy.Dot1Q(prio=5, vlan=1000)/ \
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002736 scapy.IP(),
2737 self.RESULT_NOMATCH
2738 )
2739 testPacket("Ether matching with VLAN tag present - No type match 0x8100",
2740 self.createMatch(dl_dst=parse_mac(dl_dst), dl_src=parse_mac(dl_src),
2741 dl_type=0x8100),
2742 scapy.Ether(dst=dl_dst, src=dl_src)/ \
Christian Dickmann8ac55252012-10-08 22:53:49 -07002743 scapy.Dot1Q(prio=5, vlan=1000)/ \
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002744 scapy.IP(),
2745 self.RESULT_NOMATCH
2746 )
2747 testPacket("Ether matching with double VLAN tag - Wrong type match",
2748 self.createMatch(dl_dst=parse_mac(dl_dst), dl_src=parse_mac(dl_src),
2749 dl_type=0x800),
2750 scapy.Ether(dst=dl_dst, src=dl_src)/ \
Christian Dickmann8ac55252012-10-08 22:53:49 -07002751 scapy.Dot1Q(prio=5, vlan=1000)/ \
2752 scapy.Dot1Q(prio=3, vlan=1005)/ \
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002753 scapy.IP(),
2754 self.RESULT_NOMATCH
2755 )
2756 testPacket("Ether matching with double VLAN tag - Type match",
2757 self.createMatch(dl_dst=parse_mac(dl_dst), dl_src=parse_mac(dl_src),
2758 dl_type=0x8100),
2759 scapy.Ether(dst=dl_dst, src=dl_src)/ \
Christian Dickmann8ac55252012-10-08 22:53:49 -07002760 scapy.Dot1Q(prio=5, vlan=1000)/ \
2761 scapy.Dot1Q(prio=3, vlan=1005)/ \
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002762 scapy.IP(),
2763 self.RESULT_MATCH
2764 )
2765 testPacket("IP matching - VLAN tag",
2766 self.createMatch(dl_dst=parse_mac(dl_dst), dl_src=parse_mac(dl_src),
2767 dl_type=0x0800,
2768 nw_src=parse_ip(ip_src), nw_dst=parse_ip(ip_dst)),
2769 scapy.Ether(dst=dl_dst, src=dl_src)/ \
Christian Dickmann8ac55252012-10-08 22:53:49 -07002770 scapy.Dot1Q(prio=5, vlan=1000)/ \
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002771 scapy.IP(src=ip_src, dst=ip_dst),
2772 self.RESULT_MATCH
2773 )
2774 # XXX:
2775 # - Matching on VLAN ID and Prio
2776 # - Actions
2777
2778
2779
Dan Talayco9f47f4d2010-06-03 13:54:37 -07002780if __name__ == "__main__":
2781 print "Please run through oft script: ./oft --test_spec=basic"