blob: 8483945da3a86203888fed0bf5a14f1b504b71c1 [file] [log] [blame]
Dan Talayco5eba8442010-03-10 13:58:43 -08001"""
2Test cases for testing actions taken on packets
3
4See basic.py for other info.
5
6It is recommended that these definitions be kept in their own
7namespace as different groups of tests will likely define
8similar identifiers.
9
Rich Lane477f4812012-10-04 22:49:00 -070010The switch is actively attempting to contact the controller at the address
11indicated in config.
Dan Talayco5eba8442010-03-10 13:58:43 -080012
13"""
14
Dan Talayco9f47f4d2010-06-03 13:54:37 -070015import copy
Dan Talayco5eba8442010-03-10 13:58:43 -080016import logging
Rich Laneb90a1c42012-10-05 09:16:05 -070017import time
Dan Talayco5eba8442010-03-10 13:58:43 -080018import unittest
Christian Dickmann8b59b4b2012-09-23 16:48:30 -070019import random
Dan Talayco5eba8442010-03-10 13:58:43 -080020
Rich Lane477f4812012-10-04 22:49:00 -070021from oftest import config
Dan Talayco5eba8442010-03-10 13:58:43 -080022import oftest.controller as controller
23import oftest.cstruct as ofp
24import oftest.message as message
25import oftest.dataplane as dataplane
26import oftest.action as action
27import oftest.parse as parse
Rich Laneb90a1c42012-10-05 09:16:05 -070028import oftest.base_tests as base_tests
29import basic # for IterCases
Dan Talayco5eba8442010-03-10 13:58:43 -080030
Christian Dickmann8b59b4b2012-09-23 16:48:30 -070031from oftest.parse import parse_mac, parse_ip
32
Rich Laneda3b5ad2012-10-03 09:05:32 -070033from oftest.testutils import *
Dan Talayco5eba8442010-03-10 13:58:43 -080034
Dan Talayco551befa2010-07-15 17:05:32 -070035WILDCARD_VALUES = [ofp.OFPFW_IN_PORT,
Dan Talayco488fbc52012-04-09 16:30:41 -070036 ofp.OFPFW_DL_VLAN | ofp.OFPFW_DL_VLAN_PCP,
Dan Talayco551befa2010-07-15 17:05:32 -070037 ofp.OFPFW_DL_SRC,
38 ofp.OFPFW_DL_DST,
Dan Talayco488fbc52012-04-09 16:30:41 -070039 (ofp.OFPFW_DL_TYPE | ofp.OFPFW_NW_SRC_ALL |
40 ofp.OFPFW_NW_DST_ALL | ofp.OFPFW_NW_TOS | ofp.OFPFW_NW_PROTO |
41 ofp.OFPFW_TP_SRC | ofp.OFPFW_TP_DST),
42 (ofp.OFPFW_NW_PROTO | ofp.OFPFW_TP_SRC | ofp.OFPFW_TP_DST),
Dan Talayco551befa2010-07-15 17:05:32 -070043 ofp.OFPFW_TP_SRC,
44 ofp.OFPFW_TP_DST,
Dan Talayco488fbc52012-04-09 16:30:41 -070045 ofp.OFPFW_NW_SRC_MASK,
46 ofp.OFPFW_NW_DST_MASK,
Dan Talayco551befa2010-07-15 17:05:32 -070047 ofp.OFPFW_DL_VLAN_PCP,
48 ofp.OFPFW_NW_TOS]
49
Dan Talayco488fbc52012-04-09 16:30:41 -070050NO_WILDCARD_VALUES = [(ofp.OFPFW_ALL ^ ofp.OFPFW_IN_PORT),
51 (ofp.OFPFW_ALL ^ ofp.OFPFW_DL_VLAN),
52 (ofp.OFPFW_ALL ^ ofp.OFPFW_DL_SRC),
53 (ofp.OFPFW_ALL ^ ofp.OFPFW_DL_DST),
54 (ofp.OFPFW_ALL ^ ofp.OFPFW_DL_TYPE),
55 (ofp.OFPFW_ALL ^ ofp.OFPFW_DL_TYPE ^ ofp.OFPFW_NW_PROTO),
56 (ofp.OFPFW_ALL ^ ofp.OFPFW_DL_TYPE ^ ofp.OFPFW_NW_PROTO ^
57 ofp.OFPFW_TP_SRC),
58 (ofp.OFPFW_ALL ^ ofp.OFPFW_DL_TYPE ^ ofp.OFPFW_NW_PROTO ^
59 ofp.OFPFW_TP_DST),
60 (ofp.OFPFW_ALL ^ ofp.OFPFW_DL_TYPE ^ ofp.OFPFW_NW_PROTO ^
61 ofp.OFPFW_NW_SRC_MASK),
62 (ofp.OFPFW_ALL ^ ofp.OFPFW_DL_TYPE ^ ofp.OFPFW_NW_PROTO ^
63 ofp.OFPFW_NW_DST_MASK),
64 (ofp.OFPFW_ALL ^ ofp.OFPFW_DL_VLAN ^ ofp.OFPFW_DL_VLAN_PCP),
65 (ofp.OFPFW_ALL ^ ofp.OFPFW_DL_TYPE ^ ofp.OFPFW_NW_PROTO ^
66 ofp.OFPFW_NW_TOS)]
67
Dan Talayco551befa2010-07-15 17:05:32 -070068MODIFY_ACTION_VALUES = [ofp.OFPAT_SET_VLAN_VID,
69 ofp.OFPAT_SET_VLAN_PCP,
70 ofp.OFPAT_STRIP_VLAN,
71 ofp.OFPAT_SET_DL_SRC,
72 ofp.OFPAT_SET_DL_DST,
73 ofp.OFPAT_SET_NW_SRC,
74 ofp.OFPAT_SET_NW_DST,
75 ofp.OFPAT_SET_NW_TOS,
76 ofp.OFPAT_SET_TP_SRC,
77 ofp.OFPAT_SET_TP_DST]
78
Dan Talayco21381562010-07-17 00:34:47 -070079TEST_VID_DEFAULT = 2
80
Rich Laneb90a1c42012-10-05 09:16:05 -070081class DirectPacket(base_tests.SimpleDataPlane):
Dan Talayco5eba8442010-03-10 13:58:43 -080082 """
Dan Talayco2d0d49a2010-05-11 15:29:08 -070083 Send packet to single egress port
Dan Talayco5eba8442010-03-10 13:58:43 -080084
85 Generate a packet
86 Generate and install a matching flow
87 Add action to direct the packet to an egress port
88 Send the packet to ingress dataplane port
89 Verify the packet is received at the egress port only
90 """
91 def runTest(self):
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -070092 self.handleFlow()
93
94 def handleFlow(self, pkttype='TCP'):
Rich Lane477f4812012-10-04 22:49:00 -070095 of_ports = config["port_map"].keys()
Dan Talayco5eba8442010-03-10 13:58:43 -080096 of_ports.sort()
97 self.assertTrue(len(of_ports) > 1, "Not enough ports for test")
98
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -070099 if (pkttype == 'ICMP'):
100 pkt = simple_icmp_packet()
101 else:
102 pkt = simple_tcp_packet()
Ed Swierk99a74de2012-08-22 06:40:54 -0700103 match = packet_to_flow_match(self, pkt)
Dan Talayco7dd6cd62010-03-16 15:02:35 -0700104 match.wildcards &= ~ofp.OFPFW_IN_PORT
Dan Talayco5eba8442010-03-10 13:58:43 -0800105 self.assertTrue(match is not None,
106 "Could not generate flow match from pkt")
107 act = action.action_output()
108
109 for idx in range(len(of_ports)):
Rich Lane9a003812012-10-04 17:17:59 -0700110 rv = delete_all_flows(self.controller)
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700111 self.assertEqual(rv, 0, "Failed to delete all flows")
Dan Talayco2e77a842010-05-12 15:39:46 -0700112
Dan Talayco5eba8442010-03-10 13:58:43 -0800113 ingress_port = of_ports[idx]
114 egress_port = of_ports[(idx + 1) % len(of_ports)]
Rich Lane9a003812012-10-04 17:17:59 -0700115 logging.info("Ingress " + str(ingress_port) +
Dan Talayco551befa2010-07-15 17:05:32 -0700116 " to egress " + str(egress_port))
Dan Talayco5eba8442010-03-10 13:58:43 -0800117
118 match.in_port = ingress_port
119
120 request = message.flow_mod()
121 request.match = match
Jeffrey Townsend2a300e42012-03-28 17:24:02 -0700122
Dan Talayco5eba8442010-03-10 13:58:43 -0800123 request.buffer_id = 0xffffffff
124 act.port = egress_port
125 self.assertTrue(request.actions.add(act), "Could not add action")
126
Rich Lane9a003812012-10-04 17:17:59 -0700127 logging.info("Inserting flow")
Dan Talayco5eba8442010-03-10 13:58:43 -0800128 rv = self.controller.message_send(request)
129 self.assertTrue(rv != -1, "Error installing flow mod")
Dan Talayco0fc08bd2012-04-09 16:56:18 -0700130 self.assertEqual(do_barrier(self.controller), 0, "Barrier failed")
Dan Talayco5eba8442010-03-10 13:58:43 -0800131
Rich Lane9a003812012-10-04 17:17:59 -0700132 logging.info("Sending packet to dp port " +
Dan Talayco5eba8442010-03-10 13:58:43 -0800133 str(ingress_port))
134 self.dataplane.send(ingress_port, str(pkt))
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700135
136 exp_pkt_arg = None
137 exp_port = None
Rich Lane477f4812012-10-04 22:49:00 -0700138 if config["relax"]:
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700139 exp_pkt_arg = pkt
140 exp_port = egress_port
141
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700142 (rcv_port, rcv_pkt, pkt_time) = self.dataplane.poll(port_number=exp_port,
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700143 exp_pkt=exp_pkt_arg)
Dan Talayco5eba8442010-03-10 13:58:43 -0800144 self.assertTrue(rcv_pkt is not None, "Did not receive packet")
Rich Lane9a003812012-10-04 17:17:59 -0700145 logging.debug("Packet len " + str(len(rcv_pkt)) + " in on " +
Dan Talayco5eba8442010-03-10 13:58:43 -0800146 str(rcv_port))
147 self.assertEqual(rcv_port, egress_port, "Unexpected receive port")
148 self.assertEqual(str(pkt), str(rcv_pkt),
149 'Response packet does not match send packet')
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700150
Rich Laneb90a1c42012-10-05 09:16:05 -0700151class DirectPacketController(base_tests.SimpleDataPlane):
Rich Lane51c23b32012-07-27 16:37:25 -0700152 """
153 Send packet to the controller port
154
155 Generate a packet
156 Generate and install a matching flow
157 Add action to direct the packet to the controller port
158 Send the packet to ingress dataplane port
159 Verify the packet is received at the controller port
160 """
161 def runTest(self):
162 self.handleFlow()
163
164 def handleFlow(self, pkttype='TCP'):
Rich Lane477f4812012-10-04 22:49:00 -0700165 of_ports = config["port_map"].keys()
Rich Lane51c23b32012-07-27 16:37:25 -0700166 of_ports.sort()
167 self.assertTrue(len(of_ports) > 0, "Not enough ports for test")
168
169 if (pkttype == 'ICMP'):
170 pkt = simple_icmp_packet()
171 else:
172 pkt = simple_tcp_packet()
Ed Swierk99a74de2012-08-22 06:40:54 -0700173 match = packet_to_flow_match(self, pkt)
Rich Lane51c23b32012-07-27 16:37:25 -0700174 match.wildcards &= ~ofp.OFPFW_IN_PORT
175 self.assertTrue(match is not None,
176 "Could not generate flow match from pkt")
177 act = action.action_output()
178
Rich Lane9a003812012-10-04 17:17:59 -0700179 rv = delete_all_flows(self.controller)
Rich Lane51c23b32012-07-27 16:37:25 -0700180 self.assertEqual(rv, 0, "Failed to delete all flows")
181
182 ingress_port = of_ports[0]
183 match.in_port = ingress_port
184
185 request = message.flow_mod()
186 request.match = match
187
188 request.buffer_id = 0xffffffff
189 act.port = ofp.OFPP_CONTROLLER
190 act.max_len = 65535
191 self.assertTrue(request.actions.add(act), "Could not add action")
192
Rich Lane9a003812012-10-04 17:17:59 -0700193 logging.info("Inserting flow")
Rich Lane51c23b32012-07-27 16:37:25 -0700194 rv = self.controller.message_send(request)
195 self.assertTrue(rv != -1, "Error installing flow mod")
196 self.assertEqual(do_barrier(self.controller), 0, "Barrier failed")
197
Rich Lane9a003812012-10-04 17:17:59 -0700198 logging.info("Sending packet to dp port " +
Rich Lane51c23b32012-07-27 16:37:25 -0700199 str(ingress_port))
200 self.dataplane.send(ingress_port, str(pkt))
201
202 (response, raw) = self.controller.poll(ofp.OFPT_PACKET_IN)
203
204 self.assertTrue(response is not None,
205 'Packet in message not received by controller')
206 if not dataplane.match_exp_pkt(pkt, response.data):
Rich Lane9a003812012-10-04 17:17:59 -0700207 logging.debug("Sent %s" % format_packet(pkt))
208 logging.debug("Resp %s" % format_packet(response.data))
Rich Lane51c23b32012-07-27 16:37:25 -0700209 self.assertTrue(False,
210 'Response packet does not match send packet' +
211 ' for controller port')
212
Howard Pershf97840f2012-04-10 16:30:42 -0700213
Rich Laneb90a1c42012-10-05 09:16:05 -0700214class DirectPacketQueue(base_tests.SimpleDataPlane):
Howard Pershf97840f2012-04-10 16:30:42 -0700215 """
216 Send packet to single queue on single egress port
217
218 Generate a packet
219 Generate and install a matching flow
220 Add action to direct the packet to an egress port and queue
221 Send the packet to ingress dataplane port
222 Verify the packet is received at the egress port only
223 """
224 def runTest(self):
225 self.handleFlow()
226
Howard Persh670b5672012-04-13 09:08:29 -0700227 def portQueuesGet(self, queue_stats, port_num):
228 result = []
229 for qs in queue_stats.stats:
230 if qs.port_no != port_num:
231 continue
232 result.append(qs.queue_id)
233 return result
234
Howard Pershf97840f2012-04-10 16:30:42 -0700235 def handleFlow(self, pkttype='TCP'):
Rich Lane477f4812012-10-04 22:49:00 -0700236 of_ports = config["port_map"].keys()
Howard Pershf97840f2012-04-10 16:30:42 -0700237 of_ports.sort()
238 self.assertTrue(len(of_ports) > 1, "Not enough ports for test")
239
240 if (pkttype == 'ICMP'):
241 pkt = simple_icmp_packet()
242 else:
243 pkt = simple_tcp_packet()
Ed Swierk99a74de2012-08-22 06:40:54 -0700244 match = packet_to_flow_match(self, pkt)
Howard Pershf97840f2012-04-10 16:30:42 -0700245 match.wildcards &= ~ofp.OFPFW_IN_PORT
246 self.assertTrue(match is not None,
247 "Could not generate flow match from pkt")
248
Howard Persh670b5672012-04-13 09:08:29 -0700249 # Get queue stats from switch
250
251 request = message.queue_stats_request()
252 request.port_no = ofp.OFPP_ALL
253 request.queue_id = ofp.OFPQ_ALL
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700254 (queue_stats, p) = self.controller.transact(request)
Howard Persh670b5672012-04-13 09:08:29 -0700255 self.assertNotEqual(queue_stats, None, "Queue stats request failed")
256
257 act = action.action_enqueue()
Howard Pershf97840f2012-04-10 16:30:42 -0700258
259 for idx in range(len(of_ports)):
Howard Pershf97840f2012-04-10 16:30:42 -0700260 ingress_port = of_ports[idx]
261 egress_port = of_ports[(idx + 1) % len(of_ports)]
Howard Pershf97840f2012-04-10 16:30:42 -0700262
Howard Persh670b5672012-04-13 09:08:29 -0700263 for egress_queue_id in self.portQueuesGet(queue_stats, egress_port):
Rich Lane9a003812012-10-04 17:17:59 -0700264 logging.info("Ingress " + str(ingress_port)
Howard Persh670b5672012-04-13 09:08:29 -0700265 + " to egress " + str(egress_port)
266 + " queue " + str(egress_queue_id)
267 )
Howard Pershf97840f2012-04-10 16:30:42 -0700268
Rich Lane9a003812012-10-04 17:17:59 -0700269 rv = delete_all_flows(self.controller)
Howard Persh670b5672012-04-13 09:08:29 -0700270 self.assertEqual(rv, 0, "Failed to delete all flows")
Howard Pershf97840f2012-04-10 16:30:42 -0700271
Howard Persh670b5672012-04-13 09:08:29 -0700272 match.in_port = ingress_port
273
274 request = message.flow_mod()
275 request.match = match
Howard Pershf97840f2012-04-10 16:30:42 -0700276
Howard Persh670b5672012-04-13 09:08:29 -0700277 request.buffer_id = 0xffffffff
278 act.port = egress_port
279 act.queue_id = egress_queue_id
280 self.assertTrue(request.actions.add(act), "Could not add action")
Howard Pershf97840f2012-04-10 16:30:42 -0700281
Rich Lane9a003812012-10-04 17:17:59 -0700282 logging.info("Inserting flow")
Howard Persh670b5672012-04-13 09:08:29 -0700283 rv = self.controller.message_send(request)
284 self.assertTrue(rv != -1, "Error installing flow mod")
285 self.assertEqual(do_barrier(self.controller), 0, "Barrier failed")
Howard Pershf97840f2012-04-10 16:30:42 -0700286
Howard Persh670b5672012-04-13 09:08:29 -0700287 # Get current stats for selected egress queue
Howard Pershf97840f2012-04-10 16:30:42 -0700288
Howard Persh670b5672012-04-13 09:08:29 -0700289 request = message.queue_stats_request()
290 request.port_no = egress_port
291 request.queue_id = egress_queue_id
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700292 (qs_before, p) = self.controller.transact(request)
Howard Persh670b5672012-04-13 09:08:29 -0700293 self.assertNotEqual(qs_before, None, "Queue stats request failed")
294
Rich Lane9a003812012-10-04 17:17:59 -0700295 logging.info("Sending packet to dp port " +
Howard Persh670b5672012-04-13 09:08:29 -0700296 str(ingress_port))
297 self.dataplane.send(ingress_port, str(pkt))
298
299 exp_pkt_arg = None
300 exp_port = None
Rich Lane477f4812012-10-04 22:49:00 -0700301 if config["relax"]:
Howard Persh670b5672012-04-13 09:08:29 -0700302 exp_pkt_arg = pkt
303 exp_port = egress_port
304
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700305 (rcv_port, rcv_pkt, pkt_time) = self.dataplane.poll(port_number=exp_port,
Howard Persh670b5672012-04-13 09:08:29 -0700306 exp_pkt=exp_pkt_arg)
307 self.assertTrue(rcv_pkt is not None, "Did not receive packet")
Rich Lane9a003812012-10-04 17:17:59 -0700308 logging.debug("Packet len " + str(len(rcv_pkt)) + " in on " +
Howard Persh670b5672012-04-13 09:08:29 -0700309 str(rcv_port))
310 self.assertEqual(rcv_port, egress_port, "Unexpected receive port")
311 self.assertEqual(str(pkt), str(rcv_pkt),
312 'Response packet does not match send packet')
313
Ed Swierkb8a86512012-04-18 18:45:58 -0700314 # FIXME: instead of sleeping, keep requesting queue stats until
315 # the expected queue counter increases or some large timeout is
316 # reached
317 time.sleep(2)
318
Howard Persh670b5672012-04-13 09:08:29 -0700319 # Get current stats for selected egress queue again
320
321 request = message.queue_stats_request()
322 request.port_no = egress_port
323 request.queue_id = egress_queue_id
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700324 (qs_after, p) = self.controller.transact(request)
Howard Persh670b5672012-04-13 09:08:29 -0700325 self.assertNotEqual(qs_after, None, "Queue stats request failed")
326
327 # Make sure that tx packet counter for selected egress queue was
328 # incremented
329
Ed Swierk22f59152012-04-17 16:36:47 -0700330 self.assertEqual(qs_after.stats[0].tx_packets, \
331 qs_before.stats[0].tx_packets + 1, \
Howard Persh670b5672012-04-13 09:08:29 -0700332 "Verification of egress queue tx packet count failed"
333 )
334
335
Rich Laneb90a1c42012-10-05 09:16:05 -0700336class DirectPacketControllerQueue(base_tests.SimpleDataPlane):
Ken Chiang899ff8e2012-05-23 18:26:12 -0700337 """
338 Send a packet from each of the openflow ports
339 to each of the queues configured on the controller port.
340 If no queues have been configured, no packets are sent.
Howard Pershf97840f2012-04-10 16:30:42 -0700341
Ken Chiang899ff8e2012-05-23 18:26:12 -0700342 Generate a packet
343 Generate and install a matching flow
344 Add action to direct the packet to one of the controller port queues
345 Send the packet to ingress dataplane port
346 Verify the packet is received on the controller port queue
347 """
348 def runTest(self):
349 self.handleFlow()
350
351 def portQueuesGet(self, queue_stats, port_num):
352 result = []
353 for qs in queue_stats.stats:
354 if qs.port_no != port_num:
355 continue
356 result.append(qs.queue_id)
357 return result
358
359 def handleFlow(self, pkttype='TCP'):
Rich Lane477f4812012-10-04 22:49:00 -0700360 of_ports = config["port_map"].keys()
Ken Chiang899ff8e2012-05-23 18:26:12 -0700361 of_ports.sort()
362 self.assertTrue(len(of_ports) > 1, "Not enough ports for test")
363
364 if (pkttype == 'ICMP'):
365 pkt = simple_icmp_packet()
366 else:
367 pkt = simple_tcp_packet()
Ed Swierk99a74de2012-08-22 06:40:54 -0700368 match = packet_to_flow_match(self, pkt)
Ken Chiang899ff8e2012-05-23 18:26:12 -0700369 match.wildcards &= ~ofp.OFPFW_IN_PORT
370 self.assertTrue(match is not None,
371 "Could not generate flow match from pkt")
372
373 # Get queue stats from switch
374
375 request = message.queue_stats_request()
376 request.port_no = ofp.OFPP_CONTROLLER
377 request.queue_id = ofp.OFPQ_ALL
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700378 (queue_stats, p) = self.controller.transact(request)
Ken Chiang899ff8e2012-05-23 18:26:12 -0700379 self.assertNotEqual(queue_stats, None, "Queue stats request failed")
380
381 act = action.action_enqueue()
382
383 for idx in range(len(of_ports)):
384 ingress_port = of_ports[idx]
385 egress_port = ofp.OFPP_CONTROLLER
386
Rich Lane9a003812012-10-04 17:17:59 -0700387 logging.info("Ingress port " + str(ingress_port)
Ken Chiang899ff8e2012-05-23 18:26:12 -0700388 + ", controller port queues "
389 + str(self.portQueuesGet(queue_stats, egress_port)))
390
391 for egress_queue_id in self.portQueuesGet(queue_stats, egress_port):
Rich Lane9a003812012-10-04 17:17:59 -0700392 logging.info("Ingress " + str(ingress_port)
Ken Chiang899ff8e2012-05-23 18:26:12 -0700393 + " to egress " + str(egress_port)
394 + " queue " + str(egress_queue_id)
395 )
396
Rich Lane9a003812012-10-04 17:17:59 -0700397 rv = delete_all_flows(self.controller)
Ken Chiang899ff8e2012-05-23 18:26:12 -0700398 self.assertEqual(rv, 0, "Failed to delete all flows")
399
400 match.in_port = ingress_port
401
402 request = message.flow_mod()
403 request.match = match
404
405 request.buffer_id = 0xffffffff
406 act.port = egress_port
407 act.queue_id = egress_queue_id
408 self.assertTrue(request.actions.add(act), "Could not add action")
409
Rich Lane9a003812012-10-04 17:17:59 -0700410 logging.info("Inserting flow")
Ken Chiang899ff8e2012-05-23 18:26:12 -0700411 rv = self.controller.message_send(request)
412 self.assertTrue(rv != -1, "Error installing flow mod")
413 self.assertEqual(do_barrier(self.controller), 0, "Barrier failed")
414
415 # Get current stats for selected egress queue
416
417 request = message.queue_stats_request()
418 request.port_no = egress_port
419 request.queue_id = egress_queue_id
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700420 (qs_before, p) = self.controller.transact(request)
Ken Chiang899ff8e2012-05-23 18:26:12 -0700421 self.assertNotEqual(qs_before, None, "Queue stats request failed")
422
Rich Lane9a003812012-10-04 17:17:59 -0700423 logging.info("Sending packet to dp port " +
Ken Chiang899ff8e2012-05-23 18:26:12 -0700424 str(ingress_port))
425 self.dataplane.send(ingress_port, str(pkt))
426
427 exp_pkt_arg = None
428 exp_port = None
429
Rich Lanee5779d32012-10-05 17:56:04 -0700430 count = 0
Ken Chiang899ff8e2012-05-23 18:26:12 -0700431 while True:
Dan Talaycoc689a792012-09-28 14:22:53 -0700432 (response, raw) = self.controller.poll(ofp.OFPT_PACKET_IN)
Ken Chiang899ff8e2012-05-23 18:26:12 -0700433 if not response: # Timeout
434 break
435 if dataplane.match_exp_pkt(pkt, response.data): # Got match
436 break
Rich Lane477f4812012-10-04 22:49:00 -0700437 if not config["relax"]: # Only one attempt to match
Ken Chiang899ff8e2012-05-23 18:26:12 -0700438 break
439 count += 1
440 if count > 10: # Too many tries
441 break
442
443 self.assertTrue(response is not None,
444 'Packet in message not received by controller')
445 if not dataplane.match_exp_pkt(pkt, response.data):
Rich Lane9a003812012-10-04 17:17:59 -0700446 logging.debug("Sent %s" % format_packet(pkt))
447 logging.debug("Resp %s" % format_packet(response.data))
Ken Chiang899ff8e2012-05-23 18:26:12 -0700448 self.assertTrue(False,
449 'Response packet does not match send packet' +
450 ' for controller port')
451
452 # FIXME: instead of sleeping, keep requesting queue stats until
453 # the expected queue counter increases or some large timeout is
454 # reached
455 time.sleep(2)
456
457 # Get current stats for selected egress queue again
458
459 request = message.queue_stats_request()
460 request.port_no = egress_port
461 request.queue_id = egress_queue_id
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700462 (qs_after, p) = self.controller.transact(request)
Ken Chiang899ff8e2012-05-23 18:26:12 -0700463 self.assertNotEqual(qs_after, None, "Queue stats request failed")
464
465 # Make sure that tx packet counter for selected egress queue was
466 # incremented
467
468 self.assertEqual(qs_after.stats[0].tx_packets, \
469 qs_before.stats[0].tx_packets + 1, \
470 "Verification of egress queue tx packet count failed"
471 )
472
Howard Pershf97840f2012-04-10 16:30:42 -0700473
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700474class DirectPacketICMP(DirectPacket):
475 """
476 Send ICMP packet to single egress port
477
478 Generate a ICMP packet
479 Generate and install a matching flow
480 Add action to direct the packet to an egress port
481 Send the packet to ingress dataplane port
482 Verify the packet is received at the egress port only
483 Difference from DirectPacket test is that sent packet is ICMP
484 """
485 def runTest(self):
486 self.handleFlow(pkttype='ICMP')
Dan Talayco2d0d49a2010-05-11 15:29:08 -0700487
Rich Laneb90a1c42012-10-05 09:16:05 -0700488class DirectTwoPorts(base_tests.SimpleDataPlane):
Dan Talayco2d0d49a2010-05-11 15:29:08 -0700489 """
490 Send packet to two egress ports
491
492 Generate a packet
493 Generate and install a matching flow
494 Add action to direct the packet to two egress ports
495 Send the packet to ingress dataplane port
496 Verify the packet is received at the two egress ports
497 """
498 def runTest(self):
Rich Lane477f4812012-10-04 22:49:00 -0700499 of_ports = config["port_map"].keys()
Dan Talayco2d0d49a2010-05-11 15:29:08 -0700500 of_ports.sort()
501 self.assertTrue(len(of_ports) > 2, "Not enough ports for test")
502
Dan Talayco2d0d49a2010-05-11 15:29:08 -0700503 pkt = simple_tcp_packet()
Ed Swierk99a74de2012-08-22 06:40:54 -0700504 match = packet_to_flow_match(self, pkt)
Dan Talayco2d0d49a2010-05-11 15:29:08 -0700505 match.wildcards &= ~ofp.OFPFW_IN_PORT
506 self.assertTrue(match is not None,
507 "Could not generate flow match from pkt")
508 act = action.action_output()
509
510 for idx in range(len(of_ports)):
Rich Lane9a003812012-10-04 17:17:59 -0700511 rv = delete_all_flows(self.controller)
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700512 self.assertEqual(rv, 0, "Failed to delete all flows")
Dan Talayco2e77a842010-05-12 15:39:46 -0700513
Dan Talayco2d0d49a2010-05-11 15:29:08 -0700514 ingress_port = of_ports[idx]
515 egress_port1 = of_ports[(idx + 1) % len(of_ports)]
516 egress_port2 = of_ports[(idx + 2) % len(of_ports)]
Rich Lane9a003812012-10-04 17:17:59 -0700517 logging.info("Ingress " + str(ingress_port) +
Dan Talayco2d0d49a2010-05-11 15:29:08 -0700518 " to egress " + str(egress_port1) + " and " +
519 str(egress_port2))
520
521 match.in_port = ingress_port
522
523 request = message.flow_mod()
524 request.match = match
525 request.buffer_id = 0xffffffff
526 act.port = egress_port1
527 self.assertTrue(request.actions.add(act), "Could not add action1")
528 act.port = egress_port2
529 self.assertTrue(request.actions.add(act), "Could not add action2")
Rich Lane9a003812012-10-04 17:17:59 -0700530 # logging.info(request.show())
Dan Talayco2d0d49a2010-05-11 15:29:08 -0700531
Rich Lane9a003812012-10-04 17:17:59 -0700532 logging.info("Inserting flow")
Dan Talayco2d0d49a2010-05-11 15:29:08 -0700533 rv = self.controller.message_send(request)
534 self.assertTrue(rv != -1, "Error installing flow mod")
Dan Talayco0fc08bd2012-04-09 16:56:18 -0700535 self.assertEqual(do_barrier(self.controller), 0, "Barrier failed")
Dan Talayco2d0d49a2010-05-11 15:29:08 -0700536
Rich Lane9a003812012-10-04 17:17:59 -0700537 logging.info("Sending packet to dp port " +
Dan Talayco2d0d49a2010-05-11 15:29:08 -0700538 str(ingress_port))
539 self.dataplane.send(ingress_port, str(pkt))
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700540 yes_ports = set([egress_port1, egress_port2])
541 no_ports = set(of_ports).difference(yes_ports)
Dan Talayco2d0d49a2010-05-11 15:29:08 -0700542
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700543 receive_pkt_check(self.dataplane, pkt, yes_ports, no_ports,
Rich Lane2014f9b2012-10-05 15:29:40 -0700544 self)
Dan Talaycob0b0fdb2010-05-11 15:44:56 -0700545
Rich Laneb90a1c42012-10-05 09:16:05 -0700546class DirectMCNonIngress(base_tests.SimpleDataPlane):
Dan Talaycob0b0fdb2010-05-11 15:44:56 -0700547 """
548 Multicast to all non-ingress ports
549
550 Generate a packet
551 Generate and install a matching flow
552 Add action to direct the packet to all non-ingress ports
553 Send the packet to ingress dataplane port
554 Verify the packet is received at all non-ingress ports
555
556 Does not use the flood action
557 """
558 def runTest(self):
Rich Lane477f4812012-10-04 22:49:00 -0700559 of_ports = config["port_map"].keys()
Dan Talaycob0b0fdb2010-05-11 15:44:56 -0700560 of_ports.sort()
561 self.assertTrue(len(of_ports) > 2, "Not enough ports for test")
562
Dan Talaycob0b0fdb2010-05-11 15:44:56 -0700563 pkt = simple_tcp_packet()
Ed Swierk99a74de2012-08-22 06:40:54 -0700564 match = packet_to_flow_match(self, pkt)
Dan Talaycob0b0fdb2010-05-11 15:44:56 -0700565 match.wildcards &= ~ofp.OFPFW_IN_PORT
566 self.assertTrue(match is not None,
567 "Could not generate flow match from pkt")
568 act = action.action_output()
569
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700570 for ingress_port in of_ports:
Rich Lane9a003812012-10-04 17:17:59 -0700571 rv = delete_all_flows(self.controller)
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700572 self.assertEqual(rv, 0, "Failed to delete all flows")
Dan Talayco2e77a842010-05-12 15:39:46 -0700573
Rich Lane9a003812012-10-04 17:17:59 -0700574 logging.info("Ingress " + str(ingress_port) +
Dan Talaycob0b0fdb2010-05-11 15:44:56 -0700575 " all non-ingress ports")
Dan Talaycob0b0fdb2010-05-11 15:44:56 -0700576 match.in_port = ingress_port
577
578 request = message.flow_mod()
579 request.match = match
580 request.buffer_id = 0xffffffff
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700581 for egress_port in of_ports:
582 if egress_port == ingress_port:
Dan Talaycob0b0fdb2010-05-11 15:44:56 -0700583 continue
Dan Talaycob0b0fdb2010-05-11 15:44:56 -0700584 act.port = egress_port
585 self.assertTrue(request.actions.add(act),
586 "Could not add output to " + str(egress_port))
Rich Lane9a003812012-10-04 17:17:59 -0700587 logging.debug(request.show())
Dan Talaycob0b0fdb2010-05-11 15:44:56 -0700588
Rich Lane9a003812012-10-04 17:17:59 -0700589 logging.info("Inserting flow")
Dan Talaycob0b0fdb2010-05-11 15:44:56 -0700590 rv = self.controller.message_send(request)
591 self.assertTrue(rv != -1, "Error installing flow mod")
Dan Talayco0fc08bd2012-04-09 16:56:18 -0700592 self.assertEqual(do_barrier(self.controller), 0, "Barrier failed")
Dan Talaycob0b0fdb2010-05-11 15:44:56 -0700593
Rich Lane9a003812012-10-04 17:17:59 -0700594 logging.info("Sending packet to dp port " + str(ingress_port))
Dan Talaycob0b0fdb2010-05-11 15:44:56 -0700595 self.dataplane.send(ingress_port, str(pkt))
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700596 yes_ports = set(of_ports).difference([ingress_port])
597 receive_pkt_check(self.dataplane, pkt, yes_ports, [ingress_port],
Rich Lane2014f9b2012-10-05 15:29:40 -0700598 self)
Dan Talaycob0b0fdb2010-05-11 15:44:56 -0700599
Dan Talayco32fa6542010-05-11 15:54:08 -0700600
Rich Laneb90a1c42012-10-05 09:16:05 -0700601class DirectMC(base_tests.SimpleDataPlane):
Dan Talayco32fa6542010-05-11 15:54:08 -0700602 """
603 Multicast to all ports including ingress
604
605 Generate a packet
606 Generate and install a matching flow
607 Add action to direct the packet to all non-ingress ports
608 Send the packet to ingress dataplane port
609 Verify the packet is received at all ports
610
611 Does not use the flood action
612 """
613 def runTest(self):
Rich Lane477f4812012-10-04 22:49:00 -0700614 of_ports = config["port_map"].keys()
Dan Talayco32fa6542010-05-11 15:54:08 -0700615 of_ports.sort()
616 self.assertTrue(len(of_ports) > 2, "Not enough ports for test")
617
Dan Talayco32fa6542010-05-11 15:54:08 -0700618 pkt = simple_tcp_packet()
Ed Swierk99a74de2012-08-22 06:40:54 -0700619 match = packet_to_flow_match(self, pkt)
Dan Talayco32fa6542010-05-11 15:54:08 -0700620 match.wildcards &= ~ofp.OFPFW_IN_PORT
621 self.assertTrue(match is not None,
622 "Could not generate flow match from pkt")
623 act = action.action_output()
624
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700625 for ingress_port in of_ports:
Rich Lane9a003812012-10-04 17:17:59 -0700626 rv = delete_all_flows(self.controller)
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700627 self.assertEqual(rv, 0, "Failed to delete all flows")
Dan Talayco2e77a842010-05-12 15:39:46 -0700628
Rich Lane9a003812012-10-04 17:17:59 -0700629 logging.info("Ingress " + str(ingress_port) + " to all ports")
Dan Talayco32fa6542010-05-11 15:54:08 -0700630 match.in_port = ingress_port
631
632 request = message.flow_mod()
633 request.match = match
634 request.buffer_id = 0xffffffff
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700635 for egress_port in of_ports:
636 if egress_port == ingress_port:
Dan Talayco32fa6542010-05-11 15:54:08 -0700637 act.port = ofp.OFPP_IN_PORT
638 else:
639 act.port = egress_port
640 self.assertTrue(request.actions.add(act),
641 "Could not add output to " + str(egress_port))
Rich Lane9a003812012-10-04 17:17:59 -0700642 # logging.info(request.show())
Dan Talayco2e77a842010-05-12 15:39:46 -0700643
Rich Lane9a003812012-10-04 17:17:59 -0700644 logging.info("Inserting flow")
Dan Talayco2e77a842010-05-12 15:39:46 -0700645 rv = self.controller.message_send(request)
646 self.assertTrue(rv != -1, "Error installing flow mod")
Dan Talayco0fc08bd2012-04-09 16:56:18 -0700647 self.assertEqual(do_barrier(self.controller), 0, "Barrier failed")
Dan Talayco2e77a842010-05-12 15:39:46 -0700648
Rich Lane9a003812012-10-04 17:17:59 -0700649 logging.info("Sending packet to dp port " + str(ingress_port))
Dan Talayco2e77a842010-05-12 15:39:46 -0700650 self.dataplane.send(ingress_port, str(pkt))
Rich Lane2014f9b2012-10-05 15:29:40 -0700651 receive_pkt_check(self.dataplane, pkt, of_ports, [], self)
Dan Talayco2e77a842010-05-12 15:39:46 -0700652
Rich Laneb90a1c42012-10-05 09:16:05 -0700653class Flood(base_tests.SimpleDataPlane):
Dan Talayco2e77a842010-05-12 15:39:46 -0700654 """
655 Flood to all ports except ingress
656
657 Generate a packet
658 Generate and install a matching flow
659 Add action to flood the packet
660 Send the packet to ingress dataplane port
661 Verify the packet is received at all other ports
662 """
663 def runTest(self):
Rich Lane477f4812012-10-04 22:49:00 -0700664 of_ports = config["port_map"].keys()
Dan Talayco2e77a842010-05-12 15:39:46 -0700665 of_ports.sort()
666 self.assertTrue(len(of_ports) > 1, "Not enough ports for test")
667
668 pkt = simple_tcp_packet()
Ed Swierk99a74de2012-08-22 06:40:54 -0700669 match = packet_to_flow_match(self, pkt)
Dan Talayco2e77a842010-05-12 15:39:46 -0700670 match.wildcards &= ~ofp.OFPFW_IN_PORT
671 self.assertTrue(match is not None,
672 "Could not generate flow match from pkt")
673 act = action.action_output()
674
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700675 for ingress_port in of_ports:
Rich Lane9a003812012-10-04 17:17:59 -0700676 rv = delete_all_flows(self.controller)
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700677 self.assertEqual(rv, 0, "Failed to delete all flows")
Dan Talayco2e77a842010-05-12 15:39:46 -0700678
Rich Lane9a003812012-10-04 17:17:59 -0700679 logging.info("Ingress " + str(ingress_port) + " to all ports")
Dan Talayco2e77a842010-05-12 15:39:46 -0700680 match.in_port = ingress_port
681
682 request = message.flow_mod()
683 request.match = match
684 request.buffer_id = 0xffffffff
685 act.port = ofp.OFPP_FLOOD
686 self.assertTrue(request.actions.add(act),
Dan Talayco4aa13122010-05-12 15:54:44 -0700687 "Could not add flood port action")
Rich Lane9a003812012-10-04 17:17:59 -0700688 logging.info(request.show())
Dan Talayco32fa6542010-05-11 15:54:08 -0700689
Rich Lane9a003812012-10-04 17:17:59 -0700690 logging.info("Inserting flow")
Dan Talayco32fa6542010-05-11 15:54:08 -0700691 rv = self.controller.message_send(request)
692 self.assertTrue(rv != -1, "Error installing flow mod")
Dan Talayco0fc08bd2012-04-09 16:56:18 -0700693 self.assertEqual(do_barrier(self.controller), 0, "Barrier failed")
Dan Talayco32fa6542010-05-11 15:54:08 -0700694
Rich Lane9a003812012-10-04 17:17:59 -0700695 logging.info("Sending packet to dp port " + str(ingress_port))
Dan Talayco32fa6542010-05-11 15:54:08 -0700696 self.dataplane.send(ingress_port, str(pkt))
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700697 yes_ports = set(of_ports).difference([ingress_port])
698 receive_pkt_check(self.dataplane, pkt, yes_ports, [ingress_port],
Rich Lane2014f9b2012-10-05 15:29:40 -0700699 self)
Dan Talayco3be5b062010-05-12 15:46:21 -0700700
Rich Laneb90a1c42012-10-05 09:16:05 -0700701class FloodPlusIngress(base_tests.SimpleDataPlane):
Dan Talayco3be5b062010-05-12 15:46:21 -0700702 """
703 Flood to all ports plus send to ingress port
704
705 Generate a packet
706 Generate and install a matching flow
707 Add action to flood the packet
708 Add action to send to ingress port
709 Send the packet to ingress dataplane port
710 Verify the packet is received at all other ports
711 """
712 def runTest(self):
Rich Lane477f4812012-10-04 22:49:00 -0700713 of_ports = config["port_map"].keys()
Dan Talayco3be5b062010-05-12 15:46:21 -0700714 of_ports.sort()
715 self.assertTrue(len(of_ports) > 1, "Not enough ports for test")
716
717 pkt = simple_tcp_packet()
Ed Swierk99a74de2012-08-22 06:40:54 -0700718 match = packet_to_flow_match(self, pkt)
Dan Talayco3be5b062010-05-12 15:46:21 -0700719 match.wildcards &= ~ofp.OFPFW_IN_PORT
720 self.assertTrue(match is not None,
721 "Could not generate flow match from pkt")
722 act = action.action_output()
723
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700724 for ingress_port in of_ports:
Rich Lane9a003812012-10-04 17:17:59 -0700725 rv = delete_all_flows(self.controller)
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700726 self.assertEqual(rv, 0, "Failed to delete all flows")
Dan Talayco3be5b062010-05-12 15:46:21 -0700727
Rich Lane9a003812012-10-04 17:17:59 -0700728 logging.info("Ingress " + str(ingress_port) + " to all ports")
Dan Talayco3be5b062010-05-12 15:46:21 -0700729 match.in_port = ingress_port
730
731 request = message.flow_mod()
732 request.match = match
733 request.buffer_id = 0xffffffff
734 act.port = ofp.OFPP_FLOOD
735 self.assertTrue(request.actions.add(act),
Dan Talayco4aa13122010-05-12 15:54:44 -0700736 "Could not add flood port action")
737 act.port = ofp.OFPP_IN_PORT
738 self.assertTrue(request.actions.add(act),
739 "Could not add ingress port for output")
Rich Lane9a003812012-10-04 17:17:59 -0700740 logging.info(request.show())
Dan Talayco4aa13122010-05-12 15:54:44 -0700741
Rich Lane9a003812012-10-04 17:17:59 -0700742 logging.info("Inserting flow")
Dan Talayco4aa13122010-05-12 15:54:44 -0700743 rv = self.controller.message_send(request)
744 self.assertTrue(rv != -1, "Error installing flow mod")
Dan Talayco0fc08bd2012-04-09 16:56:18 -0700745 self.assertEqual(do_barrier(self.controller), 0, "Barrier failed")
Dan Talayco4aa13122010-05-12 15:54:44 -0700746
Rich Lane9a003812012-10-04 17:17:59 -0700747 logging.info("Sending packet to dp port " + str(ingress_port))
Dan Talayco4aa13122010-05-12 15:54:44 -0700748 self.dataplane.send(ingress_port, str(pkt))
Rich Lane2014f9b2012-10-05 15:29:40 -0700749 receive_pkt_check(self.dataplane, pkt, of_ports, [], self)
Dan Talayco4aa13122010-05-12 15:54:44 -0700750
Rich Laneb90a1c42012-10-05 09:16:05 -0700751class All(base_tests.SimpleDataPlane):
Dan Talayco4aa13122010-05-12 15:54:44 -0700752 """
753 Send to OFPP_ALL port
754
755 Generate a packet
756 Generate and install a matching flow
757 Add action to forward to OFPP_ALL
758 Send the packet to ingress dataplane port
759 Verify the packet is received at all other ports
760 """
761 def runTest(self):
Rich Lane477f4812012-10-04 22:49:00 -0700762 of_ports = config["port_map"].keys()
Dan Talayco4aa13122010-05-12 15:54:44 -0700763 of_ports.sort()
764 self.assertTrue(len(of_ports) > 1, "Not enough ports for test")
765
766 pkt = simple_tcp_packet()
Ed Swierk99a74de2012-08-22 06:40:54 -0700767 match = packet_to_flow_match(self, pkt)
Dan Talayco4aa13122010-05-12 15:54:44 -0700768 match.wildcards &= ~ofp.OFPFW_IN_PORT
769 self.assertTrue(match is not None,
770 "Could not generate flow match from pkt")
771 act = action.action_output()
772
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700773 for ingress_port in of_ports:
Rich Lane9a003812012-10-04 17:17:59 -0700774 rv = delete_all_flows(self.controller)
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700775 self.assertEqual(rv, 0, "Failed to delete all flows")
Dan Talayco4aa13122010-05-12 15:54:44 -0700776
Rich Lane9a003812012-10-04 17:17:59 -0700777 logging.info("Ingress " + str(ingress_port) + " to all ports")
Dan Talayco4aa13122010-05-12 15:54:44 -0700778 match.in_port = ingress_port
779
780 request = message.flow_mod()
781 request.match = match
782 request.buffer_id = 0xffffffff
783 act.port = ofp.OFPP_ALL
784 self.assertTrue(request.actions.add(act),
785 "Could not add ALL port action")
Rich Lane9a003812012-10-04 17:17:59 -0700786 logging.info(request.show())
Dan Talayco4aa13122010-05-12 15:54:44 -0700787
Rich Lane9a003812012-10-04 17:17:59 -0700788 logging.info("Inserting flow")
Dan Talayco4aa13122010-05-12 15:54:44 -0700789 rv = self.controller.message_send(request)
790 self.assertTrue(rv != -1, "Error installing flow mod")
Dan Talayco0fc08bd2012-04-09 16:56:18 -0700791 self.assertEqual(do_barrier(self.controller), 0, "Barrier failed")
Dan Talayco4aa13122010-05-12 15:54:44 -0700792
Rich Lane9a003812012-10-04 17:17:59 -0700793 logging.info("Sending packet to dp port " + str(ingress_port))
Dan Talayco4aa13122010-05-12 15:54:44 -0700794 self.dataplane.send(ingress_port, str(pkt))
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700795 yes_ports = set(of_ports).difference([ingress_port])
796 receive_pkt_check(self.dataplane, pkt, yes_ports, [ingress_port],
Rich Lane2014f9b2012-10-05 15:29:40 -0700797 self)
Dan Talayco4aa13122010-05-12 15:54:44 -0700798
Rich Laneb90a1c42012-10-05 09:16:05 -0700799class AllPlusIngress(base_tests.SimpleDataPlane):
Dan Talayco4aa13122010-05-12 15:54:44 -0700800 """
801 Send to OFPP_ALL port and ingress port
802
803 Generate a packet
804 Generate and install a matching flow
805 Add action to forward to OFPP_ALL
806 Add action to forward to ingress port
807 Send the packet to ingress dataplane port
808 Verify the packet is received at all other ports
809 """
810 def runTest(self):
Rich Lane477f4812012-10-04 22:49:00 -0700811 of_ports = config["port_map"].keys()
Dan Talayco4aa13122010-05-12 15:54:44 -0700812 of_ports.sort()
813 self.assertTrue(len(of_ports) > 1, "Not enough ports for test")
814
815 pkt = simple_tcp_packet()
Ed Swierk99a74de2012-08-22 06:40:54 -0700816 match = packet_to_flow_match(self, pkt)
Dan Talayco4aa13122010-05-12 15:54:44 -0700817 match.wildcards &= ~ofp.OFPFW_IN_PORT
818 self.assertTrue(match is not None,
819 "Could not generate flow match from pkt")
820 act = action.action_output()
821
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700822 for ingress_port in of_ports:
Rich Lane9a003812012-10-04 17:17:59 -0700823 rv = delete_all_flows(self.controller)
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700824 self.assertEqual(rv, 0, "Failed to delete all flows")
Dan Talayco4aa13122010-05-12 15:54:44 -0700825
Rich Lane9a003812012-10-04 17:17:59 -0700826 logging.info("Ingress " + str(ingress_port) + " to all ports")
Dan Talayco4aa13122010-05-12 15:54:44 -0700827 match.in_port = ingress_port
828
829 request = message.flow_mod()
830 request.match = match
831 request.buffer_id = 0xffffffff
832 act.port = ofp.OFPP_ALL
833 self.assertTrue(request.actions.add(act),
834 "Could not add ALL port action")
Dan Talayco3be5b062010-05-12 15:46:21 -0700835 act.port = ofp.OFPP_IN_PORT
836 self.assertTrue(request.actions.add(act),
837 "Could not add ingress port for output")
Rich Lane9a003812012-10-04 17:17:59 -0700838 logging.info(request.show())
Dan Talayco3be5b062010-05-12 15:46:21 -0700839
Rich Lane9a003812012-10-04 17:17:59 -0700840 logging.info("Inserting flow")
Dan Talayco3be5b062010-05-12 15:46:21 -0700841 rv = self.controller.message_send(request)
842 self.assertTrue(rv != -1, "Error installing flow mod")
Dan Talayco0fc08bd2012-04-09 16:56:18 -0700843 self.assertEqual(do_barrier(self.controller), 0, "Barrier failed")
Dan Talayco3be5b062010-05-12 15:46:21 -0700844
Rich Lane9a003812012-10-04 17:17:59 -0700845 logging.info("Sending packet to dp port " + str(ingress_port))
Dan Talayco3be5b062010-05-12 15:46:21 -0700846 self.dataplane.send(ingress_port, str(pkt))
Rich Lane2014f9b2012-10-05 15:29:40 -0700847 receive_pkt_check(self.dataplane, pkt, of_ports, [], self)
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700848
Rich Laneb90a1c42012-10-05 09:16:05 -0700849class FloodMinusPort(base_tests.SimpleDataPlane):
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700850 """
851 Config port with No_Flood and test Flood action
852
853 Generate a packet
854 Generate a matching flow
855 Add action to forward to OFPP_ALL
856 Set port to no-flood
857 Send the packet to ingress dataplane port
858 Verify the packet is received at all other ports except
859 the ingress port and the no_flood port
860 """
861 def runTest(self):
Rich Lane477f4812012-10-04 22:49:00 -0700862 of_ports = config["port_map"].keys()
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700863 of_ports.sort()
864 self.assertTrue(len(of_ports) > 2, "Not enough ports for test")
865
866 pkt = simple_tcp_packet()
Ed Swierk99a74de2012-08-22 06:40:54 -0700867 match = packet_to_flow_match(self, pkt)
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700868 match.wildcards &= ~ofp.OFPFW_IN_PORT
869 self.assertTrue(match is not None,
870 "Could not generate flow match from pkt")
871 act = action.action_output()
872
Rich Lane4b9e38c2012-12-06 16:33:20 -0800873 # Clear OFPPC_NO_FLOOD on each port
874 for of_port in of_ports:
875 rv = port_config_set(self.controller, of_port,
876 0, ofp.OFPPC_NO_FLOOD)
877 self.assertEqual(rv, 0, "Failed to set port config")
878
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700879 for idx in range(len(of_ports)):
Rich Lane9a003812012-10-04 17:17:59 -0700880 rv = delete_all_flows(self.controller)
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700881 self.assertEqual(rv, 0, "Failed to delete all flows")
882
883 ingress_port = of_ports[idx]
884 no_flood_idx = (idx + 1) % len(of_ports)
885 no_flood_port = of_ports[no_flood_idx]
886 rv = port_config_set(self.controller, no_flood_port,
Rich Lane9a003812012-10-04 17:17:59 -0700887 ofp.OFPPC_NO_FLOOD, ofp.OFPPC_NO_FLOOD)
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700888 self.assertEqual(rv, 0, "Failed to set port config")
889
890 match.in_port = ingress_port
891
892 request = message.flow_mod()
893 request.match = match
894 request.buffer_id = 0xffffffff
895 act.port = ofp.OFPP_FLOOD
896 self.assertTrue(request.actions.add(act),
897 "Could not add flood port action")
Rich Lane9a003812012-10-04 17:17:59 -0700898 logging.info(request.show())
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700899
Rich Lane9a003812012-10-04 17:17:59 -0700900 logging.info("Inserting flow")
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700901 rv = self.controller.message_send(request)
902 self.assertTrue(rv != -1, "Error installing flow mod")
Dan Talayco0fc08bd2012-04-09 16:56:18 -0700903 self.assertEqual(do_barrier(self.controller), 0, "Barrier failed")
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700904
Rich Lane9a003812012-10-04 17:17:59 -0700905 logging.info("Sending packet to dp port " + str(ingress_port))
906 logging.info("No flood port is " + str(no_flood_port))
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700907 self.dataplane.send(ingress_port, str(pkt))
908 no_ports = set([ingress_port, no_flood_port])
909 yes_ports = set(of_ports).difference(no_ports)
Rich Lane2014f9b2012-10-05 15:29:40 -0700910 receive_pkt_check(self.dataplane, pkt, yes_ports, no_ports, self)
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700911
912 # Turn no flood off again
913 rv = port_config_set(self.controller, no_flood_port,
Rich Lane9a003812012-10-04 17:17:59 -0700914 0, ofp.OFPPC_NO_FLOOD)
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700915 self.assertEqual(rv, 0, "Failed to reset port config")
916
917 #@todo Should check no other packets received
918
Dan Talayco21381562010-07-17 00:34:47 -0700919
920
Dan Talayco551befa2010-07-15 17:05:32 -0700921################################################################
922
Rich Laneb90a1c42012-10-05 09:16:05 -0700923class BaseMatchCase(base_tests.SimpleDataPlane):
Dan Talayco551befa2010-07-15 17:05:32 -0700924 def setUp(self):
Rich Laneb90a1c42012-10-05 09:16:05 -0700925 base_tests.SimpleDataPlane.setUp(self)
Dan Talayco551befa2010-07-15 17:05:32 -0700926 def runTest(self):
Rich Lane9a003812012-10-04 17:17:59 -0700927 logging.info("BaseMatchCase")
Dan Talayco551befa2010-07-15 17:05:32 -0700928
929class ExactMatch(BaseMatchCase):
Tatsuya Yabe6a6f38a2010-05-22 23:48:04 -0700930 """
Dan Talayco551befa2010-07-15 17:05:32 -0700931 Exercise exact matching for all port pairs
Tatsuya Yabe6a6f38a2010-05-22 23:48:04 -0700932
933 Generate a packet
934 Generate and install a matching flow without wildcard mask
935 Add action to forward to a port
936 Send the packet to the port
937 Verify the packet is received at all other ports (one port at a time)
Tatsuya Yabe6a6f38a2010-05-22 23:48:04 -0700938 """
Tatsuya Yabe0718ad32010-05-24 15:22:10 -0700939
Tatsuya Yabe6a6f38a2010-05-22 23:48:04 -0700940 def runTest(self):
Rich Lane477f4812012-10-04 22:49:00 -0700941 flow_match_test(self, config["port_map"])
Tatsuya Yabe6a6f38a2010-05-22 23:48:04 -0700942
Dan Talayco551befa2010-07-15 17:05:32 -0700943class ExactMatchTagged(BaseMatchCase):
944 """
945 Exact match for all port pairs with tagged pkts
946 """
Tatsuya Yabe6a6f38a2010-05-22 23:48:04 -0700947
Dan Talayco551befa2010-07-15 17:05:32 -0700948 def runTest(self):
Rich Lane2014f9b2012-10-05 15:29:40 -0700949 vid = test_param_get('vid', default=TEST_VID_DEFAULT)
Rich Lane477f4812012-10-04 22:49:00 -0700950 flow_match_test(self, config["port_map"], dl_vlan=vid)
Tatsuya Yabe6a6f38a2010-05-22 23:48:04 -0700951
Dan Talayco551befa2010-07-15 17:05:32 -0700952class ExactMatchTaggedMany(BaseMatchCase):
953 """
954 ExactMatchTagged with many VLANS
955 """
Tatsuya Yabe6a6f38a2010-05-22 23:48:04 -0700956
Rich Laned1d9c282012-10-04 22:07:10 -0700957 priority = -1
958
Dan Talayco551befa2010-07-15 17:05:32 -0700959 def runTest(self):
Dan Talayco21381562010-07-17 00:34:47 -0700960 for vid in range(2,100,10):
Rich Lane477f4812012-10-04 22:49:00 -0700961 flow_match_test(self, config["port_map"], dl_vlan=vid, max_test=5)
Dan Talayco551befa2010-07-15 17:05:32 -0700962 for vid in range(100,4000,389):
Rich Lane477f4812012-10-04 22:49:00 -0700963 flow_match_test(self, config["port_map"], dl_vlan=vid, max_test=5)
964 flow_match_test(self, config["port_map"], dl_vlan=4094, max_test=5)
Tatsuya Yabecdf575e2010-05-25 16:56:38 -0700965
Jeffrey Townsend2a300e42012-03-28 17:24:02 -0700966class SingleWildcardMatchPriority(BaseMatchCase):
Jeffrey Townsend50c82462012-03-28 18:26:14 -0700967 """
968 SingleWildcardMatchPriority
969 """
Jeffrey Townsend2a300e42012-03-28 17:24:02 -0700970
Jeffrey Townsend50c82462012-03-28 18:26:14 -0700971 def _Init(self):
Jeffrey Townsend2a300e42012-03-28 17:24:02 -0700972 self.pkt = simple_tcp_packet()
973 self.flowMsgs = {}
974
Jeffrey Townsend50c82462012-03-28 18:26:14 -0700975 def _ClearTable(self):
Rich Lane9a003812012-10-04 17:17:59 -0700976 rc = delete_all_flows(self.controller)
Jeffrey Townsend50c82462012-03-28 18:26:14 -0700977 self.assertEqual(rc, 0, "Failed to delete all flows")
Dan Talayco0fc08bd2012-04-09 16:56:18 -0700978 self.assertEqual(do_barrier(self.controller), 0, "Barrier failed")
Jeffrey Townsend50c82462012-03-28 18:26:14 -0700979
980 def runTest(self):
981
982 self._Init()
Rich Lane477f4812012-10-04 22:49:00 -0700983 of_ports = config["port_map"].keys()
Jeffrey Townsend2a300e42012-03-28 17:24:02 -0700984 of_ports.sort()
985
986 # Delete the initial flow table
Jeffrey Townsend50c82462012-03-28 18:26:14 -0700987 self._ClearTable()
Jeffrey Townsend2a300e42012-03-28 17:24:02 -0700988
989 # Run several combinations, each at lower priority settings.
990 # At the end of each call to runPrioFlows(), the table should
991 # be empty. If its not, we'll catch it as the priorities decreases
992 portA = of_ports[0]
993 portB = of_ports[1]
994 portC = of_ports[2]
995
996 # TODO -- these priority numbers should be validated somehow?
997 self.runPrioFlows(portA, portB, portC, 1000, 999)
998 self.runPrioFlows(portB, portC, portA, 998, 997)
999 self.runPrioFlows(portC, portA, portB, 996, 995)
1000 self.runPrioFlows(portA, portC, portB, 994, 993)
1001
1002
Jeffrey Townsend50c82462012-03-28 18:26:14 -07001003
1004 def runPrioFlows(self, portA, portB, portC, prioHigher, prioLower,
1005 clearTable=False):
Jeffrey Townsend2a300e42012-03-28 17:24:02 -07001006
Jeffrey Townsend50c82462012-03-28 18:26:14 -07001007 if clearTable:
1008 self._ClearTable()
Jeffrey Townsend2a300e42012-03-28 17:24:02 -07001009
1010 # Sanity check flow at lower priority from pA to pB
Rich Lane9a003812012-10-04 17:17:59 -07001011 logging.info("runPrioFlows(pA=%d,pB=%d,pC=%d,ph=%d,pl=%d"
Jeffrey Townsend2a300e42012-03-28 17:24:02 -07001012 % (portA, portB, portC, prioHigher, prioLower))
1013
Jeffrey Townsend2a300e42012-03-28 17:24:02 -07001014 # Sanity check flow at lower priority from pA to pC
1015 self.installFlow(prioLower, portA, portC)
1016 self.verifyFlow(portA, portC)
1017 self.removeFlow(prioLower)
1018
1019 # Install and verify pA->pB @ prioLower
1020 self.installFlow(prioLower, portA, portB)
1021 self.verifyFlow(portA, portB)
1022
1023 # Install and verify pA->pC @ prioHigher, should override pA->pB
1024 self.installFlow(prioHigher, portA, portC)
1025 self.verifyFlow(portA, portC)
1026 # remove pA->pC
1027 self.removeFlow(prioHigher)
Jeffrey Townsend2a300e42012-03-28 17:24:02 -07001028 # Old flow pA -> pB @ prioLower should still be active
1029 self.verifyFlow(portA, portB)
1030 self.removeFlow(prioLower)
1031
1032 # Table should be empty at this point, leave it alone as
1033 # an assumption for future test runs
1034
1035
1036
Ed Swierk99a74de2012-08-22 06:40:54 -07001037 def installFlow(self, prio, inp, egp,
Jeffrey Townsend8364b162012-04-12 13:45:40 -07001038 wildcards=ofp.OFPFW_DL_SRC):
Ed Swierk99a74de2012-08-22 06:40:54 -07001039 wildcards |= required_wildcards(self)
Jeffrey Townsend2a300e42012-03-28 17:24:02 -07001040 request = flow_msg_create(self, self.pkt, ing_port=inp,
Jeffrey Townsend8364b162012-04-12 13:45:40 -07001041 wildcards=wildcards,
Jeffrey Townsend2a300e42012-03-28 17:24:02 -07001042 egr_ports=egp)
1043 request.priority = prio
Rich Lane9a003812012-10-04 17:17:59 -07001044 logging.debug("Install flow with priority " + str(prio))
Jeffrey Townsend50c82462012-03-28 18:26:14 -07001045 flow_msg_install(self, request, clear_table_override=False)
Jeffrey Townsend2a300e42012-03-28 17:24:02 -07001046 self.flowMsgs[prio] = request
1047
1048 def removeFlow(self, prio):
1049 if self.flowMsgs.has_key(prio):
1050 msg = self.flowMsgs[prio]
1051 msg.command = ofp.OFPFC_DELETE_STRICT
1052 # This *must* be set for DELETE
1053 msg.out_port = ofp.OFPP_NONE
Rich Lane9a003812012-10-04 17:17:59 -07001054 logging.debug("Remove flow with priority " + str(prio))
Jeffrey Townsend2a300e42012-03-28 17:24:02 -07001055 self.controller.message_send(msg)
Dan Talayco0fc08bd2012-04-09 16:56:18 -07001056 self.assertEqual(do_barrier(self.controller), 0, "Barrier failed")
Jeffrey Townsend50c82462012-03-28 18:26:14 -07001057 else:
1058 raise Exception("Not initialized")
Jeffrey Townsend2a300e42012-03-28 17:24:02 -07001059
1060
Jeffrey Townsend8364b162012-04-12 13:45:40 -07001061 def verifyFlow(self, inp, egp, pkt=None):
1062 if pkt == None:
1063 pkt = self.pkt
1064
Rich Lane9a003812012-10-04 17:17:59 -07001065 logging.info("Pkt match test: " + str(inp) + " to " + str(egp))
1066 logging.debug("Send packet: " + str(inp) + " to " + str(egp))
Jeffrey Townsend8364b162012-04-12 13:45:40 -07001067 self.dataplane.send(inp, str(pkt))
1068 receive_pkt_verify(self, egp, pkt, inp)
Jeffrey Townsend2a300e42012-03-28 17:24:02 -07001069
1070
1071
Jeffrey Townsend50c82462012-03-28 18:26:14 -07001072class SingleWildcardMatchPriorityInsertModifyDelete(SingleWildcardMatchPriority):
1073
1074 def runTest(self):
1075
1076 self._Init()
1077
Rich Lane477f4812012-10-04 22:49:00 -07001078 of_ports = config["port_map"].keys()
Jeffrey Townsend50c82462012-03-28 18:26:14 -07001079 of_ports.sort()
1080
1081 # Install an entry from 0 -> 1 @ prio 1000
1082 self._ClearTable()
1083 self.installFlow(1000, of_ports[0], of_ports[1])
1084 self.verifyFlow(of_ports[0], of_ports[1])
1085 self.installFlow(1000, of_ports[1], of_ports[0])
1086 self.verifyFlow(of_ports[1], of_ports[0])
1087 self.installFlow(1001, of_ports[0], of_ports[1])
1088 self.verifyFlow(of_ports[0], of_ports[1])
1089 self.installFlow(1001, of_ports[1], of_ports[0])
1090 self.verifyFlow(of_ports[1], of_ports[0])
1091 self.removeFlow(1001)
1092 self.verifyFlow(of_ports[0], of_ports[1])
1093 self.removeFlow(1000)
1094
1095
1096
Jeffrey Townsend8364b162012-04-12 13:45:40 -07001097class WildcardPriority(SingleWildcardMatchPriority):
Ken Chiang38d7a152012-05-24 15:33:50 -07001098 """
1099 1. Add wildcard flow, verify packet received.
1100 2. Add exact match flow with higher priority, verify packet received
1101 on port specified by this flow.
1102 3. Add wildcard flow with even higher priority, verify packet received
1103 on port specified by this flow.
Rich Laneb8392082012-11-21 15:52:54 -08001104 4. Add wildcard flow with lower priority, verify packet received
1105 on port specified by the highest priority flow.
Ken Chiang38d7a152012-05-24 15:33:50 -07001106 """
Jeffrey Townsend8364b162012-04-12 13:45:40 -07001107
1108 def runTest(self):
Jeffrey Townsend50c82462012-03-28 18:26:14 -07001109
Jeffrey Townsend8364b162012-04-12 13:45:40 -07001110 self._Init()
1111
Rich Lane477f4812012-10-04 22:49:00 -07001112 of_ports = config["port_map"].keys()
Jeffrey Townsend8364b162012-04-12 13:45:40 -07001113 of_ports.sort()
1114
1115 self._ClearTable()
Ken Chiang38d7a152012-05-24 15:33:50 -07001116
1117 # Install a flow with wildcards
1118 self.installFlow(999, of_ports[0], of_ports[1],
1119 wildcards=ofp.OFPFW_DL_DST)
Jeffrey Townsend8364b162012-04-12 13:45:40 -07001120 self.verifyFlow(of_ports[0], of_ports[1])
Ken Chiang38d7a152012-05-24 15:33:50 -07001121 # Install a flow with no wildcards for our packet
1122 self.installFlow(1000, of_ports[0], of_ports[2], wildcards=0)
Jeffrey Townsend8364b162012-04-12 13:45:40 -07001123 self.verifyFlow(of_ports[0], of_ports[2])
Ken Chiang38d7a152012-05-24 15:33:50 -07001124 # Install a flow with wildcards for our packet with higher
1125 # priority
1126 self.installFlow(1001, of_ports[0], of_ports[3])
1127 self.verifyFlow(of_ports[0], of_ports[3])
Rich Laneb8392082012-11-21 15:52:54 -08001128 # Install a flow with wildcards for our packet with lower
1129 # priority
1130 self.installFlow(999, of_ports[0], of_ports[1],
1131 wildcards=ofp.OFPFW_DL_SRC)
1132 self.verifyFlow(of_ports[0], of_ports[3])
Jeffrey Townsend8364b162012-04-12 13:45:40 -07001133
1134
Ken Chiang3978f242012-06-13 14:14:09 -07001135class WildcardPriorityWithDelete(SingleWildcardMatchPriority):
Ken Chiang38d7a152012-05-24 15:33:50 -07001136 """
1137 1. Add exact match flow, verify packet received.
1138 2. Add wildcard flow with higher priority, verify packet received on port
1139 specified by this flow.
1140 3. Add exact match flow with even higher priority, verify packet received
1141 on port specified by this flow.
1142 4. Delete lowest priority flow, verify packet received on port specified
1143 by highest priority flow.
1144 5. Delete highest priority flow, verify packet received on port specified
1145 by remaining flow.
1146 """
1147
1148 def runTest(self):
1149
1150 self._Init()
1151
Rich Lane477f4812012-10-04 22:49:00 -07001152 of_ports = config["port_map"].keys()
Ken Chiang38d7a152012-05-24 15:33:50 -07001153 of_ports.sort()
1154
1155 self._ClearTable()
1156
1157 # Install an exact match flow
1158 self.installFlow(250, of_ports[0], of_ports[1], wildcards=0)
1159 self.verifyFlow(of_ports[0], of_ports[1])
1160 # Install a flow with wildcards of higher priority
1161 self.installFlow(1250, of_ports[0], of_ports[2],
1162 wildcards=ofp.OFPFW_DL_DST)
1163 self.verifyFlow(of_ports[0], of_ports[2])
1164 # Install an exact match flow with even higher priority
1165 self.installFlow(2001, of_ports[0], of_ports[3], wildcards=0)
1166 self.verifyFlow(of_ports[0], of_ports[3])
1167 # Delete lowest priority flow
1168 self.removeFlow(250)
1169 self.verifyFlow(of_ports[0], of_ports[3])
1170 # Delete highest priority flow
1171 self.removeFlow(2001)
1172 self.verifyFlow(of_ports[0], of_ports[2])
1173
Jeffrey Townsend8364b162012-04-12 13:45:40 -07001174
Dan Talayco551befa2010-07-15 17:05:32 -07001175class SingleWildcardMatch(BaseMatchCase):
Tatsuya Yabe6a6f38a2010-05-22 23:48:04 -07001176 """
1177 Exercise wildcard matching for all ports
1178
1179 Generate a packet
1180 Generate and install a matching flow with wildcard mask
1181 Add action to forward to a port
1182 Send the packet to the port
1183 Verify the packet is received at all other ports (one port at a time)
Tatsuya Yabe0718ad32010-05-24 15:22:10 -07001184 Verify flow_expiration message is correct when command option is set
Tatsuya Yabe6a6f38a2010-05-22 23:48:04 -07001185 """
Tatsuya Yabe0718ad32010-05-24 15:22:10 -07001186 def runTest(self):
Rich Lane2014f9b2012-10-05 15:29:40 -07001187 vid = test_param_get('vid', default=TEST_VID_DEFAULT)
Dan Talayco551befa2010-07-15 17:05:32 -07001188 for wc in WILDCARD_VALUES:
Ed Swierk99a74de2012-08-22 06:40:54 -07001189 wc |= required_wildcards(self)
Dan Talayco4431d542012-03-21 16:42:16 -07001190 if wc & ofp.OFPFW_DL_VLAN:
Ken Chiang5be06dd2012-04-03 10:03:50 -07001191 # Set nonzero VLAN id to avoid sending priority-tagged packet
1192 dl_vlan = vid
Dan Talayco4431d542012-03-21 16:42:16 -07001193 else:
1194 dl_vlan = -1
Rich Lane477f4812012-10-04 22:49:00 -07001195 flow_match_test(self, config["port_map"], wildcards=wc,
Dan Talayco4431d542012-03-21 16:42:16 -07001196 dl_vlan=dl_vlan, max_test=10)
Tatsuya Yabe4fad7e32010-05-24 15:24:50 -07001197
Dan Talayco551befa2010-07-15 17:05:32 -07001198class SingleWildcardMatchTagged(BaseMatchCase):
1199 """
1200 SingleWildcardMatch with tagged packets
1201 """
1202 def runTest(self):
Rich Lane2014f9b2012-10-05 15:29:40 -07001203 vid = test_param_get('vid', default=TEST_VID_DEFAULT)
Dan Talayco551befa2010-07-15 17:05:32 -07001204 for wc in WILDCARD_VALUES:
Ed Swierk99a74de2012-08-22 06:40:54 -07001205 wc |= required_wildcards(self)
Rich Lane477f4812012-10-04 22:49:00 -07001206 flow_match_test(self, config["port_map"], wildcards=wc, dl_vlan=vid,
Dan Talayco551befa2010-07-15 17:05:32 -07001207 max_test=10)
1208
1209class AllExceptOneWildcardMatch(BaseMatchCase):
Tatsuya Yabe4fad7e32010-05-24 15:24:50 -07001210 """
Dan Talayco80b54ed2010-07-13 09:48:35 -07001211 Match exactly one field
Tatsuya Yabe4fad7e32010-05-24 15:24:50 -07001212
1213 Generate a packet
1214 Generate and install a matching flow with wildcard all except one filed
1215 Add action to forward to a port
1216 Send the packet to the port
1217 Verify the packet is received at all other ports (one port at a time)
1218 Verify flow_expiration message is correct when command option is set
1219 """
1220 def runTest(self):
Rich Lane2014f9b2012-10-05 15:29:40 -07001221 vid = test_param_get('vid', default=TEST_VID_DEFAULT)
Dan Talayco488fbc52012-04-09 16:30:41 -07001222 for all_exp_one_wildcard in NO_WILDCARD_VALUES:
Ed Swierk99a74de2012-08-22 06:40:54 -07001223 all_exp_one_wildcard |= required_wildcards(self)
Dan Talayco4431d542012-03-21 16:42:16 -07001224 if all_exp_one_wildcard & ofp.OFPFW_DL_VLAN:
Ken Chiang5be06dd2012-04-03 10:03:50 -07001225 # Set nonzero VLAN id to avoid sending priority-tagged packet
1226 dl_vlan = vid
Dan Talayco4431d542012-03-21 16:42:16 -07001227 else:
1228 dl_vlan = -1
Rich Lane477f4812012-10-04 22:49:00 -07001229 flow_match_test(self, config["port_map"], wildcards=all_exp_one_wildcard,
Dan Talayco4431d542012-03-21 16:42:16 -07001230 dl_vlan=dl_vlan)
Tatsuya Yabee30ebe22010-05-25 09:30:49 -07001231
Dan Talayco551befa2010-07-15 17:05:32 -07001232class AllExceptOneWildcardMatchTagged(BaseMatchCase):
1233 """
1234 Match one field with tagged packets
1235 """
1236 def runTest(self):
Rich Lane2014f9b2012-10-05 15:29:40 -07001237 vid = test_param_get('vid', default=TEST_VID_DEFAULT)
Dan Talayco488fbc52012-04-09 16:30:41 -07001238 for all_exp_one_wildcard in NO_WILDCARD_VALUES:
Ed Swierk99a74de2012-08-22 06:40:54 -07001239 all_exp_one_wildcard |= required_wildcards(self)
Rich Lane477f4812012-10-04 22:49:00 -07001240 flow_match_test(self, config["port_map"], wildcards=all_exp_one_wildcard,
Dan Talayco21381562010-07-17 00:34:47 -07001241 dl_vlan=vid)
Dan Talayco551befa2010-07-15 17:05:32 -07001242
1243class AllWildcardMatch(BaseMatchCase):
Tatsuya Yabee30ebe22010-05-25 09:30:49 -07001244 """
1245 Create Wildcard-all flow and exercise for all ports
1246
1247 Generate a packet
1248 Generate and install a matching flow with wildcard-all
1249 Add action to forward to a port
1250 Send the packet to the port
1251 Verify the packet is received at all other ports (one port at a time)
1252 Verify flow_expiration message is correct when command option is set
1253 """
1254 def runTest(self):
Rich Lane477f4812012-10-04 22:49:00 -07001255 flow_match_test(self, config["port_map"], wildcards=ofp.OFPFW_ALL)
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -07001256
Dan Talayco551befa2010-07-15 17:05:32 -07001257class AllWildcardMatchTagged(BaseMatchCase):
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -07001258 """
Dan Talayco551befa2010-07-15 17:05:32 -07001259 AllWildcardMatch with tagged packets
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -07001260 """
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -07001261 def runTest(self):
Rich Lane2014f9b2012-10-05 15:29:40 -07001262 vid = test_param_get('vid', default=TEST_VID_DEFAULT)
Rich Lane477f4812012-10-04 22:49:00 -07001263 flow_match_test(self, config["port_map"], wildcards=ofp.OFPFW_ALL,
Dan Talayco21381562010-07-17 00:34:47 -07001264 dl_vlan=vid)
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -07001265
Dan Talaycoba3745c2010-07-21 21:51:08 -07001266
Dan Talayco551befa2010-07-15 17:05:32 -07001267class AddVLANTag(BaseMatchCase):
1268 """
1269 Add a VLAN tag to an untagged packet
1270 """
1271 def runTest(self):
1272 new_vid = 2
Ed Swierkc7193a22012-08-22 06:51:02 -07001273 sup_acts = self.supported_actions
Dan Talayco551befa2010-07-15 17:05:32 -07001274 if not(sup_acts & 1<<ofp.OFPAT_SET_VLAN_VID):
Dan Talaycoba3745c2010-07-21 21:51:08 -07001275 skip_message_emit(self, "Add VLAN tag test")
Dan Talaycof36f1082010-07-13 13:57:17 -07001276 return
Tatsuya Yabef5ffb972010-05-26 15:36:33 -07001277
Dan Talayco551befa2010-07-15 17:05:32 -07001278 len = 100
1279 len_w_vid = 104
1280 pkt = simple_tcp_packet(pktlen=len)
1281 exp_pkt = simple_tcp_packet(pktlen=len_w_vid, dl_vlan_enable=True,
1282 dl_vlan=new_vid)
1283 vid_act = action.action_set_vlan_vid()
1284 vid_act.vlan_vid = new_vid
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -07001285
Rich Lane477f4812012-10-04 22:49:00 -07001286 flow_match_test(self, config["port_map"], pkt=pkt,
Dan Talayco551befa2010-07-15 17:05:32 -07001287 exp_pkt=exp_pkt, action_list=[vid_act])
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -07001288
Rich Laneb90a1c42012-10-05 09:16:05 -07001289class PacketOnly(base_tests.DataPlaneOnly):
Dan Talayco551befa2010-07-15 17:05:32 -07001290 """
1291 Just send a packet thru the switch
1292 """
Rich Laned1d9c282012-10-04 22:07:10 -07001293
1294 priority = -1
1295
Dan Talayco551befa2010-07-15 17:05:32 -07001296 def runTest(self):
1297 pkt = simple_tcp_packet()
Rich Lane477f4812012-10-04 22:49:00 -07001298 of_ports = config["port_map"].keys()
Dan Talayco551befa2010-07-15 17:05:32 -07001299 of_ports.sort()
1300 ing_port = of_ports[0]
Rich Lane9a003812012-10-04 17:17:59 -07001301 logging.info("Sending packet to " + str(ing_port))
1302 logging.debug("Data: " + str(pkt).encode('hex'))
Dan Talayco551befa2010-07-15 17:05:32 -07001303 self.dataplane.send(ing_port, str(pkt))
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -07001304
Rich Laneb90a1c42012-10-05 09:16:05 -07001305class PacketOnlyTagged(base_tests.DataPlaneOnly):
Dan Talayco551befa2010-07-15 17:05:32 -07001306 """
1307 Just send a packet thru the switch
1308 """
Rich Laned1d9c282012-10-04 22:07:10 -07001309
1310 priority = -1
1311
Dan Talayco551befa2010-07-15 17:05:32 -07001312 def runTest(self):
Rich Lane2014f9b2012-10-05 15:29:40 -07001313 vid = test_param_get('vid', default=TEST_VID_DEFAULT)
Dan Talayco551befa2010-07-15 17:05:32 -07001314 pkt = simple_tcp_packet(dl_vlan_enable=True, dl_vlan=vid)
Rich Lane477f4812012-10-04 22:49:00 -07001315 of_ports = config["port_map"].keys()
Dan Talayco551befa2010-07-15 17:05:32 -07001316 of_ports.sort()
1317 ing_port = of_ports[0]
Rich Lane9a003812012-10-04 17:17:59 -07001318 logging.info("Sending packet to " + str(ing_port))
1319 logging.debug("Data: " + str(pkt).encode('hex'))
Dan Talayco551befa2010-07-15 17:05:32 -07001320 self.dataplane.send(ing_port, str(pkt))
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -07001321
Dan Talayco551befa2010-07-15 17:05:32 -07001322class ModifyVID(BaseMatchCase):
Dan Talayco4b2bee62010-07-20 14:10:05 -07001323 """
1324 Modify the VLAN ID in the VLAN tag of a tagged packet
1325 """
Dan Talaycoaf669322012-09-12 22:51:22 -07001326 def setUp(self):
1327 BaseMatchCase.setUp(self)
1328 self.ing_port=False
1329
Dan Talayco551befa2010-07-15 17:05:32 -07001330 def runTest(self):
1331 old_vid = 2
1332 new_vid = 3
Ed Swierkc7193a22012-08-22 06:51:02 -07001333 sup_acts = self.supported_actions
Dan Talayco4b2bee62010-07-20 14:10:05 -07001334 if not (sup_acts & 1 << ofp.OFPAT_SET_VLAN_VID):
Dan Talaycoba3745c2010-07-21 21:51:08 -07001335 skip_message_emit(self, "Modify VLAN tag test")
Dan Talayco551befa2010-07-15 17:05:32 -07001336 return
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -07001337
Dan Talayco551befa2010-07-15 17:05:32 -07001338 pkt = simple_tcp_packet(dl_vlan_enable=True, dl_vlan=old_vid)
1339 exp_pkt = simple_tcp_packet(dl_vlan_enable=True, dl_vlan=new_vid)
1340 vid_act = action.action_set_vlan_vid()
1341 vid_act.vlan_vid = new_vid
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -07001342
Rich Lane477f4812012-10-04 22:49:00 -07001343 flow_match_test(self, config["port_map"], pkt=pkt, exp_pkt=exp_pkt,
Dan Talaycoaf669322012-09-12 22:51:22 -07001344 action_list=[vid_act], ing_port=self.ing_port)
1345
1346class ModifyVIDToIngress(ModifyVID):
1347 """
1348 Modify the VLAN ID in the VLAN tag of a tagged packet and send to
1349 ingress port
1350 """
1351 def setUp(self):
1352 BaseMatchCase.setUp(self)
1353 self.ing_port=True
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -07001354
Ken Chiange9a211d2012-04-20 14:52:11 -07001355class ModifyVIDWithTagMatchWildcarded(BaseMatchCase):
1356 """
1357 With vlan ID and priority wildcarded, perform SET_VLAN_VID action.
1358 The same flow should match on both untagged and tagged packets.
1359 """
1360 def runTest(self):
1361 old_vid = 2
1362 new_vid = 3
Ed Swierkc7193a22012-08-22 06:51:02 -07001363 sup_acts = self.supported_actions
Ken Chiange9a211d2012-04-20 14:52:11 -07001364 if not (sup_acts & 1 << ofp.OFPAT_SET_VLAN_VID):
1365 skip_message_emit(self, "ModifyVIDWithTagWildcarded test")
1366 return
1367
Rich Lane477f4812012-10-04 22:49:00 -07001368 of_ports = config["port_map"].keys()
Ken Chiange9a211d2012-04-20 14:52:11 -07001369 self.assertTrue(len(of_ports) > 1, "Not enough ports for test")
1370 ing_port = of_ports[0]
1371 egr_ports = of_ports[1]
1372
Rich Lane9a003812012-10-04 17:17:59 -07001373 rv = delete_all_flows(self.controller)
Ken Chiange9a211d2012-04-20 14:52:11 -07001374 self.assertEqual(rv, 0, "Failed to delete all flows")
1375
1376 len_untagged = 100
1377 len_w_vid = 104
1378 untagged_pkt = simple_tcp_packet(pktlen=len_untagged)
1379 tagged_pkt = simple_tcp_packet(pktlen=len_w_vid,
1380 dl_vlan_enable=True, dl_vlan=old_vid)
1381 exp_pkt = simple_tcp_packet(pktlen=len_w_vid, dl_vlan_enable=True,
1382 dl_vlan=new_vid)
Ed Swierk99a74de2012-08-22 06:40:54 -07001383 wildcards = (required_wildcards(self) | ofp.OFPFW_DL_VLAN |
1384 ofp.OFPFW_DL_VLAN_PCP)
Ken Chiange9a211d2012-04-20 14:52:11 -07001385 vid_act = action.action_set_vlan_vid()
1386 vid_act.vlan_vid = new_vid
1387 request = flow_msg_create(self, untagged_pkt, ing_port=ing_port,
1388 wildcards=wildcards, egr_ports=egr_ports,
1389 action_list=[vid_act])
1390 flow_msg_install(self, request)
1391
Rich Lane9a003812012-10-04 17:17:59 -07001392 logging.debug("Send untagged packet: " + str(ing_port) + " to " +
Ken Chiange9a211d2012-04-20 14:52:11 -07001393 str(egr_ports))
1394 self.dataplane.send(ing_port, str(untagged_pkt))
1395 receive_pkt_verify(self, egr_ports, exp_pkt, ing_port)
1396
Rich Lane9a003812012-10-04 17:17:59 -07001397 logging.debug("Send tagged packet: " + str(ing_port) + " to " +
Ken Chiange9a211d2012-04-20 14:52:11 -07001398 str(egr_ports))
1399 self.dataplane.send(ing_port, str(tagged_pkt))
1400 receive_pkt_verify(self, egr_ports, exp_pkt, ing_port)
1401
Howard Pershc1199d52012-04-11 14:21:32 -07001402class ModifyVlanPcp(BaseMatchCase):
1403 """
1404 Modify the priority field of the VLAN tag of a tagged packet
1405 """
1406 def runTest(self):
1407 vid = 123
1408 old_vlan_pcp = 2
1409 new_vlan_pcp = 3
Ed Swierkc7193a22012-08-22 06:51:02 -07001410 sup_acts = self.supported_actions
Ed Swierk8c3af7f2012-04-24 14:19:17 -07001411 if not (sup_acts & 1 << ofp.OFPAT_SET_VLAN_PCP):
1412 skip_message_emit(self, "Modify VLAN priority test")
Howard Pershc1199d52012-04-11 14:21:32 -07001413 return
1414
1415 pkt = simple_tcp_packet(dl_vlan_enable=True, dl_vlan=vid, dl_vlan_pcp=old_vlan_pcp)
1416 exp_pkt = simple_tcp_packet(dl_vlan_enable=True, dl_vlan=vid, dl_vlan_pcp=new_vlan_pcp)
1417 vid_act = action.action_set_vlan_pcp()
1418 vid_act.vlan_pcp = new_vlan_pcp
1419
Rich Lane477f4812012-10-04 22:49:00 -07001420 flow_match_test(self, config["port_map"], pkt=pkt, exp_pkt=exp_pkt,
Howard Pershc1199d52012-04-11 14:21:32 -07001421 action_list=[vid_act])
1422
Dan Talayco551befa2010-07-15 17:05:32 -07001423class StripVLANTag(BaseMatchCase):
Dan Talayco4b2bee62010-07-20 14:10:05 -07001424 """
1425 Strip the VLAN tag from a tagged packet
1426 """
Dan Talayco551befa2010-07-15 17:05:32 -07001427 def runTest(self):
1428 old_vid = 2
Ed Swierkc7193a22012-08-22 06:51:02 -07001429 sup_acts = self.supported_actions
Dan Talayco4b2bee62010-07-20 14:10:05 -07001430 if not (sup_acts & 1 << ofp.OFPAT_STRIP_VLAN):
Dan Talaycoba3745c2010-07-21 21:51:08 -07001431 skip_message_emit(self, "Strip VLAN tag test")
Dan Talayco551befa2010-07-15 17:05:32 -07001432 return
Dan Talaycof36f1082010-07-13 13:57:17 -07001433
Dan Talayco551befa2010-07-15 17:05:32 -07001434 len_w_vid = 104
1435 len = 100
1436 pkt = simple_tcp_packet(pktlen=len_w_vid, dl_vlan_enable=True,
1437 dl_vlan=old_vid)
1438 exp_pkt = simple_tcp_packet(pktlen=len)
1439 vid_act = action.action_strip_vlan()
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -07001440
Rich Lane477f4812012-10-04 22:49:00 -07001441 flow_match_test(self, config["port_map"], pkt=pkt, exp_pkt=exp_pkt,
Dan Talayco551befa2010-07-15 17:05:32 -07001442 action_list=[vid_act])
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -07001443
Ken Chiange9a211d2012-04-20 14:52:11 -07001444class StripVLANTagWithTagMatchWildcarded(BaseMatchCase):
1445 """
1446 Strip the VLAN tag from a tagged packet.
1447 Differs from StripVLANTag in that VID and PCP are both wildcarded.
1448 """
1449 def runTest(self):
1450 old_vid = 2
Ed Swierkc7193a22012-08-22 06:51:02 -07001451 sup_acts = self.supported_actions
Ken Chiange9a211d2012-04-20 14:52:11 -07001452 if not (sup_acts & 1 << ofp.OFPAT_STRIP_VLAN):
1453 skip_message_emit(self, "StripVLANTagWithTagWildcarded test")
1454 return
1455
1456 len_w_vid = 104
1457 len_untagged = 100
1458 pkt = simple_tcp_packet(pktlen=len_w_vid, dl_vlan_enable=True,
1459 dl_vlan=old_vid)
1460 exp_pkt = simple_tcp_packet(pktlen=len_untagged)
Ed Swierk99a74de2012-08-22 06:40:54 -07001461 wildcards = (required_wildcards(self) | ofp.OFPFW_DL_VLAN |
1462 ofp.OFPFW_DL_VLAN_PCP)
Ken Chiange9a211d2012-04-20 14:52:11 -07001463 vid_act = action.action_strip_vlan()
1464
Rich Lane477f4812012-10-04 22:49:00 -07001465 flow_match_test(self, config["port_map"],
Ed Swierk99a74de2012-08-22 06:40:54 -07001466 wildcards=wildcards,
Ken Chiange9a211d2012-04-20 14:52:11 -07001467 pkt=pkt, exp_pkt=exp_pkt,
1468 action_list=[vid_act])
1469
Dan Talayco4b2bee62010-07-20 14:10:05 -07001470def init_pkt_args():
1471 """
1472 Pass back a dictionary with default packet arguments
1473 """
1474 args = {}
1475 args["dl_src"] = '00:23:45:67:89:AB'
1476
1477 dl_vlan_enable=False
1478 dl_vlan=-1
Rich Lane477f4812012-10-04 22:49:00 -07001479 if config["test-params"]["vid"]:
Dan Talayco4b2bee62010-07-20 14:10:05 -07001480 dl_vlan_enable=True
Rich Lane477f4812012-10-04 22:49:00 -07001481 dl_vlan = config["test-params"]["vid"]
Dan Talayco4b2bee62010-07-20 14:10:05 -07001482
1483# Unpack operator is ** on a dictionary
1484
1485 return args
1486
Dan Talayco551befa2010-07-15 17:05:32 -07001487class ModifyL2Src(BaseMatchCase):
Dan Talayco4b2bee62010-07-20 14:10:05 -07001488 """
1489 Modify the source MAC address (TP1)
1490 """
Dan Talayco551befa2010-07-15 17:05:32 -07001491 def runTest(self):
Ed Swierkc7193a22012-08-22 06:51:02 -07001492 sup_acts = self.supported_actions
Dan Talayco4b2bee62010-07-20 14:10:05 -07001493 if not (sup_acts & 1 << ofp.OFPAT_SET_DL_SRC):
Dan Talaycoba3745c2010-07-21 21:51:08 -07001494 skip_message_emit(self, "ModifyL2Src test")
Dan Talayco4b2bee62010-07-20 14:10:05 -07001495 return
1496
1497 (pkt, exp_pkt, acts) = pkt_action_setup(self, mod_fields=['dl_src'],
1498 check_test_params=True)
Rich Lane477f4812012-10-04 22:49:00 -07001499 flow_match_test(self, config["port_map"], pkt=pkt, exp_pkt=exp_pkt,
Dan Talayco4b2bee62010-07-20 14:10:05 -07001500 action_list=acts, max_test=2)
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -07001501
Dan Talayco551befa2010-07-15 17:05:32 -07001502class ModifyL2Dst(BaseMatchCase):
Dan Talayco4b2bee62010-07-20 14:10:05 -07001503 """
1504 Modify the dest MAC address (TP1)
1505 """
Dan Talayco551befa2010-07-15 17:05:32 -07001506 def runTest(self):
Ed Swierkc7193a22012-08-22 06:51:02 -07001507 sup_acts = self.supported_actions
Dan Talayco4b2bee62010-07-20 14:10:05 -07001508 if not (sup_acts & 1 << ofp.OFPAT_SET_DL_DST):
Dan Talaycoba3745c2010-07-21 21:51:08 -07001509 skip_message_emit(self, "ModifyL2dst test")
Dan Talayco4b2bee62010-07-20 14:10:05 -07001510 return
1511
1512 (pkt, exp_pkt, acts) = pkt_action_setup(self, mod_fields=['dl_dst'],
1513 check_test_params=True)
Rich Lane477f4812012-10-04 22:49:00 -07001514 flow_match_test(self, config["port_map"], pkt=pkt, exp_pkt=exp_pkt,
Dan Talayco4b2bee62010-07-20 14:10:05 -07001515 action_list=acts, max_test=2)
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -07001516
Dan Talayco551befa2010-07-15 17:05:32 -07001517class ModifyL3Src(BaseMatchCase):
Dan Talayco4b2bee62010-07-20 14:10:05 -07001518 """
1519 Modify the source IP address of an IP packet (TP1)
1520 """
Dan Talayco551befa2010-07-15 17:05:32 -07001521 def runTest(self):
Ed Swierkc7193a22012-08-22 06:51:02 -07001522 sup_acts = self.supported_actions
Dan Talayco4b2bee62010-07-20 14:10:05 -07001523 if not (sup_acts & 1 << ofp.OFPAT_SET_NW_SRC):
Dan Talaycoba3745c2010-07-21 21:51:08 -07001524 skip_message_emit(self, "ModifyL3Src test")
Dan Talayco4b2bee62010-07-20 14:10:05 -07001525 return
1526
1527 (pkt, exp_pkt, acts) = pkt_action_setup(self, mod_fields=['ip_src'],
1528 check_test_params=True)
Rich Lane477f4812012-10-04 22:49:00 -07001529 flow_match_test(self, config["port_map"], pkt=pkt, exp_pkt=exp_pkt,
Dan Talayco4b2bee62010-07-20 14:10:05 -07001530 action_list=acts, max_test=2)
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -07001531
Dan Talayco551befa2010-07-15 17:05:32 -07001532class ModifyL3Dst(BaseMatchCase):
Dan Talayco4b2bee62010-07-20 14:10:05 -07001533 """
1534 Modify the dest IP address of an IP packet (TP1)
1535 """
Dan Talayco551befa2010-07-15 17:05:32 -07001536 def runTest(self):
Ed Swierkc7193a22012-08-22 06:51:02 -07001537 sup_acts = self.supported_actions
Dan Talayco4b2bee62010-07-20 14:10:05 -07001538 if not (sup_acts & 1 << ofp.OFPAT_SET_NW_DST):
Dan Talaycoba3745c2010-07-21 21:51:08 -07001539 skip_message_emit(self, "ModifyL3Dst test")
Dan Talayco4b2bee62010-07-20 14:10:05 -07001540 return
1541
1542 (pkt, exp_pkt, acts) = pkt_action_setup(self, mod_fields=['ip_dst'],
1543 check_test_params=True)
Rich Lane477f4812012-10-04 22:49:00 -07001544 flow_match_test(self, config["port_map"], pkt=pkt, exp_pkt=exp_pkt,
Dan Talayco4b2bee62010-07-20 14:10:05 -07001545 action_list=acts, max_test=2)
Dan Talayco551befa2010-07-15 17:05:32 -07001546
1547class ModifyL4Src(BaseMatchCase):
Dan Talayco4b2bee62010-07-20 14:10:05 -07001548 """
1549 Modify the source TCP port of a TCP packet (TP1)
1550 """
Dan Talayco551befa2010-07-15 17:05:32 -07001551 def runTest(self):
Ed Swierkc7193a22012-08-22 06:51:02 -07001552 sup_acts = self.supported_actions
Dan Talayco4b2bee62010-07-20 14:10:05 -07001553 if not (sup_acts & 1 << ofp.OFPAT_SET_TP_SRC):
Dan Talaycoba3745c2010-07-21 21:51:08 -07001554 skip_message_emit(self, "ModifyL4Src test")
Dan Talayco4b2bee62010-07-20 14:10:05 -07001555 return
1556
1557 (pkt, exp_pkt, acts) = pkt_action_setup(self, mod_fields=['tcp_sport'],
1558 check_test_params=True)
Rich Lane477f4812012-10-04 22:49:00 -07001559 flow_match_test(self, config["port_map"], pkt=pkt, exp_pkt=exp_pkt,
Dan Talayco4b2bee62010-07-20 14:10:05 -07001560 action_list=acts, max_test=2)
Dan Talayco551befa2010-07-15 17:05:32 -07001561
Rich Lane01c2b862012-10-26 16:26:25 -07001562class ModifyL4SrcUdp(BaseMatchCase):
1563 """
1564 Modify the source UDP port of a UDP packet
1565 """
1566 def runTest(self):
1567 sup_acts = self.supported_actions
1568 if not (sup_acts & 1 << ofp.OFPAT_SET_TP_DST):
1569 skip_message_emit(self, "ModifyL4SrcUdp test")
1570 return
1571
1572 (pkt, exp_pkt, acts) = pkt_action_setup(self, mod_fields=['udp_sport'],
1573 check_test_params=True, tp="udp")
1574 flow_match_test(self, config["port_map"], pkt=pkt, exp_pkt=exp_pkt,
1575 action_list=acts, max_test=2)
1576
Dan Talayco551befa2010-07-15 17:05:32 -07001577class ModifyL4Dst(BaseMatchCase):
Dan Talayco4b2bee62010-07-20 14:10:05 -07001578 """
1579 Modify the dest TCP port of a TCP packet (TP1)
1580 """
Dan Talayco551befa2010-07-15 17:05:32 -07001581 def runTest(self):
Ed Swierkc7193a22012-08-22 06:51:02 -07001582 sup_acts = self.supported_actions
Dan Talayco4b2bee62010-07-20 14:10:05 -07001583 if not (sup_acts & 1 << ofp.OFPAT_SET_TP_DST):
Dan Talaycoba3745c2010-07-21 21:51:08 -07001584 skip_message_emit(self, "ModifyL4Dst test")
Dan Talayco4b2bee62010-07-20 14:10:05 -07001585 return
1586
1587 (pkt, exp_pkt, acts) = pkt_action_setup(self, mod_fields=['tcp_dport'],
1588 check_test_params=True)
Rich Lane477f4812012-10-04 22:49:00 -07001589 flow_match_test(self, config["port_map"], pkt=pkt, exp_pkt=exp_pkt,
Dan Talayco4b2bee62010-07-20 14:10:05 -07001590 action_list=acts, max_test=2)
Dan Talayco551befa2010-07-15 17:05:32 -07001591
Rich Lane01c2b862012-10-26 16:26:25 -07001592class ModifyL4DstUdp(BaseMatchCase):
1593 """
1594 Modify the dest UDP port of a UDP packet
1595 """
1596 def runTest(self):
1597 sup_acts = self.supported_actions
1598 if not (sup_acts & 1 << ofp.OFPAT_SET_TP_DST):
1599 skip_message_emit(self, "ModifyL4DstUdp test")
1600 return
1601
1602 (pkt, exp_pkt, acts) = pkt_action_setup(self, mod_fields=['udp_dport'],
1603 check_test_params=True, tp="udp")
1604 flow_match_test(self, config["port_map"], pkt=pkt, exp_pkt=exp_pkt,
1605 action_list=acts, max_test=2)
1606
Dan Talayco551befa2010-07-15 17:05:32 -07001607class ModifyTOS(BaseMatchCase):
Dan Talayco4b2bee62010-07-20 14:10:05 -07001608 """
1609 Modify the IP type of service of an IP packet (TP1)
1610 """
Dan Talayco551befa2010-07-15 17:05:32 -07001611 def runTest(self):
Ed Swierkc7193a22012-08-22 06:51:02 -07001612 sup_acts = self.supported_actions
Dan Talayco4b2bee62010-07-20 14:10:05 -07001613 if not (sup_acts & 1 << ofp.OFPAT_SET_NW_TOS):
Dan Talaycoba3745c2010-07-21 21:51:08 -07001614 skip_message_emit(self, "ModifyTOS test")
Dan Talayco4b2bee62010-07-20 14:10:05 -07001615 return
Dan Talayco551befa2010-07-15 17:05:32 -07001616
Dan Talayco4b2bee62010-07-20 14:10:05 -07001617 (pkt, exp_pkt, acts) = pkt_action_setup(self, mod_fields=['ip_tos'],
1618 check_test_params=True)
Rich Lane477f4812012-10-04 22:49:00 -07001619 flow_match_test(self, config["port_map"], pkt=pkt, exp_pkt=exp_pkt,
Dan Talaycocfa172f2012-03-23 12:03:00 -07001620 action_list=acts, max_test=2, egr_count=-1)
Dan Talayco551befa2010-07-15 17:05:32 -07001621
Dan Talaycof6e76c02012-03-23 10:56:12 -07001622class ModifyL2DstMC(BaseMatchCase):
1623 """
1624 Modify the L2 dest and send to 2 ports
Dan Talaycof6e76c02012-03-23 10:56:12 -07001625 """
1626 def runTest(self):
Ed Swierkc7193a22012-08-22 06:51:02 -07001627 sup_acts = self.supported_actions
Dan Talaycof6e76c02012-03-23 10:56:12 -07001628 if not (sup_acts & 1 << ofp.OFPAT_SET_DL_DST):
Dan Talaycocfa172f2012-03-23 12:03:00 -07001629 skip_message_emit(self, "ModifyL2dstMC test")
Dan Talaycof6e76c02012-03-23 10:56:12 -07001630 return
1631
Dan Talaycof6e76c02012-03-23 10:56:12 -07001632 (pkt, exp_pkt, acts) = pkt_action_setup(self, mod_fields=['dl_dst'],
1633 check_test_params=True)
Rich Lane477f4812012-10-04 22:49:00 -07001634 flow_match_test(self, config["port_map"], pkt=pkt, exp_pkt=exp_pkt,
Dan Talaycocfa172f2012-03-23 12:03:00 -07001635 action_list=acts, max_test=2, egr_count=-1)
Dan Talaycof6e76c02012-03-23 10:56:12 -07001636
Dan Talaycoc948d0b2012-03-23 12:17:54 -07001637class ModifyL2DstIngress(BaseMatchCase):
1638 """
1639 Modify the L2 dest and send to the ingress port
1640 """
1641 def runTest(self):
Ed Swierkc7193a22012-08-22 06:51:02 -07001642 sup_acts = self.supported_actions
Dan Talaycoc948d0b2012-03-23 12:17:54 -07001643 if not (sup_acts & 1 << ofp.OFPAT_SET_DL_DST):
Dan Talaycoabbfdbb2012-04-05 10:29:26 -07001644 skip_message_emit(self, "ModifyL2dstIngress test")
Dan Talaycoc948d0b2012-03-23 12:17:54 -07001645 return
1646
1647 (pkt, exp_pkt, acts) = pkt_action_setup(self, mod_fields=['dl_dst'],
1648 check_test_params=True)
Rich Lane477f4812012-10-04 22:49:00 -07001649 flow_match_test(self, config["port_map"], pkt=pkt, exp_pkt=exp_pkt,
Dan Talaycoc948d0b2012-03-23 12:17:54 -07001650 action_list=acts, max_test=2, egr_count=0,
1651 ing_port=True)
1652
Dan Talaycod8ae7582012-03-23 12:24:56 -07001653class ModifyL2DstIngressMC(BaseMatchCase):
1654 """
1655 Modify the L2 dest and send to the ingress port
1656 """
1657 def runTest(self):
Ed Swierkc7193a22012-08-22 06:51:02 -07001658 sup_acts = self.supported_actions
Dan Talaycod8ae7582012-03-23 12:24:56 -07001659 if not (sup_acts & 1 << ofp.OFPAT_SET_DL_DST):
1660 skip_message_emit(self, "ModifyL2dstMC test")
1661 return
1662
1663 (pkt, exp_pkt, acts) = pkt_action_setup(self, mod_fields=['dl_dst'],
1664 check_test_params=True)
Rich Lane477f4812012-10-04 22:49:00 -07001665 flow_match_test(self, config["port_map"], pkt=pkt, exp_pkt=exp_pkt,
Dan Talaycod8ae7582012-03-23 12:24:56 -07001666 action_list=acts, max_test=2, egr_count=-1,
1667 ing_port=True)
1668
Dan Talaycof6e76c02012-03-23 10:56:12 -07001669class ModifyL2SrcMC(BaseMatchCase):
1670 """
1671 Modify the source MAC address (TP1) and send to multiple
Dan Talaycof6e76c02012-03-23 10:56:12 -07001672 """
1673 def runTest(self):
Ed Swierkc7193a22012-08-22 06:51:02 -07001674 sup_acts = self.supported_actions
Dan Talaycof6e76c02012-03-23 10:56:12 -07001675 if not (sup_acts & 1 << ofp.OFPAT_SET_DL_SRC):
Dan Talaycocfa172f2012-03-23 12:03:00 -07001676 skip_message_emit(self, "ModifyL2SrcMC test")
Dan Talaycof6e76c02012-03-23 10:56:12 -07001677 return
1678
Dan Talaycof6e76c02012-03-23 10:56:12 -07001679 (pkt, exp_pkt, acts) = pkt_action_setup(self, mod_fields=['dl_src'],
1680 check_test_params=True)
Rich Lane477f4812012-10-04 22:49:00 -07001681 flow_match_test(self, config["port_map"], pkt=pkt, exp_pkt=exp_pkt,
Dan Talaycocfa172f2012-03-23 12:03:00 -07001682 action_list=acts, max_test=2, egr_count=-1)
Dan Talaycof6e76c02012-03-23 10:56:12 -07001683
1684class ModifyL2SrcDstMC(BaseMatchCase):
1685 """
1686 Modify the L2 source and dest and send to 2 ports
Dan Talaycof6e76c02012-03-23 10:56:12 -07001687 """
1688 def runTest(self):
Ed Swierkc7193a22012-08-22 06:51:02 -07001689 sup_acts = self.supported_actions
Dan Talaycocfa172f2012-03-23 12:03:00 -07001690 if (not (sup_acts & 1 << ofp.OFPAT_SET_DL_DST) or
1691 not (sup_acts & 1 << ofp.OFPAT_SET_DL_SRC)):
1692 skip_message_emit(self, "ModifyL2SrcDstMC test")
Dan Talaycof6e76c02012-03-23 10:56:12 -07001693 return
1694
Dan Talaycof6e76c02012-03-23 10:56:12 -07001695 mod_fields = ['dl_dst', 'dl_src']
1696 (pkt, exp_pkt, acts) = pkt_action_setup(self, mod_fields=mod_fields,
1697 check_test_params=True)
Rich Lane477f4812012-10-04 22:49:00 -07001698 flow_match_test(self, config["port_map"], pkt=pkt, exp_pkt=exp_pkt,
Dan Talaycocfa172f2012-03-23 12:03:00 -07001699 action_list=acts, max_test=2, egr_count=-1)
1700
1701class ModifyL2DstVIDMC(BaseMatchCase):
1702 """
1703 Modify the L2 dest and send to 2 ports
1704 """
1705 def runTest(self):
Ed Swierkc7193a22012-08-22 06:51:02 -07001706 sup_acts = self.supported_actions
Dan Talaycocfa172f2012-03-23 12:03:00 -07001707 if (not (sup_acts & 1 << ofp.OFPAT_SET_DL_DST) or
1708 not (sup_acts & 1 << ofp.OFPAT_SET_VLAN_VID)):
1709 skip_message_emit(self, "ModifyL2DstVIDMC test")
1710 return
1711
1712 mod_fields = ['dl_dst', 'dl_vlan']
1713 (pkt, exp_pkt, acts) = pkt_action_setup(self,
1714 start_field_vals={'dl_vlan_enable':True}, mod_fields=mod_fields,
1715 check_test_params=True)
Rich Lane477f4812012-10-04 22:49:00 -07001716 flow_match_test(self, config["port_map"], pkt=pkt, exp_pkt=exp_pkt,
Dan Talaycocfa172f2012-03-23 12:03:00 -07001717 action_list=acts, max_test=2, egr_count=-1)
Dan Talaycof6e76c02012-03-23 10:56:12 -07001718
Rich Lane22e74c12012-11-12 15:06:06 -08001719class ModifyAll(BaseMatchCase):
1720 """
1721 Modify all supported fields and output to a port
1722 """
1723 def runTest(self):
1724 sup_acts = self.supported_actions
1725
1726 sup_map = {
1727 "dl_dst" : ofp.OFPAT_SET_DL_DST,
1728 "dl_src" : ofp.OFPAT_SET_DL_SRC,
1729 "dl_vlan_enable" : ofp.OFPAT_SET_VLAN_VID,
1730 "dl_vlan" : ofp.OFPAT_SET_VLAN_VID,
1731 "dl_vlan_pcp" : ofp.OFPAT_SET_VLAN_PCP,
1732 "ip_src" : ofp.OFPAT_SET_NW_SRC,
1733 "ip_dst" : ofp.OFPAT_SET_NW_DST,
1734 "ip_tos" : ofp.OFPAT_SET_NW_TOS,
1735 "tcp_sport" : ofp.OFPAT_SET_TP_SRC,
1736 "tcp_dport" : ofp.OFPAT_SET_TP_DST,
1737 }
1738
1739 mod_fields = [field for (field, bit) in sup_map.items() if (sup_acts & 1 << bit)]
1740 random.shuffle(mod_fields)
1741 start_field_vals = { "dl_vlan_enable" : True }
1742 mod_field_vals = { "dl_vlan_enable" : True }
1743 logging.info("modifying fields: %s" % repr(mod_fields))
1744
1745 (pkt, exp_pkt, acts) = pkt_action_setup(self,
1746 mod_fields=mod_fields,
1747 start_field_vals=start_field_vals,
1748 mod_field_vals=mod_field_vals,
1749 check_test_params=True)
1750 flow_match_test(self, config["port_map"], pkt=pkt, exp_pkt=exp_pkt,
1751 action_list=acts, max_test=2)
1752
Dan Talaycofa6454f2012-04-05 10:04:13 -07001753class FlowToggle(BaseMatchCase):
1754 """
1755 Add flows to the table and modify them repeatedly
Dan Talaycof7c41312012-07-23 12:53:19 -07001756
1757 This is done by using only "add" flow messages. Since the check overlap
1758 flag is not set, the switch is supposed to modify the existing flow if
1759 the match already exists.
1760
1761 Would probably be better to exercise more of the flow modify commands
1762 (add, modify, delete +/- strict).
Dan Talaycofa6454f2012-04-05 10:04:13 -07001763 """
1764 def runTest(self):
Rich Lane2014f9b2012-10-05 15:29:40 -07001765 flow_count = test_param_get('ft_flow_count', default=20)
1766 iter_count = test_param_get('ft_iter_count', default=10)
Dan Talaycofa6454f2012-04-05 10:04:13 -07001767
Rich Lane9a003812012-10-04 17:17:59 -07001768 logging.info("Running flow toggle with %d flows, %d iterations" %
Dan Talaycofa6454f2012-04-05 10:04:13 -07001769 (flow_count, iter_count))
1770 acts = []
1771 acts.append(action.action_output())
1772 acts.append(action.action_output())
1773
Rich Lane477f4812012-10-04 22:49:00 -07001774 of_ports = config["port_map"].keys()
Dan Talaycofa6454f2012-04-05 10:04:13 -07001775 if len(of_ports) < 3:
1776 self.assertTrue(False, "Too few ports for test")
1777
1778 for idx in range(2):
1779 acts[idx].port = of_ports[idx]
1780
1781 flows = []
1782 flows.append([])
1783 flows.append([])
1784
Ed Swierk99a74de2012-08-22 06:40:54 -07001785 wildcards = (required_wildcards(self) | ofp.OFPFW_DL_SRC |
1786 ofp.OFPFW_DL_DST)
Dan Talaycofa6454f2012-04-05 10:04:13 -07001787 # Create up the flows in an array
1788 for toggle in range(2):
1789 for f_idx in range(flow_count):
1790 pkt = simple_tcp_packet(tcp_sport=f_idx)
1791 msg = message.flow_mod()
Ed Swierk99a74de2012-08-22 06:40:54 -07001792 match = packet_to_flow_match(self, pkt)
Shudong Zhou031373c2012-07-19 17:37:42 -07001793 match.in_port = of_ports[2]
Dan Talayco50be7672012-04-05 11:38:08 -07001794 match.wildcards = wildcards
Dan Talaycofa6454f2012-04-05 10:04:13 -07001795 msg.match = match
1796 msg.buffer_id = 0xffffffff
Dan Talaycof7c41312012-07-23 12:53:19 -07001797 msg.command = ofp.OFPFC_ADD
Dan Talaycofa6454f2012-04-05 10:04:13 -07001798 msg.actions.add(acts[toggle])
1799 flows[toggle].append(msg)
Dan Talayco50be7672012-04-05 11:38:08 -07001800
1801 # Show two sample flows
Rich Lane9a003812012-10-04 17:17:59 -07001802 logging.debug(flows[0][0].show())
1803 logging.debug(flows[1][0].show())
Dan Talayco50be7672012-04-05 11:38:08 -07001804
Dan Talaycofa6454f2012-04-05 10:04:13 -07001805 # Install the first set of flows
1806 for f_idx in range(flow_count):
1807 rv = self.controller.message_send(flows[0][f_idx])
1808 self.assertTrue(rv != -1, "Error installing flow %d" % f_idx)
Dan Talayco0fc08bd2012-04-09 16:56:18 -07001809 self.assertEqual(do_barrier(self.controller), 0, "Barrier failed")
Dan Talaycofa6454f2012-04-05 10:04:13 -07001810
Rich Lane9a003812012-10-04 17:17:59 -07001811 logging.info("Installed %d flows" % flow_count)
Dan Talaycofa6454f2012-04-05 10:04:13 -07001812
1813 # Repeatedly modify all the flows back and forth
1814 updates = 0
1815 # Report status about 5 times
1816 mod_val = (iter_count / 4) + 1
Dan Talaycoabbfdbb2012-04-05 10:29:26 -07001817 start = time.time()
1818 for iter_idx in range(iter_count):
1819 if not iter_idx % mod_val:
Rich Lane9a003812012-10-04 17:17:59 -07001820 logging.info("Flow Toggle: iter %d of %d. " %
Dan Talaycoabbfdbb2012-04-05 10:29:26 -07001821 (iter_idx, iter_count) +
1822 "%d updates in %d secs" %
1823 (updates, time.time() - start))
Dan Talaycofa6454f2012-04-05 10:04:13 -07001824 for toggle in range(2):
1825 t_idx = 1 - toggle
1826 for f_idx in range(flow_count):
1827 rv = self.controller.message_send(flows[t_idx][f_idx])
1828 updates += 1
1829 self.assertTrue(rv != -1, "Error modifying flow %d" %
1830 f_idx)
Dan Talayco0fc08bd2012-04-09 16:56:18 -07001831 self.assertEqual(do_barrier(self.controller), 0,
1832 "Barrier failed")
Dan Talaycoabbfdbb2012-04-05 10:29:26 -07001833
1834 end = time.time()
1835 divisor = end - start or (end - start + 1)
Rich Lane9a003812012-10-04 17:17:59 -07001836 logging.info("Flow toggle: %d iterations" % iter_count)
1837 logging.info(" %d flow mods in %d secs, %d mods/sec" %
Dan Talaycoabbfdbb2012-04-05 10:29:26 -07001838 (updates, end - start, updates/divisor))
Dan Talaycofa6454f2012-04-05 10:04:13 -07001839
1840
Dan Talayco8a64e332012-03-28 14:53:20 -07001841# You can pick and choose these by commenting tests in or out
1842iter_classes = [
1843 basic.PacketIn,
1844 basic.PacketOut,
1845 DirectPacket,
Dan Talaycofa6454f2012-04-05 10:04:13 -07001846 FlowToggle,
Dan Talayco8a64e332012-03-28 14:53:20 -07001847 DirectTwoPorts,
Dan Talaycofa6454f2012-04-05 10:04:13 -07001848 DirectMCNonIngress,
Dan Talayco8a64e332012-03-28 14:53:20 -07001849 AllWildcardMatch,
1850 AllWildcardMatchTagged,
1851 SingleWildcardMatch,
1852 SingleWildcardMatchTagged,
1853 ExactMatch,
1854 ExactMatchTagged,
1855 SingleWildcardMatch,
1856 ModifyL2Src,
1857 ModifyL2Dst,
1858 ModifyL2SrcMC,
1859 ModifyL2DstMC,
1860 ModifyL2SrcDstMC
1861 ]
1862
1863class IterCases(BaseMatchCase):
Dan Talaycofa6454f2012-04-05 10:04:13 -07001864 """
1865 Iterate over a bunch of test cases
1866
1867 The cases come from the list above
1868 """
1869
Rich Laned1d9c282012-10-04 22:07:10 -07001870 priority = -1
1871
Dan Talayco8a64e332012-03-28 14:53:20 -07001872 def runTest(self):
Rich Lane2014f9b2012-10-05 15:29:40 -07001873 count = test_param_get('iter_count', default=10)
Dan Talayco8a64e332012-03-28 14:53:20 -07001874 tests_done = 0
Rich Lane9a003812012-10-04 17:17:59 -07001875 logging.info("Running iteration test " + str(count) + " times")
Dan Talayco8a64e332012-03-28 14:53:20 -07001876 start = time.time()
1877 last = start
1878 for idx in range(count):
Rich Lane9a003812012-10-04 17:17:59 -07001879 logging.info("Iteration " + str(idx + 1))
Dan Talayco8a64e332012-03-28 14:53:20 -07001880 for cls in iter_classes:
1881 test = cls()
1882 test.inheritSetup(self)
1883 test.runTest()
1884 tests_done += 1
Dan Talaycofa6454f2012-04-05 10:04:13 -07001885 # Report update about every minute, between tests
Dan Talayco8a64e332012-03-28 14:53:20 -07001886 if time.time() - last > 60:
1887 last = time.time()
Rich Lane9a003812012-10-04 17:17:59 -07001888 logging.info(
Dan Talaycofa6454f2012-04-05 10:04:13 -07001889 "IterCases: Iter %d of %d; Ran %d tests in %d " %
1890 (idx, count, tests_done, last - start) +
1891 "seconds so far")
Dan Talayco8a64e332012-03-28 14:53:20 -07001892 stats = all_stats_get(self)
1893 last = time.time()
Rich Lane9a003812012-10-04 17:17:59 -07001894 logging.info("\nIterCases ran %d tests in %d seconds." %
Dan Talayco8a64e332012-03-28 14:53:20 -07001895 (tests_done, last - start))
Rich Lane9a003812012-10-04 17:17:59 -07001896 logging.info(" flows: %d. packets: %d. bytes: %d" %
Dan Talayco8a64e332012-03-28 14:53:20 -07001897 (stats["flows"], stats["packets"], stats["bytes"]))
Rich Lane9a003812012-10-04 17:17:59 -07001898 logging.info(" active: %d. lookups: %d. matched %d." %
Dan Talayco8a64e332012-03-28 14:53:20 -07001899 (stats["active"], stats["lookups"], stats["matched"]))
1900
Dan Talayco4b2bee62010-07-20 14:10:05 -07001901#@todo Need to implement tagged versions of the above tests
1902#
1903#@todo Implement a test case that strips tag 2, adds tag 3
1904# and modifies tag 4 to tag 5. Then verify (in addition) that
1905# tag 6 does not get modified.
1906
1907class MixedVLAN(BaseMatchCase):
1908 """
1909 Test mixture of VLAN tag actions
1910
1911 Strip tag 2 on port 1, send to port 2
1912 Add tag 3 on port 1, send to port 2
1913 Modify tag 4 to 5 on port 1, send to port 2
1914 All other traffic from port 1, send to port 3
1915 All traffic from port 2 sent to port 4
1916 Use exact matches with different packets for all mods
1917 Verify the following: (port, vid)
1918 (port 1, vid 2) => VLAN tag stripped, out port 2
1919 (port 1, no tag) => tagged packet w/ vid 2 out port 2
1920 (port 1, vid 4) => tagged packet w/ vid 5 out port 2
1921 (port 1, vid 5) => tagged packet w/ vid 5 out port 2
1922 (port 1, vid 6) => tagged packet w/ vid 6 out port 2
1923 (port 2, no tag) => untagged packet out port 4
1924 (port 2, vid 2-6) => unmodified packet out port 4
1925
1926 Variation: Might try sending VID 5 to port 3 and check.
1927 If only VID 5 distinguishes pkt, this will fail on some platforms
1928 """
1929
Rich Laned1d9c282012-10-04 22:07:10 -07001930 priority = -1
Rich Lane8d6ab272012-09-23 18:06:20 -07001931
Rich Laneb90a1c42012-10-05 09:16:05 -07001932class MatchEach(base_tests.SimpleDataPlane):
Rich Lane8d6ab272012-09-23 18:06:20 -07001933 """
1934 Check that each match field is actually matched on.
1935 Installs two flows that differ in one field. The flow that should not
1936 match has a higher priority, so if that field is ignored during matching
1937 the packet will be sent out the wrong port.
1938
1939 TODO test UDP, ARP, ICMP, etc.
1940 """
1941 def runTest(self):
Rich Lane477f4812012-10-04 22:49:00 -07001942 of_ports = config["port_map"].keys()
Rich Lane8d6ab272012-09-23 18:06:20 -07001943 of_ports.sort()
1944 self.assertTrue(len(of_ports) > 1, "Not enough ports for test")
1945
Rich Lane9a003812012-10-04 17:17:59 -07001946 delete_all_flows(self.controller)
Rich Lane8d6ab272012-09-23 18:06:20 -07001947
1948 pkt = simple_tcp_packet()
1949 ingress_port = of_ports[0]
1950 egress_port = of_ports[1]
1951
1952 def testField(field, mask):
Rich Lane9a003812012-10-04 17:17:59 -07001953 logging.info("Testing field %s" % field)
Rich Lane8d6ab272012-09-23 18:06:20 -07001954
1955 def addFlow(matching, priority, output_port):
1956 match = packet_to_flow_match(self, pkt)
1957 self.assertTrue(match is not None, "Could not generate flow match from pkt")
1958 match.wildcards &= ~ofp.OFPFW_IN_PORT
1959 match.in_port = ingress_port
1960 if not matching:
1961 # Make sure flow doesn't match
1962 orig = getattr(match, field)
1963 if isinstance(orig, list):
1964 new = map(lambda a: ~a[0] & a[1], zip(orig, mask))
1965 else:
1966 new = ~orig & mask
1967 setattr(match, field, new)
1968 request = message.flow_mod()
1969 request.match = match
1970 request.buffer_id = 0xffffffff
1971 request.priority = priority
1972 act = action.action_output()
1973 act.port = output_port
1974 self.assertTrue(request.actions.add(act), "Could not add action")
Rich Lane9a003812012-10-04 17:17:59 -07001975 logging.info("Inserting flow")
Rich Lane8d6ab272012-09-23 18:06:20 -07001976 self.controller.message_send(request)
1977
1978 # This flow should match.
1979 addFlow(matching=True, priority=0, output_port=egress_port)
1980 # This flow should not match, but it has a higher priority.
1981 addFlow(matching=False, priority=1, output_port=ofp.OFPP_IN_PORT)
1982
1983 self.assertEqual(do_barrier(self.controller), 0, "Barrier failed")
1984
Rich Lane9a003812012-10-04 17:17:59 -07001985 logging.info("Sending packet to dp port " + str(ingress_port))
Rich Lane8d6ab272012-09-23 18:06:20 -07001986 self.dataplane.send(ingress_port, str(pkt))
1987
1988 exp_pkt_arg = None
1989 exp_port = None
Rich Lane477f4812012-10-04 22:49:00 -07001990 if config["relax"]:
Rich Lane8d6ab272012-09-23 18:06:20 -07001991 exp_pkt_arg = pkt
1992 exp_port = egress_port
1993
1994 (rcv_port, rcv_pkt, pkt_time) = self.dataplane.poll(port_number=exp_port,
1995 exp_pkt=exp_pkt_arg)
1996 self.assertTrue(rcv_pkt is not None, "Did not receive packet")
Rich Lane9a003812012-10-04 17:17:59 -07001997 logging.debug("Packet len " + str(len(rcv_pkt)) + " in on " + str(rcv_port))
Rich Lane8d6ab272012-09-23 18:06:20 -07001998 self.assertEqual(rcv_port, egress_port, "Unexpected receive port")
1999 self.assertEqual(str(pkt), str(rcv_pkt), 'Response packet does not match send packet')
2000
2001 # TODO in_port
2002 testField("dl_src", [0xff]*6)
2003 testField("dl_dst", [0xff]*6)
2004 testField("dl_type", 0xffff)
2005 testField("dl_vlan", 0xfff)
2006 # TODO dl_vlan_pcp
2007 testField("nw_src", 0xffffffff)
2008 testField("nw_dst", 0xffffffff)
2009 testField("nw_tos", 0x3f)
2010 testField("nw_proto", 0xff)
2011 testField("tp_src", 0xffff)
2012 testField("tp_dst", 0xffff)
2013
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002014class DirectBadPacketBase(base_tests.SimpleDataPlane):
2015 """
2016 Base class for sending single packets with single flow table entries.
2017 Used to verify matching of unusual packets and parsing/matching of
2018 corrupted packets.
2019
2020 The idea is to generate packets that may either be totally malformed or
2021 malformed just enough to trick the flow matcher into making mistakes.
2022
2023 Generate a 'bad' packet
2024 Generate and install a matching flow
2025 Add action to direct the packet to an egress port
2026 Send the packet to ingress dataplane port
2027 Verify the packet is received at the egress port only
2028 """
2029
2030 RESULT_MATCH = "MATCH"
2031 RESULT_NOMATCH = "NO MATCH"
2032 RESULT_ANY = "ANY MATCH"
2033
2034 def runTest(self):
2035 pass
2036 # TODO:
2037 # - ICMP?
2038 # - VLAN?
2039 # - action
2040
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002041 def createMatch(self, **kwargs):
2042 match = ofp.ofp_match()
2043 match.wildcards = ofp.OFPFW_ALL
2044 fields = {
2045 'dl_dst': ofp.OFPFW_DL_DST,
2046 'dl_src': ofp.OFPFW_DL_SRC,
2047 'dl_type': ofp.OFPFW_DL_TYPE,
2048 'dl_vlan': ofp.OFPFW_DL_VLAN,
2049 'nw_src': ofp.OFPFW_NW_SRC_MASK,
2050 'nw_dst': ofp.OFPFW_NW_DST_MASK,
2051 'nw_tos': ofp.OFPFW_NW_TOS,
2052 'nw_proto': ofp.OFPFW_NW_PROTO,
2053 'tp_src': ofp.OFPFW_TP_SRC,
2054 'tp_dst': ofp.OFPFW_TP_DST,
2055 }
2056 for key in kwargs:
2057 setattr(match, key, kwargs[key])
2058 match.wildcards &= ~fields[key]
2059 return match
2060
2061 def testPktsAgainstFlow(self, pkts, acts, match):
2062 if type(acts) != list:
2063 acts = [acts]
2064 for info in pkts:
2065 title, pkt, expected_result = info
2066 self.testPktAgainstFlow(title, pkt, acts, match, expected_result)
2067
2068 def testPktAgainstFlow(self, title, pkt, acts, match, expected_result):
2069 of_ports = config["port_map"].keys()
2070 of_ports.sort()
2071 self.assertTrue(len(of_ports) > 1, "Not enough ports for test")
2072
2073 rv = delete_all_flows(self.controller)
2074 self.assertEqual(rv, 0, "Failed to delete all flows")
2075
2076 ingress_port = of_ports[0]
2077 egress_port = of_ports[1]
2078
2079 logging.info("Testing packet '%s', expect result %s" %
2080 (title, expected_result))
2081 logging.info("Ingress %s to egress %s" %
2082 (str(ingress_port), str(egress_port)))
2083 logging.info("Packet:")
Rich Lane5d7e89a2012-10-26 16:43:13 -07002084 logging.info(inspect_packet(pkt))
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002085
2086 match.in_port = ingress_port
2087
2088 request = message.flow_mod()
2089 request.match = match
Rich Lane44cf12d2012-10-15 11:10:45 -07002090 request.priority = 1
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002091
2092 request.buffer_id = 0xffffffff
2093 for act in acts:
2094 act.port = egress_port
2095 rv = request.actions.add(act)
2096 self.assertTrue(rv, "Could not add action")
2097
2098 logging.info("Inserting flow")
2099 rv = self.controller.message_send(request)
2100 self.assertTrue(rv != -1, "Error installing flow mod")
Rich Lane44cf12d2012-10-15 11:10:45 -07002101
2102 # This flow speeds up negative tests
2103 logging.info("Inserting catch-all flow")
2104 request2 = message.flow_mod()
2105 request2.match = self.createMatch()
2106 request2.priority = 0
2107 act = action.action_output()
2108 act.port = ofp.OFPP_IN_PORT
2109 request2.actions.add(act)
2110 rv = self.controller.message_send(request2)
2111 self.assertTrue(rv != -1, "Error installing flow mod")
2112
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002113 self.assertEqual(do_barrier(self.controller), 0, "Barrier failed")
2114
2115 logging.info("Sending packet to dp port " +
2116 str(ingress_port))
2117 self.dataplane.send(ingress_port, str(pkt))
2118
2119 exp_pkt_arg = None
2120 exp_port = None
2121 if config["relax"]:
2122 exp_pkt_arg = pkt
2123 exp_port = egress_port
2124
Rich Lane44cf12d2012-10-15 11:10:45 -07002125 if expected_result == self.RESULT_MATCH:
2126 timeout = -1 # default timeout
2127 else:
2128 timeout = 1 # short timeout for negative tests
2129
2130 (rcv_port, rcv_pkt, pkt_time) = self.dataplane.poll(exp_pkt=exp_pkt_arg,
2131 timeout=timeout)
2132 if rcv_port == ingress_port:
2133 logging.debug("Packet matched catch-all flow")
2134 rcv_pkt = None
2135
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002136 if expected_result == self.RESULT_MATCH:
2137 self.assertTrue(rcv_pkt is not None,
2138 "Did not receive packet, expected a match")
2139 logging.debug("Packet len " + str(len(rcv_pkt)) + " in on " +
2140 str(rcv_port))
2141 self.assertEqual(rcv_port, egress_port, "Unexpected receive port")
2142 str_pkt = str(pkt)
2143 str_rcv_pkt = str(rcv_pkt)
2144 str_rcv_pkt = str_rcv_pkt[0:len(str_pkt)]
2145 if str_pkt != str_rcv_pkt:
2146 logging.error("Response packet does not match send packet")
2147 logging.info("Response:")
Rich Lane5d7e89a2012-10-26 16:43:13 -07002148 logging.info(inspect_packet(scapy.Ether(rcv_pkt)))
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002149 self.assertEqual(str_pkt, str_rcv_pkt,
2150 'Response packet does not match send packet')
2151 elif expected_result == self.RESULT_NOMATCH:
2152 self.assertTrue(rcv_pkt is None, "Received packet, expected drop")
2153 else:
2154 logging.debug("Match or drop accepted. Result = %s" %
2155 ("match" if rcv_pkt is not None else "drop"))
2156
2157
2158class DirectBadIpTcpPacketsBase(DirectBadPacketBase):
2159 """
2160 Base class for TCP and UDP parsing/matching verification under corruptions
2161 """
2162 def runTest(self):
2163 pass
2164
2165 def runTestWithProto(self, protoName = 'TCP'):
2166 dl_dst='00:01:02:03:04:05'
2167 dl_src='00:06:07:08:09:0a'
2168 ip_src='192.168.0.1'
2169 ip_dst='192.168.0.2'
2170 ip_tos=0
2171 tcp_sport=1234
2172 tcp_dport=80
2173
2174 # Generate a proper packet for constructing a match
2175 tp = None
2176 if protoName == 'TCP':
2177 tp = scapy.TCP
2178 proto = 6
2179 elif protoName == 'UDP':
2180 tp = scapy.UDP
2181 proto = 17
2182 else:
2183 raise Exception("Passed in unknown proto name")
2184
2185 match_pkt = scapy.Ether(dst=dl_dst, src=dl_src)/ \
2186 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos)/ \
2187 tp(sport=tcp_sport, dport=tcp_dport)
2188 match = packet_to_flow_match(self, match_pkt)
2189 self.assertTrue(match is not None,
2190 "Could not generate flow match from pkt")
2191 match.wildcards &= ~ofp.OFPFW_IN_PORT
2192
2193 def testPacket(title, pkt, result):
2194 act = action.action_output()
2195 pkts = [
2196 [title, pkt, result]
2197 ]
2198 self.testPktsAgainstFlow(pkts, act, match)
2199
2200 # Try incomplete IP headers
2201 testPacket("Incomplete IP header (1 bytes)",
2202 scapy.Ether(dst=dl_dst, src=dl_src)/ \
2203 str(scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, proto=proto))[0:1],
2204 self.RESULT_NOMATCH,
2205 )
2206 testPacket("Incomplete IP header (2 bytes)",
2207 scapy.Ether(dst=dl_dst, src=dl_src)/ \
2208 str(scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, proto=proto))[0:2],
2209 self.RESULT_NOMATCH,
2210 )
2211 testPacket("Incomplete IP header (3 bytes)",
2212 scapy.Ether(dst=dl_dst, src=dl_src)/ \
2213 str(scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, proto=proto))[0:3],
2214 self.RESULT_NOMATCH,
2215 )
2216 testPacket("Incomplete IP header (12 bytes)",
2217 scapy.Ether(dst=dl_dst, src=dl_src)/ \
2218 str(scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, proto=proto))[0:12],
2219 self.RESULT_NOMATCH,
2220 )
2221 testPacket("Incomplete IP header (16 bytes)",
2222 scapy.Ether(dst=dl_dst, src=dl_src)/ \
2223 str(scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, proto=proto))[0:16],
2224 self.RESULT_NOMATCH,
2225 )
2226 testPacket("Incomplete IP header (19 bytes)",
2227 scapy.Ether(dst=dl_dst, src=dl_src)/ \
2228 str(scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, proto=proto))[0:19],
2229 self.RESULT_NOMATCH,
2230 )
2231
2232 # Try variations where the TCP header is missing or incomplete. As we
2233 # saw bugs before where buffers were reused and lengths weren't honored,
2234 # we initiatlize once with a non-matching full packet and once with a
2235 # matching full packet.
2236 testPacket("Non-Matching TCP packet, warming buffer",
2237 scapy.Ether(dst=dl_dst, src=dl_src)/ \
2238 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, proto=proto)/ \
2239 tp(sport=tcp_sport, dport=tcp_dport + 1),
2240 self.RESULT_NOMATCH,
2241 )
2242 testPacket("Missing TCP header, buffer warmed with non-match",
2243 scapy.Ether(dst=dl_dst, src=dl_src)/ \
2244 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, proto=proto),
2245 self.RESULT_NOMATCH,
2246 )
2247 testPacket("Matching TCP packet, warming buffer",
2248 scapy.Ether(dst=dl_dst, src=dl_src)/ \
2249 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, proto=proto)/ \
2250 tp(sport=tcp_sport, dport=tcp_dport),
2251 self.RESULT_MATCH,
2252 )
2253 testPacket("Missing TCP header, buffer warmed with match",
2254 scapy.Ether(dst=dl_dst, src=dl_src)/ \
2255 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, proto=proto),
2256 self.RESULT_NOMATCH,
2257 )
2258 testPacket("Truncated TCP header: 2 bytes",
2259 scapy.Ether(dst=dl_dst, src=dl_src)/ \
2260 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, proto=proto)/ \
2261 (str(tp(sport=tcp_sport, dport=tcp_dport))[0:2]),
2262 self.RESULT_NOMATCH,
2263 )
2264
2265 # Play with IP header length values that put the start of TCP either
2266 # inside the generated TCP header or beyond. In some cases it may even
2267 # be beyond the packet boundary. Also play with IP options and more
2268 # importantly IP total length corruptions.
2269 testPacket("TCP packet, corrupt ihl (0x6)",
2270 simple_tcp_packet(ip_ihl=6),
2271 self.RESULT_NOMATCH,
2272 )
2273 testPacket("TCP packet, corrupt ihl (0xf)",
2274 simple_tcp_packet(ip_ihl=0xf), # ihl = 15 * 4 = 60
2275 self.RESULT_NOMATCH,
2276 )
2277 testPacket("TCP packet, corrupt ihl and total length",
2278 simple_tcp_packet(ip_ihl=0xf, pktlen=56), # ihl = 15 * 4 = 60,
2279 self.RESULT_NOMATCH,
2280 )
2281 testPacket("Corrupt IPoption: First 4 bytes of matching TCP header",
2282 simple_tcp_packet(
2283 ip_options=scapy.IPOption('\x04\xd2\x00\x50'),
2284 tcp_dport=2, tcp_sport=2
2285 ),
2286 self.RESULT_NOMATCH,
2287 )
2288 testPacket("Missing TCP header, corrupt ihl",
2289 scapy.Ether(dst=dl_dst, src=dl_src)/ \
2290 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ihl=0xf, proto=proto),
2291 self.RESULT_NOMATCH,
2292 )
2293 testPacket("Missing TCP header, corrupt total length",
2294 scapy.Ether(dst=dl_dst, src=dl_src)/ \
2295 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, proto=proto, len= 100),
2296 self.RESULT_NOMATCH,
2297 )
2298 testPacket("Missing TCP header, corrupt ihl and total length",
2299 scapy.Ether(dst=dl_dst, src=dl_src)/ \
2300 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ihl=0xf, proto=proto, len=43),
2301 self.RESULT_NOMATCH,
2302 )
2303 testPacket("Incomplete IP header (12 bytes), corrupt ihl and total length",
2304 scapy.Ether(dst=dl_dst, src=dl_src)/ \
2305 str(scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, proto=proto, ihl=10, len=43))[0:12],
2306 self.RESULT_NOMATCH,
2307 )
2308 testPacket("Incomplete IP header (16 bytes), corrupt ihl and total length",
2309 scapy.Ether(dst=dl_dst, src=dl_src)/ \
2310 str(scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, proto=proto, ihl=10, len=43))[0:16],
2311 self.RESULT_NOMATCH,
2312 )
2313
2314 # Try an incomplete TCP header that has enough bytes to carry source and
2315 # destination ports. As that is all we care about during matching, some
2316 # implementations may match and some may drop the packet
2317 testPacket("Incomplete TCP header: src/dst port present",
2318 scapy.Ether(dst=dl_dst, src=dl_src)/ \
2319 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, proto=proto)/ \
2320 (str(tp(sport=tcp_sport, dport=tcp_dport))[0:4]),
2321 self.RESULT_ANY,
2322 )
2323
2324 for i in range(1):
2325 for length in range(40 / 4): # IPv4 options are a maximum of 40 in length
2326 bytes = "".join([("%c" % random.randint(0, 255)) for x in range(length * 4)])
2327 eth = scapy.Ether(dst=dl_dst, src=dl_src)
2328 ip = scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ihl=5 + length, proto=proto)
2329 tcp = tp(sport=tcp_sport, dport=tcp_dport+1)
2330 pkt = eth / ip
2331 pkt = pkt / bytes
2332 pkt = pkt / str(tcp)
2333 testPacket("Random IP options len = %d - TP match must fail" % length * 4,
2334 pkt,
2335 self.RESULT_NOMATCH
2336 )
2337
2338 eth = scapy.Ether(dst=dl_dst, src=dl_src)
2339 ip = scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ihl=5 + length, proto=proto)
2340 tcp = tp(sport=tcp_sport, dport=tcp_dport)
2341 pkt = eth / ip
2342 pkt = pkt / bytes
2343 pkt = pkt / str(tcp)
2344
2345 testPacket("Random IP options len = %d - May match",
2346 pkt,
2347 self.RESULT_ANY
2348 )
2349
2350
2351class DirectBadIpTcpPackets(DirectBadIpTcpPacketsBase):
2352 """
2353 Verify IP/TCP parsing and matching. Focus on packet corruptions
2354 """
2355 def runTest(self):
2356 self.runTestWithProto(protoName = 'TCP')
2357
2358class DirectBadIpUdpPackets(DirectBadIpTcpPacketsBase):
2359 """
2360 Verify IP/UDP parsing and matching. Focus on packet corruptions
2361 """
2362 def runTest(self):
2363 self.runTestWithProto(protoName = 'UDP')
2364
2365class DirectBadLlcPackets(DirectBadPacketBase):
2366 """
2367 Verify LLC/SNAP parsing and matching. Focus on packet corruptions
2368 """
2369 def runTest(self):
2370 dl_dst='00:01:02:03:04:05'
2371 dl_src='00:06:07:08:09:0a'
2372 ip_src='192.168.0.1'
2373 ip_dst='192.168.0.2'
2374 ip_tos=0
2375 tcp_sport=1234
2376 tcp_dport=80
2377
2378 IS_SNAP_IP = 1
2379 IS_SNAP_IP_CORRUPT = 2
2380 IS_NOT_SNAP_IP = 3
2381
2382 def testPacketTcpMatch(title, llc):
2383 match_pkt = scapy.Ether(dst=dl_dst, src=dl_src)/ \
2384 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos)/ \
2385 scapy.TCP(sport=tcp_sport, dport=tcp_dport)
2386 match = packet_to_flow_match(self, match_pkt)
2387 self.assertTrue(match is not None,
2388 "Could not generate flow match from pkt")
2389 match.wildcards &= ~ofp.OFPFW_IN_PORT
2390 act = action.action_output()
2391
2392 self.testPktsAgainstFlow(
2393 [[
2394 "TCP match - LLC frame correct length - %s" % title,
2395 scapy.Ether(dst=dl_dst, src=dl_src, type=len(llc)) / llc,
2396 self.RESULT_ANY,
2397 ]],
2398 act, match
2399 )
2400
2401 # Corrupt length field
2402 ethLen = random.randint(0, 1535)
2403 self.testPktsAgainstFlow(
2404 [[
2405 "TCP match - LLC frame corrupted length - %s" % title,
2406 scapy.Ether(dst=dl_dst, src=dl_src, type=ethLen) / llc,
2407 self.RESULT_ANY,
2408 ]],
2409 act, match
2410 )
2411
2412 def testPacketEthSrcDstMatch(title, llc):
2413 # Matching based on Ethernet source and destination
2414 match_pkt = scapy.Ether(dst=dl_dst, src=dl_src)
2415 match = packet_to_flow_match(self, match_pkt)
2416 self.assertTrue(match is not None,
2417 "Could not generate flow match from pkt")
2418 match.wildcards &= ~ofp.OFPFW_IN_PORT
2419 match.wildcards |= ofp.OFPFW_DL_TYPE
2420 self.testPktsAgainstFlow(
2421 [[
2422 "Eth addr match - LLC frame correct length- %s" % title,
2423 scapy.Ether(dst=dl_dst, src=dl_src, type=len(llc)) / llc,
2424 self.RESULT_MATCH,
2425 ]],
2426 action.action_output(), match
2427 )
2428
2429 # Corrupt length field
2430 ethLen = random.randint(0, 1535)
2431 self.testPktsAgainstFlow(
2432 [[
2433 "Eth addr match - LLC frame corrupted length- %s" % title,
2434 scapy.Ether(dst=dl_dst, src=dl_src, type=ethLen) / llc,
2435 self.RESULT_ANY,
2436 ]],
2437 action.action_output(), match
2438 )
2439
2440 def testPacketEthSrcDstTypeMatch(title, llc, is_snap_ip):
2441 # Matching based on Ethernet source, destination and type
2442 match_pkt = scapy.Ether(dst=dl_dst, src=dl_src, type=0x800)
2443 match = packet_to_flow_match(self, match_pkt)
2444 self.assertTrue(match is not None,
2445 "Could not generate flow match from pkt")
2446 match.wildcards &= ~ofp.OFPFW_IN_PORT
2447 if is_snap_ip == IS_SNAP_IP:
2448 is_match = self.RESULT_MATCH
2449 elif is_snap_ip == IS_SNAP_IP_CORRUPT:
2450 is_match = self.RESULT_ANY
2451 else:
2452 is_match = self.RESULT_NOMATCH
2453 self.testPktsAgainstFlow(
2454 [[
2455 "Eth addr+type match - LLC frame correct length - %s" % title,
2456 scapy.Ether(dst=dl_dst, src=dl_src, type=len(llc)) / llc,
2457 is_match,
2458 ]],
2459 action.action_output(), match
2460 )
2461
2462 # Corrupt length field
2463 ethLen = random.randint(0, 1535)
2464 self.testPktsAgainstFlow(
2465 [[
2466 "Eth addr+type match - LLC frame corrupted length - %s" % title,
2467 scapy.Ether(dst=dl_dst, src=dl_src, type=ethLen) / llc,
Christian Dickmanne9b6d252012-10-08 22:56:50 -07002468 self.RESULT_ANY,
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002469 ]],
2470 action.action_output(), match
2471 )
2472
2473 def testPacket(title, llc, is_snap_ip):
2474 testPacketTcpMatch(title, llc)
2475 testPacketEthSrcDstMatch(title, llc)
2476 testPacketEthSrcDstTypeMatch(title, llc, is_snap_ip)
2477
2478 testPacket("LLC - No SNAP - No Payload",
Rich Lane6508ea02012-10-12 15:27:11 -07002479 scapy.LLC(dsap=0x33, ssap=0x44, ctrl=0x03),
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002480 IS_NOT_SNAP_IP,
2481 )
2482 testPacket("LLC - No SNAP - Small Payload",
Rich Lane6508ea02012-10-12 15:27:11 -07002483 scapy.LLC(dsap=0x33, ssap=0x44, ctrl=0x03) / ("S" * 10),
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002484 IS_NOT_SNAP_IP,
2485 )
2486 testPacket("LLC - No SNAP - Max -1 Payload",
Rich Lane6508ea02012-10-12 15:27:11 -07002487 scapy.LLC(dsap=0x33, ssap=0x44, ctrl=0x03) / ("S" * (1500 - 3 - 1)),
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002488 IS_NOT_SNAP_IP,
2489 )
2490 testPacket("LLC - No SNAP - Max Payload",
Rich Lane6508ea02012-10-12 15:27:11 -07002491 scapy.LLC(dsap=0x33, ssap=0x44, ctrl=0x03) / ("S" * (1500 - 3)),
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002492 IS_NOT_SNAP_IP,
2493 )
2494 testPacket("LLC - SNAP - Small bogus payload",
2495 scapy.LLC(dsap=0xaa, ssap=0xaa, ctrl=0x03)/ \
2496 scapy.SNAP(OUI=0x000000, code=0x800) / ("S" * 10),
2497 IS_SNAP_IP_CORRUPT,
2498 )
2499 testPacket("LLC - SNAP - Max -1 bogus payload",
2500 scapy.LLC(dsap=0xaa, ssap=0xaa, ctrl=0x03)/ \
2501 scapy.SNAP(OUI=0x000000, code=0x3) / ("S" * (1500 - 3 - 5 - 1)),
2502 IS_NOT_SNAP_IP,
2503 )
2504 testPacket("LLC - SNAP - Max bogus payload",
2505 scapy.LLC(dsap=0xaa, ssap=0xaa, ctrl=0x03)/ \
2506 scapy.SNAP(OUI=0x000000, code=0x3) / ("S" * (1500 - 3 - 5)),
2507 IS_NOT_SNAP_IP,
2508 )
2509 testPacket("LLC - SNAP - IP - TCP",
2510 scapy.LLC(dsap=0xaa, ssap=0xaa, ctrl=0x03)/ \
2511 scapy.SNAP(OUI=0x000000, code=0x800)/ \
2512 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, proto=6)/ \
2513 scapy.TCP(sport=tcp_sport, dport=tcp_dport),
2514 IS_SNAP_IP,
2515 )
2516
2517
2518class DirectLlcPackets(DirectBadPacketBase):
2519 """
2520 Verify LLC/SNAP parsing (valid and corrupted packets) and matching
2521 """
2522 def runTest(self):
2523 dl_dst='00:01:02:03:04:05'
2524 dl_src='00:06:07:08:09:0a'
2525 ip_src='192.168.0.1'
2526 ip_dst='192.168.0.2'
2527 ip_tos=0
2528 tcp_sport=1234
2529 tcp_dport=80
2530
2531 # Test ethertype in face of LLC/SNAP and OFP_DL_TYPE_NOT_ETH_TYPE
2532 IS_SNAP_NOT_IP = 1
2533 IS_SNAP_AND_IP = 2
2534 IS_NOT_SNAP = 3
2535
2536 def testPacketEthTypeIP(title, llc, is_snap):
2537 match_pkt = scapy.Ether(dst=dl_dst, src=dl_src, type=0x800)
2538 match = packet_to_flow_match(self, match_pkt)
2539 self.assertTrue(match is not None,
2540 "Could not generate flow match from pkt")
2541 match.wildcards &= ~ofp.OFPFW_IN_PORT
2542 pkts = []
2543 if is_snap == IS_NOT_SNAP or is_snap == IS_SNAP_NOT_IP:
2544 result = self.RESULT_NOMATCH
2545 else:
2546 result = self.RESULT_MATCH
2547 pkts.append([
2548 "Ether type 0x800 match - %s" % title,
2549 scapy.Ether(dst=dl_dst, src=dl_src, type=len(llc)) / llc,
2550 result,
2551 ])
2552 act = action.action_output()
2553 self.testPktsAgainstFlow(pkts, act, match)
2554
2555 def testPacketEthTypeNotEth(title, llc, is_snap):
2556 match_pkt = scapy.Ether(dst = dl_dst, src = dl_src,
2557 type = ofp.OFP_DL_TYPE_NOT_ETH_TYPE)
2558 match = packet_to_flow_match(self, match_pkt)
2559 self.assertTrue(match is not None,
2560 "Could not generate flow match from pkt")
2561 match.wildcards &= ~ofp.OFPFW_IN_PORT
2562 pkts = []
2563 if is_snap == IS_NOT_SNAP:
2564 result = self.RESULT_MATCH
2565 else:
2566 result = self.RESULT_NOMATCH
2567 pkts.append([
2568 "Ether type OFP_DL_TYPE_NOT_ETH_TYPE match - %s" % title,
2569 scapy.Ether(dst=dl_dst, src=dl_src, type=len(llc)) / llc,
2570 result,
2571 ])
2572 act = action.action_output()
2573 self.testPktsAgainstFlow(pkts, act, match)
2574
2575 def testPacket(title, llc, is_snap):
2576 testPacketEthTypeIP(title, llc, is_snap)
2577 testPacketEthTypeNotEth(title, llc, is_snap)
2578
2579 testPacket("LLC - No SNAP - No Payload",
Rich Lane6508ea02012-10-12 15:27:11 -07002580 scapy.LLC(dsap=0x33, ssap=0x44, ctrl=0x03),
2581 IS_NOT_SNAP,
2582 )
2583 testPacket("LLC (with information field) - No SNAP - No Payload",
2584 scapy.LLC(dsap=0x33, ssap=0x44, ctrl=0x12) / "S",
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002585 IS_NOT_SNAP,
2586 )
2587 testPacket("LLC - No SNAP - Small Payload",
Rich Lane6508ea02012-10-12 15:27:11 -07002588 scapy.LLC(dsap=0x33, ssap=0x44, ctrl=0x03) / ("S" * 10),
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002589 IS_NOT_SNAP,
2590 )
2591 testPacket("LLC - No SNAP - Max -1 Payload",
Rich Lane6508ea02012-10-12 15:27:11 -07002592 scapy.LLC(dsap=0x33, ssap=0x44, ctrl=0x03) / ("S" * (1500 - 3 - 1)),
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002593 IS_NOT_SNAP,
2594 )
2595 testPacket("LLC - No SNAP - Max Payload",
Rich Lane6508ea02012-10-12 15:27:11 -07002596 scapy.LLC(dsap=0x33, ssap=0x44, ctrl=0x03) / ("S" * (1500 - 3)),
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002597 IS_NOT_SNAP,
2598 )
2599 testPacket("LLC - SNAP - Non-default OUI",
2600 scapy.LLC(dsap=0xaa, ssap=0xaa, ctrl=0x03)/ \
2601 scapy.SNAP(OUI=0x000001, code=0x800) / ("S" * 10),
2602 IS_NOT_SNAP,
2603 )
2604 testPacket("LLC - SNAP - Default OUI",
2605 scapy.LLC(dsap=0xaa, ssap=0xaa, ctrl=0x03)/ \
2606 scapy.SNAP(OUI=0x000000, code=0x800) / ("S" * 10),
2607 IS_SNAP_AND_IP,
2608 )
2609 testPacket("LLC - SNAP - Max -1 bogus payload",
2610 scapy.LLC(dsap=0xaa, ssap=0xaa, ctrl=0x03)/ \
2611 scapy.SNAP(OUI=0x000000, code=0x3) / ("S" * (1500 - 3 - 5 - 1)),
2612 IS_SNAP_NOT_IP,
2613 )
2614 testPacket("LLC - SNAP - Max bogus payload",
2615 scapy.LLC(dsap=0xaa, ssap=0xaa, ctrl=0x03)/ \
2616 scapy.SNAP(OUI=0x000000, code=0x3) / ("S" * (1500 - 3 - 5)),
2617 IS_SNAP_NOT_IP,
2618 )
2619 testPacket("LLC - SNAP - IP - TCP",
2620 scapy.LLC(dsap=0xaa, ssap=0xaa, ctrl=0x03)/ \
2621 scapy.SNAP(OUI=0x000000, code=0x800)/ \
2622 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, proto=6)/ \
2623 scapy.TCP(sport=tcp_sport, dport=tcp_dport),
2624 IS_SNAP_AND_IP,
2625 )
2626
2627
2628class DirectArpPackets(DirectBadPacketBase):
2629 """
2630 Verify ARP parsing (valid and corrupted packets) and ARP matching
2631 """
2632 def runTest(self):
2633 self.testArpHandling()
2634
2635 def testArpHandling(self):
2636 dl_dst='00:01:02:03:04:05'
2637 dl_src='00:06:07:08:09:0a'
2638 ip_src='192.168.0.1'
2639 ip_dst='192.168.0.2'
2640 ip_src2='192.168.1.1'
2641 ip_dst2='192.168.1.2'
2642 ip_tos=0
2643 tcp_sport=1234
2644 tcp_dport=80
2645
2646 def testPacket(title, arp_match, arp_pkt, result):
2647 pkts = []
2648
2649 match_pkt = scapy.Ether(dst=dl_dst, src=dl_src) / arp_match
2650 match = packet_to_flow_match(self, match_pkt)
2651 self.assertTrue(match is not None,
2652 "Could not generate flow match from pkt")
2653 match.wildcards &= ~ofp.OFPFW_IN_PORT
2654
2655 pkts.append([
2656 title,
2657 scapy.Ether(dst=dl_dst, src=dl_src) / arp_pkt,
2658 result,
2659 ])
2660
2661 act = action.action_output()
2662 self.testPktsAgainstFlow(pkts, act, match)
2663
2664 testPacket("Basic ARP",
2665 scapy.ARP(psrc=ip_src, pdst=ip_dst, op = 1),
2666 scapy.ARP(hwdst = '00:00:00:00:00:00', hwsrc = dl_src,
2667 psrc = ip_src, pdst = ip_dst, hwlen = 6, plen = 4,
2668 ptype = 0x800, hwtype = 1, op = 1),
2669 self.RESULT_MATCH
2670 )
2671 # More stuff:
2672 # - Non matches on any property
2673 # - Corrupted hwlen and plen
2674 # - Other hwtype, ptype
2675 # - Truncated ARP pkt
2676
2677
2678class DirectVlanPackets(DirectBadPacketBase):
2679 """
2680 Verify VLAN parsing (valid and corrupted packets) and ARP matching
2681 """
2682 def runTest(self):
2683 dl_dst='00:01:02:03:04:05'
2684 dl_src='00:06:07:08:09:0a'
2685 ip_src='192.168.0.1'
2686 ip_dst='192.168.0.2'
2687 ip_src2='192.168.1.1'
2688 ip_dst2='192.168.1.2'
2689 ip_tos=0
2690 tcp_sport=1234
2691 tcp_dport=80
2692
2693 def testPacket(title, match, pkt, result):
2694 pkts = []
2695
2696 self.assertTrue(match is not None,
2697 "Could not generate flow match from pkt")
2698 match.wildcards &= ~ofp.OFPFW_IN_PORT
2699
2700 pkts.append([
2701 "%s" % title,
2702 pkt,
2703 result,
2704 ])
2705
2706 act = action.action_output()
2707 self.testPktsAgainstFlow(pkts, act, match)
2708
2709 testPacket("Basic MAC matching - IPv4 payload",
2710 self.createMatch(dl_dst=parse_mac(dl_dst), dl_src=parse_mac(dl_src)),
2711 scapy.Ether(dst=dl_dst, src=dl_src, type=0x800) / scapy.IP(),
2712 self.RESULT_MATCH
2713 )
2714 testPacket("Basic MAC matching - VMware beacon - no payload",
2715 self.createMatch(dl_dst=parse_mac(dl_dst), dl_src=parse_mac(dl_src)),
2716 scapy.Ether(dst=dl_dst, src=dl_src, type=0x8922),
2717 self.RESULT_MATCH
2718 )
2719 testPacket("Basic MAC matching - VMware beacon - with payload",
2720 self.createMatch(dl_dst=parse_mac(dl_dst), dl_src=parse_mac(dl_src)),
2721 scapy.Ether(dst=dl_dst, src=dl_src, type=0x8922)/ ("X" * 1),
2722 self.RESULT_MATCH
2723 )
2724 testPacket("Basic MAC matching - IPv6 payload",
2725 self.createMatch(dl_dst=parse_mac(dl_dst), dl_src=parse_mac(dl_src)),
2726 scapy.Ether(dst=dl_dst, src=dl_src) / scapy.IPv6(),
2727 self.RESULT_MATCH
2728 )
2729 testPacket("Basic MAC matching with VLAN tag present",
2730 self.createMatch(dl_dst=parse_mac(dl_dst), dl_src=parse_mac(dl_src)),
2731 scapy.Ether(dst=dl_dst, src=dl_src)/ \
Christian Dickmann8ac55252012-10-08 22:53:49 -07002732 scapy.Dot1Q(prio=5, vlan=1000)/ \
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002733 scapy.IP(),
2734 self.RESULT_MATCH
2735 )
2736 testPacket("Basic MAC matching with VLAN tag present",
2737 self.createMatch(dl_dst=parse_mac(dl_dst), dl_src=parse_mac(dl_src),
2738 dl_type=0x800),
2739 scapy.Ether(dst=dl_dst, src=dl_src)/ \
Christian Dickmann8ac55252012-10-08 22:53:49 -07002740 scapy.Dot1Q(prio=5, vlan=1000)/ \
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002741 scapy.IP(),
2742 self.RESULT_MATCH
2743 )
2744 testPacket("Ether matching with VLAN tag present - No type match",
2745 self.createMatch(dl_dst=parse_mac(dl_dst), dl_src=parse_mac(dl_src),
2746 dl_type=0x801),
2747 scapy.Ether(dst=dl_dst, src=dl_src)/ \
Christian Dickmann8ac55252012-10-08 22:53:49 -07002748 scapy.Dot1Q(prio=5, vlan=1000)/ \
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002749 scapy.IP(),
2750 self.RESULT_NOMATCH
2751 )
2752 testPacket("Ether matching with VLAN tag present - No type match 0x8100",
2753 self.createMatch(dl_dst=parse_mac(dl_dst), dl_src=parse_mac(dl_src),
2754 dl_type=0x8100),
2755 scapy.Ether(dst=dl_dst, src=dl_src)/ \
Christian Dickmann8ac55252012-10-08 22:53:49 -07002756 scapy.Dot1Q(prio=5, vlan=1000)/ \
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002757 scapy.IP(),
2758 self.RESULT_NOMATCH
2759 )
2760 testPacket("Ether matching with double VLAN tag - Wrong type match",
2761 self.createMatch(dl_dst=parse_mac(dl_dst), dl_src=parse_mac(dl_src),
2762 dl_type=0x800),
2763 scapy.Ether(dst=dl_dst, src=dl_src)/ \
Christian Dickmann8ac55252012-10-08 22:53:49 -07002764 scapy.Dot1Q(prio=5, vlan=1000)/ \
2765 scapy.Dot1Q(prio=3, vlan=1005)/ \
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002766 scapy.IP(),
2767 self.RESULT_NOMATCH
2768 )
2769 testPacket("Ether matching with double VLAN tag - Type match",
2770 self.createMatch(dl_dst=parse_mac(dl_dst), dl_src=parse_mac(dl_src),
2771 dl_type=0x8100),
2772 scapy.Ether(dst=dl_dst, src=dl_src)/ \
Christian Dickmann8ac55252012-10-08 22:53:49 -07002773 scapy.Dot1Q(prio=5, vlan=1000)/ \
2774 scapy.Dot1Q(prio=3, vlan=1005)/ \
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002775 scapy.IP(),
2776 self.RESULT_MATCH
2777 )
2778 testPacket("IP matching - VLAN tag",
2779 self.createMatch(dl_dst=parse_mac(dl_dst), dl_src=parse_mac(dl_src),
2780 dl_type=0x0800,
2781 nw_src=parse_ip(ip_src), nw_dst=parse_ip(ip_dst)),
2782 scapy.Ether(dst=dl_dst, src=dl_src)/ \
Christian Dickmann8ac55252012-10-08 22:53:49 -07002783 scapy.Dot1Q(prio=5, vlan=1000)/ \
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002784 scapy.IP(src=ip_src, dst=ip_dst),
2785 self.RESULT_MATCH
2786 )
2787 # XXX:
2788 # - Matching on VLAN ID and Prio
2789 # - Actions
2790
2791
2792
Dan Talayco9f47f4d2010-06-03 13:54:37 -07002793if __name__ == "__main__":
2794 print "Please run through oft script: ./oft --test_spec=basic"