blob: 905780e174fc10e50b1be181f1e1e597845dd8e4 [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
Rich Lane3c7cf7f2013-01-11 18:04:56 -080020import scapy.all as scapy
Dan Talayco5eba8442010-03-10 13:58:43 -080021
Rich Lane477f4812012-10-04 22:49:00 -070022from oftest import config
Dan Talayco5eba8442010-03-10 13:58:43 -080023import oftest.controller as controller
24import oftest.cstruct as ofp
25import oftest.message as message
26import oftest.dataplane as dataplane
27import oftest.action as action
28import oftest.parse as parse
Rich Laneb90a1c42012-10-05 09:16:05 -070029import oftest.base_tests as base_tests
30import basic # for IterCases
Dan Talayco5eba8442010-03-10 13:58:43 -080031
Christian Dickmann8b59b4b2012-09-23 16:48:30 -070032from oftest.parse import parse_mac, parse_ip
33
Rich Laneda3b5ad2012-10-03 09:05:32 -070034from oftest.testutils import *
Dan Talayco5eba8442010-03-10 13:58:43 -080035
Dan Talayco551befa2010-07-15 17:05:32 -070036WILDCARD_VALUES = [ofp.OFPFW_IN_PORT,
Dan Talayco488fbc52012-04-09 16:30:41 -070037 ofp.OFPFW_DL_VLAN | ofp.OFPFW_DL_VLAN_PCP,
Dan Talayco551befa2010-07-15 17:05:32 -070038 ofp.OFPFW_DL_SRC,
39 ofp.OFPFW_DL_DST,
Dan Talayco488fbc52012-04-09 16:30:41 -070040 (ofp.OFPFW_DL_TYPE | ofp.OFPFW_NW_SRC_ALL |
41 ofp.OFPFW_NW_DST_ALL | ofp.OFPFW_NW_TOS | ofp.OFPFW_NW_PROTO |
42 ofp.OFPFW_TP_SRC | ofp.OFPFW_TP_DST),
43 (ofp.OFPFW_NW_PROTO | ofp.OFPFW_TP_SRC | ofp.OFPFW_TP_DST),
Dan Talayco551befa2010-07-15 17:05:32 -070044 ofp.OFPFW_TP_SRC,
45 ofp.OFPFW_TP_DST,
Dan Talayco488fbc52012-04-09 16:30:41 -070046 ofp.OFPFW_NW_SRC_MASK,
47 ofp.OFPFW_NW_DST_MASK,
Dan Talayco551befa2010-07-15 17:05:32 -070048 ofp.OFPFW_DL_VLAN_PCP,
49 ofp.OFPFW_NW_TOS]
50
Dan Talayco488fbc52012-04-09 16:30:41 -070051NO_WILDCARD_VALUES = [(ofp.OFPFW_ALL ^ ofp.OFPFW_IN_PORT),
52 (ofp.OFPFW_ALL ^ ofp.OFPFW_DL_VLAN),
53 (ofp.OFPFW_ALL ^ ofp.OFPFW_DL_SRC),
54 (ofp.OFPFW_ALL ^ ofp.OFPFW_DL_DST),
55 (ofp.OFPFW_ALL ^ ofp.OFPFW_DL_TYPE),
56 (ofp.OFPFW_ALL ^ ofp.OFPFW_DL_TYPE ^ ofp.OFPFW_NW_PROTO),
57 (ofp.OFPFW_ALL ^ ofp.OFPFW_DL_TYPE ^ ofp.OFPFW_NW_PROTO ^
58 ofp.OFPFW_TP_SRC),
59 (ofp.OFPFW_ALL ^ ofp.OFPFW_DL_TYPE ^ ofp.OFPFW_NW_PROTO ^
60 ofp.OFPFW_TP_DST),
61 (ofp.OFPFW_ALL ^ ofp.OFPFW_DL_TYPE ^ ofp.OFPFW_NW_PROTO ^
62 ofp.OFPFW_NW_SRC_MASK),
63 (ofp.OFPFW_ALL ^ ofp.OFPFW_DL_TYPE ^ ofp.OFPFW_NW_PROTO ^
64 ofp.OFPFW_NW_DST_MASK),
65 (ofp.OFPFW_ALL ^ ofp.OFPFW_DL_VLAN ^ ofp.OFPFW_DL_VLAN_PCP),
66 (ofp.OFPFW_ALL ^ ofp.OFPFW_DL_TYPE ^ ofp.OFPFW_NW_PROTO ^
67 ofp.OFPFW_NW_TOS)]
68
Dan Talayco551befa2010-07-15 17:05:32 -070069MODIFY_ACTION_VALUES = [ofp.OFPAT_SET_VLAN_VID,
70 ofp.OFPAT_SET_VLAN_PCP,
71 ofp.OFPAT_STRIP_VLAN,
72 ofp.OFPAT_SET_DL_SRC,
73 ofp.OFPAT_SET_DL_DST,
74 ofp.OFPAT_SET_NW_SRC,
75 ofp.OFPAT_SET_NW_DST,
76 ofp.OFPAT_SET_NW_TOS,
77 ofp.OFPAT_SET_TP_SRC,
78 ofp.OFPAT_SET_TP_DST]
79
Dan Talayco21381562010-07-17 00:34:47 -070080TEST_VID_DEFAULT = 2
81
Rich Lane97e99652013-01-02 17:23:20 -080082@group('smoke')
Rich Laneb90a1c42012-10-05 09:16:05 -070083class DirectPacket(base_tests.SimpleDataPlane):
Dan Talayco5eba8442010-03-10 13:58:43 -080084 """
Dan Talayco2d0d49a2010-05-11 15:29:08 -070085 Send packet to single egress port
Dan Talayco5eba8442010-03-10 13:58:43 -080086
87 Generate a packet
88 Generate and install a matching flow
89 Add action to direct the packet to an egress port
90 Send the packet to ingress dataplane port
91 Verify the packet is received at the egress port only
92 """
93 def runTest(self):
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -070094 self.handleFlow()
95
96 def handleFlow(self, pkttype='TCP'):
Rich Lane477f4812012-10-04 22:49:00 -070097 of_ports = config["port_map"].keys()
Dan Talayco5eba8442010-03-10 13:58:43 -080098 of_ports.sort()
99 self.assertTrue(len(of_ports) > 1, "Not enough ports for test")
100
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700101 if (pkttype == 'ICMP'):
102 pkt = simple_icmp_packet()
103 else:
104 pkt = simple_tcp_packet()
Ed Swierk99a74de2012-08-22 06:40:54 -0700105 match = packet_to_flow_match(self, pkt)
Dan Talayco7dd6cd62010-03-16 15:02:35 -0700106 match.wildcards &= ~ofp.OFPFW_IN_PORT
Dan Talayco5eba8442010-03-10 13:58:43 -0800107 self.assertTrue(match is not None,
108 "Could not generate flow match from pkt")
109 act = action.action_output()
110
111 for idx in range(len(of_ports)):
Rich Lane32bf9482013-01-03 17:26:30 -0800112 delete_all_flows(self.controller)
Dan Talayco2e77a842010-05-12 15:39:46 -0700113
Dan Talayco5eba8442010-03-10 13:58:43 -0800114 ingress_port = of_ports[idx]
115 egress_port = of_ports[(idx + 1) % len(of_ports)]
Rich Lane9a003812012-10-04 17:17:59 -0700116 logging.info("Ingress " + str(ingress_port) +
Dan Talayco551befa2010-07-15 17:05:32 -0700117 " to egress " + str(egress_port))
Dan Talayco5eba8442010-03-10 13:58:43 -0800118
119 match.in_port = ingress_port
120
121 request = message.flow_mod()
122 request.match = match
Jeffrey Townsend2a300e42012-03-28 17:24:02 -0700123
Dan Talayco5eba8442010-03-10 13:58:43 -0800124 request.buffer_id = 0xffffffff
125 act.port = egress_port
Rich Lanee30455b2013-01-03 16:24:44 -0800126 request.actions.add(act)
Dan Talayco5eba8442010-03-10 13:58:43 -0800127
Rich Lane9a003812012-10-04 17:17:59 -0700128 logging.info("Inserting flow")
Rich Lane5c3151c2013-01-03 17:15:41 -0800129 self.controller.message_send(request)
Rich Lane3a261d52013-01-03 17:45:08 -0800130 do_barrier(self.controller)
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 Lane97e99652013-01-02 17:23:20 -0800151@group('smoke')
Rich Laneb90a1c42012-10-05 09:16:05 -0700152class DirectPacketController(base_tests.SimpleDataPlane):
Rich Lane51c23b32012-07-27 16:37:25 -0700153 """
154 Send packet to the controller port
155
156 Generate a packet
157 Generate and install a matching flow
158 Add action to direct the packet to the controller port
159 Send the packet to ingress dataplane port
160 Verify the packet is received at the controller port
161 """
162 def runTest(self):
163 self.handleFlow()
164
165 def handleFlow(self, pkttype='TCP'):
Rich Lane477f4812012-10-04 22:49:00 -0700166 of_ports = config["port_map"].keys()
Rich Lane51c23b32012-07-27 16:37:25 -0700167 of_ports.sort()
168 self.assertTrue(len(of_ports) > 0, "Not enough ports for test")
169
170 if (pkttype == 'ICMP'):
171 pkt = simple_icmp_packet()
172 else:
173 pkt = simple_tcp_packet()
Ed Swierk99a74de2012-08-22 06:40:54 -0700174 match = packet_to_flow_match(self, pkt)
Rich Lane51c23b32012-07-27 16:37:25 -0700175 match.wildcards &= ~ofp.OFPFW_IN_PORT
176 self.assertTrue(match is not None,
177 "Could not generate flow match from pkt")
178 act = action.action_output()
179
Rich Lane32bf9482013-01-03 17:26:30 -0800180 delete_all_flows(self.controller)
Rich Lane51c23b32012-07-27 16:37:25 -0700181
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
Rich Lanee30455b2013-01-03 16:24:44 -0800191 request.actions.add(act)
Rich Lane51c23b32012-07-27 16:37:25 -0700192
Rich Lane9a003812012-10-04 17:17:59 -0700193 logging.info("Inserting flow")
Rich Lane5c3151c2013-01-03 17:15:41 -0800194 self.controller.message_send(request)
Rich Lane3a261d52013-01-03 17:45:08 -0800195 do_barrier(self.controller)
Rich Lane51c23b32012-07-27 16:37:25 -0700196
Rich Lane9a003812012-10-04 17:17:59 -0700197 logging.info("Sending packet to dp port " +
Rich Lane51c23b32012-07-27 16:37:25 -0700198 str(ingress_port))
199 self.dataplane.send(ingress_port, str(pkt))
200
201 (response, raw) = self.controller.poll(ofp.OFPT_PACKET_IN)
202
203 self.assertTrue(response is not None,
204 'Packet in message not received by controller')
205 if not dataplane.match_exp_pkt(pkt, response.data):
Rich Lane9a003812012-10-04 17:17:59 -0700206 logging.debug("Sent %s" % format_packet(pkt))
207 logging.debug("Resp %s" % format_packet(response.data))
Rich Lane51c23b32012-07-27 16:37:25 -0700208 self.assertTrue(False,
209 'Response packet does not match send packet' +
210 ' for controller port')
211
Howard Pershf97840f2012-04-10 16:30:42 -0700212
Rich Laneb90a1c42012-10-05 09:16:05 -0700213class DirectPacketQueue(base_tests.SimpleDataPlane):
Howard Pershf97840f2012-04-10 16:30:42 -0700214 """
215 Send packet to single queue on single egress port
216
217 Generate a packet
218 Generate and install a matching flow
219 Add action to direct the packet to an egress port and queue
220 Send the packet to ingress dataplane port
221 Verify the packet is received at the egress port only
222 """
223 def runTest(self):
224 self.handleFlow()
225
Howard Persh670b5672012-04-13 09:08:29 -0700226 def portQueuesGet(self, queue_stats, port_num):
227 result = []
228 for qs in queue_stats.stats:
229 if qs.port_no != port_num:
230 continue
231 result.append(qs.queue_id)
232 return result
233
Howard Pershf97840f2012-04-10 16:30:42 -0700234 def handleFlow(self, pkttype='TCP'):
Rich Lane477f4812012-10-04 22:49:00 -0700235 of_ports = config["port_map"].keys()
Howard Pershf97840f2012-04-10 16:30:42 -0700236 of_ports.sort()
237 self.assertTrue(len(of_ports) > 1, "Not enough ports for test")
238
239 if (pkttype == 'ICMP'):
240 pkt = simple_icmp_packet()
241 else:
242 pkt = simple_tcp_packet()
Ed Swierk99a74de2012-08-22 06:40:54 -0700243 match = packet_to_flow_match(self, pkt)
Howard Pershf97840f2012-04-10 16:30:42 -0700244 match.wildcards &= ~ofp.OFPFW_IN_PORT
245 self.assertTrue(match is not None,
246 "Could not generate flow match from pkt")
247
Howard Persh670b5672012-04-13 09:08:29 -0700248 # Get queue stats from switch
249
250 request = message.queue_stats_request()
251 request.port_no = ofp.OFPP_ALL
252 request.queue_id = ofp.OFPQ_ALL
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700253 (queue_stats, p) = self.controller.transact(request)
Howard Persh670b5672012-04-13 09:08:29 -0700254 self.assertNotEqual(queue_stats, None, "Queue stats request failed")
255
256 act = action.action_enqueue()
Howard Pershf97840f2012-04-10 16:30:42 -0700257
258 for idx in range(len(of_ports)):
Howard Pershf97840f2012-04-10 16:30:42 -0700259 ingress_port = of_ports[idx]
260 egress_port = of_ports[(idx + 1) % len(of_ports)]
Howard Pershf97840f2012-04-10 16:30:42 -0700261
Howard Persh670b5672012-04-13 09:08:29 -0700262 for egress_queue_id in self.portQueuesGet(queue_stats, egress_port):
Rich Lane9a003812012-10-04 17:17:59 -0700263 logging.info("Ingress " + str(ingress_port)
Howard Persh670b5672012-04-13 09:08:29 -0700264 + " to egress " + str(egress_port)
265 + " queue " + str(egress_queue_id)
266 )
Howard Pershf97840f2012-04-10 16:30:42 -0700267
Rich Lane32bf9482013-01-03 17:26:30 -0800268 delete_all_flows(self.controller)
Howard Pershf97840f2012-04-10 16:30:42 -0700269
Howard Persh670b5672012-04-13 09:08:29 -0700270 match.in_port = ingress_port
271
272 request = message.flow_mod()
273 request.match = match
Howard Pershf97840f2012-04-10 16:30:42 -0700274
Howard Persh670b5672012-04-13 09:08:29 -0700275 request.buffer_id = 0xffffffff
276 act.port = egress_port
277 act.queue_id = egress_queue_id
Rich Lanee30455b2013-01-03 16:24:44 -0800278 request.actions.add(act)
Howard Pershf97840f2012-04-10 16:30:42 -0700279
Rich Lane9a003812012-10-04 17:17:59 -0700280 logging.info("Inserting flow")
Rich Lane5c3151c2013-01-03 17:15:41 -0800281 self.controller.message_send(request)
Rich Lane3a261d52013-01-03 17:45:08 -0800282 do_barrier(self.controller)
Howard Pershf97840f2012-04-10 16:30:42 -0700283
Howard Persh670b5672012-04-13 09:08:29 -0700284 # Get current stats for selected egress queue
Howard Pershf97840f2012-04-10 16:30:42 -0700285
Howard Persh670b5672012-04-13 09:08:29 -0700286 request = message.queue_stats_request()
287 request.port_no = egress_port
288 request.queue_id = egress_queue_id
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700289 (qs_before, p) = self.controller.transact(request)
Howard Persh670b5672012-04-13 09:08:29 -0700290 self.assertNotEqual(qs_before, None, "Queue stats request failed")
291
Rich Lane9a003812012-10-04 17:17:59 -0700292 logging.info("Sending packet to dp port " +
Howard Persh670b5672012-04-13 09:08:29 -0700293 str(ingress_port))
294 self.dataplane.send(ingress_port, str(pkt))
295
296 exp_pkt_arg = None
297 exp_port = None
Rich Lane477f4812012-10-04 22:49:00 -0700298 if config["relax"]:
Howard Persh670b5672012-04-13 09:08:29 -0700299 exp_pkt_arg = pkt
300 exp_port = egress_port
301
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700302 (rcv_port, rcv_pkt, pkt_time) = self.dataplane.poll(port_number=exp_port,
Howard Persh670b5672012-04-13 09:08:29 -0700303 exp_pkt=exp_pkt_arg)
304 self.assertTrue(rcv_pkt is not None, "Did not receive packet")
Rich Lane9a003812012-10-04 17:17:59 -0700305 logging.debug("Packet len " + str(len(rcv_pkt)) + " in on " +
Howard Persh670b5672012-04-13 09:08:29 -0700306 str(rcv_port))
307 self.assertEqual(rcv_port, egress_port, "Unexpected receive port")
308 self.assertEqual(str(pkt), str(rcv_pkt),
309 'Response packet does not match send packet')
310
Ed Swierkb8a86512012-04-18 18:45:58 -0700311 # FIXME: instead of sleeping, keep requesting queue stats until
312 # the expected queue counter increases or some large timeout is
313 # reached
314 time.sleep(2)
315
Howard Persh670b5672012-04-13 09:08:29 -0700316 # Get current stats for selected egress queue again
317
318 request = message.queue_stats_request()
319 request.port_no = egress_port
320 request.queue_id = egress_queue_id
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700321 (qs_after, p) = self.controller.transact(request)
Howard Persh670b5672012-04-13 09:08:29 -0700322 self.assertNotEqual(qs_after, None, "Queue stats request failed")
323
324 # Make sure that tx packet counter for selected egress queue was
325 # incremented
326
Ed Swierk22f59152012-04-17 16:36:47 -0700327 self.assertEqual(qs_after.stats[0].tx_packets, \
328 qs_before.stats[0].tx_packets + 1, \
Howard Persh670b5672012-04-13 09:08:29 -0700329 "Verification of egress queue tx packet count failed"
330 )
331
332
Rich Laneb90a1c42012-10-05 09:16:05 -0700333class DirectPacketControllerQueue(base_tests.SimpleDataPlane):
Ken Chiang899ff8e2012-05-23 18:26:12 -0700334 """
335 Send a packet from each of the openflow ports
336 to each of the queues configured on the controller port.
337 If no queues have been configured, no packets are sent.
Howard Pershf97840f2012-04-10 16:30:42 -0700338
Ken Chiang899ff8e2012-05-23 18:26:12 -0700339 Generate a packet
340 Generate and install a matching flow
341 Add action to direct the packet to one of the controller port queues
342 Send the packet to ingress dataplane port
343 Verify the packet is received on the controller port queue
344 """
345 def runTest(self):
346 self.handleFlow()
347
348 def portQueuesGet(self, queue_stats, port_num):
349 result = []
350 for qs in queue_stats.stats:
351 if qs.port_no != port_num:
352 continue
353 result.append(qs.queue_id)
354 return result
355
356 def handleFlow(self, pkttype='TCP'):
Rich Lane477f4812012-10-04 22:49:00 -0700357 of_ports = config["port_map"].keys()
Ken Chiang899ff8e2012-05-23 18:26:12 -0700358 of_ports.sort()
359 self.assertTrue(len(of_ports) > 1, "Not enough ports for test")
360
361 if (pkttype == 'ICMP'):
362 pkt = simple_icmp_packet()
363 else:
364 pkt = simple_tcp_packet()
Ed Swierk99a74de2012-08-22 06:40:54 -0700365 match = packet_to_flow_match(self, pkt)
Ken Chiang899ff8e2012-05-23 18:26:12 -0700366 match.wildcards &= ~ofp.OFPFW_IN_PORT
367 self.assertTrue(match is not None,
368 "Could not generate flow match from pkt")
369
370 # Get queue stats from switch
371
372 request = message.queue_stats_request()
373 request.port_no = ofp.OFPP_CONTROLLER
374 request.queue_id = ofp.OFPQ_ALL
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700375 (queue_stats, p) = self.controller.transact(request)
Ken Chiang899ff8e2012-05-23 18:26:12 -0700376 self.assertNotEqual(queue_stats, None, "Queue stats request failed")
Rich Laneb8c845a2012-12-31 17:23:51 -0800377 if queue_stats.header.type == ofp.OFPT_ERROR:
378 skip_message_emit(self, "Enqueue packet to controller")
379 return
Ken Chiang899ff8e2012-05-23 18:26:12 -0700380
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 Lane32bf9482013-01-03 17:26:30 -0800397 delete_all_flows(self.controller)
Ken Chiang899ff8e2012-05-23 18:26:12 -0700398
399 match.in_port = ingress_port
400
401 request = message.flow_mod()
402 request.match = match
403
404 request.buffer_id = 0xffffffff
405 act.port = egress_port
406 act.queue_id = egress_queue_id
Rich Lanee30455b2013-01-03 16:24:44 -0800407 request.actions.add(act)
Ken Chiang899ff8e2012-05-23 18:26:12 -0700408
Rich Lane9a003812012-10-04 17:17:59 -0700409 logging.info("Inserting flow")
Rich Lane5c3151c2013-01-03 17:15:41 -0800410 self.controller.message_send(request)
Rich Lane3a261d52013-01-03 17:45:08 -0800411 do_barrier(self.controller)
Ken Chiang899ff8e2012-05-23 18:26:12 -0700412
413 # Get current stats for selected egress queue
414
415 request = message.queue_stats_request()
416 request.port_no = egress_port
417 request.queue_id = egress_queue_id
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700418 (qs_before, p) = self.controller.transact(request)
Ken Chiang899ff8e2012-05-23 18:26:12 -0700419 self.assertNotEqual(qs_before, None, "Queue stats request failed")
420
Rich Lane9a003812012-10-04 17:17:59 -0700421 logging.info("Sending packet to dp port " +
Ken Chiang899ff8e2012-05-23 18:26:12 -0700422 str(ingress_port))
423 self.dataplane.send(ingress_port, str(pkt))
424
425 exp_pkt_arg = None
426 exp_port = None
427
Rich Lanee5779d32012-10-05 17:56:04 -0700428 count = 0
Ken Chiang899ff8e2012-05-23 18:26:12 -0700429 while True:
Dan Talaycoc689a792012-09-28 14:22:53 -0700430 (response, raw) = self.controller.poll(ofp.OFPT_PACKET_IN)
Ken Chiang899ff8e2012-05-23 18:26:12 -0700431 if not response: # Timeout
432 break
433 if dataplane.match_exp_pkt(pkt, response.data): # Got match
434 break
Rich Lane477f4812012-10-04 22:49:00 -0700435 if not config["relax"]: # Only one attempt to match
Ken Chiang899ff8e2012-05-23 18:26:12 -0700436 break
437 count += 1
438 if count > 10: # Too many tries
439 break
440
441 self.assertTrue(response is not None,
442 'Packet in message not received by controller')
443 if not dataplane.match_exp_pkt(pkt, response.data):
Rich Lane9a003812012-10-04 17:17:59 -0700444 logging.debug("Sent %s" % format_packet(pkt))
445 logging.debug("Resp %s" % format_packet(response.data))
Ken Chiang899ff8e2012-05-23 18:26:12 -0700446 self.assertTrue(False,
447 'Response packet does not match send packet' +
448 ' for controller port')
449
450 # FIXME: instead of sleeping, keep requesting queue stats until
451 # the expected queue counter increases or some large timeout is
452 # reached
453 time.sleep(2)
454
455 # Get current stats for selected egress queue again
456
457 request = message.queue_stats_request()
458 request.port_no = egress_port
459 request.queue_id = egress_queue_id
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700460 (qs_after, p) = self.controller.transact(request)
Ken Chiang899ff8e2012-05-23 18:26:12 -0700461 self.assertNotEqual(qs_after, None, "Queue stats request failed")
462
463 # Make sure that tx packet counter for selected egress queue was
464 # incremented
465
466 self.assertEqual(qs_after.stats[0].tx_packets, \
467 qs_before.stats[0].tx_packets + 1, \
468 "Verification of egress queue tx packet count failed"
469 )
470
Howard Pershf97840f2012-04-10 16:30:42 -0700471
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700472class DirectPacketICMP(DirectPacket):
473 """
474 Send ICMP packet to single egress port
475
476 Generate a ICMP packet
477 Generate and install a matching flow
478 Add action to direct the packet to an egress port
479 Send the packet to ingress dataplane port
480 Verify the packet is received at the egress port only
481 Difference from DirectPacket test is that sent packet is ICMP
482 """
483 def runTest(self):
484 self.handleFlow(pkttype='ICMP')
Dan Talayco2d0d49a2010-05-11 15:29:08 -0700485
Rich Laneb90a1c42012-10-05 09:16:05 -0700486class DirectTwoPorts(base_tests.SimpleDataPlane):
Dan Talayco2d0d49a2010-05-11 15:29:08 -0700487 """
488 Send packet to two egress ports
489
490 Generate a packet
491 Generate and install a matching flow
492 Add action to direct the packet to two egress ports
493 Send the packet to ingress dataplane port
494 Verify the packet is received at the two egress ports
495 """
496 def runTest(self):
Rich Lane477f4812012-10-04 22:49:00 -0700497 of_ports = config["port_map"].keys()
Dan Talayco2d0d49a2010-05-11 15:29:08 -0700498 of_ports.sort()
499 self.assertTrue(len(of_ports) > 2, "Not enough ports for test")
500
Dan Talayco2d0d49a2010-05-11 15:29:08 -0700501 pkt = simple_tcp_packet()
Ed Swierk99a74de2012-08-22 06:40:54 -0700502 match = packet_to_flow_match(self, pkt)
Dan Talayco2d0d49a2010-05-11 15:29:08 -0700503 match.wildcards &= ~ofp.OFPFW_IN_PORT
504 self.assertTrue(match is not None,
505 "Could not generate flow match from pkt")
506 act = action.action_output()
507
508 for idx in range(len(of_ports)):
Rich Lane32bf9482013-01-03 17:26:30 -0800509 delete_all_flows(self.controller)
Dan Talayco2e77a842010-05-12 15:39:46 -0700510
Dan Talayco2d0d49a2010-05-11 15:29:08 -0700511 ingress_port = of_ports[idx]
512 egress_port1 = of_ports[(idx + 1) % len(of_ports)]
513 egress_port2 = of_ports[(idx + 2) % len(of_ports)]
Rich Lane9a003812012-10-04 17:17:59 -0700514 logging.info("Ingress " + str(ingress_port) +
Dan Talayco2d0d49a2010-05-11 15:29:08 -0700515 " to egress " + str(egress_port1) + " and " +
516 str(egress_port2))
517
518 match.in_port = ingress_port
519
520 request = message.flow_mod()
521 request.match = match
522 request.buffer_id = 0xffffffff
523 act.port = egress_port1
Rich Lanee30455b2013-01-03 16:24:44 -0800524 request.actions.add(act)
Dan Talayco2d0d49a2010-05-11 15:29:08 -0700525 act.port = egress_port2
Rich Lanee30455b2013-01-03 16:24:44 -0800526 request.actions.add(act)
Rich Lane9a003812012-10-04 17:17:59 -0700527 # logging.info(request.show())
Dan Talayco2d0d49a2010-05-11 15:29:08 -0700528
Rich Lane9a003812012-10-04 17:17:59 -0700529 logging.info("Inserting flow")
Rich Lane5c3151c2013-01-03 17:15:41 -0800530 self.controller.message_send(request)
Rich Lane3a261d52013-01-03 17:45:08 -0800531 do_barrier(self.controller)
Dan Talayco2d0d49a2010-05-11 15:29:08 -0700532
Rich Lane9a003812012-10-04 17:17:59 -0700533 logging.info("Sending packet to dp port " +
Dan Talayco2d0d49a2010-05-11 15:29:08 -0700534 str(ingress_port))
535 self.dataplane.send(ingress_port, str(pkt))
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700536 yes_ports = set([egress_port1, egress_port2])
537 no_ports = set(of_ports).difference(yes_ports)
Dan Talayco2d0d49a2010-05-11 15:29:08 -0700538
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700539 receive_pkt_check(self.dataplane, pkt, yes_ports, no_ports,
Rich Lane2014f9b2012-10-05 15:29:40 -0700540 self)
Dan Talaycob0b0fdb2010-05-11 15:44:56 -0700541
Rich Laneb90a1c42012-10-05 09:16:05 -0700542class DirectMCNonIngress(base_tests.SimpleDataPlane):
Dan Talaycob0b0fdb2010-05-11 15:44:56 -0700543 """
544 Multicast to all non-ingress ports
545
546 Generate a packet
547 Generate and install a matching flow
548 Add action to direct the packet to all non-ingress ports
549 Send the packet to ingress dataplane port
550 Verify the packet is received at all non-ingress ports
551
552 Does not use the flood action
553 """
554 def runTest(self):
Rich Lane477f4812012-10-04 22:49:00 -0700555 of_ports = config["port_map"].keys()
Dan Talaycob0b0fdb2010-05-11 15:44:56 -0700556 of_ports.sort()
557 self.assertTrue(len(of_ports) > 2, "Not enough ports for test")
558
Dan Talaycob0b0fdb2010-05-11 15:44:56 -0700559 pkt = simple_tcp_packet()
Ed Swierk99a74de2012-08-22 06:40:54 -0700560 match = packet_to_flow_match(self, pkt)
Dan Talaycob0b0fdb2010-05-11 15:44:56 -0700561 match.wildcards &= ~ofp.OFPFW_IN_PORT
562 self.assertTrue(match is not None,
563 "Could not generate flow match from pkt")
564 act = action.action_output()
565
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700566 for ingress_port in of_ports:
Rich Lane32bf9482013-01-03 17:26:30 -0800567 delete_all_flows(self.controller)
Dan Talayco2e77a842010-05-12 15:39:46 -0700568
Rich Lane9a003812012-10-04 17:17:59 -0700569 logging.info("Ingress " + str(ingress_port) +
Dan Talaycob0b0fdb2010-05-11 15:44:56 -0700570 " all non-ingress ports")
Dan Talaycob0b0fdb2010-05-11 15:44:56 -0700571 match.in_port = ingress_port
572
573 request = message.flow_mod()
574 request.match = match
575 request.buffer_id = 0xffffffff
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700576 for egress_port in of_ports:
577 if egress_port == ingress_port:
Dan Talaycob0b0fdb2010-05-11 15:44:56 -0700578 continue
Dan Talaycob0b0fdb2010-05-11 15:44:56 -0700579 act.port = egress_port
Rich Lanee30455b2013-01-03 16:24:44 -0800580 request.actions.add(act)
Rich Lane9a003812012-10-04 17:17:59 -0700581 logging.debug(request.show())
Dan Talaycob0b0fdb2010-05-11 15:44:56 -0700582
Rich Lane9a003812012-10-04 17:17:59 -0700583 logging.info("Inserting flow")
Rich Lane5c3151c2013-01-03 17:15:41 -0800584 self.controller.message_send(request)
Rich Lane3a261d52013-01-03 17:45:08 -0800585 do_barrier(self.controller)
Dan Talaycob0b0fdb2010-05-11 15:44:56 -0700586
Rich Lane9a003812012-10-04 17:17:59 -0700587 logging.info("Sending packet to dp port " + str(ingress_port))
Dan Talaycob0b0fdb2010-05-11 15:44:56 -0700588 self.dataplane.send(ingress_port, str(pkt))
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700589 yes_ports = set(of_ports).difference([ingress_port])
590 receive_pkt_check(self.dataplane, pkt, yes_ports, [ingress_port],
Rich Lane2014f9b2012-10-05 15:29:40 -0700591 self)
Dan Talaycob0b0fdb2010-05-11 15:44:56 -0700592
Dan Talayco32fa6542010-05-11 15:54:08 -0700593
Rich Laneb90a1c42012-10-05 09:16:05 -0700594class DirectMC(base_tests.SimpleDataPlane):
Dan Talayco32fa6542010-05-11 15:54:08 -0700595 """
596 Multicast to all ports including ingress
597
598 Generate a packet
599 Generate and install a matching flow
600 Add action to direct the packet to all non-ingress ports
601 Send the packet to ingress dataplane port
602 Verify the packet is received at all ports
603
604 Does not use the flood action
605 """
606 def runTest(self):
Rich Lane477f4812012-10-04 22:49:00 -0700607 of_ports = config["port_map"].keys()
Dan Talayco32fa6542010-05-11 15:54:08 -0700608 of_ports.sort()
609 self.assertTrue(len(of_ports) > 2, "Not enough ports for test")
610
Dan Talayco32fa6542010-05-11 15:54:08 -0700611 pkt = simple_tcp_packet()
Ed Swierk99a74de2012-08-22 06:40:54 -0700612 match = packet_to_flow_match(self, pkt)
Dan Talayco32fa6542010-05-11 15:54:08 -0700613 match.wildcards &= ~ofp.OFPFW_IN_PORT
614 self.assertTrue(match is not None,
615 "Could not generate flow match from pkt")
616 act = action.action_output()
617
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700618 for ingress_port in of_ports:
Rich Lane32bf9482013-01-03 17:26:30 -0800619 delete_all_flows(self.controller)
Dan Talayco2e77a842010-05-12 15:39:46 -0700620
Rich Lane9a003812012-10-04 17:17:59 -0700621 logging.info("Ingress " + str(ingress_port) + " to all ports")
Dan Talayco32fa6542010-05-11 15:54:08 -0700622 match.in_port = ingress_port
623
624 request = message.flow_mod()
625 request.match = match
626 request.buffer_id = 0xffffffff
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700627 for egress_port in of_ports:
628 if egress_port == ingress_port:
Dan Talayco32fa6542010-05-11 15:54:08 -0700629 act.port = ofp.OFPP_IN_PORT
630 else:
631 act.port = egress_port
Rich Lanee30455b2013-01-03 16:24:44 -0800632 request.actions.add(act)
Rich Lane9a003812012-10-04 17:17:59 -0700633 # logging.info(request.show())
Dan Talayco2e77a842010-05-12 15:39:46 -0700634
Rich Lane9a003812012-10-04 17:17:59 -0700635 logging.info("Inserting flow")
Rich Lane5c3151c2013-01-03 17:15:41 -0800636 self.controller.message_send(request)
Rich Lane3a261d52013-01-03 17:45:08 -0800637 do_barrier(self.controller)
Dan Talayco2e77a842010-05-12 15:39:46 -0700638
Rich Lane9a003812012-10-04 17:17:59 -0700639 logging.info("Sending packet to dp port " + str(ingress_port))
Dan Talayco2e77a842010-05-12 15:39:46 -0700640 self.dataplane.send(ingress_port, str(pkt))
Rich Lane2014f9b2012-10-05 15:29:40 -0700641 receive_pkt_check(self.dataplane, pkt, of_ports, [], self)
Dan Talayco2e77a842010-05-12 15:39:46 -0700642
Rich Laneb90a1c42012-10-05 09:16:05 -0700643class Flood(base_tests.SimpleDataPlane):
Dan Talayco2e77a842010-05-12 15:39:46 -0700644 """
645 Flood to all ports except ingress
646
647 Generate a packet
648 Generate and install a matching flow
649 Add action to flood the packet
650 Send the packet to ingress dataplane port
651 Verify the packet is received at all other ports
652 """
653 def runTest(self):
Rich Lane477f4812012-10-04 22:49:00 -0700654 of_ports = config["port_map"].keys()
Dan Talayco2e77a842010-05-12 15:39:46 -0700655 of_ports.sort()
656 self.assertTrue(len(of_ports) > 1, "Not enough ports for test")
657
658 pkt = simple_tcp_packet()
Ed Swierk99a74de2012-08-22 06:40:54 -0700659 match = packet_to_flow_match(self, pkt)
Dan Talayco2e77a842010-05-12 15:39:46 -0700660 match.wildcards &= ~ofp.OFPFW_IN_PORT
661 self.assertTrue(match is not None,
662 "Could not generate flow match from pkt")
663 act = action.action_output()
664
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700665 for ingress_port in of_ports:
Rich Lane32bf9482013-01-03 17:26:30 -0800666 delete_all_flows(self.controller)
Dan Talayco2e77a842010-05-12 15:39:46 -0700667
Rich Lane9a003812012-10-04 17:17:59 -0700668 logging.info("Ingress " + str(ingress_port) + " to all ports")
Dan Talayco2e77a842010-05-12 15:39:46 -0700669 match.in_port = ingress_port
670
671 request = message.flow_mod()
672 request.match = match
673 request.buffer_id = 0xffffffff
674 act.port = ofp.OFPP_FLOOD
Rich Lanee30455b2013-01-03 16:24:44 -0800675 request.actions.add(act)
Rich Lane9a003812012-10-04 17:17:59 -0700676 logging.info(request.show())
Dan Talayco32fa6542010-05-11 15:54:08 -0700677
Rich Lane9a003812012-10-04 17:17:59 -0700678 logging.info("Inserting flow")
Rich Lane5c3151c2013-01-03 17:15:41 -0800679 self.controller.message_send(request)
Rich Lane3a261d52013-01-03 17:45:08 -0800680 do_barrier(self.controller)
Dan Talayco32fa6542010-05-11 15:54:08 -0700681
Rich Lane9a003812012-10-04 17:17:59 -0700682 logging.info("Sending packet to dp port " + str(ingress_port))
Dan Talayco32fa6542010-05-11 15:54:08 -0700683 self.dataplane.send(ingress_port, str(pkt))
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700684 yes_ports = set(of_ports).difference([ingress_port])
685 receive_pkt_check(self.dataplane, pkt, yes_ports, [ingress_port],
Rich Lane2014f9b2012-10-05 15:29:40 -0700686 self)
Dan Talayco3be5b062010-05-12 15:46:21 -0700687
Rich Laneb90a1c42012-10-05 09:16:05 -0700688class FloodPlusIngress(base_tests.SimpleDataPlane):
Dan Talayco3be5b062010-05-12 15:46:21 -0700689 """
690 Flood to all ports plus send to ingress port
691
692 Generate a packet
693 Generate and install a matching flow
694 Add action to flood the packet
695 Add action to send to ingress port
696 Send the packet to ingress dataplane port
697 Verify the packet is received at all other ports
698 """
699 def runTest(self):
Rich Lane477f4812012-10-04 22:49:00 -0700700 of_ports = config["port_map"].keys()
Dan Talayco3be5b062010-05-12 15:46:21 -0700701 of_ports.sort()
702 self.assertTrue(len(of_ports) > 1, "Not enough ports for test")
703
704 pkt = simple_tcp_packet()
Ed Swierk99a74de2012-08-22 06:40:54 -0700705 match = packet_to_flow_match(self, pkt)
Dan Talayco3be5b062010-05-12 15:46:21 -0700706 match.wildcards &= ~ofp.OFPFW_IN_PORT
707 self.assertTrue(match is not None,
708 "Could not generate flow match from pkt")
709 act = action.action_output()
710
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700711 for ingress_port in of_ports:
Rich Lane32bf9482013-01-03 17:26:30 -0800712 delete_all_flows(self.controller)
Dan Talayco3be5b062010-05-12 15:46:21 -0700713
Rich Lane9a003812012-10-04 17:17:59 -0700714 logging.info("Ingress " + str(ingress_port) + " to all ports")
Dan Talayco3be5b062010-05-12 15:46:21 -0700715 match.in_port = ingress_port
716
717 request = message.flow_mod()
718 request.match = match
719 request.buffer_id = 0xffffffff
720 act.port = ofp.OFPP_FLOOD
Rich Lanee30455b2013-01-03 16:24:44 -0800721 request.actions.add(act)
Dan Talayco4aa13122010-05-12 15:54:44 -0700722 act.port = ofp.OFPP_IN_PORT
Rich Lanee30455b2013-01-03 16:24:44 -0800723 request.actions.add(act)
Rich Lane9a003812012-10-04 17:17:59 -0700724 logging.info(request.show())
Dan Talayco4aa13122010-05-12 15:54:44 -0700725
Rich Lane9a003812012-10-04 17:17:59 -0700726 logging.info("Inserting flow")
Rich Lane5c3151c2013-01-03 17:15:41 -0800727 self.controller.message_send(request)
Rich Lane3a261d52013-01-03 17:45:08 -0800728 do_barrier(self.controller)
Dan Talayco4aa13122010-05-12 15:54:44 -0700729
Rich Lane9a003812012-10-04 17:17:59 -0700730 logging.info("Sending packet to dp port " + str(ingress_port))
Dan Talayco4aa13122010-05-12 15:54:44 -0700731 self.dataplane.send(ingress_port, str(pkt))
Rich Lane2014f9b2012-10-05 15:29:40 -0700732 receive_pkt_check(self.dataplane, pkt, of_ports, [], self)
Dan Talayco4aa13122010-05-12 15:54:44 -0700733
Rich Laneb90a1c42012-10-05 09:16:05 -0700734class All(base_tests.SimpleDataPlane):
Dan Talayco4aa13122010-05-12 15:54:44 -0700735 """
736 Send to OFPP_ALL port
737
738 Generate a packet
739 Generate and install a matching flow
740 Add action to forward to OFPP_ALL
741 Send the packet to ingress dataplane port
742 Verify the packet is received at all other ports
743 """
744 def runTest(self):
Rich Lane477f4812012-10-04 22:49:00 -0700745 of_ports = config["port_map"].keys()
Dan Talayco4aa13122010-05-12 15:54:44 -0700746 of_ports.sort()
747 self.assertTrue(len(of_ports) > 1, "Not enough ports for test")
748
749 pkt = simple_tcp_packet()
Ed Swierk99a74de2012-08-22 06:40:54 -0700750 match = packet_to_flow_match(self, pkt)
Dan Talayco4aa13122010-05-12 15:54:44 -0700751 match.wildcards &= ~ofp.OFPFW_IN_PORT
752 self.assertTrue(match is not None,
753 "Could not generate flow match from pkt")
754 act = action.action_output()
755
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700756 for ingress_port in of_ports:
Rich Lane32bf9482013-01-03 17:26:30 -0800757 delete_all_flows(self.controller)
Dan Talayco4aa13122010-05-12 15:54:44 -0700758
Rich Lane9a003812012-10-04 17:17:59 -0700759 logging.info("Ingress " + str(ingress_port) + " to all ports")
Dan Talayco4aa13122010-05-12 15:54:44 -0700760 match.in_port = ingress_port
761
762 request = message.flow_mod()
763 request.match = match
764 request.buffer_id = 0xffffffff
765 act.port = ofp.OFPP_ALL
Rich Lanee30455b2013-01-03 16:24:44 -0800766 request.actions.add(act)
Rich Lane9a003812012-10-04 17:17:59 -0700767 logging.info(request.show())
Dan Talayco4aa13122010-05-12 15:54:44 -0700768
Rich Lane9a003812012-10-04 17:17:59 -0700769 logging.info("Inserting flow")
Rich Lane5c3151c2013-01-03 17:15:41 -0800770 self.controller.message_send(request)
Rich Lane3a261d52013-01-03 17:45:08 -0800771 do_barrier(self.controller)
Dan Talayco4aa13122010-05-12 15:54:44 -0700772
Rich Lane9a003812012-10-04 17:17:59 -0700773 logging.info("Sending packet to dp port " + str(ingress_port))
Dan Talayco4aa13122010-05-12 15:54:44 -0700774 self.dataplane.send(ingress_port, str(pkt))
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700775 yes_ports = set(of_ports).difference([ingress_port])
776 receive_pkt_check(self.dataplane, pkt, yes_ports, [ingress_port],
Rich Lane2014f9b2012-10-05 15:29:40 -0700777 self)
Dan Talayco4aa13122010-05-12 15:54:44 -0700778
Rich Laneb90a1c42012-10-05 09:16:05 -0700779class AllPlusIngress(base_tests.SimpleDataPlane):
Dan Talayco4aa13122010-05-12 15:54:44 -0700780 """
781 Send to OFPP_ALL port and ingress port
782
783 Generate a packet
784 Generate and install a matching flow
785 Add action to forward to OFPP_ALL
786 Add action to forward to ingress port
787 Send the packet to ingress dataplane port
788 Verify the packet is received at all other ports
789 """
790 def runTest(self):
Rich Lane477f4812012-10-04 22:49:00 -0700791 of_ports = config["port_map"].keys()
Dan Talayco4aa13122010-05-12 15:54:44 -0700792 of_ports.sort()
793 self.assertTrue(len(of_ports) > 1, "Not enough ports for test")
794
795 pkt = simple_tcp_packet()
Ed Swierk99a74de2012-08-22 06:40:54 -0700796 match = packet_to_flow_match(self, pkt)
Dan Talayco4aa13122010-05-12 15:54:44 -0700797 match.wildcards &= ~ofp.OFPFW_IN_PORT
798 self.assertTrue(match is not None,
799 "Could not generate flow match from pkt")
800 act = action.action_output()
801
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700802 for ingress_port in of_ports:
Rich Lane32bf9482013-01-03 17:26:30 -0800803 delete_all_flows(self.controller)
Dan Talayco4aa13122010-05-12 15:54:44 -0700804
Rich Lane9a003812012-10-04 17:17:59 -0700805 logging.info("Ingress " + str(ingress_port) + " to all ports")
Dan Talayco4aa13122010-05-12 15:54:44 -0700806 match.in_port = ingress_port
807
808 request = message.flow_mod()
809 request.match = match
810 request.buffer_id = 0xffffffff
811 act.port = ofp.OFPP_ALL
Rich Lanee30455b2013-01-03 16:24:44 -0800812 request.actions.add(act)
Dan Talayco3be5b062010-05-12 15:46:21 -0700813 act.port = ofp.OFPP_IN_PORT
Rich Lanee30455b2013-01-03 16:24:44 -0800814 request.actions.add(act)
Rich Lane9a003812012-10-04 17:17:59 -0700815 logging.info(request.show())
Dan Talayco3be5b062010-05-12 15:46:21 -0700816
Rich Lane9a003812012-10-04 17:17:59 -0700817 logging.info("Inserting flow")
Rich Lane5c3151c2013-01-03 17:15:41 -0800818 self.controller.message_send(request)
Rich Lane3a261d52013-01-03 17:45:08 -0800819 do_barrier(self.controller)
Dan Talayco3be5b062010-05-12 15:46:21 -0700820
Rich Lane9a003812012-10-04 17:17:59 -0700821 logging.info("Sending packet to dp port " + str(ingress_port))
Dan Talayco3be5b062010-05-12 15:46:21 -0700822 self.dataplane.send(ingress_port, str(pkt))
Rich Lane2014f9b2012-10-05 15:29:40 -0700823 receive_pkt_check(self.dataplane, pkt, of_ports, [], self)
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700824
Rich Laneb90a1c42012-10-05 09:16:05 -0700825class FloodMinusPort(base_tests.SimpleDataPlane):
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700826 """
827 Config port with No_Flood and test Flood action
828
829 Generate a packet
830 Generate a matching flow
831 Add action to forward to OFPP_ALL
832 Set port to no-flood
833 Send the packet to ingress dataplane port
834 Verify the packet is received at all other ports except
835 the ingress port and the no_flood port
836 """
837 def runTest(self):
Rich Lane477f4812012-10-04 22:49:00 -0700838 of_ports = config["port_map"].keys()
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700839 of_ports.sort()
840 self.assertTrue(len(of_ports) > 2, "Not enough ports for test")
841
842 pkt = simple_tcp_packet()
Ed Swierk99a74de2012-08-22 06:40:54 -0700843 match = packet_to_flow_match(self, pkt)
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700844 match.wildcards &= ~ofp.OFPFW_IN_PORT
845 self.assertTrue(match is not None,
846 "Could not generate flow match from pkt")
847 act = action.action_output()
848
Rich Lane4b9e38c2012-12-06 16:33:20 -0800849 # Clear OFPPC_NO_FLOOD on each port
850 for of_port in of_ports:
851 rv = port_config_set(self.controller, of_port,
852 0, ofp.OFPPC_NO_FLOOD)
853 self.assertEqual(rv, 0, "Failed to set port config")
854
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700855 for idx in range(len(of_ports)):
Rich Lane32bf9482013-01-03 17:26:30 -0800856 delete_all_flows(self.controller)
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700857
858 ingress_port = of_ports[idx]
859 no_flood_idx = (idx + 1) % len(of_ports)
860 no_flood_port = of_ports[no_flood_idx]
861 rv = port_config_set(self.controller, no_flood_port,
Rich Lane9a003812012-10-04 17:17:59 -0700862 ofp.OFPPC_NO_FLOOD, ofp.OFPPC_NO_FLOOD)
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700863 self.assertEqual(rv, 0, "Failed to set port config")
864
865 match.in_port = ingress_port
866
867 request = message.flow_mod()
868 request.match = match
869 request.buffer_id = 0xffffffff
870 act.port = ofp.OFPP_FLOOD
Rich Lanee30455b2013-01-03 16:24:44 -0800871 request.actions.add(act)
Rich Lane9a003812012-10-04 17:17:59 -0700872 logging.info(request.show())
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700873
Rich Lane9a003812012-10-04 17:17:59 -0700874 logging.info("Inserting flow")
Rich Lane5c3151c2013-01-03 17:15:41 -0800875 self.controller.message_send(request)
Rich Lane3a261d52013-01-03 17:45:08 -0800876 do_barrier(self.controller)
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700877
Rich Lane9a003812012-10-04 17:17:59 -0700878 logging.info("Sending packet to dp port " + str(ingress_port))
879 logging.info("No flood port is " + str(no_flood_port))
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700880 self.dataplane.send(ingress_port, str(pkt))
881 no_ports = set([ingress_port, no_flood_port])
882 yes_ports = set(of_ports).difference(no_ports)
Rich Lane2014f9b2012-10-05 15:29:40 -0700883 receive_pkt_check(self.dataplane, pkt, yes_ports, no_ports, self)
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700884
885 # Turn no flood off again
886 rv = port_config_set(self.controller, no_flood_port,
Rich Lane9a003812012-10-04 17:17:59 -0700887 0, ofp.OFPPC_NO_FLOOD)
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700888 self.assertEqual(rv, 0, "Failed to reset port config")
Rich Lane3a261d52013-01-03 17:45:08 -0800889 do_barrier(self.controller)
Rich Lane4ecc1f42012-12-06 16:35:24 -0800890
891 # Check that packets are now flooded to no_flood_port
892 logging.info("Sending packet to dp port " + str(ingress_port))
893 self.dataplane.send(ingress_port, str(pkt))
894 no_ports = set([ingress_port])
895 yes_ports = set(of_ports).difference(no_ports)
896 receive_pkt_check(self.dataplane, pkt, yes_ports, no_ports, self)
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700897
898 #@todo Should check no other packets received
899
Dan Talayco21381562010-07-17 00:34:47 -0700900
901
Dan Talayco551befa2010-07-15 17:05:32 -0700902################################################################
903
Rich Laneb90a1c42012-10-05 09:16:05 -0700904class BaseMatchCase(base_tests.SimpleDataPlane):
Dan Talayco551befa2010-07-15 17:05:32 -0700905 def setUp(self):
Rich Laneb90a1c42012-10-05 09:16:05 -0700906 base_tests.SimpleDataPlane.setUp(self)
Dan Talayco551befa2010-07-15 17:05:32 -0700907 def runTest(self):
Rich Lane9a003812012-10-04 17:17:59 -0700908 logging.info("BaseMatchCase")
Dan Talayco551befa2010-07-15 17:05:32 -0700909
910class ExactMatch(BaseMatchCase):
Tatsuya Yabe6a6f38a2010-05-22 23:48:04 -0700911 """
Dan Talayco551befa2010-07-15 17:05:32 -0700912 Exercise exact matching for all port pairs
Tatsuya Yabe6a6f38a2010-05-22 23:48:04 -0700913
914 Generate a packet
915 Generate and install a matching flow without wildcard mask
916 Add action to forward to a port
917 Send the packet to the port
918 Verify the packet is received at all other ports (one port at a time)
Tatsuya Yabe6a6f38a2010-05-22 23:48:04 -0700919 """
Tatsuya Yabe0718ad32010-05-24 15:22:10 -0700920
Tatsuya Yabe6a6f38a2010-05-22 23:48:04 -0700921 def runTest(self):
Rich Lane477f4812012-10-04 22:49:00 -0700922 flow_match_test(self, config["port_map"])
Tatsuya Yabe6a6f38a2010-05-22 23:48:04 -0700923
Dan Talayco551befa2010-07-15 17:05:32 -0700924class ExactMatchTagged(BaseMatchCase):
925 """
926 Exact match for all port pairs with tagged pkts
927 """
Tatsuya Yabe6a6f38a2010-05-22 23:48:04 -0700928
Dan Talayco551befa2010-07-15 17:05:32 -0700929 def runTest(self):
Rich Lane2014f9b2012-10-05 15:29:40 -0700930 vid = test_param_get('vid', default=TEST_VID_DEFAULT)
Rich Lane477f4812012-10-04 22:49:00 -0700931 flow_match_test(self, config["port_map"], dl_vlan=vid)
Tatsuya Yabe6a6f38a2010-05-22 23:48:04 -0700932
Rich Lane0a4f6372013-01-02 14:40:22 -0800933@disabled
Dan Talayco551befa2010-07-15 17:05:32 -0700934class ExactMatchTaggedMany(BaseMatchCase):
935 """
936 ExactMatchTagged with many VLANS
937 """
Tatsuya Yabe6a6f38a2010-05-22 23:48:04 -0700938
Dan Talayco551befa2010-07-15 17:05:32 -0700939 def runTest(self):
Dan Talayco21381562010-07-17 00:34:47 -0700940 for vid in range(2,100,10):
Rich Lane477f4812012-10-04 22:49:00 -0700941 flow_match_test(self, config["port_map"], dl_vlan=vid, max_test=5)
Dan Talayco551befa2010-07-15 17:05:32 -0700942 for vid in range(100,4000,389):
Rich Lane477f4812012-10-04 22:49:00 -0700943 flow_match_test(self, config["port_map"], dl_vlan=vid, max_test=5)
944 flow_match_test(self, config["port_map"], dl_vlan=4094, max_test=5)
Tatsuya Yabecdf575e2010-05-25 16:56:38 -0700945
Jeffrey Townsend2a300e42012-03-28 17:24:02 -0700946class SingleWildcardMatchPriority(BaseMatchCase):
Jeffrey Townsend50c82462012-03-28 18:26:14 -0700947 """
948 SingleWildcardMatchPriority
949 """
Jeffrey Townsend2a300e42012-03-28 17:24:02 -0700950
Jeffrey Townsend50c82462012-03-28 18:26:14 -0700951 def _Init(self):
Jeffrey Townsend2a300e42012-03-28 17:24:02 -0700952 self.pkt = simple_tcp_packet()
953 self.flowMsgs = {}
954
Jeffrey Townsend50c82462012-03-28 18:26:14 -0700955 def _ClearTable(self):
Rich Lane32bf9482013-01-03 17:26:30 -0800956 delete_all_flows(self.controller)
Rich Lane3a261d52013-01-03 17:45:08 -0800957 do_barrier(self.controller)
Jeffrey Townsend50c82462012-03-28 18:26:14 -0700958
959 def runTest(self):
960
961 self._Init()
Rich Lane477f4812012-10-04 22:49:00 -0700962 of_ports = config["port_map"].keys()
Jeffrey Townsend2a300e42012-03-28 17:24:02 -0700963 of_ports.sort()
964
965 # Delete the initial flow table
Jeffrey Townsend50c82462012-03-28 18:26:14 -0700966 self._ClearTable()
Jeffrey Townsend2a300e42012-03-28 17:24:02 -0700967
968 # Run several combinations, each at lower priority settings.
969 # At the end of each call to runPrioFlows(), the table should
970 # be empty. If its not, we'll catch it as the priorities decreases
971 portA = of_ports[0]
972 portB = of_ports[1]
973 portC = of_ports[2]
974
975 # TODO -- these priority numbers should be validated somehow?
976 self.runPrioFlows(portA, portB, portC, 1000, 999)
977 self.runPrioFlows(portB, portC, portA, 998, 997)
978 self.runPrioFlows(portC, portA, portB, 996, 995)
979 self.runPrioFlows(portA, portC, portB, 994, 993)
980
981
Jeffrey Townsend50c82462012-03-28 18:26:14 -0700982
983 def runPrioFlows(self, portA, portB, portC, prioHigher, prioLower,
984 clearTable=False):
Jeffrey Townsend2a300e42012-03-28 17:24:02 -0700985
Jeffrey Townsend50c82462012-03-28 18:26:14 -0700986 if clearTable:
987 self._ClearTable()
Jeffrey Townsend2a300e42012-03-28 17:24:02 -0700988
989 # Sanity check flow at lower priority from pA to pB
Rich Lane9a003812012-10-04 17:17:59 -0700990 logging.info("runPrioFlows(pA=%d,pB=%d,pC=%d,ph=%d,pl=%d"
Jeffrey Townsend2a300e42012-03-28 17:24:02 -0700991 % (portA, portB, portC, prioHigher, prioLower))
992
Jeffrey Townsend2a300e42012-03-28 17:24:02 -0700993 # Sanity check flow at lower priority from pA to pC
994 self.installFlow(prioLower, portA, portC)
995 self.verifyFlow(portA, portC)
996 self.removeFlow(prioLower)
997
998 # Install and verify pA->pB @ prioLower
999 self.installFlow(prioLower, portA, portB)
1000 self.verifyFlow(portA, portB)
1001
1002 # Install and verify pA->pC @ prioHigher, should override pA->pB
1003 self.installFlow(prioHigher, portA, portC)
1004 self.verifyFlow(portA, portC)
1005 # remove pA->pC
1006 self.removeFlow(prioHigher)
Jeffrey Townsend2a300e42012-03-28 17:24:02 -07001007 # Old flow pA -> pB @ prioLower should still be active
1008 self.verifyFlow(portA, portB)
1009 self.removeFlow(prioLower)
1010
1011 # Table should be empty at this point, leave it alone as
1012 # an assumption for future test runs
1013
1014
1015
Ed Swierk99a74de2012-08-22 06:40:54 -07001016 def installFlow(self, prio, inp, egp,
Jeffrey Townsend8364b162012-04-12 13:45:40 -07001017 wildcards=ofp.OFPFW_DL_SRC):
Ed Swierk99a74de2012-08-22 06:40:54 -07001018 wildcards |= required_wildcards(self)
Jeffrey Townsend2a300e42012-03-28 17:24:02 -07001019 request = flow_msg_create(self, self.pkt, ing_port=inp,
Jeffrey Townsend8364b162012-04-12 13:45:40 -07001020 wildcards=wildcards,
Jeffrey Townsend2a300e42012-03-28 17:24:02 -07001021 egr_ports=egp)
1022 request.priority = prio
Rich Lane9a003812012-10-04 17:17:59 -07001023 logging.debug("Install flow with priority " + str(prio))
Jeffrey Townsend50c82462012-03-28 18:26:14 -07001024 flow_msg_install(self, request, clear_table_override=False)
Jeffrey Townsend2a300e42012-03-28 17:24:02 -07001025 self.flowMsgs[prio] = request
1026
1027 def removeFlow(self, prio):
1028 if self.flowMsgs.has_key(prio):
1029 msg = self.flowMsgs[prio]
1030 msg.command = ofp.OFPFC_DELETE_STRICT
1031 # This *must* be set for DELETE
1032 msg.out_port = ofp.OFPP_NONE
Rich Lane9a003812012-10-04 17:17:59 -07001033 logging.debug("Remove flow with priority " + str(prio))
Jeffrey Townsend2a300e42012-03-28 17:24:02 -07001034 self.controller.message_send(msg)
Rich Lane3a261d52013-01-03 17:45:08 -08001035 do_barrier(self.controller)
Jeffrey Townsend50c82462012-03-28 18:26:14 -07001036 else:
1037 raise Exception("Not initialized")
Jeffrey Townsend2a300e42012-03-28 17:24:02 -07001038
1039
Jeffrey Townsend8364b162012-04-12 13:45:40 -07001040 def verifyFlow(self, inp, egp, pkt=None):
1041 if pkt == None:
1042 pkt = self.pkt
1043
Rich Lane9a003812012-10-04 17:17:59 -07001044 logging.info("Pkt match test: " + str(inp) + " to " + str(egp))
1045 logging.debug("Send packet: " + str(inp) + " to " + str(egp))
Jeffrey Townsend8364b162012-04-12 13:45:40 -07001046 self.dataplane.send(inp, str(pkt))
1047 receive_pkt_verify(self, egp, pkt, inp)
Jeffrey Townsend2a300e42012-03-28 17:24:02 -07001048
1049
1050
Jeffrey Townsend50c82462012-03-28 18:26:14 -07001051class SingleWildcardMatchPriorityInsertModifyDelete(SingleWildcardMatchPriority):
1052
1053 def runTest(self):
1054
1055 self._Init()
1056
Rich Lane477f4812012-10-04 22:49:00 -07001057 of_ports = config["port_map"].keys()
Jeffrey Townsend50c82462012-03-28 18:26:14 -07001058 of_ports.sort()
1059
1060 # Install an entry from 0 -> 1 @ prio 1000
1061 self._ClearTable()
1062 self.installFlow(1000, of_ports[0], of_ports[1])
1063 self.verifyFlow(of_ports[0], of_ports[1])
1064 self.installFlow(1000, of_ports[1], of_ports[0])
1065 self.verifyFlow(of_ports[1], of_ports[0])
1066 self.installFlow(1001, of_ports[0], of_ports[1])
1067 self.verifyFlow(of_ports[0], of_ports[1])
1068 self.installFlow(1001, of_ports[1], of_ports[0])
1069 self.verifyFlow(of_ports[1], of_ports[0])
1070 self.removeFlow(1001)
1071 self.verifyFlow(of_ports[0], of_ports[1])
1072 self.removeFlow(1000)
1073
1074
1075
Jeffrey Townsend8364b162012-04-12 13:45:40 -07001076class WildcardPriority(SingleWildcardMatchPriority):
Ken Chiang38d7a152012-05-24 15:33:50 -07001077 """
1078 1. Add wildcard flow, verify packet received.
Rich Lane0a78fbd2012-12-31 16:25:04 -08001079 2. Add wildcard flow with higher priority, verify packet received
Ken Chiang38d7a152012-05-24 15:33:50 -07001080 on port specified by this flow.
Rich Lane0a78fbd2012-12-31 16:25:04 -08001081 3. Add wildcard flow with lower priority, verify packet received
Rich Laneb8392082012-11-21 15:52:54 -08001082 on port specified by the highest priority flow.
Ken Chiang38d7a152012-05-24 15:33:50 -07001083 """
Jeffrey Townsend8364b162012-04-12 13:45:40 -07001084
1085 def runTest(self):
Jeffrey Townsend50c82462012-03-28 18:26:14 -07001086
Jeffrey Townsend8364b162012-04-12 13:45:40 -07001087 self._Init()
1088
Rich Lane477f4812012-10-04 22:49:00 -07001089 of_ports = config["port_map"].keys()
Jeffrey Townsend8364b162012-04-12 13:45:40 -07001090 of_ports.sort()
1091
1092 self._ClearTable()
Ken Chiang38d7a152012-05-24 15:33:50 -07001093
1094 # Install a flow with wildcards
1095 self.installFlow(999, of_ports[0], of_ports[1],
1096 wildcards=ofp.OFPFW_DL_DST)
Jeffrey Townsend8364b162012-04-12 13:45:40 -07001097 self.verifyFlow(of_ports[0], of_ports[1])
Rich Lane0a78fbd2012-12-31 16:25:04 -08001098 # Install a flow with wildcards with higher priority
1099 self.installFlow(1000, of_ports[0], of_ports[2],
1100 wildcards=ofp.OFPFW_DL_DST)
Jeffrey Townsend8364b162012-04-12 13:45:40 -07001101 self.verifyFlow(of_ports[0], of_ports[2])
Rich Lane0a78fbd2012-12-31 16:25:04 -08001102 # Install a flow with wildcards with lower priority
Rich Laneb8392082012-11-21 15:52:54 -08001103 self.installFlow(999, of_ports[0], of_ports[1],
1104 wildcards=ofp.OFPFW_DL_SRC)
Rich Lane0a78fbd2012-12-31 16:25:04 -08001105 self.verifyFlow(of_ports[0], of_ports[2])
Jeffrey Townsend8364b162012-04-12 13:45:40 -07001106
1107
Rich Lane97e99652013-01-02 17:23:20 -08001108@group("smoke")
Ken Chiang3978f242012-06-13 14:14:09 -07001109class WildcardPriorityWithDelete(SingleWildcardMatchPriority):
Ken Chiang38d7a152012-05-24 15:33:50 -07001110 """
Rich Lane0a78fbd2012-12-31 16:25:04 -08001111 1. Add wildcard match flow, verify packet received.
Ken Chiang38d7a152012-05-24 15:33:50 -07001112 2. Add wildcard flow with higher priority, verify packet received on port
1113 specified by this flow.
Rich Lane0a78fbd2012-12-31 16:25:04 -08001114 3. Add wildcard flow with even higher priority, verify packet received
Ken Chiang38d7a152012-05-24 15:33:50 -07001115 on port specified by this flow.
1116 4. Delete lowest priority flow, verify packet received on port specified
1117 by highest priority flow.
1118 5. Delete highest priority flow, verify packet received on port specified
1119 by remaining flow.
1120 """
1121
1122 def runTest(self):
1123
1124 self._Init()
1125
Rich Lane477f4812012-10-04 22:49:00 -07001126 of_ports = config["port_map"].keys()
Ken Chiang38d7a152012-05-24 15:33:50 -07001127 of_ports.sort()
1128
1129 self._ClearTable()
1130
Rich Lane0a78fbd2012-12-31 16:25:04 -08001131 # Install a flow with wildcards
1132 self.installFlow(250, of_ports[0], of_ports[1],
1133 wildcards=ofp.OFPFW_DL_DST)
Ken Chiang38d7a152012-05-24 15:33:50 -07001134 self.verifyFlow(of_ports[0], of_ports[1])
1135 # Install a flow with wildcards of higher priority
1136 self.installFlow(1250, of_ports[0], of_ports[2],
1137 wildcards=ofp.OFPFW_DL_DST)
1138 self.verifyFlow(of_ports[0], of_ports[2])
Rich Lane0a78fbd2012-12-31 16:25:04 -08001139 # Install a flow with wildcards with even higher priority
1140 self.installFlow(2001, of_ports[0], of_ports[3],
1141 wildcards=ofp.OFPFW_DL_DST)
Ken Chiang38d7a152012-05-24 15:33:50 -07001142 self.verifyFlow(of_ports[0], of_ports[3])
1143 # Delete lowest priority flow
1144 self.removeFlow(250)
1145 self.verifyFlow(of_ports[0], of_ports[3])
1146 # Delete highest priority flow
1147 self.removeFlow(2001)
1148 self.verifyFlow(of_ports[0], of_ports[2])
1149
Jeffrey Townsend8364b162012-04-12 13:45:40 -07001150
Dan Talayco551befa2010-07-15 17:05:32 -07001151class SingleWildcardMatch(BaseMatchCase):
Tatsuya Yabe6a6f38a2010-05-22 23:48:04 -07001152 """
1153 Exercise wildcard matching for all ports
1154
1155 Generate a packet
1156 Generate and install a matching flow with wildcard mask
1157 Add action to forward to a port
1158 Send the packet to the port
1159 Verify the packet is received at all other ports (one port at a time)
Tatsuya Yabe0718ad32010-05-24 15:22:10 -07001160 Verify flow_expiration message is correct when command option is set
Tatsuya Yabe6a6f38a2010-05-22 23:48:04 -07001161 """
Tatsuya Yabe0718ad32010-05-24 15:22:10 -07001162 def runTest(self):
Rich Lane2014f9b2012-10-05 15:29:40 -07001163 vid = test_param_get('vid', default=TEST_VID_DEFAULT)
Dan Talayco551befa2010-07-15 17:05:32 -07001164 for wc in WILDCARD_VALUES:
Ed Swierk99a74de2012-08-22 06:40:54 -07001165 wc |= required_wildcards(self)
Dan Talayco4431d542012-03-21 16:42:16 -07001166 if wc & ofp.OFPFW_DL_VLAN:
Ken Chiang5be06dd2012-04-03 10:03:50 -07001167 # Set nonzero VLAN id to avoid sending priority-tagged packet
1168 dl_vlan = vid
Dan Talayco4431d542012-03-21 16:42:16 -07001169 else:
1170 dl_vlan = -1
Rich Lane477f4812012-10-04 22:49:00 -07001171 flow_match_test(self, config["port_map"], wildcards=wc,
Dan Talayco4431d542012-03-21 16:42:16 -07001172 dl_vlan=dl_vlan, max_test=10)
Tatsuya Yabe4fad7e32010-05-24 15:24:50 -07001173
Dan Talayco551befa2010-07-15 17:05:32 -07001174class SingleWildcardMatchTagged(BaseMatchCase):
1175 """
1176 SingleWildcardMatch with tagged packets
1177 """
1178 def runTest(self):
Rich Lane2014f9b2012-10-05 15:29:40 -07001179 vid = test_param_get('vid', default=TEST_VID_DEFAULT)
Dan Talayco551befa2010-07-15 17:05:32 -07001180 for wc in WILDCARD_VALUES:
Ed Swierk99a74de2012-08-22 06:40:54 -07001181 wc |= required_wildcards(self)
Rich Lane477f4812012-10-04 22:49:00 -07001182 flow_match_test(self, config["port_map"], wildcards=wc, dl_vlan=vid,
Dan Talayco551befa2010-07-15 17:05:32 -07001183 max_test=10)
1184
1185class AllExceptOneWildcardMatch(BaseMatchCase):
Tatsuya Yabe4fad7e32010-05-24 15:24:50 -07001186 """
Dan Talayco80b54ed2010-07-13 09:48:35 -07001187 Match exactly one field
Tatsuya Yabe4fad7e32010-05-24 15:24:50 -07001188
1189 Generate a packet
1190 Generate and install a matching flow with wildcard all except one filed
1191 Add action to forward to a port
1192 Send the packet to the port
1193 Verify the packet is received at all other ports (one port at a time)
1194 Verify flow_expiration message is correct when command option is set
1195 """
1196 def runTest(self):
Rich Lane2014f9b2012-10-05 15:29:40 -07001197 vid = test_param_get('vid', default=TEST_VID_DEFAULT)
Dan Talayco488fbc52012-04-09 16:30:41 -07001198 for all_exp_one_wildcard in NO_WILDCARD_VALUES:
Ed Swierk99a74de2012-08-22 06:40:54 -07001199 all_exp_one_wildcard |= required_wildcards(self)
Dan Talayco4431d542012-03-21 16:42:16 -07001200 if all_exp_one_wildcard & ofp.OFPFW_DL_VLAN:
Ken Chiang5be06dd2012-04-03 10:03:50 -07001201 # Set nonzero VLAN id to avoid sending priority-tagged packet
1202 dl_vlan = vid
Dan Talayco4431d542012-03-21 16:42:16 -07001203 else:
1204 dl_vlan = -1
Rich Lane477f4812012-10-04 22:49:00 -07001205 flow_match_test(self, config["port_map"], wildcards=all_exp_one_wildcard,
Dan Talayco4431d542012-03-21 16:42:16 -07001206 dl_vlan=dl_vlan)
Tatsuya Yabee30ebe22010-05-25 09:30:49 -07001207
Dan Talayco551befa2010-07-15 17:05:32 -07001208class AllExceptOneWildcardMatchTagged(BaseMatchCase):
1209 """
1210 Match one field with tagged packets
1211 """
1212 def runTest(self):
Rich Lane2014f9b2012-10-05 15:29:40 -07001213 vid = test_param_get('vid', default=TEST_VID_DEFAULT)
Dan Talayco488fbc52012-04-09 16:30:41 -07001214 for all_exp_one_wildcard in NO_WILDCARD_VALUES:
Ed Swierk99a74de2012-08-22 06:40:54 -07001215 all_exp_one_wildcard |= required_wildcards(self)
Rich Lane477f4812012-10-04 22:49:00 -07001216 flow_match_test(self, config["port_map"], wildcards=all_exp_one_wildcard,
Dan Talayco21381562010-07-17 00:34:47 -07001217 dl_vlan=vid)
Dan Talayco551befa2010-07-15 17:05:32 -07001218
1219class AllWildcardMatch(BaseMatchCase):
Tatsuya Yabee30ebe22010-05-25 09:30:49 -07001220 """
1221 Create Wildcard-all flow and exercise for all ports
1222
1223 Generate a packet
1224 Generate and install a matching flow with wildcard-all
1225 Add action to forward to a port
1226 Send the packet to the port
1227 Verify the packet is received at all other ports (one port at a time)
1228 Verify flow_expiration message is correct when command option is set
1229 """
1230 def runTest(self):
Rich Lane477f4812012-10-04 22:49:00 -07001231 flow_match_test(self, config["port_map"], wildcards=ofp.OFPFW_ALL)
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -07001232
Dan Talayco551befa2010-07-15 17:05:32 -07001233class AllWildcardMatchTagged(BaseMatchCase):
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -07001234 """
Dan Talayco551befa2010-07-15 17:05:32 -07001235 AllWildcardMatch with tagged packets
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -07001236 """
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -07001237 def runTest(self):
Rich Lane2014f9b2012-10-05 15:29:40 -07001238 vid = test_param_get('vid', default=TEST_VID_DEFAULT)
Rich Lane477f4812012-10-04 22:49:00 -07001239 flow_match_test(self, config["port_map"], wildcards=ofp.OFPFW_ALL,
Dan Talayco21381562010-07-17 00:34:47 -07001240 dl_vlan=vid)
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -07001241
Rich Lane97e99652013-01-02 17:23:20 -08001242@group('smoke')
Dan Talayco551befa2010-07-15 17:05:32 -07001243class AddVLANTag(BaseMatchCase):
1244 """
1245 Add a VLAN tag to an untagged packet
1246 """
1247 def runTest(self):
1248 new_vid = 2
Ed Swierkc7193a22012-08-22 06:51:02 -07001249 sup_acts = self.supported_actions
Dan Talayco551befa2010-07-15 17:05:32 -07001250 if not(sup_acts & 1<<ofp.OFPAT_SET_VLAN_VID):
Dan Talaycoba3745c2010-07-21 21:51:08 -07001251 skip_message_emit(self, "Add VLAN tag test")
Dan Talaycof36f1082010-07-13 13:57:17 -07001252 return
Tatsuya Yabef5ffb972010-05-26 15:36:33 -07001253
Dan Talayco551befa2010-07-15 17:05:32 -07001254 len = 100
1255 len_w_vid = 104
1256 pkt = simple_tcp_packet(pktlen=len)
1257 exp_pkt = simple_tcp_packet(pktlen=len_w_vid, dl_vlan_enable=True,
1258 dl_vlan=new_vid)
1259 vid_act = action.action_set_vlan_vid()
1260 vid_act.vlan_vid = new_vid
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -07001261
Rich Lane477f4812012-10-04 22:49:00 -07001262 flow_match_test(self, config["port_map"], pkt=pkt,
Dan Talayco551befa2010-07-15 17:05:32 -07001263 exp_pkt=exp_pkt, action_list=[vid_act])
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -07001264
Rich Lane0a4f6372013-01-02 14:40:22 -08001265@disabled
Rich Laneb90a1c42012-10-05 09:16:05 -07001266class PacketOnly(base_tests.DataPlaneOnly):
Dan Talayco551befa2010-07-15 17:05:32 -07001267 """
1268 Just send a packet thru the switch
1269 """
Rich Laned1d9c282012-10-04 22:07:10 -07001270
Dan Talayco551befa2010-07-15 17:05:32 -07001271 def runTest(self):
1272 pkt = simple_tcp_packet()
Rich Lane477f4812012-10-04 22:49:00 -07001273 of_ports = config["port_map"].keys()
Dan Talayco551befa2010-07-15 17:05:32 -07001274 of_ports.sort()
1275 ing_port = of_ports[0]
Rich Lane9a003812012-10-04 17:17:59 -07001276 logging.info("Sending packet to " + str(ing_port))
1277 logging.debug("Data: " + str(pkt).encode('hex'))
Dan Talayco551befa2010-07-15 17:05:32 -07001278 self.dataplane.send(ing_port, str(pkt))
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -07001279
Rich Lane0a4f6372013-01-02 14:40:22 -08001280@disabled
Rich Laneb90a1c42012-10-05 09:16:05 -07001281class PacketOnlyTagged(base_tests.DataPlaneOnly):
Dan Talayco551befa2010-07-15 17:05:32 -07001282 """
1283 Just send a packet thru the switch
1284 """
Rich Laned1d9c282012-10-04 22:07:10 -07001285
Dan Talayco551befa2010-07-15 17:05:32 -07001286 def runTest(self):
Rich Lane2014f9b2012-10-05 15:29:40 -07001287 vid = test_param_get('vid', default=TEST_VID_DEFAULT)
Dan Talayco551befa2010-07-15 17:05:32 -07001288 pkt = simple_tcp_packet(dl_vlan_enable=True, dl_vlan=vid)
Rich Lane477f4812012-10-04 22:49:00 -07001289 of_ports = config["port_map"].keys()
Dan Talayco551befa2010-07-15 17:05:32 -07001290 of_ports.sort()
1291 ing_port = of_ports[0]
Rich Lane9a003812012-10-04 17:17:59 -07001292 logging.info("Sending packet to " + str(ing_port))
1293 logging.debug("Data: " + str(pkt).encode('hex'))
Dan Talayco551befa2010-07-15 17:05:32 -07001294 self.dataplane.send(ing_port, str(pkt))
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -07001295
Dan Talayco551befa2010-07-15 17:05:32 -07001296class ModifyVID(BaseMatchCase):
Dan Talayco4b2bee62010-07-20 14:10:05 -07001297 """
1298 Modify the VLAN ID in the VLAN tag of a tagged packet
1299 """
Dan Talaycoaf669322012-09-12 22:51:22 -07001300 def setUp(self):
1301 BaseMatchCase.setUp(self)
1302 self.ing_port=False
1303
Dan Talayco551befa2010-07-15 17:05:32 -07001304 def runTest(self):
1305 old_vid = 2
1306 new_vid = 3
Ed Swierkc7193a22012-08-22 06:51:02 -07001307 sup_acts = self.supported_actions
Dan Talayco4b2bee62010-07-20 14:10:05 -07001308 if not (sup_acts & 1 << ofp.OFPAT_SET_VLAN_VID):
Dan Talaycoba3745c2010-07-21 21:51:08 -07001309 skip_message_emit(self, "Modify VLAN tag test")
Dan Talayco551befa2010-07-15 17:05:32 -07001310 return
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -07001311
Dan Talayco551befa2010-07-15 17:05:32 -07001312 pkt = simple_tcp_packet(dl_vlan_enable=True, dl_vlan=old_vid)
1313 exp_pkt = simple_tcp_packet(dl_vlan_enable=True, dl_vlan=new_vid)
1314 vid_act = action.action_set_vlan_vid()
1315 vid_act.vlan_vid = new_vid
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -07001316
Rich Lane477f4812012-10-04 22:49:00 -07001317 flow_match_test(self, config["port_map"], pkt=pkt, exp_pkt=exp_pkt,
Dan Talaycoaf669322012-09-12 22:51:22 -07001318 action_list=[vid_act], ing_port=self.ing_port)
1319
1320class ModifyVIDToIngress(ModifyVID):
1321 """
1322 Modify the VLAN ID in the VLAN tag of a tagged packet and send to
1323 ingress port
1324 """
1325 def setUp(self):
1326 BaseMatchCase.setUp(self)
1327 self.ing_port=True
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -07001328
Ken Chiange9a211d2012-04-20 14:52:11 -07001329class ModifyVIDWithTagMatchWildcarded(BaseMatchCase):
1330 """
1331 With vlan ID and priority wildcarded, perform SET_VLAN_VID action.
1332 The same flow should match on both untagged and tagged packets.
1333 """
1334 def runTest(self):
1335 old_vid = 2
1336 new_vid = 3
Ed Swierkc7193a22012-08-22 06:51:02 -07001337 sup_acts = self.supported_actions
Ken Chiange9a211d2012-04-20 14:52:11 -07001338 if not (sup_acts & 1 << ofp.OFPAT_SET_VLAN_VID):
1339 skip_message_emit(self, "ModifyVIDWithTagWildcarded test")
1340 return
1341
Rich Lane477f4812012-10-04 22:49:00 -07001342 of_ports = config["port_map"].keys()
Ken Chiange9a211d2012-04-20 14:52:11 -07001343 self.assertTrue(len(of_ports) > 1, "Not enough ports for test")
1344 ing_port = of_ports[0]
1345 egr_ports = of_ports[1]
1346
Rich Lane32bf9482013-01-03 17:26:30 -08001347 delete_all_flows(self.controller)
Ken Chiange9a211d2012-04-20 14:52:11 -07001348
1349 len_untagged = 100
1350 len_w_vid = 104
1351 untagged_pkt = simple_tcp_packet(pktlen=len_untagged)
1352 tagged_pkt = simple_tcp_packet(pktlen=len_w_vid,
1353 dl_vlan_enable=True, dl_vlan=old_vid)
1354 exp_pkt = simple_tcp_packet(pktlen=len_w_vid, dl_vlan_enable=True,
1355 dl_vlan=new_vid)
Ed Swierk99a74de2012-08-22 06:40:54 -07001356 wildcards = (required_wildcards(self) | ofp.OFPFW_DL_VLAN |
1357 ofp.OFPFW_DL_VLAN_PCP)
Ken Chiange9a211d2012-04-20 14:52:11 -07001358 vid_act = action.action_set_vlan_vid()
1359 vid_act.vlan_vid = new_vid
1360 request = flow_msg_create(self, untagged_pkt, ing_port=ing_port,
1361 wildcards=wildcards, egr_ports=egr_ports,
1362 action_list=[vid_act])
1363 flow_msg_install(self, request)
1364
Rich Lane9a003812012-10-04 17:17:59 -07001365 logging.debug("Send untagged packet: " + str(ing_port) + " to " +
Ken Chiange9a211d2012-04-20 14:52:11 -07001366 str(egr_ports))
1367 self.dataplane.send(ing_port, str(untagged_pkt))
1368 receive_pkt_verify(self, egr_ports, exp_pkt, ing_port)
1369
Rich Lane9a003812012-10-04 17:17:59 -07001370 logging.debug("Send tagged packet: " + str(ing_port) + " to " +
Ken Chiange9a211d2012-04-20 14:52:11 -07001371 str(egr_ports))
1372 self.dataplane.send(ing_port, str(tagged_pkt))
1373 receive_pkt_verify(self, egr_ports, exp_pkt, ing_port)
1374
Howard Pershc1199d52012-04-11 14:21:32 -07001375class ModifyVlanPcp(BaseMatchCase):
1376 """
1377 Modify the priority field of the VLAN tag of a tagged packet
1378 """
1379 def runTest(self):
1380 vid = 123
1381 old_vlan_pcp = 2
1382 new_vlan_pcp = 3
Ed Swierkc7193a22012-08-22 06:51:02 -07001383 sup_acts = self.supported_actions
Ed Swierk8c3af7f2012-04-24 14:19:17 -07001384 if not (sup_acts & 1 << ofp.OFPAT_SET_VLAN_PCP):
1385 skip_message_emit(self, "Modify VLAN priority test")
Howard Pershc1199d52012-04-11 14:21:32 -07001386 return
1387
1388 pkt = simple_tcp_packet(dl_vlan_enable=True, dl_vlan=vid, dl_vlan_pcp=old_vlan_pcp)
1389 exp_pkt = simple_tcp_packet(dl_vlan_enable=True, dl_vlan=vid, dl_vlan_pcp=new_vlan_pcp)
1390 vid_act = action.action_set_vlan_pcp()
1391 vid_act.vlan_pcp = new_vlan_pcp
1392
Rich Lane477f4812012-10-04 22:49:00 -07001393 flow_match_test(self, config["port_map"], pkt=pkt, exp_pkt=exp_pkt,
Howard Pershc1199d52012-04-11 14:21:32 -07001394 action_list=[vid_act])
1395
Dan Talayco551befa2010-07-15 17:05:32 -07001396class StripVLANTag(BaseMatchCase):
Dan Talayco4b2bee62010-07-20 14:10:05 -07001397 """
1398 Strip the VLAN tag from a tagged packet
1399 """
Dan Talayco551befa2010-07-15 17:05:32 -07001400 def runTest(self):
1401 old_vid = 2
Ed Swierkc7193a22012-08-22 06:51:02 -07001402 sup_acts = self.supported_actions
Dan Talayco4b2bee62010-07-20 14:10:05 -07001403 if not (sup_acts & 1 << ofp.OFPAT_STRIP_VLAN):
Dan Talaycoba3745c2010-07-21 21:51:08 -07001404 skip_message_emit(self, "Strip VLAN tag test")
Dan Talayco551befa2010-07-15 17:05:32 -07001405 return
Dan Talaycof36f1082010-07-13 13:57:17 -07001406
Dan Talayco551befa2010-07-15 17:05:32 -07001407 len_w_vid = 104
1408 len = 100
1409 pkt = simple_tcp_packet(pktlen=len_w_vid, dl_vlan_enable=True,
1410 dl_vlan=old_vid)
1411 exp_pkt = simple_tcp_packet(pktlen=len)
1412 vid_act = action.action_strip_vlan()
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -07001413
Rich Lane477f4812012-10-04 22:49:00 -07001414 flow_match_test(self, config["port_map"], pkt=pkt, exp_pkt=exp_pkt,
Dan Talayco551befa2010-07-15 17:05:32 -07001415 action_list=[vid_act])
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -07001416
Ken Chiange9a211d2012-04-20 14:52:11 -07001417class StripVLANTagWithTagMatchWildcarded(BaseMatchCase):
1418 """
1419 Strip the VLAN tag from a tagged packet.
1420 Differs from StripVLANTag in that VID and PCP are both wildcarded.
1421 """
1422 def runTest(self):
1423 old_vid = 2
Ed Swierkc7193a22012-08-22 06:51:02 -07001424 sup_acts = self.supported_actions
Ken Chiange9a211d2012-04-20 14:52:11 -07001425 if not (sup_acts & 1 << ofp.OFPAT_STRIP_VLAN):
1426 skip_message_emit(self, "StripVLANTagWithTagWildcarded test")
1427 return
1428
1429 len_w_vid = 104
1430 len_untagged = 100
1431 pkt = simple_tcp_packet(pktlen=len_w_vid, dl_vlan_enable=True,
1432 dl_vlan=old_vid)
1433 exp_pkt = simple_tcp_packet(pktlen=len_untagged)
Ed Swierk99a74de2012-08-22 06:40:54 -07001434 wildcards = (required_wildcards(self) | ofp.OFPFW_DL_VLAN |
1435 ofp.OFPFW_DL_VLAN_PCP)
Ken Chiange9a211d2012-04-20 14:52:11 -07001436 vid_act = action.action_strip_vlan()
1437
Rich Lane477f4812012-10-04 22:49:00 -07001438 flow_match_test(self, config["port_map"],
Ed Swierk99a74de2012-08-22 06:40:54 -07001439 wildcards=wildcards,
Ken Chiange9a211d2012-04-20 14:52:11 -07001440 pkt=pkt, exp_pkt=exp_pkt,
1441 action_list=[vid_act])
1442
Dan Talayco4b2bee62010-07-20 14:10:05 -07001443def init_pkt_args():
1444 """
1445 Pass back a dictionary with default packet arguments
1446 """
1447 args = {}
1448 args["dl_src"] = '00:23:45:67:89:AB'
1449
1450 dl_vlan_enable=False
1451 dl_vlan=-1
Rich Lane477f4812012-10-04 22:49:00 -07001452 if config["test-params"]["vid"]:
Dan Talayco4b2bee62010-07-20 14:10:05 -07001453 dl_vlan_enable=True
Rich Lane477f4812012-10-04 22:49:00 -07001454 dl_vlan = config["test-params"]["vid"]
Dan Talayco4b2bee62010-07-20 14:10:05 -07001455
1456# Unpack operator is ** on a dictionary
1457
1458 return args
1459
Dan Talayco551befa2010-07-15 17:05:32 -07001460class ModifyL2Src(BaseMatchCase):
Dan Talayco4b2bee62010-07-20 14:10:05 -07001461 """
1462 Modify the source MAC address (TP1)
1463 """
Dan Talayco551befa2010-07-15 17:05:32 -07001464 def runTest(self):
Ed Swierkc7193a22012-08-22 06:51:02 -07001465 sup_acts = self.supported_actions
Dan Talayco4b2bee62010-07-20 14:10:05 -07001466 if not (sup_acts & 1 << ofp.OFPAT_SET_DL_SRC):
Dan Talaycoba3745c2010-07-21 21:51:08 -07001467 skip_message_emit(self, "ModifyL2Src test")
Dan Talayco4b2bee62010-07-20 14:10:05 -07001468 return
1469
1470 (pkt, exp_pkt, acts) = pkt_action_setup(self, mod_fields=['dl_src'],
1471 check_test_params=True)
Rich Lane477f4812012-10-04 22:49:00 -07001472 flow_match_test(self, config["port_map"], pkt=pkt, exp_pkt=exp_pkt,
Dan Talayco4b2bee62010-07-20 14:10:05 -07001473 action_list=acts, max_test=2)
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -07001474
Dan Talayco551befa2010-07-15 17:05:32 -07001475class ModifyL2Dst(BaseMatchCase):
Dan Talayco4b2bee62010-07-20 14:10:05 -07001476 """
1477 Modify the dest MAC address (TP1)
1478 """
Dan Talayco551befa2010-07-15 17:05:32 -07001479 def runTest(self):
Ed Swierkc7193a22012-08-22 06:51:02 -07001480 sup_acts = self.supported_actions
Dan Talayco4b2bee62010-07-20 14:10:05 -07001481 if not (sup_acts & 1 << ofp.OFPAT_SET_DL_DST):
Dan Talaycoba3745c2010-07-21 21:51:08 -07001482 skip_message_emit(self, "ModifyL2dst test")
Dan Talayco4b2bee62010-07-20 14:10:05 -07001483 return
1484
1485 (pkt, exp_pkt, acts) = pkt_action_setup(self, mod_fields=['dl_dst'],
1486 check_test_params=True)
Rich Lane477f4812012-10-04 22:49:00 -07001487 flow_match_test(self, config["port_map"], pkt=pkt, exp_pkt=exp_pkt,
Dan Talayco4b2bee62010-07-20 14:10:05 -07001488 action_list=acts, max_test=2)
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -07001489
Dan Talayco551befa2010-07-15 17:05:32 -07001490class ModifyL3Src(BaseMatchCase):
Dan Talayco4b2bee62010-07-20 14:10:05 -07001491 """
1492 Modify the source IP address of an IP packet (TP1)
1493 """
Dan Talayco551befa2010-07-15 17:05:32 -07001494 def runTest(self):
Ed Swierkc7193a22012-08-22 06:51:02 -07001495 sup_acts = self.supported_actions
Dan Talayco4b2bee62010-07-20 14:10:05 -07001496 if not (sup_acts & 1 << ofp.OFPAT_SET_NW_SRC):
Dan Talaycoba3745c2010-07-21 21:51:08 -07001497 skip_message_emit(self, "ModifyL3Src test")
Dan Talayco4b2bee62010-07-20 14:10:05 -07001498 return
1499
1500 (pkt, exp_pkt, acts) = pkt_action_setup(self, mod_fields=['ip_src'],
1501 check_test_params=True)
Rich Lane477f4812012-10-04 22:49:00 -07001502 flow_match_test(self, config["port_map"], pkt=pkt, exp_pkt=exp_pkt,
Dan Talayco4b2bee62010-07-20 14:10:05 -07001503 action_list=acts, max_test=2)
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -07001504
Dan Talayco551befa2010-07-15 17:05:32 -07001505class ModifyL3Dst(BaseMatchCase):
Dan Talayco4b2bee62010-07-20 14:10:05 -07001506 """
1507 Modify the dest IP address of an IP packet (TP1)
1508 """
Dan Talayco551befa2010-07-15 17:05:32 -07001509 def runTest(self):
Ed Swierkc7193a22012-08-22 06:51:02 -07001510 sup_acts = self.supported_actions
Dan Talayco4b2bee62010-07-20 14:10:05 -07001511 if not (sup_acts & 1 << ofp.OFPAT_SET_NW_DST):
Dan Talaycoba3745c2010-07-21 21:51:08 -07001512 skip_message_emit(self, "ModifyL3Dst test")
Dan Talayco4b2bee62010-07-20 14:10:05 -07001513 return
1514
1515 (pkt, exp_pkt, acts) = pkt_action_setup(self, mod_fields=['ip_dst'],
1516 check_test_params=True)
Rich Lane477f4812012-10-04 22:49:00 -07001517 flow_match_test(self, config["port_map"], pkt=pkt, exp_pkt=exp_pkt,
Dan Talayco4b2bee62010-07-20 14:10:05 -07001518 action_list=acts, max_test=2)
Dan Talayco551befa2010-07-15 17:05:32 -07001519
1520class ModifyL4Src(BaseMatchCase):
Dan Talayco4b2bee62010-07-20 14:10:05 -07001521 """
1522 Modify the source TCP port of a TCP packet (TP1)
1523 """
Dan Talayco551befa2010-07-15 17:05:32 -07001524 def runTest(self):
Ed Swierkc7193a22012-08-22 06:51:02 -07001525 sup_acts = self.supported_actions
Dan Talayco4b2bee62010-07-20 14:10:05 -07001526 if not (sup_acts & 1 << ofp.OFPAT_SET_TP_SRC):
Dan Talaycoba3745c2010-07-21 21:51:08 -07001527 skip_message_emit(self, "ModifyL4Src test")
Dan Talayco4b2bee62010-07-20 14:10:05 -07001528 return
1529
1530 (pkt, exp_pkt, acts) = pkt_action_setup(self, mod_fields=['tcp_sport'],
1531 check_test_params=True)
Rich Lane477f4812012-10-04 22:49:00 -07001532 flow_match_test(self, config["port_map"], pkt=pkt, exp_pkt=exp_pkt,
Dan Talayco4b2bee62010-07-20 14:10:05 -07001533 action_list=acts, max_test=2)
Dan Talayco551befa2010-07-15 17:05:32 -07001534
Rich Lane01c2b862012-10-26 16:26:25 -07001535class ModifyL4SrcUdp(BaseMatchCase):
1536 """
1537 Modify the source UDP port of a UDP packet
1538 """
1539 def runTest(self):
1540 sup_acts = self.supported_actions
1541 if not (sup_acts & 1 << ofp.OFPAT_SET_TP_DST):
1542 skip_message_emit(self, "ModifyL4SrcUdp test")
1543 return
1544
1545 (pkt, exp_pkt, acts) = pkt_action_setup(self, mod_fields=['udp_sport'],
1546 check_test_params=True, tp="udp")
1547 flow_match_test(self, config["port_map"], pkt=pkt, exp_pkt=exp_pkt,
1548 action_list=acts, max_test=2)
1549
Dan Talayco551befa2010-07-15 17:05:32 -07001550class ModifyL4Dst(BaseMatchCase):
Dan Talayco4b2bee62010-07-20 14:10:05 -07001551 """
1552 Modify the dest TCP port of a TCP packet (TP1)
1553 """
Dan Talayco551befa2010-07-15 17:05:32 -07001554 def runTest(self):
Ed Swierkc7193a22012-08-22 06:51:02 -07001555 sup_acts = self.supported_actions
Dan Talayco4b2bee62010-07-20 14:10:05 -07001556 if not (sup_acts & 1 << ofp.OFPAT_SET_TP_DST):
Dan Talaycoba3745c2010-07-21 21:51:08 -07001557 skip_message_emit(self, "ModifyL4Dst test")
Dan Talayco4b2bee62010-07-20 14:10:05 -07001558 return
1559
1560 (pkt, exp_pkt, acts) = pkt_action_setup(self, mod_fields=['tcp_dport'],
1561 check_test_params=True)
Rich Lane477f4812012-10-04 22:49:00 -07001562 flow_match_test(self, config["port_map"], pkt=pkt, exp_pkt=exp_pkt,
Dan Talayco4b2bee62010-07-20 14:10:05 -07001563 action_list=acts, max_test=2)
Dan Talayco551befa2010-07-15 17:05:32 -07001564
Rich Lane01c2b862012-10-26 16:26:25 -07001565class ModifyL4DstUdp(BaseMatchCase):
1566 """
1567 Modify the dest UDP port of a UDP packet
1568 """
1569 def runTest(self):
1570 sup_acts = self.supported_actions
1571 if not (sup_acts & 1 << ofp.OFPAT_SET_TP_DST):
1572 skip_message_emit(self, "ModifyL4DstUdp test")
1573 return
1574
1575 (pkt, exp_pkt, acts) = pkt_action_setup(self, mod_fields=['udp_dport'],
1576 check_test_params=True, tp="udp")
1577 flow_match_test(self, config["port_map"], pkt=pkt, exp_pkt=exp_pkt,
1578 action_list=acts, max_test=2)
1579
Dan Talayco551befa2010-07-15 17:05:32 -07001580class ModifyTOS(BaseMatchCase):
Dan Talayco4b2bee62010-07-20 14:10:05 -07001581 """
1582 Modify the IP type of service of an IP packet (TP1)
1583 """
Dan Talayco551befa2010-07-15 17:05:32 -07001584 def runTest(self):
Ed Swierkc7193a22012-08-22 06:51:02 -07001585 sup_acts = self.supported_actions
Dan Talayco4b2bee62010-07-20 14:10:05 -07001586 if not (sup_acts & 1 << ofp.OFPAT_SET_NW_TOS):
Dan Talaycoba3745c2010-07-21 21:51:08 -07001587 skip_message_emit(self, "ModifyTOS test")
Dan Talayco4b2bee62010-07-20 14:10:05 -07001588 return
Dan Talayco551befa2010-07-15 17:05:32 -07001589
Dan Talayco4b2bee62010-07-20 14:10:05 -07001590 (pkt, exp_pkt, acts) = pkt_action_setup(self, mod_fields=['ip_tos'],
1591 check_test_params=True)
Rich Lane477f4812012-10-04 22:49:00 -07001592 flow_match_test(self, config["port_map"], pkt=pkt, exp_pkt=exp_pkt,
Dan Talaycocfa172f2012-03-23 12:03:00 -07001593 action_list=acts, max_test=2, egr_count=-1)
Dan Talayco551befa2010-07-15 17:05:32 -07001594
Dan Talaycof6e76c02012-03-23 10:56:12 -07001595class ModifyL2DstMC(BaseMatchCase):
1596 """
1597 Modify the L2 dest and send to 2 ports
Dan Talaycof6e76c02012-03-23 10:56:12 -07001598 """
1599 def runTest(self):
Ed Swierkc7193a22012-08-22 06:51:02 -07001600 sup_acts = self.supported_actions
Dan Talaycof6e76c02012-03-23 10:56:12 -07001601 if not (sup_acts & 1 << ofp.OFPAT_SET_DL_DST):
Dan Talaycocfa172f2012-03-23 12:03:00 -07001602 skip_message_emit(self, "ModifyL2dstMC test")
Dan Talaycof6e76c02012-03-23 10:56:12 -07001603 return
1604
Dan Talaycof6e76c02012-03-23 10:56:12 -07001605 (pkt, exp_pkt, acts) = pkt_action_setup(self, mod_fields=['dl_dst'],
1606 check_test_params=True)
Rich Lane477f4812012-10-04 22:49:00 -07001607 flow_match_test(self, config["port_map"], pkt=pkt, exp_pkt=exp_pkt,
Dan Talaycocfa172f2012-03-23 12:03:00 -07001608 action_list=acts, max_test=2, egr_count=-1)
Dan Talaycof6e76c02012-03-23 10:56:12 -07001609
Dan Talaycoc948d0b2012-03-23 12:17:54 -07001610class ModifyL2DstIngress(BaseMatchCase):
1611 """
1612 Modify the L2 dest and send to the ingress port
1613 """
1614 def runTest(self):
Ed Swierkc7193a22012-08-22 06:51:02 -07001615 sup_acts = self.supported_actions
Dan Talaycoc948d0b2012-03-23 12:17:54 -07001616 if not (sup_acts & 1 << ofp.OFPAT_SET_DL_DST):
Dan Talaycoabbfdbb2012-04-05 10:29:26 -07001617 skip_message_emit(self, "ModifyL2dstIngress test")
Dan Talaycoc948d0b2012-03-23 12:17:54 -07001618 return
1619
1620 (pkt, exp_pkt, acts) = pkt_action_setup(self, mod_fields=['dl_dst'],
1621 check_test_params=True)
Rich Lane477f4812012-10-04 22:49:00 -07001622 flow_match_test(self, config["port_map"], pkt=pkt, exp_pkt=exp_pkt,
Dan Talaycoc948d0b2012-03-23 12:17:54 -07001623 action_list=acts, max_test=2, egr_count=0,
1624 ing_port=True)
1625
Dan Talaycod8ae7582012-03-23 12:24:56 -07001626class ModifyL2DstIngressMC(BaseMatchCase):
1627 """
1628 Modify the L2 dest and send to the ingress port
1629 """
1630 def runTest(self):
Ed Swierkc7193a22012-08-22 06:51:02 -07001631 sup_acts = self.supported_actions
Dan Talaycod8ae7582012-03-23 12:24:56 -07001632 if not (sup_acts & 1 << ofp.OFPAT_SET_DL_DST):
1633 skip_message_emit(self, "ModifyL2dstMC test")
1634 return
1635
1636 (pkt, exp_pkt, acts) = pkt_action_setup(self, mod_fields=['dl_dst'],
1637 check_test_params=True)
Rich Lane477f4812012-10-04 22:49:00 -07001638 flow_match_test(self, config["port_map"], pkt=pkt, exp_pkt=exp_pkt,
Dan Talaycod8ae7582012-03-23 12:24:56 -07001639 action_list=acts, max_test=2, egr_count=-1,
1640 ing_port=True)
1641
Dan Talaycof6e76c02012-03-23 10:56:12 -07001642class ModifyL2SrcMC(BaseMatchCase):
1643 """
1644 Modify the source MAC address (TP1) and send to multiple
Dan Talaycof6e76c02012-03-23 10:56:12 -07001645 """
1646 def runTest(self):
Ed Swierkc7193a22012-08-22 06:51:02 -07001647 sup_acts = self.supported_actions
Dan Talaycof6e76c02012-03-23 10:56:12 -07001648 if not (sup_acts & 1 << ofp.OFPAT_SET_DL_SRC):
Dan Talaycocfa172f2012-03-23 12:03:00 -07001649 skip_message_emit(self, "ModifyL2SrcMC test")
Dan Talaycof6e76c02012-03-23 10:56:12 -07001650 return
1651
Dan Talaycof6e76c02012-03-23 10:56:12 -07001652 (pkt, exp_pkt, acts) = pkt_action_setup(self, mod_fields=['dl_src'],
1653 check_test_params=True)
Rich Lane477f4812012-10-04 22:49:00 -07001654 flow_match_test(self, config["port_map"], pkt=pkt, exp_pkt=exp_pkt,
Dan Talaycocfa172f2012-03-23 12:03:00 -07001655 action_list=acts, max_test=2, egr_count=-1)
Dan Talaycof6e76c02012-03-23 10:56:12 -07001656
1657class ModifyL2SrcDstMC(BaseMatchCase):
1658 """
1659 Modify the L2 source and dest and send to 2 ports
Dan Talaycof6e76c02012-03-23 10:56:12 -07001660 """
1661 def runTest(self):
Ed Swierkc7193a22012-08-22 06:51:02 -07001662 sup_acts = self.supported_actions
Dan Talaycocfa172f2012-03-23 12:03:00 -07001663 if (not (sup_acts & 1 << ofp.OFPAT_SET_DL_DST) or
1664 not (sup_acts & 1 << ofp.OFPAT_SET_DL_SRC)):
1665 skip_message_emit(self, "ModifyL2SrcDstMC test")
Dan Talaycof6e76c02012-03-23 10:56:12 -07001666 return
1667
Dan Talaycof6e76c02012-03-23 10:56:12 -07001668 mod_fields = ['dl_dst', 'dl_src']
1669 (pkt, exp_pkt, acts) = pkt_action_setup(self, mod_fields=mod_fields,
1670 check_test_params=True)
Rich Lane477f4812012-10-04 22:49:00 -07001671 flow_match_test(self, config["port_map"], pkt=pkt, exp_pkt=exp_pkt,
Dan Talaycocfa172f2012-03-23 12:03:00 -07001672 action_list=acts, max_test=2, egr_count=-1)
1673
1674class ModifyL2DstVIDMC(BaseMatchCase):
1675 """
1676 Modify the L2 dest and send to 2 ports
1677 """
1678 def runTest(self):
Ed Swierkc7193a22012-08-22 06:51:02 -07001679 sup_acts = self.supported_actions
Dan Talaycocfa172f2012-03-23 12:03:00 -07001680 if (not (sup_acts & 1 << ofp.OFPAT_SET_DL_DST) or
1681 not (sup_acts & 1 << ofp.OFPAT_SET_VLAN_VID)):
1682 skip_message_emit(self, "ModifyL2DstVIDMC test")
1683 return
1684
1685 mod_fields = ['dl_dst', 'dl_vlan']
1686 (pkt, exp_pkt, acts) = pkt_action_setup(self,
1687 start_field_vals={'dl_vlan_enable':True}, mod_fields=mod_fields,
1688 check_test_params=True)
Rich Lane477f4812012-10-04 22:49:00 -07001689 flow_match_test(self, config["port_map"], pkt=pkt, exp_pkt=exp_pkt,
Dan Talaycocfa172f2012-03-23 12:03:00 -07001690 action_list=acts, max_test=2, egr_count=-1)
Dan Talaycof6e76c02012-03-23 10:56:12 -07001691
Rich Lane97e99652013-01-02 17:23:20 -08001692@group("smoke")
Rich Lane22e74c12012-11-12 15:06:06 -08001693class ModifyAll(BaseMatchCase):
1694 """
1695 Modify all supported fields and output to a port
1696 """
1697 def runTest(self):
1698 sup_acts = self.supported_actions
1699
1700 sup_map = {
1701 "dl_dst" : ofp.OFPAT_SET_DL_DST,
1702 "dl_src" : ofp.OFPAT_SET_DL_SRC,
1703 "dl_vlan_enable" : ofp.OFPAT_SET_VLAN_VID,
1704 "dl_vlan" : ofp.OFPAT_SET_VLAN_VID,
1705 "dl_vlan_pcp" : ofp.OFPAT_SET_VLAN_PCP,
1706 "ip_src" : ofp.OFPAT_SET_NW_SRC,
1707 "ip_dst" : ofp.OFPAT_SET_NW_DST,
1708 "ip_tos" : ofp.OFPAT_SET_NW_TOS,
1709 "tcp_sport" : ofp.OFPAT_SET_TP_SRC,
1710 "tcp_dport" : ofp.OFPAT_SET_TP_DST,
1711 }
1712
1713 mod_fields = [field for (field, bit) in sup_map.items() if (sup_acts & 1 << bit)]
1714 random.shuffle(mod_fields)
1715 start_field_vals = { "dl_vlan_enable" : True }
1716 mod_field_vals = { "dl_vlan_enable" : True }
1717 logging.info("modifying fields: %s" % repr(mod_fields))
1718
1719 (pkt, exp_pkt, acts) = pkt_action_setup(self,
1720 mod_fields=mod_fields,
1721 start_field_vals=start_field_vals,
1722 mod_field_vals=mod_field_vals,
1723 check_test_params=True)
1724 flow_match_test(self, config["port_map"], pkt=pkt, exp_pkt=exp_pkt,
1725 action_list=acts, max_test=2)
1726
Dan Talaycofa6454f2012-04-05 10:04:13 -07001727class FlowToggle(BaseMatchCase):
1728 """
1729 Add flows to the table and modify them repeatedly
Dan Talaycof7c41312012-07-23 12:53:19 -07001730
1731 This is done by using only "add" flow messages. Since the check overlap
1732 flag is not set, the switch is supposed to modify the existing flow if
1733 the match already exists.
1734
1735 Would probably be better to exercise more of the flow modify commands
1736 (add, modify, delete +/- strict).
Dan Talaycofa6454f2012-04-05 10:04:13 -07001737 """
1738 def runTest(self):
Rich Lane2014f9b2012-10-05 15:29:40 -07001739 flow_count = test_param_get('ft_flow_count', default=20)
1740 iter_count = test_param_get('ft_iter_count', default=10)
Dan Talaycofa6454f2012-04-05 10:04:13 -07001741
Rich Lane9a003812012-10-04 17:17:59 -07001742 logging.info("Running flow toggle with %d flows, %d iterations" %
Dan Talaycofa6454f2012-04-05 10:04:13 -07001743 (flow_count, iter_count))
1744 acts = []
1745 acts.append(action.action_output())
1746 acts.append(action.action_output())
1747
Rich Lane477f4812012-10-04 22:49:00 -07001748 of_ports = config["port_map"].keys()
Dan Talaycofa6454f2012-04-05 10:04:13 -07001749 if len(of_ports) < 3:
1750 self.assertTrue(False, "Too few ports for test")
1751
1752 for idx in range(2):
1753 acts[idx].port = of_ports[idx]
1754
1755 flows = []
1756 flows.append([])
1757 flows.append([])
1758
Ed Swierk99a74de2012-08-22 06:40:54 -07001759 wildcards = (required_wildcards(self) | ofp.OFPFW_DL_SRC |
1760 ofp.OFPFW_DL_DST)
Dan Talaycofa6454f2012-04-05 10:04:13 -07001761 # Create up the flows in an array
1762 for toggle in range(2):
1763 for f_idx in range(flow_count):
1764 pkt = simple_tcp_packet(tcp_sport=f_idx)
1765 msg = message.flow_mod()
Ed Swierk99a74de2012-08-22 06:40:54 -07001766 match = packet_to_flow_match(self, pkt)
Shudong Zhou031373c2012-07-19 17:37:42 -07001767 match.in_port = of_ports[2]
Dan Talayco50be7672012-04-05 11:38:08 -07001768 match.wildcards = wildcards
Dan Talaycofa6454f2012-04-05 10:04:13 -07001769 msg.match = match
1770 msg.buffer_id = 0xffffffff
Dan Talaycof7c41312012-07-23 12:53:19 -07001771 msg.command = ofp.OFPFC_ADD
Dan Talaycofa6454f2012-04-05 10:04:13 -07001772 msg.actions.add(acts[toggle])
1773 flows[toggle].append(msg)
Dan Talayco50be7672012-04-05 11:38:08 -07001774
1775 # Show two sample flows
Rich Lane9a003812012-10-04 17:17:59 -07001776 logging.debug(flows[0][0].show())
1777 logging.debug(flows[1][0].show())
Dan Talayco50be7672012-04-05 11:38:08 -07001778
Dan Talaycofa6454f2012-04-05 10:04:13 -07001779 # Install the first set of flows
1780 for f_idx in range(flow_count):
Rich Lane5c3151c2013-01-03 17:15:41 -08001781 self.controller.message_send(flows[0][f_idx])
Rich Lane3a261d52013-01-03 17:45:08 -08001782 do_barrier(self.controller)
Dan Talaycofa6454f2012-04-05 10:04:13 -07001783
Rich Lane9a003812012-10-04 17:17:59 -07001784 logging.info("Installed %d flows" % flow_count)
Dan Talaycofa6454f2012-04-05 10:04:13 -07001785
1786 # Repeatedly modify all the flows back and forth
1787 updates = 0
1788 # Report status about 5 times
1789 mod_val = (iter_count / 4) + 1
Dan Talaycoabbfdbb2012-04-05 10:29:26 -07001790 start = time.time()
1791 for iter_idx in range(iter_count):
1792 if not iter_idx % mod_val:
Rich Lane9a003812012-10-04 17:17:59 -07001793 logging.info("Flow Toggle: iter %d of %d. " %
Dan Talaycoabbfdbb2012-04-05 10:29:26 -07001794 (iter_idx, iter_count) +
1795 "%d updates in %d secs" %
1796 (updates, time.time() - start))
Dan Talaycofa6454f2012-04-05 10:04:13 -07001797 for toggle in range(2):
1798 t_idx = 1 - toggle
1799 for f_idx in range(flow_count):
Rich Lane5c3151c2013-01-03 17:15:41 -08001800 self.controller.message_send(flows[t_idx][f_idx])
Dan Talaycofa6454f2012-04-05 10:04:13 -07001801 updates += 1
Rich Lane3a261d52013-01-03 17:45:08 -08001802 do_barrier(self.controller)
Dan Talaycoabbfdbb2012-04-05 10:29:26 -07001803
1804 end = time.time()
1805 divisor = end - start or (end - start + 1)
Rich Lane9a003812012-10-04 17:17:59 -07001806 logging.info("Flow toggle: %d iterations" % iter_count)
1807 logging.info(" %d flow mods in %d secs, %d mods/sec" %
Dan Talaycoabbfdbb2012-04-05 10:29:26 -07001808 (updates, end - start, updates/divisor))
Dan Talaycofa6454f2012-04-05 10:04:13 -07001809
1810
Dan Talayco8a64e332012-03-28 14:53:20 -07001811# You can pick and choose these by commenting tests in or out
1812iter_classes = [
1813 basic.PacketIn,
1814 basic.PacketOut,
1815 DirectPacket,
Dan Talaycofa6454f2012-04-05 10:04:13 -07001816 FlowToggle,
Dan Talayco8a64e332012-03-28 14:53:20 -07001817 DirectTwoPorts,
Dan Talaycofa6454f2012-04-05 10:04:13 -07001818 DirectMCNonIngress,
Dan Talayco8a64e332012-03-28 14:53:20 -07001819 AllWildcardMatch,
1820 AllWildcardMatchTagged,
1821 SingleWildcardMatch,
1822 SingleWildcardMatchTagged,
1823 ExactMatch,
1824 ExactMatchTagged,
1825 SingleWildcardMatch,
1826 ModifyL2Src,
1827 ModifyL2Dst,
1828 ModifyL2SrcMC,
1829 ModifyL2DstMC,
1830 ModifyL2SrcDstMC
1831 ]
1832
Rich Lane0a4f6372013-01-02 14:40:22 -08001833@disabled
Dan Talayco8a64e332012-03-28 14:53:20 -07001834class IterCases(BaseMatchCase):
Dan Talaycofa6454f2012-04-05 10:04:13 -07001835 """
1836 Iterate over a bunch of test cases
1837
1838 The cases come from the list above
1839 """
1840
Dan Talayco8a64e332012-03-28 14:53:20 -07001841 def runTest(self):
Rich Lane2014f9b2012-10-05 15:29:40 -07001842 count = test_param_get('iter_count', default=10)
Dan Talayco8a64e332012-03-28 14:53:20 -07001843 tests_done = 0
Rich Lane9a003812012-10-04 17:17:59 -07001844 logging.info("Running iteration test " + str(count) + " times")
Dan Talayco8a64e332012-03-28 14:53:20 -07001845 start = time.time()
1846 last = start
1847 for idx in range(count):
Rich Lane9a003812012-10-04 17:17:59 -07001848 logging.info("Iteration " + str(idx + 1))
Dan Talayco8a64e332012-03-28 14:53:20 -07001849 for cls in iter_classes:
1850 test = cls()
1851 test.inheritSetup(self)
1852 test.runTest()
1853 tests_done += 1
Dan Talaycofa6454f2012-04-05 10:04:13 -07001854 # Report update about every minute, between tests
Dan Talayco8a64e332012-03-28 14:53:20 -07001855 if time.time() - last > 60:
1856 last = time.time()
Rich Lane9a003812012-10-04 17:17:59 -07001857 logging.info(
Dan Talaycofa6454f2012-04-05 10:04:13 -07001858 "IterCases: Iter %d of %d; Ran %d tests in %d " %
1859 (idx, count, tests_done, last - start) +
1860 "seconds so far")
Dan Talayco8a64e332012-03-28 14:53:20 -07001861 stats = all_stats_get(self)
1862 last = time.time()
Rich Lane9a003812012-10-04 17:17:59 -07001863 logging.info("\nIterCases ran %d tests in %d seconds." %
Dan Talayco8a64e332012-03-28 14:53:20 -07001864 (tests_done, last - start))
Rich Lane9a003812012-10-04 17:17:59 -07001865 logging.info(" flows: %d. packets: %d. bytes: %d" %
Dan Talayco8a64e332012-03-28 14:53:20 -07001866 (stats["flows"], stats["packets"], stats["bytes"]))
Rich Lane9a003812012-10-04 17:17:59 -07001867 logging.info(" active: %d. lookups: %d. matched %d." %
Dan Talayco8a64e332012-03-28 14:53:20 -07001868 (stats["active"], stats["lookups"], stats["matched"]))
1869
Dan Talayco4b2bee62010-07-20 14:10:05 -07001870#@todo Need to implement tagged versions of the above tests
1871#
1872#@todo Implement a test case that strips tag 2, adds tag 3
1873# and modifies tag 4 to tag 5. Then verify (in addition) that
1874# tag 6 does not get modified.
1875
Rich Lane0a4f6372013-01-02 14:40:22 -08001876@disabled
Dan Talayco4b2bee62010-07-20 14:10:05 -07001877class MixedVLAN(BaseMatchCase):
1878 """
1879 Test mixture of VLAN tag actions
1880
1881 Strip tag 2 on port 1, send to port 2
1882 Add tag 3 on port 1, send to port 2
1883 Modify tag 4 to 5 on port 1, send to port 2
1884 All other traffic from port 1, send to port 3
1885 All traffic from port 2 sent to port 4
1886 Use exact matches with different packets for all mods
1887 Verify the following: (port, vid)
1888 (port 1, vid 2) => VLAN tag stripped, out port 2
1889 (port 1, no tag) => tagged packet w/ vid 2 out port 2
1890 (port 1, vid 4) => tagged packet w/ vid 5 out port 2
1891 (port 1, vid 5) => tagged packet w/ vid 5 out port 2
1892 (port 1, vid 6) => tagged packet w/ vid 6 out port 2
1893 (port 2, no tag) => untagged packet out port 4
1894 (port 2, vid 2-6) => unmodified packet out port 4
1895
1896 Variation: Might try sending VID 5 to port 3 and check.
1897 If only VID 5 distinguishes pkt, this will fail on some platforms
1898 """
1899
Rich Lane97e99652013-01-02 17:23:20 -08001900@group('smoke')
Rich Laneb90a1c42012-10-05 09:16:05 -07001901class MatchEach(base_tests.SimpleDataPlane):
Rich Lane8d6ab272012-09-23 18:06:20 -07001902 """
1903 Check that each match field is actually matched on.
1904 Installs two flows that differ in one field. The flow that should not
1905 match has a higher priority, so if that field is ignored during matching
1906 the packet will be sent out the wrong port.
1907
1908 TODO test UDP, ARP, ICMP, etc.
1909 """
1910 def runTest(self):
Rich Lane477f4812012-10-04 22:49:00 -07001911 of_ports = config["port_map"].keys()
Rich Lane8d6ab272012-09-23 18:06:20 -07001912 of_ports.sort()
1913 self.assertTrue(len(of_ports) > 1, "Not enough ports for test")
1914
Rich Lane9a003812012-10-04 17:17:59 -07001915 delete_all_flows(self.controller)
Rich Lane8d6ab272012-09-23 18:06:20 -07001916
Ed Swierk7040a8d2012-12-11 16:30:13 -08001917 pkt = simple_tcp_packet(dl_vlan_enable=True, dl_vlan=2)
Rich Lane8d6ab272012-09-23 18:06:20 -07001918 ingress_port = of_ports[0]
1919 egress_port = of_ports[1]
1920
1921 def testField(field, mask):
Rich Lane9a003812012-10-04 17:17:59 -07001922 logging.info("Testing field %s" % field)
Rich Lane8d6ab272012-09-23 18:06:20 -07001923
1924 def addFlow(matching, priority, output_port):
1925 match = packet_to_flow_match(self, pkt)
1926 self.assertTrue(match is not None, "Could not generate flow match from pkt")
1927 match.wildcards &= ~ofp.OFPFW_IN_PORT
1928 match.in_port = ingress_port
1929 if not matching:
1930 # Make sure flow doesn't match
1931 orig = getattr(match, field)
1932 if isinstance(orig, list):
1933 new = map(lambda a: ~a[0] & a[1], zip(orig, mask))
1934 else:
1935 new = ~orig & mask
1936 setattr(match, field, new)
1937 request = message.flow_mod()
1938 request.match = match
1939 request.buffer_id = 0xffffffff
1940 request.priority = priority
1941 act = action.action_output()
1942 act.port = output_port
Rich Lanee30455b2013-01-03 16:24:44 -08001943 request.actions.add(act)
Rich Lane9a003812012-10-04 17:17:59 -07001944 logging.info("Inserting flow")
Rich Lane8d6ab272012-09-23 18:06:20 -07001945 self.controller.message_send(request)
1946
1947 # This flow should match.
1948 addFlow(matching=True, priority=0, output_port=egress_port)
1949 # This flow should not match, but it has a higher priority.
1950 addFlow(matching=False, priority=1, output_port=ofp.OFPP_IN_PORT)
1951
Rich Lane3a261d52013-01-03 17:45:08 -08001952 do_barrier(self.controller)
Rich Lane8d6ab272012-09-23 18:06:20 -07001953
Rich Lane9a003812012-10-04 17:17:59 -07001954 logging.info("Sending packet to dp port " + str(ingress_port))
Rich Lane8d6ab272012-09-23 18:06:20 -07001955 self.dataplane.send(ingress_port, str(pkt))
1956
1957 exp_pkt_arg = None
1958 exp_port = None
Rich Lane477f4812012-10-04 22:49:00 -07001959 if config["relax"]:
Rich Lane8d6ab272012-09-23 18:06:20 -07001960 exp_pkt_arg = pkt
1961 exp_port = egress_port
1962
1963 (rcv_port, rcv_pkt, pkt_time) = self.dataplane.poll(port_number=exp_port,
1964 exp_pkt=exp_pkt_arg)
1965 self.assertTrue(rcv_pkt is not None, "Did not receive packet")
Rich Lane9a003812012-10-04 17:17:59 -07001966 logging.debug("Packet len " + str(len(rcv_pkt)) + " in on " + str(rcv_port))
Rich Lane8d6ab272012-09-23 18:06:20 -07001967 self.assertEqual(rcv_port, egress_port, "Unexpected receive port")
1968 self.assertEqual(str(pkt), str(rcv_pkt), 'Response packet does not match send packet')
1969
Ed Swierkb603b192012-12-12 15:38:49 -08001970 wildcards = required_wildcards(self)
Rich Lane8d6ab272012-09-23 18:06:20 -07001971 # TODO in_port
Ed Swierkb603b192012-12-12 15:38:49 -08001972 if not (wildcards & ofp.OFPFW_DL_SRC):
1973 testField("dl_src", [0xff]*6)
1974 if not (wildcards & ofp.OFPFW_DL_DST):
1975 testField("dl_dst", [0xff]*6)
1976 if not (wildcards & ofp.OFPFW_DL_TYPE):
1977 testField("dl_type", 0xffff)
1978 if not (wildcards & ofp.OFPFW_DL_VLAN):
1979 testField("dl_vlan", 0xfff)
Rich Lane8d6ab272012-09-23 18:06:20 -07001980 # TODO dl_vlan_pcp
Ed Swierkb603b192012-12-12 15:38:49 -08001981 if not (wildcards & ofp.OFPFW_NW_SRC_ALL):
1982 testField("nw_src", 0xffffffff)
1983 if not (wildcards & ofp.OFPFW_NW_DST_ALL):
1984 testField("nw_dst", 0xffffffff)
1985 if not (wildcards & ofp.OFPFW_NW_TOS):
1986 testField("nw_tos", 0x3f)
1987 if not (wildcards & ofp.OFPFW_NW_PROTO):
1988 testField("nw_proto", 0xff)
1989 if not (wildcards & ofp.OFPFW_TP_SRC):
1990 testField("tp_src", 0xffff)
1991 if not (wildcards & ofp.OFPFW_TP_DST):
1992 testField("tp_dst", 0xffff)
Rich Lane8d6ab272012-09-23 18:06:20 -07001993
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07001994class DirectBadPacketBase(base_tests.SimpleDataPlane):
1995 """
1996 Base class for sending single packets with single flow table entries.
1997 Used to verify matching of unusual packets and parsing/matching of
1998 corrupted packets.
1999
2000 The idea is to generate packets that may either be totally malformed or
2001 malformed just enough to trick the flow matcher into making mistakes.
2002
2003 Generate a 'bad' packet
2004 Generate and install a matching flow
2005 Add action to direct the packet to an egress port
2006 Send the packet to ingress dataplane port
2007 Verify the packet is received at the egress port only
2008 """
2009
2010 RESULT_MATCH = "MATCH"
2011 RESULT_NOMATCH = "NO MATCH"
2012 RESULT_ANY = "ANY MATCH"
2013
2014 def runTest(self):
2015 pass
2016 # TODO:
2017 # - ICMP?
2018 # - VLAN?
2019 # - action
2020
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002021 def createMatch(self, **kwargs):
2022 match = ofp.ofp_match()
2023 match.wildcards = ofp.OFPFW_ALL
2024 fields = {
2025 'dl_dst': ofp.OFPFW_DL_DST,
2026 'dl_src': ofp.OFPFW_DL_SRC,
2027 'dl_type': ofp.OFPFW_DL_TYPE,
2028 'dl_vlan': ofp.OFPFW_DL_VLAN,
2029 'nw_src': ofp.OFPFW_NW_SRC_MASK,
2030 'nw_dst': ofp.OFPFW_NW_DST_MASK,
2031 'nw_tos': ofp.OFPFW_NW_TOS,
2032 'nw_proto': ofp.OFPFW_NW_PROTO,
2033 'tp_src': ofp.OFPFW_TP_SRC,
2034 'tp_dst': ofp.OFPFW_TP_DST,
2035 }
2036 for key in kwargs:
2037 setattr(match, key, kwargs[key])
2038 match.wildcards &= ~fields[key]
2039 return match
2040
2041 def testPktsAgainstFlow(self, pkts, acts, match):
2042 if type(acts) != list:
2043 acts = [acts]
2044 for info in pkts:
2045 title, pkt, expected_result = info
2046 self.testPktAgainstFlow(title, pkt, acts, match, expected_result)
2047
2048 def testPktAgainstFlow(self, title, pkt, acts, match, expected_result):
2049 of_ports = config["port_map"].keys()
2050 of_ports.sort()
2051 self.assertTrue(len(of_ports) > 1, "Not enough ports for test")
2052
Rich Lane32bf9482013-01-03 17:26:30 -08002053 delete_all_flows(self.controller)
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002054
2055 ingress_port = of_ports[0]
2056 egress_port = of_ports[1]
2057
2058 logging.info("Testing packet '%s', expect result %s" %
2059 (title, expected_result))
2060 logging.info("Ingress %s to egress %s" %
2061 (str(ingress_port), str(egress_port)))
2062 logging.info("Packet:")
Rich Lane5d7e89a2012-10-26 16:43:13 -07002063 logging.info(inspect_packet(pkt))
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002064
2065 match.in_port = ingress_port
2066
2067 request = message.flow_mod()
2068 request.match = match
Rich Lane44cf12d2012-10-15 11:10:45 -07002069 request.priority = 1
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002070
2071 request.buffer_id = 0xffffffff
2072 for act in acts:
2073 act.port = egress_port
Rich Lanee30455b2013-01-03 16:24:44 -08002074 request.actions.add(act)
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002075
2076 logging.info("Inserting flow")
Rich Lane5c3151c2013-01-03 17:15:41 -08002077 self.controller.message_send(request)
Rich Lane44cf12d2012-10-15 11:10:45 -07002078
2079 # This flow speeds up negative tests
2080 logging.info("Inserting catch-all flow")
2081 request2 = message.flow_mod()
2082 request2.match = self.createMatch()
2083 request2.priority = 0
2084 act = action.action_output()
2085 act.port = ofp.OFPP_IN_PORT
2086 request2.actions.add(act)
Rich Lane5c3151c2013-01-03 17:15:41 -08002087 self.controller.message_send(request2)
Rich Lane44cf12d2012-10-15 11:10:45 -07002088
Rich Lane3a261d52013-01-03 17:45:08 -08002089 do_barrier(self.controller)
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002090
2091 logging.info("Sending packet to dp port " +
2092 str(ingress_port))
2093 self.dataplane.send(ingress_port, str(pkt))
2094
2095 exp_pkt_arg = None
2096 exp_port = None
2097 if config["relax"]:
2098 exp_pkt_arg = pkt
2099 exp_port = egress_port
2100
Rich Lane44cf12d2012-10-15 11:10:45 -07002101 if expected_result == self.RESULT_MATCH:
2102 timeout = -1 # default timeout
2103 else:
2104 timeout = 1 # short timeout for negative tests
2105
2106 (rcv_port, rcv_pkt, pkt_time) = self.dataplane.poll(exp_pkt=exp_pkt_arg,
2107 timeout=timeout)
2108 if rcv_port == ingress_port:
2109 logging.debug("Packet matched catch-all flow")
2110 rcv_pkt = None
2111
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002112 if expected_result == self.RESULT_MATCH:
2113 self.assertTrue(rcv_pkt is not None,
2114 "Did not receive packet, expected a match")
2115 logging.debug("Packet len " + str(len(rcv_pkt)) + " in on " +
2116 str(rcv_port))
2117 self.assertEqual(rcv_port, egress_port, "Unexpected receive port")
2118 str_pkt = str(pkt)
2119 str_rcv_pkt = str(rcv_pkt)
2120 str_rcv_pkt = str_rcv_pkt[0:len(str_pkt)]
2121 if str_pkt != str_rcv_pkt:
2122 logging.error("Response packet does not match send packet")
2123 logging.info("Response:")
Rich Lane5d7e89a2012-10-26 16:43:13 -07002124 logging.info(inspect_packet(scapy.Ether(rcv_pkt)))
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002125 self.assertEqual(str_pkt, str_rcv_pkt,
2126 'Response packet does not match send packet')
2127 elif expected_result == self.RESULT_NOMATCH:
2128 self.assertTrue(rcv_pkt is None, "Received packet, expected drop")
2129 else:
2130 logging.debug("Match or drop accepted. Result = %s" %
2131 ("match" if rcv_pkt is not None else "drop"))
2132
2133
2134class DirectBadIpTcpPacketsBase(DirectBadPacketBase):
2135 """
2136 Base class for TCP and UDP parsing/matching verification under corruptions
2137 """
2138 def runTest(self):
2139 pass
2140
2141 def runTestWithProto(self, protoName = 'TCP'):
2142 dl_dst='00:01:02:03:04:05'
2143 dl_src='00:06:07:08:09:0a'
2144 ip_src='192.168.0.1'
2145 ip_dst='192.168.0.2'
2146 ip_tos=0
2147 tcp_sport=1234
2148 tcp_dport=80
2149
2150 # Generate a proper packet for constructing a match
2151 tp = None
2152 if protoName == 'TCP':
2153 tp = scapy.TCP
2154 proto = 6
2155 elif protoName == 'UDP':
2156 tp = scapy.UDP
2157 proto = 17
2158 else:
2159 raise Exception("Passed in unknown proto name")
2160
2161 match_pkt = scapy.Ether(dst=dl_dst, src=dl_src)/ \
2162 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos)/ \
2163 tp(sport=tcp_sport, dport=tcp_dport)
2164 match = packet_to_flow_match(self, match_pkt)
2165 self.assertTrue(match is not None,
2166 "Could not generate flow match from pkt")
2167 match.wildcards &= ~ofp.OFPFW_IN_PORT
2168
2169 def testPacket(title, pkt, result):
2170 act = action.action_output()
2171 pkts = [
2172 [title, pkt, result]
2173 ]
2174 self.testPktsAgainstFlow(pkts, act, match)
2175
2176 # Try incomplete IP headers
2177 testPacket("Incomplete IP header (1 bytes)",
2178 scapy.Ether(dst=dl_dst, src=dl_src)/ \
2179 str(scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, proto=proto))[0:1],
2180 self.RESULT_NOMATCH,
2181 )
2182 testPacket("Incomplete IP header (2 bytes)",
2183 scapy.Ether(dst=dl_dst, src=dl_src)/ \
2184 str(scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, proto=proto))[0:2],
2185 self.RESULT_NOMATCH,
2186 )
2187 testPacket("Incomplete IP header (3 bytes)",
2188 scapy.Ether(dst=dl_dst, src=dl_src)/ \
2189 str(scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, proto=proto))[0:3],
2190 self.RESULT_NOMATCH,
2191 )
2192 testPacket("Incomplete IP header (12 bytes)",
2193 scapy.Ether(dst=dl_dst, src=dl_src)/ \
2194 str(scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, proto=proto))[0:12],
2195 self.RESULT_NOMATCH,
2196 )
2197 testPacket("Incomplete IP header (16 bytes)",
2198 scapy.Ether(dst=dl_dst, src=dl_src)/ \
2199 str(scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, proto=proto))[0:16],
2200 self.RESULT_NOMATCH,
2201 )
2202 testPacket("Incomplete IP header (19 bytes)",
2203 scapy.Ether(dst=dl_dst, src=dl_src)/ \
2204 str(scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, proto=proto))[0:19],
2205 self.RESULT_NOMATCH,
2206 )
2207
2208 # Try variations where the TCP header is missing or incomplete. As we
2209 # saw bugs before where buffers were reused and lengths weren't honored,
2210 # we initiatlize once with a non-matching full packet and once with a
2211 # matching full packet.
2212 testPacket("Non-Matching TCP packet, warming buffer",
2213 scapy.Ether(dst=dl_dst, src=dl_src)/ \
2214 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, proto=proto)/ \
2215 tp(sport=tcp_sport, dport=tcp_dport + 1),
2216 self.RESULT_NOMATCH,
2217 )
2218 testPacket("Missing TCP header, buffer warmed with non-match",
2219 scapy.Ether(dst=dl_dst, src=dl_src)/ \
2220 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, proto=proto),
2221 self.RESULT_NOMATCH,
2222 )
2223 testPacket("Matching TCP packet, warming buffer",
2224 scapy.Ether(dst=dl_dst, src=dl_src)/ \
2225 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, proto=proto)/ \
2226 tp(sport=tcp_sport, dport=tcp_dport),
2227 self.RESULT_MATCH,
2228 )
2229 testPacket("Missing TCP header, buffer warmed with match",
2230 scapy.Ether(dst=dl_dst, src=dl_src)/ \
2231 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, proto=proto),
2232 self.RESULT_NOMATCH,
2233 )
2234 testPacket("Truncated TCP header: 2 bytes",
2235 scapy.Ether(dst=dl_dst, src=dl_src)/ \
2236 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, proto=proto)/ \
2237 (str(tp(sport=tcp_sport, dport=tcp_dport))[0:2]),
2238 self.RESULT_NOMATCH,
2239 )
2240
2241 # Play with IP header length values that put the start of TCP either
2242 # inside the generated TCP header or beyond. In some cases it may even
2243 # be beyond the packet boundary. Also play with IP options and more
2244 # importantly IP total length corruptions.
2245 testPacket("TCP packet, corrupt ihl (0x6)",
2246 simple_tcp_packet(ip_ihl=6),
2247 self.RESULT_NOMATCH,
2248 )
2249 testPacket("TCP packet, corrupt ihl (0xf)",
2250 simple_tcp_packet(ip_ihl=0xf), # ihl = 15 * 4 = 60
2251 self.RESULT_NOMATCH,
2252 )
2253 testPacket("TCP packet, corrupt ihl and total length",
2254 simple_tcp_packet(ip_ihl=0xf, pktlen=56), # ihl = 15 * 4 = 60,
2255 self.RESULT_NOMATCH,
2256 )
2257 testPacket("Corrupt IPoption: First 4 bytes of matching TCP header",
2258 simple_tcp_packet(
2259 ip_options=scapy.IPOption('\x04\xd2\x00\x50'),
2260 tcp_dport=2, tcp_sport=2
2261 ),
2262 self.RESULT_NOMATCH,
2263 )
2264 testPacket("Missing TCP header, corrupt ihl",
2265 scapy.Ether(dst=dl_dst, src=dl_src)/ \
2266 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ihl=0xf, proto=proto),
2267 self.RESULT_NOMATCH,
2268 )
2269 testPacket("Missing TCP header, corrupt total length",
2270 scapy.Ether(dst=dl_dst, src=dl_src)/ \
2271 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, proto=proto, len= 100),
2272 self.RESULT_NOMATCH,
2273 )
2274 testPacket("Missing TCP header, corrupt ihl and total length",
2275 scapy.Ether(dst=dl_dst, src=dl_src)/ \
2276 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ihl=0xf, proto=proto, len=43),
2277 self.RESULT_NOMATCH,
2278 )
2279 testPacket("Incomplete IP header (12 bytes), corrupt ihl and total length",
2280 scapy.Ether(dst=dl_dst, src=dl_src)/ \
2281 str(scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, proto=proto, ihl=10, len=43))[0:12],
2282 self.RESULT_NOMATCH,
2283 )
2284 testPacket("Incomplete IP header (16 bytes), corrupt ihl and total length",
2285 scapy.Ether(dst=dl_dst, src=dl_src)/ \
2286 str(scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, proto=proto, ihl=10, len=43))[0:16],
2287 self.RESULT_NOMATCH,
2288 )
2289
2290 # Try an incomplete TCP header that has enough bytes to carry source and
2291 # destination ports. As that is all we care about during matching, some
2292 # implementations may match and some may drop the packet
2293 testPacket("Incomplete TCP header: src/dst port present",
2294 scapy.Ether(dst=dl_dst, src=dl_src)/ \
2295 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, proto=proto)/ \
2296 (str(tp(sport=tcp_sport, dport=tcp_dport))[0:4]),
2297 self.RESULT_ANY,
2298 )
2299
2300 for i in range(1):
2301 for length in range(40 / 4): # IPv4 options are a maximum of 40 in length
2302 bytes = "".join([("%c" % random.randint(0, 255)) for x in range(length * 4)])
2303 eth = scapy.Ether(dst=dl_dst, src=dl_src)
2304 ip = scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ihl=5 + length, proto=proto)
2305 tcp = tp(sport=tcp_sport, dport=tcp_dport+1)
2306 pkt = eth / ip
2307 pkt = pkt / bytes
2308 pkt = pkt / str(tcp)
2309 testPacket("Random IP options len = %d - TP match must fail" % length * 4,
2310 pkt,
2311 self.RESULT_NOMATCH
2312 )
2313
2314 eth = scapy.Ether(dst=dl_dst, src=dl_src)
2315 ip = scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ihl=5 + length, proto=proto)
2316 tcp = tp(sport=tcp_sport, dport=tcp_dport)
2317 pkt = eth / ip
2318 pkt = pkt / bytes
2319 pkt = pkt / str(tcp)
2320
2321 testPacket("Random IP options len = %d - May match",
2322 pkt,
2323 self.RESULT_ANY
2324 )
2325
2326
2327class DirectBadIpTcpPackets(DirectBadIpTcpPacketsBase):
2328 """
2329 Verify IP/TCP parsing and matching. Focus on packet corruptions
2330 """
2331 def runTest(self):
2332 self.runTestWithProto(protoName = 'TCP')
2333
2334class DirectBadIpUdpPackets(DirectBadIpTcpPacketsBase):
2335 """
2336 Verify IP/UDP parsing and matching. Focus on packet corruptions
2337 """
2338 def runTest(self):
2339 self.runTestWithProto(protoName = 'UDP')
2340
2341class DirectBadLlcPackets(DirectBadPacketBase):
2342 """
2343 Verify LLC/SNAP parsing and matching. Focus on packet corruptions
2344 """
2345 def runTest(self):
2346 dl_dst='00:01:02:03:04:05'
2347 dl_src='00:06:07:08:09:0a'
2348 ip_src='192.168.0.1'
2349 ip_dst='192.168.0.2'
2350 ip_tos=0
2351 tcp_sport=1234
2352 tcp_dport=80
2353
2354 IS_SNAP_IP = 1
2355 IS_SNAP_IP_CORRUPT = 2
2356 IS_NOT_SNAP_IP = 3
2357
2358 def testPacketTcpMatch(title, llc):
2359 match_pkt = scapy.Ether(dst=dl_dst, src=dl_src)/ \
2360 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos)/ \
2361 scapy.TCP(sport=tcp_sport, dport=tcp_dport)
2362 match = packet_to_flow_match(self, match_pkt)
2363 self.assertTrue(match is not None,
2364 "Could not generate flow match from pkt")
2365 match.wildcards &= ~ofp.OFPFW_IN_PORT
2366 act = action.action_output()
2367
2368 self.testPktsAgainstFlow(
2369 [[
2370 "TCP match - LLC frame correct length - %s" % title,
2371 scapy.Ether(dst=dl_dst, src=dl_src, type=len(llc)) / llc,
2372 self.RESULT_ANY,
2373 ]],
2374 act, match
2375 )
2376
2377 # Corrupt length field
2378 ethLen = random.randint(0, 1535)
2379 self.testPktsAgainstFlow(
2380 [[
2381 "TCP match - LLC frame corrupted length - %s" % title,
2382 scapy.Ether(dst=dl_dst, src=dl_src, type=ethLen) / llc,
2383 self.RESULT_ANY,
2384 ]],
2385 act, match
2386 )
2387
2388 def testPacketEthSrcDstMatch(title, llc):
2389 # Matching based on Ethernet source and destination
2390 match_pkt = scapy.Ether(dst=dl_dst, src=dl_src)
2391 match = packet_to_flow_match(self, match_pkt)
2392 self.assertTrue(match is not None,
2393 "Could not generate flow match from pkt")
2394 match.wildcards &= ~ofp.OFPFW_IN_PORT
2395 match.wildcards |= ofp.OFPFW_DL_TYPE
2396 self.testPktsAgainstFlow(
2397 [[
2398 "Eth addr match - LLC frame correct length- %s" % title,
2399 scapy.Ether(dst=dl_dst, src=dl_src, type=len(llc)) / llc,
2400 self.RESULT_MATCH,
2401 ]],
2402 action.action_output(), match
2403 )
2404
2405 # Corrupt length field
2406 ethLen = random.randint(0, 1535)
2407 self.testPktsAgainstFlow(
2408 [[
2409 "Eth addr match - LLC frame corrupted length- %s" % title,
2410 scapy.Ether(dst=dl_dst, src=dl_src, type=ethLen) / llc,
2411 self.RESULT_ANY,
2412 ]],
2413 action.action_output(), match
2414 )
2415
2416 def testPacketEthSrcDstTypeMatch(title, llc, is_snap_ip):
2417 # Matching based on Ethernet source, destination and type
2418 match_pkt = scapy.Ether(dst=dl_dst, src=dl_src, type=0x800)
2419 match = packet_to_flow_match(self, match_pkt)
2420 self.assertTrue(match is not None,
2421 "Could not generate flow match from pkt")
2422 match.wildcards &= ~ofp.OFPFW_IN_PORT
2423 if is_snap_ip == IS_SNAP_IP:
2424 is_match = self.RESULT_MATCH
2425 elif is_snap_ip == IS_SNAP_IP_CORRUPT:
2426 is_match = self.RESULT_ANY
2427 else:
2428 is_match = self.RESULT_NOMATCH
2429 self.testPktsAgainstFlow(
2430 [[
2431 "Eth addr+type match - LLC frame correct length - %s" % title,
2432 scapy.Ether(dst=dl_dst, src=dl_src, type=len(llc)) / llc,
2433 is_match,
2434 ]],
2435 action.action_output(), match
2436 )
2437
2438 # Corrupt length field
2439 ethLen = random.randint(0, 1535)
2440 self.testPktsAgainstFlow(
2441 [[
2442 "Eth addr+type match - LLC frame corrupted length - %s" % title,
2443 scapy.Ether(dst=dl_dst, src=dl_src, type=ethLen) / llc,
Christian Dickmanne9b6d252012-10-08 22:56:50 -07002444 self.RESULT_ANY,
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002445 ]],
2446 action.action_output(), match
2447 )
2448
2449 def testPacket(title, llc, is_snap_ip):
2450 testPacketTcpMatch(title, llc)
2451 testPacketEthSrcDstMatch(title, llc)
2452 testPacketEthSrcDstTypeMatch(title, llc, is_snap_ip)
2453
2454 testPacket("LLC - No SNAP - No Payload",
Rich Lane6508ea02012-10-12 15:27:11 -07002455 scapy.LLC(dsap=0x33, ssap=0x44, ctrl=0x03),
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002456 IS_NOT_SNAP_IP,
2457 )
2458 testPacket("LLC - No SNAP - Small Payload",
Rich Lane6508ea02012-10-12 15:27:11 -07002459 scapy.LLC(dsap=0x33, ssap=0x44, ctrl=0x03) / ("S" * 10),
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002460 IS_NOT_SNAP_IP,
2461 )
2462 testPacket("LLC - No SNAP - Max -1 Payload",
Rich Lane6508ea02012-10-12 15:27:11 -07002463 scapy.LLC(dsap=0x33, ssap=0x44, ctrl=0x03) / ("S" * (1500 - 3 - 1)),
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002464 IS_NOT_SNAP_IP,
2465 )
2466 testPacket("LLC - No SNAP - Max Payload",
Rich Lane6508ea02012-10-12 15:27:11 -07002467 scapy.LLC(dsap=0x33, ssap=0x44, ctrl=0x03) / ("S" * (1500 - 3)),
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002468 IS_NOT_SNAP_IP,
2469 )
2470 testPacket("LLC - SNAP - Small bogus payload",
2471 scapy.LLC(dsap=0xaa, ssap=0xaa, ctrl=0x03)/ \
2472 scapy.SNAP(OUI=0x000000, code=0x800) / ("S" * 10),
2473 IS_SNAP_IP_CORRUPT,
2474 )
2475 testPacket("LLC - SNAP - Max -1 bogus payload",
2476 scapy.LLC(dsap=0xaa, ssap=0xaa, ctrl=0x03)/ \
2477 scapy.SNAP(OUI=0x000000, code=0x3) / ("S" * (1500 - 3 - 5 - 1)),
2478 IS_NOT_SNAP_IP,
2479 )
2480 testPacket("LLC - SNAP - Max bogus payload",
2481 scapy.LLC(dsap=0xaa, ssap=0xaa, ctrl=0x03)/ \
2482 scapy.SNAP(OUI=0x000000, code=0x3) / ("S" * (1500 - 3 - 5)),
2483 IS_NOT_SNAP_IP,
2484 )
2485 testPacket("LLC - SNAP - IP - TCP",
2486 scapy.LLC(dsap=0xaa, ssap=0xaa, ctrl=0x03)/ \
2487 scapy.SNAP(OUI=0x000000, code=0x800)/ \
2488 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, proto=6)/ \
2489 scapy.TCP(sport=tcp_sport, dport=tcp_dport),
2490 IS_SNAP_IP,
2491 )
2492
2493
2494class DirectLlcPackets(DirectBadPacketBase):
2495 """
2496 Verify LLC/SNAP parsing (valid and corrupted packets) and matching
2497 """
2498 def runTest(self):
2499 dl_dst='00:01:02:03:04:05'
2500 dl_src='00:06:07:08:09:0a'
2501 ip_src='192.168.0.1'
2502 ip_dst='192.168.0.2'
2503 ip_tos=0
2504 tcp_sport=1234
2505 tcp_dport=80
2506
2507 # Test ethertype in face of LLC/SNAP and OFP_DL_TYPE_NOT_ETH_TYPE
2508 IS_SNAP_NOT_IP = 1
2509 IS_SNAP_AND_IP = 2
2510 IS_NOT_SNAP = 3
2511
2512 def testPacketEthTypeIP(title, llc, is_snap):
2513 match_pkt = scapy.Ether(dst=dl_dst, src=dl_src, type=0x800)
2514 match = packet_to_flow_match(self, match_pkt)
2515 self.assertTrue(match is not None,
2516 "Could not generate flow match from pkt")
2517 match.wildcards &= ~ofp.OFPFW_IN_PORT
2518 pkts = []
2519 if is_snap == IS_NOT_SNAP or is_snap == IS_SNAP_NOT_IP:
2520 result = self.RESULT_NOMATCH
2521 else:
2522 result = self.RESULT_MATCH
2523 pkts.append([
2524 "Ether type 0x800 match - %s" % title,
2525 scapy.Ether(dst=dl_dst, src=dl_src, type=len(llc)) / llc,
2526 result,
2527 ])
2528 act = action.action_output()
2529 self.testPktsAgainstFlow(pkts, act, match)
2530
2531 def testPacketEthTypeNotEth(title, llc, is_snap):
2532 match_pkt = scapy.Ether(dst = dl_dst, src = dl_src,
2533 type = ofp.OFP_DL_TYPE_NOT_ETH_TYPE)
2534 match = packet_to_flow_match(self, match_pkt)
2535 self.assertTrue(match is not None,
2536 "Could not generate flow match from pkt")
2537 match.wildcards &= ~ofp.OFPFW_IN_PORT
2538 pkts = []
2539 if is_snap == IS_NOT_SNAP:
2540 result = self.RESULT_MATCH
2541 else:
2542 result = self.RESULT_NOMATCH
2543 pkts.append([
2544 "Ether type OFP_DL_TYPE_NOT_ETH_TYPE match - %s" % title,
2545 scapy.Ether(dst=dl_dst, src=dl_src, type=len(llc)) / llc,
2546 result,
2547 ])
2548 act = action.action_output()
2549 self.testPktsAgainstFlow(pkts, act, match)
2550
2551 def testPacket(title, llc, is_snap):
2552 testPacketEthTypeIP(title, llc, is_snap)
2553 testPacketEthTypeNotEth(title, llc, is_snap)
2554
2555 testPacket("LLC - No SNAP - No Payload",
Rich Lane6508ea02012-10-12 15:27:11 -07002556 scapy.LLC(dsap=0x33, ssap=0x44, ctrl=0x03),
2557 IS_NOT_SNAP,
2558 )
2559 testPacket("LLC (with information field) - No SNAP - No Payload",
2560 scapy.LLC(dsap=0x33, ssap=0x44, ctrl=0x12) / "S",
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002561 IS_NOT_SNAP,
2562 )
2563 testPacket("LLC - No SNAP - Small Payload",
Rich Lane6508ea02012-10-12 15:27:11 -07002564 scapy.LLC(dsap=0x33, ssap=0x44, ctrl=0x03) / ("S" * 10),
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002565 IS_NOT_SNAP,
2566 )
2567 testPacket("LLC - No SNAP - Max -1 Payload",
Rich Lane6508ea02012-10-12 15:27:11 -07002568 scapy.LLC(dsap=0x33, ssap=0x44, ctrl=0x03) / ("S" * (1500 - 3 - 1)),
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002569 IS_NOT_SNAP,
2570 )
2571 testPacket("LLC - No SNAP - Max Payload",
Rich Lane6508ea02012-10-12 15:27:11 -07002572 scapy.LLC(dsap=0x33, ssap=0x44, ctrl=0x03) / ("S" * (1500 - 3)),
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002573 IS_NOT_SNAP,
2574 )
2575 testPacket("LLC - SNAP - Non-default OUI",
2576 scapy.LLC(dsap=0xaa, ssap=0xaa, ctrl=0x03)/ \
2577 scapy.SNAP(OUI=0x000001, code=0x800) / ("S" * 10),
2578 IS_NOT_SNAP,
2579 )
2580 testPacket("LLC - SNAP - Default OUI",
2581 scapy.LLC(dsap=0xaa, ssap=0xaa, ctrl=0x03)/ \
2582 scapy.SNAP(OUI=0x000000, code=0x800) / ("S" * 10),
2583 IS_SNAP_AND_IP,
2584 )
2585 testPacket("LLC - SNAP - Max -1 bogus payload",
2586 scapy.LLC(dsap=0xaa, ssap=0xaa, ctrl=0x03)/ \
2587 scapy.SNAP(OUI=0x000000, code=0x3) / ("S" * (1500 - 3 - 5 - 1)),
2588 IS_SNAP_NOT_IP,
2589 )
2590 testPacket("LLC - SNAP - Max bogus payload",
2591 scapy.LLC(dsap=0xaa, ssap=0xaa, ctrl=0x03)/ \
2592 scapy.SNAP(OUI=0x000000, code=0x3) / ("S" * (1500 - 3 - 5)),
2593 IS_SNAP_NOT_IP,
2594 )
2595 testPacket("LLC - SNAP - IP - TCP",
2596 scapy.LLC(dsap=0xaa, ssap=0xaa, ctrl=0x03)/ \
2597 scapy.SNAP(OUI=0x000000, code=0x800)/ \
2598 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, proto=6)/ \
2599 scapy.TCP(sport=tcp_sport, dport=tcp_dport),
2600 IS_SNAP_AND_IP,
2601 )
2602
2603
2604class DirectArpPackets(DirectBadPacketBase):
2605 """
2606 Verify ARP parsing (valid and corrupted packets) and ARP matching
2607 """
2608 def runTest(self):
2609 self.testArpHandling()
2610
2611 def testArpHandling(self):
2612 dl_dst='00:01:02:03:04:05'
2613 dl_src='00:06:07:08:09:0a'
2614 ip_src='192.168.0.1'
2615 ip_dst='192.168.0.2'
2616 ip_src2='192.168.1.1'
2617 ip_dst2='192.168.1.2'
2618 ip_tos=0
2619 tcp_sport=1234
2620 tcp_dport=80
2621
2622 def testPacket(title, arp_match, arp_pkt, result):
2623 pkts = []
2624
2625 match_pkt = scapy.Ether(dst=dl_dst, src=dl_src) / arp_match
2626 match = packet_to_flow_match(self, match_pkt)
2627 self.assertTrue(match is not None,
2628 "Could not generate flow match from pkt")
2629 match.wildcards &= ~ofp.OFPFW_IN_PORT
2630
2631 pkts.append([
2632 title,
2633 scapy.Ether(dst=dl_dst, src=dl_src) / arp_pkt,
2634 result,
2635 ])
2636
2637 act = action.action_output()
2638 self.testPktsAgainstFlow(pkts, act, match)
2639
2640 testPacket("Basic ARP",
2641 scapy.ARP(psrc=ip_src, pdst=ip_dst, op = 1),
2642 scapy.ARP(hwdst = '00:00:00:00:00:00', hwsrc = dl_src,
2643 psrc = ip_src, pdst = ip_dst, hwlen = 6, plen = 4,
2644 ptype = 0x800, hwtype = 1, op = 1),
2645 self.RESULT_MATCH
2646 )
2647 # More stuff:
2648 # - Non matches on any property
2649 # - Corrupted hwlen and plen
2650 # - Other hwtype, ptype
2651 # - Truncated ARP pkt
2652
2653
2654class DirectVlanPackets(DirectBadPacketBase):
2655 """
2656 Verify VLAN parsing (valid and corrupted packets) and ARP matching
2657 """
2658 def runTest(self):
2659 dl_dst='00:01:02:03:04:05'
2660 dl_src='00:06:07:08:09:0a'
2661 ip_src='192.168.0.1'
2662 ip_dst='192.168.0.2'
2663 ip_src2='192.168.1.1'
2664 ip_dst2='192.168.1.2'
2665 ip_tos=0
2666 tcp_sport=1234
2667 tcp_dport=80
2668
2669 def testPacket(title, match, pkt, result):
2670 pkts = []
2671
2672 self.assertTrue(match is not None,
2673 "Could not generate flow match from pkt")
2674 match.wildcards &= ~ofp.OFPFW_IN_PORT
2675
2676 pkts.append([
2677 "%s" % title,
2678 pkt,
2679 result,
2680 ])
2681
2682 act = action.action_output()
2683 self.testPktsAgainstFlow(pkts, act, match)
2684
2685 testPacket("Basic MAC matching - IPv4 payload",
2686 self.createMatch(dl_dst=parse_mac(dl_dst), dl_src=parse_mac(dl_src)),
2687 scapy.Ether(dst=dl_dst, src=dl_src, type=0x800) / scapy.IP(),
2688 self.RESULT_MATCH
2689 )
2690 testPacket("Basic MAC matching - VMware beacon - no payload",
2691 self.createMatch(dl_dst=parse_mac(dl_dst), dl_src=parse_mac(dl_src)),
2692 scapy.Ether(dst=dl_dst, src=dl_src, type=0x8922),
2693 self.RESULT_MATCH
2694 )
2695 testPacket("Basic MAC matching - VMware beacon - with payload",
2696 self.createMatch(dl_dst=parse_mac(dl_dst), dl_src=parse_mac(dl_src)),
2697 scapy.Ether(dst=dl_dst, src=dl_src, type=0x8922)/ ("X" * 1),
2698 self.RESULT_MATCH
2699 )
2700 testPacket("Basic MAC matching - IPv6 payload",
2701 self.createMatch(dl_dst=parse_mac(dl_dst), dl_src=parse_mac(dl_src)),
2702 scapy.Ether(dst=dl_dst, src=dl_src) / scapy.IPv6(),
2703 self.RESULT_MATCH
2704 )
2705 testPacket("Basic MAC matching with VLAN tag present",
2706 self.createMatch(dl_dst=parse_mac(dl_dst), dl_src=parse_mac(dl_src)),
2707 scapy.Ether(dst=dl_dst, src=dl_src)/ \
Christian Dickmann8ac55252012-10-08 22:53:49 -07002708 scapy.Dot1Q(prio=5, vlan=1000)/ \
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002709 scapy.IP(),
2710 self.RESULT_MATCH
2711 )
2712 testPacket("Basic MAC matching with VLAN tag present",
2713 self.createMatch(dl_dst=parse_mac(dl_dst), dl_src=parse_mac(dl_src),
2714 dl_type=0x800),
2715 scapy.Ether(dst=dl_dst, src=dl_src)/ \
Christian Dickmann8ac55252012-10-08 22:53:49 -07002716 scapy.Dot1Q(prio=5, vlan=1000)/ \
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002717 scapy.IP(),
2718 self.RESULT_MATCH
2719 )
2720 testPacket("Ether matching with VLAN tag present - No type match",
2721 self.createMatch(dl_dst=parse_mac(dl_dst), dl_src=parse_mac(dl_src),
2722 dl_type=0x801),
2723 scapy.Ether(dst=dl_dst, src=dl_src)/ \
Christian Dickmann8ac55252012-10-08 22:53:49 -07002724 scapy.Dot1Q(prio=5, vlan=1000)/ \
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002725 scapy.IP(),
2726 self.RESULT_NOMATCH
2727 )
2728 testPacket("Ether matching with VLAN tag present - No type match 0x8100",
2729 self.createMatch(dl_dst=parse_mac(dl_dst), dl_src=parse_mac(dl_src),
2730 dl_type=0x8100),
2731 scapy.Ether(dst=dl_dst, src=dl_src)/ \
Christian Dickmann8ac55252012-10-08 22:53:49 -07002732 scapy.Dot1Q(prio=5, vlan=1000)/ \
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002733 scapy.IP(),
2734 self.RESULT_NOMATCH
2735 )
2736 testPacket("Ether matching with double VLAN tag - Wrong type match",
2737 self.createMatch(dl_dst=parse_mac(dl_dst), dl_src=parse_mac(dl_src),
2738 dl_type=0x800),
2739 scapy.Ether(dst=dl_dst, src=dl_src)/ \
Christian Dickmann8ac55252012-10-08 22:53:49 -07002740 scapy.Dot1Q(prio=5, vlan=1000)/ \
2741 scapy.Dot1Q(prio=3, vlan=1005)/ \
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002742 scapy.IP(),
2743 self.RESULT_NOMATCH
2744 )
2745 testPacket("Ether matching with double VLAN tag - Type match",
2746 self.createMatch(dl_dst=parse_mac(dl_dst), dl_src=parse_mac(dl_src),
2747 dl_type=0x8100),
2748 scapy.Ether(dst=dl_dst, src=dl_src)/ \
Christian Dickmann8ac55252012-10-08 22:53:49 -07002749 scapy.Dot1Q(prio=5, vlan=1000)/ \
2750 scapy.Dot1Q(prio=3, vlan=1005)/ \
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002751 scapy.IP(),
2752 self.RESULT_MATCH
2753 )
2754 testPacket("IP matching - VLAN tag",
2755 self.createMatch(dl_dst=parse_mac(dl_dst), dl_src=parse_mac(dl_src),
2756 dl_type=0x0800,
2757 nw_src=parse_ip(ip_src), nw_dst=parse_ip(ip_dst)),
2758 scapy.Ether(dst=dl_dst, src=dl_src)/ \
Christian Dickmann8ac55252012-10-08 22:53:49 -07002759 scapy.Dot1Q(prio=5, vlan=1000)/ \
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002760 scapy.IP(src=ip_src, dst=ip_dst),
2761 self.RESULT_MATCH
2762 )
2763 # XXX:
2764 # - Matching on VLAN ID and Prio
2765 # - Actions
2766
2767
2768
Dan Talayco9f47f4d2010-06-03 13:54:37 -07002769if __name__ == "__main__":
2770 print "Please run through oft script: ./oft --test_spec=basic"