blob: 7d306989445452b2855c2b00f309b32446720e88 [file] [log] [blame]
Dan Talayco5eba8442010-03-10 13:58:43 -08001"""
2Test cases for testing actions taken on packets
3
4See basic.py for other info.
5
6It is recommended that these definitions be kept in their own
7namespace as different groups of tests will likely define
8similar identifiers.
9
Rich Lane477f4812012-10-04 22:49:00 -070010The switch is actively attempting to contact the controller at the address
11indicated in config.
Dan Talayco5eba8442010-03-10 13:58:43 -080012
13"""
14
Dan Talayco9f47f4d2010-06-03 13:54:37 -070015import copy
Dan Talayco5eba8442010-03-10 13:58:43 -080016import logging
Rich Laneb90a1c42012-10-05 09:16:05 -070017import time
Dan Talayco5eba8442010-03-10 13:58:43 -080018import unittest
Christian Dickmann8b59b4b2012-09-23 16:48:30 -070019import random
Dan Talayco5eba8442010-03-10 13:58:43 -080020
Rich Lane477f4812012-10-04 22:49:00 -070021from oftest import config
Dan Talayco5eba8442010-03-10 13:58:43 -080022import oftest.controller as controller
23import oftest.cstruct as ofp
24import oftest.message as message
25import oftest.dataplane as dataplane
26import oftest.action as action
27import oftest.parse as parse
Rich Laneb90a1c42012-10-05 09:16:05 -070028import oftest.base_tests as base_tests
29import basic # for IterCases
Dan Talayco5eba8442010-03-10 13:58:43 -080030
Christian Dickmann8b59b4b2012-09-23 16:48:30 -070031from oftest.parse import parse_mac, parse_ip
32
Rich Laneda3b5ad2012-10-03 09:05:32 -070033from oftest.testutils import *
Dan Talayco5eba8442010-03-10 13:58:43 -080034
Dan Talayco551befa2010-07-15 17:05:32 -070035WILDCARD_VALUES = [ofp.OFPFW_IN_PORT,
Dan Talayco488fbc52012-04-09 16:30:41 -070036 ofp.OFPFW_DL_VLAN | ofp.OFPFW_DL_VLAN_PCP,
Dan Talayco551befa2010-07-15 17:05:32 -070037 ofp.OFPFW_DL_SRC,
38 ofp.OFPFW_DL_DST,
Dan Talayco488fbc52012-04-09 16:30:41 -070039 (ofp.OFPFW_DL_TYPE | ofp.OFPFW_NW_SRC_ALL |
40 ofp.OFPFW_NW_DST_ALL | ofp.OFPFW_NW_TOS | ofp.OFPFW_NW_PROTO |
41 ofp.OFPFW_TP_SRC | ofp.OFPFW_TP_DST),
42 (ofp.OFPFW_NW_PROTO | ofp.OFPFW_TP_SRC | ofp.OFPFW_TP_DST),
Dan Talayco551befa2010-07-15 17:05:32 -070043 ofp.OFPFW_TP_SRC,
44 ofp.OFPFW_TP_DST,
Dan Talayco488fbc52012-04-09 16:30:41 -070045 ofp.OFPFW_NW_SRC_MASK,
46 ofp.OFPFW_NW_DST_MASK,
Dan Talayco551befa2010-07-15 17:05:32 -070047 ofp.OFPFW_DL_VLAN_PCP,
48 ofp.OFPFW_NW_TOS]
49
Dan Talayco488fbc52012-04-09 16:30:41 -070050NO_WILDCARD_VALUES = [(ofp.OFPFW_ALL ^ ofp.OFPFW_IN_PORT),
51 (ofp.OFPFW_ALL ^ ofp.OFPFW_DL_VLAN),
52 (ofp.OFPFW_ALL ^ ofp.OFPFW_DL_SRC),
53 (ofp.OFPFW_ALL ^ ofp.OFPFW_DL_DST),
54 (ofp.OFPFW_ALL ^ ofp.OFPFW_DL_TYPE),
55 (ofp.OFPFW_ALL ^ ofp.OFPFW_DL_TYPE ^ ofp.OFPFW_NW_PROTO),
56 (ofp.OFPFW_ALL ^ ofp.OFPFW_DL_TYPE ^ ofp.OFPFW_NW_PROTO ^
57 ofp.OFPFW_TP_SRC),
58 (ofp.OFPFW_ALL ^ ofp.OFPFW_DL_TYPE ^ ofp.OFPFW_NW_PROTO ^
59 ofp.OFPFW_TP_DST),
60 (ofp.OFPFW_ALL ^ ofp.OFPFW_DL_TYPE ^ ofp.OFPFW_NW_PROTO ^
61 ofp.OFPFW_NW_SRC_MASK),
62 (ofp.OFPFW_ALL ^ ofp.OFPFW_DL_TYPE ^ ofp.OFPFW_NW_PROTO ^
63 ofp.OFPFW_NW_DST_MASK),
64 (ofp.OFPFW_ALL ^ ofp.OFPFW_DL_VLAN ^ ofp.OFPFW_DL_VLAN_PCP),
65 (ofp.OFPFW_ALL ^ ofp.OFPFW_DL_TYPE ^ ofp.OFPFW_NW_PROTO ^
66 ofp.OFPFW_NW_TOS)]
67
Dan Talayco551befa2010-07-15 17:05:32 -070068MODIFY_ACTION_VALUES = [ofp.OFPAT_SET_VLAN_VID,
69 ofp.OFPAT_SET_VLAN_PCP,
70 ofp.OFPAT_STRIP_VLAN,
71 ofp.OFPAT_SET_DL_SRC,
72 ofp.OFPAT_SET_DL_DST,
73 ofp.OFPAT_SET_NW_SRC,
74 ofp.OFPAT_SET_NW_DST,
75 ofp.OFPAT_SET_NW_TOS,
76 ofp.OFPAT_SET_TP_SRC,
77 ofp.OFPAT_SET_TP_DST]
78
Dan Talayco21381562010-07-17 00:34:47 -070079TEST_VID_DEFAULT = 2
80
Rich Lane97e99652013-01-02 17:23:20 -080081@group('smoke')
Rich Laneb90a1c42012-10-05 09:16:05 -070082class DirectPacket(base_tests.SimpleDataPlane):
Dan Talayco5eba8442010-03-10 13:58:43 -080083 """
Dan Talayco2d0d49a2010-05-11 15:29:08 -070084 Send packet to single egress port
Dan Talayco5eba8442010-03-10 13:58:43 -080085
86 Generate a packet
87 Generate and install a matching flow
88 Add action to direct the packet to an egress port
89 Send the packet to ingress dataplane port
90 Verify the packet is received at the egress port only
91 """
92 def runTest(self):
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -070093 self.handleFlow()
94
95 def handleFlow(self, pkttype='TCP'):
Rich Lane477f4812012-10-04 22:49:00 -070096 of_ports = config["port_map"].keys()
Dan Talayco5eba8442010-03-10 13:58:43 -080097 of_ports.sort()
98 self.assertTrue(len(of_ports) > 1, "Not enough ports for test")
99
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700100 if (pkttype == 'ICMP'):
101 pkt = simple_icmp_packet()
102 else:
103 pkt = simple_tcp_packet()
Ed Swierk99a74de2012-08-22 06:40:54 -0700104 match = packet_to_flow_match(self, pkt)
Dan Talayco7dd6cd62010-03-16 15:02:35 -0700105 match.wildcards &= ~ofp.OFPFW_IN_PORT
Dan Talayco5eba8442010-03-10 13:58:43 -0800106 self.assertTrue(match is not None,
107 "Could not generate flow match from pkt")
108 act = action.action_output()
109
110 for idx in range(len(of_ports)):
Rich Lane32bf9482013-01-03 17:26:30 -0800111 delete_all_flows(self.controller)
Dan Talayco2e77a842010-05-12 15:39:46 -0700112
Dan Talayco5eba8442010-03-10 13:58:43 -0800113 ingress_port = of_ports[idx]
114 egress_port = of_ports[(idx + 1) % len(of_ports)]
Rich Lane9a003812012-10-04 17:17:59 -0700115 logging.info("Ingress " + str(ingress_port) +
Dan Talayco551befa2010-07-15 17:05:32 -0700116 " to egress " + str(egress_port))
Dan Talayco5eba8442010-03-10 13:58:43 -0800117
118 match.in_port = ingress_port
119
120 request = message.flow_mod()
121 request.match = match
Jeffrey Townsend2a300e42012-03-28 17:24:02 -0700122
Dan Talayco5eba8442010-03-10 13:58:43 -0800123 request.buffer_id = 0xffffffff
124 act.port = egress_port
Rich Lanee30455b2013-01-03 16:24:44 -0800125 request.actions.add(act)
Dan Talayco5eba8442010-03-10 13:58:43 -0800126
Rich Lane9a003812012-10-04 17:17:59 -0700127 logging.info("Inserting flow")
Rich Lane5c3151c2013-01-03 17:15:41 -0800128 self.controller.message_send(request)
Rich Lane3a261d52013-01-03 17:45:08 -0800129 do_barrier(self.controller)
Dan Talayco5eba8442010-03-10 13:58:43 -0800130
Rich Lane9a003812012-10-04 17:17:59 -0700131 logging.info("Sending packet to dp port " +
Dan Talayco5eba8442010-03-10 13:58:43 -0800132 str(ingress_port))
133 self.dataplane.send(ingress_port, str(pkt))
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700134
135 exp_pkt_arg = None
136 exp_port = None
Rich Lane477f4812012-10-04 22:49:00 -0700137 if config["relax"]:
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700138 exp_pkt_arg = pkt
139 exp_port = egress_port
140
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700141 (rcv_port, rcv_pkt, pkt_time) = self.dataplane.poll(port_number=exp_port,
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700142 exp_pkt=exp_pkt_arg)
Dan Talayco5eba8442010-03-10 13:58:43 -0800143 self.assertTrue(rcv_pkt is not None, "Did not receive packet")
Rich Lane9a003812012-10-04 17:17:59 -0700144 logging.debug("Packet len " + str(len(rcv_pkt)) + " in on " +
Dan Talayco5eba8442010-03-10 13:58:43 -0800145 str(rcv_port))
146 self.assertEqual(rcv_port, egress_port, "Unexpected receive port")
147 self.assertEqual(str(pkt), str(rcv_pkt),
148 'Response packet does not match send packet')
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700149
Rich Lane97e99652013-01-02 17:23:20 -0800150@group('smoke')
Rich Laneb90a1c42012-10-05 09:16:05 -0700151class DirectPacketController(base_tests.SimpleDataPlane):
Rich Lane51c23b32012-07-27 16:37:25 -0700152 """
153 Send packet to the controller port
154
155 Generate a packet
156 Generate and install a matching flow
157 Add action to direct the packet to the controller port
158 Send the packet to ingress dataplane port
159 Verify the packet is received at the controller port
160 """
161 def runTest(self):
162 self.handleFlow()
163
164 def handleFlow(self, pkttype='TCP'):
Rich Lane477f4812012-10-04 22:49:00 -0700165 of_ports = config["port_map"].keys()
Rich Lane51c23b32012-07-27 16:37:25 -0700166 of_ports.sort()
167 self.assertTrue(len(of_ports) > 0, "Not enough ports for test")
168
169 if (pkttype == 'ICMP'):
170 pkt = simple_icmp_packet()
171 else:
172 pkt = simple_tcp_packet()
Ed Swierk99a74de2012-08-22 06:40:54 -0700173 match = packet_to_flow_match(self, pkt)
Rich Lane51c23b32012-07-27 16:37:25 -0700174 match.wildcards &= ~ofp.OFPFW_IN_PORT
175 self.assertTrue(match is not None,
176 "Could not generate flow match from pkt")
177 act = action.action_output()
178
Rich Lane32bf9482013-01-03 17:26:30 -0800179 delete_all_flows(self.controller)
Rich Lane51c23b32012-07-27 16:37:25 -0700180
181 ingress_port = of_ports[0]
182 match.in_port = ingress_port
183
184 request = message.flow_mod()
185 request.match = match
186
187 request.buffer_id = 0xffffffff
188 act.port = ofp.OFPP_CONTROLLER
189 act.max_len = 65535
Rich Lanee30455b2013-01-03 16:24:44 -0800190 request.actions.add(act)
Rich Lane51c23b32012-07-27 16:37:25 -0700191
Rich Lane9a003812012-10-04 17:17:59 -0700192 logging.info("Inserting flow")
Rich Lane5c3151c2013-01-03 17:15:41 -0800193 self.controller.message_send(request)
Rich Lane3a261d52013-01-03 17:45:08 -0800194 do_barrier(self.controller)
Rich Lane51c23b32012-07-27 16:37:25 -0700195
Rich Lane9a003812012-10-04 17:17:59 -0700196 logging.info("Sending packet to dp port " +
Rich Lane51c23b32012-07-27 16:37:25 -0700197 str(ingress_port))
198 self.dataplane.send(ingress_port, str(pkt))
199
200 (response, raw) = self.controller.poll(ofp.OFPT_PACKET_IN)
201
202 self.assertTrue(response is not None,
203 'Packet in message not received by controller')
204 if not dataplane.match_exp_pkt(pkt, response.data):
Rich Lane9a003812012-10-04 17:17:59 -0700205 logging.debug("Sent %s" % format_packet(pkt))
206 logging.debug("Resp %s" % format_packet(response.data))
Rich Lane51c23b32012-07-27 16:37:25 -0700207 self.assertTrue(False,
208 'Response packet does not match send packet' +
209 ' for controller port')
210
Howard Pershf97840f2012-04-10 16:30:42 -0700211
Rich Laneb90a1c42012-10-05 09:16:05 -0700212class DirectPacketQueue(base_tests.SimpleDataPlane):
Howard Pershf97840f2012-04-10 16:30:42 -0700213 """
214 Send packet to single queue on single egress port
215
216 Generate a packet
217 Generate and install a matching flow
218 Add action to direct the packet to an egress port and queue
219 Send the packet to ingress dataplane port
220 Verify the packet is received at the egress port only
221 """
222 def runTest(self):
223 self.handleFlow()
224
Howard Persh670b5672012-04-13 09:08:29 -0700225 def portQueuesGet(self, queue_stats, port_num):
226 result = []
227 for qs in queue_stats.stats:
228 if qs.port_no != port_num:
229 continue
230 result.append(qs.queue_id)
231 return result
232
Howard Pershf97840f2012-04-10 16:30:42 -0700233 def handleFlow(self, pkttype='TCP'):
Rich Lane477f4812012-10-04 22:49:00 -0700234 of_ports = config["port_map"].keys()
Howard Pershf97840f2012-04-10 16:30:42 -0700235 of_ports.sort()
236 self.assertTrue(len(of_ports) > 1, "Not enough ports for test")
237
238 if (pkttype == 'ICMP'):
239 pkt = simple_icmp_packet()
240 else:
241 pkt = simple_tcp_packet()
Ed Swierk99a74de2012-08-22 06:40:54 -0700242 match = packet_to_flow_match(self, pkt)
Howard Pershf97840f2012-04-10 16:30:42 -0700243 match.wildcards &= ~ofp.OFPFW_IN_PORT
244 self.assertTrue(match is not None,
245 "Could not generate flow match from pkt")
246
Howard Persh670b5672012-04-13 09:08:29 -0700247 # Get queue stats from switch
248
249 request = message.queue_stats_request()
250 request.port_no = ofp.OFPP_ALL
251 request.queue_id = ofp.OFPQ_ALL
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700252 (queue_stats, p) = self.controller.transact(request)
Howard Persh670b5672012-04-13 09:08:29 -0700253 self.assertNotEqual(queue_stats, None, "Queue stats request failed")
254
255 act = action.action_enqueue()
Howard Pershf97840f2012-04-10 16:30:42 -0700256
257 for idx in range(len(of_ports)):
Howard Pershf97840f2012-04-10 16:30:42 -0700258 ingress_port = of_ports[idx]
259 egress_port = of_ports[(idx + 1) % len(of_ports)]
Howard Pershf97840f2012-04-10 16:30:42 -0700260
Howard Persh670b5672012-04-13 09:08:29 -0700261 for egress_queue_id in self.portQueuesGet(queue_stats, egress_port):
Rich Lane9a003812012-10-04 17:17:59 -0700262 logging.info("Ingress " + str(ingress_port)
Howard Persh670b5672012-04-13 09:08:29 -0700263 + " to egress " + str(egress_port)
264 + " queue " + str(egress_queue_id)
265 )
Howard Pershf97840f2012-04-10 16:30:42 -0700266
Rich Lane32bf9482013-01-03 17:26:30 -0800267 delete_all_flows(self.controller)
Howard Pershf97840f2012-04-10 16:30:42 -0700268
Howard Persh670b5672012-04-13 09:08:29 -0700269 match.in_port = ingress_port
270
271 request = message.flow_mod()
272 request.match = match
Howard Pershf97840f2012-04-10 16:30:42 -0700273
Howard Persh670b5672012-04-13 09:08:29 -0700274 request.buffer_id = 0xffffffff
275 act.port = egress_port
276 act.queue_id = egress_queue_id
Rich Lanee30455b2013-01-03 16:24:44 -0800277 request.actions.add(act)
Howard Pershf97840f2012-04-10 16:30:42 -0700278
Rich Lane9a003812012-10-04 17:17:59 -0700279 logging.info("Inserting flow")
Rich Lane5c3151c2013-01-03 17:15:41 -0800280 self.controller.message_send(request)
Rich Lane3a261d52013-01-03 17:45:08 -0800281 do_barrier(self.controller)
Howard Pershf97840f2012-04-10 16:30:42 -0700282
Howard Persh670b5672012-04-13 09:08:29 -0700283 # Get current stats for selected egress queue
Howard Pershf97840f2012-04-10 16:30:42 -0700284
Howard Persh670b5672012-04-13 09:08:29 -0700285 request = message.queue_stats_request()
286 request.port_no = egress_port
287 request.queue_id = egress_queue_id
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700288 (qs_before, p) = self.controller.transact(request)
Howard Persh670b5672012-04-13 09:08:29 -0700289 self.assertNotEqual(qs_before, None, "Queue stats request failed")
290
Rich Lane9a003812012-10-04 17:17:59 -0700291 logging.info("Sending packet to dp port " +
Howard Persh670b5672012-04-13 09:08:29 -0700292 str(ingress_port))
293 self.dataplane.send(ingress_port, str(pkt))
294
295 exp_pkt_arg = None
296 exp_port = None
Rich Lane477f4812012-10-04 22:49:00 -0700297 if config["relax"]:
Howard Persh670b5672012-04-13 09:08:29 -0700298 exp_pkt_arg = pkt
299 exp_port = egress_port
300
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700301 (rcv_port, rcv_pkt, pkt_time) = self.dataplane.poll(port_number=exp_port,
Howard Persh670b5672012-04-13 09:08:29 -0700302 exp_pkt=exp_pkt_arg)
303 self.assertTrue(rcv_pkt is not None, "Did not receive packet")
Rich Lane9a003812012-10-04 17:17:59 -0700304 logging.debug("Packet len " + str(len(rcv_pkt)) + " in on " +
Howard Persh670b5672012-04-13 09:08:29 -0700305 str(rcv_port))
306 self.assertEqual(rcv_port, egress_port, "Unexpected receive port")
307 self.assertEqual(str(pkt), str(rcv_pkt),
308 'Response packet does not match send packet')
309
Ed Swierkb8a86512012-04-18 18:45:58 -0700310 # FIXME: instead of sleeping, keep requesting queue stats until
311 # the expected queue counter increases or some large timeout is
312 # reached
313 time.sleep(2)
314
Howard Persh670b5672012-04-13 09:08:29 -0700315 # Get current stats for selected egress queue again
316
317 request = message.queue_stats_request()
318 request.port_no = egress_port
319 request.queue_id = egress_queue_id
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700320 (qs_after, p) = self.controller.transact(request)
Howard Persh670b5672012-04-13 09:08:29 -0700321 self.assertNotEqual(qs_after, None, "Queue stats request failed")
322
323 # Make sure that tx packet counter for selected egress queue was
324 # incremented
325
Ed Swierk22f59152012-04-17 16:36:47 -0700326 self.assertEqual(qs_after.stats[0].tx_packets, \
327 qs_before.stats[0].tx_packets + 1, \
Howard Persh670b5672012-04-13 09:08:29 -0700328 "Verification of egress queue tx packet count failed"
329 )
330
331
Rich Laneb90a1c42012-10-05 09:16:05 -0700332class DirectPacketControllerQueue(base_tests.SimpleDataPlane):
Ken Chiang899ff8e2012-05-23 18:26:12 -0700333 """
334 Send a packet from each of the openflow ports
335 to each of the queues configured on the controller port.
336 If no queues have been configured, no packets are sent.
Howard Pershf97840f2012-04-10 16:30:42 -0700337
Ken Chiang899ff8e2012-05-23 18:26:12 -0700338 Generate a packet
339 Generate and install a matching flow
340 Add action to direct the packet to one of the controller port queues
341 Send the packet to ingress dataplane port
342 Verify the packet is received on the controller port queue
343 """
344 def runTest(self):
345 self.handleFlow()
346
347 def portQueuesGet(self, queue_stats, port_num):
348 result = []
349 for qs in queue_stats.stats:
350 if qs.port_no != port_num:
351 continue
352 result.append(qs.queue_id)
353 return result
354
355 def handleFlow(self, pkttype='TCP'):
Rich Lane477f4812012-10-04 22:49:00 -0700356 of_ports = config["port_map"].keys()
Ken Chiang899ff8e2012-05-23 18:26:12 -0700357 of_ports.sort()
358 self.assertTrue(len(of_ports) > 1, "Not enough ports for test")
359
360 if (pkttype == 'ICMP'):
361 pkt = simple_icmp_packet()
362 else:
363 pkt = simple_tcp_packet()
Ed Swierk99a74de2012-08-22 06:40:54 -0700364 match = packet_to_flow_match(self, pkt)
Ken Chiang899ff8e2012-05-23 18:26:12 -0700365 match.wildcards &= ~ofp.OFPFW_IN_PORT
366 self.assertTrue(match is not None,
367 "Could not generate flow match from pkt")
368
369 # Get queue stats from switch
370
371 request = message.queue_stats_request()
372 request.port_no = ofp.OFPP_CONTROLLER
373 request.queue_id = ofp.OFPQ_ALL
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700374 (queue_stats, p) = self.controller.transact(request)
Ken Chiang899ff8e2012-05-23 18:26:12 -0700375 self.assertNotEqual(queue_stats, None, "Queue stats request failed")
Rich Laneb8c845a2012-12-31 17:23:51 -0800376 if queue_stats.header.type == ofp.OFPT_ERROR:
377 skip_message_emit(self, "Enqueue packet to controller")
378 return
Ken Chiang899ff8e2012-05-23 18:26:12 -0700379
380 act = action.action_enqueue()
381
382 for idx in range(len(of_ports)):
383 ingress_port = of_ports[idx]
384 egress_port = ofp.OFPP_CONTROLLER
385
Rich Lane9a003812012-10-04 17:17:59 -0700386 logging.info("Ingress port " + str(ingress_port)
Ken Chiang899ff8e2012-05-23 18:26:12 -0700387 + ", controller port queues "
388 + str(self.portQueuesGet(queue_stats, egress_port)))
389
390 for egress_queue_id in self.portQueuesGet(queue_stats, egress_port):
Rich Lane9a003812012-10-04 17:17:59 -0700391 logging.info("Ingress " + str(ingress_port)
Ken Chiang899ff8e2012-05-23 18:26:12 -0700392 + " to egress " + str(egress_port)
393 + " queue " + str(egress_queue_id)
394 )
395
Rich Lane32bf9482013-01-03 17:26:30 -0800396 delete_all_flows(self.controller)
Ken Chiang899ff8e2012-05-23 18:26:12 -0700397
398 match.in_port = ingress_port
399
400 request = message.flow_mod()
401 request.match = match
402
403 request.buffer_id = 0xffffffff
404 act.port = egress_port
405 act.queue_id = egress_queue_id
Rich Lanee30455b2013-01-03 16:24:44 -0800406 request.actions.add(act)
Ken Chiang899ff8e2012-05-23 18:26:12 -0700407
Rich Lane9a003812012-10-04 17:17:59 -0700408 logging.info("Inserting flow")
Rich Lane5c3151c2013-01-03 17:15:41 -0800409 self.controller.message_send(request)
Rich Lane3a261d52013-01-03 17:45:08 -0800410 do_barrier(self.controller)
Ken Chiang899ff8e2012-05-23 18:26:12 -0700411
412 # Get current stats for selected egress queue
413
414 request = message.queue_stats_request()
415 request.port_no = egress_port
416 request.queue_id = egress_queue_id
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700417 (qs_before, p) = self.controller.transact(request)
Ken Chiang899ff8e2012-05-23 18:26:12 -0700418 self.assertNotEqual(qs_before, None, "Queue stats request failed")
419
Rich Lane9a003812012-10-04 17:17:59 -0700420 logging.info("Sending packet to dp port " +
Ken Chiang899ff8e2012-05-23 18:26:12 -0700421 str(ingress_port))
422 self.dataplane.send(ingress_port, str(pkt))
423
424 exp_pkt_arg = None
425 exp_port = None
426
Rich Lanee5779d32012-10-05 17:56:04 -0700427 count = 0
Ken Chiang899ff8e2012-05-23 18:26:12 -0700428 while True:
Dan Talaycoc689a792012-09-28 14:22:53 -0700429 (response, raw) = self.controller.poll(ofp.OFPT_PACKET_IN)
Ken Chiang899ff8e2012-05-23 18:26:12 -0700430 if not response: # Timeout
431 break
432 if dataplane.match_exp_pkt(pkt, response.data): # Got match
433 break
Rich Lane477f4812012-10-04 22:49:00 -0700434 if not config["relax"]: # Only one attempt to match
Ken Chiang899ff8e2012-05-23 18:26:12 -0700435 break
436 count += 1
437 if count > 10: # Too many tries
438 break
439
440 self.assertTrue(response is not None,
441 'Packet in message not received by controller')
442 if not dataplane.match_exp_pkt(pkt, response.data):
Rich Lane9a003812012-10-04 17:17:59 -0700443 logging.debug("Sent %s" % format_packet(pkt))
444 logging.debug("Resp %s" % format_packet(response.data))
Ken Chiang899ff8e2012-05-23 18:26:12 -0700445 self.assertTrue(False,
446 'Response packet does not match send packet' +
447 ' for controller port')
448
449 # FIXME: instead of sleeping, keep requesting queue stats until
450 # the expected queue counter increases or some large timeout is
451 # reached
452 time.sleep(2)
453
454 # Get current stats for selected egress queue again
455
456 request = message.queue_stats_request()
457 request.port_no = egress_port
458 request.queue_id = egress_queue_id
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700459 (qs_after, p) = self.controller.transact(request)
Ken Chiang899ff8e2012-05-23 18:26:12 -0700460 self.assertNotEqual(qs_after, None, "Queue stats request failed")
461
462 # Make sure that tx packet counter for selected egress queue was
463 # incremented
464
465 self.assertEqual(qs_after.stats[0].tx_packets, \
466 qs_before.stats[0].tx_packets + 1, \
467 "Verification of egress queue tx packet count failed"
468 )
469
Howard Pershf97840f2012-04-10 16:30:42 -0700470
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700471class DirectPacketICMP(DirectPacket):
472 """
473 Send ICMP packet to single egress port
474
475 Generate a ICMP packet
476 Generate and install a matching flow
477 Add action to direct the packet to an egress port
478 Send the packet to ingress dataplane port
479 Verify the packet is received at the egress port only
480 Difference from DirectPacket test is that sent packet is ICMP
481 """
482 def runTest(self):
483 self.handleFlow(pkttype='ICMP')
Dan Talayco2d0d49a2010-05-11 15:29:08 -0700484
Rich Laneb90a1c42012-10-05 09:16:05 -0700485class DirectTwoPorts(base_tests.SimpleDataPlane):
Dan Talayco2d0d49a2010-05-11 15:29:08 -0700486 """
487 Send packet to two egress ports
488
489 Generate a packet
490 Generate and install a matching flow
491 Add action to direct the packet to two egress ports
492 Send the packet to ingress dataplane port
493 Verify the packet is received at the two egress ports
494 """
495 def runTest(self):
Rich Lane477f4812012-10-04 22:49:00 -0700496 of_ports = config["port_map"].keys()
Dan Talayco2d0d49a2010-05-11 15:29:08 -0700497 of_ports.sort()
498 self.assertTrue(len(of_ports) > 2, "Not enough ports for test")
499
Dan Talayco2d0d49a2010-05-11 15:29:08 -0700500 pkt = simple_tcp_packet()
Ed Swierk99a74de2012-08-22 06:40:54 -0700501 match = packet_to_flow_match(self, pkt)
Dan Talayco2d0d49a2010-05-11 15:29:08 -0700502 match.wildcards &= ~ofp.OFPFW_IN_PORT
503 self.assertTrue(match is not None,
504 "Could not generate flow match from pkt")
505 act = action.action_output()
506
507 for idx in range(len(of_ports)):
Rich Lane32bf9482013-01-03 17:26:30 -0800508 delete_all_flows(self.controller)
Dan Talayco2e77a842010-05-12 15:39:46 -0700509
Dan Talayco2d0d49a2010-05-11 15:29:08 -0700510 ingress_port = of_ports[idx]
511 egress_port1 = of_ports[(idx + 1) % len(of_ports)]
512 egress_port2 = of_ports[(idx + 2) % len(of_ports)]
Rich Lane9a003812012-10-04 17:17:59 -0700513 logging.info("Ingress " + str(ingress_port) +
Dan Talayco2d0d49a2010-05-11 15:29:08 -0700514 " to egress " + str(egress_port1) + " and " +
515 str(egress_port2))
516
517 match.in_port = ingress_port
518
519 request = message.flow_mod()
520 request.match = match
521 request.buffer_id = 0xffffffff
522 act.port = egress_port1
Rich Lanee30455b2013-01-03 16:24:44 -0800523 request.actions.add(act)
Dan Talayco2d0d49a2010-05-11 15:29:08 -0700524 act.port = egress_port2
Rich Lanee30455b2013-01-03 16:24:44 -0800525 request.actions.add(act)
Rich Lane9a003812012-10-04 17:17:59 -0700526 # logging.info(request.show())
Dan Talayco2d0d49a2010-05-11 15:29:08 -0700527
Rich Lane9a003812012-10-04 17:17:59 -0700528 logging.info("Inserting flow")
Rich Lane5c3151c2013-01-03 17:15:41 -0800529 self.controller.message_send(request)
Rich Lane3a261d52013-01-03 17:45:08 -0800530 do_barrier(self.controller)
Dan Talayco2d0d49a2010-05-11 15:29:08 -0700531
Rich Lane9a003812012-10-04 17:17:59 -0700532 logging.info("Sending packet to dp port " +
Dan Talayco2d0d49a2010-05-11 15:29:08 -0700533 str(ingress_port))
534 self.dataplane.send(ingress_port, str(pkt))
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700535 yes_ports = set([egress_port1, egress_port2])
536 no_ports = set(of_ports).difference(yes_ports)
Dan Talayco2d0d49a2010-05-11 15:29:08 -0700537
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700538 receive_pkt_check(self.dataplane, pkt, yes_ports, no_ports,
Rich Lane2014f9b2012-10-05 15:29:40 -0700539 self)
Dan Talaycob0b0fdb2010-05-11 15:44:56 -0700540
Rich Laneb90a1c42012-10-05 09:16:05 -0700541class DirectMCNonIngress(base_tests.SimpleDataPlane):
Dan Talaycob0b0fdb2010-05-11 15:44:56 -0700542 """
543 Multicast to all non-ingress ports
544
545 Generate a packet
546 Generate and install a matching flow
547 Add action to direct the packet to all non-ingress ports
548 Send the packet to ingress dataplane port
549 Verify the packet is received at all non-ingress ports
550
551 Does not use the flood action
552 """
553 def runTest(self):
Rich Lane477f4812012-10-04 22:49:00 -0700554 of_ports = config["port_map"].keys()
Dan Talaycob0b0fdb2010-05-11 15:44:56 -0700555 of_ports.sort()
556 self.assertTrue(len(of_ports) > 2, "Not enough ports for test")
557
Dan Talaycob0b0fdb2010-05-11 15:44:56 -0700558 pkt = simple_tcp_packet()
Ed Swierk99a74de2012-08-22 06:40:54 -0700559 match = packet_to_flow_match(self, pkt)
Dan Talaycob0b0fdb2010-05-11 15:44:56 -0700560 match.wildcards &= ~ofp.OFPFW_IN_PORT
561 self.assertTrue(match is not None,
562 "Could not generate flow match from pkt")
563 act = action.action_output()
564
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700565 for ingress_port in of_ports:
Rich Lane32bf9482013-01-03 17:26:30 -0800566 delete_all_flows(self.controller)
Dan Talayco2e77a842010-05-12 15:39:46 -0700567
Rich Lane9a003812012-10-04 17:17:59 -0700568 logging.info("Ingress " + str(ingress_port) +
Dan Talaycob0b0fdb2010-05-11 15:44:56 -0700569 " all non-ingress ports")
Dan Talaycob0b0fdb2010-05-11 15:44:56 -0700570 match.in_port = ingress_port
571
572 request = message.flow_mod()
573 request.match = match
574 request.buffer_id = 0xffffffff
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700575 for egress_port in of_ports:
576 if egress_port == ingress_port:
Dan Talaycob0b0fdb2010-05-11 15:44:56 -0700577 continue
Dan Talaycob0b0fdb2010-05-11 15:44:56 -0700578 act.port = egress_port
Rich Lanee30455b2013-01-03 16:24:44 -0800579 request.actions.add(act)
Rich Lane9a003812012-10-04 17:17:59 -0700580 logging.debug(request.show())
Dan Talaycob0b0fdb2010-05-11 15:44:56 -0700581
Rich Lane9a003812012-10-04 17:17:59 -0700582 logging.info("Inserting flow")
Rich Lane5c3151c2013-01-03 17:15:41 -0800583 self.controller.message_send(request)
Rich Lane3a261d52013-01-03 17:45:08 -0800584 do_barrier(self.controller)
Dan Talaycob0b0fdb2010-05-11 15:44:56 -0700585
Rich Lane9a003812012-10-04 17:17:59 -0700586 logging.info("Sending packet to dp port " + str(ingress_port))
Dan Talaycob0b0fdb2010-05-11 15:44:56 -0700587 self.dataplane.send(ingress_port, str(pkt))
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700588 yes_ports = set(of_ports).difference([ingress_port])
589 receive_pkt_check(self.dataplane, pkt, yes_ports, [ingress_port],
Rich Lane2014f9b2012-10-05 15:29:40 -0700590 self)
Dan Talaycob0b0fdb2010-05-11 15:44:56 -0700591
Dan Talayco32fa6542010-05-11 15:54:08 -0700592
Rich Laneb90a1c42012-10-05 09:16:05 -0700593class DirectMC(base_tests.SimpleDataPlane):
Dan Talayco32fa6542010-05-11 15:54:08 -0700594 """
595 Multicast to all ports including ingress
596
597 Generate a packet
598 Generate and install a matching flow
599 Add action to direct the packet to all non-ingress ports
600 Send the packet to ingress dataplane port
601 Verify the packet is received at all ports
602
603 Does not use the flood action
604 """
605 def runTest(self):
Rich Lane477f4812012-10-04 22:49:00 -0700606 of_ports = config["port_map"].keys()
Dan Talayco32fa6542010-05-11 15:54:08 -0700607 of_ports.sort()
608 self.assertTrue(len(of_ports) > 2, "Not enough ports for test")
609
Dan Talayco32fa6542010-05-11 15:54:08 -0700610 pkt = simple_tcp_packet()
Ed Swierk99a74de2012-08-22 06:40:54 -0700611 match = packet_to_flow_match(self, pkt)
Dan Talayco32fa6542010-05-11 15:54:08 -0700612 match.wildcards &= ~ofp.OFPFW_IN_PORT
613 self.assertTrue(match is not None,
614 "Could not generate flow match from pkt")
615 act = action.action_output()
616
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700617 for ingress_port in of_ports:
Rich Lane32bf9482013-01-03 17:26:30 -0800618 delete_all_flows(self.controller)
Dan Talayco2e77a842010-05-12 15:39:46 -0700619
Rich Lane9a003812012-10-04 17:17:59 -0700620 logging.info("Ingress " + str(ingress_port) + " to all ports")
Dan Talayco32fa6542010-05-11 15:54:08 -0700621 match.in_port = ingress_port
622
623 request = message.flow_mod()
624 request.match = match
625 request.buffer_id = 0xffffffff
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700626 for egress_port in of_ports:
627 if egress_port == ingress_port:
Dan Talayco32fa6542010-05-11 15:54:08 -0700628 act.port = ofp.OFPP_IN_PORT
629 else:
630 act.port = egress_port
Rich Lanee30455b2013-01-03 16:24:44 -0800631 request.actions.add(act)
Rich Lane9a003812012-10-04 17:17:59 -0700632 # logging.info(request.show())
Dan Talayco2e77a842010-05-12 15:39:46 -0700633
Rich Lane9a003812012-10-04 17:17:59 -0700634 logging.info("Inserting flow")
Rich Lane5c3151c2013-01-03 17:15:41 -0800635 self.controller.message_send(request)
Rich Lane3a261d52013-01-03 17:45:08 -0800636 do_barrier(self.controller)
Dan Talayco2e77a842010-05-12 15:39:46 -0700637
Rich Lane9a003812012-10-04 17:17:59 -0700638 logging.info("Sending packet to dp port " + str(ingress_port))
Dan Talayco2e77a842010-05-12 15:39:46 -0700639 self.dataplane.send(ingress_port, str(pkt))
Rich Lane2014f9b2012-10-05 15:29:40 -0700640 receive_pkt_check(self.dataplane, pkt, of_ports, [], self)
Dan Talayco2e77a842010-05-12 15:39:46 -0700641
Rich Laneb90a1c42012-10-05 09:16:05 -0700642class Flood(base_tests.SimpleDataPlane):
Dan Talayco2e77a842010-05-12 15:39:46 -0700643 """
644 Flood to all ports except ingress
645
646 Generate a packet
647 Generate and install a matching flow
648 Add action to flood the packet
649 Send the packet to ingress dataplane port
650 Verify the packet is received at all other ports
651 """
652 def runTest(self):
Rich Lane477f4812012-10-04 22:49:00 -0700653 of_ports = config["port_map"].keys()
Dan Talayco2e77a842010-05-12 15:39:46 -0700654 of_ports.sort()
655 self.assertTrue(len(of_ports) > 1, "Not enough ports for test")
656
657 pkt = simple_tcp_packet()
Ed Swierk99a74de2012-08-22 06:40:54 -0700658 match = packet_to_flow_match(self, pkt)
Dan Talayco2e77a842010-05-12 15:39:46 -0700659 match.wildcards &= ~ofp.OFPFW_IN_PORT
660 self.assertTrue(match is not None,
661 "Could not generate flow match from pkt")
662 act = action.action_output()
663
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700664 for ingress_port in of_ports:
Rich Lane32bf9482013-01-03 17:26:30 -0800665 delete_all_flows(self.controller)
Dan Talayco2e77a842010-05-12 15:39:46 -0700666
Rich Lane9a003812012-10-04 17:17:59 -0700667 logging.info("Ingress " + str(ingress_port) + " to all ports")
Dan Talayco2e77a842010-05-12 15:39:46 -0700668 match.in_port = ingress_port
669
670 request = message.flow_mod()
671 request.match = match
672 request.buffer_id = 0xffffffff
673 act.port = ofp.OFPP_FLOOD
Rich Lanee30455b2013-01-03 16:24:44 -0800674 request.actions.add(act)
Rich Lane9a003812012-10-04 17:17:59 -0700675 logging.info(request.show())
Dan Talayco32fa6542010-05-11 15:54:08 -0700676
Rich Lane9a003812012-10-04 17:17:59 -0700677 logging.info("Inserting flow")
Rich Lane5c3151c2013-01-03 17:15:41 -0800678 self.controller.message_send(request)
Rich Lane3a261d52013-01-03 17:45:08 -0800679 do_barrier(self.controller)
Dan Talayco32fa6542010-05-11 15:54:08 -0700680
Rich Lane9a003812012-10-04 17:17:59 -0700681 logging.info("Sending packet to dp port " + str(ingress_port))
Dan Talayco32fa6542010-05-11 15:54:08 -0700682 self.dataplane.send(ingress_port, str(pkt))
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700683 yes_ports = set(of_ports).difference([ingress_port])
684 receive_pkt_check(self.dataplane, pkt, yes_ports, [ingress_port],
Rich Lane2014f9b2012-10-05 15:29:40 -0700685 self)
Dan Talayco3be5b062010-05-12 15:46:21 -0700686
Rich Laneb90a1c42012-10-05 09:16:05 -0700687class FloodPlusIngress(base_tests.SimpleDataPlane):
Dan Talayco3be5b062010-05-12 15:46:21 -0700688 """
689 Flood to all ports plus send to ingress port
690
691 Generate a packet
692 Generate and install a matching flow
693 Add action to flood the packet
694 Add action to send to ingress port
695 Send the packet to ingress dataplane port
696 Verify the packet is received at all other ports
697 """
698 def runTest(self):
Rich Lane477f4812012-10-04 22:49:00 -0700699 of_ports = config["port_map"].keys()
Dan Talayco3be5b062010-05-12 15:46:21 -0700700 of_ports.sort()
701 self.assertTrue(len(of_ports) > 1, "Not enough ports for test")
702
703 pkt = simple_tcp_packet()
Ed Swierk99a74de2012-08-22 06:40:54 -0700704 match = packet_to_flow_match(self, pkt)
Dan Talayco3be5b062010-05-12 15:46:21 -0700705 match.wildcards &= ~ofp.OFPFW_IN_PORT
706 self.assertTrue(match is not None,
707 "Could not generate flow match from pkt")
708 act = action.action_output()
709
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700710 for ingress_port in of_ports:
Rich Lane32bf9482013-01-03 17:26:30 -0800711 delete_all_flows(self.controller)
Dan Talayco3be5b062010-05-12 15:46:21 -0700712
Rich Lane9a003812012-10-04 17:17:59 -0700713 logging.info("Ingress " + str(ingress_port) + " to all ports")
Dan Talayco3be5b062010-05-12 15:46:21 -0700714 match.in_port = ingress_port
715
716 request = message.flow_mod()
717 request.match = match
718 request.buffer_id = 0xffffffff
719 act.port = ofp.OFPP_FLOOD
Rich Lanee30455b2013-01-03 16:24:44 -0800720 request.actions.add(act)
Dan Talayco4aa13122010-05-12 15:54:44 -0700721 act.port = ofp.OFPP_IN_PORT
Rich Lanee30455b2013-01-03 16:24:44 -0800722 request.actions.add(act)
Rich Lane9a003812012-10-04 17:17:59 -0700723 logging.info(request.show())
Dan Talayco4aa13122010-05-12 15:54:44 -0700724
Rich Lane9a003812012-10-04 17:17:59 -0700725 logging.info("Inserting flow")
Rich Lane5c3151c2013-01-03 17:15:41 -0800726 self.controller.message_send(request)
Rich Lane3a261d52013-01-03 17:45:08 -0800727 do_barrier(self.controller)
Dan Talayco4aa13122010-05-12 15:54:44 -0700728
Rich Lane9a003812012-10-04 17:17:59 -0700729 logging.info("Sending packet to dp port " + str(ingress_port))
Dan Talayco4aa13122010-05-12 15:54:44 -0700730 self.dataplane.send(ingress_port, str(pkt))
Rich Lane2014f9b2012-10-05 15:29:40 -0700731 receive_pkt_check(self.dataplane, pkt, of_ports, [], self)
Dan Talayco4aa13122010-05-12 15:54:44 -0700732
Rich Laneb90a1c42012-10-05 09:16:05 -0700733class All(base_tests.SimpleDataPlane):
Dan Talayco4aa13122010-05-12 15:54:44 -0700734 """
735 Send to OFPP_ALL port
736
737 Generate a packet
738 Generate and install a matching flow
739 Add action to forward to OFPP_ALL
740 Send the packet to ingress dataplane port
741 Verify the packet is received at all other ports
742 """
743 def runTest(self):
Rich Lane477f4812012-10-04 22:49:00 -0700744 of_ports = config["port_map"].keys()
Dan Talayco4aa13122010-05-12 15:54:44 -0700745 of_ports.sort()
746 self.assertTrue(len(of_ports) > 1, "Not enough ports for test")
747
748 pkt = simple_tcp_packet()
Ed Swierk99a74de2012-08-22 06:40:54 -0700749 match = packet_to_flow_match(self, pkt)
Dan Talayco4aa13122010-05-12 15:54:44 -0700750 match.wildcards &= ~ofp.OFPFW_IN_PORT
751 self.assertTrue(match is not None,
752 "Could not generate flow match from pkt")
753 act = action.action_output()
754
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700755 for ingress_port in of_ports:
Rich Lane32bf9482013-01-03 17:26:30 -0800756 delete_all_flows(self.controller)
Dan Talayco4aa13122010-05-12 15:54:44 -0700757
Rich Lane9a003812012-10-04 17:17:59 -0700758 logging.info("Ingress " + str(ingress_port) + " to all ports")
Dan Talayco4aa13122010-05-12 15:54:44 -0700759 match.in_port = ingress_port
760
761 request = message.flow_mod()
762 request.match = match
763 request.buffer_id = 0xffffffff
764 act.port = ofp.OFPP_ALL
Rich Lanee30455b2013-01-03 16:24:44 -0800765 request.actions.add(act)
Rich Lane9a003812012-10-04 17:17:59 -0700766 logging.info(request.show())
Dan Talayco4aa13122010-05-12 15:54:44 -0700767
Rich Lane9a003812012-10-04 17:17:59 -0700768 logging.info("Inserting flow")
Rich Lane5c3151c2013-01-03 17:15:41 -0800769 self.controller.message_send(request)
Rich Lane3a261d52013-01-03 17:45:08 -0800770 do_barrier(self.controller)
Dan Talayco4aa13122010-05-12 15:54:44 -0700771
Rich Lane9a003812012-10-04 17:17:59 -0700772 logging.info("Sending packet to dp port " + str(ingress_port))
Dan Talayco4aa13122010-05-12 15:54:44 -0700773 self.dataplane.send(ingress_port, str(pkt))
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700774 yes_ports = set(of_ports).difference([ingress_port])
775 receive_pkt_check(self.dataplane, pkt, yes_ports, [ingress_port],
Rich Lane2014f9b2012-10-05 15:29:40 -0700776 self)
Dan Talayco4aa13122010-05-12 15:54:44 -0700777
Rich Laneb90a1c42012-10-05 09:16:05 -0700778class AllPlusIngress(base_tests.SimpleDataPlane):
Dan Talayco4aa13122010-05-12 15:54:44 -0700779 """
780 Send to OFPP_ALL port and ingress port
781
782 Generate a packet
783 Generate and install a matching flow
784 Add action to forward to OFPP_ALL
785 Add action to forward to ingress port
786 Send the packet to ingress dataplane port
787 Verify the packet is received at all other ports
788 """
789 def runTest(self):
Rich Lane477f4812012-10-04 22:49:00 -0700790 of_ports = config["port_map"].keys()
Dan Talayco4aa13122010-05-12 15:54:44 -0700791 of_ports.sort()
792 self.assertTrue(len(of_ports) > 1, "Not enough ports for test")
793
794 pkt = simple_tcp_packet()
Ed Swierk99a74de2012-08-22 06:40:54 -0700795 match = packet_to_flow_match(self, pkt)
Dan Talayco4aa13122010-05-12 15:54:44 -0700796 match.wildcards &= ~ofp.OFPFW_IN_PORT
797 self.assertTrue(match is not None,
798 "Could not generate flow match from pkt")
799 act = action.action_output()
800
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700801 for ingress_port in of_ports:
Rich Lane32bf9482013-01-03 17:26:30 -0800802 delete_all_flows(self.controller)
Dan Talayco4aa13122010-05-12 15:54:44 -0700803
Rich Lane9a003812012-10-04 17:17:59 -0700804 logging.info("Ingress " + str(ingress_port) + " to all ports")
Dan Talayco4aa13122010-05-12 15:54:44 -0700805 match.in_port = ingress_port
806
807 request = message.flow_mod()
808 request.match = match
809 request.buffer_id = 0xffffffff
810 act.port = ofp.OFPP_ALL
Rich Lanee30455b2013-01-03 16:24:44 -0800811 request.actions.add(act)
Dan Talayco3be5b062010-05-12 15:46:21 -0700812 act.port = ofp.OFPP_IN_PORT
Rich Lanee30455b2013-01-03 16:24:44 -0800813 request.actions.add(act)
Rich Lane9a003812012-10-04 17:17:59 -0700814 logging.info(request.show())
Dan Talayco3be5b062010-05-12 15:46:21 -0700815
Rich Lane9a003812012-10-04 17:17:59 -0700816 logging.info("Inserting flow")
Rich Lane5c3151c2013-01-03 17:15:41 -0800817 self.controller.message_send(request)
Rich Lane3a261d52013-01-03 17:45:08 -0800818 do_barrier(self.controller)
Dan Talayco3be5b062010-05-12 15:46:21 -0700819
Rich Lane9a003812012-10-04 17:17:59 -0700820 logging.info("Sending packet to dp port " + str(ingress_port))
Dan Talayco3be5b062010-05-12 15:46:21 -0700821 self.dataplane.send(ingress_port, str(pkt))
Rich Lane2014f9b2012-10-05 15:29:40 -0700822 receive_pkt_check(self.dataplane, pkt, of_ports, [], self)
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700823
Rich Laneb90a1c42012-10-05 09:16:05 -0700824class FloodMinusPort(base_tests.SimpleDataPlane):
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700825 """
826 Config port with No_Flood and test Flood action
827
828 Generate a packet
829 Generate a matching flow
830 Add action to forward to OFPP_ALL
831 Set port to no-flood
832 Send the packet to ingress dataplane port
833 Verify the packet is received at all other ports except
834 the ingress port and the no_flood port
835 """
836 def runTest(self):
Rich Lane477f4812012-10-04 22:49:00 -0700837 of_ports = config["port_map"].keys()
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700838 of_ports.sort()
839 self.assertTrue(len(of_ports) > 2, "Not enough ports for test")
840
841 pkt = simple_tcp_packet()
Ed Swierk99a74de2012-08-22 06:40:54 -0700842 match = packet_to_flow_match(self, pkt)
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700843 match.wildcards &= ~ofp.OFPFW_IN_PORT
844 self.assertTrue(match is not None,
845 "Could not generate flow match from pkt")
846 act = action.action_output()
847
Rich Lane4b9e38c2012-12-06 16:33:20 -0800848 # Clear OFPPC_NO_FLOOD on each port
849 for of_port in of_ports:
850 rv = port_config_set(self.controller, of_port,
851 0, ofp.OFPPC_NO_FLOOD)
852 self.assertEqual(rv, 0, "Failed to set port config")
853
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700854 for idx in range(len(of_ports)):
Rich Lane32bf9482013-01-03 17:26:30 -0800855 delete_all_flows(self.controller)
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700856
857 ingress_port = of_ports[idx]
858 no_flood_idx = (idx + 1) % len(of_ports)
859 no_flood_port = of_ports[no_flood_idx]
860 rv = port_config_set(self.controller, no_flood_port,
Rich Lane9a003812012-10-04 17:17:59 -0700861 ofp.OFPPC_NO_FLOOD, ofp.OFPPC_NO_FLOOD)
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700862 self.assertEqual(rv, 0, "Failed to set port config")
863
864 match.in_port = ingress_port
865
866 request = message.flow_mod()
867 request.match = match
868 request.buffer_id = 0xffffffff
869 act.port = ofp.OFPP_FLOOD
Rich Lanee30455b2013-01-03 16:24:44 -0800870 request.actions.add(act)
Rich Lane9a003812012-10-04 17:17:59 -0700871 logging.info(request.show())
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700872
Rich Lane9a003812012-10-04 17:17:59 -0700873 logging.info("Inserting flow")
Rich Lane5c3151c2013-01-03 17:15:41 -0800874 self.controller.message_send(request)
Rich Lane3a261d52013-01-03 17:45:08 -0800875 do_barrier(self.controller)
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700876
Rich Lane9a003812012-10-04 17:17:59 -0700877 logging.info("Sending packet to dp port " + str(ingress_port))
878 logging.info("No flood port is " + str(no_flood_port))
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700879 self.dataplane.send(ingress_port, str(pkt))
880 no_ports = set([ingress_port, no_flood_port])
881 yes_ports = set(of_ports).difference(no_ports)
Rich Lane2014f9b2012-10-05 15:29:40 -0700882 receive_pkt_check(self.dataplane, pkt, yes_ports, no_ports, self)
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700883
884 # Turn no flood off again
885 rv = port_config_set(self.controller, no_flood_port,
Rich Lane9a003812012-10-04 17:17:59 -0700886 0, ofp.OFPPC_NO_FLOOD)
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700887 self.assertEqual(rv, 0, "Failed to reset port config")
Rich Lane3a261d52013-01-03 17:45:08 -0800888 do_barrier(self.controller)
Rich Lane4ecc1f42012-12-06 16:35:24 -0800889
890 # Check that packets are now flooded to no_flood_port
891 logging.info("Sending packet to dp port " + str(ingress_port))
892 self.dataplane.send(ingress_port, str(pkt))
893 no_ports = set([ingress_port])
894 yes_ports = set(of_ports).difference(no_ports)
895 receive_pkt_check(self.dataplane, pkt, yes_ports, no_ports, self)
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700896
897 #@todo Should check no other packets received
898
Dan Talayco21381562010-07-17 00:34:47 -0700899
900
Dan Talayco551befa2010-07-15 17:05:32 -0700901################################################################
902
Rich Laneb90a1c42012-10-05 09:16:05 -0700903class BaseMatchCase(base_tests.SimpleDataPlane):
Dan Talayco551befa2010-07-15 17:05:32 -0700904 def setUp(self):
Rich Laneb90a1c42012-10-05 09:16:05 -0700905 base_tests.SimpleDataPlane.setUp(self)
Dan Talayco551befa2010-07-15 17:05:32 -0700906 def runTest(self):
Rich Lane9a003812012-10-04 17:17:59 -0700907 logging.info("BaseMatchCase")
Dan Talayco551befa2010-07-15 17:05:32 -0700908
909class ExactMatch(BaseMatchCase):
Tatsuya Yabe6a6f38a2010-05-22 23:48:04 -0700910 """
Dan Talayco551befa2010-07-15 17:05:32 -0700911 Exercise exact matching for all port pairs
Tatsuya Yabe6a6f38a2010-05-22 23:48:04 -0700912
913 Generate a packet
914 Generate and install a matching flow without wildcard mask
915 Add action to forward to a port
916 Send the packet to the port
917 Verify the packet is received at all other ports (one port at a time)
Tatsuya Yabe6a6f38a2010-05-22 23:48:04 -0700918 """
Tatsuya Yabe0718ad32010-05-24 15:22:10 -0700919
Tatsuya Yabe6a6f38a2010-05-22 23:48:04 -0700920 def runTest(self):
Rich Lane477f4812012-10-04 22:49:00 -0700921 flow_match_test(self, config["port_map"])
Tatsuya Yabe6a6f38a2010-05-22 23:48:04 -0700922
Dan Talayco551befa2010-07-15 17:05:32 -0700923class ExactMatchTagged(BaseMatchCase):
924 """
925 Exact match for all port pairs with tagged pkts
926 """
Tatsuya Yabe6a6f38a2010-05-22 23:48:04 -0700927
Dan Talayco551befa2010-07-15 17:05:32 -0700928 def runTest(self):
Rich Lane2014f9b2012-10-05 15:29:40 -0700929 vid = test_param_get('vid', default=TEST_VID_DEFAULT)
Rich Lane477f4812012-10-04 22:49:00 -0700930 flow_match_test(self, config["port_map"], dl_vlan=vid)
Tatsuya Yabe6a6f38a2010-05-22 23:48:04 -0700931
Rich Lane0a4f6372013-01-02 14:40:22 -0800932@disabled
Dan Talayco551befa2010-07-15 17:05:32 -0700933class ExactMatchTaggedMany(BaseMatchCase):
934 """
935 ExactMatchTagged with many VLANS
936 """
Tatsuya Yabe6a6f38a2010-05-22 23:48:04 -0700937
Dan Talayco551befa2010-07-15 17:05:32 -0700938 def runTest(self):
Dan Talayco21381562010-07-17 00:34:47 -0700939 for vid in range(2,100,10):
Rich Lane477f4812012-10-04 22:49:00 -0700940 flow_match_test(self, config["port_map"], dl_vlan=vid, max_test=5)
Dan Talayco551befa2010-07-15 17:05:32 -0700941 for vid in range(100,4000,389):
Rich Lane477f4812012-10-04 22:49:00 -0700942 flow_match_test(self, config["port_map"], dl_vlan=vid, max_test=5)
943 flow_match_test(self, config["port_map"], dl_vlan=4094, max_test=5)
Tatsuya Yabecdf575e2010-05-25 16:56:38 -0700944
Jeffrey Townsend2a300e42012-03-28 17:24:02 -0700945class SingleWildcardMatchPriority(BaseMatchCase):
Jeffrey Townsend50c82462012-03-28 18:26:14 -0700946 """
947 SingleWildcardMatchPriority
948 """
Jeffrey Townsend2a300e42012-03-28 17:24:02 -0700949
Jeffrey Townsend50c82462012-03-28 18:26:14 -0700950 def _Init(self):
Jeffrey Townsend2a300e42012-03-28 17:24:02 -0700951 self.pkt = simple_tcp_packet()
952 self.flowMsgs = {}
953
Jeffrey Townsend50c82462012-03-28 18:26:14 -0700954 def _ClearTable(self):
Rich Lane32bf9482013-01-03 17:26:30 -0800955 delete_all_flows(self.controller)
Rich Lane3a261d52013-01-03 17:45:08 -0800956 do_barrier(self.controller)
Jeffrey Townsend50c82462012-03-28 18:26:14 -0700957
958 def runTest(self):
959
960 self._Init()
Rich Lane477f4812012-10-04 22:49:00 -0700961 of_ports = config["port_map"].keys()
Jeffrey Townsend2a300e42012-03-28 17:24:02 -0700962 of_ports.sort()
963
964 # Delete the initial flow table
Jeffrey Townsend50c82462012-03-28 18:26:14 -0700965 self._ClearTable()
Jeffrey Townsend2a300e42012-03-28 17:24:02 -0700966
967 # Run several combinations, each at lower priority settings.
968 # At the end of each call to runPrioFlows(), the table should
969 # be empty. If its not, we'll catch it as the priorities decreases
970 portA = of_ports[0]
971 portB = of_ports[1]
972 portC = of_ports[2]
973
974 # TODO -- these priority numbers should be validated somehow?
975 self.runPrioFlows(portA, portB, portC, 1000, 999)
976 self.runPrioFlows(portB, portC, portA, 998, 997)
977 self.runPrioFlows(portC, portA, portB, 996, 995)
978 self.runPrioFlows(portA, portC, portB, 994, 993)
979
980
Jeffrey Townsend50c82462012-03-28 18:26:14 -0700981
982 def runPrioFlows(self, portA, portB, portC, prioHigher, prioLower,
983 clearTable=False):
Jeffrey Townsend2a300e42012-03-28 17:24:02 -0700984
Jeffrey Townsend50c82462012-03-28 18:26:14 -0700985 if clearTable:
986 self._ClearTable()
Jeffrey Townsend2a300e42012-03-28 17:24:02 -0700987
988 # Sanity check flow at lower priority from pA to pB
Rich Lane9a003812012-10-04 17:17:59 -0700989 logging.info("runPrioFlows(pA=%d,pB=%d,pC=%d,ph=%d,pl=%d"
Jeffrey Townsend2a300e42012-03-28 17:24:02 -0700990 % (portA, portB, portC, prioHigher, prioLower))
991
Jeffrey Townsend2a300e42012-03-28 17:24:02 -0700992 # Sanity check flow at lower priority from pA to pC
993 self.installFlow(prioLower, portA, portC)
994 self.verifyFlow(portA, portC)
995 self.removeFlow(prioLower)
996
997 # Install and verify pA->pB @ prioLower
998 self.installFlow(prioLower, portA, portB)
999 self.verifyFlow(portA, portB)
1000
1001 # Install and verify pA->pC @ prioHigher, should override pA->pB
1002 self.installFlow(prioHigher, portA, portC)
1003 self.verifyFlow(portA, portC)
1004 # remove pA->pC
1005 self.removeFlow(prioHigher)
Jeffrey Townsend2a300e42012-03-28 17:24:02 -07001006 # Old flow pA -> pB @ prioLower should still be active
1007 self.verifyFlow(portA, portB)
1008 self.removeFlow(prioLower)
1009
1010 # Table should be empty at this point, leave it alone as
1011 # an assumption for future test runs
1012
1013
1014
Ed Swierk99a74de2012-08-22 06:40:54 -07001015 def installFlow(self, prio, inp, egp,
Jeffrey Townsend8364b162012-04-12 13:45:40 -07001016 wildcards=ofp.OFPFW_DL_SRC):
Ed Swierk99a74de2012-08-22 06:40:54 -07001017 wildcards |= required_wildcards(self)
Jeffrey Townsend2a300e42012-03-28 17:24:02 -07001018 request = flow_msg_create(self, self.pkt, ing_port=inp,
Jeffrey Townsend8364b162012-04-12 13:45:40 -07001019 wildcards=wildcards,
Jeffrey Townsend2a300e42012-03-28 17:24:02 -07001020 egr_ports=egp)
1021 request.priority = prio
Rich Lane9a003812012-10-04 17:17:59 -07001022 logging.debug("Install flow with priority " + str(prio))
Jeffrey Townsend50c82462012-03-28 18:26:14 -07001023 flow_msg_install(self, request, clear_table_override=False)
Jeffrey Townsend2a300e42012-03-28 17:24:02 -07001024 self.flowMsgs[prio] = request
1025
1026 def removeFlow(self, prio):
1027 if self.flowMsgs.has_key(prio):
1028 msg = self.flowMsgs[prio]
1029 msg.command = ofp.OFPFC_DELETE_STRICT
1030 # This *must* be set for DELETE
1031 msg.out_port = ofp.OFPP_NONE
Rich Lane9a003812012-10-04 17:17:59 -07001032 logging.debug("Remove flow with priority " + str(prio))
Jeffrey Townsend2a300e42012-03-28 17:24:02 -07001033 self.controller.message_send(msg)
Rich Lane3a261d52013-01-03 17:45:08 -08001034 do_barrier(self.controller)
Jeffrey Townsend50c82462012-03-28 18:26:14 -07001035 else:
1036 raise Exception("Not initialized")
Jeffrey Townsend2a300e42012-03-28 17:24:02 -07001037
1038
Jeffrey Townsend8364b162012-04-12 13:45:40 -07001039 def verifyFlow(self, inp, egp, pkt=None):
1040 if pkt == None:
1041 pkt = self.pkt
1042
Rich Lane9a003812012-10-04 17:17:59 -07001043 logging.info("Pkt match test: " + str(inp) + " to " + str(egp))
1044 logging.debug("Send packet: " + str(inp) + " to " + str(egp))
Jeffrey Townsend8364b162012-04-12 13:45:40 -07001045 self.dataplane.send(inp, str(pkt))
1046 receive_pkt_verify(self, egp, pkt, inp)
Jeffrey Townsend2a300e42012-03-28 17:24:02 -07001047
1048
1049
Jeffrey Townsend50c82462012-03-28 18:26:14 -07001050class SingleWildcardMatchPriorityInsertModifyDelete(SingleWildcardMatchPriority):
1051
1052 def runTest(self):
1053
1054 self._Init()
1055
Rich Lane477f4812012-10-04 22:49:00 -07001056 of_ports = config["port_map"].keys()
Jeffrey Townsend50c82462012-03-28 18:26:14 -07001057 of_ports.sort()
1058
1059 # Install an entry from 0 -> 1 @ prio 1000
1060 self._ClearTable()
1061 self.installFlow(1000, of_ports[0], of_ports[1])
1062 self.verifyFlow(of_ports[0], of_ports[1])
1063 self.installFlow(1000, of_ports[1], of_ports[0])
1064 self.verifyFlow(of_ports[1], of_ports[0])
1065 self.installFlow(1001, of_ports[0], of_ports[1])
1066 self.verifyFlow(of_ports[0], of_ports[1])
1067 self.installFlow(1001, of_ports[1], of_ports[0])
1068 self.verifyFlow(of_ports[1], of_ports[0])
1069 self.removeFlow(1001)
1070 self.verifyFlow(of_ports[0], of_ports[1])
1071 self.removeFlow(1000)
1072
1073
1074
Jeffrey Townsend8364b162012-04-12 13:45:40 -07001075class WildcardPriority(SingleWildcardMatchPriority):
Ken Chiang38d7a152012-05-24 15:33:50 -07001076 """
1077 1. Add wildcard flow, verify packet received.
Rich Lane0a78fbd2012-12-31 16:25:04 -08001078 2. Add wildcard flow with higher priority, verify packet received
Ken Chiang38d7a152012-05-24 15:33:50 -07001079 on port specified by this flow.
Rich Lane0a78fbd2012-12-31 16:25:04 -08001080 3. Add wildcard flow with lower priority, verify packet received
Rich Laneb8392082012-11-21 15:52:54 -08001081 on port specified by the highest priority flow.
Ken Chiang38d7a152012-05-24 15:33:50 -07001082 """
Jeffrey Townsend8364b162012-04-12 13:45:40 -07001083
1084 def runTest(self):
Jeffrey Townsend50c82462012-03-28 18:26:14 -07001085
Jeffrey Townsend8364b162012-04-12 13:45:40 -07001086 self._Init()
1087
Rich Lane477f4812012-10-04 22:49:00 -07001088 of_ports = config["port_map"].keys()
Jeffrey Townsend8364b162012-04-12 13:45:40 -07001089 of_ports.sort()
1090
1091 self._ClearTable()
Ken Chiang38d7a152012-05-24 15:33:50 -07001092
1093 # Install a flow with wildcards
1094 self.installFlow(999, of_ports[0], of_ports[1],
1095 wildcards=ofp.OFPFW_DL_DST)
Jeffrey Townsend8364b162012-04-12 13:45:40 -07001096 self.verifyFlow(of_ports[0], of_ports[1])
Rich Lane0a78fbd2012-12-31 16:25:04 -08001097 # Install a flow with wildcards with higher priority
1098 self.installFlow(1000, of_ports[0], of_ports[2],
1099 wildcards=ofp.OFPFW_DL_DST)
Jeffrey Townsend8364b162012-04-12 13:45:40 -07001100 self.verifyFlow(of_ports[0], of_ports[2])
Rich Lane0a78fbd2012-12-31 16:25:04 -08001101 # Install a flow with wildcards with lower priority
Rich Laneb8392082012-11-21 15:52:54 -08001102 self.installFlow(999, of_ports[0], of_ports[1],
1103 wildcards=ofp.OFPFW_DL_SRC)
Rich Lane0a78fbd2012-12-31 16:25:04 -08001104 self.verifyFlow(of_ports[0], of_ports[2])
Jeffrey Townsend8364b162012-04-12 13:45:40 -07001105
1106
Rich Lane97e99652013-01-02 17:23:20 -08001107@group("smoke")
Ken Chiang3978f242012-06-13 14:14:09 -07001108class WildcardPriorityWithDelete(SingleWildcardMatchPriority):
Ken Chiang38d7a152012-05-24 15:33:50 -07001109 """
Rich Lane0a78fbd2012-12-31 16:25:04 -08001110 1. Add wildcard match flow, verify packet received.
Ken Chiang38d7a152012-05-24 15:33:50 -07001111 2. Add wildcard flow with higher priority, verify packet received on port
1112 specified by this flow.
Rich Lane0a78fbd2012-12-31 16:25:04 -08001113 3. Add wildcard flow with even higher priority, verify packet received
Ken Chiang38d7a152012-05-24 15:33:50 -07001114 on port specified by this flow.
1115 4. Delete lowest priority flow, verify packet received on port specified
1116 by highest priority flow.
1117 5. Delete highest priority flow, verify packet received on port specified
1118 by remaining flow.
1119 """
1120
1121 def runTest(self):
1122
1123 self._Init()
1124
Rich Lane477f4812012-10-04 22:49:00 -07001125 of_ports = config["port_map"].keys()
Ken Chiang38d7a152012-05-24 15:33:50 -07001126 of_ports.sort()
1127
1128 self._ClearTable()
1129
Rich Lane0a78fbd2012-12-31 16:25:04 -08001130 # Install a flow with wildcards
1131 self.installFlow(250, of_ports[0], of_ports[1],
1132 wildcards=ofp.OFPFW_DL_DST)
Ken Chiang38d7a152012-05-24 15:33:50 -07001133 self.verifyFlow(of_ports[0], of_ports[1])
1134 # Install a flow with wildcards of higher priority
1135 self.installFlow(1250, of_ports[0], of_ports[2],
1136 wildcards=ofp.OFPFW_DL_DST)
1137 self.verifyFlow(of_ports[0], of_ports[2])
Rich Lane0a78fbd2012-12-31 16:25:04 -08001138 # Install a flow with wildcards with even higher priority
1139 self.installFlow(2001, of_ports[0], of_ports[3],
1140 wildcards=ofp.OFPFW_DL_DST)
Ken Chiang38d7a152012-05-24 15:33:50 -07001141 self.verifyFlow(of_ports[0], of_ports[3])
1142 # Delete lowest priority flow
1143 self.removeFlow(250)
1144 self.verifyFlow(of_ports[0], of_ports[3])
1145 # Delete highest priority flow
1146 self.removeFlow(2001)
1147 self.verifyFlow(of_ports[0], of_ports[2])
1148
Jeffrey Townsend8364b162012-04-12 13:45:40 -07001149
Dan Talayco551befa2010-07-15 17:05:32 -07001150class SingleWildcardMatch(BaseMatchCase):
Tatsuya Yabe6a6f38a2010-05-22 23:48:04 -07001151 """
1152 Exercise wildcard matching for all ports
1153
1154 Generate a packet
1155 Generate and install a matching flow with wildcard mask
1156 Add action to forward to a port
1157 Send the packet to the port
1158 Verify the packet is received at all other ports (one port at a time)
Tatsuya Yabe0718ad32010-05-24 15:22:10 -07001159 Verify flow_expiration message is correct when command option is set
Tatsuya Yabe6a6f38a2010-05-22 23:48:04 -07001160 """
Tatsuya Yabe0718ad32010-05-24 15:22:10 -07001161 def runTest(self):
Rich Lane2014f9b2012-10-05 15:29:40 -07001162 vid = test_param_get('vid', default=TEST_VID_DEFAULT)
Dan Talayco551befa2010-07-15 17:05:32 -07001163 for wc in WILDCARD_VALUES:
Ed Swierk99a74de2012-08-22 06:40:54 -07001164 wc |= required_wildcards(self)
Dan Talayco4431d542012-03-21 16:42:16 -07001165 if wc & ofp.OFPFW_DL_VLAN:
Ken Chiang5be06dd2012-04-03 10:03:50 -07001166 # Set nonzero VLAN id to avoid sending priority-tagged packet
1167 dl_vlan = vid
Dan Talayco4431d542012-03-21 16:42:16 -07001168 else:
1169 dl_vlan = -1
Rich Lane477f4812012-10-04 22:49:00 -07001170 flow_match_test(self, config["port_map"], wildcards=wc,
Dan Talayco4431d542012-03-21 16:42:16 -07001171 dl_vlan=dl_vlan, max_test=10)
Tatsuya Yabe4fad7e32010-05-24 15:24:50 -07001172
Dan Talayco551befa2010-07-15 17:05:32 -07001173class SingleWildcardMatchTagged(BaseMatchCase):
1174 """
1175 SingleWildcardMatch with tagged packets
1176 """
1177 def runTest(self):
Rich Lane2014f9b2012-10-05 15:29:40 -07001178 vid = test_param_get('vid', default=TEST_VID_DEFAULT)
Dan Talayco551befa2010-07-15 17:05:32 -07001179 for wc in WILDCARD_VALUES:
Ed Swierk99a74de2012-08-22 06:40:54 -07001180 wc |= required_wildcards(self)
Rich Lane477f4812012-10-04 22:49:00 -07001181 flow_match_test(self, config["port_map"], wildcards=wc, dl_vlan=vid,
Dan Talayco551befa2010-07-15 17:05:32 -07001182 max_test=10)
1183
1184class AllExceptOneWildcardMatch(BaseMatchCase):
Tatsuya Yabe4fad7e32010-05-24 15:24:50 -07001185 """
Dan Talayco80b54ed2010-07-13 09:48:35 -07001186 Match exactly one field
Tatsuya Yabe4fad7e32010-05-24 15:24:50 -07001187
1188 Generate a packet
1189 Generate and install a matching flow with wildcard all except one filed
1190 Add action to forward to a port
1191 Send the packet to the port
1192 Verify the packet is received at all other ports (one port at a time)
1193 Verify flow_expiration message is correct when command option is set
1194 """
1195 def runTest(self):
Rich Lane2014f9b2012-10-05 15:29:40 -07001196 vid = test_param_get('vid', default=TEST_VID_DEFAULT)
Dan Talayco488fbc52012-04-09 16:30:41 -07001197 for all_exp_one_wildcard in NO_WILDCARD_VALUES:
Ed Swierk99a74de2012-08-22 06:40:54 -07001198 all_exp_one_wildcard |= required_wildcards(self)
Dan Talayco4431d542012-03-21 16:42:16 -07001199 if all_exp_one_wildcard & ofp.OFPFW_DL_VLAN:
Ken Chiang5be06dd2012-04-03 10:03:50 -07001200 # Set nonzero VLAN id to avoid sending priority-tagged packet
1201 dl_vlan = vid
Dan Talayco4431d542012-03-21 16:42:16 -07001202 else:
1203 dl_vlan = -1
Rich Lane477f4812012-10-04 22:49:00 -07001204 flow_match_test(self, config["port_map"], wildcards=all_exp_one_wildcard,
Dan Talayco4431d542012-03-21 16:42:16 -07001205 dl_vlan=dl_vlan)
Tatsuya Yabee30ebe22010-05-25 09:30:49 -07001206
Dan Talayco551befa2010-07-15 17:05:32 -07001207class AllExceptOneWildcardMatchTagged(BaseMatchCase):
1208 """
1209 Match one field with tagged packets
1210 """
1211 def runTest(self):
Rich Lane2014f9b2012-10-05 15:29:40 -07001212 vid = test_param_get('vid', default=TEST_VID_DEFAULT)
Dan Talayco488fbc52012-04-09 16:30:41 -07001213 for all_exp_one_wildcard in NO_WILDCARD_VALUES:
Ed Swierk99a74de2012-08-22 06:40:54 -07001214 all_exp_one_wildcard |= required_wildcards(self)
Rich Lane477f4812012-10-04 22:49:00 -07001215 flow_match_test(self, config["port_map"], wildcards=all_exp_one_wildcard,
Dan Talayco21381562010-07-17 00:34:47 -07001216 dl_vlan=vid)
Dan Talayco551befa2010-07-15 17:05:32 -07001217
1218class AllWildcardMatch(BaseMatchCase):
Tatsuya Yabee30ebe22010-05-25 09:30:49 -07001219 """
1220 Create Wildcard-all flow and exercise for all ports
1221
1222 Generate a packet
1223 Generate and install a matching flow with wildcard-all
1224 Add action to forward to a port
1225 Send the packet to the port
1226 Verify the packet is received at all other ports (one port at a time)
1227 Verify flow_expiration message is correct when command option is set
1228 """
1229 def runTest(self):
Rich Lane477f4812012-10-04 22:49:00 -07001230 flow_match_test(self, config["port_map"], wildcards=ofp.OFPFW_ALL)
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -07001231
Dan Talayco551befa2010-07-15 17:05:32 -07001232class AllWildcardMatchTagged(BaseMatchCase):
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -07001233 """
Dan Talayco551befa2010-07-15 17:05:32 -07001234 AllWildcardMatch with tagged packets
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -07001235 """
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -07001236 def runTest(self):
Rich Lane2014f9b2012-10-05 15:29:40 -07001237 vid = test_param_get('vid', default=TEST_VID_DEFAULT)
Rich Lane477f4812012-10-04 22:49:00 -07001238 flow_match_test(self, config["port_map"], wildcards=ofp.OFPFW_ALL,
Dan Talayco21381562010-07-17 00:34:47 -07001239 dl_vlan=vid)
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -07001240
Rich Lane97e99652013-01-02 17:23:20 -08001241@group('smoke')
Dan Talayco551befa2010-07-15 17:05:32 -07001242class AddVLANTag(BaseMatchCase):
1243 """
1244 Add a VLAN tag to an untagged packet
1245 """
1246 def runTest(self):
1247 new_vid = 2
Ed Swierkc7193a22012-08-22 06:51:02 -07001248 sup_acts = self.supported_actions
Dan Talayco551befa2010-07-15 17:05:32 -07001249 if not(sup_acts & 1<<ofp.OFPAT_SET_VLAN_VID):
Dan Talaycoba3745c2010-07-21 21:51:08 -07001250 skip_message_emit(self, "Add VLAN tag test")
Dan Talaycof36f1082010-07-13 13:57:17 -07001251 return
Tatsuya Yabef5ffb972010-05-26 15:36:33 -07001252
Dan Talayco551befa2010-07-15 17:05:32 -07001253 len = 100
1254 len_w_vid = 104
1255 pkt = simple_tcp_packet(pktlen=len)
1256 exp_pkt = simple_tcp_packet(pktlen=len_w_vid, dl_vlan_enable=True,
1257 dl_vlan=new_vid)
1258 vid_act = action.action_set_vlan_vid()
1259 vid_act.vlan_vid = new_vid
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -07001260
Rich Lane477f4812012-10-04 22:49:00 -07001261 flow_match_test(self, config["port_map"], pkt=pkt,
Dan Talayco551befa2010-07-15 17:05:32 -07001262 exp_pkt=exp_pkt, action_list=[vid_act])
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -07001263
Rich Lane0a4f6372013-01-02 14:40:22 -08001264@disabled
Rich Laneb90a1c42012-10-05 09:16:05 -07001265class PacketOnly(base_tests.DataPlaneOnly):
Dan Talayco551befa2010-07-15 17:05:32 -07001266 """
1267 Just send a packet thru the switch
1268 """
Rich Laned1d9c282012-10-04 22:07:10 -07001269
Dan Talayco551befa2010-07-15 17:05:32 -07001270 def runTest(self):
1271 pkt = simple_tcp_packet()
Rich Lane477f4812012-10-04 22:49:00 -07001272 of_ports = config["port_map"].keys()
Dan Talayco551befa2010-07-15 17:05:32 -07001273 of_ports.sort()
1274 ing_port = of_ports[0]
Rich Lane9a003812012-10-04 17:17:59 -07001275 logging.info("Sending packet to " + str(ing_port))
1276 logging.debug("Data: " + str(pkt).encode('hex'))
Dan Talayco551befa2010-07-15 17:05:32 -07001277 self.dataplane.send(ing_port, str(pkt))
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -07001278
Rich Lane0a4f6372013-01-02 14:40:22 -08001279@disabled
Rich Laneb90a1c42012-10-05 09:16:05 -07001280class PacketOnlyTagged(base_tests.DataPlaneOnly):
Dan Talayco551befa2010-07-15 17:05:32 -07001281 """
1282 Just send a packet thru the switch
1283 """
Rich Laned1d9c282012-10-04 22:07:10 -07001284
Dan Talayco551befa2010-07-15 17:05:32 -07001285 def runTest(self):
Rich Lane2014f9b2012-10-05 15:29:40 -07001286 vid = test_param_get('vid', default=TEST_VID_DEFAULT)
Dan Talayco551befa2010-07-15 17:05:32 -07001287 pkt = simple_tcp_packet(dl_vlan_enable=True, dl_vlan=vid)
Rich Lane477f4812012-10-04 22:49:00 -07001288 of_ports = config["port_map"].keys()
Dan Talayco551befa2010-07-15 17:05:32 -07001289 of_ports.sort()
1290 ing_port = of_ports[0]
Rich Lane9a003812012-10-04 17:17:59 -07001291 logging.info("Sending packet to " + str(ing_port))
1292 logging.debug("Data: " + str(pkt).encode('hex'))
Dan Talayco551befa2010-07-15 17:05:32 -07001293 self.dataplane.send(ing_port, str(pkt))
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -07001294
Dan Talayco551befa2010-07-15 17:05:32 -07001295class ModifyVID(BaseMatchCase):
Dan Talayco4b2bee62010-07-20 14:10:05 -07001296 """
1297 Modify the VLAN ID in the VLAN tag of a tagged packet
1298 """
Dan Talaycoaf669322012-09-12 22:51:22 -07001299 def setUp(self):
1300 BaseMatchCase.setUp(self)
1301 self.ing_port=False
1302
Dan Talayco551befa2010-07-15 17:05:32 -07001303 def runTest(self):
1304 old_vid = 2
1305 new_vid = 3
Ed Swierkc7193a22012-08-22 06:51:02 -07001306 sup_acts = self.supported_actions
Dan Talayco4b2bee62010-07-20 14:10:05 -07001307 if not (sup_acts & 1 << ofp.OFPAT_SET_VLAN_VID):
Dan Talaycoba3745c2010-07-21 21:51:08 -07001308 skip_message_emit(self, "Modify VLAN tag test")
Dan Talayco551befa2010-07-15 17:05:32 -07001309 return
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -07001310
Dan Talayco551befa2010-07-15 17:05:32 -07001311 pkt = simple_tcp_packet(dl_vlan_enable=True, dl_vlan=old_vid)
1312 exp_pkt = simple_tcp_packet(dl_vlan_enable=True, dl_vlan=new_vid)
1313 vid_act = action.action_set_vlan_vid()
1314 vid_act.vlan_vid = new_vid
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -07001315
Rich Lane477f4812012-10-04 22:49:00 -07001316 flow_match_test(self, config["port_map"], pkt=pkt, exp_pkt=exp_pkt,
Dan Talaycoaf669322012-09-12 22:51:22 -07001317 action_list=[vid_act], ing_port=self.ing_port)
1318
1319class ModifyVIDToIngress(ModifyVID):
1320 """
1321 Modify the VLAN ID in the VLAN tag of a tagged packet and send to
1322 ingress port
1323 """
1324 def setUp(self):
1325 BaseMatchCase.setUp(self)
1326 self.ing_port=True
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -07001327
Ken Chiange9a211d2012-04-20 14:52:11 -07001328class ModifyVIDWithTagMatchWildcarded(BaseMatchCase):
1329 """
1330 With vlan ID and priority wildcarded, perform SET_VLAN_VID action.
1331 The same flow should match on both untagged and tagged packets.
1332 """
1333 def runTest(self):
1334 old_vid = 2
1335 new_vid = 3
Ed Swierkc7193a22012-08-22 06:51:02 -07001336 sup_acts = self.supported_actions
Ken Chiange9a211d2012-04-20 14:52:11 -07001337 if not (sup_acts & 1 << ofp.OFPAT_SET_VLAN_VID):
1338 skip_message_emit(self, "ModifyVIDWithTagWildcarded test")
1339 return
1340
Rich Lane477f4812012-10-04 22:49:00 -07001341 of_ports = config["port_map"].keys()
Ken Chiange9a211d2012-04-20 14:52:11 -07001342 self.assertTrue(len(of_ports) > 1, "Not enough ports for test")
1343 ing_port = of_ports[0]
1344 egr_ports = of_ports[1]
1345
Rich Lane32bf9482013-01-03 17:26:30 -08001346 delete_all_flows(self.controller)
Ken Chiange9a211d2012-04-20 14:52:11 -07001347
1348 len_untagged = 100
1349 len_w_vid = 104
1350 untagged_pkt = simple_tcp_packet(pktlen=len_untagged)
1351 tagged_pkt = simple_tcp_packet(pktlen=len_w_vid,
1352 dl_vlan_enable=True, dl_vlan=old_vid)
1353 exp_pkt = simple_tcp_packet(pktlen=len_w_vid, dl_vlan_enable=True,
1354 dl_vlan=new_vid)
Ed Swierk99a74de2012-08-22 06:40:54 -07001355 wildcards = (required_wildcards(self) | ofp.OFPFW_DL_VLAN |
1356 ofp.OFPFW_DL_VLAN_PCP)
Ken Chiange9a211d2012-04-20 14:52:11 -07001357 vid_act = action.action_set_vlan_vid()
1358 vid_act.vlan_vid = new_vid
1359 request = flow_msg_create(self, untagged_pkt, ing_port=ing_port,
1360 wildcards=wildcards, egr_ports=egr_ports,
1361 action_list=[vid_act])
1362 flow_msg_install(self, request)
1363
Rich Lane9a003812012-10-04 17:17:59 -07001364 logging.debug("Send untagged packet: " + str(ing_port) + " to " +
Ken Chiange9a211d2012-04-20 14:52:11 -07001365 str(egr_ports))
1366 self.dataplane.send(ing_port, str(untagged_pkt))
1367 receive_pkt_verify(self, egr_ports, exp_pkt, ing_port)
1368
Rich Lane9a003812012-10-04 17:17:59 -07001369 logging.debug("Send tagged packet: " + str(ing_port) + " to " +
Ken Chiange9a211d2012-04-20 14:52:11 -07001370 str(egr_ports))
1371 self.dataplane.send(ing_port, str(tagged_pkt))
1372 receive_pkt_verify(self, egr_ports, exp_pkt, ing_port)
1373
Howard Pershc1199d52012-04-11 14:21:32 -07001374class ModifyVlanPcp(BaseMatchCase):
1375 """
1376 Modify the priority field of the VLAN tag of a tagged packet
1377 """
1378 def runTest(self):
1379 vid = 123
1380 old_vlan_pcp = 2
1381 new_vlan_pcp = 3
Ed Swierkc7193a22012-08-22 06:51:02 -07001382 sup_acts = self.supported_actions
Ed Swierk8c3af7f2012-04-24 14:19:17 -07001383 if not (sup_acts & 1 << ofp.OFPAT_SET_VLAN_PCP):
1384 skip_message_emit(self, "Modify VLAN priority test")
Howard Pershc1199d52012-04-11 14:21:32 -07001385 return
1386
1387 pkt = simple_tcp_packet(dl_vlan_enable=True, dl_vlan=vid, dl_vlan_pcp=old_vlan_pcp)
1388 exp_pkt = simple_tcp_packet(dl_vlan_enable=True, dl_vlan=vid, dl_vlan_pcp=new_vlan_pcp)
1389 vid_act = action.action_set_vlan_pcp()
1390 vid_act.vlan_pcp = new_vlan_pcp
1391
Rich Lane477f4812012-10-04 22:49:00 -07001392 flow_match_test(self, config["port_map"], pkt=pkt, exp_pkt=exp_pkt,
Howard Pershc1199d52012-04-11 14:21:32 -07001393 action_list=[vid_act])
1394
Dan Talayco551befa2010-07-15 17:05:32 -07001395class StripVLANTag(BaseMatchCase):
Dan Talayco4b2bee62010-07-20 14:10:05 -07001396 """
1397 Strip the VLAN tag from a tagged packet
1398 """
Dan Talayco551befa2010-07-15 17:05:32 -07001399 def runTest(self):
1400 old_vid = 2
Ed Swierkc7193a22012-08-22 06:51:02 -07001401 sup_acts = self.supported_actions
Dan Talayco4b2bee62010-07-20 14:10:05 -07001402 if not (sup_acts & 1 << ofp.OFPAT_STRIP_VLAN):
Dan Talaycoba3745c2010-07-21 21:51:08 -07001403 skip_message_emit(self, "Strip VLAN tag test")
Dan Talayco551befa2010-07-15 17:05:32 -07001404 return
Dan Talaycof36f1082010-07-13 13:57:17 -07001405
Dan Talayco551befa2010-07-15 17:05:32 -07001406 len_w_vid = 104
1407 len = 100
1408 pkt = simple_tcp_packet(pktlen=len_w_vid, dl_vlan_enable=True,
1409 dl_vlan=old_vid)
1410 exp_pkt = simple_tcp_packet(pktlen=len)
1411 vid_act = action.action_strip_vlan()
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -07001412
Rich Lane477f4812012-10-04 22:49:00 -07001413 flow_match_test(self, config["port_map"], pkt=pkt, exp_pkt=exp_pkt,
Dan Talayco551befa2010-07-15 17:05:32 -07001414 action_list=[vid_act])
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -07001415
Ken Chiange9a211d2012-04-20 14:52:11 -07001416class StripVLANTagWithTagMatchWildcarded(BaseMatchCase):
1417 """
1418 Strip the VLAN tag from a tagged packet.
1419 Differs from StripVLANTag in that VID and PCP are both wildcarded.
1420 """
1421 def runTest(self):
1422 old_vid = 2
Ed Swierkc7193a22012-08-22 06:51:02 -07001423 sup_acts = self.supported_actions
Ken Chiange9a211d2012-04-20 14:52:11 -07001424 if not (sup_acts & 1 << ofp.OFPAT_STRIP_VLAN):
1425 skip_message_emit(self, "StripVLANTagWithTagWildcarded test")
1426 return
1427
1428 len_w_vid = 104
1429 len_untagged = 100
1430 pkt = simple_tcp_packet(pktlen=len_w_vid, dl_vlan_enable=True,
1431 dl_vlan=old_vid)
1432 exp_pkt = simple_tcp_packet(pktlen=len_untagged)
Ed Swierk99a74de2012-08-22 06:40:54 -07001433 wildcards = (required_wildcards(self) | ofp.OFPFW_DL_VLAN |
1434 ofp.OFPFW_DL_VLAN_PCP)
Ken Chiange9a211d2012-04-20 14:52:11 -07001435 vid_act = action.action_strip_vlan()
1436
Rich Lane477f4812012-10-04 22:49:00 -07001437 flow_match_test(self, config["port_map"],
Ed Swierk99a74de2012-08-22 06:40:54 -07001438 wildcards=wildcards,
Ken Chiange9a211d2012-04-20 14:52:11 -07001439 pkt=pkt, exp_pkt=exp_pkt,
1440 action_list=[vid_act])
1441
Dan Talayco4b2bee62010-07-20 14:10:05 -07001442def init_pkt_args():
1443 """
1444 Pass back a dictionary with default packet arguments
1445 """
1446 args = {}
1447 args["dl_src"] = '00:23:45:67:89:AB'
1448
1449 dl_vlan_enable=False
1450 dl_vlan=-1
Rich Lane477f4812012-10-04 22:49:00 -07001451 if config["test-params"]["vid"]:
Dan Talayco4b2bee62010-07-20 14:10:05 -07001452 dl_vlan_enable=True
Rich Lane477f4812012-10-04 22:49:00 -07001453 dl_vlan = config["test-params"]["vid"]
Dan Talayco4b2bee62010-07-20 14:10:05 -07001454
1455# Unpack operator is ** on a dictionary
1456
1457 return args
1458
Dan Talayco551befa2010-07-15 17:05:32 -07001459class ModifyL2Src(BaseMatchCase):
Dan Talayco4b2bee62010-07-20 14:10:05 -07001460 """
1461 Modify the source MAC address (TP1)
1462 """
Dan Talayco551befa2010-07-15 17:05:32 -07001463 def runTest(self):
Ed Swierkc7193a22012-08-22 06:51:02 -07001464 sup_acts = self.supported_actions
Dan Talayco4b2bee62010-07-20 14:10:05 -07001465 if not (sup_acts & 1 << ofp.OFPAT_SET_DL_SRC):
Dan Talaycoba3745c2010-07-21 21:51:08 -07001466 skip_message_emit(self, "ModifyL2Src test")
Dan Talayco4b2bee62010-07-20 14:10:05 -07001467 return
1468
1469 (pkt, exp_pkt, acts) = pkt_action_setup(self, mod_fields=['dl_src'],
1470 check_test_params=True)
Rich Lane477f4812012-10-04 22:49:00 -07001471 flow_match_test(self, config["port_map"], pkt=pkt, exp_pkt=exp_pkt,
Dan Talayco4b2bee62010-07-20 14:10:05 -07001472 action_list=acts, max_test=2)
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -07001473
Dan Talayco551befa2010-07-15 17:05:32 -07001474class ModifyL2Dst(BaseMatchCase):
Dan Talayco4b2bee62010-07-20 14:10:05 -07001475 """
1476 Modify the dest MAC address (TP1)
1477 """
Dan Talayco551befa2010-07-15 17:05:32 -07001478 def runTest(self):
Ed Swierkc7193a22012-08-22 06:51:02 -07001479 sup_acts = self.supported_actions
Dan Talayco4b2bee62010-07-20 14:10:05 -07001480 if not (sup_acts & 1 << ofp.OFPAT_SET_DL_DST):
Dan Talaycoba3745c2010-07-21 21:51:08 -07001481 skip_message_emit(self, "ModifyL2dst test")
Dan Talayco4b2bee62010-07-20 14:10:05 -07001482 return
1483
1484 (pkt, exp_pkt, acts) = pkt_action_setup(self, mod_fields=['dl_dst'],
1485 check_test_params=True)
Rich Lane477f4812012-10-04 22:49:00 -07001486 flow_match_test(self, config["port_map"], pkt=pkt, exp_pkt=exp_pkt,
Dan Talayco4b2bee62010-07-20 14:10:05 -07001487 action_list=acts, max_test=2)
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -07001488
Dan Talayco551befa2010-07-15 17:05:32 -07001489class ModifyL3Src(BaseMatchCase):
Dan Talayco4b2bee62010-07-20 14:10:05 -07001490 """
1491 Modify the source IP address of an IP packet (TP1)
1492 """
Dan Talayco551befa2010-07-15 17:05:32 -07001493 def runTest(self):
Ed Swierkc7193a22012-08-22 06:51:02 -07001494 sup_acts = self.supported_actions
Dan Talayco4b2bee62010-07-20 14:10:05 -07001495 if not (sup_acts & 1 << ofp.OFPAT_SET_NW_SRC):
Dan Talaycoba3745c2010-07-21 21:51:08 -07001496 skip_message_emit(self, "ModifyL3Src test")
Dan Talayco4b2bee62010-07-20 14:10:05 -07001497 return
1498
1499 (pkt, exp_pkt, acts) = pkt_action_setup(self, mod_fields=['ip_src'],
1500 check_test_params=True)
Rich Lane477f4812012-10-04 22:49:00 -07001501 flow_match_test(self, config["port_map"], pkt=pkt, exp_pkt=exp_pkt,
Dan Talayco4b2bee62010-07-20 14:10:05 -07001502 action_list=acts, max_test=2)
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -07001503
Dan Talayco551befa2010-07-15 17:05:32 -07001504class ModifyL3Dst(BaseMatchCase):
Dan Talayco4b2bee62010-07-20 14:10:05 -07001505 """
1506 Modify the dest IP address of an IP packet (TP1)
1507 """
Dan Talayco551befa2010-07-15 17:05:32 -07001508 def runTest(self):
Ed Swierkc7193a22012-08-22 06:51:02 -07001509 sup_acts = self.supported_actions
Dan Talayco4b2bee62010-07-20 14:10:05 -07001510 if not (sup_acts & 1 << ofp.OFPAT_SET_NW_DST):
Dan Talaycoba3745c2010-07-21 21:51:08 -07001511 skip_message_emit(self, "ModifyL3Dst test")
Dan Talayco4b2bee62010-07-20 14:10:05 -07001512 return
1513
1514 (pkt, exp_pkt, acts) = pkt_action_setup(self, mod_fields=['ip_dst'],
1515 check_test_params=True)
Rich Lane477f4812012-10-04 22:49:00 -07001516 flow_match_test(self, config["port_map"], pkt=pkt, exp_pkt=exp_pkt,
Dan Talayco4b2bee62010-07-20 14:10:05 -07001517 action_list=acts, max_test=2)
Dan Talayco551befa2010-07-15 17:05:32 -07001518
1519class ModifyL4Src(BaseMatchCase):
Dan Talayco4b2bee62010-07-20 14:10:05 -07001520 """
1521 Modify the source TCP port of a TCP packet (TP1)
1522 """
Dan Talayco551befa2010-07-15 17:05:32 -07001523 def runTest(self):
Ed Swierkc7193a22012-08-22 06:51:02 -07001524 sup_acts = self.supported_actions
Dan Talayco4b2bee62010-07-20 14:10:05 -07001525 if not (sup_acts & 1 << ofp.OFPAT_SET_TP_SRC):
Dan Talaycoba3745c2010-07-21 21:51:08 -07001526 skip_message_emit(self, "ModifyL4Src test")
Dan Talayco4b2bee62010-07-20 14:10:05 -07001527 return
1528
1529 (pkt, exp_pkt, acts) = pkt_action_setup(self, mod_fields=['tcp_sport'],
1530 check_test_params=True)
Rich Lane477f4812012-10-04 22:49:00 -07001531 flow_match_test(self, config["port_map"], pkt=pkt, exp_pkt=exp_pkt,
Dan Talayco4b2bee62010-07-20 14:10:05 -07001532 action_list=acts, max_test=2)
Dan Talayco551befa2010-07-15 17:05:32 -07001533
Rich Lane01c2b862012-10-26 16:26:25 -07001534class ModifyL4SrcUdp(BaseMatchCase):
1535 """
1536 Modify the source UDP port of a UDP packet
1537 """
1538 def runTest(self):
1539 sup_acts = self.supported_actions
1540 if not (sup_acts & 1 << ofp.OFPAT_SET_TP_DST):
1541 skip_message_emit(self, "ModifyL4SrcUdp test")
1542 return
1543
1544 (pkt, exp_pkt, acts) = pkt_action_setup(self, mod_fields=['udp_sport'],
1545 check_test_params=True, tp="udp")
1546 flow_match_test(self, config["port_map"], pkt=pkt, exp_pkt=exp_pkt,
1547 action_list=acts, max_test=2)
1548
Dan Talayco551befa2010-07-15 17:05:32 -07001549class ModifyL4Dst(BaseMatchCase):
Dan Talayco4b2bee62010-07-20 14:10:05 -07001550 """
1551 Modify the dest TCP port of a TCP packet (TP1)
1552 """
Dan Talayco551befa2010-07-15 17:05:32 -07001553 def runTest(self):
Ed Swierkc7193a22012-08-22 06:51:02 -07001554 sup_acts = self.supported_actions
Dan Talayco4b2bee62010-07-20 14:10:05 -07001555 if not (sup_acts & 1 << ofp.OFPAT_SET_TP_DST):
Dan Talaycoba3745c2010-07-21 21:51:08 -07001556 skip_message_emit(self, "ModifyL4Dst test")
Dan Talayco4b2bee62010-07-20 14:10:05 -07001557 return
1558
1559 (pkt, exp_pkt, acts) = pkt_action_setup(self, mod_fields=['tcp_dport'],
1560 check_test_params=True)
Rich Lane477f4812012-10-04 22:49:00 -07001561 flow_match_test(self, config["port_map"], pkt=pkt, exp_pkt=exp_pkt,
Dan Talayco4b2bee62010-07-20 14:10:05 -07001562 action_list=acts, max_test=2)
Dan Talayco551befa2010-07-15 17:05:32 -07001563
Rich Lane01c2b862012-10-26 16:26:25 -07001564class ModifyL4DstUdp(BaseMatchCase):
1565 """
1566 Modify the dest UDP port of a UDP packet
1567 """
1568 def runTest(self):
1569 sup_acts = self.supported_actions
1570 if not (sup_acts & 1 << ofp.OFPAT_SET_TP_DST):
1571 skip_message_emit(self, "ModifyL4DstUdp test")
1572 return
1573
1574 (pkt, exp_pkt, acts) = pkt_action_setup(self, mod_fields=['udp_dport'],
1575 check_test_params=True, tp="udp")
1576 flow_match_test(self, config["port_map"], pkt=pkt, exp_pkt=exp_pkt,
1577 action_list=acts, max_test=2)
1578
Dan Talayco551befa2010-07-15 17:05:32 -07001579class ModifyTOS(BaseMatchCase):
Dan Talayco4b2bee62010-07-20 14:10:05 -07001580 """
1581 Modify the IP type of service of an IP packet (TP1)
1582 """
Dan Talayco551befa2010-07-15 17:05:32 -07001583 def runTest(self):
Ed Swierkc7193a22012-08-22 06:51:02 -07001584 sup_acts = self.supported_actions
Dan Talayco4b2bee62010-07-20 14:10:05 -07001585 if not (sup_acts & 1 << ofp.OFPAT_SET_NW_TOS):
Dan Talaycoba3745c2010-07-21 21:51:08 -07001586 skip_message_emit(self, "ModifyTOS test")
Dan Talayco4b2bee62010-07-20 14:10:05 -07001587 return
Dan Talayco551befa2010-07-15 17:05:32 -07001588
Dan Talayco4b2bee62010-07-20 14:10:05 -07001589 (pkt, exp_pkt, acts) = pkt_action_setup(self, mod_fields=['ip_tos'],
1590 check_test_params=True)
Rich Lane477f4812012-10-04 22:49:00 -07001591 flow_match_test(self, config["port_map"], pkt=pkt, exp_pkt=exp_pkt,
Dan Talaycocfa172f2012-03-23 12:03:00 -07001592 action_list=acts, max_test=2, egr_count=-1)
Dan Talayco551befa2010-07-15 17:05:32 -07001593
Dan Talaycof6e76c02012-03-23 10:56:12 -07001594class ModifyL2DstMC(BaseMatchCase):
1595 """
1596 Modify the L2 dest and send to 2 ports
Dan Talaycof6e76c02012-03-23 10:56:12 -07001597 """
1598 def runTest(self):
Ed Swierkc7193a22012-08-22 06:51:02 -07001599 sup_acts = self.supported_actions
Dan Talaycof6e76c02012-03-23 10:56:12 -07001600 if not (sup_acts & 1 << ofp.OFPAT_SET_DL_DST):
Dan Talaycocfa172f2012-03-23 12:03:00 -07001601 skip_message_emit(self, "ModifyL2dstMC test")
Dan Talaycof6e76c02012-03-23 10:56:12 -07001602 return
1603
Dan Talaycof6e76c02012-03-23 10:56:12 -07001604 (pkt, exp_pkt, acts) = pkt_action_setup(self, mod_fields=['dl_dst'],
1605 check_test_params=True)
Rich Lane477f4812012-10-04 22:49:00 -07001606 flow_match_test(self, config["port_map"], pkt=pkt, exp_pkt=exp_pkt,
Dan Talaycocfa172f2012-03-23 12:03:00 -07001607 action_list=acts, max_test=2, egr_count=-1)
Dan Talaycof6e76c02012-03-23 10:56:12 -07001608
Dan Talaycoc948d0b2012-03-23 12:17:54 -07001609class ModifyL2DstIngress(BaseMatchCase):
1610 """
1611 Modify the L2 dest and send to the ingress port
1612 """
1613 def runTest(self):
Ed Swierkc7193a22012-08-22 06:51:02 -07001614 sup_acts = self.supported_actions
Dan Talaycoc948d0b2012-03-23 12:17:54 -07001615 if not (sup_acts & 1 << ofp.OFPAT_SET_DL_DST):
Dan Talaycoabbfdbb2012-04-05 10:29:26 -07001616 skip_message_emit(self, "ModifyL2dstIngress test")
Dan Talaycoc948d0b2012-03-23 12:17:54 -07001617 return
1618
1619 (pkt, exp_pkt, acts) = pkt_action_setup(self, mod_fields=['dl_dst'],
1620 check_test_params=True)
Rich Lane477f4812012-10-04 22:49:00 -07001621 flow_match_test(self, config["port_map"], pkt=pkt, exp_pkt=exp_pkt,
Dan Talaycoc948d0b2012-03-23 12:17:54 -07001622 action_list=acts, max_test=2, egr_count=0,
1623 ing_port=True)
1624
Dan Talaycod8ae7582012-03-23 12:24:56 -07001625class ModifyL2DstIngressMC(BaseMatchCase):
1626 """
1627 Modify the L2 dest and send to the ingress port
1628 """
1629 def runTest(self):
Ed Swierkc7193a22012-08-22 06:51:02 -07001630 sup_acts = self.supported_actions
Dan Talaycod8ae7582012-03-23 12:24:56 -07001631 if not (sup_acts & 1 << ofp.OFPAT_SET_DL_DST):
1632 skip_message_emit(self, "ModifyL2dstMC test")
1633 return
1634
1635 (pkt, exp_pkt, acts) = pkt_action_setup(self, mod_fields=['dl_dst'],
1636 check_test_params=True)
Rich Lane477f4812012-10-04 22:49:00 -07001637 flow_match_test(self, config["port_map"], pkt=pkt, exp_pkt=exp_pkt,
Dan Talaycod8ae7582012-03-23 12:24:56 -07001638 action_list=acts, max_test=2, egr_count=-1,
1639 ing_port=True)
1640
Dan Talaycof6e76c02012-03-23 10:56:12 -07001641class ModifyL2SrcMC(BaseMatchCase):
1642 """
1643 Modify the source MAC address (TP1) and send to multiple
Dan Talaycof6e76c02012-03-23 10:56:12 -07001644 """
1645 def runTest(self):
Ed Swierkc7193a22012-08-22 06:51:02 -07001646 sup_acts = self.supported_actions
Dan Talaycof6e76c02012-03-23 10:56:12 -07001647 if not (sup_acts & 1 << ofp.OFPAT_SET_DL_SRC):
Dan Talaycocfa172f2012-03-23 12:03:00 -07001648 skip_message_emit(self, "ModifyL2SrcMC test")
Dan Talaycof6e76c02012-03-23 10:56:12 -07001649 return
1650
Dan Talaycof6e76c02012-03-23 10:56:12 -07001651 (pkt, exp_pkt, acts) = pkt_action_setup(self, mod_fields=['dl_src'],
1652 check_test_params=True)
Rich Lane477f4812012-10-04 22:49:00 -07001653 flow_match_test(self, config["port_map"], pkt=pkt, exp_pkt=exp_pkt,
Dan Talaycocfa172f2012-03-23 12:03:00 -07001654 action_list=acts, max_test=2, egr_count=-1)
Dan Talaycof6e76c02012-03-23 10:56:12 -07001655
1656class ModifyL2SrcDstMC(BaseMatchCase):
1657 """
1658 Modify the L2 source and dest and send to 2 ports
Dan Talaycof6e76c02012-03-23 10:56:12 -07001659 """
1660 def runTest(self):
Ed Swierkc7193a22012-08-22 06:51:02 -07001661 sup_acts = self.supported_actions
Dan Talaycocfa172f2012-03-23 12:03:00 -07001662 if (not (sup_acts & 1 << ofp.OFPAT_SET_DL_DST) or
1663 not (sup_acts & 1 << ofp.OFPAT_SET_DL_SRC)):
1664 skip_message_emit(self, "ModifyL2SrcDstMC test")
Dan Talaycof6e76c02012-03-23 10:56:12 -07001665 return
1666
Dan Talaycof6e76c02012-03-23 10:56:12 -07001667 mod_fields = ['dl_dst', 'dl_src']
1668 (pkt, exp_pkt, acts) = pkt_action_setup(self, mod_fields=mod_fields,
1669 check_test_params=True)
Rich Lane477f4812012-10-04 22:49:00 -07001670 flow_match_test(self, config["port_map"], pkt=pkt, exp_pkt=exp_pkt,
Dan Talaycocfa172f2012-03-23 12:03:00 -07001671 action_list=acts, max_test=2, egr_count=-1)
1672
1673class ModifyL2DstVIDMC(BaseMatchCase):
1674 """
1675 Modify the L2 dest and send to 2 ports
1676 """
1677 def runTest(self):
Ed Swierkc7193a22012-08-22 06:51:02 -07001678 sup_acts = self.supported_actions
Dan Talaycocfa172f2012-03-23 12:03:00 -07001679 if (not (sup_acts & 1 << ofp.OFPAT_SET_DL_DST) or
1680 not (sup_acts & 1 << ofp.OFPAT_SET_VLAN_VID)):
1681 skip_message_emit(self, "ModifyL2DstVIDMC test")
1682 return
1683
1684 mod_fields = ['dl_dst', 'dl_vlan']
1685 (pkt, exp_pkt, acts) = pkt_action_setup(self,
1686 start_field_vals={'dl_vlan_enable':True}, mod_fields=mod_fields,
1687 check_test_params=True)
Rich Lane477f4812012-10-04 22:49:00 -07001688 flow_match_test(self, config["port_map"], pkt=pkt, exp_pkt=exp_pkt,
Dan Talaycocfa172f2012-03-23 12:03:00 -07001689 action_list=acts, max_test=2, egr_count=-1)
Dan Talaycof6e76c02012-03-23 10:56:12 -07001690
Rich Lane97e99652013-01-02 17:23:20 -08001691@group("smoke")
Rich Lane22e74c12012-11-12 15:06:06 -08001692class ModifyAll(BaseMatchCase):
1693 """
1694 Modify all supported fields and output to a port
1695 """
1696 def runTest(self):
1697 sup_acts = self.supported_actions
1698
1699 sup_map = {
1700 "dl_dst" : ofp.OFPAT_SET_DL_DST,
1701 "dl_src" : ofp.OFPAT_SET_DL_SRC,
1702 "dl_vlan_enable" : ofp.OFPAT_SET_VLAN_VID,
1703 "dl_vlan" : ofp.OFPAT_SET_VLAN_VID,
1704 "dl_vlan_pcp" : ofp.OFPAT_SET_VLAN_PCP,
1705 "ip_src" : ofp.OFPAT_SET_NW_SRC,
1706 "ip_dst" : ofp.OFPAT_SET_NW_DST,
1707 "ip_tos" : ofp.OFPAT_SET_NW_TOS,
1708 "tcp_sport" : ofp.OFPAT_SET_TP_SRC,
1709 "tcp_dport" : ofp.OFPAT_SET_TP_DST,
1710 }
1711
1712 mod_fields = [field for (field, bit) in sup_map.items() if (sup_acts & 1 << bit)]
1713 random.shuffle(mod_fields)
1714 start_field_vals = { "dl_vlan_enable" : True }
1715 mod_field_vals = { "dl_vlan_enable" : True }
1716 logging.info("modifying fields: %s" % repr(mod_fields))
1717
1718 (pkt, exp_pkt, acts) = pkt_action_setup(self,
1719 mod_fields=mod_fields,
1720 start_field_vals=start_field_vals,
1721 mod_field_vals=mod_field_vals,
1722 check_test_params=True)
1723 flow_match_test(self, config["port_map"], pkt=pkt, exp_pkt=exp_pkt,
1724 action_list=acts, max_test=2)
1725
Dan Talaycofa6454f2012-04-05 10:04:13 -07001726class FlowToggle(BaseMatchCase):
1727 """
1728 Add flows to the table and modify them repeatedly
Dan Talaycof7c41312012-07-23 12:53:19 -07001729
1730 This is done by using only "add" flow messages. Since the check overlap
1731 flag is not set, the switch is supposed to modify the existing flow if
1732 the match already exists.
1733
1734 Would probably be better to exercise more of the flow modify commands
1735 (add, modify, delete +/- strict).
Dan Talaycofa6454f2012-04-05 10:04:13 -07001736 """
1737 def runTest(self):
Rich Lane2014f9b2012-10-05 15:29:40 -07001738 flow_count = test_param_get('ft_flow_count', default=20)
1739 iter_count = test_param_get('ft_iter_count', default=10)
Dan Talaycofa6454f2012-04-05 10:04:13 -07001740
Rich Lane9a003812012-10-04 17:17:59 -07001741 logging.info("Running flow toggle with %d flows, %d iterations" %
Dan Talaycofa6454f2012-04-05 10:04:13 -07001742 (flow_count, iter_count))
1743 acts = []
1744 acts.append(action.action_output())
1745 acts.append(action.action_output())
1746
Rich Lane477f4812012-10-04 22:49:00 -07001747 of_ports = config["port_map"].keys()
Dan Talaycofa6454f2012-04-05 10:04:13 -07001748 if len(of_ports) < 3:
1749 self.assertTrue(False, "Too few ports for test")
1750
1751 for idx in range(2):
1752 acts[idx].port = of_ports[idx]
1753
1754 flows = []
1755 flows.append([])
1756 flows.append([])
1757
Ed Swierk99a74de2012-08-22 06:40:54 -07001758 wildcards = (required_wildcards(self) | ofp.OFPFW_DL_SRC |
1759 ofp.OFPFW_DL_DST)
Dan Talaycofa6454f2012-04-05 10:04:13 -07001760 # Create up the flows in an array
1761 for toggle in range(2):
1762 for f_idx in range(flow_count):
1763 pkt = simple_tcp_packet(tcp_sport=f_idx)
1764 msg = message.flow_mod()
Ed Swierk99a74de2012-08-22 06:40:54 -07001765 match = packet_to_flow_match(self, pkt)
Shudong Zhou031373c2012-07-19 17:37:42 -07001766 match.in_port = of_ports[2]
Dan Talayco50be7672012-04-05 11:38:08 -07001767 match.wildcards = wildcards
Dan Talaycofa6454f2012-04-05 10:04:13 -07001768 msg.match = match
1769 msg.buffer_id = 0xffffffff
Dan Talaycof7c41312012-07-23 12:53:19 -07001770 msg.command = ofp.OFPFC_ADD
Dan Talaycofa6454f2012-04-05 10:04:13 -07001771 msg.actions.add(acts[toggle])
1772 flows[toggle].append(msg)
Dan Talayco50be7672012-04-05 11:38:08 -07001773
1774 # Show two sample flows
Rich Lane9a003812012-10-04 17:17:59 -07001775 logging.debug(flows[0][0].show())
1776 logging.debug(flows[1][0].show())
Dan Talayco50be7672012-04-05 11:38:08 -07001777
Dan Talaycofa6454f2012-04-05 10:04:13 -07001778 # Install the first set of flows
1779 for f_idx in range(flow_count):
Rich Lane5c3151c2013-01-03 17:15:41 -08001780 self.controller.message_send(flows[0][f_idx])
Rich Lane3a261d52013-01-03 17:45:08 -08001781 do_barrier(self.controller)
Dan Talaycofa6454f2012-04-05 10:04:13 -07001782
Rich Lane9a003812012-10-04 17:17:59 -07001783 logging.info("Installed %d flows" % flow_count)
Dan Talaycofa6454f2012-04-05 10:04:13 -07001784
1785 # Repeatedly modify all the flows back and forth
1786 updates = 0
1787 # Report status about 5 times
1788 mod_val = (iter_count / 4) + 1
Dan Talaycoabbfdbb2012-04-05 10:29:26 -07001789 start = time.time()
1790 for iter_idx in range(iter_count):
1791 if not iter_idx % mod_val:
Rich Lane9a003812012-10-04 17:17:59 -07001792 logging.info("Flow Toggle: iter %d of %d. " %
Dan Talaycoabbfdbb2012-04-05 10:29:26 -07001793 (iter_idx, iter_count) +
1794 "%d updates in %d secs" %
1795 (updates, time.time() - start))
Dan Talaycofa6454f2012-04-05 10:04:13 -07001796 for toggle in range(2):
1797 t_idx = 1 - toggle
1798 for f_idx in range(flow_count):
Rich Lane5c3151c2013-01-03 17:15:41 -08001799 self.controller.message_send(flows[t_idx][f_idx])
Dan Talaycofa6454f2012-04-05 10:04:13 -07001800 updates += 1
Rich Lane3a261d52013-01-03 17:45:08 -08001801 do_barrier(self.controller)
Dan Talaycoabbfdbb2012-04-05 10:29:26 -07001802
1803 end = time.time()
1804 divisor = end - start or (end - start + 1)
Rich Lane9a003812012-10-04 17:17:59 -07001805 logging.info("Flow toggle: %d iterations" % iter_count)
1806 logging.info(" %d flow mods in %d secs, %d mods/sec" %
Dan Talaycoabbfdbb2012-04-05 10:29:26 -07001807 (updates, end - start, updates/divisor))
Dan Talaycofa6454f2012-04-05 10:04:13 -07001808
1809
Dan Talayco8a64e332012-03-28 14:53:20 -07001810# You can pick and choose these by commenting tests in or out
1811iter_classes = [
1812 basic.PacketIn,
1813 basic.PacketOut,
1814 DirectPacket,
Dan Talaycofa6454f2012-04-05 10:04:13 -07001815 FlowToggle,
Dan Talayco8a64e332012-03-28 14:53:20 -07001816 DirectTwoPorts,
Dan Talaycofa6454f2012-04-05 10:04:13 -07001817 DirectMCNonIngress,
Dan Talayco8a64e332012-03-28 14:53:20 -07001818 AllWildcardMatch,
1819 AllWildcardMatchTagged,
1820 SingleWildcardMatch,
1821 SingleWildcardMatchTagged,
1822 ExactMatch,
1823 ExactMatchTagged,
1824 SingleWildcardMatch,
1825 ModifyL2Src,
1826 ModifyL2Dst,
1827 ModifyL2SrcMC,
1828 ModifyL2DstMC,
1829 ModifyL2SrcDstMC
1830 ]
1831
Rich Lane0a4f6372013-01-02 14:40:22 -08001832@disabled
Dan Talayco8a64e332012-03-28 14:53:20 -07001833class IterCases(BaseMatchCase):
Dan Talaycofa6454f2012-04-05 10:04:13 -07001834 """
1835 Iterate over a bunch of test cases
1836
1837 The cases come from the list above
1838 """
1839
Dan Talayco8a64e332012-03-28 14:53:20 -07001840 def runTest(self):
Rich Lane2014f9b2012-10-05 15:29:40 -07001841 count = test_param_get('iter_count', default=10)
Dan Talayco8a64e332012-03-28 14:53:20 -07001842 tests_done = 0
Rich Lane9a003812012-10-04 17:17:59 -07001843 logging.info("Running iteration test " + str(count) + " times")
Dan Talayco8a64e332012-03-28 14:53:20 -07001844 start = time.time()
1845 last = start
1846 for idx in range(count):
Rich Lane9a003812012-10-04 17:17:59 -07001847 logging.info("Iteration " + str(idx + 1))
Dan Talayco8a64e332012-03-28 14:53:20 -07001848 for cls in iter_classes:
1849 test = cls()
1850 test.inheritSetup(self)
1851 test.runTest()
1852 tests_done += 1
Dan Talaycofa6454f2012-04-05 10:04:13 -07001853 # Report update about every minute, between tests
Dan Talayco8a64e332012-03-28 14:53:20 -07001854 if time.time() - last > 60:
1855 last = time.time()
Rich Lane9a003812012-10-04 17:17:59 -07001856 logging.info(
Dan Talaycofa6454f2012-04-05 10:04:13 -07001857 "IterCases: Iter %d of %d; Ran %d tests in %d " %
1858 (idx, count, tests_done, last - start) +
1859 "seconds so far")
Dan Talayco8a64e332012-03-28 14:53:20 -07001860 stats = all_stats_get(self)
1861 last = time.time()
Rich Lane9a003812012-10-04 17:17:59 -07001862 logging.info("\nIterCases ran %d tests in %d seconds." %
Dan Talayco8a64e332012-03-28 14:53:20 -07001863 (tests_done, last - start))
Rich Lane9a003812012-10-04 17:17:59 -07001864 logging.info(" flows: %d. packets: %d. bytes: %d" %
Dan Talayco8a64e332012-03-28 14:53:20 -07001865 (stats["flows"], stats["packets"], stats["bytes"]))
Rich Lane9a003812012-10-04 17:17:59 -07001866 logging.info(" active: %d. lookups: %d. matched %d." %
Dan Talayco8a64e332012-03-28 14:53:20 -07001867 (stats["active"], stats["lookups"], stats["matched"]))
1868
Dan Talayco4b2bee62010-07-20 14:10:05 -07001869#@todo Need to implement tagged versions of the above tests
1870#
1871#@todo Implement a test case that strips tag 2, adds tag 3
1872# and modifies tag 4 to tag 5. Then verify (in addition) that
1873# tag 6 does not get modified.
1874
Rich Lane0a4f6372013-01-02 14:40:22 -08001875@disabled
Dan Talayco4b2bee62010-07-20 14:10:05 -07001876class MixedVLAN(BaseMatchCase):
1877 """
1878 Test mixture of VLAN tag actions
1879
1880 Strip tag 2 on port 1, send to port 2
1881 Add tag 3 on port 1, send to port 2
1882 Modify tag 4 to 5 on port 1, send to port 2
1883 All other traffic from port 1, send to port 3
1884 All traffic from port 2 sent to port 4
1885 Use exact matches with different packets for all mods
1886 Verify the following: (port, vid)
1887 (port 1, vid 2) => VLAN tag stripped, out port 2
1888 (port 1, no tag) => tagged packet w/ vid 2 out port 2
1889 (port 1, vid 4) => tagged packet w/ vid 5 out port 2
1890 (port 1, vid 5) => tagged packet w/ vid 5 out port 2
1891 (port 1, vid 6) => tagged packet w/ vid 6 out port 2
1892 (port 2, no tag) => untagged packet out port 4
1893 (port 2, vid 2-6) => unmodified packet out port 4
1894
1895 Variation: Might try sending VID 5 to port 3 and check.
1896 If only VID 5 distinguishes pkt, this will fail on some platforms
1897 """
1898
Rich Lane97e99652013-01-02 17:23:20 -08001899@group('smoke')
Rich Laneb90a1c42012-10-05 09:16:05 -07001900class MatchEach(base_tests.SimpleDataPlane):
Rich Lane8d6ab272012-09-23 18:06:20 -07001901 """
1902 Check that each match field is actually matched on.
1903 Installs two flows that differ in one field. The flow that should not
1904 match has a higher priority, so if that field is ignored during matching
1905 the packet will be sent out the wrong port.
1906
1907 TODO test UDP, ARP, ICMP, etc.
1908 """
1909 def runTest(self):
Rich Lane477f4812012-10-04 22:49:00 -07001910 of_ports = config["port_map"].keys()
Rich Lane8d6ab272012-09-23 18:06:20 -07001911 of_ports.sort()
1912 self.assertTrue(len(of_ports) > 1, "Not enough ports for test")
1913
Rich Lane9a003812012-10-04 17:17:59 -07001914 delete_all_flows(self.controller)
Rich Lane8d6ab272012-09-23 18:06:20 -07001915
Ed Swierk7040a8d2012-12-11 16:30:13 -08001916 pkt = simple_tcp_packet(dl_vlan_enable=True, dl_vlan=2)
Rich Lane8d6ab272012-09-23 18:06:20 -07001917 ingress_port = of_ports[0]
1918 egress_port = of_ports[1]
1919
1920 def testField(field, mask):
Rich Lane9a003812012-10-04 17:17:59 -07001921 logging.info("Testing field %s" % field)
Rich Lane8d6ab272012-09-23 18:06:20 -07001922
1923 def addFlow(matching, priority, output_port):
1924 match = packet_to_flow_match(self, pkt)
1925 self.assertTrue(match is not None, "Could not generate flow match from pkt")
1926 match.wildcards &= ~ofp.OFPFW_IN_PORT
1927 match.in_port = ingress_port
1928 if not matching:
1929 # Make sure flow doesn't match
1930 orig = getattr(match, field)
1931 if isinstance(orig, list):
1932 new = map(lambda a: ~a[0] & a[1], zip(orig, mask))
1933 else:
1934 new = ~orig & mask
1935 setattr(match, field, new)
1936 request = message.flow_mod()
1937 request.match = match
1938 request.buffer_id = 0xffffffff
1939 request.priority = priority
1940 act = action.action_output()
1941 act.port = output_port
Rich Lanee30455b2013-01-03 16:24:44 -08001942 request.actions.add(act)
Rich Lane9a003812012-10-04 17:17:59 -07001943 logging.info("Inserting flow")
Rich Lane8d6ab272012-09-23 18:06:20 -07001944 self.controller.message_send(request)
1945
1946 # This flow should match.
1947 addFlow(matching=True, priority=0, output_port=egress_port)
1948 # This flow should not match, but it has a higher priority.
1949 addFlow(matching=False, priority=1, output_port=ofp.OFPP_IN_PORT)
1950
Rich Lane3a261d52013-01-03 17:45:08 -08001951 do_barrier(self.controller)
Rich Lane8d6ab272012-09-23 18:06:20 -07001952
Rich Lane9a003812012-10-04 17:17:59 -07001953 logging.info("Sending packet to dp port " + str(ingress_port))
Rich Lane8d6ab272012-09-23 18:06:20 -07001954 self.dataplane.send(ingress_port, str(pkt))
1955
1956 exp_pkt_arg = None
1957 exp_port = None
Rich Lane477f4812012-10-04 22:49:00 -07001958 if config["relax"]:
Rich Lane8d6ab272012-09-23 18:06:20 -07001959 exp_pkt_arg = pkt
1960 exp_port = egress_port
1961
1962 (rcv_port, rcv_pkt, pkt_time) = self.dataplane.poll(port_number=exp_port,
1963 exp_pkt=exp_pkt_arg)
1964 self.assertTrue(rcv_pkt is not None, "Did not receive packet")
Rich Lane9a003812012-10-04 17:17:59 -07001965 logging.debug("Packet len " + str(len(rcv_pkt)) + " in on " + str(rcv_port))
Rich Lane8d6ab272012-09-23 18:06:20 -07001966 self.assertEqual(rcv_port, egress_port, "Unexpected receive port")
1967 self.assertEqual(str(pkt), str(rcv_pkt), 'Response packet does not match send packet')
1968
Ed Swierkb603b192012-12-12 15:38:49 -08001969 wildcards = required_wildcards(self)
Rich Lane8d6ab272012-09-23 18:06:20 -07001970 # TODO in_port
Ed Swierkb603b192012-12-12 15:38:49 -08001971 if not (wildcards & ofp.OFPFW_DL_SRC):
1972 testField("dl_src", [0xff]*6)
1973 if not (wildcards & ofp.OFPFW_DL_DST):
1974 testField("dl_dst", [0xff]*6)
1975 if not (wildcards & ofp.OFPFW_DL_TYPE):
1976 testField("dl_type", 0xffff)
1977 if not (wildcards & ofp.OFPFW_DL_VLAN):
1978 testField("dl_vlan", 0xfff)
Rich Lane8d6ab272012-09-23 18:06:20 -07001979 # TODO dl_vlan_pcp
Ed Swierkb603b192012-12-12 15:38:49 -08001980 if not (wildcards & ofp.OFPFW_NW_SRC_ALL):
1981 testField("nw_src", 0xffffffff)
1982 if not (wildcards & ofp.OFPFW_NW_DST_ALL):
1983 testField("nw_dst", 0xffffffff)
1984 if not (wildcards & ofp.OFPFW_NW_TOS):
1985 testField("nw_tos", 0x3f)
1986 if not (wildcards & ofp.OFPFW_NW_PROTO):
1987 testField("nw_proto", 0xff)
1988 if not (wildcards & ofp.OFPFW_TP_SRC):
1989 testField("tp_src", 0xffff)
1990 if not (wildcards & ofp.OFPFW_TP_DST):
1991 testField("tp_dst", 0xffff)
Rich Lane8d6ab272012-09-23 18:06:20 -07001992
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07001993class DirectBadPacketBase(base_tests.SimpleDataPlane):
1994 """
1995 Base class for sending single packets with single flow table entries.
1996 Used to verify matching of unusual packets and parsing/matching of
1997 corrupted packets.
1998
1999 The idea is to generate packets that may either be totally malformed or
2000 malformed just enough to trick the flow matcher into making mistakes.
2001
2002 Generate a 'bad' packet
2003 Generate and install a matching flow
2004 Add action to direct the packet to an egress port
2005 Send the packet to ingress dataplane port
2006 Verify the packet is received at the egress port only
2007 """
2008
2009 RESULT_MATCH = "MATCH"
2010 RESULT_NOMATCH = "NO MATCH"
2011 RESULT_ANY = "ANY MATCH"
2012
2013 def runTest(self):
2014 pass
2015 # TODO:
2016 # - ICMP?
2017 # - VLAN?
2018 # - action
2019
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002020 def createMatch(self, **kwargs):
2021 match = ofp.ofp_match()
2022 match.wildcards = ofp.OFPFW_ALL
2023 fields = {
2024 'dl_dst': ofp.OFPFW_DL_DST,
2025 'dl_src': ofp.OFPFW_DL_SRC,
2026 'dl_type': ofp.OFPFW_DL_TYPE,
2027 'dl_vlan': ofp.OFPFW_DL_VLAN,
2028 'nw_src': ofp.OFPFW_NW_SRC_MASK,
2029 'nw_dst': ofp.OFPFW_NW_DST_MASK,
2030 'nw_tos': ofp.OFPFW_NW_TOS,
2031 'nw_proto': ofp.OFPFW_NW_PROTO,
2032 'tp_src': ofp.OFPFW_TP_SRC,
2033 'tp_dst': ofp.OFPFW_TP_DST,
2034 }
2035 for key in kwargs:
2036 setattr(match, key, kwargs[key])
2037 match.wildcards &= ~fields[key]
2038 return match
2039
2040 def testPktsAgainstFlow(self, pkts, acts, match):
2041 if type(acts) != list:
2042 acts = [acts]
2043 for info in pkts:
2044 title, pkt, expected_result = info
2045 self.testPktAgainstFlow(title, pkt, acts, match, expected_result)
2046
2047 def testPktAgainstFlow(self, title, pkt, acts, match, expected_result):
2048 of_ports = config["port_map"].keys()
2049 of_ports.sort()
2050 self.assertTrue(len(of_ports) > 1, "Not enough ports for test")
2051
Rich Lane32bf9482013-01-03 17:26:30 -08002052 delete_all_flows(self.controller)
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002053
2054 ingress_port = of_ports[0]
2055 egress_port = of_ports[1]
2056
2057 logging.info("Testing packet '%s', expect result %s" %
2058 (title, expected_result))
2059 logging.info("Ingress %s to egress %s" %
2060 (str(ingress_port), str(egress_port)))
2061 logging.info("Packet:")
Rich Lane5d7e89a2012-10-26 16:43:13 -07002062 logging.info(inspect_packet(pkt))
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002063
2064 match.in_port = ingress_port
2065
2066 request = message.flow_mod()
2067 request.match = match
Rich Lane44cf12d2012-10-15 11:10:45 -07002068 request.priority = 1
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002069
2070 request.buffer_id = 0xffffffff
2071 for act in acts:
2072 act.port = egress_port
Rich Lanee30455b2013-01-03 16:24:44 -08002073 request.actions.add(act)
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002074
2075 logging.info("Inserting flow")
Rich Lane5c3151c2013-01-03 17:15:41 -08002076 self.controller.message_send(request)
Rich Lane44cf12d2012-10-15 11:10:45 -07002077
2078 # This flow speeds up negative tests
2079 logging.info("Inserting catch-all flow")
2080 request2 = message.flow_mod()
2081 request2.match = self.createMatch()
2082 request2.priority = 0
2083 act = action.action_output()
2084 act.port = ofp.OFPP_IN_PORT
2085 request2.actions.add(act)
Rich Lane5c3151c2013-01-03 17:15:41 -08002086 self.controller.message_send(request2)
Rich Lane44cf12d2012-10-15 11:10:45 -07002087
Rich Lane3a261d52013-01-03 17:45:08 -08002088 do_barrier(self.controller)
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002089
2090 logging.info("Sending packet to dp port " +
2091 str(ingress_port))
2092 self.dataplane.send(ingress_port, str(pkt))
2093
2094 exp_pkt_arg = None
2095 exp_port = None
2096 if config["relax"]:
2097 exp_pkt_arg = pkt
2098 exp_port = egress_port
2099
Rich Lane44cf12d2012-10-15 11:10:45 -07002100 if expected_result == self.RESULT_MATCH:
2101 timeout = -1 # default timeout
2102 else:
2103 timeout = 1 # short timeout for negative tests
2104
2105 (rcv_port, rcv_pkt, pkt_time) = self.dataplane.poll(exp_pkt=exp_pkt_arg,
2106 timeout=timeout)
2107 if rcv_port == ingress_port:
2108 logging.debug("Packet matched catch-all flow")
2109 rcv_pkt = None
2110
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002111 if expected_result == self.RESULT_MATCH:
2112 self.assertTrue(rcv_pkt is not None,
2113 "Did not receive packet, expected a match")
2114 logging.debug("Packet len " + str(len(rcv_pkt)) + " in on " +
2115 str(rcv_port))
2116 self.assertEqual(rcv_port, egress_port, "Unexpected receive port")
2117 str_pkt = str(pkt)
2118 str_rcv_pkt = str(rcv_pkt)
2119 str_rcv_pkt = str_rcv_pkt[0:len(str_pkt)]
2120 if str_pkt != str_rcv_pkt:
2121 logging.error("Response packet does not match send packet")
2122 logging.info("Response:")
Rich Lane5d7e89a2012-10-26 16:43:13 -07002123 logging.info(inspect_packet(scapy.Ether(rcv_pkt)))
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002124 self.assertEqual(str_pkt, str_rcv_pkt,
2125 'Response packet does not match send packet')
2126 elif expected_result == self.RESULT_NOMATCH:
2127 self.assertTrue(rcv_pkt is None, "Received packet, expected drop")
2128 else:
2129 logging.debug("Match or drop accepted. Result = %s" %
2130 ("match" if rcv_pkt is not None else "drop"))
2131
2132
2133class DirectBadIpTcpPacketsBase(DirectBadPacketBase):
2134 """
2135 Base class for TCP and UDP parsing/matching verification under corruptions
2136 """
2137 def runTest(self):
2138 pass
2139
2140 def runTestWithProto(self, protoName = 'TCP'):
2141 dl_dst='00:01:02:03:04:05'
2142 dl_src='00:06:07:08:09:0a'
2143 ip_src='192.168.0.1'
2144 ip_dst='192.168.0.2'
2145 ip_tos=0
2146 tcp_sport=1234
2147 tcp_dport=80
2148
2149 # Generate a proper packet for constructing a match
2150 tp = None
2151 if protoName == 'TCP':
2152 tp = scapy.TCP
2153 proto = 6
2154 elif protoName == 'UDP':
2155 tp = scapy.UDP
2156 proto = 17
2157 else:
2158 raise Exception("Passed in unknown proto name")
2159
2160 match_pkt = scapy.Ether(dst=dl_dst, src=dl_src)/ \
2161 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos)/ \
2162 tp(sport=tcp_sport, dport=tcp_dport)
2163 match = packet_to_flow_match(self, match_pkt)
2164 self.assertTrue(match is not None,
2165 "Could not generate flow match from pkt")
2166 match.wildcards &= ~ofp.OFPFW_IN_PORT
2167
2168 def testPacket(title, pkt, result):
2169 act = action.action_output()
2170 pkts = [
2171 [title, pkt, result]
2172 ]
2173 self.testPktsAgainstFlow(pkts, act, match)
2174
2175 # Try incomplete IP headers
2176 testPacket("Incomplete IP header (1 bytes)",
2177 scapy.Ether(dst=dl_dst, src=dl_src)/ \
2178 str(scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, proto=proto))[0:1],
2179 self.RESULT_NOMATCH,
2180 )
2181 testPacket("Incomplete IP header (2 bytes)",
2182 scapy.Ether(dst=dl_dst, src=dl_src)/ \
2183 str(scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, proto=proto))[0:2],
2184 self.RESULT_NOMATCH,
2185 )
2186 testPacket("Incomplete IP header (3 bytes)",
2187 scapy.Ether(dst=dl_dst, src=dl_src)/ \
2188 str(scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, proto=proto))[0:3],
2189 self.RESULT_NOMATCH,
2190 )
2191 testPacket("Incomplete IP header (12 bytes)",
2192 scapy.Ether(dst=dl_dst, src=dl_src)/ \
2193 str(scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, proto=proto))[0:12],
2194 self.RESULT_NOMATCH,
2195 )
2196 testPacket("Incomplete IP header (16 bytes)",
2197 scapy.Ether(dst=dl_dst, src=dl_src)/ \
2198 str(scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, proto=proto))[0:16],
2199 self.RESULT_NOMATCH,
2200 )
2201 testPacket("Incomplete IP header (19 bytes)",
2202 scapy.Ether(dst=dl_dst, src=dl_src)/ \
2203 str(scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, proto=proto))[0:19],
2204 self.RESULT_NOMATCH,
2205 )
2206
2207 # Try variations where the TCP header is missing or incomplete. As we
2208 # saw bugs before where buffers were reused and lengths weren't honored,
2209 # we initiatlize once with a non-matching full packet and once with a
2210 # matching full packet.
2211 testPacket("Non-Matching TCP packet, warming buffer",
2212 scapy.Ether(dst=dl_dst, src=dl_src)/ \
2213 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, proto=proto)/ \
2214 tp(sport=tcp_sport, dport=tcp_dport + 1),
2215 self.RESULT_NOMATCH,
2216 )
2217 testPacket("Missing TCP header, buffer warmed with non-match",
2218 scapy.Ether(dst=dl_dst, src=dl_src)/ \
2219 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, proto=proto),
2220 self.RESULT_NOMATCH,
2221 )
2222 testPacket("Matching TCP packet, warming buffer",
2223 scapy.Ether(dst=dl_dst, src=dl_src)/ \
2224 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, proto=proto)/ \
2225 tp(sport=tcp_sport, dport=tcp_dport),
2226 self.RESULT_MATCH,
2227 )
2228 testPacket("Missing TCP header, buffer warmed with match",
2229 scapy.Ether(dst=dl_dst, src=dl_src)/ \
2230 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, proto=proto),
2231 self.RESULT_NOMATCH,
2232 )
2233 testPacket("Truncated TCP header: 2 bytes",
2234 scapy.Ether(dst=dl_dst, src=dl_src)/ \
2235 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, proto=proto)/ \
2236 (str(tp(sport=tcp_sport, dport=tcp_dport))[0:2]),
2237 self.RESULT_NOMATCH,
2238 )
2239
2240 # Play with IP header length values that put the start of TCP either
2241 # inside the generated TCP header or beyond. In some cases it may even
2242 # be beyond the packet boundary. Also play with IP options and more
2243 # importantly IP total length corruptions.
2244 testPacket("TCP packet, corrupt ihl (0x6)",
2245 simple_tcp_packet(ip_ihl=6),
2246 self.RESULT_NOMATCH,
2247 )
2248 testPacket("TCP packet, corrupt ihl (0xf)",
2249 simple_tcp_packet(ip_ihl=0xf), # ihl = 15 * 4 = 60
2250 self.RESULT_NOMATCH,
2251 )
2252 testPacket("TCP packet, corrupt ihl and total length",
2253 simple_tcp_packet(ip_ihl=0xf, pktlen=56), # ihl = 15 * 4 = 60,
2254 self.RESULT_NOMATCH,
2255 )
2256 testPacket("Corrupt IPoption: First 4 bytes of matching TCP header",
2257 simple_tcp_packet(
2258 ip_options=scapy.IPOption('\x04\xd2\x00\x50'),
2259 tcp_dport=2, tcp_sport=2
2260 ),
2261 self.RESULT_NOMATCH,
2262 )
2263 testPacket("Missing TCP header, corrupt ihl",
2264 scapy.Ether(dst=dl_dst, src=dl_src)/ \
2265 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ihl=0xf, proto=proto),
2266 self.RESULT_NOMATCH,
2267 )
2268 testPacket("Missing TCP header, corrupt total length",
2269 scapy.Ether(dst=dl_dst, src=dl_src)/ \
2270 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, proto=proto, len= 100),
2271 self.RESULT_NOMATCH,
2272 )
2273 testPacket("Missing TCP header, corrupt ihl and total length",
2274 scapy.Ether(dst=dl_dst, src=dl_src)/ \
2275 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ihl=0xf, proto=proto, len=43),
2276 self.RESULT_NOMATCH,
2277 )
2278 testPacket("Incomplete IP header (12 bytes), corrupt ihl and total length",
2279 scapy.Ether(dst=dl_dst, src=dl_src)/ \
2280 str(scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, proto=proto, ihl=10, len=43))[0:12],
2281 self.RESULT_NOMATCH,
2282 )
2283 testPacket("Incomplete IP header (16 bytes), corrupt ihl and total length",
2284 scapy.Ether(dst=dl_dst, src=dl_src)/ \
2285 str(scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, proto=proto, ihl=10, len=43))[0:16],
2286 self.RESULT_NOMATCH,
2287 )
2288
2289 # Try an incomplete TCP header that has enough bytes to carry source and
2290 # destination ports. As that is all we care about during matching, some
2291 # implementations may match and some may drop the packet
2292 testPacket("Incomplete TCP header: src/dst port present",
2293 scapy.Ether(dst=dl_dst, src=dl_src)/ \
2294 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, proto=proto)/ \
2295 (str(tp(sport=tcp_sport, dport=tcp_dport))[0:4]),
2296 self.RESULT_ANY,
2297 )
2298
2299 for i in range(1):
2300 for length in range(40 / 4): # IPv4 options are a maximum of 40 in length
2301 bytes = "".join([("%c" % random.randint(0, 255)) for x in range(length * 4)])
2302 eth = scapy.Ether(dst=dl_dst, src=dl_src)
2303 ip = scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ihl=5 + length, proto=proto)
2304 tcp = tp(sport=tcp_sport, dport=tcp_dport+1)
2305 pkt = eth / ip
2306 pkt = pkt / bytes
2307 pkt = pkt / str(tcp)
2308 testPacket("Random IP options len = %d - TP match must fail" % length * 4,
2309 pkt,
2310 self.RESULT_NOMATCH
2311 )
2312
2313 eth = scapy.Ether(dst=dl_dst, src=dl_src)
2314 ip = scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ihl=5 + length, proto=proto)
2315 tcp = tp(sport=tcp_sport, dport=tcp_dport)
2316 pkt = eth / ip
2317 pkt = pkt / bytes
2318 pkt = pkt / str(tcp)
2319
2320 testPacket("Random IP options len = %d - May match",
2321 pkt,
2322 self.RESULT_ANY
2323 )
2324
2325
2326class DirectBadIpTcpPackets(DirectBadIpTcpPacketsBase):
2327 """
2328 Verify IP/TCP parsing and matching. Focus on packet corruptions
2329 """
2330 def runTest(self):
2331 self.runTestWithProto(protoName = 'TCP')
2332
2333class DirectBadIpUdpPackets(DirectBadIpTcpPacketsBase):
2334 """
2335 Verify IP/UDP parsing and matching. Focus on packet corruptions
2336 """
2337 def runTest(self):
2338 self.runTestWithProto(protoName = 'UDP')
2339
2340class DirectBadLlcPackets(DirectBadPacketBase):
2341 """
2342 Verify LLC/SNAP parsing and matching. Focus on packet corruptions
2343 """
2344 def runTest(self):
2345 dl_dst='00:01:02:03:04:05'
2346 dl_src='00:06:07:08:09:0a'
2347 ip_src='192.168.0.1'
2348 ip_dst='192.168.0.2'
2349 ip_tos=0
2350 tcp_sport=1234
2351 tcp_dport=80
2352
2353 IS_SNAP_IP = 1
2354 IS_SNAP_IP_CORRUPT = 2
2355 IS_NOT_SNAP_IP = 3
2356
2357 def testPacketTcpMatch(title, llc):
2358 match_pkt = scapy.Ether(dst=dl_dst, src=dl_src)/ \
2359 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos)/ \
2360 scapy.TCP(sport=tcp_sport, dport=tcp_dport)
2361 match = packet_to_flow_match(self, match_pkt)
2362 self.assertTrue(match is not None,
2363 "Could not generate flow match from pkt")
2364 match.wildcards &= ~ofp.OFPFW_IN_PORT
2365 act = action.action_output()
2366
2367 self.testPktsAgainstFlow(
2368 [[
2369 "TCP match - LLC frame correct length - %s" % title,
2370 scapy.Ether(dst=dl_dst, src=dl_src, type=len(llc)) / llc,
2371 self.RESULT_ANY,
2372 ]],
2373 act, match
2374 )
2375
2376 # Corrupt length field
2377 ethLen = random.randint(0, 1535)
2378 self.testPktsAgainstFlow(
2379 [[
2380 "TCP match - LLC frame corrupted length - %s" % title,
2381 scapy.Ether(dst=dl_dst, src=dl_src, type=ethLen) / llc,
2382 self.RESULT_ANY,
2383 ]],
2384 act, match
2385 )
2386
2387 def testPacketEthSrcDstMatch(title, llc):
2388 # Matching based on Ethernet source and destination
2389 match_pkt = scapy.Ether(dst=dl_dst, src=dl_src)
2390 match = packet_to_flow_match(self, match_pkt)
2391 self.assertTrue(match is not None,
2392 "Could not generate flow match from pkt")
2393 match.wildcards &= ~ofp.OFPFW_IN_PORT
2394 match.wildcards |= ofp.OFPFW_DL_TYPE
2395 self.testPktsAgainstFlow(
2396 [[
2397 "Eth addr match - LLC frame correct length- %s" % title,
2398 scapy.Ether(dst=dl_dst, src=dl_src, type=len(llc)) / llc,
2399 self.RESULT_MATCH,
2400 ]],
2401 action.action_output(), match
2402 )
2403
2404 # Corrupt length field
2405 ethLen = random.randint(0, 1535)
2406 self.testPktsAgainstFlow(
2407 [[
2408 "Eth addr match - LLC frame corrupted length- %s" % title,
2409 scapy.Ether(dst=dl_dst, src=dl_src, type=ethLen) / llc,
2410 self.RESULT_ANY,
2411 ]],
2412 action.action_output(), match
2413 )
2414
2415 def testPacketEthSrcDstTypeMatch(title, llc, is_snap_ip):
2416 # Matching based on Ethernet source, destination and type
2417 match_pkt = scapy.Ether(dst=dl_dst, src=dl_src, type=0x800)
2418 match = packet_to_flow_match(self, match_pkt)
2419 self.assertTrue(match is not None,
2420 "Could not generate flow match from pkt")
2421 match.wildcards &= ~ofp.OFPFW_IN_PORT
2422 if is_snap_ip == IS_SNAP_IP:
2423 is_match = self.RESULT_MATCH
2424 elif is_snap_ip == IS_SNAP_IP_CORRUPT:
2425 is_match = self.RESULT_ANY
2426 else:
2427 is_match = self.RESULT_NOMATCH
2428 self.testPktsAgainstFlow(
2429 [[
2430 "Eth addr+type match - LLC frame correct length - %s" % title,
2431 scapy.Ether(dst=dl_dst, src=dl_src, type=len(llc)) / llc,
2432 is_match,
2433 ]],
2434 action.action_output(), match
2435 )
2436
2437 # Corrupt length field
2438 ethLen = random.randint(0, 1535)
2439 self.testPktsAgainstFlow(
2440 [[
2441 "Eth addr+type match - LLC frame corrupted length - %s" % title,
2442 scapy.Ether(dst=dl_dst, src=dl_src, type=ethLen) / llc,
Christian Dickmanne9b6d252012-10-08 22:56:50 -07002443 self.RESULT_ANY,
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002444 ]],
2445 action.action_output(), match
2446 )
2447
2448 def testPacket(title, llc, is_snap_ip):
2449 testPacketTcpMatch(title, llc)
2450 testPacketEthSrcDstMatch(title, llc)
2451 testPacketEthSrcDstTypeMatch(title, llc, is_snap_ip)
2452
2453 testPacket("LLC - No SNAP - No Payload",
Rich Lane6508ea02012-10-12 15:27:11 -07002454 scapy.LLC(dsap=0x33, ssap=0x44, ctrl=0x03),
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002455 IS_NOT_SNAP_IP,
2456 )
2457 testPacket("LLC - No SNAP - Small Payload",
Rich Lane6508ea02012-10-12 15:27:11 -07002458 scapy.LLC(dsap=0x33, ssap=0x44, ctrl=0x03) / ("S" * 10),
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002459 IS_NOT_SNAP_IP,
2460 )
2461 testPacket("LLC - No SNAP - Max -1 Payload",
Rich Lane6508ea02012-10-12 15:27:11 -07002462 scapy.LLC(dsap=0x33, ssap=0x44, ctrl=0x03) / ("S" * (1500 - 3 - 1)),
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002463 IS_NOT_SNAP_IP,
2464 )
2465 testPacket("LLC - No SNAP - Max Payload",
Rich Lane6508ea02012-10-12 15:27:11 -07002466 scapy.LLC(dsap=0x33, ssap=0x44, ctrl=0x03) / ("S" * (1500 - 3)),
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002467 IS_NOT_SNAP_IP,
2468 )
2469 testPacket("LLC - SNAP - Small bogus payload",
2470 scapy.LLC(dsap=0xaa, ssap=0xaa, ctrl=0x03)/ \
2471 scapy.SNAP(OUI=0x000000, code=0x800) / ("S" * 10),
2472 IS_SNAP_IP_CORRUPT,
2473 )
2474 testPacket("LLC - SNAP - Max -1 bogus payload",
2475 scapy.LLC(dsap=0xaa, ssap=0xaa, ctrl=0x03)/ \
2476 scapy.SNAP(OUI=0x000000, code=0x3) / ("S" * (1500 - 3 - 5 - 1)),
2477 IS_NOT_SNAP_IP,
2478 )
2479 testPacket("LLC - SNAP - Max bogus payload",
2480 scapy.LLC(dsap=0xaa, ssap=0xaa, ctrl=0x03)/ \
2481 scapy.SNAP(OUI=0x000000, code=0x3) / ("S" * (1500 - 3 - 5)),
2482 IS_NOT_SNAP_IP,
2483 )
2484 testPacket("LLC - SNAP - IP - TCP",
2485 scapy.LLC(dsap=0xaa, ssap=0xaa, ctrl=0x03)/ \
2486 scapy.SNAP(OUI=0x000000, code=0x800)/ \
2487 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, proto=6)/ \
2488 scapy.TCP(sport=tcp_sport, dport=tcp_dport),
2489 IS_SNAP_IP,
2490 )
2491
2492
2493class DirectLlcPackets(DirectBadPacketBase):
2494 """
2495 Verify LLC/SNAP parsing (valid and corrupted packets) and matching
2496 """
2497 def runTest(self):
2498 dl_dst='00:01:02:03:04:05'
2499 dl_src='00:06:07:08:09:0a'
2500 ip_src='192.168.0.1'
2501 ip_dst='192.168.0.2'
2502 ip_tos=0
2503 tcp_sport=1234
2504 tcp_dport=80
2505
2506 # Test ethertype in face of LLC/SNAP and OFP_DL_TYPE_NOT_ETH_TYPE
2507 IS_SNAP_NOT_IP = 1
2508 IS_SNAP_AND_IP = 2
2509 IS_NOT_SNAP = 3
2510
2511 def testPacketEthTypeIP(title, llc, is_snap):
2512 match_pkt = scapy.Ether(dst=dl_dst, src=dl_src, type=0x800)
2513 match = packet_to_flow_match(self, match_pkt)
2514 self.assertTrue(match is not None,
2515 "Could not generate flow match from pkt")
2516 match.wildcards &= ~ofp.OFPFW_IN_PORT
2517 pkts = []
2518 if is_snap == IS_NOT_SNAP or is_snap == IS_SNAP_NOT_IP:
2519 result = self.RESULT_NOMATCH
2520 else:
2521 result = self.RESULT_MATCH
2522 pkts.append([
2523 "Ether type 0x800 match - %s" % title,
2524 scapy.Ether(dst=dl_dst, src=dl_src, type=len(llc)) / llc,
2525 result,
2526 ])
2527 act = action.action_output()
2528 self.testPktsAgainstFlow(pkts, act, match)
2529
2530 def testPacketEthTypeNotEth(title, llc, is_snap):
2531 match_pkt = scapy.Ether(dst = dl_dst, src = dl_src,
2532 type = ofp.OFP_DL_TYPE_NOT_ETH_TYPE)
2533 match = packet_to_flow_match(self, match_pkt)
2534 self.assertTrue(match is not None,
2535 "Could not generate flow match from pkt")
2536 match.wildcards &= ~ofp.OFPFW_IN_PORT
2537 pkts = []
2538 if is_snap == IS_NOT_SNAP:
2539 result = self.RESULT_MATCH
2540 else:
2541 result = self.RESULT_NOMATCH
2542 pkts.append([
2543 "Ether type OFP_DL_TYPE_NOT_ETH_TYPE match - %s" % title,
2544 scapy.Ether(dst=dl_dst, src=dl_src, type=len(llc)) / llc,
2545 result,
2546 ])
2547 act = action.action_output()
2548 self.testPktsAgainstFlow(pkts, act, match)
2549
2550 def testPacket(title, llc, is_snap):
2551 testPacketEthTypeIP(title, llc, is_snap)
2552 testPacketEthTypeNotEth(title, llc, is_snap)
2553
2554 testPacket("LLC - No SNAP - No Payload",
Rich Lane6508ea02012-10-12 15:27:11 -07002555 scapy.LLC(dsap=0x33, ssap=0x44, ctrl=0x03),
2556 IS_NOT_SNAP,
2557 )
2558 testPacket("LLC (with information field) - No SNAP - No Payload",
2559 scapy.LLC(dsap=0x33, ssap=0x44, ctrl=0x12) / "S",
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002560 IS_NOT_SNAP,
2561 )
2562 testPacket("LLC - No SNAP - Small Payload",
Rich Lane6508ea02012-10-12 15:27:11 -07002563 scapy.LLC(dsap=0x33, ssap=0x44, ctrl=0x03) / ("S" * 10),
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002564 IS_NOT_SNAP,
2565 )
2566 testPacket("LLC - No SNAP - Max -1 Payload",
Rich Lane6508ea02012-10-12 15:27:11 -07002567 scapy.LLC(dsap=0x33, ssap=0x44, ctrl=0x03) / ("S" * (1500 - 3 - 1)),
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002568 IS_NOT_SNAP,
2569 )
2570 testPacket("LLC - No SNAP - Max Payload",
Rich Lane6508ea02012-10-12 15:27:11 -07002571 scapy.LLC(dsap=0x33, ssap=0x44, ctrl=0x03) / ("S" * (1500 - 3)),
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002572 IS_NOT_SNAP,
2573 )
2574 testPacket("LLC - SNAP - Non-default OUI",
2575 scapy.LLC(dsap=0xaa, ssap=0xaa, ctrl=0x03)/ \
2576 scapy.SNAP(OUI=0x000001, code=0x800) / ("S" * 10),
2577 IS_NOT_SNAP,
2578 )
2579 testPacket("LLC - SNAP - Default OUI",
2580 scapy.LLC(dsap=0xaa, ssap=0xaa, ctrl=0x03)/ \
2581 scapy.SNAP(OUI=0x000000, code=0x800) / ("S" * 10),
2582 IS_SNAP_AND_IP,
2583 )
2584 testPacket("LLC - SNAP - Max -1 bogus payload",
2585 scapy.LLC(dsap=0xaa, ssap=0xaa, ctrl=0x03)/ \
2586 scapy.SNAP(OUI=0x000000, code=0x3) / ("S" * (1500 - 3 - 5 - 1)),
2587 IS_SNAP_NOT_IP,
2588 )
2589 testPacket("LLC - SNAP - Max bogus payload",
2590 scapy.LLC(dsap=0xaa, ssap=0xaa, ctrl=0x03)/ \
2591 scapy.SNAP(OUI=0x000000, code=0x3) / ("S" * (1500 - 3 - 5)),
2592 IS_SNAP_NOT_IP,
2593 )
2594 testPacket("LLC - SNAP - IP - TCP",
2595 scapy.LLC(dsap=0xaa, ssap=0xaa, ctrl=0x03)/ \
2596 scapy.SNAP(OUI=0x000000, code=0x800)/ \
2597 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, proto=6)/ \
2598 scapy.TCP(sport=tcp_sport, dport=tcp_dport),
2599 IS_SNAP_AND_IP,
2600 )
2601
2602
2603class DirectArpPackets(DirectBadPacketBase):
2604 """
2605 Verify ARP parsing (valid and corrupted packets) and ARP matching
2606 """
2607 def runTest(self):
2608 self.testArpHandling()
2609
2610 def testArpHandling(self):
2611 dl_dst='00:01:02:03:04:05'
2612 dl_src='00:06:07:08:09:0a'
2613 ip_src='192.168.0.1'
2614 ip_dst='192.168.0.2'
2615 ip_src2='192.168.1.1'
2616 ip_dst2='192.168.1.2'
2617 ip_tos=0
2618 tcp_sport=1234
2619 tcp_dport=80
2620
2621 def testPacket(title, arp_match, arp_pkt, result):
2622 pkts = []
2623
2624 match_pkt = scapy.Ether(dst=dl_dst, src=dl_src) / arp_match
2625 match = packet_to_flow_match(self, match_pkt)
2626 self.assertTrue(match is not None,
2627 "Could not generate flow match from pkt")
2628 match.wildcards &= ~ofp.OFPFW_IN_PORT
2629
2630 pkts.append([
2631 title,
2632 scapy.Ether(dst=dl_dst, src=dl_src) / arp_pkt,
2633 result,
2634 ])
2635
2636 act = action.action_output()
2637 self.testPktsAgainstFlow(pkts, act, match)
2638
2639 testPacket("Basic ARP",
2640 scapy.ARP(psrc=ip_src, pdst=ip_dst, op = 1),
2641 scapy.ARP(hwdst = '00:00:00:00:00:00', hwsrc = dl_src,
2642 psrc = ip_src, pdst = ip_dst, hwlen = 6, plen = 4,
2643 ptype = 0x800, hwtype = 1, op = 1),
2644 self.RESULT_MATCH
2645 )
2646 # More stuff:
2647 # - Non matches on any property
2648 # - Corrupted hwlen and plen
2649 # - Other hwtype, ptype
2650 # - Truncated ARP pkt
2651
2652
2653class DirectVlanPackets(DirectBadPacketBase):
2654 """
2655 Verify VLAN parsing (valid and corrupted packets) and ARP matching
2656 """
2657 def runTest(self):
2658 dl_dst='00:01:02:03:04:05'
2659 dl_src='00:06:07:08:09:0a'
2660 ip_src='192.168.0.1'
2661 ip_dst='192.168.0.2'
2662 ip_src2='192.168.1.1'
2663 ip_dst2='192.168.1.2'
2664 ip_tos=0
2665 tcp_sport=1234
2666 tcp_dport=80
2667
2668 def testPacket(title, match, pkt, result):
2669 pkts = []
2670
2671 self.assertTrue(match is not None,
2672 "Could not generate flow match from pkt")
2673 match.wildcards &= ~ofp.OFPFW_IN_PORT
2674
2675 pkts.append([
2676 "%s" % title,
2677 pkt,
2678 result,
2679 ])
2680
2681 act = action.action_output()
2682 self.testPktsAgainstFlow(pkts, act, match)
2683
2684 testPacket("Basic MAC matching - IPv4 payload",
2685 self.createMatch(dl_dst=parse_mac(dl_dst), dl_src=parse_mac(dl_src)),
2686 scapy.Ether(dst=dl_dst, src=dl_src, type=0x800) / scapy.IP(),
2687 self.RESULT_MATCH
2688 )
2689 testPacket("Basic MAC matching - VMware beacon - no payload",
2690 self.createMatch(dl_dst=parse_mac(dl_dst), dl_src=parse_mac(dl_src)),
2691 scapy.Ether(dst=dl_dst, src=dl_src, type=0x8922),
2692 self.RESULT_MATCH
2693 )
2694 testPacket("Basic MAC matching - VMware beacon - with payload",
2695 self.createMatch(dl_dst=parse_mac(dl_dst), dl_src=parse_mac(dl_src)),
2696 scapy.Ether(dst=dl_dst, src=dl_src, type=0x8922)/ ("X" * 1),
2697 self.RESULT_MATCH
2698 )
2699 testPacket("Basic MAC matching - IPv6 payload",
2700 self.createMatch(dl_dst=parse_mac(dl_dst), dl_src=parse_mac(dl_src)),
2701 scapy.Ether(dst=dl_dst, src=dl_src) / scapy.IPv6(),
2702 self.RESULT_MATCH
2703 )
2704 testPacket("Basic MAC matching with VLAN tag present",
2705 self.createMatch(dl_dst=parse_mac(dl_dst), dl_src=parse_mac(dl_src)),
2706 scapy.Ether(dst=dl_dst, src=dl_src)/ \
Christian Dickmann8ac55252012-10-08 22:53:49 -07002707 scapy.Dot1Q(prio=5, vlan=1000)/ \
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002708 scapy.IP(),
2709 self.RESULT_MATCH
2710 )
2711 testPacket("Basic MAC matching with VLAN tag present",
2712 self.createMatch(dl_dst=parse_mac(dl_dst), dl_src=parse_mac(dl_src),
2713 dl_type=0x800),
2714 scapy.Ether(dst=dl_dst, src=dl_src)/ \
Christian Dickmann8ac55252012-10-08 22:53:49 -07002715 scapy.Dot1Q(prio=5, vlan=1000)/ \
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002716 scapy.IP(),
2717 self.RESULT_MATCH
2718 )
2719 testPacket("Ether matching with VLAN tag present - No type match",
2720 self.createMatch(dl_dst=parse_mac(dl_dst), dl_src=parse_mac(dl_src),
2721 dl_type=0x801),
2722 scapy.Ether(dst=dl_dst, src=dl_src)/ \
Christian Dickmann8ac55252012-10-08 22:53:49 -07002723 scapy.Dot1Q(prio=5, vlan=1000)/ \
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002724 scapy.IP(),
2725 self.RESULT_NOMATCH
2726 )
2727 testPacket("Ether matching with VLAN tag present - No type match 0x8100",
2728 self.createMatch(dl_dst=parse_mac(dl_dst), dl_src=parse_mac(dl_src),
2729 dl_type=0x8100),
2730 scapy.Ether(dst=dl_dst, src=dl_src)/ \
Christian Dickmann8ac55252012-10-08 22:53:49 -07002731 scapy.Dot1Q(prio=5, vlan=1000)/ \
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002732 scapy.IP(),
2733 self.RESULT_NOMATCH
2734 )
2735 testPacket("Ether matching with double VLAN tag - Wrong type match",
2736 self.createMatch(dl_dst=parse_mac(dl_dst), dl_src=parse_mac(dl_src),
2737 dl_type=0x800),
2738 scapy.Ether(dst=dl_dst, src=dl_src)/ \
Christian Dickmann8ac55252012-10-08 22:53:49 -07002739 scapy.Dot1Q(prio=5, vlan=1000)/ \
2740 scapy.Dot1Q(prio=3, vlan=1005)/ \
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002741 scapy.IP(),
2742 self.RESULT_NOMATCH
2743 )
2744 testPacket("Ether matching with double VLAN tag - Type match",
2745 self.createMatch(dl_dst=parse_mac(dl_dst), dl_src=parse_mac(dl_src),
2746 dl_type=0x8100),
2747 scapy.Ether(dst=dl_dst, src=dl_src)/ \
Christian Dickmann8ac55252012-10-08 22:53:49 -07002748 scapy.Dot1Q(prio=5, vlan=1000)/ \
2749 scapy.Dot1Q(prio=3, vlan=1005)/ \
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002750 scapy.IP(),
2751 self.RESULT_MATCH
2752 )
2753 testPacket("IP matching - VLAN tag",
2754 self.createMatch(dl_dst=parse_mac(dl_dst), dl_src=parse_mac(dl_src),
2755 dl_type=0x0800,
2756 nw_src=parse_ip(ip_src), nw_dst=parse_ip(ip_dst)),
2757 scapy.Ether(dst=dl_dst, src=dl_src)/ \
Christian Dickmann8ac55252012-10-08 22:53:49 -07002758 scapy.Dot1Q(prio=5, vlan=1000)/ \
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002759 scapy.IP(src=ip_src, dst=ip_dst),
2760 self.RESULT_MATCH
2761 )
2762 # XXX:
2763 # - Matching on VLAN ID and Prio
2764 # - Actions
2765
2766
2767
Dan Talayco9f47f4d2010-06-03 13:54:37 -07002768if __name__ == "__main__":
2769 print "Please run through oft script: ./oft --test_spec=basic"