blob: 54fa28afb3f735b046812df6c578f9ae3e15dfef [file] [log] [blame]
Dan Talayco5eba8442010-03-10 13:58:43 -08001"""
2Test cases for testing actions taken on packets
3
4See basic.py for other info.
5
6It is recommended that these definitions be kept in their own
7namespace as different groups of tests will likely define
8similar identifiers.
9
Rich Lane477f4812012-10-04 22:49:00 -070010The switch is actively attempting to contact the controller at the address
11indicated in config.
Dan Talayco5eba8442010-03-10 13:58:43 -080012
13"""
14
Dan Talayco9f47f4d2010-06-03 13:54:37 -070015import copy
Dan Talayco5eba8442010-03-10 13:58:43 -080016import logging
Rich Laneb90a1c42012-10-05 09:16:05 -070017import time
Dan Talayco5eba8442010-03-10 13:58:43 -080018import unittest
Christian Dickmann8b59b4b2012-09-23 16:48:30 -070019import random
Dan Talayco5eba8442010-03-10 13:58:43 -080020
Rich Lane477f4812012-10-04 22:49:00 -070021from oftest import config
Dan Talayco5eba8442010-03-10 13:58:43 -080022import oftest.controller as controller
23import oftest.cstruct as ofp
24import oftest.message as message
25import oftest.dataplane as dataplane
26import oftest.action as action
27import oftest.parse as parse
Rich Laneb90a1c42012-10-05 09:16:05 -070028import oftest.base_tests as base_tests
29import basic # for IterCases
Dan Talayco5eba8442010-03-10 13:58:43 -080030
Christian Dickmann8b59b4b2012-09-23 16:48:30 -070031from oftest.parse import parse_mac, parse_ip
32
Rich Laneda3b5ad2012-10-03 09:05:32 -070033from oftest.testutils import *
Dan Talayco5eba8442010-03-10 13:58:43 -080034
Dan Talayco551befa2010-07-15 17:05:32 -070035WILDCARD_VALUES = [ofp.OFPFW_IN_PORT,
Dan Talayco488fbc52012-04-09 16:30:41 -070036 ofp.OFPFW_DL_VLAN | ofp.OFPFW_DL_VLAN_PCP,
Dan Talayco551befa2010-07-15 17:05:32 -070037 ofp.OFPFW_DL_SRC,
38 ofp.OFPFW_DL_DST,
Dan Talayco488fbc52012-04-09 16:30:41 -070039 (ofp.OFPFW_DL_TYPE | ofp.OFPFW_NW_SRC_ALL |
40 ofp.OFPFW_NW_DST_ALL | ofp.OFPFW_NW_TOS | ofp.OFPFW_NW_PROTO |
41 ofp.OFPFW_TP_SRC | ofp.OFPFW_TP_DST),
42 (ofp.OFPFW_NW_PROTO | ofp.OFPFW_TP_SRC | ofp.OFPFW_TP_DST),
Dan Talayco551befa2010-07-15 17:05:32 -070043 ofp.OFPFW_TP_SRC,
44 ofp.OFPFW_TP_DST,
Dan Talayco488fbc52012-04-09 16:30:41 -070045 ofp.OFPFW_NW_SRC_MASK,
46 ofp.OFPFW_NW_DST_MASK,
Dan Talayco551befa2010-07-15 17:05:32 -070047 ofp.OFPFW_DL_VLAN_PCP,
48 ofp.OFPFW_NW_TOS]
49
Dan Talayco488fbc52012-04-09 16:30:41 -070050NO_WILDCARD_VALUES = [(ofp.OFPFW_ALL ^ ofp.OFPFW_IN_PORT),
51 (ofp.OFPFW_ALL ^ ofp.OFPFW_DL_VLAN),
52 (ofp.OFPFW_ALL ^ ofp.OFPFW_DL_SRC),
53 (ofp.OFPFW_ALL ^ ofp.OFPFW_DL_DST),
54 (ofp.OFPFW_ALL ^ ofp.OFPFW_DL_TYPE),
55 (ofp.OFPFW_ALL ^ ofp.OFPFW_DL_TYPE ^ ofp.OFPFW_NW_PROTO),
56 (ofp.OFPFW_ALL ^ ofp.OFPFW_DL_TYPE ^ ofp.OFPFW_NW_PROTO ^
57 ofp.OFPFW_TP_SRC),
58 (ofp.OFPFW_ALL ^ ofp.OFPFW_DL_TYPE ^ ofp.OFPFW_NW_PROTO ^
59 ofp.OFPFW_TP_DST),
60 (ofp.OFPFW_ALL ^ ofp.OFPFW_DL_TYPE ^ ofp.OFPFW_NW_PROTO ^
61 ofp.OFPFW_NW_SRC_MASK),
62 (ofp.OFPFW_ALL ^ ofp.OFPFW_DL_TYPE ^ ofp.OFPFW_NW_PROTO ^
63 ofp.OFPFW_NW_DST_MASK),
64 (ofp.OFPFW_ALL ^ ofp.OFPFW_DL_VLAN ^ ofp.OFPFW_DL_VLAN_PCP),
65 (ofp.OFPFW_ALL ^ ofp.OFPFW_DL_TYPE ^ ofp.OFPFW_NW_PROTO ^
66 ofp.OFPFW_NW_TOS)]
67
Dan Talayco551befa2010-07-15 17:05:32 -070068MODIFY_ACTION_VALUES = [ofp.OFPAT_SET_VLAN_VID,
69 ofp.OFPAT_SET_VLAN_PCP,
70 ofp.OFPAT_STRIP_VLAN,
71 ofp.OFPAT_SET_DL_SRC,
72 ofp.OFPAT_SET_DL_DST,
73 ofp.OFPAT_SET_NW_SRC,
74 ofp.OFPAT_SET_NW_DST,
75 ofp.OFPAT_SET_NW_TOS,
76 ofp.OFPAT_SET_TP_SRC,
77 ofp.OFPAT_SET_TP_DST]
78
Dan Talayco21381562010-07-17 00:34:47 -070079TEST_VID_DEFAULT = 2
80
Rich Laneb90a1c42012-10-05 09:16:05 -070081class DirectPacket(base_tests.SimpleDataPlane):
Dan Talayco5eba8442010-03-10 13:58:43 -080082 """
Dan Talayco2d0d49a2010-05-11 15:29:08 -070083 Send packet to single egress port
Dan Talayco5eba8442010-03-10 13:58:43 -080084
85 Generate a packet
86 Generate and install a matching flow
87 Add action to direct the packet to an egress port
88 Send the packet to ingress dataplane port
89 Verify the packet is received at the egress port only
90 """
91 def runTest(self):
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -070092 self.handleFlow()
93
94 def handleFlow(self, pkttype='TCP'):
Rich Lane477f4812012-10-04 22:49:00 -070095 of_ports = config["port_map"].keys()
Dan Talayco5eba8442010-03-10 13:58:43 -080096 of_ports.sort()
97 self.assertTrue(len(of_ports) > 1, "Not enough ports for test")
98
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -070099 if (pkttype == 'ICMP'):
100 pkt = simple_icmp_packet()
101 else:
102 pkt = simple_tcp_packet()
Ed Swierk99a74de2012-08-22 06:40:54 -0700103 match = packet_to_flow_match(self, pkt)
Dan Talayco7dd6cd62010-03-16 15:02:35 -0700104 match.wildcards &= ~ofp.OFPFW_IN_PORT
Dan Talayco5eba8442010-03-10 13:58:43 -0800105 self.assertTrue(match is not None,
106 "Could not generate flow match from pkt")
107 act = action.action_output()
108
109 for idx in range(len(of_ports)):
Rich Lane9a003812012-10-04 17:17:59 -0700110 rv = delete_all_flows(self.controller)
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700111 self.assertEqual(rv, 0, "Failed to delete all flows")
Dan Talayco2e77a842010-05-12 15:39:46 -0700112
Dan Talayco5eba8442010-03-10 13:58:43 -0800113 ingress_port = of_ports[idx]
114 egress_port = of_ports[(idx + 1) % len(of_ports)]
Rich Lane9a003812012-10-04 17:17:59 -0700115 logging.info("Ingress " + str(ingress_port) +
Dan Talayco551befa2010-07-15 17:05:32 -0700116 " to egress " + str(egress_port))
Dan Talayco5eba8442010-03-10 13:58:43 -0800117
118 match.in_port = ingress_port
119
120 request = message.flow_mod()
121 request.match = match
Jeffrey Townsend2a300e42012-03-28 17:24:02 -0700122
Dan Talayco5eba8442010-03-10 13:58:43 -0800123 request.buffer_id = 0xffffffff
124 act.port = egress_port
125 self.assertTrue(request.actions.add(act), "Could not add action")
126
Rich Lane9a003812012-10-04 17:17:59 -0700127 logging.info("Inserting flow")
Dan Talayco5eba8442010-03-10 13:58:43 -0800128 rv = self.controller.message_send(request)
129 self.assertTrue(rv != -1, "Error installing flow mod")
Dan Talayco0fc08bd2012-04-09 16:56:18 -0700130 self.assertEqual(do_barrier(self.controller), 0, "Barrier failed")
Dan Talayco5eba8442010-03-10 13:58:43 -0800131
Rich Lane9a003812012-10-04 17:17:59 -0700132 logging.info("Sending packet to dp port " +
Dan Talayco5eba8442010-03-10 13:58:43 -0800133 str(ingress_port))
134 self.dataplane.send(ingress_port, str(pkt))
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700135
136 exp_pkt_arg = None
137 exp_port = None
Rich Lane477f4812012-10-04 22:49:00 -0700138 if config["relax"]:
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700139 exp_pkt_arg = pkt
140 exp_port = egress_port
141
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700142 (rcv_port, rcv_pkt, pkt_time) = self.dataplane.poll(port_number=exp_port,
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700143 exp_pkt=exp_pkt_arg)
Dan Talayco5eba8442010-03-10 13:58:43 -0800144 self.assertTrue(rcv_pkt is not None, "Did not receive packet")
Rich Lane9a003812012-10-04 17:17:59 -0700145 logging.debug("Packet len " + str(len(rcv_pkt)) + " in on " +
Dan Talayco5eba8442010-03-10 13:58:43 -0800146 str(rcv_port))
147 self.assertEqual(rcv_port, egress_port, "Unexpected receive port")
148 self.assertEqual(str(pkt), str(rcv_pkt),
149 'Response packet does not match send packet')
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700150
Rich Laneb90a1c42012-10-05 09:16:05 -0700151class DirectPacketController(base_tests.SimpleDataPlane):
Rich Lane51c23b32012-07-27 16:37:25 -0700152 """
153 Send packet to the controller port
154
155 Generate a packet
156 Generate and install a matching flow
157 Add action to direct the packet to the controller port
158 Send the packet to ingress dataplane port
159 Verify the packet is received at the controller port
160 """
161 def runTest(self):
162 self.handleFlow()
163
164 def handleFlow(self, pkttype='TCP'):
Rich Lane477f4812012-10-04 22:49:00 -0700165 of_ports = config["port_map"].keys()
Rich Lane51c23b32012-07-27 16:37:25 -0700166 of_ports.sort()
167 self.assertTrue(len(of_ports) > 0, "Not enough ports for test")
168
169 if (pkttype == 'ICMP'):
170 pkt = simple_icmp_packet()
171 else:
172 pkt = simple_tcp_packet()
Ed Swierk99a74de2012-08-22 06:40:54 -0700173 match = packet_to_flow_match(self, pkt)
Rich Lane51c23b32012-07-27 16:37:25 -0700174 match.wildcards &= ~ofp.OFPFW_IN_PORT
175 self.assertTrue(match is not None,
176 "Could not generate flow match from pkt")
177 act = action.action_output()
178
Rich Lane9a003812012-10-04 17:17:59 -0700179 rv = delete_all_flows(self.controller)
Rich Lane51c23b32012-07-27 16:37:25 -0700180 self.assertEqual(rv, 0, "Failed to delete all flows")
181
182 ingress_port = of_ports[0]
183 match.in_port = ingress_port
184
185 request = message.flow_mod()
186 request.match = match
187
188 request.buffer_id = 0xffffffff
189 act.port = ofp.OFPP_CONTROLLER
190 act.max_len = 65535
191 self.assertTrue(request.actions.add(act), "Could not add action")
192
Rich Lane9a003812012-10-04 17:17:59 -0700193 logging.info("Inserting flow")
Rich Lane51c23b32012-07-27 16:37:25 -0700194 rv = self.controller.message_send(request)
195 self.assertTrue(rv != -1, "Error installing flow mod")
196 self.assertEqual(do_barrier(self.controller), 0, "Barrier failed")
197
Rich Lane9a003812012-10-04 17:17:59 -0700198 logging.info("Sending packet to dp port " +
Rich Lane51c23b32012-07-27 16:37:25 -0700199 str(ingress_port))
200 self.dataplane.send(ingress_port, str(pkt))
201
202 (response, raw) = self.controller.poll(ofp.OFPT_PACKET_IN)
203
204 self.assertTrue(response is not None,
205 'Packet in message not received by controller')
206 if not dataplane.match_exp_pkt(pkt, response.data):
Rich Lane9a003812012-10-04 17:17:59 -0700207 logging.debug("Sent %s" % format_packet(pkt))
208 logging.debug("Resp %s" % format_packet(response.data))
Rich Lane51c23b32012-07-27 16:37:25 -0700209 self.assertTrue(False,
210 'Response packet does not match send packet' +
211 ' for controller port')
212
Howard Pershf97840f2012-04-10 16:30:42 -0700213
Rich Laneb90a1c42012-10-05 09:16:05 -0700214class DirectPacketQueue(base_tests.SimpleDataPlane):
Howard Pershf97840f2012-04-10 16:30:42 -0700215 """
216 Send packet to single queue on single egress port
217
218 Generate a packet
219 Generate and install a matching flow
220 Add action to direct the packet to an egress port and queue
221 Send the packet to ingress dataplane port
222 Verify the packet is received at the egress port only
223 """
224 def runTest(self):
225 self.handleFlow()
226
Howard Persh670b5672012-04-13 09:08:29 -0700227 def portQueuesGet(self, queue_stats, port_num):
228 result = []
229 for qs in queue_stats.stats:
230 if qs.port_no != port_num:
231 continue
232 result.append(qs.queue_id)
233 return result
234
Howard Pershf97840f2012-04-10 16:30:42 -0700235 def handleFlow(self, pkttype='TCP'):
Rich Lane477f4812012-10-04 22:49:00 -0700236 of_ports = config["port_map"].keys()
Howard Pershf97840f2012-04-10 16:30:42 -0700237 of_ports.sort()
238 self.assertTrue(len(of_ports) > 1, "Not enough ports for test")
239
240 if (pkttype == 'ICMP'):
241 pkt = simple_icmp_packet()
242 else:
243 pkt = simple_tcp_packet()
Ed Swierk99a74de2012-08-22 06:40:54 -0700244 match = packet_to_flow_match(self, pkt)
Howard Pershf97840f2012-04-10 16:30:42 -0700245 match.wildcards &= ~ofp.OFPFW_IN_PORT
246 self.assertTrue(match is not None,
247 "Could not generate flow match from pkt")
248
Howard Persh670b5672012-04-13 09:08:29 -0700249 # Get queue stats from switch
250
251 request = message.queue_stats_request()
252 request.port_no = ofp.OFPP_ALL
253 request.queue_id = ofp.OFPQ_ALL
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700254 (queue_stats, p) = self.controller.transact(request)
Howard Persh670b5672012-04-13 09:08:29 -0700255 self.assertNotEqual(queue_stats, None, "Queue stats request failed")
256
257 act = action.action_enqueue()
Howard Pershf97840f2012-04-10 16:30:42 -0700258
259 for idx in range(len(of_ports)):
Howard Pershf97840f2012-04-10 16:30:42 -0700260 ingress_port = of_ports[idx]
261 egress_port = of_ports[(idx + 1) % len(of_ports)]
Howard Pershf97840f2012-04-10 16:30:42 -0700262
Howard Persh670b5672012-04-13 09:08:29 -0700263 for egress_queue_id in self.portQueuesGet(queue_stats, egress_port):
Rich Lane9a003812012-10-04 17:17:59 -0700264 logging.info("Ingress " + str(ingress_port)
Howard Persh670b5672012-04-13 09:08:29 -0700265 + " to egress " + str(egress_port)
266 + " queue " + str(egress_queue_id)
267 )
Howard Pershf97840f2012-04-10 16:30:42 -0700268
Rich Lane9a003812012-10-04 17:17:59 -0700269 rv = delete_all_flows(self.controller)
Howard Persh670b5672012-04-13 09:08:29 -0700270 self.assertEqual(rv, 0, "Failed to delete all flows")
Howard Pershf97840f2012-04-10 16:30:42 -0700271
Howard Persh670b5672012-04-13 09:08:29 -0700272 match.in_port = ingress_port
273
274 request = message.flow_mod()
275 request.match = match
Howard Pershf97840f2012-04-10 16:30:42 -0700276
Howard Persh670b5672012-04-13 09:08:29 -0700277 request.buffer_id = 0xffffffff
278 act.port = egress_port
279 act.queue_id = egress_queue_id
280 self.assertTrue(request.actions.add(act), "Could not add action")
Howard Pershf97840f2012-04-10 16:30:42 -0700281
Rich Lane9a003812012-10-04 17:17:59 -0700282 logging.info("Inserting flow")
Howard Persh670b5672012-04-13 09:08:29 -0700283 rv = self.controller.message_send(request)
284 self.assertTrue(rv != -1, "Error installing flow mod")
285 self.assertEqual(do_barrier(self.controller), 0, "Barrier failed")
Howard Pershf97840f2012-04-10 16:30:42 -0700286
Howard Persh670b5672012-04-13 09:08:29 -0700287 # Get current stats for selected egress queue
Howard Pershf97840f2012-04-10 16:30:42 -0700288
Howard Persh670b5672012-04-13 09:08:29 -0700289 request = message.queue_stats_request()
290 request.port_no = egress_port
291 request.queue_id = egress_queue_id
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700292 (qs_before, p) = self.controller.transact(request)
Howard Persh670b5672012-04-13 09:08:29 -0700293 self.assertNotEqual(qs_before, None, "Queue stats request failed")
294
Rich Lane9a003812012-10-04 17:17:59 -0700295 logging.info("Sending packet to dp port " +
Howard Persh670b5672012-04-13 09:08:29 -0700296 str(ingress_port))
297 self.dataplane.send(ingress_port, str(pkt))
298
299 exp_pkt_arg = None
300 exp_port = None
Rich Lane477f4812012-10-04 22:49:00 -0700301 if config["relax"]:
Howard Persh670b5672012-04-13 09:08:29 -0700302 exp_pkt_arg = pkt
303 exp_port = egress_port
304
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700305 (rcv_port, rcv_pkt, pkt_time) = self.dataplane.poll(port_number=exp_port,
Howard Persh670b5672012-04-13 09:08:29 -0700306 exp_pkt=exp_pkt_arg)
307 self.assertTrue(rcv_pkt is not None, "Did not receive packet")
Rich Lane9a003812012-10-04 17:17:59 -0700308 logging.debug("Packet len " + str(len(rcv_pkt)) + " in on " +
Howard Persh670b5672012-04-13 09:08:29 -0700309 str(rcv_port))
310 self.assertEqual(rcv_port, egress_port, "Unexpected receive port")
311 self.assertEqual(str(pkt), str(rcv_pkt),
312 'Response packet does not match send packet')
313
Ed Swierkb8a86512012-04-18 18:45:58 -0700314 # FIXME: instead of sleeping, keep requesting queue stats until
315 # the expected queue counter increases or some large timeout is
316 # reached
317 time.sleep(2)
318
Howard Persh670b5672012-04-13 09:08:29 -0700319 # Get current stats for selected egress queue again
320
321 request = message.queue_stats_request()
322 request.port_no = egress_port
323 request.queue_id = egress_queue_id
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700324 (qs_after, p) = self.controller.transact(request)
Howard Persh670b5672012-04-13 09:08:29 -0700325 self.assertNotEqual(qs_after, None, "Queue stats request failed")
326
327 # Make sure that tx packet counter for selected egress queue was
328 # incremented
329
Ed Swierk22f59152012-04-17 16:36:47 -0700330 self.assertEqual(qs_after.stats[0].tx_packets, \
331 qs_before.stats[0].tx_packets + 1, \
Howard Persh670b5672012-04-13 09:08:29 -0700332 "Verification of egress queue tx packet count failed"
333 )
334
335
Rich Laneb90a1c42012-10-05 09:16:05 -0700336class DirectPacketControllerQueue(base_tests.SimpleDataPlane):
Ken Chiang899ff8e2012-05-23 18:26:12 -0700337 """
338 Send a packet from each of the openflow ports
339 to each of the queues configured on the controller port.
340 If no queues have been configured, no packets are sent.
Howard Pershf97840f2012-04-10 16:30:42 -0700341
Ken Chiang899ff8e2012-05-23 18:26:12 -0700342 Generate a packet
343 Generate and install a matching flow
344 Add action to direct the packet to one of the controller port queues
345 Send the packet to ingress dataplane port
346 Verify the packet is received on the controller port queue
347 """
348 def runTest(self):
349 self.handleFlow()
350
351 def portQueuesGet(self, queue_stats, port_num):
352 result = []
353 for qs in queue_stats.stats:
354 if qs.port_no != port_num:
355 continue
356 result.append(qs.queue_id)
357 return result
358
359 def handleFlow(self, pkttype='TCP'):
Rich Lane477f4812012-10-04 22:49:00 -0700360 of_ports = config["port_map"].keys()
Ken Chiang899ff8e2012-05-23 18:26:12 -0700361 of_ports.sort()
362 self.assertTrue(len(of_ports) > 1, "Not enough ports for test")
363
364 if (pkttype == 'ICMP'):
365 pkt = simple_icmp_packet()
366 else:
367 pkt = simple_tcp_packet()
Ed Swierk99a74de2012-08-22 06:40:54 -0700368 match = packet_to_flow_match(self, pkt)
Ken Chiang899ff8e2012-05-23 18:26:12 -0700369 match.wildcards &= ~ofp.OFPFW_IN_PORT
370 self.assertTrue(match is not None,
371 "Could not generate flow match from pkt")
372
373 # Get queue stats from switch
374
375 request = message.queue_stats_request()
376 request.port_no = ofp.OFPP_CONTROLLER
377 request.queue_id = ofp.OFPQ_ALL
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700378 (queue_stats, p) = self.controller.transact(request)
Ken Chiang899ff8e2012-05-23 18:26:12 -0700379 self.assertNotEqual(queue_stats, None, "Queue stats request failed")
380
381 act = action.action_enqueue()
382
383 for idx in range(len(of_ports)):
384 ingress_port = of_ports[idx]
385 egress_port = ofp.OFPP_CONTROLLER
386
Rich Lane9a003812012-10-04 17:17:59 -0700387 logging.info("Ingress port " + str(ingress_port)
Ken Chiang899ff8e2012-05-23 18:26:12 -0700388 + ", controller port queues "
389 + str(self.portQueuesGet(queue_stats, egress_port)))
390
391 for egress_queue_id in self.portQueuesGet(queue_stats, egress_port):
Rich Lane9a003812012-10-04 17:17:59 -0700392 logging.info("Ingress " + str(ingress_port)
Ken Chiang899ff8e2012-05-23 18:26:12 -0700393 + " to egress " + str(egress_port)
394 + " queue " + str(egress_queue_id)
395 )
396
Rich Lane9a003812012-10-04 17:17:59 -0700397 rv = delete_all_flows(self.controller)
Ken Chiang899ff8e2012-05-23 18:26:12 -0700398 self.assertEqual(rv, 0, "Failed to delete all flows")
399
400 match.in_port = ingress_port
401
402 request = message.flow_mod()
403 request.match = match
404
405 request.buffer_id = 0xffffffff
406 act.port = egress_port
407 act.queue_id = egress_queue_id
408 self.assertTrue(request.actions.add(act), "Could not add action")
409
Rich Lane9a003812012-10-04 17:17:59 -0700410 logging.info("Inserting flow")
Ken Chiang899ff8e2012-05-23 18:26:12 -0700411 rv = self.controller.message_send(request)
412 self.assertTrue(rv != -1, "Error installing flow mod")
413 self.assertEqual(do_barrier(self.controller), 0, "Barrier failed")
414
415 # Get current stats for selected egress queue
416
417 request = message.queue_stats_request()
418 request.port_no = egress_port
419 request.queue_id = egress_queue_id
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700420 (qs_before, p) = self.controller.transact(request)
Ken Chiang899ff8e2012-05-23 18:26:12 -0700421 self.assertNotEqual(qs_before, None, "Queue stats request failed")
422
Rich Lane9a003812012-10-04 17:17:59 -0700423 logging.info("Sending packet to dp port " +
Ken Chiang899ff8e2012-05-23 18:26:12 -0700424 str(ingress_port))
425 self.dataplane.send(ingress_port, str(pkt))
426
427 exp_pkt_arg = None
428 exp_port = None
429
Rich Lanee5779d32012-10-05 17:56:04 -0700430 count = 0
Ken Chiang899ff8e2012-05-23 18:26:12 -0700431 while True:
Dan Talaycoc689a792012-09-28 14:22:53 -0700432 (response, raw) = self.controller.poll(ofp.OFPT_PACKET_IN)
Ken Chiang899ff8e2012-05-23 18:26:12 -0700433 if not response: # Timeout
434 break
435 if dataplane.match_exp_pkt(pkt, response.data): # Got match
436 break
Rich Lane477f4812012-10-04 22:49:00 -0700437 if not config["relax"]: # Only one attempt to match
Ken Chiang899ff8e2012-05-23 18:26:12 -0700438 break
439 count += 1
440 if count > 10: # Too many tries
441 break
442
443 self.assertTrue(response is not None,
444 'Packet in message not received by controller')
445 if not dataplane.match_exp_pkt(pkt, response.data):
Rich Lane9a003812012-10-04 17:17:59 -0700446 logging.debug("Sent %s" % format_packet(pkt))
447 logging.debug("Resp %s" % format_packet(response.data))
Ken Chiang899ff8e2012-05-23 18:26:12 -0700448 self.assertTrue(False,
449 'Response packet does not match send packet' +
450 ' for controller port')
451
452 # FIXME: instead of sleeping, keep requesting queue stats until
453 # the expected queue counter increases or some large timeout is
454 # reached
455 time.sleep(2)
456
457 # Get current stats for selected egress queue again
458
459 request = message.queue_stats_request()
460 request.port_no = egress_port
461 request.queue_id = egress_queue_id
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700462 (qs_after, p) = self.controller.transact(request)
Ken Chiang899ff8e2012-05-23 18:26:12 -0700463 self.assertNotEqual(qs_after, None, "Queue stats request failed")
464
465 # Make sure that tx packet counter for selected egress queue was
466 # incremented
467
468 self.assertEqual(qs_after.stats[0].tx_packets, \
469 qs_before.stats[0].tx_packets + 1, \
470 "Verification of egress queue tx packet count failed"
471 )
472
Howard Pershf97840f2012-04-10 16:30:42 -0700473
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700474class DirectPacketICMP(DirectPacket):
475 """
476 Send ICMP packet to single egress port
477
478 Generate a ICMP packet
479 Generate and install a matching flow
480 Add action to direct the packet to an egress port
481 Send the packet to ingress dataplane port
482 Verify the packet is received at the egress port only
483 Difference from DirectPacket test is that sent packet is ICMP
484 """
485 def runTest(self):
486 self.handleFlow(pkttype='ICMP')
Dan Talayco2d0d49a2010-05-11 15:29:08 -0700487
Rich Laneb90a1c42012-10-05 09:16:05 -0700488class DirectTwoPorts(base_tests.SimpleDataPlane):
Dan Talayco2d0d49a2010-05-11 15:29:08 -0700489 """
490 Send packet to two egress ports
491
492 Generate a packet
493 Generate and install a matching flow
494 Add action to direct the packet to two egress ports
495 Send the packet to ingress dataplane port
496 Verify the packet is received at the two egress ports
497 """
498 def runTest(self):
Rich Lane477f4812012-10-04 22:49:00 -0700499 of_ports = config["port_map"].keys()
Dan Talayco2d0d49a2010-05-11 15:29:08 -0700500 of_ports.sort()
501 self.assertTrue(len(of_ports) > 2, "Not enough ports for test")
502
Dan Talayco2d0d49a2010-05-11 15:29:08 -0700503 pkt = simple_tcp_packet()
Ed Swierk99a74de2012-08-22 06:40:54 -0700504 match = packet_to_flow_match(self, pkt)
Dan Talayco2d0d49a2010-05-11 15:29:08 -0700505 match.wildcards &= ~ofp.OFPFW_IN_PORT
506 self.assertTrue(match is not None,
507 "Could not generate flow match from pkt")
508 act = action.action_output()
509
510 for idx in range(len(of_ports)):
Rich Lane9a003812012-10-04 17:17:59 -0700511 rv = delete_all_flows(self.controller)
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700512 self.assertEqual(rv, 0, "Failed to delete all flows")
Dan Talayco2e77a842010-05-12 15:39:46 -0700513
Dan Talayco2d0d49a2010-05-11 15:29:08 -0700514 ingress_port = of_ports[idx]
515 egress_port1 = of_ports[(idx + 1) % len(of_ports)]
516 egress_port2 = of_ports[(idx + 2) % len(of_ports)]
Rich Lane9a003812012-10-04 17:17:59 -0700517 logging.info("Ingress " + str(ingress_port) +
Dan Talayco2d0d49a2010-05-11 15:29:08 -0700518 " to egress " + str(egress_port1) + " and " +
519 str(egress_port2))
520
521 match.in_port = ingress_port
522
523 request = message.flow_mod()
524 request.match = match
525 request.buffer_id = 0xffffffff
526 act.port = egress_port1
527 self.assertTrue(request.actions.add(act), "Could not add action1")
528 act.port = egress_port2
529 self.assertTrue(request.actions.add(act), "Could not add action2")
Rich Lane9a003812012-10-04 17:17:59 -0700530 # logging.info(request.show())
Dan Talayco2d0d49a2010-05-11 15:29:08 -0700531
Rich Lane9a003812012-10-04 17:17:59 -0700532 logging.info("Inserting flow")
Dan Talayco2d0d49a2010-05-11 15:29:08 -0700533 rv = self.controller.message_send(request)
534 self.assertTrue(rv != -1, "Error installing flow mod")
Dan Talayco0fc08bd2012-04-09 16:56:18 -0700535 self.assertEqual(do_barrier(self.controller), 0, "Barrier failed")
Dan Talayco2d0d49a2010-05-11 15:29:08 -0700536
Rich Lane9a003812012-10-04 17:17:59 -0700537 logging.info("Sending packet to dp port " +
Dan Talayco2d0d49a2010-05-11 15:29:08 -0700538 str(ingress_port))
539 self.dataplane.send(ingress_port, str(pkt))
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700540 yes_ports = set([egress_port1, egress_port2])
541 no_ports = set(of_ports).difference(yes_ports)
Dan Talayco2d0d49a2010-05-11 15:29:08 -0700542
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700543 receive_pkt_check(self.dataplane, pkt, yes_ports, no_ports,
Rich Lane2014f9b2012-10-05 15:29:40 -0700544 self)
Dan Talaycob0b0fdb2010-05-11 15:44:56 -0700545
Rich Laneb90a1c42012-10-05 09:16:05 -0700546class DirectMCNonIngress(base_tests.SimpleDataPlane):
Dan Talaycob0b0fdb2010-05-11 15:44:56 -0700547 """
548 Multicast to all non-ingress ports
549
550 Generate a packet
551 Generate and install a matching flow
552 Add action to direct the packet to all non-ingress ports
553 Send the packet to ingress dataplane port
554 Verify the packet is received at all non-ingress ports
555
556 Does not use the flood action
557 """
558 def runTest(self):
Rich Lane477f4812012-10-04 22:49:00 -0700559 of_ports = config["port_map"].keys()
Dan Talaycob0b0fdb2010-05-11 15:44:56 -0700560 of_ports.sort()
561 self.assertTrue(len(of_ports) > 2, "Not enough ports for test")
562
Dan Talaycob0b0fdb2010-05-11 15:44:56 -0700563 pkt = simple_tcp_packet()
Ed Swierk99a74de2012-08-22 06:40:54 -0700564 match = packet_to_flow_match(self, pkt)
Dan Talaycob0b0fdb2010-05-11 15:44:56 -0700565 match.wildcards &= ~ofp.OFPFW_IN_PORT
566 self.assertTrue(match is not None,
567 "Could not generate flow match from pkt")
568 act = action.action_output()
569
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700570 for ingress_port in of_ports:
Rich Lane9a003812012-10-04 17:17:59 -0700571 rv = delete_all_flows(self.controller)
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700572 self.assertEqual(rv, 0, "Failed to delete all flows")
Dan Talayco2e77a842010-05-12 15:39:46 -0700573
Rich Lane9a003812012-10-04 17:17:59 -0700574 logging.info("Ingress " + str(ingress_port) +
Dan Talaycob0b0fdb2010-05-11 15:44:56 -0700575 " all non-ingress ports")
Dan Talaycob0b0fdb2010-05-11 15:44:56 -0700576 match.in_port = ingress_port
577
578 request = message.flow_mod()
579 request.match = match
580 request.buffer_id = 0xffffffff
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700581 for egress_port in of_ports:
582 if egress_port == ingress_port:
Dan Talaycob0b0fdb2010-05-11 15:44:56 -0700583 continue
Dan Talaycob0b0fdb2010-05-11 15:44:56 -0700584 act.port = egress_port
585 self.assertTrue(request.actions.add(act),
586 "Could not add output to " + str(egress_port))
Rich Lane9a003812012-10-04 17:17:59 -0700587 logging.debug(request.show())
Dan Talaycob0b0fdb2010-05-11 15:44:56 -0700588
Rich Lane9a003812012-10-04 17:17:59 -0700589 logging.info("Inserting flow")
Dan Talaycob0b0fdb2010-05-11 15:44:56 -0700590 rv = self.controller.message_send(request)
591 self.assertTrue(rv != -1, "Error installing flow mod")
Dan Talayco0fc08bd2012-04-09 16:56:18 -0700592 self.assertEqual(do_barrier(self.controller), 0, "Barrier failed")
Dan Talaycob0b0fdb2010-05-11 15:44:56 -0700593
Rich Lane9a003812012-10-04 17:17:59 -0700594 logging.info("Sending packet to dp port " + str(ingress_port))
Dan Talaycob0b0fdb2010-05-11 15:44:56 -0700595 self.dataplane.send(ingress_port, str(pkt))
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700596 yes_ports = set(of_ports).difference([ingress_port])
597 receive_pkt_check(self.dataplane, pkt, yes_ports, [ingress_port],
Rich Lane2014f9b2012-10-05 15:29:40 -0700598 self)
Dan Talaycob0b0fdb2010-05-11 15:44:56 -0700599
Dan Talayco32fa6542010-05-11 15:54:08 -0700600
Rich Laneb90a1c42012-10-05 09:16:05 -0700601class DirectMC(base_tests.SimpleDataPlane):
Dan Talayco32fa6542010-05-11 15:54:08 -0700602 """
603 Multicast to all ports including ingress
604
605 Generate a packet
606 Generate and install a matching flow
607 Add action to direct the packet to all non-ingress ports
608 Send the packet to ingress dataplane port
609 Verify the packet is received at all ports
610
611 Does not use the flood action
612 """
613 def runTest(self):
Rich Lane477f4812012-10-04 22:49:00 -0700614 of_ports = config["port_map"].keys()
Dan Talayco32fa6542010-05-11 15:54:08 -0700615 of_ports.sort()
616 self.assertTrue(len(of_ports) > 2, "Not enough ports for test")
617
Dan Talayco32fa6542010-05-11 15:54:08 -0700618 pkt = simple_tcp_packet()
Ed Swierk99a74de2012-08-22 06:40:54 -0700619 match = packet_to_flow_match(self, pkt)
Dan Talayco32fa6542010-05-11 15:54:08 -0700620 match.wildcards &= ~ofp.OFPFW_IN_PORT
621 self.assertTrue(match is not None,
622 "Could not generate flow match from pkt")
623 act = action.action_output()
624
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700625 for ingress_port in of_ports:
Rich Lane9a003812012-10-04 17:17:59 -0700626 rv = delete_all_flows(self.controller)
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700627 self.assertEqual(rv, 0, "Failed to delete all flows")
Dan Talayco2e77a842010-05-12 15:39:46 -0700628
Rich Lane9a003812012-10-04 17:17:59 -0700629 logging.info("Ingress " + str(ingress_port) + " to all ports")
Dan Talayco32fa6542010-05-11 15:54:08 -0700630 match.in_port = ingress_port
631
632 request = message.flow_mod()
633 request.match = match
634 request.buffer_id = 0xffffffff
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700635 for egress_port in of_ports:
636 if egress_port == ingress_port:
Dan Talayco32fa6542010-05-11 15:54:08 -0700637 act.port = ofp.OFPP_IN_PORT
638 else:
639 act.port = egress_port
640 self.assertTrue(request.actions.add(act),
641 "Could not add output to " + str(egress_port))
Rich Lane9a003812012-10-04 17:17:59 -0700642 # logging.info(request.show())
Dan Talayco2e77a842010-05-12 15:39:46 -0700643
Rich Lane9a003812012-10-04 17:17:59 -0700644 logging.info("Inserting flow")
Dan Talayco2e77a842010-05-12 15:39:46 -0700645 rv = self.controller.message_send(request)
646 self.assertTrue(rv != -1, "Error installing flow mod")
Dan Talayco0fc08bd2012-04-09 16:56:18 -0700647 self.assertEqual(do_barrier(self.controller), 0, "Barrier failed")
Dan Talayco2e77a842010-05-12 15:39:46 -0700648
Rich Lane9a003812012-10-04 17:17:59 -0700649 logging.info("Sending packet to dp port " + str(ingress_port))
Dan Talayco2e77a842010-05-12 15:39:46 -0700650 self.dataplane.send(ingress_port, str(pkt))
Rich Lane2014f9b2012-10-05 15:29:40 -0700651 receive_pkt_check(self.dataplane, pkt, of_ports, [], self)
Dan Talayco2e77a842010-05-12 15:39:46 -0700652
Rich Laneb90a1c42012-10-05 09:16:05 -0700653class Flood(base_tests.SimpleDataPlane):
Dan Talayco2e77a842010-05-12 15:39:46 -0700654 """
655 Flood to all ports except ingress
656
657 Generate a packet
658 Generate and install a matching flow
659 Add action to flood the packet
660 Send the packet to ingress dataplane port
661 Verify the packet is received at all other ports
662 """
663 def runTest(self):
Rich Lane477f4812012-10-04 22:49:00 -0700664 of_ports = config["port_map"].keys()
Dan Talayco2e77a842010-05-12 15:39:46 -0700665 of_ports.sort()
666 self.assertTrue(len(of_ports) > 1, "Not enough ports for test")
667
668 pkt = simple_tcp_packet()
Ed Swierk99a74de2012-08-22 06:40:54 -0700669 match = packet_to_flow_match(self, pkt)
Dan Talayco2e77a842010-05-12 15:39:46 -0700670 match.wildcards &= ~ofp.OFPFW_IN_PORT
671 self.assertTrue(match is not None,
672 "Could not generate flow match from pkt")
673 act = action.action_output()
674
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700675 for ingress_port in of_ports:
Rich Lane9a003812012-10-04 17:17:59 -0700676 rv = delete_all_flows(self.controller)
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700677 self.assertEqual(rv, 0, "Failed to delete all flows")
Dan Talayco2e77a842010-05-12 15:39:46 -0700678
Rich Lane9a003812012-10-04 17:17:59 -0700679 logging.info("Ingress " + str(ingress_port) + " to all ports")
Dan Talayco2e77a842010-05-12 15:39:46 -0700680 match.in_port = ingress_port
681
682 request = message.flow_mod()
683 request.match = match
684 request.buffer_id = 0xffffffff
685 act.port = ofp.OFPP_FLOOD
686 self.assertTrue(request.actions.add(act),
Dan Talayco4aa13122010-05-12 15:54:44 -0700687 "Could not add flood port action")
Rich Lane9a003812012-10-04 17:17:59 -0700688 logging.info(request.show())
Dan Talayco32fa6542010-05-11 15:54:08 -0700689
Rich Lane9a003812012-10-04 17:17:59 -0700690 logging.info("Inserting flow")
Dan Talayco32fa6542010-05-11 15:54:08 -0700691 rv = self.controller.message_send(request)
692 self.assertTrue(rv != -1, "Error installing flow mod")
Dan Talayco0fc08bd2012-04-09 16:56:18 -0700693 self.assertEqual(do_barrier(self.controller), 0, "Barrier failed")
Dan Talayco32fa6542010-05-11 15:54:08 -0700694
Rich Lane9a003812012-10-04 17:17:59 -0700695 logging.info("Sending packet to dp port " + str(ingress_port))
Dan Talayco32fa6542010-05-11 15:54:08 -0700696 self.dataplane.send(ingress_port, str(pkt))
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700697 yes_ports = set(of_ports).difference([ingress_port])
698 receive_pkt_check(self.dataplane, pkt, yes_ports, [ingress_port],
Rich Lane2014f9b2012-10-05 15:29:40 -0700699 self)
Dan Talayco3be5b062010-05-12 15:46:21 -0700700
Rich Laneb90a1c42012-10-05 09:16:05 -0700701class FloodPlusIngress(base_tests.SimpleDataPlane):
Dan Talayco3be5b062010-05-12 15:46:21 -0700702 """
703 Flood to all ports plus send to ingress port
704
705 Generate a packet
706 Generate and install a matching flow
707 Add action to flood the packet
708 Add action to send to ingress port
709 Send the packet to ingress dataplane port
710 Verify the packet is received at all other ports
711 """
712 def runTest(self):
Rich Lane477f4812012-10-04 22:49:00 -0700713 of_ports = config["port_map"].keys()
Dan Talayco3be5b062010-05-12 15:46:21 -0700714 of_ports.sort()
715 self.assertTrue(len(of_ports) > 1, "Not enough ports for test")
716
717 pkt = simple_tcp_packet()
Ed Swierk99a74de2012-08-22 06:40:54 -0700718 match = packet_to_flow_match(self, pkt)
Dan Talayco3be5b062010-05-12 15:46:21 -0700719 match.wildcards &= ~ofp.OFPFW_IN_PORT
720 self.assertTrue(match is not None,
721 "Could not generate flow match from pkt")
722 act = action.action_output()
723
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700724 for ingress_port in of_ports:
Rich Lane9a003812012-10-04 17:17:59 -0700725 rv = delete_all_flows(self.controller)
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700726 self.assertEqual(rv, 0, "Failed to delete all flows")
Dan Talayco3be5b062010-05-12 15:46:21 -0700727
Rich Lane9a003812012-10-04 17:17:59 -0700728 logging.info("Ingress " + str(ingress_port) + " to all ports")
Dan Talayco3be5b062010-05-12 15:46:21 -0700729 match.in_port = ingress_port
730
731 request = message.flow_mod()
732 request.match = match
733 request.buffer_id = 0xffffffff
734 act.port = ofp.OFPP_FLOOD
735 self.assertTrue(request.actions.add(act),
Dan Talayco4aa13122010-05-12 15:54:44 -0700736 "Could not add flood port action")
737 act.port = ofp.OFPP_IN_PORT
738 self.assertTrue(request.actions.add(act),
739 "Could not add ingress port for output")
Rich Lane9a003812012-10-04 17:17:59 -0700740 logging.info(request.show())
Dan Talayco4aa13122010-05-12 15:54:44 -0700741
Rich Lane9a003812012-10-04 17:17:59 -0700742 logging.info("Inserting flow")
Dan Talayco4aa13122010-05-12 15:54:44 -0700743 rv = self.controller.message_send(request)
744 self.assertTrue(rv != -1, "Error installing flow mod")
Dan Talayco0fc08bd2012-04-09 16:56:18 -0700745 self.assertEqual(do_barrier(self.controller), 0, "Barrier failed")
Dan Talayco4aa13122010-05-12 15:54:44 -0700746
Rich Lane9a003812012-10-04 17:17:59 -0700747 logging.info("Sending packet to dp port " + str(ingress_port))
Dan Talayco4aa13122010-05-12 15:54:44 -0700748 self.dataplane.send(ingress_port, str(pkt))
Rich Lane2014f9b2012-10-05 15:29:40 -0700749 receive_pkt_check(self.dataplane, pkt, of_ports, [], self)
Dan Talayco4aa13122010-05-12 15:54:44 -0700750
Rich Laneb90a1c42012-10-05 09:16:05 -0700751class All(base_tests.SimpleDataPlane):
Dan Talayco4aa13122010-05-12 15:54:44 -0700752 """
753 Send to OFPP_ALL port
754
755 Generate a packet
756 Generate and install a matching flow
757 Add action to forward to OFPP_ALL
758 Send the packet to ingress dataplane port
759 Verify the packet is received at all other ports
760 """
761 def runTest(self):
Rich Lane477f4812012-10-04 22:49:00 -0700762 of_ports = config["port_map"].keys()
Dan Talayco4aa13122010-05-12 15:54:44 -0700763 of_ports.sort()
764 self.assertTrue(len(of_ports) > 1, "Not enough ports for test")
765
766 pkt = simple_tcp_packet()
Ed Swierk99a74de2012-08-22 06:40:54 -0700767 match = packet_to_flow_match(self, pkt)
Dan Talayco4aa13122010-05-12 15:54:44 -0700768 match.wildcards &= ~ofp.OFPFW_IN_PORT
769 self.assertTrue(match is not None,
770 "Could not generate flow match from pkt")
771 act = action.action_output()
772
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700773 for ingress_port in of_ports:
Rich Lane9a003812012-10-04 17:17:59 -0700774 rv = delete_all_flows(self.controller)
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700775 self.assertEqual(rv, 0, "Failed to delete all flows")
Dan Talayco4aa13122010-05-12 15:54:44 -0700776
Rich Lane9a003812012-10-04 17:17:59 -0700777 logging.info("Ingress " + str(ingress_port) + " to all ports")
Dan Talayco4aa13122010-05-12 15:54:44 -0700778 match.in_port = ingress_port
779
780 request = message.flow_mod()
781 request.match = match
782 request.buffer_id = 0xffffffff
783 act.port = ofp.OFPP_ALL
784 self.assertTrue(request.actions.add(act),
785 "Could not add ALL port action")
Rich Lane9a003812012-10-04 17:17:59 -0700786 logging.info(request.show())
Dan Talayco4aa13122010-05-12 15:54:44 -0700787
Rich Lane9a003812012-10-04 17:17:59 -0700788 logging.info("Inserting flow")
Dan Talayco4aa13122010-05-12 15:54:44 -0700789 rv = self.controller.message_send(request)
790 self.assertTrue(rv != -1, "Error installing flow mod")
Dan Talayco0fc08bd2012-04-09 16:56:18 -0700791 self.assertEqual(do_barrier(self.controller), 0, "Barrier failed")
Dan Talayco4aa13122010-05-12 15:54:44 -0700792
Rich Lane9a003812012-10-04 17:17:59 -0700793 logging.info("Sending packet to dp port " + str(ingress_port))
Dan Talayco4aa13122010-05-12 15:54:44 -0700794 self.dataplane.send(ingress_port, str(pkt))
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700795 yes_ports = set(of_ports).difference([ingress_port])
796 receive_pkt_check(self.dataplane, pkt, yes_ports, [ingress_port],
Rich Lane2014f9b2012-10-05 15:29:40 -0700797 self)
Dan Talayco4aa13122010-05-12 15:54:44 -0700798
Rich Laneb90a1c42012-10-05 09:16:05 -0700799class AllPlusIngress(base_tests.SimpleDataPlane):
Dan Talayco4aa13122010-05-12 15:54:44 -0700800 """
801 Send to OFPP_ALL port and ingress port
802
803 Generate a packet
804 Generate and install a matching flow
805 Add action to forward to OFPP_ALL
806 Add action to forward to ingress port
807 Send the packet to ingress dataplane port
808 Verify the packet is received at all other ports
809 """
810 def runTest(self):
Rich Lane477f4812012-10-04 22:49:00 -0700811 of_ports = config["port_map"].keys()
Dan Talayco4aa13122010-05-12 15:54:44 -0700812 of_ports.sort()
813 self.assertTrue(len(of_ports) > 1, "Not enough ports for test")
814
815 pkt = simple_tcp_packet()
Ed Swierk99a74de2012-08-22 06:40:54 -0700816 match = packet_to_flow_match(self, pkt)
Dan Talayco4aa13122010-05-12 15:54:44 -0700817 match.wildcards &= ~ofp.OFPFW_IN_PORT
818 self.assertTrue(match is not None,
819 "Could not generate flow match from pkt")
820 act = action.action_output()
821
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700822 for ingress_port in of_ports:
Rich Lane9a003812012-10-04 17:17:59 -0700823 rv = delete_all_flows(self.controller)
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700824 self.assertEqual(rv, 0, "Failed to delete all flows")
Dan Talayco4aa13122010-05-12 15:54:44 -0700825
Rich Lane9a003812012-10-04 17:17:59 -0700826 logging.info("Ingress " + str(ingress_port) + " to all ports")
Dan Talayco4aa13122010-05-12 15:54:44 -0700827 match.in_port = ingress_port
828
829 request = message.flow_mod()
830 request.match = match
831 request.buffer_id = 0xffffffff
832 act.port = ofp.OFPP_ALL
833 self.assertTrue(request.actions.add(act),
834 "Could not add ALL port action")
Dan Talayco3be5b062010-05-12 15:46:21 -0700835 act.port = ofp.OFPP_IN_PORT
836 self.assertTrue(request.actions.add(act),
837 "Could not add ingress port for output")
Rich Lane9a003812012-10-04 17:17:59 -0700838 logging.info(request.show())
Dan Talayco3be5b062010-05-12 15:46:21 -0700839
Rich Lane9a003812012-10-04 17:17:59 -0700840 logging.info("Inserting flow")
Dan Talayco3be5b062010-05-12 15:46:21 -0700841 rv = self.controller.message_send(request)
842 self.assertTrue(rv != -1, "Error installing flow mod")
Dan Talayco0fc08bd2012-04-09 16:56:18 -0700843 self.assertEqual(do_barrier(self.controller), 0, "Barrier failed")
Dan Talayco3be5b062010-05-12 15:46:21 -0700844
Rich Lane9a003812012-10-04 17:17:59 -0700845 logging.info("Sending packet to dp port " + str(ingress_port))
Dan Talayco3be5b062010-05-12 15:46:21 -0700846 self.dataplane.send(ingress_port, str(pkt))
Rich Lane2014f9b2012-10-05 15:29:40 -0700847 receive_pkt_check(self.dataplane, pkt, of_ports, [], self)
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700848
Rich Laneb90a1c42012-10-05 09:16:05 -0700849class FloodMinusPort(base_tests.SimpleDataPlane):
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700850 """
851 Config port with No_Flood and test Flood action
852
853 Generate a packet
854 Generate a matching flow
855 Add action to forward to OFPP_ALL
856 Set port to no-flood
857 Send the packet to ingress dataplane port
858 Verify the packet is received at all other ports except
859 the ingress port and the no_flood port
860 """
861 def runTest(self):
Rich Lane477f4812012-10-04 22:49:00 -0700862 of_ports = config["port_map"].keys()
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700863 of_ports.sort()
864 self.assertTrue(len(of_ports) > 2, "Not enough ports for test")
865
866 pkt = simple_tcp_packet()
Ed Swierk99a74de2012-08-22 06:40:54 -0700867 match = packet_to_flow_match(self, pkt)
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700868 match.wildcards &= ~ofp.OFPFW_IN_PORT
869 self.assertTrue(match is not None,
870 "Could not generate flow match from pkt")
871 act = action.action_output()
872
873 for idx in range(len(of_ports)):
Rich Lane9a003812012-10-04 17:17:59 -0700874 rv = delete_all_flows(self.controller)
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700875 self.assertEqual(rv, 0, "Failed to delete all flows")
876
877 ingress_port = of_ports[idx]
878 no_flood_idx = (idx + 1) % len(of_ports)
879 no_flood_port = of_ports[no_flood_idx]
880 rv = port_config_set(self.controller, no_flood_port,
Rich Lane9a003812012-10-04 17:17:59 -0700881 ofp.OFPPC_NO_FLOOD, ofp.OFPPC_NO_FLOOD)
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700882 self.assertEqual(rv, 0, "Failed to set port config")
883
884 match.in_port = ingress_port
885
886 request = message.flow_mod()
887 request.match = match
888 request.buffer_id = 0xffffffff
889 act.port = ofp.OFPP_FLOOD
890 self.assertTrue(request.actions.add(act),
891 "Could not add flood port action")
Rich Lane9a003812012-10-04 17:17:59 -0700892 logging.info(request.show())
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700893
Rich Lane9a003812012-10-04 17:17:59 -0700894 logging.info("Inserting flow")
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700895 rv = self.controller.message_send(request)
896 self.assertTrue(rv != -1, "Error installing flow mod")
Dan Talayco0fc08bd2012-04-09 16:56:18 -0700897 self.assertEqual(do_barrier(self.controller), 0, "Barrier failed")
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700898
Rich Lane9a003812012-10-04 17:17:59 -0700899 logging.info("Sending packet to dp port " + str(ingress_port))
900 logging.info("No flood port is " + str(no_flood_port))
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700901 self.dataplane.send(ingress_port, str(pkt))
902 no_ports = set([ingress_port, no_flood_port])
903 yes_ports = set(of_ports).difference(no_ports)
Rich Lane2014f9b2012-10-05 15:29:40 -0700904 receive_pkt_check(self.dataplane, pkt, yes_ports, no_ports, self)
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700905
906 # Turn no flood off again
907 rv = port_config_set(self.controller, no_flood_port,
Rich Lane9a003812012-10-04 17:17:59 -0700908 0, ofp.OFPPC_NO_FLOOD)
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700909 self.assertEqual(rv, 0, "Failed to reset port config")
910
911 #@todo Should check no other packets received
912
Dan Talayco21381562010-07-17 00:34:47 -0700913
914
Dan Talayco551befa2010-07-15 17:05:32 -0700915################################################################
916
Rich Laneb90a1c42012-10-05 09:16:05 -0700917class BaseMatchCase(base_tests.SimpleDataPlane):
Dan Talayco551befa2010-07-15 17:05:32 -0700918 def setUp(self):
Rich Laneb90a1c42012-10-05 09:16:05 -0700919 base_tests.SimpleDataPlane.setUp(self)
Dan Talayco551befa2010-07-15 17:05:32 -0700920 def runTest(self):
Rich Lane9a003812012-10-04 17:17:59 -0700921 logging.info("BaseMatchCase")
Dan Talayco551befa2010-07-15 17:05:32 -0700922
923class ExactMatch(BaseMatchCase):
Tatsuya Yabe6a6f38a2010-05-22 23:48:04 -0700924 """
Dan Talayco551befa2010-07-15 17:05:32 -0700925 Exercise exact matching for all port pairs
Tatsuya Yabe6a6f38a2010-05-22 23:48:04 -0700926
927 Generate a packet
928 Generate and install a matching flow without wildcard mask
929 Add action to forward to a port
930 Send the packet to the port
931 Verify the packet is received at all other ports (one port at a time)
Tatsuya Yabe6a6f38a2010-05-22 23:48:04 -0700932 """
Tatsuya Yabe0718ad32010-05-24 15:22:10 -0700933
Tatsuya Yabe6a6f38a2010-05-22 23:48:04 -0700934 def runTest(self):
Rich Lane477f4812012-10-04 22:49:00 -0700935 flow_match_test(self, config["port_map"])
Tatsuya Yabe6a6f38a2010-05-22 23:48:04 -0700936
Dan Talayco551befa2010-07-15 17:05:32 -0700937class ExactMatchTagged(BaseMatchCase):
938 """
939 Exact match for all port pairs with tagged pkts
940 """
Tatsuya Yabe6a6f38a2010-05-22 23:48:04 -0700941
Dan Talayco551befa2010-07-15 17:05:32 -0700942 def runTest(self):
Rich Lane2014f9b2012-10-05 15:29:40 -0700943 vid = test_param_get('vid', default=TEST_VID_DEFAULT)
Rich Lane477f4812012-10-04 22:49:00 -0700944 flow_match_test(self, config["port_map"], dl_vlan=vid)
Tatsuya Yabe6a6f38a2010-05-22 23:48:04 -0700945
Dan Talayco551befa2010-07-15 17:05:32 -0700946class ExactMatchTaggedMany(BaseMatchCase):
947 """
948 ExactMatchTagged with many VLANS
949 """
Tatsuya Yabe6a6f38a2010-05-22 23:48:04 -0700950
Rich Laned1d9c282012-10-04 22:07:10 -0700951 priority = -1
952
Dan Talayco551befa2010-07-15 17:05:32 -0700953 def runTest(self):
Dan Talayco21381562010-07-17 00:34:47 -0700954 for vid in range(2,100,10):
Rich Lane477f4812012-10-04 22:49:00 -0700955 flow_match_test(self, config["port_map"], dl_vlan=vid, max_test=5)
Dan Talayco551befa2010-07-15 17:05:32 -0700956 for vid in range(100,4000,389):
Rich Lane477f4812012-10-04 22:49:00 -0700957 flow_match_test(self, config["port_map"], dl_vlan=vid, max_test=5)
958 flow_match_test(self, config["port_map"], dl_vlan=4094, max_test=5)
Tatsuya Yabecdf575e2010-05-25 16:56:38 -0700959
Jeffrey Townsend2a300e42012-03-28 17:24:02 -0700960class SingleWildcardMatchPriority(BaseMatchCase):
Jeffrey Townsend50c82462012-03-28 18:26:14 -0700961 """
962 SingleWildcardMatchPriority
963 """
Jeffrey Townsend2a300e42012-03-28 17:24:02 -0700964
Jeffrey Townsend50c82462012-03-28 18:26:14 -0700965 def _Init(self):
Jeffrey Townsend2a300e42012-03-28 17:24:02 -0700966 self.pkt = simple_tcp_packet()
967 self.flowMsgs = {}
968
Jeffrey Townsend50c82462012-03-28 18:26:14 -0700969 def _ClearTable(self):
Rich Lane9a003812012-10-04 17:17:59 -0700970 rc = delete_all_flows(self.controller)
Jeffrey Townsend50c82462012-03-28 18:26:14 -0700971 self.assertEqual(rc, 0, "Failed to delete all flows")
Dan Talayco0fc08bd2012-04-09 16:56:18 -0700972 self.assertEqual(do_barrier(self.controller), 0, "Barrier failed")
Jeffrey Townsend50c82462012-03-28 18:26:14 -0700973
974 def runTest(self):
975
976 self._Init()
Rich Lane477f4812012-10-04 22:49:00 -0700977 of_ports = config["port_map"].keys()
Jeffrey Townsend2a300e42012-03-28 17:24:02 -0700978 of_ports.sort()
979
980 # Delete the initial flow table
Jeffrey Townsend50c82462012-03-28 18:26:14 -0700981 self._ClearTable()
Jeffrey Townsend2a300e42012-03-28 17:24:02 -0700982
983 # Run several combinations, each at lower priority settings.
984 # At the end of each call to runPrioFlows(), the table should
985 # be empty. If its not, we'll catch it as the priorities decreases
986 portA = of_ports[0]
987 portB = of_ports[1]
988 portC = of_ports[2]
989
990 # TODO -- these priority numbers should be validated somehow?
991 self.runPrioFlows(portA, portB, portC, 1000, 999)
992 self.runPrioFlows(portB, portC, portA, 998, 997)
993 self.runPrioFlows(portC, portA, portB, 996, 995)
994 self.runPrioFlows(portA, portC, portB, 994, 993)
995
996
Jeffrey Townsend50c82462012-03-28 18:26:14 -0700997
998 def runPrioFlows(self, portA, portB, portC, prioHigher, prioLower,
999 clearTable=False):
Jeffrey Townsend2a300e42012-03-28 17:24:02 -07001000
Jeffrey Townsend50c82462012-03-28 18:26:14 -07001001 if clearTable:
1002 self._ClearTable()
Jeffrey Townsend2a300e42012-03-28 17:24:02 -07001003
1004 # Sanity check flow at lower priority from pA to pB
Rich Lane9a003812012-10-04 17:17:59 -07001005 logging.info("runPrioFlows(pA=%d,pB=%d,pC=%d,ph=%d,pl=%d"
Jeffrey Townsend2a300e42012-03-28 17:24:02 -07001006 % (portA, portB, portC, prioHigher, prioLower))
1007
Jeffrey Townsend2a300e42012-03-28 17:24:02 -07001008 # Sanity check flow at lower priority from pA to pC
1009 self.installFlow(prioLower, portA, portC)
1010 self.verifyFlow(portA, portC)
1011 self.removeFlow(prioLower)
1012
1013 # Install and verify pA->pB @ prioLower
1014 self.installFlow(prioLower, portA, portB)
1015 self.verifyFlow(portA, portB)
1016
1017 # Install and verify pA->pC @ prioHigher, should override pA->pB
1018 self.installFlow(prioHigher, portA, portC)
1019 self.verifyFlow(portA, portC)
1020 # remove pA->pC
1021 self.removeFlow(prioHigher)
Jeffrey Townsend2a300e42012-03-28 17:24:02 -07001022 # Old flow pA -> pB @ prioLower should still be active
1023 self.verifyFlow(portA, portB)
1024 self.removeFlow(prioLower)
1025
1026 # Table should be empty at this point, leave it alone as
1027 # an assumption for future test runs
1028
1029
1030
Ed Swierk99a74de2012-08-22 06:40:54 -07001031 def installFlow(self, prio, inp, egp,
Jeffrey Townsend8364b162012-04-12 13:45:40 -07001032 wildcards=ofp.OFPFW_DL_SRC):
Ed Swierk99a74de2012-08-22 06:40:54 -07001033 wildcards |= required_wildcards(self)
Jeffrey Townsend2a300e42012-03-28 17:24:02 -07001034 request = flow_msg_create(self, self.pkt, ing_port=inp,
Jeffrey Townsend8364b162012-04-12 13:45:40 -07001035 wildcards=wildcards,
Jeffrey Townsend2a300e42012-03-28 17:24:02 -07001036 egr_ports=egp)
1037 request.priority = prio
Rich Lane9a003812012-10-04 17:17:59 -07001038 logging.debug("Install flow with priority " + str(prio))
Jeffrey Townsend50c82462012-03-28 18:26:14 -07001039 flow_msg_install(self, request, clear_table_override=False)
Jeffrey Townsend2a300e42012-03-28 17:24:02 -07001040 self.flowMsgs[prio] = request
1041
1042 def removeFlow(self, prio):
1043 if self.flowMsgs.has_key(prio):
1044 msg = self.flowMsgs[prio]
1045 msg.command = ofp.OFPFC_DELETE_STRICT
1046 # This *must* be set for DELETE
1047 msg.out_port = ofp.OFPP_NONE
Rich Lane9a003812012-10-04 17:17:59 -07001048 logging.debug("Remove flow with priority " + str(prio))
Jeffrey Townsend2a300e42012-03-28 17:24:02 -07001049 self.controller.message_send(msg)
Dan Talayco0fc08bd2012-04-09 16:56:18 -07001050 self.assertEqual(do_barrier(self.controller), 0, "Barrier failed")
Jeffrey Townsend50c82462012-03-28 18:26:14 -07001051 else:
1052 raise Exception("Not initialized")
Jeffrey Townsend2a300e42012-03-28 17:24:02 -07001053
1054
Jeffrey Townsend8364b162012-04-12 13:45:40 -07001055 def verifyFlow(self, inp, egp, pkt=None):
1056 if pkt == None:
1057 pkt = self.pkt
1058
Rich Lane9a003812012-10-04 17:17:59 -07001059 logging.info("Pkt match test: " + str(inp) + " to " + str(egp))
1060 logging.debug("Send packet: " + str(inp) + " to " + str(egp))
Jeffrey Townsend8364b162012-04-12 13:45:40 -07001061 self.dataplane.send(inp, str(pkt))
1062 receive_pkt_verify(self, egp, pkt, inp)
Jeffrey Townsend2a300e42012-03-28 17:24:02 -07001063
1064
1065
Jeffrey Townsend50c82462012-03-28 18:26:14 -07001066class SingleWildcardMatchPriorityInsertModifyDelete(SingleWildcardMatchPriority):
1067
1068 def runTest(self):
1069
1070 self._Init()
1071
Rich Lane477f4812012-10-04 22:49:00 -07001072 of_ports = config["port_map"].keys()
Jeffrey Townsend50c82462012-03-28 18:26:14 -07001073 of_ports.sort()
1074
1075 # Install an entry from 0 -> 1 @ prio 1000
1076 self._ClearTable()
1077 self.installFlow(1000, of_ports[0], of_ports[1])
1078 self.verifyFlow(of_ports[0], of_ports[1])
1079 self.installFlow(1000, of_ports[1], of_ports[0])
1080 self.verifyFlow(of_ports[1], of_ports[0])
1081 self.installFlow(1001, of_ports[0], of_ports[1])
1082 self.verifyFlow(of_ports[0], of_ports[1])
1083 self.installFlow(1001, of_ports[1], of_ports[0])
1084 self.verifyFlow(of_ports[1], of_ports[0])
1085 self.removeFlow(1001)
1086 self.verifyFlow(of_ports[0], of_ports[1])
1087 self.removeFlow(1000)
1088
1089
1090
Jeffrey Townsend8364b162012-04-12 13:45:40 -07001091class WildcardPriority(SingleWildcardMatchPriority):
Ken Chiang38d7a152012-05-24 15:33:50 -07001092 """
1093 1. Add wildcard flow, verify packet received.
1094 2. Add exact match flow with higher priority, verify packet received
1095 on port specified by this flow.
1096 3. Add wildcard flow with even higher priority, verify packet received
1097 on port specified by this flow.
Rich Laneb8392082012-11-21 15:52:54 -08001098 4. Add wildcard flow with lower priority, verify packet received
1099 on port specified by the highest priority flow.
Ken Chiang38d7a152012-05-24 15:33:50 -07001100 """
Jeffrey Townsend8364b162012-04-12 13:45:40 -07001101
1102 def runTest(self):
Jeffrey Townsend50c82462012-03-28 18:26:14 -07001103
Jeffrey Townsend8364b162012-04-12 13:45:40 -07001104 self._Init()
1105
Rich Lane477f4812012-10-04 22:49:00 -07001106 of_ports = config["port_map"].keys()
Jeffrey Townsend8364b162012-04-12 13:45:40 -07001107 of_ports.sort()
1108
1109 self._ClearTable()
Ken Chiang38d7a152012-05-24 15:33:50 -07001110
1111 # Install a flow with wildcards
1112 self.installFlow(999, of_ports[0], of_ports[1],
1113 wildcards=ofp.OFPFW_DL_DST)
Jeffrey Townsend8364b162012-04-12 13:45:40 -07001114 self.verifyFlow(of_ports[0], of_ports[1])
Ken Chiang38d7a152012-05-24 15:33:50 -07001115 # Install a flow with no wildcards for our packet
1116 self.installFlow(1000, of_ports[0], of_ports[2], wildcards=0)
Jeffrey Townsend8364b162012-04-12 13:45:40 -07001117 self.verifyFlow(of_ports[0], of_ports[2])
Ken Chiang38d7a152012-05-24 15:33:50 -07001118 # Install a flow with wildcards for our packet with higher
1119 # priority
1120 self.installFlow(1001, of_ports[0], of_ports[3])
1121 self.verifyFlow(of_ports[0], of_ports[3])
Rich Laneb8392082012-11-21 15:52:54 -08001122 # Install a flow with wildcards for our packet with lower
1123 # priority
1124 self.installFlow(999, of_ports[0], of_ports[1],
1125 wildcards=ofp.OFPFW_DL_SRC)
1126 self.verifyFlow(of_ports[0], of_ports[3])
Jeffrey Townsend8364b162012-04-12 13:45:40 -07001127
1128
Ken Chiang3978f242012-06-13 14:14:09 -07001129class WildcardPriorityWithDelete(SingleWildcardMatchPriority):
Ken Chiang38d7a152012-05-24 15:33:50 -07001130 """
1131 1. Add exact match flow, verify packet received.
1132 2. Add wildcard flow with higher priority, verify packet received on port
1133 specified by this flow.
1134 3. Add exact match flow with even higher priority, verify packet received
1135 on port specified by this flow.
1136 4. Delete lowest priority flow, verify packet received on port specified
1137 by highest priority flow.
1138 5. Delete highest priority flow, verify packet received on port specified
1139 by remaining flow.
1140 """
1141
1142 def runTest(self):
1143
1144 self._Init()
1145
Rich Lane477f4812012-10-04 22:49:00 -07001146 of_ports = config["port_map"].keys()
Ken Chiang38d7a152012-05-24 15:33:50 -07001147 of_ports.sort()
1148
1149 self._ClearTable()
1150
1151 # Install an exact match flow
1152 self.installFlow(250, of_ports[0], of_ports[1], wildcards=0)
1153 self.verifyFlow(of_ports[0], of_ports[1])
1154 # Install a flow with wildcards of higher priority
1155 self.installFlow(1250, of_ports[0], of_ports[2],
1156 wildcards=ofp.OFPFW_DL_DST)
1157 self.verifyFlow(of_ports[0], of_ports[2])
1158 # Install an exact match flow with even higher priority
1159 self.installFlow(2001, of_ports[0], of_ports[3], wildcards=0)
1160 self.verifyFlow(of_ports[0], of_ports[3])
1161 # Delete lowest priority flow
1162 self.removeFlow(250)
1163 self.verifyFlow(of_ports[0], of_ports[3])
1164 # Delete highest priority flow
1165 self.removeFlow(2001)
1166 self.verifyFlow(of_ports[0], of_ports[2])
1167
Jeffrey Townsend8364b162012-04-12 13:45:40 -07001168
Dan Talayco551befa2010-07-15 17:05:32 -07001169class SingleWildcardMatch(BaseMatchCase):
Tatsuya Yabe6a6f38a2010-05-22 23:48:04 -07001170 """
1171 Exercise wildcard matching for all ports
1172
1173 Generate a packet
1174 Generate and install a matching flow with wildcard mask
1175 Add action to forward to a port
1176 Send the packet to the port
1177 Verify the packet is received at all other ports (one port at a time)
Tatsuya Yabe0718ad32010-05-24 15:22:10 -07001178 Verify flow_expiration message is correct when command option is set
Tatsuya Yabe6a6f38a2010-05-22 23:48:04 -07001179 """
Tatsuya Yabe0718ad32010-05-24 15:22:10 -07001180 def runTest(self):
Rich Lane2014f9b2012-10-05 15:29:40 -07001181 vid = test_param_get('vid', default=TEST_VID_DEFAULT)
Dan Talayco551befa2010-07-15 17:05:32 -07001182 for wc in WILDCARD_VALUES:
Ed Swierk99a74de2012-08-22 06:40:54 -07001183 wc |= required_wildcards(self)
Dan Talayco4431d542012-03-21 16:42:16 -07001184 if wc & ofp.OFPFW_DL_VLAN:
Ken Chiang5be06dd2012-04-03 10:03:50 -07001185 # Set nonzero VLAN id to avoid sending priority-tagged packet
1186 dl_vlan = vid
Dan Talayco4431d542012-03-21 16:42:16 -07001187 else:
1188 dl_vlan = -1
Rich Lane477f4812012-10-04 22:49:00 -07001189 flow_match_test(self, config["port_map"], wildcards=wc,
Dan Talayco4431d542012-03-21 16:42:16 -07001190 dl_vlan=dl_vlan, max_test=10)
Tatsuya Yabe4fad7e32010-05-24 15:24:50 -07001191
Dan Talayco551befa2010-07-15 17:05:32 -07001192class SingleWildcardMatchTagged(BaseMatchCase):
1193 """
1194 SingleWildcardMatch with tagged packets
1195 """
1196 def runTest(self):
Rich Lane2014f9b2012-10-05 15:29:40 -07001197 vid = test_param_get('vid', default=TEST_VID_DEFAULT)
Dan Talayco551befa2010-07-15 17:05:32 -07001198 for wc in WILDCARD_VALUES:
Ed Swierk99a74de2012-08-22 06:40:54 -07001199 wc |= required_wildcards(self)
Rich Lane477f4812012-10-04 22:49:00 -07001200 flow_match_test(self, config["port_map"], wildcards=wc, dl_vlan=vid,
Dan Talayco551befa2010-07-15 17:05:32 -07001201 max_test=10)
1202
1203class AllExceptOneWildcardMatch(BaseMatchCase):
Tatsuya Yabe4fad7e32010-05-24 15:24:50 -07001204 """
Dan Talayco80b54ed2010-07-13 09:48:35 -07001205 Match exactly one field
Tatsuya Yabe4fad7e32010-05-24 15:24:50 -07001206
1207 Generate a packet
1208 Generate and install a matching flow with wildcard all except one filed
1209 Add action to forward to a port
1210 Send the packet to the port
1211 Verify the packet is received at all other ports (one port at a time)
1212 Verify flow_expiration message is correct when command option is set
1213 """
1214 def runTest(self):
Rich Lane2014f9b2012-10-05 15:29:40 -07001215 vid = test_param_get('vid', default=TEST_VID_DEFAULT)
Dan Talayco488fbc52012-04-09 16:30:41 -07001216 for all_exp_one_wildcard in NO_WILDCARD_VALUES:
Ed Swierk99a74de2012-08-22 06:40:54 -07001217 all_exp_one_wildcard |= required_wildcards(self)
Dan Talayco4431d542012-03-21 16:42:16 -07001218 if all_exp_one_wildcard & ofp.OFPFW_DL_VLAN:
Ken Chiang5be06dd2012-04-03 10:03:50 -07001219 # Set nonzero VLAN id to avoid sending priority-tagged packet
1220 dl_vlan = vid
Dan Talayco4431d542012-03-21 16:42:16 -07001221 else:
1222 dl_vlan = -1
Rich Lane477f4812012-10-04 22:49:00 -07001223 flow_match_test(self, config["port_map"], wildcards=all_exp_one_wildcard,
Dan Talayco4431d542012-03-21 16:42:16 -07001224 dl_vlan=dl_vlan)
Tatsuya Yabee30ebe22010-05-25 09:30:49 -07001225
Dan Talayco551befa2010-07-15 17:05:32 -07001226class AllExceptOneWildcardMatchTagged(BaseMatchCase):
1227 """
1228 Match one field with tagged packets
1229 """
1230 def runTest(self):
Rich Lane2014f9b2012-10-05 15:29:40 -07001231 vid = test_param_get('vid', default=TEST_VID_DEFAULT)
Dan Talayco488fbc52012-04-09 16:30:41 -07001232 for all_exp_one_wildcard in NO_WILDCARD_VALUES:
Ed Swierk99a74de2012-08-22 06:40:54 -07001233 all_exp_one_wildcard |= required_wildcards(self)
Rich Lane477f4812012-10-04 22:49:00 -07001234 flow_match_test(self, config["port_map"], wildcards=all_exp_one_wildcard,
Dan Talayco21381562010-07-17 00:34:47 -07001235 dl_vlan=vid)
Dan Talayco551befa2010-07-15 17:05:32 -07001236
1237class AllWildcardMatch(BaseMatchCase):
Tatsuya Yabee30ebe22010-05-25 09:30:49 -07001238 """
1239 Create Wildcard-all flow and exercise for all ports
1240
1241 Generate a packet
1242 Generate and install a matching flow with wildcard-all
1243 Add action to forward to a port
1244 Send the packet to the port
1245 Verify the packet is received at all other ports (one port at a time)
1246 Verify flow_expiration message is correct when command option is set
1247 """
1248 def runTest(self):
Rich Lane477f4812012-10-04 22:49:00 -07001249 flow_match_test(self, config["port_map"], wildcards=ofp.OFPFW_ALL)
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -07001250
Dan Talayco551befa2010-07-15 17:05:32 -07001251class AllWildcardMatchTagged(BaseMatchCase):
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -07001252 """
Dan Talayco551befa2010-07-15 17:05:32 -07001253 AllWildcardMatch with tagged packets
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -07001254 """
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -07001255 def runTest(self):
Rich Lane2014f9b2012-10-05 15:29:40 -07001256 vid = test_param_get('vid', default=TEST_VID_DEFAULT)
Rich Lane477f4812012-10-04 22:49:00 -07001257 flow_match_test(self, config["port_map"], wildcards=ofp.OFPFW_ALL,
Dan Talayco21381562010-07-17 00:34:47 -07001258 dl_vlan=vid)
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -07001259
Dan Talaycoba3745c2010-07-21 21:51:08 -07001260
Dan Talayco551befa2010-07-15 17:05:32 -07001261class AddVLANTag(BaseMatchCase):
1262 """
1263 Add a VLAN tag to an untagged packet
1264 """
1265 def runTest(self):
1266 new_vid = 2
Ed Swierkc7193a22012-08-22 06:51:02 -07001267 sup_acts = self.supported_actions
Dan Talayco551befa2010-07-15 17:05:32 -07001268 if not(sup_acts & 1<<ofp.OFPAT_SET_VLAN_VID):
Dan Talaycoba3745c2010-07-21 21:51:08 -07001269 skip_message_emit(self, "Add VLAN tag test")
Dan Talaycof36f1082010-07-13 13:57:17 -07001270 return
Tatsuya Yabef5ffb972010-05-26 15:36:33 -07001271
Dan Talayco551befa2010-07-15 17:05:32 -07001272 len = 100
1273 len_w_vid = 104
1274 pkt = simple_tcp_packet(pktlen=len)
1275 exp_pkt = simple_tcp_packet(pktlen=len_w_vid, dl_vlan_enable=True,
1276 dl_vlan=new_vid)
1277 vid_act = action.action_set_vlan_vid()
1278 vid_act.vlan_vid = new_vid
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -07001279
Rich Lane477f4812012-10-04 22:49:00 -07001280 flow_match_test(self, config["port_map"], pkt=pkt,
Dan Talayco551befa2010-07-15 17:05:32 -07001281 exp_pkt=exp_pkt, action_list=[vid_act])
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -07001282
Rich Laneb90a1c42012-10-05 09:16:05 -07001283class PacketOnly(base_tests.DataPlaneOnly):
Dan Talayco551befa2010-07-15 17:05:32 -07001284 """
1285 Just send a packet thru the switch
1286 """
Rich Laned1d9c282012-10-04 22:07:10 -07001287
1288 priority = -1
1289
Dan Talayco551befa2010-07-15 17:05:32 -07001290 def runTest(self):
1291 pkt = simple_tcp_packet()
Rich Lane477f4812012-10-04 22:49:00 -07001292 of_ports = config["port_map"].keys()
Dan Talayco551befa2010-07-15 17:05:32 -07001293 of_ports.sort()
1294 ing_port = of_ports[0]
Rich Lane9a003812012-10-04 17:17:59 -07001295 logging.info("Sending packet to " + str(ing_port))
1296 logging.debug("Data: " + str(pkt).encode('hex'))
Dan Talayco551befa2010-07-15 17:05:32 -07001297 self.dataplane.send(ing_port, str(pkt))
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -07001298
Rich Laneb90a1c42012-10-05 09:16:05 -07001299class PacketOnlyTagged(base_tests.DataPlaneOnly):
Dan Talayco551befa2010-07-15 17:05:32 -07001300 """
1301 Just send a packet thru the switch
1302 """
Rich Laned1d9c282012-10-04 22:07:10 -07001303
1304 priority = -1
1305
Dan Talayco551befa2010-07-15 17:05:32 -07001306 def runTest(self):
Rich Lane2014f9b2012-10-05 15:29:40 -07001307 vid = test_param_get('vid', default=TEST_VID_DEFAULT)
Dan Talayco551befa2010-07-15 17:05:32 -07001308 pkt = simple_tcp_packet(dl_vlan_enable=True, dl_vlan=vid)
Rich Lane477f4812012-10-04 22:49:00 -07001309 of_ports = config["port_map"].keys()
Dan Talayco551befa2010-07-15 17:05:32 -07001310 of_ports.sort()
1311 ing_port = of_ports[0]
Rich Lane9a003812012-10-04 17:17:59 -07001312 logging.info("Sending packet to " + str(ing_port))
1313 logging.debug("Data: " + str(pkt).encode('hex'))
Dan Talayco551befa2010-07-15 17:05:32 -07001314 self.dataplane.send(ing_port, str(pkt))
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -07001315
Dan Talayco551befa2010-07-15 17:05:32 -07001316class ModifyVID(BaseMatchCase):
Dan Talayco4b2bee62010-07-20 14:10:05 -07001317 """
1318 Modify the VLAN ID in the VLAN tag of a tagged packet
1319 """
Dan Talaycoaf669322012-09-12 22:51:22 -07001320 def setUp(self):
1321 BaseMatchCase.setUp(self)
1322 self.ing_port=False
1323
Dan Talayco551befa2010-07-15 17:05:32 -07001324 def runTest(self):
1325 old_vid = 2
1326 new_vid = 3
Ed Swierkc7193a22012-08-22 06:51:02 -07001327 sup_acts = self.supported_actions
Dan Talayco4b2bee62010-07-20 14:10:05 -07001328 if not (sup_acts & 1 << ofp.OFPAT_SET_VLAN_VID):
Dan Talaycoba3745c2010-07-21 21:51:08 -07001329 skip_message_emit(self, "Modify VLAN tag test")
Dan Talayco551befa2010-07-15 17:05:32 -07001330 return
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -07001331
Dan Talayco551befa2010-07-15 17:05:32 -07001332 pkt = simple_tcp_packet(dl_vlan_enable=True, dl_vlan=old_vid)
1333 exp_pkt = simple_tcp_packet(dl_vlan_enable=True, dl_vlan=new_vid)
1334 vid_act = action.action_set_vlan_vid()
1335 vid_act.vlan_vid = new_vid
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -07001336
Rich Lane477f4812012-10-04 22:49:00 -07001337 flow_match_test(self, config["port_map"], pkt=pkt, exp_pkt=exp_pkt,
Dan Talaycoaf669322012-09-12 22:51:22 -07001338 action_list=[vid_act], ing_port=self.ing_port)
1339
1340class ModifyVIDToIngress(ModifyVID):
1341 """
1342 Modify the VLAN ID in the VLAN tag of a tagged packet and send to
1343 ingress port
1344 """
1345 def setUp(self):
1346 BaseMatchCase.setUp(self)
1347 self.ing_port=True
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -07001348
Ken Chiange9a211d2012-04-20 14:52:11 -07001349class ModifyVIDWithTagMatchWildcarded(BaseMatchCase):
1350 """
1351 With vlan ID and priority wildcarded, perform SET_VLAN_VID action.
1352 The same flow should match on both untagged and tagged packets.
1353 """
1354 def runTest(self):
1355 old_vid = 2
1356 new_vid = 3
Ed Swierkc7193a22012-08-22 06:51:02 -07001357 sup_acts = self.supported_actions
Ken Chiange9a211d2012-04-20 14:52:11 -07001358 if not (sup_acts & 1 << ofp.OFPAT_SET_VLAN_VID):
1359 skip_message_emit(self, "ModifyVIDWithTagWildcarded test")
1360 return
1361
Rich Lane477f4812012-10-04 22:49:00 -07001362 of_ports = config["port_map"].keys()
Ken Chiange9a211d2012-04-20 14:52:11 -07001363 self.assertTrue(len(of_ports) > 1, "Not enough ports for test")
1364 ing_port = of_ports[0]
1365 egr_ports = of_ports[1]
1366
Rich Lane9a003812012-10-04 17:17:59 -07001367 rv = delete_all_flows(self.controller)
Ken Chiange9a211d2012-04-20 14:52:11 -07001368 self.assertEqual(rv, 0, "Failed to delete all flows")
1369
1370 len_untagged = 100
1371 len_w_vid = 104
1372 untagged_pkt = simple_tcp_packet(pktlen=len_untagged)
1373 tagged_pkt = simple_tcp_packet(pktlen=len_w_vid,
1374 dl_vlan_enable=True, dl_vlan=old_vid)
1375 exp_pkt = simple_tcp_packet(pktlen=len_w_vid, dl_vlan_enable=True,
1376 dl_vlan=new_vid)
Ed Swierk99a74de2012-08-22 06:40:54 -07001377 wildcards = (required_wildcards(self) | ofp.OFPFW_DL_VLAN |
1378 ofp.OFPFW_DL_VLAN_PCP)
Ken Chiange9a211d2012-04-20 14:52:11 -07001379 vid_act = action.action_set_vlan_vid()
1380 vid_act.vlan_vid = new_vid
1381 request = flow_msg_create(self, untagged_pkt, ing_port=ing_port,
1382 wildcards=wildcards, egr_ports=egr_ports,
1383 action_list=[vid_act])
1384 flow_msg_install(self, request)
1385
Rich Lane9a003812012-10-04 17:17:59 -07001386 logging.debug("Send untagged packet: " + str(ing_port) + " to " +
Ken Chiange9a211d2012-04-20 14:52:11 -07001387 str(egr_ports))
1388 self.dataplane.send(ing_port, str(untagged_pkt))
1389 receive_pkt_verify(self, egr_ports, exp_pkt, ing_port)
1390
Rich Lane9a003812012-10-04 17:17:59 -07001391 logging.debug("Send tagged packet: " + str(ing_port) + " to " +
Ken Chiange9a211d2012-04-20 14:52:11 -07001392 str(egr_ports))
1393 self.dataplane.send(ing_port, str(tagged_pkt))
1394 receive_pkt_verify(self, egr_ports, exp_pkt, ing_port)
1395
Howard Pershc1199d52012-04-11 14:21:32 -07001396class ModifyVlanPcp(BaseMatchCase):
1397 """
1398 Modify the priority field of the VLAN tag of a tagged packet
1399 """
1400 def runTest(self):
1401 vid = 123
1402 old_vlan_pcp = 2
1403 new_vlan_pcp = 3
Ed Swierkc7193a22012-08-22 06:51:02 -07001404 sup_acts = self.supported_actions
Ed Swierk8c3af7f2012-04-24 14:19:17 -07001405 if not (sup_acts & 1 << ofp.OFPAT_SET_VLAN_PCP):
1406 skip_message_emit(self, "Modify VLAN priority test")
Howard Pershc1199d52012-04-11 14:21:32 -07001407 return
1408
1409 pkt = simple_tcp_packet(dl_vlan_enable=True, dl_vlan=vid, dl_vlan_pcp=old_vlan_pcp)
1410 exp_pkt = simple_tcp_packet(dl_vlan_enable=True, dl_vlan=vid, dl_vlan_pcp=new_vlan_pcp)
1411 vid_act = action.action_set_vlan_pcp()
1412 vid_act.vlan_pcp = new_vlan_pcp
1413
Rich Lane477f4812012-10-04 22:49:00 -07001414 flow_match_test(self, config["port_map"], pkt=pkt, exp_pkt=exp_pkt,
Howard Pershc1199d52012-04-11 14:21:32 -07001415 action_list=[vid_act])
1416
Dan Talayco551befa2010-07-15 17:05:32 -07001417class StripVLANTag(BaseMatchCase):
Dan Talayco4b2bee62010-07-20 14:10:05 -07001418 """
1419 Strip the VLAN tag from a tagged packet
1420 """
Dan Talayco551befa2010-07-15 17:05:32 -07001421 def runTest(self):
1422 old_vid = 2
Ed Swierkc7193a22012-08-22 06:51:02 -07001423 sup_acts = self.supported_actions
Dan Talayco4b2bee62010-07-20 14:10:05 -07001424 if not (sup_acts & 1 << ofp.OFPAT_STRIP_VLAN):
Dan Talaycoba3745c2010-07-21 21:51:08 -07001425 skip_message_emit(self, "Strip VLAN tag test")
Dan Talayco551befa2010-07-15 17:05:32 -07001426 return
Dan Talaycof36f1082010-07-13 13:57:17 -07001427
Dan Talayco551befa2010-07-15 17:05:32 -07001428 len_w_vid = 104
1429 len = 100
1430 pkt = simple_tcp_packet(pktlen=len_w_vid, dl_vlan_enable=True,
1431 dl_vlan=old_vid)
1432 exp_pkt = simple_tcp_packet(pktlen=len)
1433 vid_act = action.action_strip_vlan()
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -07001434
Rich Lane477f4812012-10-04 22:49:00 -07001435 flow_match_test(self, config["port_map"], pkt=pkt, exp_pkt=exp_pkt,
Dan Talayco551befa2010-07-15 17:05:32 -07001436 action_list=[vid_act])
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -07001437
Ken Chiange9a211d2012-04-20 14:52:11 -07001438class StripVLANTagWithTagMatchWildcarded(BaseMatchCase):
1439 """
1440 Strip the VLAN tag from a tagged packet.
1441 Differs from StripVLANTag in that VID and PCP are both wildcarded.
1442 """
1443 def runTest(self):
1444 old_vid = 2
Ed Swierkc7193a22012-08-22 06:51:02 -07001445 sup_acts = self.supported_actions
Ken Chiange9a211d2012-04-20 14:52:11 -07001446 if not (sup_acts & 1 << ofp.OFPAT_STRIP_VLAN):
1447 skip_message_emit(self, "StripVLANTagWithTagWildcarded test")
1448 return
1449
1450 len_w_vid = 104
1451 len_untagged = 100
1452 pkt = simple_tcp_packet(pktlen=len_w_vid, dl_vlan_enable=True,
1453 dl_vlan=old_vid)
1454 exp_pkt = simple_tcp_packet(pktlen=len_untagged)
Ed Swierk99a74de2012-08-22 06:40:54 -07001455 wildcards = (required_wildcards(self) | ofp.OFPFW_DL_VLAN |
1456 ofp.OFPFW_DL_VLAN_PCP)
Ken Chiange9a211d2012-04-20 14:52:11 -07001457 vid_act = action.action_strip_vlan()
1458
Rich Lane477f4812012-10-04 22:49:00 -07001459 flow_match_test(self, config["port_map"],
Ed Swierk99a74de2012-08-22 06:40:54 -07001460 wildcards=wildcards,
Ken Chiange9a211d2012-04-20 14:52:11 -07001461 pkt=pkt, exp_pkt=exp_pkt,
1462 action_list=[vid_act])
1463
Dan Talayco4b2bee62010-07-20 14:10:05 -07001464def init_pkt_args():
1465 """
1466 Pass back a dictionary with default packet arguments
1467 """
1468 args = {}
1469 args["dl_src"] = '00:23:45:67:89:AB'
1470
1471 dl_vlan_enable=False
1472 dl_vlan=-1
Rich Lane477f4812012-10-04 22:49:00 -07001473 if config["test-params"]["vid"]:
Dan Talayco4b2bee62010-07-20 14:10:05 -07001474 dl_vlan_enable=True
Rich Lane477f4812012-10-04 22:49:00 -07001475 dl_vlan = config["test-params"]["vid"]
Dan Talayco4b2bee62010-07-20 14:10:05 -07001476
1477# Unpack operator is ** on a dictionary
1478
1479 return args
1480
Dan Talayco551befa2010-07-15 17:05:32 -07001481class ModifyL2Src(BaseMatchCase):
Dan Talayco4b2bee62010-07-20 14:10:05 -07001482 """
1483 Modify the source MAC address (TP1)
1484 """
Dan Talayco551befa2010-07-15 17:05:32 -07001485 def runTest(self):
Ed Swierkc7193a22012-08-22 06:51:02 -07001486 sup_acts = self.supported_actions
Dan Talayco4b2bee62010-07-20 14:10:05 -07001487 if not (sup_acts & 1 << ofp.OFPAT_SET_DL_SRC):
Dan Talaycoba3745c2010-07-21 21:51:08 -07001488 skip_message_emit(self, "ModifyL2Src test")
Dan Talayco4b2bee62010-07-20 14:10:05 -07001489 return
1490
1491 (pkt, exp_pkt, acts) = pkt_action_setup(self, mod_fields=['dl_src'],
1492 check_test_params=True)
Rich Lane477f4812012-10-04 22:49:00 -07001493 flow_match_test(self, config["port_map"], pkt=pkt, exp_pkt=exp_pkt,
Dan Talayco4b2bee62010-07-20 14:10:05 -07001494 action_list=acts, max_test=2)
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -07001495
Dan Talayco551befa2010-07-15 17:05:32 -07001496class ModifyL2Dst(BaseMatchCase):
Dan Talayco4b2bee62010-07-20 14:10:05 -07001497 """
1498 Modify the dest MAC address (TP1)
1499 """
Dan Talayco551befa2010-07-15 17:05:32 -07001500 def runTest(self):
Ed Swierkc7193a22012-08-22 06:51:02 -07001501 sup_acts = self.supported_actions
Dan Talayco4b2bee62010-07-20 14:10:05 -07001502 if not (sup_acts & 1 << ofp.OFPAT_SET_DL_DST):
Dan Talaycoba3745c2010-07-21 21:51:08 -07001503 skip_message_emit(self, "ModifyL2dst test")
Dan Talayco4b2bee62010-07-20 14:10:05 -07001504 return
1505
1506 (pkt, exp_pkt, acts) = pkt_action_setup(self, mod_fields=['dl_dst'],
1507 check_test_params=True)
Rich Lane477f4812012-10-04 22:49:00 -07001508 flow_match_test(self, config["port_map"], pkt=pkt, exp_pkt=exp_pkt,
Dan Talayco4b2bee62010-07-20 14:10:05 -07001509 action_list=acts, max_test=2)
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -07001510
Dan Talayco551befa2010-07-15 17:05:32 -07001511class ModifyL3Src(BaseMatchCase):
Dan Talayco4b2bee62010-07-20 14:10:05 -07001512 """
1513 Modify the source IP address of an IP packet (TP1)
1514 """
Dan Talayco551befa2010-07-15 17:05:32 -07001515 def runTest(self):
Ed Swierkc7193a22012-08-22 06:51:02 -07001516 sup_acts = self.supported_actions
Dan Talayco4b2bee62010-07-20 14:10:05 -07001517 if not (sup_acts & 1 << ofp.OFPAT_SET_NW_SRC):
Dan Talaycoba3745c2010-07-21 21:51:08 -07001518 skip_message_emit(self, "ModifyL3Src test")
Dan Talayco4b2bee62010-07-20 14:10:05 -07001519 return
1520
1521 (pkt, exp_pkt, acts) = pkt_action_setup(self, mod_fields=['ip_src'],
1522 check_test_params=True)
Rich Lane477f4812012-10-04 22:49:00 -07001523 flow_match_test(self, config["port_map"], pkt=pkt, exp_pkt=exp_pkt,
Dan Talayco4b2bee62010-07-20 14:10:05 -07001524 action_list=acts, max_test=2)
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -07001525
Dan Talayco551befa2010-07-15 17:05:32 -07001526class ModifyL3Dst(BaseMatchCase):
Dan Talayco4b2bee62010-07-20 14:10:05 -07001527 """
1528 Modify the dest IP address of an IP packet (TP1)
1529 """
Dan Talayco551befa2010-07-15 17:05:32 -07001530 def runTest(self):
Ed Swierkc7193a22012-08-22 06:51:02 -07001531 sup_acts = self.supported_actions
Dan Talayco4b2bee62010-07-20 14:10:05 -07001532 if not (sup_acts & 1 << ofp.OFPAT_SET_NW_DST):
Dan Talaycoba3745c2010-07-21 21:51:08 -07001533 skip_message_emit(self, "ModifyL3Dst test")
Dan Talayco4b2bee62010-07-20 14:10:05 -07001534 return
1535
1536 (pkt, exp_pkt, acts) = pkt_action_setup(self, mod_fields=['ip_dst'],
1537 check_test_params=True)
Rich Lane477f4812012-10-04 22:49:00 -07001538 flow_match_test(self, config["port_map"], pkt=pkt, exp_pkt=exp_pkt,
Dan Talayco4b2bee62010-07-20 14:10:05 -07001539 action_list=acts, max_test=2)
Dan Talayco551befa2010-07-15 17:05:32 -07001540
1541class ModifyL4Src(BaseMatchCase):
Dan Talayco4b2bee62010-07-20 14:10:05 -07001542 """
1543 Modify the source TCP port of a TCP packet (TP1)
1544 """
Dan Talayco551befa2010-07-15 17:05:32 -07001545 def runTest(self):
Ed Swierkc7193a22012-08-22 06:51:02 -07001546 sup_acts = self.supported_actions
Dan Talayco4b2bee62010-07-20 14:10:05 -07001547 if not (sup_acts & 1 << ofp.OFPAT_SET_TP_SRC):
Dan Talaycoba3745c2010-07-21 21:51:08 -07001548 skip_message_emit(self, "ModifyL4Src test")
Dan Talayco4b2bee62010-07-20 14:10:05 -07001549 return
1550
1551 (pkt, exp_pkt, acts) = pkt_action_setup(self, mod_fields=['tcp_sport'],
1552 check_test_params=True)
Rich Lane477f4812012-10-04 22:49:00 -07001553 flow_match_test(self, config["port_map"], pkt=pkt, exp_pkt=exp_pkt,
Dan Talayco4b2bee62010-07-20 14:10:05 -07001554 action_list=acts, max_test=2)
Dan Talayco551befa2010-07-15 17:05:32 -07001555
Rich Lane01c2b862012-10-26 16:26:25 -07001556class ModifyL4SrcUdp(BaseMatchCase):
1557 """
1558 Modify the source UDP port of a UDP packet
1559 """
1560 def runTest(self):
1561 sup_acts = self.supported_actions
1562 if not (sup_acts & 1 << ofp.OFPAT_SET_TP_DST):
1563 skip_message_emit(self, "ModifyL4SrcUdp test")
1564 return
1565
1566 (pkt, exp_pkt, acts) = pkt_action_setup(self, mod_fields=['udp_sport'],
1567 check_test_params=True, tp="udp")
1568 flow_match_test(self, config["port_map"], pkt=pkt, exp_pkt=exp_pkt,
1569 action_list=acts, max_test=2)
1570
Dan Talayco551befa2010-07-15 17:05:32 -07001571class ModifyL4Dst(BaseMatchCase):
Dan Talayco4b2bee62010-07-20 14:10:05 -07001572 """
1573 Modify the dest TCP port of a TCP packet (TP1)
1574 """
Dan Talayco551befa2010-07-15 17:05:32 -07001575 def runTest(self):
Ed Swierkc7193a22012-08-22 06:51:02 -07001576 sup_acts = self.supported_actions
Dan Talayco4b2bee62010-07-20 14:10:05 -07001577 if not (sup_acts & 1 << ofp.OFPAT_SET_TP_DST):
Dan Talaycoba3745c2010-07-21 21:51:08 -07001578 skip_message_emit(self, "ModifyL4Dst test")
Dan Talayco4b2bee62010-07-20 14:10:05 -07001579 return
1580
1581 (pkt, exp_pkt, acts) = pkt_action_setup(self, mod_fields=['tcp_dport'],
1582 check_test_params=True)
Rich Lane477f4812012-10-04 22:49:00 -07001583 flow_match_test(self, config["port_map"], pkt=pkt, exp_pkt=exp_pkt,
Dan Talayco4b2bee62010-07-20 14:10:05 -07001584 action_list=acts, max_test=2)
Dan Talayco551befa2010-07-15 17:05:32 -07001585
Rich Lane01c2b862012-10-26 16:26:25 -07001586class ModifyL4DstUdp(BaseMatchCase):
1587 """
1588 Modify the dest UDP port of a UDP packet
1589 """
1590 def runTest(self):
1591 sup_acts = self.supported_actions
1592 if not (sup_acts & 1 << ofp.OFPAT_SET_TP_DST):
1593 skip_message_emit(self, "ModifyL4DstUdp test")
1594 return
1595
1596 (pkt, exp_pkt, acts) = pkt_action_setup(self, mod_fields=['udp_dport'],
1597 check_test_params=True, tp="udp")
1598 flow_match_test(self, config["port_map"], pkt=pkt, exp_pkt=exp_pkt,
1599 action_list=acts, max_test=2)
1600
Dan Talayco551befa2010-07-15 17:05:32 -07001601class ModifyTOS(BaseMatchCase):
Dan Talayco4b2bee62010-07-20 14:10:05 -07001602 """
1603 Modify the IP type of service of an IP packet (TP1)
1604 """
Dan Talayco551befa2010-07-15 17:05:32 -07001605 def runTest(self):
Ed Swierkc7193a22012-08-22 06:51:02 -07001606 sup_acts = self.supported_actions
Dan Talayco4b2bee62010-07-20 14:10:05 -07001607 if not (sup_acts & 1 << ofp.OFPAT_SET_NW_TOS):
Dan Talaycoba3745c2010-07-21 21:51:08 -07001608 skip_message_emit(self, "ModifyTOS test")
Dan Talayco4b2bee62010-07-20 14:10:05 -07001609 return
Dan Talayco551befa2010-07-15 17:05:32 -07001610
Dan Talayco4b2bee62010-07-20 14:10:05 -07001611 (pkt, exp_pkt, acts) = pkt_action_setup(self, mod_fields=['ip_tos'],
1612 check_test_params=True)
Rich Lane477f4812012-10-04 22:49:00 -07001613 flow_match_test(self, config["port_map"], pkt=pkt, exp_pkt=exp_pkt,
Dan Talaycocfa172f2012-03-23 12:03:00 -07001614 action_list=acts, max_test=2, egr_count=-1)
Dan Talayco551befa2010-07-15 17:05:32 -07001615
Dan Talaycof6e76c02012-03-23 10:56:12 -07001616class ModifyL2DstMC(BaseMatchCase):
1617 """
1618 Modify the L2 dest and send to 2 ports
Dan Talaycof6e76c02012-03-23 10:56:12 -07001619 """
1620 def runTest(self):
Ed Swierkc7193a22012-08-22 06:51:02 -07001621 sup_acts = self.supported_actions
Dan Talaycof6e76c02012-03-23 10:56:12 -07001622 if not (sup_acts & 1 << ofp.OFPAT_SET_DL_DST):
Dan Talaycocfa172f2012-03-23 12:03:00 -07001623 skip_message_emit(self, "ModifyL2dstMC test")
Dan Talaycof6e76c02012-03-23 10:56:12 -07001624 return
1625
Dan Talaycof6e76c02012-03-23 10:56:12 -07001626 (pkt, exp_pkt, acts) = pkt_action_setup(self, mod_fields=['dl_dst'],
1627 check_test_params=True)
Rich Lane477f4812012-10-04 22:49:00 -07001628 flow_match_test(self, config["port_map"], pkt=pkt, exp_pkt=exp_pkt,
Dan Talaycocfa172f2012-03-23 12:03:00 -07001629 action_list=acts, max_test=2, egr_count=-1)
Dan Talaycof6e76c02012-03-23 10:56:12 -07001630
Dan Talaycoc948d0b2012-03-23 12:17:54 -07001631class ModifyL2DstIngress(BaseMatchCase):
1632 """
1633 Modify the L2 dest and send to the ingress port
1634 """
1635 def runTest(self):
Ed Swierkc7193a22012-08-22 06:51:02 -07001636 sup_acts = self.supported_actions
Dan Talaycoc948d0b2012-03-23 12:17:54 -07001637 if not (sup_acts & 1 << ofp.OFPAT_SET_DL_DST):
Dan Talaycoabbfdbb2012-04-05 10:29:26 -07001638 skip_message_emit(self, "ModifyL2dstIngress test")
Dan Talaycoc948d0b2012-03-23 12:17:54 -07001639 return
1640
1641 (pkt, exp_pkt, acts) = pkt_action_setup(self, mod_fields=['dl_dst'],
1642 check_test_params=True)
Rich Lane477f4812012-10-04 22:49:00 -07001643 flow_match_test(self, config["port_map"], pkt=pkt, exp_pkt=exp_pkt,
Dan Talaycoc948d0b2012-03-23 12:17:54 -07001644 action_list=acts, max_test=2, egr_count=0,
1645 ing_port=True)
1646
Dan Talaycod8ae7582012-03-23 12:24:56 -07001647class ModifyL2DstIngressMC(BaseMatchCase):
1648 """
1649 Modify the L2 dest and send to the ingress port
1650 """
1651 def runTest(self):
Ed Swierkc7193a22012-08-22 06:51:02 -07001652 sup_acts = self.supported_actions
Dan Talaycod8ae7582012-03-23 12:24:56 -07001653 if not (sup_acts & 1 << ofp.OFPAT_SET_DL_DST):
1654 skip_message_emit(self, "ModifyL2dstMC test")
1655 return
1656
1657 (pkt, exp_pkt, acts) = pkt_action_setup(self, mod_fields=['dl_dst'],
1658 check_test_params=True)
Rich Lane477f4812012-10-04 22:49:00 -07001659 flow_match_test(self, config["port_map"], pkt=pkt, exp_pkt=exp_pkt,
Dan Talaycod8ae7582012-03-23 12:24:56 -07001660 action_list=acts, max_test=2, egr_count=-1,
1661 ing_port=True)
1662
Dan Talaycof6e76c02012-03-23 10:56:12 -07001663class ModifyL2SrcMC(BaseMatchCase):
1664 """
1665 Modify the source MAC address (TP1) and send to multiple
Dan Talaycof6e76c02012-03-23 10:56:12 -07001666 """
1667 def runTest(self):
Ed Swierkc7193a22012-08-22 06:51:02 -07001668 sup_acts = self.supported_actions
Dan Talaycof6e76c02012-03-23 10:56:12 -07001669 if not (sup_acts & 1 << ofp.OFPAT_SET_DL_SRC):
Dan Talaycocfa172f2012-03-23 12:03:00 -07001670 skip_message_emit(self, "ModifyL2SrcMC test")
Dan Talaycof6e76c02012-03-23 10:56:12 -07001671 return
1672
Dan Talaycof6e76c02012-03-23 10:56:12 -07001673 (pkt, exp_pkt, acts) = pkt_action_setup(self, mod_fields=['dl_src'],
1674 check_test_params=True)
Rich Lane477f4812012-10-04 22:49:00 -07001675 flow_match_test(self, config["port_map"], pkt=pkt, exp_pkt=exp_pkt,
Dan Talaycocfa172f2012-03-23 12:03:00 -07001676 action_list=acts, max_test=2, egr_count=-1)
Dan Talaycof6e76c02012-03-23 10:56:12 -07001677
1678class ModifyL2SrcDstMC(BaseMatchCase):
1679 """
1680 Modify the L2 source and dest and send to 2 ports
Dan Talaycof6e76c02012-03-23 10:56:12 -07001681 """
1682 def runTest(self):
Ed Swierkc7193a22012-08-22 06:51:02 -07001683 sup_acts = self.supported_actions
Dan Talaycocfa172f2012-03-23 12:03:00 -07001684 if (not (sup_acts & 1 << ofp.OFPAT_SET_DL_DST) or
1685 not (sup_acts & 1 << ofp.OFPAT_SET_DL_SRC)):
1686 skip_message_emit(self, "ModifyL2SrcDstMC test")
Dan Talaycof6e76c02012-03-23 10:56:12 -07001687 return
1688
Dan Talaycof6e76c02012-03-23 10:56:12 -07001689 mod_fields = ['dl_dst', 'dl_src']
1690 (pkt, exp_pkt, acts) = pkt_action_setup(self, mod_fields=mod_fields,
1691 check_test_params=True)
Rich Lane477f4812012-10-04 22:49:00 -07001692 flow_match_test(self, config["port_map"], pkt=pkt, exp_pkt=exp_pkt,
Dan Talaycocfa172f2012-03-23 12:03:00 -07001693 action_list=acts, max_test=2, egr_count=-1)
1694
1695class ModifyL2DstVIDMC(BaseMatchCase):
1696 """
1697 Modify the L2 dest and send to 2 ports
1698 """
1699 def runTest(self):
Ed Swierkc7193a22012-08-22 06:51:02 -07001700 sup_acts = self.supported_actions
Dan Talaycocfa172f2012-03-23 12:03:00 -07001701 if (not (sup_acts & 1 << ofp.OFPAT_SET_DL_DST) or
1702 not (sup_acts & 1 << ofp.OFPAT_SET_VLAN_VID)):
1703 skip_message_emit(self, "ModifyL2DstVIDMC test")
1704 return
1705
1706 mod_fields = ['dl_dst', 'dl_vlan']
1707 (pkt, exp_pkt, acts) = pkt_action_setup(self,
1708 start_field_vals={'dl_vlan_enable':True}, mod_fields=mod_fields,
1709 check_test_params=True)
Rich Lane477f4812012-10-04 22:49:00 -07001710 flow_match_test(self, config["port_map"], pkt=pkt, exp_pkt=exp_pkt,
Dan Talaycocfa172f2012-03-23 12:03:00 -07001711 action_list=acts, max_test=2, egr_count=-1)
Dan Talaycof6e76c02012-03-23 10:56:12 -07001712
Rich Lane22e74c12012-11-12 15:06:06 -08001713class ModifyAll(BaseMatchCase):
1714 """
1715 Modify all supported fields and output to a port
1716 """
1717 def runTest(self):
1718 sup_acts = self.supported_actions
1719
1720 sup_map = {
1721 "dl_dst" : ofp.OFPAT_SET_DL_DST,
1722 "dl_src" : ofp.OFPAT_SET_DL_SRC,
1723 "dl_vlan_enable" : ofp.OFPAT_SET_VLAN_VID,
1724 "dl_vlan" : ofp.OFPAT_SET_VLAN_VID,
1725 "dl_vlan_pcp" : ofp.OFPAT_SET_VLAN_PCP,
1726 "ip_src" : ofp.OFPAT_SET_NW_SRC,
1727 "ip_dst" : ofp.OFPAT_SET_NW_DST,
1728 "ip_tos" : ofp.OFPAT_SET_NW_TOS,
1729 "tcp_sport" : ofp.OFPAT_SET_TP_SRC,
1730 "tcp_dport" : ofp.OFPAT_SET_TP_DST,
1731 }
1732
1733 mod_fields = [field for (field, bit) in sup_map.items() if (sup_acts & 1 << bit)]
1734 random.shuffle(mod_fields)
1735 start_field_vals = { "dl_vlan_enable" : True }
1736 mod_field_vals = { "dl_vlan_enable" : True }
1737 logging.info("modifying fields: %s" % repr(mod_fields))
1738
1739 (pkt, exp_pkt, acts) = pkt_action_setup(self,
1740 mod_fields=mod_fields,
1741 start_field_vals=start_field_vals,
1742 mod_field_vals=mod_field_vals,
1743 check_test_params=True)
1744 flow_match_test(self, config["port_map"], pkt=pkt, exp_pkt=exp_pkt,
1745 action_list=acts, max_test=2)
1746
Dan Talaycofa6454f2012-04-05 10:04:13 -07001747class FlowToggle(BaseMatchCase):
1748 """
1749 Add flows to the table and modify them repeatedly
Dan Talaycof7c41312012-07-23 12:53:19 -07001750
1751 This is done by using only "add" flow messages. Since the check overlap
1752 flag is not set, the switch is supposed to modify the existing flow if
1753 the match already exists.
1754
1755 Would probably be better to exercise more of the flow modify commands
1756 (add, modify, delete +/- strict).
Dan Talaycofa6454f2012-04-05 10:04:13 -07001757 """
1758 def runTest(self):
Rich Lane2014f9b2012-10-05 15:29:40 -07001759 flow_count = test_param_get('ft_flow_count', default=20)
1760 iter_count = test_param_get('ft_iter_count', default=10)
Dan Talaycofa6454f2012-04-05 10:04:13 -07001761
Rich Lane9a003812012-10-04 17:17:59 -07001762 logging.info("Running flow toggle with %d flows, %d iterations" %
Dan Talaycofa6454f2012-04-05 10:04:13 -07001763 (flow_count, iter_count))
1764 acts = []
1765 acts.append(action.action_output())
1766 acts.append(action.action_output())
1767
Rich Lane477f4812012-10-04 22:49:00 -07001768 of_ports = config["port_map"].keys()
Dan Talaycofa6454f2012-04-05 10:04:13 -07001769 if len(of_ports) < 3:
1770 self.assertTrue(False, "Too few ports for test")
1771
1772 for idx in range(2):
1773 acts[idx].port = of_ports[idx]
1774
1775 flows = []
1776 flows.append([])
1777 flows.append([])
1778
Ed Swierk99a74de2012-08-22 06:40:54 -07001779 wildcards = (required_wildcards(self) | ofp.OFPFW_DL_SRC |
1780 ofp.OFPFW_DL_DST)
Dan Talaycofa6454f2012-04-05 10:04:13 -07001781 # Create up the flows in an array
1782 for toggle in range(2):
1783 for f_idx in range(flow_count):
1784 pkt = simple_tcp_packet(tcp_sport=f_idx)
1785 msg = message.flow_mod()
Ed Swierk99a74de2012-08-22 06:40:54 -07001786 match = packet_to_flow_match(self, pkt)
Shudong Zhou031373c2012-07-19 17:37:42 -07001787 match.in_port = of_ports[2]
Dan Talayco50be7672012-04-05 11:38:08 -07001788 match.wildcards = wildcards
Dan Talaycofa6454f2012-04-05 10:04:13 -07001789 msg.match = match
1790 msg.buffer_id = 0xffffffff
Dan Talaycof7c41312012-07-23 12:53:19 -07001791 msg.command = ofp.OFPFC_ADD
Dan Talaycofa6454f2012-04-05 10:04:13 -07001792 msg.actions.add(acts[toggle])
1793 flows[toggle].append(msg)
Dan Talayco50be7672012-04-05 11:38:08 -07001794
1795 # Show two sample flows
Rich Lane9a003812012-10-04 17:17:59 -07001796 logging.debug(flows[0][0].show())
1797 logging.debug(flows[1][0].show())
Dan Talayco50be7672012-04-05 11:38:08 -07001798
Dan Talaycofa6454f2012-04-05 10:04:13 -07001799 # Install the first set of flows
1800 for f_idx in range(flow_count):
1801 rv = self.controller.message_send(flows[0][f_idx])
1802 self.assertTrue(rv != -1, "Error installing flow %d" % f_idx)
Dan Talayco0fc08bd2012-04-09 16:56:18 -07001803 self.assertEqual(do_barrier(self.controller), 0, "Barrier failed")
Dan Talaycofa6454f2012-04-05 10:04:13 -07001804
Rich Lane9a003812012-10-04 17:17:59 -07001805 logging.info("Installed %d flows" % flow_count)
Dan Talaycofa6454f2012-04-05 10:04:13 -07001806
1807 # Repeatedly modify all the flows back and forth
1808 updates = 0
1809 # Report status about 5 times
1810 mod_val = (iter_count / 4) + 1
Dan Talaycoabbfdbb2012-04-05 10:29:26 -07001811 start = time.time()
1812 for iter_idx in range(iter_count):
1813 if not iter_idx % mod_val:
Rich Lane9a003812012-10-04 17:17:59 -07001814 logging.info("Flow Toggle: iter %d of %d. " %
Dan Talaycoabbfdbb2012-04-05 10:29:26 -07001815 (iter_idx, iter_count) +
1816 "%d updates in %d secs" %
1817 (updates, time.time() - start))
Dan Talaycofa6454f2012-04-05 10:04:13 -07001818 for toggle in range(2):
1819 t_idx = 1 - toggle
1820 for f_idx in range(flow_count):
1821 rv = self.controller.message_send(flows[t_idx][f_idx])
1822 updates += 1
1823 self.assertTrue(rv != -1, "Error modifying flow %d" %
1824 f_idx)
Dan Talayco0fc08bd2012-04-09 16:56:18 -07001825 self.assertEqual(do_barrier(self.controller), 0,
1826 "Barrier failed")
Dan Talaycoabbfdbb2012-04-05 10:29:26 -07001827
1828 end = time.time()
1829 divisor = end - start or (end - start + 1)
Rich Lane9a003812012-10-04 17:17:59 -07001830 logging.info("Flow toggle: %d iterations" % iter_count)
1831 logging.info(" %d flow mods in %d secs, %d mods/sec" %
Dan Talaycoabbfdbb2012-04-05 10:29:26 -07001832 (updates, end - start, updates/divisor))
Dan Talaycofa6454f2012-04-05 10:04:13 -07001833
1834
Dan Talayco8a64e332012-03-28 14:53:20 -07001835# You can pick and choose these by commenting tests in or out
1836iter_classes = [
1837 basic.PacketIn,
1838 basic.PacketOut,
1839 DirectPacket,
Dan Talaycofa6454f2012-04-05 10:04:13 -07001840 FlowToggle,
Dan Talayco8a64e332012-03-28 14:53:20 -07001841 DirectTwoPorts,
Dan Talaycofa6454f2012-04-05 10:04:13 -07001842 DirectMCNonIngress,
Dan Talayco8a64e332012-03-28 14:53:20 -07001843 AllWildcardMatch,
1844 AllWildcardMatchTagged,
1845 SingleWildcardMatch,
1846 SingleWildcardMatchTagged,
1847 ExactMatch,
1848 ExactMatchTagged,
1849 SingleWildcardMatch,
1850 ModifyL2Src,
1851 ModifyL2Dst,
1852 ModifyL2SrcMC,
1853 ModifyL2DstMC,
1854 ModifyL2SrcDstMC
1855 ]
1856
1857class IterCases(BaseMatchCase):
Dan Talaycofa6454f2012-04-05 10:04:13 -07001858 """
1859 Iterate over a bunch of test cases
1860
1861 The cases come from the list above
1862 """
1863
Rich Laned1d9c282012-10-04 22:07:10 -07001864 priority = -1
1865
Dan Talayco8a64e332012-03-28 14:53:20 -07001866 def runTest(self):
Rich Lane2014f9b2012-10-05 15:29:40 -07001867 count = test_param_get('iter_count', default=10)
Dan Talayco8a64e332012-03-28 14:53:20 -07001868 tests_done = 0
Rich Lane9a003812012-10-04 17:17:59 -07001869 logging.info("Running iteration test " + str(count) + " times")
Dan Talayco8a64e332012-03-28 14:53:20 -07001870 start = time.time()
1871 last = start
1872 for idx in range(count):
Rich Lane9a003812012-10-04 17:17:59 -07001873 logging.info("Iteration " + str(idx + 1))
Dan Talayco8a64e332012-03-28 14:53:20 -07001874 for cls in iter_classes:
1875 test = cls()
1876 test.inheritSetup(self)
1877 test.runTest()
1878 tests_done += 1
Dan Talaycofa6454f2012-04-05 10:04:13 -07001879 # Report update about every minute, between tests
Dan Talayco8a64e332012-03-28 14:53:20 -07001880 if time.time() - last > 60:
1881 last = time.time()
Rich Lane9a003812012-10-04 17:17:59 -07001882 logging.info(
Dan Talaycofa6454f2012-04-05 10:04:13 -07001883 "IterCases: Iter %d of %d; Ran %d tests in %d " %
1884 (idx, count, tests_done, last - start) +
1885 "seconds so far")
Dan Talayco8a64e332012-03-28 14:53:20 -07001886 stats = all_stats_get(self)
1887 last = time.time()
Rich Lane9a003812012-10-04 17:17:59 -07001888 logging.info("\nIterCases ran %d tests in %d seconds." %
Dan Talayco8a64e332012-03-28 14:53:20 -07001889 (tests_done, last - start))
Rich Lane9a003812012-10-04 17:17:59 -07001890 logging.info(" flows: %d. packets: %d. bytes: %d" %
Dan Talayco8a64e332012-03-28 14:53:20 -07001891 (stats["flows"], stats["packets"], stats["bytes"]))
Rich Lane9a003812012-10-04 17:17:59 -07001892 logging.info(" active: %d. lookups: %d. matched %d." %
Dan Talayco8a64e332012-03-28 14:53:20 -07001893 (stats["active"], stats["lookups"], stats["matched"]))
1894
Dan Talayco4b2bee62010-07-20 14:10:05 -07001895#@todo Need to implement tagged versions of the above tests
1896#
1897#@todo Implement a test case that strips tag 2, adds tag 3
1898# and modifies tag 4 to tag 5. Then verify (in addition) that
1899# tag 6 does not get modified.
1900
1901class MixedVLAN(BaseMatchCase):
1902 """
1903 Test mixture of VLAN tag actions
1904
1905 Strip tag 2 on port 1, send to port 2
1906 Add tag 3 on port 1, send to port 2
1907 Modify tag 4 to 5 on port 1, send to port 2
1908 All other traffic from port 1, send to port 3
1909 All traffic from port 2 sent to port 4
1910 Use exact matches with different packets for all mods
1911 Verify the following: (port, vid)
1912 (port 1, vid 2) => VLAN tag stripped, out port 2
1913 (port 1, no tag) => tagged packet w/ vid 2 out port 2
1914 (port 1, vid 4) => tagged packet w/ vid 5 out port 2
1915 (port 1, vid 5) => tagged packet w/ vid 5 out port 2
1916 (port 1, vid 6) => tagged packet w/ vid 6 out port 2
1917 (port 2, no tag) => untagged packet out port 4
1918 (port 2, vid 2-6) => unmodified packet out port 4
1919
1920 Variation: Might try sending VID 5 to port 3 and check.
1921 If only VID 5 distinguishes pkt, this will fail on some platforms
1922 """
1923
Rich Laned1d9c282012-10-04 22:07:10 -07001924 priority = -1
Rich Lane8d6ab272012-09-23 18:06:20 -07001925
Rich Laneb90a1c42012-10-05 09:16:05 -07001926class MatchEach(base_tests.SimpleDataPlane):
Rich Lane8d6ab272012-09-23 18:06:20 -07001927 """
1928 Check that each match field is actually matched on.
1929 Installs two flows that differ in one field. The flow that should not
1930 match has a higher priority, so if that field is ignored during matching
1931 the packet will be sent out the wrong port.
1932
1933 TODO test UDP, ARP, ICMP, etc.
1934 """
1935 def runTest(self):
Rich Lane477f4812012-10-04 22:49:00 -07001936 of_ports = config["port_map"].keys()
Rich Lane8d6ab272012-09-23 18:06:20 -07001937 of_ports.sort()
1938 self.assertTrue(len(of_ports) > 1, "Not enough ports for test")
1939
Rich Lane9a003812012-10-04 17:17:59 -07001940 delete_all_flows(self.controller)
Rich Lane8d6ab272012-09-23 18:06:20 -07001941
1942 pkt = simple_tcp_packet()
1943 ingress_port = of_ports[0]
1944 egress_port = of_ports[1]
1945
1946 def testField(field, mask):
Rich Lane9a003812012-10-04 17:17:59 -07001947 logging.info("Testing field %s" % field)
Rich Lane8d6ab272012-09-23 18:06:20 -07001948
1949 def addFlow(matching, priority, output_port):
1950 match = packet_to_flow_match(self, pkt)
1951 self.assertTrue(match is not None, "Could not generate flow match from pkt")
1952 match.wildcards &= ~ofp.OFPFW_IN_PORT
1953 match.in_port = ingress_port
1954 if not matching:
1955 # Make sure flow doesn't match
1956 orig = getattr(match, field)
1957 if isinstance(orig, list):
1958 new = map(lambda a: ~a[0] & a[1], zip(orig, mask))
1959 else:
1960 new = ~orig & mask
1961 setattr(match, field, new)
1962 request = message.flow_mod()
1963 request.match = match
1964 request.buffer_id = 0xffffffff
1965 request.priority = priority
1966 act = action.action_output()
1967 act.port = output_port
1968 self.assertTrue(request.actions.add(act), "Could not add action")
Rich Lane9a003812012-10-04 17:17:59 -07001969 logging.info("Inserting flow")
Rich Lane8d6ab272012-09-23 18:06:20 -07001970 self.controller.message_send(request)
1971
1972 # This flow should match.
1973 addFlow(matching=True, priority=0, output_port=egress_port)
1974 # This flow should not match, but it has a higher priority.
1975 addFlow(matching=False, priority=1, output_port=ofp.OFPP_IN_PORT)
1976
1977 self.assertEqual(do_barrier(self.controller), 0, "Barrier failed")
1978
Rich Lane9a003812012-10-04 17:17:59 -07001979 logging.info("Sending packet to dp port " + str(ingress_port))
Rich Lane8d6ab272012-09-23 18:06:20 -07001980 self.dataplane.send(ingress_port, str(pkt))
1981
1982 exp_pkt_arg = None
1983 exp_port = None
Rich Lane477f4812012-10-04 22:49:00 -07001984 if config["relax"]:
Rich Lane8d6ab272012-09-23 18:06:20 -07001985 exp_pkt_arg = pkt
1986 exp_port = egress_port
1987
1988 (rcv_port, rcv_pkt, pkt_time) = self.dataplane.poll(port_number=exp_port,
1989 exp_pkt=exp_pkt_arg)
1990 self.assertTrue(rcv_pkt is not None, "Did not receive packet")
Rich Lane9a003812012-10-04 17:17:59 -07001991 logging.debug("Packet len " + str(len(rcv_pkt)) + " in on " + str(rcv_port))
Rich Lane8d6ab272012-09-23 18:06:20 -07001992 self.assertEqual(rcv_port, egress_port, "Unexpected receive port")
1993 self.assertEqual(str(pkt), str(rcv_pkt), 'Response packet does not match send packet')
1994
1995 # TODO in_port
1996 testField("dl_src", [0xff]*6)
1997 testField("dl_dst", [0xff]*6)
1998 testField("dl_type", 0xffff)
1999 testField("dl_vlan", 0xfff)
2000 # TODO dl_vlan_pcp
2001 testField("nw_src", 0xffffffff)
2002 testField("nw_dst", 0xffffffff)
2003 testField("nw_tos", 0x3f)
2004 testField("nw_proto", 0xff)
2005 testField("tp_src", 0xffff)
2006 testField("tp_dst", 0xffff)
2007
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002008class DirectBadPacketBase(base_tests.SimpleDataPlane):
2009 """
2010 Base class for sending single packets with single flow table entries.
2011 Used to verify matching of unusual packets and parsing/matching of
2012 corrupted packets.
2013
2014 The idea is to generate packets that may either be totally malformed or
2015 malformed just enough to trick the flow matcher into making mistakes.
2016
2017 Generate a 'bad' packet
2018 Generate and install a matching flow
2019 Add action to direct the packet to an egress port
2020 Send the packet to ingress dataplane port
2021 Verify the packet is received at the egress port only
2022 """
2023
2024 RESULT_MATCH = "MATCH"
2025 RESULT_NOMATCH = "NO MATCH"
2026 RESULT_ANY = "ANY MATCH"
2027
2028 def runTest(self):
2029 pass
2030 # TODO:
2031 # - ICMP?
2032 # - VLAN?
2033 # - action
2034
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002035 def createMatch(self, **kwargs):
2036 match = ofp.ofp_match()
2037 match.wildcards = ofp.OFPFW_ALL
2038 fields = {
2039 'dl_dst': ofp.OFPFW_DL_DST,
2040 'dl_src': ofp.OFPFW_DL_SRC,
2041 'dl_type': ofp.OFPFW_DL_TYPE,
2042 'dl_vlan': ofp.OFPFW_DL_VLAN,
2043 'nw_src': ofp.OFPFW_NW_SRC_MASK,
2044 'nw_dst': ofp.OFPFW_NW_DST_MASK,
2045 'nw_tos': ofp.OFPFW_NW_TOS,
2046 'nw_proto': ofp.OFPFW_NW_PROTO,
2047 'tp_src': ofp.OFPFW_TP_SRC,
2048 'tp_dst': ofp.OFPFW_TP_DST,
2049 }
2050 for key in kwargs:
2051 setattr(match, key, kwargs[key])
2052 match.wildcards &= ~fields[key]
2053 return match
2054
2055 def testPktsAgainstFlow(self, pkts, acts, match):
2056 if type(acts) != list:
2057 acts = [acts]
2058 for info in pkts:
2059 title, pkt, expected_result = info
2060 self.testPktAgainstFlow(title, pkt, acts, match, expected_result)
2061
2062 def testPktAgainstFlow(self, title, pkt, acts, match, expected_result):
2063 of_ports = config["port_map"].keys()
2064 of_ports.sort()
2065 self.assertTrue(len(of_ports) > 1, "Not enough ports for test")
2066
2067 rv = delete_all_flows(self.controller)
2068 self.assertEqual(rv, 0, "Failed to delete all flows")
2069
2070 ingress_port = of_ports[0]
2071 egress_port = of_ports[1]
2072
2073 logging.info("Testing packet '%s', expect result %s" %
2074 (title, expected_result))
2075 logging.info("Ingress %s to egress %s" %
2076 (str(ingress_port), str(egress_port)))
2077 logging.info("Packet:")
Rich Lane5d7e89a2012-10-26 16:43:13 -07002078 logging.info(inspect_packet(pkt))
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002079
2080 match.in_port = ingress_port
2081
2082 request = message.flow_mod()
2083 request.match = match
Rich Lane44cf12d2012-10-15 11:10:45 -07002084 request.priority = 1
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002085
2086 request.buffer_id = 0xffffffff
2087 for act in acts:
2088 act.port = egress_port
2089 rv = request.actions.add(act)
2090 self.assertTrue(rv, "Could not add action")
2091
2092 logging.info("Inserting flow")
2093 rv = self.controller.message_send(request)
2094 self.assertTrue(rv != -1, "Error installing flow mod")
Rich Lane44cf12d2012-10-15 11:10:45 -07002095
2096 # This flow speeds up negative tests
2097 logging.info("Inserting catch-all flow")
2098 request2 = message.flow_mod()
2099 request2.match = self.createMatch()
2100 request2.priority = 0
2101 act = action.action_output()
2102 act.port = ofp.OFPP_IN_PORT
2103 request2.actions.add(act)
2104 rv = self.controller.message_send(request2)
2105 self.assertTrue(rv != -1, "Error installing flow mod")
2106
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002107 self.assertEqual(do_barrier(self.controller), 0, "Barrier failed")
2108
2109 logging.info("Sending packet to dp port " +
2110 str(ingress_port))
2111 self.dataplane.send(ingress_port, str(pkt))
2112
2113 exp_pkt_arg = None
2114 exp_port = None
2115 if config["relax"]:
2116 exp_pkt_arg = pkt
2117 exp_port = egress_port
2118
Rich Lane44cf12d2012-10-15 11:10:45 -07002119 if expected_result == self.RESULT_MATCH:
2120 timeout = -1 # default timeout
2121 else:
2122 timeout = 1 # short timeout for negative tests
2123
2124 (rcv_port, rcv_pkt, pkt_time) = self.dataplane.poll(exp_pkt=exp_pkt_arg,
2125 timeout=timeout)
2126 if rcv_port == ingress_port:
2127 logging.debug("Packet matched catch-all flow")
2128 rcv_pkt = None
2129
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002130 if expected_result == self.RESULT_MATCH:
2131 self.assertTrue(rcv_pkt is not None,
2132 "Did not receive packet, expected a match")
2133 logging.debug("Packet len " + str(len(rcv_pkt)) + " in on " +
2134 str(rcv_port))
2135 self.assertEqual(rcv_port, egress_port, "Unexpected receive port")
2136 str_pkt = str(pkt)
2137 str_rcv_pkt = str(rcv_pkt)
2138 str_rcv_pkt = str_rcv_pkt[0:len(str_pkt)]
2139 if str_pkt != str_rcv_pkt:
2140 logging.error("Response packet does not match send packet")
2141 logging.info("Response:")
Rich Lane5d7e89a2012-10-26 16:43:13 -07002142 logging.info(inspect_packet(scapy.Ether(rcv_pkt)))
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002143 self.assertEqual(str_pkt, str_rcv_pkt,
2144 'Response packet does not match send packet')
2145 elif expected_result == self.RESULT_NOMATCH:
2146 self.assertTrue(rcv_pkt is None, "Received packet, expected drop")
2147 else:
2148 logging.debug("Match or drop accepted. Result = %s" %
2149 ("match" if rcv_pkt is not None else "drop"))
2150
2151
2152class DirectBadIpTcpPacketsBase(DirectBadPacketBase):
2153 """
2154 Base class for TCP and UDP parsing/matching verification under corruptions
2155 """
2156 def runTest(self):
2157 pass
2158
2159 def runTestWithProto(self, protoName = 'TCP'):
2160 dl_dst='00:01:02:03:04:05'
2161 dl_src='00:06:07:08:09:0a'
2162 ip_src='192.168.0.1'
2163 ip_dst='192.168.0.2'
2164 ip_tos=0
2165 tcp_sport=1234
2166 tcp_dport=80
2167
2168 # Generate a proper packet for constructing a match
2169 tp = None
2170 if protoName == 'TCP':
2171 tp = scapy.TCP
2172 proto = 6
2173 elif protoName == 'UDP':
2174 tp = scapy.UDP
2175 proto = 17
2176 else:
2177 raise Exception("Passed in unknown proto name")
2178
2179 match_pkt = scapy.Ether(dst=dl_dst, src=dl_src)/ \
2180 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos)/ \
2181 tp(sport=tcp_sport, dport=tcp_dport)
2182 match = packet_to_flow_match(self, match_pkt)
2183 self.assertTrue(match is not None,
2184 "Could not generate flow match from pkt")
2185 match.wildcards &= ~ofp.OFPFW_IN_PORT
2186
2187 def testPacket(title, pkt, result):
2188 act = action.action_output()
2189 pkts = [
2190 [title, pkt, result]
2191 ]
2192 self.testPktsAgainstFlow(pkts, act, match)
2193
2194 # Try incomplete IP headers
2195 testPacket("Incomplete IP header (1 bytes)",
2196 scapy.Ether(dst=dl_dst, src=dl_src)/ \
2197 str(scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, proto=proto))[0:1],
2198 self.RESULT_NOMATCH,
2199 )
2200 testPacket("Incomplete IP header (2 bytes)",
2201 scapy.Ether(dst=dl_dst, src=dl_src)/ \
2202 str(scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, proto=proto))[0:2],
2203 self.RESULT_NOMATCH,
2204 )
2205 testPacket("Incomplete IP header (3 bytes)",
2206 scapy.Ether(dst=dl_dst, src=dl_src)/ \
2207 str(scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, proto=proto))[0:3],
2208 self.RESULT_NOMATCH,
2209 )
2210 testPacket("Incomplete IP header (12 bytes)",
2211 scapy.Ether(dst=dl_dst, src=dl_src)/ \
2212 str(scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, proto=proto))[0:12],
2213 self.RESULT_NOMATCH,
2214 )
2215 testPacket("Incomplete IP header (16 bytes)",
2216 scapy.Ether(dst=dl_dst, src=dl_src)/ \
2217 str(scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, proto=proto))[0:16],
2218 self.RESULT_NOMATCH,
2219 )
2220 testPacket("Incomplete IP header (19 bytes)",
2221 scapy.Ether(dst=dl_dst, src=dl_src)/ \
2222 str(scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, proto=proto))[0:19],
2223 self.RESULT_NOMATCH,
2224 )
2225
2226 # Try variations where the TCP header is missing or incomplete. As we
2227 # saw bugs before where buffers were reused and lengths weren't honored,
2228 # we initiatlize once with a non-matching full packet and once with a
2229 # matching full packet.
2230 testPacket("Non-Matching TCP packet, warming buffer",
2231 scapy.Ether(dst=dl_dst, src=dl_src)/ \
2232 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, proto=proto)/ \
2233 tp(sport=tcp_sport, dport=tcp_dport + 1),
2234 self.RESULT_NOMATCH,
2235 )
2236 testPacket("Missing TCP header, buffer warmed with non-match",
2237 scapy.Ether(dst=dl_dst, src=dl_src)/ \
2238 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, proto=proto),
2239 self.RESULT_NOMATCH,
2240 )
2241 testPacket("Matching TCP packet, warming buffer",
2242 scapy.Ether(dst=dl_dst, src=dl_src)/ \
2243 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, proto=proto)/ \
2244 tp(sport=tcp_sport, dport=tcp_dport),
2245 self.RESULT_MATCH,
2246 )
2247 testPacket("Missing TCP header, buffer warmed with match",
2248 scapy.Ether(dst=dl_dst, src=dl_src)/ \
2249 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, proto=proto),
2250 self.RESULT_NOMATCH,
2251 )
2252 testPacket("Truncated TCP header: 2 bytes",
2253 scapy.Ether(dst=dl_dst, src=dl_src)/ \
2254 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, proto=proto)/ \
2255 (str(tp(sport=tcp_sport, dport=tcp_dport))[0:2]),
2256 self.RESULT_NOMATCH,
2257 )
2258
2259 # Play with IP header length values that put the start of TCP either
2260 # inside the generated TCP header or beyond. In some cases it may even
2261 # be beyond the packet boundary. Also play with IP options and more
2262 # importantly IP total length corruptions.
2263 testPacket("TCP packet, corrupt ihl (0x6)",
2264 simple_tcp_packet(ip_ihl=6),
2265 self.RESULT_NOMATCH,
2266 )
2267 testPacket("TCP packet, corrupt ihl (0xf)",
2268 simple_tcp_packet(ip_ihl=0xf), # ihl = 15 * 4 = 60
2269 self.RESULT_NOMATCH,
2270 )
2271 testPacket("TCP packet, corrupt ihl and total length",
2272 simple_tcp_packet(ip_ihl=0xf, pktlen=56), # ihl = 15 * 4 = 60,
2273 self.RESULT_NOMATCH,
2274 )
2275 testPacket("Corrupt IPoption: First 4 bytes of matching TCP header",
2276 simple_tcp_packet(
2277 ip_options=scapy.IPOption('\x04\xd2\x00\x50'),
2278 tcp_dport=2, tcp_sport=2
2279 ),
2280 self.RESULT_NOMATCH,
2281 )
2282 testPacket("Missing TCP header, corrupt ihl",
2283 scapy.Ether(dst=dl_dst, src=dl_src)/ \
2284 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ihl=0xf, proto=proto),
2285 self.RESULT_NOMATCH,
2286 )
2287 testPacket("Missing TCP header, corrupt total length",
2288 scapy.Ether(dst=dl_dst, src=dl_src)/ \
2289 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, proto=proto, len= 100),
2290 self.RESULT_NOMATCH,
2291 )
2292 testPacket("Missing TCP header, corrupt ihl and total length",
2293 scapy.Ether(dst=dl_dst, src=dl_src)/ \
2294 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ihl=0xf, proto=proto, len=43),
2295 self.RESULT_NOMATCH,
2296 )
2297 testPacket("Incomplete IP header (12 bytes), corrupt ihl and total length",
2298 scapy.Ether(dst=dl_dst, src=dl_src)/ \
2299 str(scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, proto=proto, ihl=10, len=43))[0:12],
2300 self.RESULT_NOMATCH,
2301 )
2302 testPacket("Incomplete IP header (16 bytes), corrupt ihl and total length",
2303 scapy.Ether(dst=dl_dst, src=dl_src)/ \
2304 str(scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, proto=proto, ihl=10, len=43))[0:16],
2305 self.RESULT_NOMATCH,
2306 )
2307
2308 # Try an incomplete TCP header that has enough bytes to carry source and
2309 # destination ports. As that is all we care about during matching, some
2310 # implementations may match and some may drop the packet
2311 testPacket("Incomplete TCP header: src/dst port present",
2312 scapy.Ether(dst=dl_dst, src=dl_src)/ \
2313 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, proto=proto)/ \
2314 (str(tp(sport=tcp_sport, dport=tcp_dport))[0:4]),
2315 self.RESULT_ANY,
2316 )
2317
2318 for i in range(1):
2319 for length in range(40 / 4): # IPv4 options are a maximum of 40 in length
2320 bytes = "".join([("%c" % random.randint(0, 255)) for x in range(length * 4)])
2321 eth = scapy.Ether(dst=dl_dst, src=dl_src)
2322 ip = scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ihl=5 + length, proto=proto)
2323 tcp = tp(sport=tcp_sport, dport=tcp_dport+1)
2324 pkt = eth / ip
2325 pkt = pkt / bytes
2326 pkt = pkt / str(tcp)
2327 testPacket("Random IP options len = %d - TP match must fail" % length * 4,
2328 pkt,
2329 self.RESULT_NOMATCH
2330 )
2331
2332 eth = scapy.Ether(dst=dl_dst, src=dl_src)
2333 ip = scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ihl=5 + length, proto=proto)
2334 tcp = tp(sport=tcp_sport, dport=tcp_dport)
2335 pkt = eth / ip
2336 pkt = pkt / bytes
2337 pkt = pkt / str(tcp)
2338
2339 testPacket("Random IP options len = %d - May match",
2340 pkt,
2341 self.RESULT_ANY
2342 )
2343
2344
2345class DirectBadIpTcpPackets(DirectBadIpTcpPacketsBase):
2346 """
2347 Verify IP/TCP parsing and matching. Focus on packet corruptions
2348 """
2349 def runTest(self):
2350 self.runTestWithProto(protoName = 'TCP')
2351
2352class DirectBadIpUdpPackets(DirectBadIpTcpPacketsBase):
2353 """
2354 Verify IP/UDP parsing and matching. Focus on packet corruptions
2355 """
2356 def runTest(self):
2357 self.runTestWithProto(protoName = 'UDP')
2358
2359class DirectBadLlcPackets(DirectBadPacketBase):
2360 """
2361 Verify LLC/SNAP parsing and matching. Focus on packet corruptions
2362 """
2363 def runTest(self):
2364 dl_dst='00:01:02:03:04:05'
2365 dl_src='00:06:07:08:09:0a'
2366 ip_src='192.168.0.1'
2367 ip_dst='192.168.0.2'
2368 ip_tos=0
2369 tcp_sport=1234
2370 tcp_dport=80
2371
2372 IS_SNAP_IP = 1
2373 IS_SNAP_IP_CORRUPT = 2
2374 IS_NOT_SNAP_IP = 3
2375
2376 def testPacketTcpMatch(title, llc):
2377 match_pkt = scapy.Ether(dst=dl_dst, src=dl_src)/ \
2378 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos)/ \
2379 scapy.TCP(sport=tcp_sport, dport=tcp_dport)
2380 match = packet_to_flow_match(self, match_pkt)
2381 self.assertTrue(match is not None,
2382 "Could not generate flow match from pkt")
2383 match.wildcards &= ~ofp.OFPFW_IN_PORT
2384 act = action.action_output()
2385
2386 self.testPktsAgainstFlow(
2387 [[
2388 "TCP match - LLC frame correct length - %s" % title,
2389 scapy.Ether(dst=dl_dst, src=dl_src, type=len(llc)) / llc,
2390 self.RESULT_ANY,
2391 ]],
2392 act, match
2393 )
2394
2395 # Corrupt length field
2396 ethLen = random.randint(0, 1535)
2397 self.testPktsAgainstFlow(
2398 [[
2399 "TCP match - LLC frame corrupted length - %s" % title,
2400 scapy.Ether(dst=dl_dst, src=dl_src, type=ethLen) / llc,
2401 self.RESULT_ANY,
2402 ]],
2403 act, match
2404 )
2405
2406 def testPacketEthSrcDstMatch(title, llc):
2407 # Matching based on Ethernet source and destination
2408 match_pkt = scapy.Ether(dst=dl_dst, src=dl_src)
2409 match = packet_to_flow_match(self, match_pkt)
2410 self.assertTrue(match is not None,
2411 "Could not generate flow match from pkt")
2412 match.wildcards &= ~ofp.OFPFW_IN_PORT
2413 match.wildcards |= ofp.OFPFW_DL_TYPE
2414 self.testPktsAgainstFlow(
2415 [[
2416 "Eth addr match - LLC frame correct length- %s" % title,
2417 scapy.Ether(dst=dl_dst, src=dl_src, type=len(llc)) / llc,
2418 self.RESULT_MATCH,
2419 ]],
2420 action.action_output(), match
2421 )
2422
2423 # Corrupt length field
2424 ethLen = random.randint(0, 1535)
2425 self.testPktsAgainstFlow(
2426 [[
2427 "Eth addr match - LLC frame corrupted length- %s" % title,
2428 scapy.Ether(dst=dl_dst, src=dl_src, type=ethLen) / llc,
2429 self.RESULT_ANY,
2430 ]],
2431 action.action_output(), match
2432 )
2433
2434 def testPacketEthSrcDstTypeMatch(title, llc, is_snap_ip):
2435 # Matching based on Ethernet source, destination and type
2436 match_pkt = scapy.Ether(dst=dl_dst, src=dl_src, type=0x800)
2437 match = packet_to_flow_match(self, match_pkt)
2438 self.assertTrue(match is not None,
2439 "Could not generate flow match from pkt")
2440 match.wildcards &= ~ofp.OFPFW_IN_PORT
2441 if is_snap_ip == IS_SNAP_IP:
2442 is_match = self.RESULT_MATCH
2443 elif is_snap_ip == IS_SNAP_IP_CORRUPT:
2444 is_match = self.RESULT_ANY
2445 else:
2446 is_match = self.RESULT_NOMATCH
2447 self.testPktsAgainstFlow(
2448 [[
2449 "Eth addr+type match - LLC frame correct length - %s" % title,
2450 scapy.Ether(dst=dl_dst, src=dl_src, type=len(llc)) / llc,
2451 is_match,
2452 ]],
2453 action.action_output(), match
2454 )
2455
2456 # Corrupt length field
2457 ethLen = random.randint(0, 1535)
2458 self.testPktsAgainstFlow(
2459 [[
2460 "Eth addr+type match - LLC frame corrupted length - %s" % title,
2461 scapy.Ether(dst=dl_dst, src=dl_src, type=ethLen) / llc,
Christian Dickmanne9b6d252012-10-08 22:56:50 -07002462 self.RESULT_ANY,
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002463 ]],
2464 action.action_output(), match
2465 )
2466
2467 def testPacket(title, llc, is_snap_ip):
2468 testPacketTcpMatch(title, llc)
2469 testPacketEthSrcDstMatch(title, llc)
2470 testPacketEthSrcDstTypeMatch(title, llc, is_snap_ip)
2471
2472 testPacket("LLC - No SNAP - No Payload",
Rich Lane6508ea02012-10-12 15:27:11 -07002473 scapy.LLC(dsap=0x33, ssap=0x44, ctrl=0x03),
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002474 IS_NOT_SNAP_IP,
2475 )
2476 testPacket("LLC - No SNAP - Small Payload",
Rich Lane6508ea02012-10-12 15:27:11 -07002477 scapy.LLC(dsap=0x33, ssap=0x44, ctrl=0x03) / ("S" * 10),
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002478 IS_NOT_SNAP_IP,
2479 )
2480 testPacket("LLC - No SNAP - Max -1 Payload",
Rich Lane6508ea02012-10-12 15:27:11 -07002481 scapy.LLC(dsap=0x33, ssap=0x44, ctrl=0x03) / ("S" * (1500 - 3 - 1)),
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002482 IS_NOT_SNAP_IP,
2483 )
2484 testPacket("LLC - No SNAP - Max Payload",
Rich Lane6508ea02012-10-12 15:27:11 -07002485 scapy.LLC(dsap=0x33, ssap=0x44, ctrl=0x03) / ("S" * (1500 - 3)),
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002486 IS_NOT_SNAP_IP,
2487 )
2488 testPacket("LLC - SNAP - Small bogus payload",
2489 scapy.LLC(dsap=0xaa, ssap=0xaa, ctrl=0x03)/ \
2490 scapy.SNAP(OUI=0x000000, code=0x800) / ("S" * 10),
2491 IS_SNAP_IP_CORRUPT,
2492 )
2493 testPacket("LLC - SNAP - Max -1 bogus payload",
2494 scapy.LLC(dsap=0xaa, ssap=0xaa, ctrl=0x03)/ \
2495 scapy.SNAP(OUI=0x000000, code=0x3) / ("S" * (1500 - 3 - 5 - 1)),
2496 IS_NOT_SNAP_IP,
2497 )
2498 testPacket("LLC - SNAP - Max bogus payload",
2499 scapy.LLC(dsap=0xaa, ssap=0xaa, ctrl=0x03)/ \
2500 scapy.SNAP(OUI=0x000000, code=0x3) / ("S" * (1500 - 3 - 5)),
2501 IS_NOT_SNAP_IP,
2502 )
2503 testPacket("LLC - SNAP - IP - TCP",
2504 scapy.LLC(dsap=0xaa, ssap=0xaa, ctrl=0x03)/ \
2505 scapy.SNAP(OUI=0x000000, code=0x800)/ \
2506 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, proto=6)/ \
2507 scapy.TCP(sport=tcp_sport, dport=tcp_dport),
2508 IS_SNAP_IP,
2509 )
2510
2511
2512class DirectLlcPackets(DirectBadPacketBase):
2513 """
2514 Verify LLC/SNAP parsing (valid and corrupted packets) and matching
2515 """
2516 def runTest(self):
2517 dl_dst='00:01:02:03:04:05'
2518 dl_src='00:06:07:08:09:0a'
2519 ip_src='192.168.0.1'
2520 ip_dst='192.168.0.2'
2521 ip_tos=0
2522 tcp_sport=1234
2523 tcp_dport=80
2524
2525 # Test ethertype in face of LLC/SNAP and OFP_DL_TYPE_NOT_ETH_TYPE
2526 IS_SNAP_NOT_IP = 1
2527 IS_SNAP_AND_IP = 2
2528 IS_NOT_SNAP = 3
2529
2530 def testPacketEthTypeIP(title, llc, is_snap):
2531 match_pkt = scapy.Ether(dst=dl_dst, src=dl_src, type=0x800)
2532 match = packet_to_flow_match(self, match_pkt)
2533 self.assertTrue(match is not None,
2534 "Could not generate flow match from pkt")
2535 match.wildcards &= ~ofp.OFPFW_IN_PORT
2536 pkts = []
2537 if is_snap == IS_NOT_SNAP or is_snap == IS_SNAP_NOT_IP:
2538 result = self.RESULT_NOMATCH
2539 else:
2540 result = self.RESULT_MATCH
2541 pkts.append([
2542 "Ether type 0x800 match - %s" % title,
2543 scapy.Ether(dst=dl_dst, src=dl_src, type=len(llc)) / llc,
2544 result,
2545 ])
2546 act = action.action_output()
2547 self.testPktsAgainstFlow(pkts, act, match)
2548
2549 def testPacketEthTypeNotEth(title, llc, is_snap):
2550 match_pkt = scapy.Ether(dst = dl_dst, src = dl_src,
2551 type = ofp.OFP_DL_TYPE_NOT_ETH_TYPE)
2552 match = packet_to_flow_match(self, match_pkt)
2553 self.assertTrue(match is not None,
2554 "Could not generate flow match from pkt")
2555 match.wildcards &= ~ofp.OFPFW_IN_PORT
2556 pkts = []
2557 if is_snap == IS_NOT_SNAP:
2558 result = self.RESULT_MATCH
2559 else:
2560 result = self.RESULT_NOMATCH
2561 pkts.append([
2562 "Ether type OFP_DL_TYPE_NOT_ETH_TYPE match - %s" % title,
2563 scapy.Ether(dst=dl_dst, src=dl_src, type=len(llc)) / llc,
2564 result,
2565 ])
2566 act = action.action_output()
2567 self.testPktsAgainstFlow(pkts, act, match)
2568
2569 def testPacket(title, llc, is_snap):
2570 testPacketEthTypeIP(title, llc, is_snap)
2571 testPacketEthTypeNotEth(title, llc, is_snap)
2572
2573 testPacket("LLC - No SNAP - No Payload",
Rich Lane6508ea02012-10-12 15:27:11 -07002574 scapy.LLC(dsap=0x33, ssap=0x44, ctrl=0x03),
2575 IS_NOT_SNAP,
2576 )
2577 testPacket("LLC (with information field) - No SNAP - No Payload",
2578 scapy.LLC(dsap=0x33, ssap=0x44, ctrl=0x12) / "S",
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002579 IS_NOT_SNAP,
2580 )
2581 testPacket("LLC - No SNAP - Small Payload",
Rich Lane6508ea02012-10-12 15:27:11 -07002582 scapy.LLC(dsap=0x33, ssap=0x44, ctrl=0x03) / ("S" * 10),
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002583 IS_NOT_SNAP,
2584 )
2585 testPacket("LLC - No SNAP - Max -1 Payload",
Rich Lane6508ea02012-10-12 15:27:11 -07002586 scapy.LLC(dsap=0x33, ssap=0x44, ctrl=0x03) / ("S" * (1500 - 3 - 1)),
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002587 IS_NOT_SNAP,
2588 )
2589 testPacket("LLC - No SNAP - Max Payload",
Rich Lane6508ea02012-10-12 15:27:11 -07002590 scapy.LLC(dsap=0x33, ssap=0x44, ctrl=0x03) / ("S" * (1500 - 3)),
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002591 IS_NOT_SNAP,
2592 )
2593 testPacket("LLC - SNAP - Non-default OUI",
2594 scapy.LLC(dsap=0xaa, ssap=0xaa, ctrl=0x03)/ \
2595 scapy.SNAP(OUI=0x000001, code=0x800) / ("S" * 10),
2596 IS_NOT_SNAP,
2597 )
2598 testPacket("LLC - SNAP - Default OUI",
2599 scapy.LLC(dsap=0xaa, ssap=0xaa, ctrl=0x03)/ \
2600 scapy.SNAP(OUI=0x000000, code=0x800) / ("S" * 10),
2601 IS_SNAP_AND_IP,
2602 )
2603 testPacket("LLC - SNAP - Max -1 bogus payload",
2604 scapy.LLC(dsap=0xaa, ssap=0xaa, ctrl=0x03)/ \
2605 scapy.SNAP(OUI=0x000000, code=0x3) / ("S" * (1500 - 3 - 5 - 1)),
2606 IS_SNAP_NOT_IP,
2607 )
2608 testPacket("LLC - SNAP - Max bogus payload",
2609 scapy.LLC(dsap=0xaa, ssap=0xaa, ctrl=0x03)/ \
2610 scapy.SNAP(OUI=0x000000, code=0x3) / ("S" * (1500 - 3 - 5)),
2611 IS_SNAP_NOT_IP,
2612 )
2613 testPacket("LLC - SNAP - IP - TCP",
2614 scapy.LLC(dsap=0xaa, ssap=0xaa, ctrl=0x03)/ \
2615 scapy.SNAP(OUI=0x000000, code=0x800)/ \
2616 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, proto=6)/ \
2617 scapy.TCP(sport=tcp_sport, dport=tcp_dport),
2618 IS_SNAP_AND_IP,
2619 )
2620
2621
2622class DirectArpPackets(DirectBadPacketBase):
2623 """
2624 Verify ARP parsing (valid and corrupted packets) and ARP matching
2625 """
2626 def runTest(self):
2627 self.testArpHandling()
2628
2629 def testArpHandling(self):
2630 dl_dst='00:01:02:03:04:05'
2631 dl_src='00:06:07:08:09:0a'
2632 ip_src='192.168.0.1'
2633 ip_dst='192.168.0.2'
2634 ip_src2='192.168.1.1'
2635 ip_dst2='192.168.1.2'
2636 ip_tos=0
2637 tcp_sport=1234
2638 tcp_dport=80
2639
2640 def testPacket(title, arp_match, arp_pkt, result):
2641 pkts = []
2642
2643 match_pkt = scapy.Ether(dst=dl_dst, src=dl_src) / arp_match
2644 match = packet_to_flow_match(self, match_pkt)
2645 self.assertTrue(match is not None,
2646 "Could not generate flow match from pkt")
2647 match.wildcards &= ~ofp.OFPFW_IN_PORT
2648
2649 pkts.append([
2650 title,
2651 scapy.Ether(dst=dl_dst, src=dl_src) / arp_pkt,
2652 result,
2653 ])
2654
2655 act = action.action_output()
2656 self.testPktsAgainstFlow(pkts, act, match)
2657
2658 testPacket("Basic ARP",
2659 scapy.ARP(psrc=ip_src, pdst=ip_dst, op = 1),
2660 scapy.ARP(hwdst = '00:00:00:00:00:00', hwsrc = dl_src,
2661 psrc = ip_src, pdst = ip_dst, hwlen = 6, plen = 4,
2662 ptype = 0x800, hwtype = 1, op = 1),
2663 self.RESULT_MATCH
2664 )
2665 # More stuff:
2666 # - Non matches on any property
2667 # - Corrupted hwlen and plen
2668 # - Other hwtype, ptype
2669 # - Truncated ARP pkt
2670
2671
2672class DirectVlanPackets(DirectBadPacketBase):
2673 """
2674 Verify VLAN parsing (valid and corrupted packets) and ARP matching
2675 """
2676 def runTest(self):
2677 dl_dst='00:01:02:03:04:05'
2678 dl_src='00:06:07:08:09:0a'
2679 ip_src='192.168.0.1'
2680 ip_dst='192.168.0.2'
2681 ip_src2='192.168.1.1'
2682 ip_dst2='192.168.1.2'
2683 ip_tos=0
2684 tcp_sport=1234
2685 tcp_dport=80
2686
2687 def testPacket(title, match, pkt, result):
2688 pkts = []
2689
2690 self.assertTrue(match is not None,
2691 "Could not generate flow match from pkt")
2692 match.wildcards &= ~ofp.OFPFW_IN_PORT
2693
2694 pkts.append([
2695 "%s" % title,
2696 pkt,
2697 result,
2698 ])
2699
2700 act = action.action_output()
2701 self.testPktsAgainstFlow(pkts, act, match)
2702
2703 testPacket("Basic MAC matching - IPv4 payload",
2704 self.createMatch(dl_dst=parse_mac(dl_dst), dl_src=parse_mac(dl_src)),
2705 scapy.Ether(dst=dl_dst, src=dl_src, type=0x800) / scapy.IP(),
2706 self.RESULT_MATCH
2707 )
2708 testPacket("Basic MAC matching - VMware beacon - no payload",
2709 self.createMatch(dl_dst=parse_mac(dl_dst), dl_src=parse_mac(dl_src)),
2710 scapy.Ether(dst=dl_dst, src=dl_src, type=0x8922),
2711 self.RESULT_MATCH
2712 )
2713 testPacket("Basic MAC matching - VMware beacon - with payload",
2714 self.createMatch(dl_dst=parse_mac(dl_dst), dl_src=parse_mac(dl_src)),
2715 scapy.Ether(dst=dl_dst, src=dl_src, type=0x8922)/ ("X" * 1),
2716 self.RESULT_MATCH
2717 )
2718 testPacket("Basic MAC matching - IPv6 payload",
2719 self.createMatch(dl_dst=parse_mac(dl_dst), dl_src=parse_mac(dl_src)),
2720 scapy.Ether(dst=dl_dst, src=dl_src) / scapy.IPv6(),
2721 self.RESULT_MATCH
2722 )
2723 testPacket("Basic MAC matching with VLAN tag present",
2724 self.createMatch(dl_dst=parse_mac(dl_dst), dl_src=parse_mac(dl_src)),
2725 scapy.Ether(dst=dl_dst, src=dl_src)/ \
Christian Dickmann8ac55252012-10-08 22:53:49 -07002726 scapy.Dot1Q(prio=5, vlan=1000)/ \
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002727 scapy.IP(),
2728 self.RESULT_MATCH
2729 )
2730 testPacket("Basic MAC matching with VLAN tag present",
2731 self.createMatch(dl_dst=parse_mac(dl_dst), dl_src=parse_mac(dl_src),
2732 dl_type=0x800),
2733 scapy.Ether(dst=dl_dst, src=dl_src)/ \
Christian Dickmann8ac55252012-10-08 22:53:49 -07002734 scapy.Dot1Q(prio=5, vlan=1000)/ \
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002735 scapy.IP(),
2736 self.RESULT_MATCH
2737 )
2738 testPacket("Ether matching with VLAN tag present - No type match",
2739 self.createMatch(dl_dst=parse_mac(dl_dst), dl_src=parse_mac(dl_src),
2740 dl_type=0x801),
2741 scapy.Ether(dst=dl_dst, src=dl_src)/ \
Christian Dickmann8ac55252012-10-08 22:53:49 -07002742 scapy.Dot1Q(prio=5, vlan=1000)/ \
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002743 scapy.IP(),
2744 self.RESULT_NOMATCH
2745 )
2746 testPacket("Ether matching with VLAN tag present - No type match 0x8100",
2747 self.createMatch(dl_dst=parse_mac(dl_dst), dl_src=parse_mac(dl_src),
2748 dl_type=0x8100),
2749 scapy.Ether(dst=dl_dst, src=dl_src)/ \
Christian Dickmann8ac55252012-10-08 22:53:49 -07002750 scapy.Dot1Q(prio=5, vlan=1000)/ \
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002751 scapy.IP(),
2752 self.RESULT_NOMATCH
2753 )
2754 testPacket("Ether matching with double VLAN tag - Wrong type match",
2755 self.createMatch(dl_dst=parse_mac(dl_dst), dl_src=parse_mac(dl_src),
2756 dl_type=0x800),
2757 scapy.Ether(dst=dl_dst, src=dl_src)/ \
Christian Dickmann8ac55252012-10-08 22:53:49 -07002758 scapy.Dot1Q(prio=5, vlan=1000)/ \
2759 scapy.Dot1Q(prio=3, vlan=1005)/ \
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002760 scapy.IP(),
2761 self.RESULT_NOMATCH
2762 )
2763 testPacket("Ether matching with double VLAN tag - Type match",
2764 self.createMatch(dl_dst=parse_mac(dl_dst), dl_src=parse_mac(dl_src),
2765 dl_type=0x8100),
2766 scapy.Ether(dst=dl_dst, src=dl_src)/ \
Christian Dickmann8ac55252012-10-08 22:53:49 -07002767 scapy.Dot1Q(prio=5, vlan=1000)/ \
2768 scapy.Dot1Q(prio=3, vlan=1005)/ \
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002769 scapy.IP(),
2770 self.RESULT_MATCH
2771 )
2772 testPacket("IP matching - VLAN tag",
2773 self.createMatch(dl_dst=parse_mac(dl_dst), dl_src=parse_mac(dl_src),
2774 dl_type=0x0800,
2775 nw_src=parse_ip(ip_src), nw_dst=parse_ip(ip_dst)),
2776 scapy.Ether(dst=dl_dst, src=dl_src)/ \
Christian Dickmann8ac55252012-10-08 22:53:49 -07002777 scapy.Dot1Q(prio=5, vlan=1000)/ \
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002778 scapy.IP(src=ip_src, dst=ip_dst),
2779 self.RESULT_MATCH
2780 )
2781 # XXX:
2782 # - Matching on VLAN ID and Prio
2783 # - Actions
2784
2785
2786
Dan Talayco9f47f4d2010-06-03 13:54:37 -07002787if __name__ == "__main__":
2788 print "Please run through oft script: ./oft --test_spec=basic"