blob: 3c9b04ca30ae46c297ef62aa381ab295b7ccbf05 [file] [log] [blame]
Dan Talayco5eba8442010-03-10 13:58:43 -08001"""
2Test cases for testing actions taken on packets
3
4See basic.py for other info.
5
6It is recommended that these definitions be kept in their own
7namespace as different groups of tests will likely define
8similar identifiers.
9
Rich Lane477f4812012-10-04 22:49:00 -070010The switch is actively attempting to contact the controller at the address
11indicated in config.
Dan Talayco5eba8442010-03-10 13:58:43 -080012
13"""
14
Dan Talayco9f47f4d2010-06-03 13:54:37 -070015import copy
Dan Talayco5eba8442010-03-10 13:58:43 -080016import logging
Rich Laneb90a1c42012-10-05 09:16:05 -070017import time
Dan Talayco5eba8442010-03-10 13:58:43 -080018import unittest
Christian Dickmann8b59b4b2012-09-23 16:48:30 -070019import random
Dan Talayco5eba8442010-03-10 13:58:43 -080020
Rich Lane477f4812012-10-04 22:49:00 -070021from oftest import config
Dan Talayco5eba8442010-03-10 13:58:43 -080022import oftest.controller as controller
23import oftest.cstruct as ofp
24import oftest.message as message
25import oftest.dataplane as dataplane
26import oftest.action as action
27import oftest.parse as parse
Rich Laneb90a1c42012-10-05 09:16:05 -070028import oftest.base_tests as base_tests
29import basic # for IterCases
Dan Talayco5eba8442010-03-10 13:58:43 -080030
Christian Dickmann8b59b4b2012-09-23 16:48:30 -070031from oftest.parse import parse_mac, parse_ip
32
Rich Laneda3b5ad2012-10-03 09:05:32 -070033from oftest.testutils import *
Dan Talayco5eba8442010-03-10 13:58:43 -080034
Dan Talayco551befa2010-07-15 17:05:32 -070035WILDCARD_VALUES = [ofp.OFPFW_IN_PORT,
Dan Talayco488fbc52012-04-09 16:30:41 -070036 ofp.OFPFW_DL_VLAN | ofp.OFPFW_DL_VLAN_PCP,
Dan Talayco551befa2010-07-15 17:05:32 -070037 ofp.OFPFW_DL_SRC,
38 ofp.OFPFW_DL_DST,
Dan Talayco488fbc52012-04-09 16:30:41 -070039 (ofp.OFPFW_DL_TYPE | ofp.OFPFW_NW_SRC_ALL |
40 ofp.OFPFW_NW_DST_ALL | ofp.OFPFW_NW_TOS | ofp.OFPFW_NW_PROTO |
41 ofp.OFPFW_TP_SRC | ofp.OFPFW_TP_DST),
42 (ofp.OFPFW_NW_PROTO | ofp.OFPFW_TP_SRC | ofp.OFPFW_TP_DST),
Dan Talayco551befa2010-07-15 17:05:32 -070043 ofp.OFPFW_TP_SRC,
44 ofp.OFPFW_TP_DST,
Dan Talayco488fbc52012-04-09 16:30:41 -070045 ofp.OFPFW_NW_SRC_MASK,
46 ofp.OFPFW_NW_DST_MASK,
Dan Talayco551befa2010-07-15 17:05:32 -070047 ofp.OFPFW_DL_VLAN_PCP,
48 ofp.OFPFW_NW_TOS]
49
Dan Talayco488fbc52012-04-09 16:30:41 -070050NO_WILDCARD_VALUES = [(ofp.OFPFW_ALL ^ ofp.OFPFW_IN_PORT),
51 (ofp.OFPFW_ALL ^ ofp.OFPFW_DL_VLAN),
52 (ofp.OFPFW_ALL ^ ofp.OFPFW_DL_SRC),
53 (ofp.OFPFW_ALL ^ ofp.OFPFW_DL_DST),
54 (ofp.OFPFW_ALL ^ ofp.OFPFW_DL_TYPE),
55 (ofp.OFPFW_ALL ^ ofp.OFPFW_DL_TYPE ^ ofp.OFPFW_NW_PROTO),
56 (ofp.OFPFW_ALL ^ ofp.OFPFW_DL_TYPE ^ ofp.OFPFW_NW_PROTO ^
57 ofp.OFPFW_TP_SRC),
58 (ofp.OFPFW_ALL ^ ofp.OFPFW_DL_TYPE ^ ofp.OFPFW_NW_PROTO ^
59 ofp.OFPFW_TP_DST),
60 (ofp.OFPFW_ALL ^ ofp.OFPFW_DL_TYPE ^ ofp.OFPFW_NW_PROTO ^
61 ofp.OFPFW_NW_SRC_MASK),
62 (ofp.OFPFW_ALL ^ ofp.OFPFW_DL_TYPE ^ ofp.OFPFW_NW_PROTO ^
63 ofp.OFPFW_NW_DST_MASK),
64 (ofp.OFPFW_ALL ^ ofp.OFPFW_DL_VLAN ^ ofp.OFPFW_DL_VLAN_PCP),
65 (ofp.OFPFW_ALL ^ ofp.OFPFW_DL_TYPE ^ ofp.OFPFW_NW_PROTO ^
66 ofp.OFPFW_NW_TOS)]
67
Dan Talayco551befa2010-07-15 17:05:32 -070068MODIFY_ACTION_VALUES = [ofp.OFPAT_SET_VLAN_VID,
69 ofp.OFPAT_SET_VLAN_PCP,
70 ofp.OFPAT_STRIP_VLAN,
71 ofp.OFPAT_SET_DL_SRC,
72 ofp.OFPAT_SET_DL_DST,
73 ofp.OFPAT_SET_NW_SRC,
74 ofp.OFPAT_SET_NW_DST,
75 ofp.OFPAT_SET_NW_TOS,
76 ofp.OFPAT_SET_TP_SRC,
77 ofp.OFPAT_SET_TP_DST]
78
Dan Talayco21381562010-07-17 00:34:47 -070079TEST_VID_DEFAULT = 2
80
Rich Laneb90a1c42012-10-05 09:16:05 -070081class DirectPacket(base_tests.SimpleDataPlane):
Dan Talayco5eba8442010-03-10 13:58:43 -080082 """
Dan Talayco2d0d49a2010-05-11 15:29:08 -070083 Send packet to single egress port
Dan Talayco5eba8442010-03-10 13:58:43 -080084
85 Generate a packet
86 Generate and install a matching flow
87 Add action to direct the packet to an egress port
88 Send the packet to ingress dataplane port
89 Verify the packet is received at the egress port only
90 """
91 def runTest(self):
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -070092 self.handleFlow()
93
94 def handleFlow(self, pkttype='TCP'):
Rich Lane477f4812012-10-04 22:49:00 -070095 of_ports = config["port_map"].keys()
Dan Talayco5eba8442010-03-10 13:58:43 -080096 of_ports.sort()
97 self.assertTrue(len(of_ports) > 1, "Not enough ports for test")
98
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -070099 if (pkttype == 'ICMP'):
100 pkt = simple_icmp_packet()
101 else:
102 pkt = simple_tcp_packet()
Ed Swierk99a74de2012-08-22 06:40:54 -0700103 match = packet_to_flow_match(self, pkt)
Dan Talayco7dd6cd62010-03-16 15:02:35 -0700104 match.wildcards &= ~ofp.OFPFW_IN_PORT
Dan Talayco5eba8442010-03-10 13:58:43 -0800105 self.assertTrue(match is not None,
106 "Could not generate flow match from pkt")
107 act = action.action_output()
108
109 for idx in range(len(of_ports)):
Rich Lane32bf9482013-01-03 17:26:30 -0800110 delete_all_flows(self.controller)
Dan Talayco2e77a842010-05-12 15:39:46 -0700111
Dan Talayco5eba8442010-03-10 13:58:43 -0800112 ingress_port = of_ports[idx]
113 egress_port = of_ports[(idx + 1) % len(of_ports)]
Rich Lane9a003812012-10-04 17:17:59 -0700114 logging.info("Ingress " + str(ingress_port) +
Dan Talayco551befa2010-07-15 17:05:32 -0700115 " to egress " + str(egress_port))
Dan Talayco5eba8442010-03-10 13:58:43 -0800116
117 match.in_port = ingress_port
118
119 request = message.flow_mod()
120 request.match = match
Jeffrey Townsend2a300e42012-03-28 17:24:02 -0700121
Dan Talayco5eba8442010-03-10 13:58:43 -0800122 request.buffer_id = 0xffffffff
123 act.port = egress_port
Rich Lanee30455b2013-01-03 16:24:44 -0800124 request.actions.add(act)
Dan Talayco5eba8442010-03-10 13:58:43 -0800125
Rich Lane9a003812012-10-04 17:17:59 -0700126 logging.info("Inserting flow")
Rich Lane5c3151c2013-01-03 17:15:41 -0800127 self.controller.message_send(request)
Dan Talayco0fc08bd2012-04-09 16:56:18 -0700128 self.assertEqual(do_barrier(self.controller), 0, "Barrier failed")
Dan Talayco5eba8442010-03-10 13:58:43 -0800129
Rich Lane9a003812012-10-04 17:17:59 -0700130 logging.info("Sending packet to dp port " +
Dan Talayco5eba8442010-03-10 13:58:43 -0800131 str(ingress_port))
132 self.dataplane.send(ingress_port, str(pkt))
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700133
134 exp_pkt_arg = None
135 exp_port = None
Rich Lane477f4812012-10-04 22:49:00 -0700136 if config["relax"]:
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700137 exp_pkt_arg = pkt
138 exp_port = egress_port
139
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700140 (rcv_port, rcv_pkt, pkt_time) = self.dataplane.poll(port_number=exp_port,
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700141 exp_pkt=exp_pkt_arg)
Dan Talayco5eba8442010-03-10 13:58:43 -0800142 self.assertTrue(rcv_pkt is not None, "Did not receive packet")
Rich Lane9a003812012-10-04 17:17:59 -0700143 logging.debug("Packet len " + str(len(rcv_pkt)) + " in on " +
Dan Talayco5eba8442010-03-10 13:58:43 -0800144 str(rcv_port))
145 self.assertEqual(rcv_port, egress_port, "Unexpected receive port")
146 self.assertEqual(str(pkt), str(rcv_pkt),
147 'Response packet does not match send packet')
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700148
Rich Laneb90a1c42012-10-05 09:16:05 -0700149class DirectPacketController(base_tests.SimpleDataPlane):
Rich Lane51c23b32012-07-27 16:37:25 -0700150 """
151 Send packet to the controller port
152
153 Generate a packet
154 Generate and install a matching flow
155 Add action to direct the packet to the controller port
156 Send the packet to ingress dataplane port
157 Verify the packet is received at the controller port
158 """
159 def runTest(self):
160 self.handleFlow()
161
162 def handleFlow(self, pkttype='TCP'):
Rich Lane477f4812012-10-04 22:49:00 -0700163 of_ports = config["port_map"].keys()
Rich Lane51c23b32012-07-27 16:37:25 -0700164 of_ports.sort()
165 self.assertTrue(len(of_ports) > 0, "Not enough ports for test")
166
167 if (pkttype == 'ICMP'):
168 pkt = simple_icmp_packet()
169 else:
170 pkt = simple_tcp_packet()
Ed Swierk99a74de2012-08-22 06:40:54 -0700171 match = packet_to_flow_match(self, pkt)
Rich Lane51c23b32012-07-27 16:37:25 -0700172 match.wildcards &= ~ofp.OFPFW_IN_PORT
173 self.assertTrue(match is not None,
174 "Could not generate flow match from pkt")
175 act = action.action_output()
176
Rich Lane32bf9482013-01-03 17:26:30 -0800177 delete_all_flows(self.controller)
Rich Lane51c23b32012-07-27 16:37:25 -0700178
179 ingress_port = of_ports[0]
180 match.in_port = ingress_port
181
182 request = message.flow_mod()
183 request.match = match
184
185 request.buffer_id = 0xffffffff
186 act.port = ofp.OFPP_CONTROLLER
187 act.max_len = 65535
Rich Lanee30455b2013-01-03 16:24:44 -0800188 request.actions.add(act)
Rich Lane51c23b32012-07-27 16:37:25 -0700189
Rich Lane9a003812012-10-04 17:17:59 -0700190 logging.info("Inserting flow")
Rich Lane5c3151c2013-01-03 17:15:41 -0800191 self.controller.message_send(request)
Rich Lane51c23b32012-07-27 16:37:25 -0700192 self.assertEqual(do_barrier(self.controller), 0, "Barrier failed")
193
Rich Lane9a003812012-10-04 17:17:59 -0700194 logging.info("Sending packet to dp port " +
Rich Lane51c23b32012-07-27 16:37:25 -0700195 str(ingress_port))
196 self.dataplane.send(ingress_port, str(pkt))
197
198 (response, raw) = self.controller.poll(ofp.OFPT_PACKET_IN)
199
200 self.assertTrue(response is not None,
201 'Packet in message not received by controller')
202 if not dataplane.match_exp_pkt(pkt, response.data):
Rich Lane9a003812012-10-04 17:17:59 -0700203 logging.debug("Sent %s" % format_packet(pkt))
204 logging.debug("Resp %s" % format_packet(response.data))
Rich Lane51c23b32012-07-27 16:37:25 -0700205 self.assertTrue(False,
206 'Response packet does not match send packet' +
207 ' for controller port')
208
Howard Pershf97840f2012-04-10 16:30:42 -0700209
Rich Laneb90a1c42012-10-05 09:16:05 -0700210class DirectPacketQueue(base_tests.SimpleDataPlane):
Howard Pershf97840f2012-04-10 16:30:42 -0700211 """
212 Send packet to single queue on single egress port
213
214 Generate a packet
215 Generate and install a matching flow
216 Add action to direct the packet to an egress port and queue
217 Send the packet to ingress dataplane port
218 Verify the packet is received at the egress port only
219 """
220 def runTest(self):
221 self.handleFlow()
222
Howard Persh670b5672012-04-13 09:08:29 -0700223 def portQueuesGet(self, queue_stats, port_num):
224 result = []
225 for qs in queue_stats.stats:
226 if qs.port_no != port_num:
227 continue
228 result.append(qs.queue_id)
229 return result
230
Howard Pershf97840f2012-04-10 16:30:42 -0700231 def handleFlow(self, pkttype='TCP'):
Rich Lane477f4812012-10-04 22:49:00 -0700232 of_ports = config["port_map"].keys()
Howard Pershf97840f2012-04-10 16:30:42 -0700233 of_ports.sort()
234 self.assertTrue(len(of_ports) > 1, "Not enough ports for test")
235
236 if (pkttype == 'ICMP'):
237 pkt = simple_icmp_packet()
238 else:
239 pkt = simple_tcp_packet()
Ed Swierk99a74de2012-08-22 06:40:54 -0700240 match = packet_to_flow_match(self, pkt)
Howard Pershf97840f2012-04-10 16:30:42 -0700241 match.wildcards &= ~ofp.OFPFW_IN_PORT
242 self.assertTrue(match is not None,
243 "Could not generate flow match from pkt")
244
Howard Persh670b5672012-04-13 09:08:29 -0700245 # Get queue stats from switch
246
247 request = message.queue_stats_request()
248 request.port_no = ofp.OFPP_ALL
249 request.queue_id = ofp.OFPQ_ALL
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700250 (queue_stats, p) = self.controller.transact(request)
Howard Persh670b5672012-04-13 09:08:29 -0700251 self.assertNotEqual(queue_stats, None, "Queue stats request failed")
252
253 act = action.action_enqueue()
Howard Pershf97840f2012-04-10 16:30:42 -0700254
255 for idx in range(len(of_ports)):
Howard Pershf97840f2012-04-10 16:30:42 -0700256 ingress_port = of_ports[idx]
257 egress_port = of_ports[(idx + 1) % len(of_ports)]
Howard Pershf97840f2012-04-10 16:30:42 -0700258
Howard Persh670b5672012-04-13 09:08:29 -0700259 for egress_queue_id in self.portQueuesGet(queue_stats, egress_port):
Rich Lane9a003812012-10-04 17:17:59 -0700260 logging.info("Ingress " + str(ingress_port)
Howard Persh670b5672012-04-13 09:08:29 -0700261 + " to egress " + str(egress_port)
262 + " queue " + str(egress_queue_id)
263 )
Howard Pershf97840f2012-04-10 16:30:42 -0700264
Rich Lane32bf9482013-01-03 17:26:30 -0800265 delete_all_flows(self.controller)
Howard Pershf97840f2012-04-10 16:30:42 -0700266
Howard Persh670b5672012-04-13 09:08:29 -0700267 match.in_port = ingress_port
268
269 request = message.flow_mod()
270 request.match = match
Howard Pershf97840f2012-04-10 16:30:42 -0700271
Howard Persh670b5672012-04-13 09:08:29 -0700272 request.buffer_id = 0xffffffff
273 act.port = egress_port
274 act.queue_id = egress_queue_id
Rich Lanee30455b2013-01-03 16:24:44 -0800275 request.actions.add(act)
Howard Pershf97840f2012-04-10 16:30:42 -0700276
Rich Lane9a003812012-10-04 17:17:59 -0700277 logging.info("Inserting flow")
Rich Lane5c3151c2013-01-03 17:15:41 -0800278 self.controller.message_send(request)
Howard Persh670b5672012-04-13 09:08:29 -0700279 self.assertEqual(do_barrier(self.controller), 0, "Barrier failed")
Howard Pershf97840f2012-04-10 16:30:42 -0700280
Howard Persh670b5672012-04-13 09:08:29 -0700281 # Get current stats for selected egress queue
Howard Pershf97840f2012-04-10 16:30:42 -0700282
Howard Persh670b5672012-04-13 09:08:29 -0700283 request = message.queue_stats_request()
284 request.port_no = egress_port
285 request.queue_id = egress_queue_id
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700286 (qs_before, p) = self.controller.transact(request)
Howard Persh670b5672012-04-13 09:08:29 -0700287 self.assertNotEqual(qs_before, None, "Queue stats request failed")
288
Rich Lane9a003812012-10-04 17:17:59 -0700289 logging.info("Sending packet to dp port " +
Howard Persh670b5672012-04-13 09:08:29 -0700290 str(ingress_port))
291 self.dataplane.send(ingress_port, str(pkt))
292
293 exp_pkt_arg = None
294 exp_port = None
Rich Lane477f4812012-10-04 22:49:00 -0700295 if config["relax"]:
Howard Persh670b5672012-04-13 09:08:29 -0700296 exp_pkt_arg = pkt
297 exp_port = egress_port
298
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700299 (rcv_port, rcv_pkt, pkt_time) = self.dataplane.poll(port_number=exp_port,
Howard Persh670b5672012-04-13 09:08:29 -0700300 exp_pkt=exp_pkt_arg)
301 self.assertTrue(rcv_pkt is not None, "Did not receive packet")
Rich Lane9a003812012-10-04 17:17:59 -0700302 logging.debug("Packet len " + str(len(rcv_pkt)) + " in on " +
Howard Persh670b5672012-04-13 09:08:29 -0700303 str(rcv_port))
304 self.assertEqual(rcv_port, egress_port, "Unexpected receive port")
305 self.assertEqual(str(pkt), str(rcv_pkt),
306 'Response packet does not match send packet')
307
Ed Swierkb8a86512012-04-18 18:45:58 -0700308 # FIXME: instead of sleeping, keep requesting queue stats until
309 # the expected queue counter increases or some large timeout is
310 # reached
311 time.sleep(2)
312
Howard Persh670b5672012-04-13 09:08:29 -0700313 # Get current stats for selected egress queue again
314
315 request = message.queue_stats_request()
316 request.port_no = egress_port
317 request.queue_id = egress_queue_id
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700318 (qs_after, p) = self.controller.transact(request)
Howard Persh670b5672012-04-13 09:08:29 -0700319 self.assertNotEqual(qs_after, None, "Queue stats request failed")
320
321 # Make sure that tx packet counter for selected egress queue was
322 # incremented
323
Ed Swierk22f59152012-04-17 16:36:47 -0700324 self.assertEqual(qs_after.stats[0].tx_packets, \
325 qs_before.stats[0].tx_packets + 1, \
Howard Persh670b5672012-04-13 09:08:29 -0700326 "Verification of egress queue tx packet count failed"
327 )
328
329
Rich Laneb90a1c42012-10-05 09:16:05 -0700330class DirectPacketControllerQueue(base_tests.SimpleDataPlane):
Ken Chiang899ff8e2012-05-23 18:26:12 -0700331 """
332 Send a packet from each of the openflow ports
333 to each of the queues configured on the controller port.
334 If no queues have been configured, no packets are sent.
Howard Pershf97840f2012-04-10 16:30:42 -0700335
Ken Chiang899ff8e2012-05-23 18:26:12 -0700336 Generate a packet
337 Generate and install a matching flow
338 Add action to direct the packet to one of the controller port queues
339 Send the packet to ingress dataplane port
340 Verify the packet is received on the controller port queue
341 """
342 def runTest(self):
343 self.handleFlow()
344
345 def portQueuesGet(self, queue_stats, port_num):
346 result = []
347 for qs in queue_stats.stats:
348 if qs.port_no != port_num:
349 continue
350 result.append(qs.queue_id)
351 return result
352
353 def handleFlow(self, pkttype='TCP'):
Rich Lane477f4812012-10-04 22:49:00 -0700354 of_ports = config["port_map"].keys()
Ken Chiang899ff8e2012-05-23 18:26:12 -0700355 of_ports.sort()
356 self.assertTrue(len(of_ports) > 1, "Not enough ports for test")
357
358 if (pkttype == 'ICMP'):
359 pkt = simple_icmp_packet()
360 else:
361 pkt = simple_tcp_packet()
Ed Swierk99a74de2012-08-22 06:40:54 -0700362 match = packet_to_flow_match(self, pkt)
Ken Chiang899ff8e2012-05-23 18:26:12 -0700363 match.wildcards &= ~ofp.OFPFW_IN_PORT
364 self.assertTrue(match is not None,
365 "Could not generate flow match from pkt")
366
367 # Get queue stats from switch
368
369 request = message.queue_stats_request()
370 request.port_no = ofp.OFPP_CONTROLLER
371 request.queue_id = ofp.OFPQ_ALL
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700372 (queue_stats, p) = self.controller.transact(request)
Ken Chiang899ff8e2012-05-23 18:26:12 -0700373 self.assertNotEqual(queue_stats, None, "Queue stats request failed")
Rich Laneb8c845a2012-12-31 17:23:51 -0800374 if queue_stats.header.type == ofp.OFPT_ERROR:
375 skip_message_emit(self, "Enqueue packet to controller")
376 return
Ken Chiang899ff8e2012-05-23 18:26:12 -0700377
378 act = action.action_enqueue()
379
380 for idx in range(len(of_ports)):
381 ingress_port = of_ports[idx]
382 egress_port = ofp.OFPP_CONTROLLER
383
Rich Lane9a003812012-10-04 17:17:59 -0700384 logging.info("Ingress port " + str(ingress_port)
Ken Chiang899ff8e2012-05-23 18:26:12 -0700385 + ", controller port queues "
386 + str(self.portQueuesGet(queue_stats, egress_port)))
387
388 for egress_queue_id in self.portQueuesGet(queue_stats, egress_port):
Rich Lane9a003812012-10-04 17:17:59 -0700389 logging.info("Ingress " + str(ingress_port)
Ken Chiang899ff8e2012-05-23 18:26:12 -0700390 + " to egress " + str(egress_port)
391 + " queue " + str(egress_queue_id)
392 )
393
Rich Lane32bf9482013-01-03 17:26:30 -0800394 delete_all_flows(self.controller)
Ken Chiang899ff8e2012-05-23 18:26:12 -0700395
396 match.in_port = ingress_port
397
398 request = message.flow_mod()
399 request.match = match
400
401 request.buffer_id = 0xffffffff
402 act.port = egress_port
403 act.queue_id = egress_queue_id
Rich Lanee30455b2013-01-03 16:24:44 -0800404 request.actions.add(act)
Ken Chiang899ff8e2012-05-23 18:26:12 -0700405
Rich Lane9a003812012-10-04 17:17:59 -0700406 logging.info("Inserting flow")
Rich Lane5c3151c2013-01-03 17:15:41 -0800407 self.controller.message_send(request)
Ken Chiang899ff8e2012-05-23 18:26:12 -0700408 self.assertEqual(do_barrier(self.controller), 0, "Barrier failed")
409
410 # Get current stats for selected egress queue
411
412 request = message.queue_stats_request()
413 request.port_no = egress_port
414 request.queue_id = egress_queue_id
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700415 (qs_before, p) = self.controller.transact(request)
Ken Chiang899ff8e2012-05-23 18:26:12 -0700416 self.assertNotEqual(qs_before, None, "Queue stats request failed")
417
Rich Lane9a003812012-10-04 17:17:59 -0700418 logging.info("Sending packet to dp port " +
Ken Chiang899ff8e2012-05-23 18:26:12 -0700419 str(ingress_port))
420 self.dataplane.send(ingress_port, str(pkt))
421
422 exp_pkt_arg = None
423 exp_port = None
424
Rich Lanee5779d32012-10-05 17:56:04 -0700425 count = 0
Ken Chiang899ff8e2012-05-23 18:26:12 -0700426 while True:
Dan Talaycoc689a792012-09-28 14:22:53 -0700427 (response, raw) = self.controller.poll(ofp.OFPT_PACKET_IN)
Ken Chiang899ff8e2012-05-23 18:26:12 -0700428 if not response: # Timeout
429 break
430 if dataplane.match_exp_pkt(pkt, response.data): # Got match
431 break
Rich Lane477f4812012-10-04 22:49:00 -0700432 if not config["relax"]: # Only one attempt to match
Ken Chiang899ff8e2012-05-23 18:26:12 -0700433 break
434 count += 1
435 if count > 10: # Too many tries
436 break
437
438 self.assertTrue(response is not None,
439 'Packet in message not received by controller')
440 if not dataplane.match_exp_pkt(pkt, response.data):
Rich Lane9a003812012-10-04 17:17:59 -0700441 logging.debug("Sent %s" % format_packet(pkt))
442 logging.debug("Resp %s" % format_packet(response.data))
Ken Chiang899ff8e2012-05-23 18:26:12 -0700443 self.assertTrue(False,
444 'Response packet does not match send packet' +
445 ' for controller port')
446
447 # FIXME: instead of sleeping, keep requesting queue stats until
448 # the expected queue counter increases or some large timeout is
449 # reached
450 time.sleep(2)
451
452 # Get current stats for selected egress queue again
453
454 request = message.queue_stats_request()
455 request.port_no = egress_port
456 request.queue_id = egress_queue_id
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700457 (qs_after, p) = self.controller.transact(request)
Ken Chiang899ff8e2012-05-23 18:26:12 -0700458 self.assertNotEqual(qs_after, None, "Queue stats request failed")
459
460 # Make sure that tx packet counter for selected egress queue was
461 # incremented
462
463 self.assertEqual(qs_after.stats[0].tx_packets, \
464 qs_before.stats[0].tx_packets + 1, \
465 "Verification of egress queue tx packet count failed"
466 )
467
Howard Pershf97840f2012-04-10 16:30:42 -0700468
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700469class DirectPacketICMP(DirectPacket):
470 """
471 Send ICMP packet to single egress port
472
473 Generate a ICMP packet
474 Generate and install a matching flow
475 Add action to direct the packet to an egress port
476 Send the packet to ingress dataplane port
477 Verify the packet is received at the egress port only
478 Difference from DirectPacket test is that sent packet is ICMP
479 """
480 def runTest(self):
481 self.handleFlow(pkttype='ICMP')
Dan Talayco2d0d49a2010-05-11 15:29:08 -0700482
Rich Laneb90a1c42012-10-05 09:16:05 -0700483class DirectTwoPorts(base_tests.SimpleDataPlane):
Dan Talayco2d0d49a2010-05-11 15:29:08 -0700484 """
485 Send packet to two egress ports
486
487 Generate a packet
488 Generate and install a matching flow
489 Add action to direct the packet to two egress ports
490 Send the packet to ingress dataplane port
491 Verify the packet is received at the two egress ports
492 """
493 def runTest(self):
Rich Lane477f4812012-10-04 22:49:00 -0700494 of_ports = config["port_map"].keys()
Dan Talayco2d0d49a2010-05-11 15:29:08 -0700495 of_ports.sort()
496 self.assertTrue(len(of_ports) > 2, "Not enough ports for test")
497
Dan Talayco2d0d49a2010-05-11 15:29:08 -0700498 pkt = simple_tcp_packet()
Ed Swierk99a74de2012-08-22 06:40:54 -0700499 match = packet_to_flow_match(self, pkt)
Dan Talayco2d0d49a2010-05-11 15:29:08 -0700500 match.wildcards &= ~ofp.OFPFW_IN_PORT
501 self.assertTrue(match is not None,
502 "Could not generate flow match from pkt")
503 act = action.action_output()
504
505 for idx in range(len(of_ports)):
Rich Lane32bf9482013-01-03 17:26:30 -0800506 delete_all_flows(self.controller)
Dan Talayco2e77a842010-05-12 15:39:46 -0700507
Dan Talayco2d0d49a2010-05-11 15:29:08 -0700508 ingress_port = of_ports[idx]
509 egress_port1 = of_ports[(idx + 1) % len(of_ports)]
510 egress_port2 = of_ports[(idx + 2) % len(of_ports)]
Rich Lane9a003812012-10-04 17:17:59 -0700511 logging.info("Ingress " + str(ingress_port) +
Dan Talayco2d0d49a2010-05-11 15:29:08 -0700512 " to egress " + str(egress_port1) + " and " +
513 str(egress_port2))
514
515 match.in_port = ingress_port
516
517 request = message.flow_mod()
518 request.match = match
519 request.buffer_id = 0xffffffff
520 act.port = egress_port1
Rich Lanee30455b2013-01-03 16:24:44 -0800521 request.actions.add(act)
Dan Talayco2d0d49a2010-05-11 15:29:08 -0700522 act.port = egress_port2
Rich Lanee30455b2013-01-03 16:24:44 -0800523 request.actions.add(act)
Rich Lane9a003812012-10-04 17:17:59 -0700524 # logging.info(request.show())
Dan Talayco2d0d49a2010-05-11 15:29:08 -0700525
Rich Lane9a003812012-10-04 17:17:59 -0700526 logging.info("Inserting flow")
Rich Lane5c3151c2013-01-03 17:15:41 -0800527 self.controller.message_send(request)
Dan Talayco0fc08bd2012-04-09 16:56:18 -0700528 self.assertEqual(do_barrier(self.controller), 0, "Barrier failed")
Dan Talayco2d0d49a2010-05-11 15:29:08 -0700529
Rich Lane9a003812012-10-04 17:17:59 -0700530 logging.info("Sending packet to dp port " +
Dan Talayco2d0d49a2010-05-11 15:29:08 -0700531 str(ingress_port))
532 self.dataplane.send(ingress_port, str(pkt))
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700533 yes_ports = set([egress_port1, egress_port2])
534 no_ports = set(of_ports).difference(yes_ports)
Dan Talayco2d0d49a2010-05-11 15:29:08 -0700535
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700536 receive_pkt_check(self.dataplane, pkt, yes_ports, no_ports,
Rich Lane2014f9b2012-10-05 15:29:40 -0700537 self)
Dan Talaycob0b0fdb2010-05-11 15:44:56 -0700538
Rich Laneb90a1c42012-10-05 09:16:05 -0700539class DirectMCNonIngress(base_tests.SimpleDataPlane):
Dan Talaycob0b0fdb2010-05-11 15:44:56 -0700540 """
541 Multicast to all non-ingress ports
542
543 Generate a packet
544 Generate and install a matching flow
545 Add action to direct the packet to all non-ingress ports
546 Send the packet to ingress dataplane port
547 Verify the packet is received at all non-ingress ports
548
549 Does not use the flood action
550 """
551 def runTest(self):
Rich Lane477f4812012-10-04 22:49:00 -0700552 of_ports = config["port_map"].keys()
Dan Talaycob0b0fdb2010-05-11 15:44:56 -0700553 of_ports.sort()
554 self.assertTrue(len(of_ports) > 2, "Not enough ports for test")
555
Dan Talaycob0b0fdb2010-05-11 15:44:56 -0700556 pkt = simple_tcp_packet()
Ed Swierk99a74de2012-08-22 06:40:54 -0700557 match = packet_to_flow_match(self, pkt)
Dan Talaycob0b0fdb2010-05-11 15:44:56 -0700558 match.wildcards &= ~ofp.OFPFW_IN_PORT
559 self.assertTrue(match is not None,
560 "Could not generate flow match from pkt")
561 act = action.action_output()
562
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700563 for ingress_port in of_ports:
Rich Lane32bf9482013-01-03 17:26:30 -0800564 delete_all_flows(self.controller)
Dan Talayco2e77a842010-05-12 15:39:46 -0700565
Rich Lane9a003812012-10-04 17:17:59 -0700566 logging.info("Ingress " + str(ingress_port) +
Dan Talaycob0b0fdb2010-05-11 15:44:56 -0700567 " all non-ingress ports")
Dan Talaycob0b0fdb2010-05-11 15:44:56 -0700568 match.in_port = ingress_port
569
570 request = message.flow_mod()
571 request.match = match
572 request.buffer_id = 0xffffffff
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700573 for egress_port in of_ports:
574 if egress_port == ingress_port:
Dan Talaycob0b0fdb2010-05-11 15:44:56 -0700575 continue
Dan Talaycob0b0fdb2010-05-11 15:44:56 -0700576 act.port = egress_port
Rich Lanee30455b2013-01-03 16:24:44 -0800577 request.actions.add(act)
Rich Lane9a003812012-10-04 17:17:59 -0700578 logging.debug(request.show())
Dan Talaycob0b0fdb2010-05-11 15:44:56 -0700579
Rich Lane9a003812012-10-04 17:17:59 -0700580 logging.info("Inserting flow")
Rich Lane5c3151c2013-01-03 17:15:41 -0800581 self.controller.message_send(request)
Dan Talayco0fc08bd2012-04-09 16:56:18 -0700582 self.assertEqual(do_barrier(self.controller), 0, "Barrier failed")
Dan Talaycob0b0fdb2010-05-11 15:44:56 -0700583
Rich Lane9a003812012-10-04 17:17:59 -0700584 logging.info("Sending packet to dp port " + str(ingress_port))
Dan Talaycob0b0fdb2010-05-11 15:44:56 -0700585 self.dataplane.send(ingress_port, str(pkt))
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700586 yes_ports = set(of_ports).difference([ingress_port])
587 receive_pkt_check(self.dataplane, pkt, yes_ports, [ingress_port],
Rich Lane2014f9b2012-10-05 15:29:40 -0700588 self)
Dan Talaycob0b0fdb2010-05-11 15:44:56 -0700589
Dan Talayco32fa6542010-05-11 15:54:08 -0700590
Rich Laneb90a1c42012-10-05 09:16:05 -0700591class DirectMC(base_tests.SimpleDataPlane):
Dan Talayco32fa6542010-05-11 15:54:08 -0700592 """
593 Multicast to all ports including ingress
594
595 Generate a packet
596 Generate and install a matching flow
597 Add action to direct the packet to all non-ingress ports
598 Send the packet to ingress dataplane port
599 Verify the packet is received at all ports
600
601 Does not use the flood action
602 """
603 def runTest(self):
Rich Lane477f4812012-10-04 22:49:00 -0700604 of_ports = config["port_map"].keys()
Dan Talayco32fa6542010-05-11 15:54:08 -0700605 of_ports.sort()
606 self.assertTrue(len(of_ports) > 2, "Not enough ports for test")
607
Dan Talayco32fa6542010-05-11 15:54:08 -0700608 pkt = simple_tcp_packet()
Ed Swierk99a74de2012-08-22 06:40:54 -0700609 match = packet_to_flow_match(self, pkt)
Dan Talayco32fa6542010-05-11 15:54:08 -0700610 match.wildcards &= ~ofp.OFPFW_IN_PORT
611 self.assertTrue(match is not None,
612 "Could not generate flow match from pkt")
613 act = action.action_output()
614
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700615 for ingress_port in of_ports:
Rich Lane32bf9482013-01-03 17:26:30 -0800616 delete_all_flows(self.controller)
Dan Talayco2e77a842010-05-12 15:39:46 -0700617
Rich Lane9a003812012-10-04 17:17:59 -0700618 logging.info("Ingress " + str(ingress_port) + " to all ports")
Dan Talayco32fa6542010-05-11 15:54:08 -0700619 match.in_port = ingress_port
620
621 request = message.flow_mod()
622 request.match = match
623 request.buffer_id = 0xffffffff
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700624 for egress_port in of_ports:
625 if egress_port == ingress_port:
Dan Talayco32fa6542010-05-11 15:54:08 -0700626 act.port = ofp.OFPP_IN_PORT
627 else:
628 act.port = egress_port
Rich Lanee30455b2013-01-03 16:24:44 -0800629 request.actions.add(act)
Rich Lane9a003812012-10-04 17:17:59 -0700630 # logging.info(request.show())
Dan Talayco2e77a842010-05-12 15:39:46 -0700631
Rich Lane9a003812012-10-04 17:17:59 -0700632 logging.info("Inserting flow")
Rich Lane5c3151c2013-01-03 17:15:41 -0800633 self.controller.message_send(request)
Dan Talayco0fc08bd2012-04-09 16:56:18 -0700634 self.assertEqual(do_barrier(self.controller), 0, "Barrier failed")
Dan Talayco2e77a842010-05-12 15:39:46 -0700635
Rich Lane9a003812012-10-04 17:17:59 -0700636 logging.info("Sending packet to dp port " + str(ingress_port))
Dan Talayco2e77a842010-05-12 15:39:46 -0700637 self.dataplane.send(ingress_port, str(pkt))
Rich Lane2014f9b2012-10-05 15:29:40 -0700638 receive_pkt_check(self.dataplane, pkt, of_ports, [], self)
Dan Talayco2e77a842010-05-12 15:39:46 -0700639
Rich Laneb90a1c42012-10-05 09:16:05 -0700640class Flood(base_tests.SimpleDataPlane):
Dan Talayco2e77a842010-05-12 15:39:46 -0700641 """
642 Flood to all ports except ingress
643
644 Generate a packet
645 Generate and install a matching flow
646 Add action to flood the packet
647 Send the packet to ingress dataplane port
648 Verify the packet is received at all other ports
649 """
650 def runTest(self):
Rich Lane477f4812012-10-04 22:49:00 -0700651 of_ports = config["port_map"].keys()
Dan Talayco2e77a842010-05-12 15:39:46 -0700652 of_ports.sort()
653 self.assertTrue(len(of_ports) > 1, "Not enough ports for test")
654
655 pkt = simple_tcp_packet()
Ed Swierk99a74de2012-08-22 06:40:54 -0700656 match = packet_to_flow_match(self, pkt)
Dan Talayco2e77a842010-05-12 15:39:46 -0700657 match.wildcards &= ~ofp.OFPFW_IN_PORT
658 self.assertTrue(match is not None,
659 "Could not generate flow match from pkt")
660 act = action.action_output()
661
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700662 for ingress_port in of_ports:
Rich Lane32bf9482013-01-03 17:26:30 -0800663 delete_all_flows(self.controller)
Dan Talayco2e77a842010-05-12 15:39:46 -0700664
Rich Lane9a003812012-10-04 17:17:59 -0700665 logging.info("Ingress " + str(ingress_port) + " to all ports")
Dan Talayco2e77a842010-05-12 15:39:46 -0700666 match.in_port = ingress_port
667
668 request = message.flow_mod()
669 request.match = match
670 request.buffer_id = 0xffffffff
671 act.port = ofp.OFPP_FLOOD
Rich Lanee30455b2013-01-03 16:24:44 -0800672 request.actions.add(act)
Rich Lane9a003812012-10-04 17:17:59 -0700673 logging.info(request.show())
Dan Talayco32fa6542010-05-11 15:54:08 -0700674
Rich Lane9a003812012-10-04 17:17:59 -0700675 logging.info("Inserting flow")
Rich Lane5c3151c2013-01-03 17:15:41 -0800676 self.controller.message_send(request)
Dan Talayco0fc08bd2012-04-09 16:56:18 -0700677 self.assertEqual(do_barrier(self.controller), 0, "Barrier failed")
Dan Talayco32fa6542010-05-11 15:54:08 -0700678
Rich Lane9a003812012-10-04 17:17:59 -0700679 logging.info("Sending packet to dp port " + str(ingress_port))
Dan Talayco32fa6542010-05-11 15:54:08 -0700680 self.dataplane.send(ingress_port, str(pkt))
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700681 yes_ports = set(of_ports).difference([ingress_port])
682 receive_pkt_check(self.dataplane, pkt, yes_ports, [ingress_port],
Rich Lane2014f9b2012-10-05 15:29:40 -0700683 self)
Dan Talayco3be5b062010-05-12 15:46:21 -0700684
Rich Laneb90a1c42012-10-05 09:16:05 -0700685class FloodPlusIngress(base_tests.SimpleDataPlane):
Dan Talayco3be5b062010-05-12 15:46:21 -0700686 """
687 Flood to all ports plus send to ingress port
688
689 Generate a packet
690 Generate and install a matching flow
691 Add action to flood the packet
692 Add action to send to ingress port
693 Send the packet to ingress dataplane port
694 Verify the packet is received at all other ports
695 """
696 def runTest(self):
Rich Lane477f4812012-10-04 22:49:00 -0700697 of_ports = config["port_map"].keys()
Dan Talayco3be5b062010-05-12 15:46:21 -0700698 of_ports.sort()
699 self.assertTrue(len(of_ports) > 1, "Not enough ports for test")
700
701 pkt = simple_tcp_packet()
Ed Swierk99a74de2012-08-22 06:40:54 -0700702 match = packet_to_flow_match(self, pkt)
Dan Talayco3be5b062010-05-12 15:46:21 -0700703 match.wildcards &= ~ofp.OFPFW_IN_PORT
704 self.assertTrue(match is not None,
705 "Could not generate flow match from pkt")
706 act = action.action_output()
707
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700708 for ingress_port in of_ports:
Rich Lane32bf9482013-01-03 17:26:30 -0800709 delete_all_flows(self.controller)
Dan Talayco3be5b062010-05-12 15:46:21 -0700710
Rich Lane9a003812012-10-04 17:17:59 -0700711 logging.info("Ingress " + str(ingress_port) + " to all ports")
Dan Talayco3be5b062010-05-12 15:46:21 -0700712 match.in_port = ingress_port
713
714 request = message.flow_mod()
715 request.match = match
716 request.buffer_id = 0xffffffff
717 act.port = ofp.OFPP_FLOOD
Rich Lanee30455b2013-01-03 16:24:44 -0800718 request.actions.add(act)
Dan Talayco4aa13122010-05-12 15:54:44 -0700719 act.port = ofp.OFPP_IN_PORT
Rich Lanee30455b2013-01-03 16:24:44 -0800720 request.actions.add(act)
Rich Lane9a003812012-10-04 17:17:59 -0700721 logging.info(request.show())
Dan Talayco4aa13122010-05-12 15:54:44 -0700722
Rich Lane9a003812012-10-04 17:17:59 -0700723 logging.info("Inserting flow")
Rich Lane5c3151c2013-01-03 17:15:41 -0800724 self.controller.message_send(request)
Dan Talayco0fc08bd2012-04-09 16:56:18 -0700725 self.assertEqual(do_barrier(self.controller), 0, "Barrier failed")
Dan Talayco4aa13122010-05-12 15:54:44 -0700726
Rich Lane9a003812012-10-04 17:17:59 -0700727 logging.info("Sending packet to dp port " + str(ingress_port))
Dan Talayco4aa13122010-05-12 15:54:44 -0700728 self.dataplane.send(ingress_port, str(pkt))
Rich Lane2014f9b2012-10-05 15:29:40 -0700729 receive_pkt_check(self.dataplane, pkt, of_ports, [], self)
Dan Talayco4aa13122010-05-12 15:54:44 -0700730
Rich Laneb90a1c42012-10-05 09:16:05 -0700731class All(base_tests.SimpleDataPlane):
Dan Talayco4aa13122010-05-12 15:54:44 -0700732 """
733 Send to OFPP_ALL port
734
735 Generate a packet
736 Generate and install a matching flow
737 Add action to forward to OFPP_ALL
738 Send the packet to ingress dataplane port
739 Verify the packet is received at all other ports
740 """
741 def runTest(self):
Rich Lane477f4812012-10-04 22:49:00 -0700742 of_ports = config["port_map"].keys()
Dan Talayco4aa13122010-05-12 15:54:44 -0700743 of_ports.sort()
744 self.assertTrue(len(of_ports) > 1, "Not enough ports for test")
745
746 pkt = simple_tcp_packet()
Ed Swierk99a74de2012-08-22 06:40:54 -0700747 match = packet_to_flow_match(self, pkt)
Dan Talayco4aa13122010-05-12 15:54:44 -0700748 match.wildcards &= ~ofp.OFPFW_IN_PORT
749 self.assertTrue(match is not None,
750 "Could not generate flow match from pkt")
751 act = action.action_output()
752
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700753 for ingress_port in of_ports:
Rich Lane32bf9482013-01-03 17:26:30 -0800754 delete_all_flows(self.controller)
Dan Talayco4aa13122010-05-12 15:54:44 -0700755
Rich Lane9a003812012-10-04 17:17:59 -0700756 logging.info("Ingress " + str(ingress_port) + " to all ports")
Dan Talayco4aa13122010-05-12 15:54:44 -0700757 match.in_port = ingress_port
758
759 request = message.flow_mod()
760 request.match = match
761 request.buffer_id = 0xffffffff
762 act.port = ofp.OFPP_ALL
Rich Lanee30455b2013-01-03 16:24:44 -0800763 request.actions.add(act)
Rich Lane9a003812012-10-04 17:17:59 -0700764 logging.info(request.show())
Dan Talayco4aa13122010-05-12 15:54:44 -0700765
Rich Lane9a003812012-10-04 17:17:59 -0700766 logging.info("Inserting flow")
Rich Lane5c3151c2013-01-03 17:15:41 -0800767 self.controller.message_send(request)
Dan Talayco0fc08bd2012-04-09 16:56:18 -0700768 self.assertEqual(do_barrier(self.controller), 0, "Barrier failed")
Dan Talayco4aa13122010-05-12 15:54:44 -0700769
Rich Lane9a003812012-10-04 17:17:59 -0700770 logging.info("Sending packet to dp port " + str(ingress_port))
Dan Talayco4aa13122010-05-12 15:54:44 -0700771 self.dataplane.send(ingress_port, str(pkt))
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700772 yes_ports = set(of_ports).difference([ingress_port])
773 receive_pkt_check(self.dataplane, pkt, yes_ports, [ingress_port],
Rich Lane2014f9b2012-10-05 15:29:40 -0700774 self)
Dan Talayco4aa13122010-05-12 15:54:44 -0700775
Rich Laneb90a1c42012-10-05 09:16:05 -0700776class AllPlusIngress(base_tests.SimpleDataPlane):
Dan Talayco4aa13122010-05-12 15:54:44 -0700777 """
778 Send to OFPP_ALL port and ingress port
779
780 Generate a packet
781 Generate and install a matching flow
782 Add action to forward to OFPP_ALL
783 Add action to forward to ingress port
784 Send the packet to ingress dataplane port
785 Verify the packet is received at all other ports
786 """
787 def runTest(self):
Rich Lane477f4812012-10-04 22:49:00 -0700788 of_ports = config["port_map"].keys()
Dan Talayco4aa13122010-05-12 15:54:44 -0700789 of_ports.sort()
790 self.assertTrue(len(of_ports) > 1, "Not enough ports for test")
791
792 pkt = simple_tcp_packet()
Ed Swierk99a74de2012-08-22 06:40:54 -0700793 match = packet_to_flow_match(self, pkt)
Dan Talayco4aa13122010-05-12 15:54:44 -0700794 match.wildcards &= ~ofp.OFPFW_IN_PORT
795 self.assertTrue(match is not None,
796 "Could not generate flow match from pkt")
797 act = action.action_output()
798
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700799 for ingress_port in of_ports:
Rich Lane32bf9482013-01-03 17:26:30 -0800800 delete_all_flows(self.controller)
Dan Talayco4aa13122010-05-12 15:54:44 -0700801
Rich Lane9a003812012-10-04 17:17:59 -0700802 logging.info("Ingress " + str(ingress_port) + " to all ports")
Dan Talayco4aa13122010-05-12 15:54:44 -0700803 match.in_port = ingress_port
804
805 request = message.flow_mod()
806 request.match = match
807 request.buffer_id = 0xffffffff
808 act.port = ofp.OFPP_ALL
Rich Lanee30455b2013-01-03 16:24:44 -0800809 request.actions.add(act)
Dan Talayco3be5b062010-05-12 15:46:21 -0700810 act.port = ofp.OFPP_IN_PORT
Rich Lanee30455b2013-01-03 16:24:44 -0800811 request.actions.add(act)
Rich Lane9a003812012-10-04 17:17:59 -0700812 logging.info(request.show())
Dan Talayco3be5b062010-05-12 15:46:21 -0700813
Rich Lane9a003812012-10-04 17:17:59 -0700814 logging.info("Inserting flow")
Rich Lane5c3151c2013-01-03 17:15:41 -0800815 self.controller.message_send(request)
Dan Talayco0fc08bd2012-04-09 16:56:18 -0700816 self.assertEqual(do_barrier(self.controller), 0, "Barrier failed")
Dan Talayco3be5b062010-05-12 15:46:21 -0700817
Rich Lane9a003812012-10-04 17:17:59 -0700818 logging.info("Sending packet to dp port " + str(ingress_port))
Dan Talayco3be5b062010-05-12 15:46:21 -0700819 self.dataplane.send(ingress_port, str(pkt))
Rich Lane2014f9b2012-10-05 15:29:40 -0700820 receive_pkt_check(self.dataplane, pkt, of_ports, [], self)
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700821
Rich Laneb90a1c42012-10-05 09:16:05 -0700822class FloodMinusPort(base_tests.SimpleDataPlane):
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700823 """
824 Config port with No_Flood and test Flood action
825
826 Generate a packet
827 Generate a matching flow
828 Add action to forward to OFPP_ALL
829 Set port to no-flood
830 Send the packet to ingress dataplane port
831 Verify the packet is received at all other ports except
832 the ingress port and the no_flood port
833 """
834 def runTest(self):
Rich Lane477f4812012-10-04 22:49:00 -0700835 of_ports = config["port_map"].keys()
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700836 of_ports.sort()
837 self.assertTrue(len(of_ports) > 2, "Not enough ports for test")
838
839 pkt = simple_tcp_packet()
Ed Swierk99a74de2012-08-22 06:40:54 -0700840 match = packet_to_flow_match(self, pkt)
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700841 match.wildcards &= ~ofp.OFPFW_IN_PORT
842 self.assertTrue(match is not None,
843 "Could not generate flow match from pkt")
844 act = action.action_output()
845
Rich Lane4b9e38c2012-12-06 16:33:20 -0800846 # Clear OFPPC_NO_FLOOD on each port
847 for of_port in of_ports:
848 rv = port_config_set(self.controller, of_port,
849 0, ofp.OFPPC_NO_FLOOD)
850 self.assertEqual(rv, 0, "Failed to set port config")
851
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700852 for idx in range(len(of_ports)):
Rich Lane32bf9482013-01-03 17:26:30 -0800853 delete_all_flows(self.controller)
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700854
855 ingress_port = of_ports[idx]
856 no_flood_idx = (idx + 1) % len(of_ports)
857 no_flood_port = of_ports[no_flood_idx]
858 rv = port_config_set(self.controller, no_flood_port,
Rich Lane9a003812012-10-04 17:17:59 -0700859 ofp.OFPPC_NO_FLOOD, ofp.OFPPC_NO_FLOOD)
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700860 self.assertEqual(rv, 0, "Failed to set port config")
861
862 match.in_port = ingress_port
863
864 request = message.flow_mod()
865 request.match = match
866 request.buffer_id = 0xffffffff
867 act.port = ofp.OFPP_FLOOD
Rich Lanee30455b2013-01-03 16:24:44 -0800868 request.actions.add(act)
Rich Lane9a003812012-10-04 17:17:59 -0700869 logging.info(request.show())
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700870
Rich Lane9a003812012-10-04 17:17:59 -0700871 logging.info("Inserting flow")
Rich Lane5c3151c2013-01-03 17:15:41 -0800872 self.controller.message_send(request)
Dan Talayco0fc08bd2012-04-09 16:56:18 -0700873 self.assertEqual(do_barrier(self.controller), 0, "Barrier failed")
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700874
Rich Lane9a003812012-10-04 17:17:59 -0700875 logging.info("Sending packet to dp port " + str(ingress_port))
876 logging.info("No flood port is " + str(no_flood_port))
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700877 self.dataplane.send(ingress_port, str(pkt))
878 no_ports = set([ingress_port, no_flood_port])
879 yes_ports = set(of_ports).difference(no_ports)
Rich Lane2014f9b2012-10-05 15:29:40 -0700880 receive_pkt_check(self.dataplane, pkt, yes_ports, no_ports, self)
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700881
882 # Turn no flood off again
883 rv = port_config_set(self.controller, no_flood_port,
Rich Lane9a003812012-10-04 17:17:59 -0700884 0, ofp.OFPPC_NO_FLOOD)
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700885 self.assertEqual(rv, 0, "Failed to reset port config")
Rich Lane4ecc1f42012-12-06 16:35:24 -0800886 self.assertEqual(do_barrier(self.controller), 0, "Barrier failed")
887
888 # Check that packets are now flooded to no_flood_port
889 logging.info("Sending packet to dp port " + str(ingress_port))
890 self.dataplane.send(ingress_port, str(pkt))
891 no_ports = set([ingress_port])
892 yes_ports = set(of_ports).difference(no_ports)
893 receive_pkt_check(self.dataplane, pkt, yes_ports, no_ports, self)
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700894
895 #@todo Should check no other packets received
896
Dan Talayco21381562010-07-17 00:34:47 -0700897
898
Dan Talayco551befa2010-07-15 17:05:32 -0700899################################################################
900
Rich Laneb90a1c42012-10-05 09:16:05 -0700901class BaseMatchCase(base_tests.SimpleDataPlane):
Dan Talayco551befa2010-07-15 17:05:32 -0700902 def setUp(self):
Rich Laneb90a1c42012-10-05 09:16:05 -0700903 base_tests.SimpleDataPlane.setUp(self)
Dan Talayco551befa2010-07-15 17:05:32 -0700904 def runTest(self):
Rich Lane9a003812012-10-04 17:17:59 -0700905 logging.info("BaseMatchCase")
Dan Talayco551befa2010-07-15 17:05:32 -0700906
907class ExactMatch(BaseMatchCase):
Tatsuya Yabe6a6f38a2010-05-22 23:48:04 -0700908 """
Dan Talayco551befa2010-07-15 17:05:32 -0700909 Exercise exact matching for all port pairs
Tatsuya Yabe6a6f38a2010-05-22 23:48:04 -0700910
911 Generate a packet
912 Generate and install a matching flow without wildcard mask
913 Add action to forward to a port
914 Send the packet to the port
915 Verify the packet is received at all other ports (one port at a time)
Tatsuya Yabe6a6f38a2010-05-22 23:48:04 -0700916 """
Tatsuya Yabe0718ad32010-05-24 15:22:10 -0700917
Tatsuya Yabe6a6f38a2010-05-22 23:48:04 -0700918 def runTest(self):
Rich Lane477f4812012-10-04 22:49:00 -0700919 flow_match_test(self, config["port_map"])
Tatsuya Yabe6a6f38a2010-05-22 23:48:04 -0700920
Dan Talayco551befa2010-07-15 17:05:32 -0700921class ExactMatchTagged(BaseMatchCase):
922 """
923 Exact match for all port pairs with tagged pkts
924 """
Tatsuya Yabe6a6f38a2010-05-22 23:48:04 -0700925
Dan Talayco551befa2010-07-15 17:05:32 -0700926 def runTest(self):
Rich Lane2014f9b2012-10-05 15:29:40 -0700927 vid = test_param_get('vid', default=TEST_VID_DEFAULT)
Rich Lane477f4812012-10-04 22:49:00 -0700928 flow_match_test(self, config["port_map"], dl_vlan=vid)
Tatsuya Yabe6a6f38a2010-05-22 23:48:04 -0700929
Dan Talayco551befa2010-07-15 17:05:32 -0700930class ExactMatchTaggedMany(BaseMatchCase):
931 """
932 ExactMatchTagged with many VLANS
933 """
Tatsuya Yabe6a6f38a2010-05-22 23:48:04 -0700934
Rich Laned1d9c282012-10-04 22:07:10 -0700935 priority = -1
936
Dan Talayco551befa2010-07-15 17:05:32 -0700937 def runTest(self):
Dan Talayco21381562010-07-17 00:34:47 -0700938 for vid in range(2,100,10):
Rich Lane477f4812012-10-04 22:49:00 -0700939 flow_match_test(self, config["port_map"], dl_vlan=vid, max_test=5)
Dan Talayco551befa2010-07-15 17:05:32 -0700940 for vid in range(100,4000,389):
Rich Lane477f4812012-10-04 22:49:00 -0700941 flow_match_test(self, config["port_map"], dl_vlan=vid, max_test=5)
942 flow_match_test(self, config["port_map"], dl_vlan=4094, max_test=5)
Tatsuya Yabecdf575e2010-05-25 16:56:38 -0700943
Jeffrey Townsend2a300e42012-03-28 17:24:02 -0700944class SingleWildcardMatchPriority(BaseMatchCase):
Jeffrey Townsend50c82462012-03-28 18:26:14 -0700945 """
946 SingleWildcardMatchPriority
947 """
Jeffrey Townsend2a300e42012-03-28 17:24:02 -0700948
Jeffrey Townsend50c82462012-03-28 18:26:14 -0700949 def _Init(self):
Jeffrey Townsend2a300e42012-03-28 17:24:02 -0700950 self.pkt = simple_tcp_packet()
951 self.flowMsgs = {}
952
Jeffrey Townsend50c82462012-03-28 18:26:14 -0700953 def _ClearTable(self):
Rich Lane32bf9482013-01-03 17:26:30 -0800954 delete_all_flows(self.controller)
Dan Talayco0fc08bd2012-04-09 16:56:18 -0700955 self.assertEqual(do_barrier(self.controller), 0, "Barrier failed")
Jeffrey Townsend50c82462012-03-28 18:26:14 -0700956
957 def runTest(self):
958
959 self._Init()
Rich Lane477f4812012-10-04 22:49:00 -0700960 of_ports = config["port_map"].keys()
Jeffrey Townsend2a300e42012-03-28 17:24:02 -0700961 of_ports.sort()
962
963 # Delete the initial flow table
Jeffrey Townsend50c82462012-03-28 18:26:14 -0700964 self._ClearTable()
Jeffrey Townsend2a300e42012-03-28 17:24:02 -0700965
966 # Run several combinations, each at lower priority settings.
967 # At the end of each call to runPrioFlows(), the table should
968 # be empty. If its not, we'll catch it as the priorities decreases
969 portA = of_ports[0]
970 portB = of_ports[1]
971 portC = of_ports[2]
972
973 # TODO -- these priority numbers should be validated somehow?
974 self.runPrioFlows(portA, portB, portC, 1000, 999)
975 self.runPrioFlows(portB, portC, portA, 998, 997)
976 self.runPrioFlows(portC, portA, portB, 996, 995)
977 self.runPrioFlows(portA, portC, portB, 994, 993)
978
979
Jeffrey Townsend50c82462012-03-28 18:26:14 -0700980
981 def runPrioFlows(self, portA, portB, portC, prioHigher, prioLower,
982 clearTable=False):
Jeffrey Townsend2a300e42012-03-28 17:24:02 -0700983
Jeffrey Townsend50c82462012-03-28 18:26:14 -0700984 if clearTable:
985 self._ClearTable()
Jeffrey Townsend2a300e42012-03-28 17:24:02 -0700986
987 # Sanity check flow at lower priority from pA to pB
Rich Lane9a003812012-10-04 17:17:59 -0700988 logging.info("runPrioFlows(pA=%d,pB=%d,pC=%d,ph=%d,pl=%d"
Jeffrey Townsend2a300e42012-03-28 17:24:02 -0700989 % (portA, portB, portC, prioHigher, prioLower))
990
Jeffrey Townsend2a300e42012-03-28 17:24:02 -0700991 # Sanity check flow at lower priority from pA to pC
992 self.installFlow(prioLower, portA, portC)
993 self.verifyFlow(portA, portC)
994 self.removeFlow(prioLower)
995
996 # Install and verify pA->pB @ prioLower
997 self.installFlow(prioLower, portA, portB)
998 self.verifyFlow(portA, portB)
999
1000 # Install and verify pA->pC @ prioHigher, should override pA->pB
1001 self.installFlow(prioHigher, portA, portC)
1002 self.verifyFlow(portA, portC)
1003 # remove pA->pC
1004 self.removeFlow(prioHigher)
Jeffrey Townsend2a300e42012-03-28 17:24:02 -07001005 # Old flow pA -> pB @ prioLower should still be active
1006 self.verifyFlow(portA, portB)
1007 self.removeFlow(prioLower)
1008
1009 # Table should be empty at this point, leave it alone as
1010 # an assumption for future test runs
1011
1012
1013
Ed Swierk99a74de2012-08-22 06:40:54 -07001014 def installFlow(self, prio, inp, egp,
Jeffrey Townsend8364b162012-04-12 13:45:40 -07001015 wildcards=ofp.OFPFW_DL_SRC):
Ed Swierk99a74de2012-08-22 06:40:54 -07001016 wildcards |= required_wildcards(self)
Jeffrey Townsend2a300e42012-03-28 17:24:02 -07001017 request = flow_msg_create(self, self.pkt, ing_port=inp,
Jeffrey Townsend8364b162012-04-12 13:45:40 -07001018 wildcards=wildcards,
Jeffrey Townsend2a300e42012-03-28 17:24:02 -07001019 egr_ports=egp)
1020 request.priority = prio
Rich Lane9a003812012-10-04 17:17:59 -07001021 logging.debug("Install flow with priority " + str(prio))
Jeffrey Townsend50c82462012-03-28 18:26:14 -07001022 flow_msg_install(self, request, clear_table_override=False)
Jeffrey Townsend2a300e42012-03-28 17:24:02 -07001023 self.flowMsgs[prio] = request
1024
1025 def removeFlow(self, prio):
1026 if self.flowMsgs.has_key(prio):
1027 msg = self.flowMsgs[prio]
1028 msg.command = ofp.OFPFC_DELETE_STRICT
1029 # This *must* be set for DELETE
1030 msg.out_port = ofp.OFPP_NONE
Rich Lane9a003812012-10-04 17:17:59 -07001031 logging.debug("Remove flow with priority " + str(prio))
Jeffrey Townsend2a300e42012-03-28 17:24:02 -07001032 self.controller.message_send(msg)
Dan Talayco0fc08bd2012-04-09 16:56:18 -07001033 self.assertEqual(do_barrier(self.controller), 0, "Barrier failed")
Jeffrey Townsend50c82462012-03-28 18:26:14 -07001034 else:
1035 raise Exception("Not initialized")
Jeffrey Townsend2a300e42012-03-28 17:24:02 -07001036
1037
Jeffrey Townsend8364b162012-04-12 13:45:40 -07001038 def verifyFlow(self, inp, egp, pkt=None):
1039 if pkt == None:
1040 pkt = self.pkt
1041
Rich Lane9a003812012-10-04 17:17:59 -07001042 logging.info("Pkt match test: " + str(inp) + " to " + str(egp))
1043 logging.debug("Send packet: " + str(inp) + " to " + str(egp))
Jeffrey Townsend8364b162012-04-12 13:45:40 -07001044 self.dataplane.send(inp, str(pkt))
1045 receive_pkt_verify(self, egp, pkt, inp)
Jeffrey Townsend2a300e42012-03-28 17:24:02 -07001046
1047
1048
Jeffrey Townsend50c82462012-03-28 18:26:14 -07001049class SingleWildcardMatchPriorityInsertModifyDelete(SingleWildcardMatchPriority):
1050
1051 def runTest(self):
1052
1053 self._Init()
1054
Rich Lane477f4812012-10-04 22:49:00 -07001055 of_ports = config["port_map"].keys()
Jeffrey Townsend50c82462012-03-28 18:26:14 -07001056 of_ports.sort()
1057
1058 # Install an entry from 0 -> 1 @ prio 1000
1059 self._ClearTable()
1060 self.installFlow(1000, of_ports[0], of_ports[1])
1061 self.verifyFlow(of_ports[0], of_ports[1])
1062 self.installFlow(1000, of_ports[1], of_ports[0])
1063 self.verifyFlow(of_ports[1], of_ports[0])
1064 self.installFlow(1001, of_ports[0], of_ports[1])
1065 self.verifyFlow(of_ports[0], of_ports[1])
1066 self.installFlow(1001, of_ports[1], of_ports[0])
1067 self.verifyFlow(of_ports[1], of_ports[0])
1068 self.removeFlow(1001)
1069 self.verifyFlow(of_ports[0], of_ports[1])
1070 self.removeFlow(1000)
1071
1072
1073
Jeffrey Townsend8364b162012-04-12 13:45:40 -07001074class WildcardPriority(SingleWildcardMatchPriority):
Ken Chiang38d7a152012-05-24 15:33:50 -07001075 """
1076 1. Add wildcard flow, verify packet received.
Rich Lane0a78fbd2012-12-31 16:25:04 -08001077 2. Add wildcard flow with higher priority, verify packet received
Ken Chiang38d7a152012-05-24 15:33:50 -07001078 on port specified by this flow.
Rich Lane0a78fbd2012-12-31 16:25:04 -08001079 3. Add wildcard flow with lower priority, verify packet received
Rich Laneb8392082012-11-21 15:52:54 -08001080 on port specified by the highest priority flow.
Ken Chiang38d7a152012-05-24 15:33:50 -07001081 """
Jeffrey Townsend8364b162012-04-12 13:45:40 -07001082
1083 def runTest(self):
Jeffrey Townsend50c82462012-03-28 18:26:14 -07001084
Jeffrey Townsend8364b162012-04-12 13:45:40 -07001085 self._Init()
1086
Rich Lane477f4812012-10-04 22:49:00 -07001087 of_ports = config["port_map"].keys()
Jeffrey Townsend8364b162012-04-12 13:45:40 -07001088 of_ports.sort()
1089
1090 self._ClearTable()
Ken Chiang38d7a152012-05-24 15:33:50 -07001091
1092 # Install a flow with wildcards
1093 self.installFlow(999, of_ports[0], of_ports[1],
1094 wildcards=ofp.OFPFW_DL_DST)
Jeffrey Townsend8364b162012-04-12 13:45:40 -07001095 self.verifyFlow(of_ports[0], of_ports[1])
Rich Lane0a78fbd2012-12-31 16:25:04 -08001096 # Install a flow with wildcards with higher priority
1097 self.installFlow(1000, of_ports[0], of_ports[2],
1098 wildcards=ofp.OFPFW_DL_DST)
Jeffrey Townsend8364b162012-04-12 13:45:40 -07001099 self.verifyFlow(of_ports[0], of_ports[2])
Rich Lane0a78fbd2012-12-31 16:25:04 -08001100 # Install a flow with wildcards with lower priority
Rich Laneb8392082012-11-21 15:52:54 -08001101 self.installFlow(999, of_ports[0], of_ports[1],
1102 wildcards=ofp.OFPFW_DL_SRC)
Rich Lane0a78fbd2012-12-31 16:25:04 -08001103 self.verifyFlow(of_ports[0], of_ports[2])
Jeffrey Townsend8364b162012-04-12 13:45:40 -07001104
1105
Ken Chiang3978f242012-06-13 14:14:09 -07001106class WildcardPriorityWithDelete(SingleWildcardMatchPriority):
Ken Chiang38d7a152012-05-24 15:33:50 -07001107 """
Rich Lane0a78fbd2012-12-31 16:25:04 -08001108 1. Add wildcard match flow, verify packet received.
Ken Chiang38d7a152012-05-24 15:33:50 -07001109 2. Add wildcard flow with higher priority, verify packet received on port
1110 specified by this flow.
Rich Lane0a78fbd2012-12-31 16:25:04 -08001111 3. Add wildcard flow with even higher priority, verify packet received
Ken Chiang38d7a152012-05-24 15:33:50 -07001112 on port specified by this flow.
1113 4. Delete lowest priority flow, verify packet received on port specified
1114 by highest priority flow.
1115 5. Delete highest priority flow, verify packet received on port specified
1116 by remaining flow.
1117 """
1118
1119 def runTest(self):
1120
1121 self._Init()
1122
Rich Lane477f4812012-10-04 22:49:00 -07001123 of_ports = config["port_map"].keys()
Ken Chiang38d7a152012-05-24 15:33:50 -07001124 of_ports.sort()
1125
1126 self._ClearTable()
1127
Rich Lane0a78fbd2012-12-31 16:25:04 -08001128 # Install a flow with wildcards
1129 self.installFlow(250, of_ports[0], of_ports[1],
1130 wildcards=ofp.OFPFW_DL_DST)
Ken Chiang38d7a152012-05-24 15:33:50 -07001131 self.verifyFlow(of_ports[0], of_ports[1])
1132 # Install a flow with wildcards of higher priority
1133 self.installFlow(1250, of_ports[0], of_ports[2],
1134 wildcards=ofp.OFPFW_DL_DST)
1135 self.verifyFlow(of_ports[0], of_ports[2])
Rich Lane0a78fbd2012-12-31 16:25:04 -08001136 # Install a flow with wildcards with even higher priority
1137 self.installFlow(2001, of_ports[0], of_ports[3],
1138 wildcards=ofp.OFPFW_DL_DST)
Ken Chiang38d7a152012-05-24 15:33:50 -07001139 self.verifyFlow(of_ports[0], of_ports[3])
1140 # Delete lowest priority flow
1141 self.removeFlow(250)
1142 self.verifyFlow(of_ports[0], of_ports[3])
1143 # Delete highest priority flow
1144 self.removeFlow(2001)
1145 self.verifyFlow(of_ports[0], of_ports[2])
1146
Jeffrey Townsend8364b162012-04-12 13:45:40 -07001147
Dan Talayco551befa2010-07-15 17:05:32 -07001148class SingleWildcardMatch(BaseMatchCase):
Tatsuya Yabe6a6f38a2010-05-22 23:48:04 -07001149 """
1150 Exercise wildcard matching for all ports
1151
1152 Generate a packet
1153 Generate and install a matching flow with wildcard mask
1154 Add action to forward to a port
1155 Send the packet to the port
1156 Verify the packet is received at all other ports (one port at a time)
Tatsuya Yabe0718ad32010-05-24 15:22:10 -07001157 Verify flow_expiration message is correct when command option is set
Tatsuya Yabe6a6f38a2010-05-22 23:48:04 -07001158 """
Tatsuya Yabe0718ad32010-05-24 15:22:10 -07001159 def runTest(self):
Rich Lane2014f9b2012-10-05 15:29:40 -07001160 vid = test_param_get('vid', default=TEST_VID_DEFAULT)
Dan Talayco551befa2010-07-15 17:05:32 -07001161 for wc in WILDCARD_VALUES:
Ed Swierk99a74de2012-08-22 06:40:54 -07001162 wc |= required_wildcards(self)
Dan Talayco4431d542012-03-21 16:42:16 -07001163 if wc & ofp.OFPFW_DL_VLAN:
Ken Chiang5be06dd2012-04-03 10:03:50 -07001164 # Set nonzero VLAN id to avoid sending priority-tagged packet
1165 dl_vlan = vid
Dan Talayco4431d542012-03-21 16:42:16 -07001166 else:
1167 dl_vlan = -1
Rich Lane477f4812012-10-04 22:49:00 -07001168 flow_match_test(self, config["port_map"], wildcards=wc,
Dan Talayco4431d542012-03-21 16:42:16 -07001169 dl_vlan=dl_vlan, max_test=10)
Tatsuya Yabe4fad7e32010-05-24 15:24:50 -07001170
Dan Talayco551befa2010-07-15 17:05:32 -07001171class SingleWildcardMatchTagged(BaseMatchCase):
1172 """
1173 SingleWildcardMatch with tagged packets
1174 """
1175 def runTest(self):
Rich Lane2014f9b2012-10-05 15:29:40 -07001176 vid = test_param_get('vid', default=TEST_VID_DEFAULT)
Dan Talayco551befa2010-07-15 17:05:32 -07001177 for wc in WILDCARD_VALUES:
Ed Swierk99a74de2012-08-22 06:40:54 -07001178 wc |= required_wildcards(self)
Rich Lane477f4812012-10-04 22:49:00 -07001179 flow_match_test(self, config["port_map"], wildcards=wc, dl_vlan=vid,
Dan Talayco551befa2010-07-15 17:05:32 -07001180 max_test=10)
1181
1182class AllExceptOneWildcardMatch(BaseMatchCase):
Tatsuya Yabe4fad7e32010-05-24 15:24:50 -07001183 """
Dan Talayco80b54ed2010-07-13 09:48:35 -07001184 Match exactly one field
Tatsuya Yabe4fad7e32010-05-24 15:24:50 -07001185
1186 Generate a packet
1187 Generate and install a matching flow with wildcard all except one filed
1188 Add action to forward to a port
1189 Send the packet to the port
1190 Verify the packet is received at all other ports (one port at a time)
1191 Verify flow_expiration message is correct when command option is set
1192 """
1193 def runTest(self):
Rich Lane2014f9b2012-10-05 15:29:40 -07001194 vid = test_param_get('vid', default=TEST_VID_DEFAULT)
Dan Talayco488fbc52012-04-09 16:30:41 -07001195 for all_exp_one_wildcard in NO_WILDCARD_VALUES:
Ed Swierk99a74de2012-08-22 06:40:54 -07001196 all_exp_one_wildcard |= required_wildcards(self)
Dan Talayco4431d542012-03-21 16:42:16 -07001197 if all_exp_one_wildcard & ofp.OFPFW_DL_VLAN:
Ken Chiang5be06dd2012-04-03 10:03:50 -07001198 # Set nonzero VLAN id to avoid sending priority-tagged packet
1199 dl_vlan = vid
Dan Talayco4431d542012-03-21 16:42:16 -07001200 else:
1201 dl_vlan = -1
Rich Lane477f4812012-10-04 22:49:00 -07001202 flow_match_test(self, config["port_map"], wildcards=all_exp_one_wildcard,
Dan Talayco4431d542012-03-21 16:42:16 -07001203 dl_vlan=dl_vlan)
Tatsuya Yabee30ebe22010-05-25 09:30:49 -07001204
Dan Talayco551befa2010-07-15 17:05:32 -07001205class AllExceptOneWildcardMatchTagged(BaseMatchCase):
1206 """
1207 Match one field with tagged packets
1208 """
1209 def runTest(self):
Rich Lane2014f9b2012-10-05 15:29:40 -07001210 vid = test_param_get('vid', default=TEST_VID_DEFAULT)
Dan Talayco488fbc52012-04-09 16:30:41 -07001211 for all_exp_one_wildcard in NO_WILDCARD_VALUES:
Ed Swierk99a74de2012-08-22 06:40:54 -07001212 all_exp_one_wildcard |= required_wildcards(self)
Rich Lane477f4812012-10-04 22:49:00 -07001213 flow_match_test(self, config["port_map"], wildcards=all_exp_one_wildcard,
Dan Talayco21381562010-07-17 00:34:47 -07001214 dl_vlan=vid)
Dan Talayco551befa2010-07-15 17:05:32 -07001215
1216class AllWildcardMatch(BaseMatchCase):
Tatsuya Yabee30ebe22010-05-25 09:30:49 -07001217 """
1218 Create Wildcard-all flow and exercise for all ports
1219
1220 Generate a packet
1221 Generate and install a matching flow with wildcard-all
1222 Add action to forward to a port
1223 Send the packet to the port
1224 Verify the packet is received at all other ports (one port at a time)
1225 Verify flow_expiration message is correct when command option is set
1226 """
1227 def runTest(self):
Rich Lane477f4812012-10-04 22:49:00 -07001228 flow_match_test(self, config["port_map"], wildcards=ofp.OFPFW_ALL)
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -07001229
Dan Talayco551befa2010-07-15 17:05:32 -07001230class AllWildcardMatchTagged(BaseMatchCase):
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -07001231 """
Dan Talayco551befa2010-07-15 17:05:32 -07001232 AllWildcardMatch with tagged packets
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -07001233 """
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -07001234 def runTest(self):
Rich Lane2014f9b2012-10-05 15:29:40 -07001235 vid = test_param_get('vid', default=TEST_VID_DEFAULT)
Rich Lane477f4812012-10-04 22:49:00 -07001236 flow_match_test(self, config["port_map"], wildcards=ofp.OFPFW_ALL,
Dan Talayco21381562010-07-17 00:34:47 -07001237 dl_vlan=vid)
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -07001238
Dan Talaycoba3745c2010-07-21 21:51:08 -07001239
Dan Talayco551befa2010-07-15 17:05:32 -07001240class AddVLANTag(BaseMatchCase):
1241 """
1242 Add a VLAN tag to an untagged packet
1243 """
1244 def runTest(self):
1245 new_vid = 2
Ed Swierkc7193a22012-08-22 06:51:02 -07001246 sup_acts = self.supported_actions
Dan Talayco551befa2010-07-15 17:05:32 -07001247 if not(sup_acts & 1<<ofp.OFPAT_SET_VLAN_VID):
Dan Talaycoba3745c2010-07-21 21:51:08 -07001248 skip_message_emit(self, "Add VLAN tag test")
Dan Talaycof36f1082010-07-13 13:57:17 -07001249 return
Tatsuya Yabef5ffb972010-05-26 15:36:33 -07001250
Dan Talayco551befa2010-07-15 17:05:32 -07001251 len = 100
1252 len_w_vid = 104
1253 pkt = simple_tcp_packet(pktlen=len)
1254 exp_pkt = simple_tcp_packet(pktlen=len_w_vid, dl_vlan_enable=True,
1255 dl_vlan=new_vid)
1256 vid_act = action.action_set_vlan_vid()
1257 vid_act.vlan_vid = new_vid
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -07001258
Rich Lane477f4812012-10-04 22:49:00 -07001259 flow_match_test(self, config["port_map"], pkt=pkt,
Dan Talayco551befa2010-07-15 17:05:32 -07001260 exp_pkt=exp_pkt, action_list=[vid_act])
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -07001261
Rich Laneb90a1c42012-10-05 09:16:05 -07001262class PacketOnly(base_tests.DataPlaneOnly):
Dan Talayco551befa2010-07-15 17:05:32 -07001263 """
1264 Just send a packet thru the switch
1265 """
Rich Laned1d9c282012-10-04 22:07:10 -07001266
1267 priority = -1
1268
Dan Talayco551befa2010-07-15 17:05:32 -07001269 def runTest(self):
1270 pkt = simple_tcp_packet()
Rich Lane477f4812012-10-04 22:49:00 -07001271 of_ports = config["port_map"].keys()
Dan Talayco551befa2010-07-15 17:05:32 -07001272 of_ports.sort()
1273 ing_port = of_ports[0]
Rich Lane9a003812012-10-04 17:17:59 -07001274 logging.info("Sending packet to " + str(ing_port))
1275 logging.debug("Data: " + str(pkt).encode('hex'))
Dan Talayco551befa2010-07-15 17:05:32 -07001276 self.dataplane.send(ing_port, str(pkt))
Tatsuya Yabee6cae8b2010-05-25 18:20:04 -07001277
Rich Laneb90a1c42012-10-05 09:16:05 -07001278class PacketOnlyTagged(base_tests.DataPlaneOnly):
Dan Talayco551befa2010-07-15 17:05:32 -07001279 """
1280 Just send a packet thru the switch
1281 """
Rich Laned1d9c282012-10-04 22:07:10 -07001282
1283 priority = -1
1284
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 Lane22e74c12012-11-12 15:06:06 -08001691class ModifyAll(BaseMatchCase):
1692 """
1693 Modify all supported fields and output to a port
1694 """
1695 def runTest(self):
1696 sup_acts = self.supported_actions
1697
1698 sup_map = {
1699 "dl_dst" : ofp.OFPAT_SET_DL_DST,
1700 "dl_src" : ofp.OFPAT_SET_DL_SRC,
1701 "dl_vlan_enable" : ofp.OFPAT_SET_VLAN_VID,
1702 "dl_vlan" : ofp.OFPAT_SET_VLAN_VID,
1703 "dl_vlan_pcp" : ofp.OFPAT_SET_VLAN_PCP,
1704 "ip_src" : ofp.OFPAT_SET_NW_SRC,
1705 "ip_dst" : ofp.OFPAT_SET_NW_DST,
1706 "ip_tos" : ofp.OFPAT_SET_NW_TOS,
1707 "tcp_sport" : ofp.OFPAT_SET_TP_SRC,
1708 "tcp_dport" : ofp.OFPAT_SET_TP_DST,
1709 }
1710
1711 mod_fields = [field for (field, bit) in sup_map.items() if (sup_acts & 1 << bit)]
1712 random.shuffle(mod_fields)
1713 start_field_vals = { "dl_vlan_enable" : True }
1714 mod_field_vals = { "dl_vlan_enable" : True }
1715 logging.info("modifying fields: %s" % repr(mod_fields))
1716
1717 (pkt, exp_pkt, acts) = pkt_action_setup(self,
1718 mod_fields=mod_fields,
1719 start_field_vals=start_field_vals,
1720 mod_field_vals=mod_field_vals,
1721 check_test_params=True)
1722 flow_match_test(self, config["port_map"], pkt=pkt, exp_pkt=exp_pkt,
1723 action_list=acts, max_test=2)
1724
Dan Talaycofa6454f2012-04-05 10:04:13 -07001725class FlowToggle(BaseMatchCase):
1726 """
1727 Add flows to the table and modify them repeatedly
Dan Talaycof7c41312012-07-23 12:53:19 -07001728
1729 This is done by using only "add" flow messages. Since the check overlap
1730 flag is not set, the switch is supposed to modify the existing flow if
1731 the match already exists.
1732
1733 Would probably be better to exercise more of the flow modify commands
1734 (add, modify, delete +/- strict).
Dan Talaycofa6454f2012-04-05 10:04:13 -07001735 """
1736 def runTest(self):
Rich Lane2014f9b2012-10-05 15:29:40 -07001737 flow_count = test_param_get('ft_flow_count', default=20)
1738 iter_count = test_param_get('ft_iter_count', default=10)
Dan Talaycofa6454f2012-04-05 10:04:13 -07001739
Rich Lane9a003812012-10-04 17:17:59 -07001740 logging.info("Running flow toggle with %d flows, %d iterations" %
Dan Talaycofa6454f2012-04-05 10:04:13 -07001741 (flow_count, iter_count))
1742 acts = []
1743 acts.append(action.action_output())
1744 acts.append(action.action_output())
1745
Rich Lane477f4812012-10-04 22:49:00 -07001746 of_ports = config["port_map"].keys()
Dan Talaycofa6454f2012-04-05 10:04:13 -07001747 if len(of_ports) < 3:
1748 self.assertTrue(False, "Too few ports for test")
1749
1750 for idx in range(2):
1751 acts[idx].port = of_ports[idx]
1752
1753 flows = []
1754 flows.append([])
1755 flows.append([])
1756
Ed Swierk99a74de2012-08-22 06:40:54 -07001757 wildcards = (required_wildcards(self) | ofp.OFPFW_DL_SRC |
1758 ofp.OFPFW_DL_DST)
Dan Talaycofa6454f2012-04-05 10:04:13 -07001759 # Create up the flows in an array
1760 for toggle in range(2):
1761 for f_idx in range(flow_count):
1762 pkt = simple_tcp_packet(tcp_sport=f_idx)
1763 msg = message.flow_mod()
Ed Swierk99a74de2012-08-22 06:40:54 -07001764 match = packet_to_flow_match(self, pkt)
Shudong Zhou031373c2012-07-19 17:37:42 -07001765 match.in_port = of_ports[2]
Dan Talayco50be7672012-04-05 11:38:08 -07001766 match.wildcards = wildcards
Dan Talaycofa6454f2012-04-05 10:04:13 -07001767 msg.match = match
1768 msg.buffer_id = 0xffffffff
Dan Talaycof7c41312012-07-23 12:53:19 -07001769 msg.command = ofp.OFPFC_ADD
Dan Talaycofa6454f2012-04-05 10:04:13 -07001770 msg.actions.add(acts[toggle])
1771 flows[toggle].append(msg)
Dan Talayco50be7672012-04-05 11:38:08 -07001772
1773 # Show two sample flows
Rich Lane9a003812012-10-04 17:17:59 -07001774 logging.debug(flows[0][0].show())
1775 logging.debug(flows[1][0].show())
Dan Talayco50be7672012-04-05 11:38:08 -07001776
Dan Talaycofa6454f2012-04-05 10:04:13 -07001777 # Install the first set of flows
1778 for f_idx in range(flow_count):
Rich Lane5c3151c2013-01-03 17:15:41 -08001779 self.controller.message_send(flows[0][f_idx])
Dan Talayco0fc08bd2012-04-09 16:56:18 -07001780 self.assertEqual(do_barrier(self.controller), 0, "Barrier failed")
Dan Talaycofa6454f2012-04-05 10:04:13 -07001781
Rich Lane9a003812012-10-04 17:17:59 -07001782 logging.info("Installed %d flows" % flow_count)
Dan Talaycofa6454f2012-04-05 10:04:13 -07001783
1784 # Repeatedly modify all the flows back and forth
1785 updates = 0
1786 # Report status about 5 times
1787 mod_val = (iter_count / 4) + 1
Dan Talaycoabbfdbb2012-04-05 10:29:26 -07001788 start = time.time()
1789 for iter_idx in range(iter_count):
1790 if not iter_idx % mod_val:
Rich Lane9a003812012-10-04 17:17:59 -07001791 logging.info("Flow Toggle: iter %d of %d. " %
Dan Talaycoabbfdbb2012-04-05 10:29:26 -07001792 (iter_idx, iter_count) +
1793 "%d updates in %d secs" %
1794 (updates, time.time() - start))
Dan Talaycofa6454f2012-04-05 10:04:13 -07001795 for toggle in range(2):
1796 t_idx = 1 - toggle
1797 for f_idx in range(flow_count):
Rich Lane5c3151c2013-01-03 17:15:41 -08001798 self.controller.message_send(flows[t_idx][f_idx])
Dan Talaycofa6454f2012-04-05 10:04:13 -07001799 updates += 1
Dan Talayco0fc08bd2012-04-09 16:56:18 -07001800 self.assertEqual(do_barrier(self.controller), 0,
1801 "Barrier failed")
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
1832class IterCases(BaseMatchCase):
Dan Talaycofa6454f2012-04-05 10:04:13 -07001833 """
1834 Iterate over a bunch of test cases
1835
1836 The cases come from the list above
1837 """
1838
Rich Laned1d9c282012-10-04 22:07:10 -07001839 priority = -1
1840
Dan Talayco8a64e332012-03-28 14:53:20 -07001841 def runTest(self):
Rich Lane2014f9b2012-10-05 15:29:40 -07001842 count = test_param_get('iter_count', default=10)
Dan Talayco8a64e332012-03-28 14:53:20 -07001843 tests_done = 0
Rich Lane9a003812012-10-04 17:17:59 -07001844 logging.info("Running iteration test " + str(count) + " times")
Dan Talayco8a64e332012-03-28 14:53:20 -07001845 start = time.time()
1846 last = start
1847 for idx in range(count):
Rich Lane9a003812012-10-04 17:17:59 -07001848 logging.info("Iteration " + str(idx + 1))
Dan Talayco8a64e332012-03-28 14:53:20 -07001849 for cls in iter_classes:
1850 test = cls()
1851 test.inheritSetup(self)
1852 test.runTest()
1853 tests_done += 1
Dan Talaycofa6454f2012-04-05 10:04:13 -07001854 # Report update about every minute, between tests
Dan Talayco8a64e332012-03-28 14:53:20 -07001855 if time.time() - last > 60:
1856 last = time.time()
Rich Lane9a003812012-10-04 17:17:59 -07001857 logging.info(
Dan Talaycofa6454f2012-04-05 10:04:13 -07001858 "IterCases: Iter %d of %d; Ran %d tests in %d " %
1859 (idx, count, tests_done, last - start) +
1860 "seconds so far")
Dan Talayco8a64e332012-03-28 14:53:20 -07001861 stats = all_stats_get(self)
1862 last = time.time()
Rich Lane9a003812012-10-04 17:17:59 -07001863 logging.info("\nIterCases ran %d tests in %d seconds." %
Dan Talayco8a64e332012-03-28 14:53:20 -07001864 (tests_done, last - start))
Rich Lane9a003812012-10-04 17:17:59 -07001865 logging.info(" flows: %d. packets: %d. bytes: %d" %
Dan Talayco8a64e332012-03-28 14:53:20 -07001866 (stats["flows"], stats["packets"], stats["bytes"]))
Rich Lane9a003812012-10-04 17:17:59 -07001867 logging.info(" active: %d. lookups: %d. matched %d." %
Dan Talayco8a64e332012-03-28 14:53:20 -07001868 (stats["active"], stats["lookups"], stats["matched"]))
1869
Dan Talayco4b2bee62010-07-20 14:10:05 -07001870#@todo Need to implement tagged versions of the above tests
1871#
1872#@todo Implement a test case that strips tag 2, adds tag 3
1873# and modifies tag 4 to tag 5. Then verify (in addition) that
1874# tag 6 does not get modified.
1875
1876class 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 Laned1d9c282012-10-04 22:07:10 -07001899 priority = -1
Rich Lane8d6ab272012-09-23 18:06:20 -07001900
Rich Laneb90a1c42012-10-05 09:16:05 -07001901class MatchEach(base_tests.SimpleDataPlane):
Rich Lane8d6ab272012-09-23 18:06:20 -07001902 """
1903 Check that each match field is actually matched on.
1904 Installs two flows that differ in one field. The flow that should not
1905 match has a higher priority, so if that field is ignored during matching
1906 the packet will be sent out the wrong port.
1907
1908 TODO test UDP, ARP, ICMP, etc.
1909 """
1910 def runTest(self):
Rich Lane477f4812012-10-04 22:49:00 -07001911 of_ports = config["port_map"].keys()
Rich Lane8d6ab272012-09-23 18:06:20 -07001912 of_ports.sort()
1913 self.assertTrue(len(of_ports) > 1, "Not enough ports for test")
1914
Rich Lane9a003812012-10-04 17:17:59 -07001915 delete_all_flows(self.controller)
Rich Lane8d6ab272012-09-23 18:06:20 -07001916
Ed Swierk7040a8d2012-12-11 16:30:13 -08001917 pkt = simple_tcp_packet(dl_vlan_enable=True, dl_vlan=2)
Rich Lane8d6ab272012-09-23 18:06:20 -07001918 ingress_port = of_ports[0]
1919 egress_port = of_ports[1]
1920
1921 def testField(field, mask):
Rich Lane9a003812012-10-04 17:17:59 -07001922 logging.info("Testing field %s" % field)
Rich Lane8d6ab272012-09-23 18:06:20 -07001923
1924 def addFlow(matching, priority, output_port):
1925 match = packet_to_flow_match(self, pkt)
1926 self.assertTrue(match is not None, "Could not generate flow match from pkt")
1927 match.wildcards &= ~ofp.OFPFW_IN_PORT
1928 match.in_port = ingress_port
1929 if not matching:
1930 # Make sure flow doesn't match
1931 orig = getattr(match, field)
1932 if isinstance(orig, list):
1933 new = map(lambda a: ~a[0] & a[1], zip(orig, mask))
1934 else:
1935 new = ~orig & mask
1936 setattr(match, field, new)
1937 request = message.flow_mod()
1938 request.match = match
1939 request.buffer_id = 0xffffffff
1940 request.priority = priority
1941 act = action.action_output()
1942 act.port = output_port
Rich Lanee30455b2013-01-03 16:24:44 -08001943 request.actions.add(act)
Rich Lane9a003812012-10-04 17:17:59 -07001944 logging.info("Inserting flow")
Rich Lane8d6ab272012-09-23 18:06:20 -07001945 self.controller.message_send(request)
1946
1947 # This flow should match.
1948 addFlow(matching=True, priority=0, output_port=egress_port)
1949 # This flow should not match, but it has a higher priority.
1950 addFlow(matching=False, priority=1, output_port=ofp.OFPP_IN_PORT)
1951
1952 self.assertEqual(do_barrier(self.controller), 0, "Barrier failed")
1953
Rich Lane9a003812012-10-04 17:17:59 -07001954 logging.info("Sending packet to dp port " + str(ingress_port))
Rich Lane8d6ab272012-09-23 18:06:20 -07001955 self.dataplane.send(ingress_port, str(pkt))
1956
1957 exp_pkt_arg = None
1958 exp_port = None
Rich Lane477f4812012-10-04 22:49:00 -07001959 if config["relax"]:
Rich Lane8d6ab272012-09-23 18:06:20 -07001960 exp_pkt_arg = pkt
1961 exp_port = egress_port
1962
1963 (rcv_port, rcv_pkt, pkt_time) = self.dataplane.poll(port_number=exp_port,
1964 exp_pkt=exp_pkt_arg)
1965 self.assertTrue(rcv_pkt is not None, "Did not receive packet")
Rich Lane9a003812012-10-04 17:17:59 -07001966 logging.debug("Packet len " + str(len(rcv_pkt)) + " in on " + str(rcv_port))
Rich Lane8d6ab272012-09-23 18:06:20 -07001967 self.assertEqual(rcv_port, egress_port, "Unexpected receive port")
1968 self.assertEqual(str(pkt), str(rcv_pkt), 'Response packet does not match send packet')
1969
Ed Swierkb603b192012-12-12 15:38:49 -08001970 wildcards = required_wildcards(self)
Rich Lane8d6ab272012-09-23 18:06:20 -07001971 # TODO in_port
Ed Swierkb603b192012-12-12 15:38:49 -08001972 if not (wildcards & ofp.OFPFW_DL_SRC):
1973 testField("dl_src", [0xff]*6)
1974 if not (wildcards & ofp.OFPFW_DL_DST):
1975 testField("dl_dst", [0xff]*6)
1976 if not (wildcards & ofp.OFPFW_DL_TYPE):
1977 testField("dl_type", 0xffff)
1978 if not (wildcards & ofp.OFPFW_DL_VLAN):
1979 testField("dl_vlan", 0xfff)
Rich Lane8d6ab272012-09-23 18:06:20 -07001980 # TODO dl_vlan_pcp
Ed Swierkb603b192012-12-12 15:38:49 -08001981 if not (wildcards & ofp.OFPFW_NW_SRC_ALL):
1982 testField("nw_src", 0xffffffff)
1983 if not (wildcards & ofp.OFPFW_NW_DST_ALL):
1984 testField("nw_dst", 0xffffffff)
1985 if not (wildcards & ofp.OFPFW_NW_TOS):
1986 testField("nw_tos", 0x3f)
1987 if not (wildcards & ofp.OFPFW_NW_PROTO):
1988 testField("nw_proto", 0xff)
1989 if not (wildcards & ofp.OFPFW_TP_SRC):
1990 testField("tp_src", 0xffff)
1991 if not (wildcards & ofp.OFPFW_TP_DST):
1992 testField("tp_dst", 0xffff)
Rich Lane8d6ab272012-09-23 18:06:20 -07001993
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07001994class DirectBadPacketBase(base_tests.SimpleDataPlane):
1995 """
1996 Base class for sending single packets with single flow table entries.
1997 Used to verify matching of unusual packets and parsing/matching of
1998 corrupted packets.
1999
2000 The idea is to generate packets that may either be totally malformed or
2001 malformed just enough to trick the flow matcher into making mistakes.
2002
2003 Generate a 'bad' packet
2004 Generate and install a matching flow
2005 Add action to direct the packet to an egress port
2006 Send the packet to ingress dataplane port
2007 Verify the packet is received at the egress port only
2008 """
2009
2010 RESULT_MATCH = "MATCH"
2011 RESULT_NOMATCH = "NO MATCH"
2012 RESULT_ANY = "ANY MATCH"
2013
2014 def runTest(self):
2015 pass
2016 # TODO:
2017 # - ICMP?
2018 # - VLAN?
2019 # - action
2020
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002021 def createMatch(self, **kwargs):
2022 match = ofp.ofp_match()
2023 match.wildcards = ofp.OFPFW_ALL
2024 fields = {
2025 'dl_dst': ofp.OFPFW_DL_DST,
2026 'dl_src': ofp.OFPFW_DL_SRC,
2027 'dl_type': ofp.OFPFW_DL_TYPE,
2028 'dl_vlan': ofp.OFPFW_DL_VLAN,
2029 'nw_src': ofp.OFPFW_NW_SRC_MASK,
2030 'nw_dst': ofp.OFPFW_NW_DST_MASK,
2031 'nw_tos': ofp.OFPFW_NW_TOS,
2032 'nw_proto': ofp.OFPFW_NW_PROTO,
2033 'tp_src': ofp.OFPFW_TP_SRC,
2034 'tp_dst': ofp.OFPFW_TP_DST,
2035 }
2036 for key in kwargs:
2037 setattr(match, key, kwargs[key])
2038 match.wildcards &= ~fields[key]
2039 return match
2040
2041 def testPktsAgainstFlow(self, pkts, acts, match):
2042 if type(acts) != list:
2043 acts = [acts]
2044 for info in pkts:
2045 title, pkt, expected_result = info
2046 self.testPktAgainstFlow(title, pkt, acts, match, expected_result)
2047
2048 def testPktAgainstFlow(self, title, pkt, acts, match, expected_result):
2049 of_ports = config["port_map"].keys()
2050 of_ports.sort()
2051 self.assertTrue(len(of_ports) > 1, "Not enough ports for test")
2052
Rich Lane32bf9482013-01-03 17:26:30 -08002053 delete_all_flows(self.controller)
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002054
2055 ingress_port = of_ports[0]
2056 egress_port = of_ports[1]
2057
2058 logging.info("Testing packet '%s', expect result %s" %
2059 (title, expected_result))
2060 logging.info("Ingress %s to egress %s" %
2061 (str(ingress_port), str(egress_port)))
2062 logging.info("Packet:")
Rich Lane5d7e89a2012-10-26 16:43:13 -07002063 logging.info(inspect_packet(pkt))
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002064
2065 match.in_port = ingress_port
2066
2067 request = message.flow_mod()
2068 request.match = match
Rich Lane44cf12d2012-10-15 11:10:45 -07002069 request.priority = 1
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002070
2071 request.buffer_id = 0xffffffff
2072 for act in acts:
2073 act.port = egress_port
Rich Lanee30455b2013-01-03 16:24:44 -08002074 request.actions.add(act)
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002075
2076 logging.info("Inserting flow")
Rich Lane5c3151c2013-01-03 17:15:41 -08002077 self.controller.message_send(request)
Rich Lane44cf12d2012-10-15 11:10:45 -07002078
2079 # This flow speeds up negative tests
2080 logging.info("Inserting catch-all flow")
2081 request2 = message.flow_mod()
2082 request2.match = self.createMatch()
2083 request2.priority = 0
2084 act = action.action_output()
2085 act.port = ofp.OFPP_IN_PORT
2086 request2.actions.add(act)
Rich Lane5c3151c2013-01-03 17:15:41 -08002087 self.controller.message_send(request2)
Rich Lane44cf12d2012-10-15 11:10:45 -07002088
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002089 self.assertEqual(do_barrier(self.controller), 0, "Barrier failed")
2090
2091 logging.info("Sending packet to dp port " +
2092 str(ingress_port))
2093 self.dataplane.send(ingress_port, str(pkt))
2094
2095 exp_pkt_arg = None
2096 exp_port = None
2097 if config["relax"]:
2098 exp_pkt_arg = pkt
2099 exp_port = egress_port
2100
Rich Lane44cf12d2012-10-15 11:10:45 -07002101 if expected_result == self.RESULT_MATCH:
2102 timeout = -1 # default timeout
2103 else:
2104 timeout = 1 # short timeout for negative tests
2105
2106 (rcv_port, rcv_pkt, pkt_time) = self.dataplane.poll(exp_pkt=exp_pkt_arg,
2107 timeout=timeout)
2108 if rcv_port == ingress_port:
2109 logging.debug("Packet matched catch-all flow")
2110 rcv_pkt = None
2111
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002112 if expected_result == self.RESULT_MATCH:
2113 self.assertTrue(rcv_pkt is not None,
2114 "Did not receive packet, expected a match")
2115 logging.debug("Packet len " + str(len(rcv_pkt)) + " in on " +
2116 str(rcv_port))
2117 self.assertEqual(rcv_port, egress_port, "Unexpected receive port")
2118 str_pkt = str(pkt)
2119 str_rcv_pkt = str(rcv_pkt)
2120 str_rcv_pkt = str_rcv_pkt[0:len(str_pkt)]
2121 if str_pkt != str_rcv_pkt:
2122 logging.error("Response packet does not match send packet")
2123 logging.info("Response:")
Rich Lane5d7e89a2012-10-26 16:43:13 -07002124 logging.info(inspect_packet(scapy.Ether(rcv_pkt)))
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002125 self.assertEqual(str_pkt, str_rcv_pkt,
2126 'Response packet does not match send packet')
2127 elif expected_result == self.RESULT_NOMATCH:
2128 self.assertTrue(rcv_pkt is None, "Received packet, expected drop")
2129 else:
2130 logging.debug("Match or drop accepted. Result = %s" %
2131 ("match" if rcv_pkt is not None else "drop"))
2132
2133
2134class DirectBadIpTcpPacketsBase(DirectBadPacketBase):
2135 """
2136 Base class for TCP and UDP parsing/matching verification under corruptions
2137 """
2138 def runTest(self):
2139 pass
2140
2141 def runTestWithProto(self, protoName = 'TCP'):
2142 dl_dst='00:01:02:03:04:05'
2143 dl_src='00:06:07:08:09:0a'
2144 ip_src='192.168.0.1'
2145 ip_dst='192.168.0.2'
2146 ip_tos=0
2147 tcp_sport=1234
2148 tcp_dport=80
2149
2150 # Generate a proper packet for constructing a match
2151 tp = None
2152 if protoName == 'TCP':
2153 tp = scapy.TCP
2154 proto = 6
2155 elif protoName == 'UDP':
2156 tp = scapy.UDP
2157 proto = 17
2158 else:
2159 raise Exception("Passed in unknown proto name")
2160
2161 match_pkt = scapy.Ether(dst=dl_dst, src=dl_src)/ \
2162 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos)/ \
2163 tp(sport=tcp_sport, dport=tcp_dport)
2164 match = packet_to_flow_match(self, match_pkt)
2165 self.assertTrue(match is not None,
2166 "Could not generate flow match from pkt")
2167 match.wildcards &= ~ofp.OFPFW_IN_PORT
2168
2169 def testPacket(title, pkt, result):
2170 act = action.action_output()
2171 pkts = [
2172 [title, pkt, result]
2173 ]
2174 self.testPktsAgainstFlow(pkts, act, match)
2175
2176 # Try incomplete IP headers
2177 testPacket("Incomplete IP header (1 bytes)",
2178 scapy.Ether(dst=dl_dst, src=dl_src)/ \
2179 str(scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, proto=proto))[0:1],
2180 self.RESULT_NOMATCH,
2181 )
2182 testPacket("Incomplete IP header (2 bytes)",
2183 scapy.Ether(dst=dl_dst, src=dl_src)/ \
2184 str(scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, proto=proto))[0:2],
2185 self.RESULT_NOMATCH,
2186 )
2187 testPacket("Incomplete IP header (3 bytes)",
2188 scapy.Ether(dst=dl_dst, src=dl_src)/ \
2189 str(scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, proto=proto))[0:3],
2190 self.RESULT_NOMATCH,
2191 )
2192 testPacket("Incomplete IP header (12 bytes)",
2193 scapy.Ether(dst=dl_dst, src=dl_src)/ \
2194 str(scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, proto=proto))[0:12],
2195 self.RESULT_NOMATCH,
2196 )
2197 testPacket("Incomplete IP header (16 bytes)",
2198 scapy.Ether(dst=dl_dst, src=dl_src)/ \
2199 str(scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, proto=proto))[0:16],
2200 self.RESULT_NOMATCH,
2201 )
2202 testPacket("Incomplete IP header (19 bytes)",
2203 scapy.Ether(dst=dl_dst, src=dl_src)/ \
2204 str(scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, proto=proto))[0:19],
2205 self.RESULT_NOMATCH,
2206 )
2207
2208 # Try variations where the TCP header is missing or incomplete. As we
2209 # saw bugs before where buffers were reused and lengths weren't honored,
2210 # we initiatlize once with a non-matching full packet and once with a
2211 # matching full packet.
2212 testPacket("Non-Matching TCP packet, warming buffer",
2213 scapy.Ether(dst=dl_dst, src=dl_src)/ \
2214 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, proto=proto)/ \
2215 tp(sport=tcp_sport, dport=tcp_dport + 1),
2216 self.RESULT_NOMATCH,
2217 )
2218 testPacket("Missing TCP header, buffer warmed with non-match",
2219 scapy.Ether(dst=dl_dst, src=dl_src)/ \
2220 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, proto=proto),
2221 self.RESULT_NOMATCH,
2222 )
2223 testPacket("Matching TCP packet, warming buffer",
2224 scapy.Ether(dst=dl_dst, src=dl_src)/ \
2225 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, proto=proto)/ \
2226 tp(sport=tcp_sport, dport=tcp_dport),
2227 self.RESULT_MATCH,
2228 )
2229 testPacket("Missing TCP header, buffer warmed with match",
2230 scapy.Ether(dst=dl_dst, src=dl_src)/ \
2231 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, proto=proto),
2232 self.RESULT_NOMATCH,
2233 )
2234 testPacket("Truncated TCP header: 2 bytes",
2235 scapy.Ether(dst=dl_dst, src=dl_src)/ \
2236 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, proto=proto)/ \
2237 (str(tp(sport=tcp_sport, dport=tcp_dport))[0:2]),
2238 self.RESULT_NOMATCH,
2239 )
2240
2241 # Play with IP header length values that put the start of TCP either
2242 # inside the generated TCP header or beyond. In some cases it may even
2243 # be beyond the packet boundary. Also play with IP options and more
2244 # importantly IP total length corruptions.
2245 testPacket("TCP packet, corrupt ihl (0x6)",
2246 simple_tcp_packet(ip_ihl=6),
2247 self.RESULT_NOMATCH,
2248 )
2249 testPacket("TCP packet, corrupt ihl (0xf)",
2250 simple_tcp_packet(ip_ihl=0xf), # ihl = 15 * 4 = 60
2251 self.RESULT_NOMATCH,
2252 )
2253 testPacket("TCP packet, corrupt ihl and total length",
2254 simple_tcp_packet(ip_ihl=0xf, pktlen=56), # ihl = 15 * 4 = 60,
2255 self.RESULT_NOMATCH,
2256 )
2257 testPacket("Corrupt IPoption: First 4 bytes of matching TCP header",
2258 simple_tcp_packet(
2259 ip_options=scapy.IPOption('\x04\xd2\x00\x50'),
2260 tcp_dport=2, tcp_sport=2
2261 ),
2262 self.RESULT_NOMATCH,
2263 )
2264 testPacket("Missing TCP header, corrupt ihl",
2265 scapy.Ether(dst=dl_dst, src=dl_src)/ \
2266 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ihl=0xf, proto=proto),
2267 self.RESULT_NOMATCH,
2268 )
2269 testPacket("Missing TCP header, corrupt total length",
2270 scapy.Ether(dst=dl_dst, src=dl_src)/ \
2271 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, proto=proto, len= 100),
2272 self.RESULT_NOMATCH,
2273 )
2274 testPacket("Missing TCP header, corrupt ihl and total length",
2275 scapy.Ether(dst=dl_dst, src=dl_src)/ \
2276 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ihl=0xf, proto=proto, len=43),
2277 self.RESULT_NOMATCH,
2278 )
2279 testPacket("Incomplete IP header (12 bytes), corrupt ihl and total length",
2280 scapy.Ether(dst=dl_dst, src=dl_src)/ \
2281 str(scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, proto=proto, ihl=10, len=43))[0:12],
2282 self.RESULT_NOMATCH,
2283 )
2284 testPacket("Incomplete IP header (16 bytes), corrupt ihl and total length",
2285 scapy.Ether(dst=dl_dst, src=dl_src)/ \
2286 str(scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, proto=proto, ihl=10, len=43))[0:16],
2287 self.RESULT_NOMATCH,
2288 )
2289
2290 # Try an incomplete TCP header that has enough bytes to carry source and
2291 # destination ports. As that is all we care about during matching, some
2292 # implementations may match and some may drop the packet
2293 testPacket("Incomplete TCP header: src/dst port present",
2294 scapy.Ether(dst=dl_dst, src=dl_src)/ \
2295 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, proto=proto)/ \
2296 (str(tp(sport=tcp_sport, dport=tcp_dport))[0:4]),
2297 self.RESULT_ANY,
2298 )
2299
2300 for i in range(1):
2301 for length in range(40 / 4): # IPv4 options are a maximum of 40 in length
2302 bytes = "".join([("%c" % random.randint(0, 255)) for x in range(length * 4)])
2303 eth = scapy.Ether(dst=dl_dst, src=dl_src)
2304 ip = scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ihl=5 + length, proto=proto)
2305 tcp = tp(sport=tcp_sport, dport=tcp_dport+1)
2306 pkt = eth / ip
2307 pkt = pkt / bytes
2308 pkt = pkt / str(tcp)
2309 testPacket("Random IP options len = %d - TP match must fail" % length * 4,
2310 pkt,
2311 self.RESULT_NOMATCH
2312 )
2313
2314 eth = scapy.Ether(dst=dl_dst, src=dl_src)
2315 ip = scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ihl=5 + length, proto=proto)
2316 tcp = tp(sport=tcp_sport, dport=tcp_dport)
2317 pkt = eth / ip
2318 pkt = pkt / bytes
2319 pkt = pkt / str(tcp)
2320
2321 testPacket("Random IP options len = %d - May match",
2322 pkt,
2323 self.RESULT_ANY
2324 )
2325
2326
2327class DirectBadIpTcpPackets(DirectBadIpTcpPacketsBase):
2328 """
2329 Verify IP/TCP parsing and matching. Focus on packet corruptions
2330 """
2331 def runTest(self):
2332 self.runTestWithProto(protoName = 'TCP')
2333
2334class DirectBadIpUdpPackets(DirectBadIpTcpPacketsBase):
2335 """
2336 Verify IP/UDP parsing and matching. Focus on packet corruptions
2337 """
2338 def runTest(self):
2339 self.runTestWithProto(protoName = 'UDP')
2340
2341class DirectBadLlcPackets(DirectBadPacketBase):
2342 """
2343 Verify LLC/SNAP parsing and matching. Focus on packet corruptions
2344 """
2345 def runTest(self):
2346 dl_dst='00:01:02:03:04:05'
2347 dl_src='00:06:07:08:09:0a'
2348 ip_src='192.168.0.1'
2349 ip_dst='192.168.0.2'
2350 ip_tos=0
2351 tcp_sport=1234
2352 tcp_dport=80
2353
2354 IS_SNAP_IP = 1
2355 IS_SNAP_IP_CORRUPT = 2
2356 IS_NOT_SNAP_IP = 3
2357
2358 def testPacketTcpMatch(title, llc):
2359 match_pkt = scapy.Ether(dst=dl_dst, src=dl_src)/ \
2360 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos)/ \
2361 scapy.TCP(sport=tcp_sport, dport=tcp_dport)
2362 match = packet_to_flow_match(self, match_pkt)
2363 self.assertTrue(match is not None,
2364 "Could not generate flow match from pkt")
2365 match.wildcards &= ~ofp.OFPFW_IN_PORT
2366 act = action.action_output()
2367
2368 self.testPktsAgainstFlow(
2369 [[
2370 "TCP match - LLC frame correct length - %s" % title,
2371 scapy.Ether(dst=dl_dst, src=dl_src, type=len(llc)) / llc,
2372 self.RESULT_ANY,
2373 ]],
2374 act, match
2375 )
2376
2377 # Corrupt length field
2378 ethLen = random.randint(0, 1535)
2379 self.testPktsAgainstFlow(
2380 [[
2381 "TCP match - LLC frame corrupted length - %s" % title,
2382 scapy.Ether(dst=dl_dst, src=dl_src, type=ethLen) / llc,
2383 self.RESULT_ANY,
2384 ]],
2385 act, match
2386 )
2387
2388 def testPacketEthSrcDstMatch(title, llc):
2389 # Matching based on Ethernet source and destination
2390 match_pkt = scapy.Ether(dst=dl_dst, src=dl_src)
2391 match = packet_to_flow_match(self, match_pkt)
2392 self.assertTrue(match is not None,
2393 "Could not generate flow match from pkt")
2394 match.wildcards &= ~ofp.OFPFW_IN_PORT
2395 match.wildcards |= ofp.OFPFW_DL_TYPE
2396 self.testPktsAgainstFlow(
2397 [[
2398 "Eth addr match - LLC frame correct length- %s" % title,
2399 scapy.Ether(dst=dl_dst, src=dl_src, type=len(llc)) / llc,
2400 self.RESULT_MATCH,
2401 ]],
2402 action.action_output(), match
2403 )
2404
2405 # Corrupt length field
2406 ethLen = random.randint(0, 1535)
2407 self.testPktsAgainstFlow(
2408 [[
2409 "Eth addr match - LLC frame corrupted length- %s" % title,
2410 scapy.Ether(dst=dl_dst, src=dl_src, type=ethLen) / llc,
2411 self.RESULT_ANY,
2412 ]],
2413 action.action_output(), match
2414 )
2415
2416 def testPacketEthSrcDstTypeMatch(title, llc, is_snap_ip):
2417 # Matching based on Ethernet source, destination and type
2418 match_pkt = scapy.Ether(dst=dl_dst, src=dl_src, type=0x800)
2419 match = packet_to_flow_match(self, match_pkt)
2420 self.assertTrue(match is not None,
2421 "Could not generate flow match from pkt")
2422 match.wildcards &= ~ofp.OFPFW_IN_PORT
2423 if is_snap_ip == IS_SNAP_IP:
2424 is_match = self.RESULT_MATCH
2425 elif is_snap_ip == IS_SNAP_IP_CORRUPT:
2426 is_match = self.RESULT_ANY
2427 else:
2428 is_match = self.RESULT_NOMATCH
2429 self.testPktsAgainstFlow(
2430 [[
2431 "Eth addr+type match - LLC frame correct length - %s" % title,
2432 scapy.Ether(dst=dl_dst, src=dl_src, type=len(llc)) / llc,
2433 is_match,
2434 ]],
2435 action.action_output(), match
2436 )
2437
2438 # Corrupt length field
2439 ethLen = random.randint(0, 1535)
2440 self.testPktsAgainstFlow(
2441 [[
2442 "Eth addr+type match - LLC frame corrupted length - %s" % title,
2443 scapy.Ether(dst=dl_dst, src=dl_src, type=ethLen) / llc,
Christian Dickmanne9b6d252012-10-08 22:56:50 -07002444 self.RESULT_ANY,
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002445 ]],
2446 action.action_output(), match
2447 )
2448
2449 def testPacket(title, llc, is_snap_ip):
2450 testPacketTcpMatch(title, llc)
2451 testPacketEthSrcDstMatch(title, llc)
2452 testPacketEthSrcDstTypeMatch(title, llc, is_snap_ip)
2453
2454 testPacket("LLC - No SNAP - No Payload",
Rich Lane6508ea02012-10-12 15:27:11 -07002455 scapy.LLC(dsap=0x33, ssap=0x44, ctrl=0x03),
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002456 IS_NOT_SNAP_IP,
2457 )
2458 testPacket("LLC - No SNAP - Small Payload",
Rich Lane6508ea02012-10-12 15:27:11 -07002459 scapy.LLC(dsap=0x33, ssap=0x44, ctrl=0x03) / ("S" * 10),
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002460 IS_NOT_SNAP_IP,
2461 )
2462 testPacket("LLC - No SNAP - Max -1 Payload",
Rich Lane6508ea02012-10-12 15:27:11 -07002463 scapy.LLC(dsap=0x33, ssap=0x44, ctrl=0x03) / ("S" * (1500 - 3 - 1)),
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002464 IS_NOT_SNAP_IP,
2465 )
2466 testPacket("LLC - No SNAP - Max Payload",
Rich Lane6508ea02012-10-12 15:27:11 -07002467 scapy.LLC(dsap=0x33, ssap=0x44, ctrl=0x03) / ("S" * (1500 - 3)),
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002468 IS_NOT_SNAP_IP,
2469 )
2470 testPacket("LLC - SNAP - Small bogus payload",
2471 scapy.LLC(dsap=0xaa, ssap=0xaa, ctrl=0x03)/ \
2472 scapy.SNAP(OUI=0x000000, code=0x800) / ("S" * 10),
2473 IS_SNAP_IP_CORRUPT,
2474 )
2475 testPacket("LLC - SNAP - Max -1 bogus payload",
2476 scapy.LLC(dsap=0xaa, ssap=0xaa, ctrl=0x03)/ \
2477 scapy.SNAP(OUI=0x000000, code=0x3) / ("S" * (1500 - 3 - 5 - 1)),
2478 IS_NOT_SNAP_IP,
2479 )
2480 testPacket("LLC - SNAP - Max bogus payload",
2481 scapy.LLC(dsap=0xaa, ssap=0xaa, ctrl=0x03)/ \
2482 scapy.SNAP(OUI=0x000000, code=0x3) / ("S" * (1500 - 3 - 5)),
2483 IS_NOT_SNAP_IP,
2484 )
2485 testPacket("LLC - SNAP - IP - TCP",
2486 scapy.LLC(dsap=0xaa, ssap=0xaa, ctrl=0x03)/ \
2487 scapy.SNAP(OUI=0x000000, code=0x800)/ \
2488 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, proto=6)/ \
2489 scapy.TCP(sport=tcp_sport, dport=tcp_dport),
2490 IS_SNAP_IP,
2491 )
2492
2493
2494class DirectLlcPackets(DirectBadPacketBase):
2495 """
2496 Verify LLC/SNAP parsing (valid and corrupted packets) and matching
2497 """
2498 def runTest(self):
2499 dl_dst='00:01:02:03:04:05'
2500 dl_src='00:06:07:08:09:0a'
2501 ip_src='192.168.0.1'
2502 ip_dst='192.168.0.2'
2503 ip_tos=0
2504 tcp_sport=1234
2505 tcp_dport=80
2506
2507 # Test ethertype in face of LLC/SNAP and OFP_DL_TYPE_NOT_ETH_TYPE
2508 IS_SNAP_NOT_IP = 1
2509 IS_SNAP_AND_IP = 2
2510 IS_NOT_SNAP = 3
2511
2512 def testPacketEthTypeIP(title, llc, is_snap):
2513 match_pkt = scapy.Ether(dst=dl_dst, src=dl_src, type=0x800)
2514 match = packet_to_flow_match(self, match_pkt)
2515 self.assertTrue(match is not None,
2516 "Could not generate flow match from pkt")
2517 match.wildcards &= ~ofp.OFPFW_IN_PORT
2518 pkts = []
2519 if is_snap == IS_NOT_SNAP or is_snap == IS_SNAP_NOT_IP:
2520 result = self.RESULT_NOMATCH
2521 else:
2522 result = self.RESULT_MATCH
2523 pkts.append([
2524 "Ether type 0x800 match - %s" % title,
2525 scapy.Ether(dst=dl_dst, src=dl_src, type=len(llc)) / llc,
2526 result,
2527 ])
2528 act = action.action_output()
2529 self.testPktsAgainstFlow(pkts, act, match)
2530
2531 def testPacketEthTypeNotEth(title, llc, is_snap):
2532 match_pkt = scapy.Ether(dst = dl_dst, src = dl_src,
2533 type = ofp.OFP_DL_TYPE_NOT_ETH_TYPE)
2534 match = packet_to_flow_match(self, match_pkt)
2535 self.assertTrue(match is not None,
2536 "Could not generate flow match from pkt")
2537 match.wildcards &= ~ofp.OFPFW_IN_PORT
2538 pkts = []
2539 if is_snap == IS_NOT_SNAP:
2540 result = self.RESULT_MATCH
2541 else:
2542 result = self.RESULT_NOMATCH
2543 pkts.append([
2544 "Ether type OFP_DL_TYPE_NOT_ETH_TYPE match - %s" % title,
2545 scapy.Ether(dst=dl_dst, src=dl_src, type=len(llc)) / llc,
2546 result,
2547 ])
2548 act = action.action_output()
2549 self.testPktsAgainstFlow(pkts, act, match)
2550
2551 def testPacket(title, llc, is_snap):
2552 testPacketEthTypeIP(title, llc, is_snap)
2553 testPacketEthTypeNotEth(title, llc, is_snap)
2554
2555 testPacket("LLC - No SNAP - No Payload",
Rich Lane6508ea02012-10-12 15:27:11 -07002556 scapy.LLC(dsap=0x33, ssap=0x44, ctrl=0x03),
2557 IS_NOT_SNAP,
2558 )
2559 testPacket("LLC (with information field) - No SNAP - No Payload",
2560 scapy.LLC(dsap=0x33, ssap=0x44, ctrl=0x12) / "S",
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002561 IS_NOT_SNAP,
2562 )
2563 testPacket("LLC - No SNAP - Small Payload",
Rich Lane6508ea02012-10-12 15:27:11 -07002564 scapy.LLC(dsap=0x33, ssap=0x44, ctrl=0x03) / ("S" * 10),
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002565 IS_NOT_SNAP,
2566 )
2567 testPacket("LLC - No SNAP - Max -1 Payload",
Rich Lane6508ea02012-10-12 15:27:11 -07002568 scapy.LLC(dsap=0x33, ssap=0x44, ctrl=0x03) / ("S" * (1500 - 3 - 1)),
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002569 IS_NOT_SNAP,
2570 )
2571 testPacket("LLC - No SNAP - Max Payload",
Rich Lane6508ea02012-10-12 15:27:11 -07002572 scapy.LLC(dsap=0x33, ssap=0x44, ctrl=0x03) / ("S" * (1500 - 3)),
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002573 IS_NOT_SNAP,
2574 )
2575 testPacket("LLC - SNAP - Non-default OUI",
2576 scapy.LLC(dsap=0xaa, ssap=0xaa, ctrl=0x03)/ \
2577 scapy.SNAP(OUI=0x000001, code=0x800) / ("S" * 10),
2578 IS_NOT_SNAP,
2579 )
2580 testPacket("LLC - SNAP - Default OUI",
2581 scapy.LLC(dsap=0xaa, ssap=0xaa, ctrl=0x03)/ \
2582 scapy.SNAP(OUI=0x000000, code=0x800) / ("S" * 10),
2583 IS_SNAP_AND_IP,
2584 )
2585 testPacket("LLC - SNAP - Max -1 bogus payload",
2586 scapy.LLC(dsap=0xaa, ssap=0xaa, ctrl=0x03)/ \
2587 scapy.SNAP(OUI=0x000000, code=0x3) / ("S" * (1500 - 3 - 5 - 1)),
2588 IS_SNAP_NOT_IP,
2589 )
2590 testPacket("LLC - SNAP - Max bogus payload",
2591 scapy.LLC(dsap=0xaa, ssap=0xaa, ctrl=0x03)/ \
2592 scapy.SNAP(OUI=0x000000, code=0x3) / ("S" * (1500 - 3 - 5)),
2593 IS_SNAP_NOT_IP,
2594 )
2595 testPacket("LLC - SNAP - IP - TCP",
2596 scapy.LLC(dsap=0xaa, ssap=0xaa, ctrl=0x03)/ \
2597 scapy.SNAP(OUI=0x000000, code=0x800)/ \
2598 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, proto=6)/ \
2599 scapy.TCP(sport=tcp_sport, dport=tcp_dport),
2600 IS_SNAP_AND_IP,
2601 )
2602
2603
2604class DirectArpPackets(DirectBadPacketBase):
2605 """
2606 Verify ARP parsing (valid and corrupted packets) and ARP matching
2607 """
2608 def runTest(self):
2609 self.testArpHandling()
2610
2611 def testArpHandling(self):
2612 dl_dst='00:01:02:03:04:05'
2613 dl_src='00:06:07:08:09:0a'
2614 ip_src='192.168.0.1'
2615 ip_dst='192.168.0.2'
2616 ip_src2='192.168.1.1'
2617 ip_dst2='192.168.1.2'
2618 ip_tos=0
2619 tcp_sport=1234
2620 tcp_dport=80
2621
2622 def testPacket(title, arp_match, arp_pkt, result):
2623 pkts = []
2624
2625 match_pkt = scapy.Ether(dst=dl_dst, src=dl_src) / arp_match
2626 match = packet_to_flow_match(self, match_pkt)
2627 self.assertTrue(match is not None,
2628 "Could not generate flow match from pkt")
2629 match.wildcards &= ~ofp.OFPFW_IN_PORT
2630
2631 pkts.append([
2632 title,
2633 scapy.Ether(dst=dl_dst, src=dl_src) / arp_pkt,
2634 result,
2635 ])
2636
2637 act = action.action_output()
2638 self.testPktsAgainstFlow(pkts, act, match)
2639
2640 testPacket("Basic ARP",
2641 scapy.ARP(psrc=ip_src, pdst=ip_dst, op = 1),
2642 scapy.ARP(hwdst = '00:00:00:00:00:00', hwsrc = dl_src,
2643 psrc = ip_src, pdst = ip_dst, hwlen = 6, plen = 4,
2644 ptype = 0x800, hwtype = 1, op = 1),
2645 self.RESULT_MATCH
2646 )
2647 # More stuff:
2648 # - Non matches on any property
2649 # - Corrupted hwlen and plen
2650 # - Other hwtype, ptype
2651 # - Truncated ARP pkt
2652
2653
2654class DirectVlanPackets(DirectBadPacketBase):
2655 """
2656 Verify VLAN parsing (valid and corrupted packets) and ARP matching
2657 """
2658 def runTest(self):
2659 dl_dst='00:01:02:03:04:05'
2660 dl_src='00:06:07:08:09:0a'
2661 ip_src='192.168.0.1'
2662 ip_dst='192.168.0.2'
2663 ip_src2='192.168.1.1'
2664 ip_dst2='192.168.1.2'
2665 ip_tos=0
2666 tcp_sport=1234
2667 tcp_dport=80
2668
2669 def testPacket(title, match, pkt, result):
2670 pkts = []
2671
2672 self.assertTrue(match is not None,
2673 "Could not generate flow match from pkt")
2674 match.wildcards &= ~ofp.OFPFW_IN_PORT
2675
2676 pkts.append([
2677 "%s" % title,
2678 pkt,
2679 result,
2680 ])
2681
2682 act = action.action_output()
2683 self.testPktsAgainstFlow(pkts, act, match)
2684
2685 testPacket("Basic MAC matching - IPv4 payload",
2686 self.createMatch(dl_dst=parse_mac(dl_dst), dl_src=parse_mac(dl_src)),
2687 scapy.Ether(dst=dl_dst, src=dl_src, type=0x800) / scapy.IP(),
2688 self.RESULT_MATCH
2689 )
2690 testPacket("Basic MAC matching - VMware beacon - no payload",
2691 self.createMatch(dl_dst=parse_mac(dl_dst), dl_src=parse_mac(dl_src)),
2692 scapy.Ether(dst=dl_dst, src=dl_src, type=0x8922),
2693 self.RESULT_MATCH
2694 )
2695 testPacket("Basic MAC matching - VMware beacon - with payload",
2696 self.createMatch(dl_dst=parse_mac(dl_dst), dl_src=parse_mac(dl_src)),
2697 scapy.Ether(dst=dl_dst, src=dl_src, type=0x8922)/ ("X" * 1),
2698 self.RESULT_MATCH
2699 )
2700 testPacket("Basic MAC matching - IPv6 payload",
2701 self.createMatch(dl_dst=parse_mac(dl_dst), dl_src=parse_mac(dl_src)),
2702 scapy.Ether(dst=dl_dst, src=dl_src) / scapy.IPv6(),
2703 self.RESULT_MATCH
2704 )
2705 testPacket("Basic MAC matching with VLAN tag present",
2706 self.createMatch(dl_dst=parse_mac(dl_dst), dl_src=parse_mac(dl_src)),
2707 scapy.Ether(dst=dl_dst, src=dl_src)/ \
Christian Dickmann8ac55252012-10-08 22:53:49 -07002708 scapy.Dot1Q(prio=5, vlan=1000)/ \
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002709 scapy.IP(),
2710 self.RESULT_MATCH
2711 )
2712 testPacket("Basic MAC matching with VLAN tag present",
2713 self.createMatch(dl_dst=parse_mac(dl_dst), dl_src=parse_mac(dl_src),
2714 dl_type=0x800),
2715 scapy.Ether(dst=dl_dst, src=dl_src)/ \
Christian Dickmann8ac55252012-10-08 22:53:49 -07002716 scapy.Dot1Q(prio=5, vlan=1000)/ \
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002717 scapy.IP(),
2718 self.RESULT_MATCH
2719 )
2720 testPacket("Ether matching with VLAN tag present - No type match",
2721 self.createMatch(dl_dst=parse_mac(dl_dst), dl_src=parse_mac(dl_src),
2722 dl_type=0x801),
2723 scapy.Ether(dst=dl_dst, src=dl_src)/ \
Christian Dickmann8ac55252012-10-08 22:53:49 -07002724 scapy.Dot1Q(prio=5, vlan=1000)/ \
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002725 scapy.IP(),
2726 self.RESULT_NOMATCH
2727 )
2728 testPacket("Ether matching with VLAN tag present - No type match 0x8100",
2729 self.createMatch(dl_dst=parse_mac(dl_dst), dl_src=parse_mac(dl_src),
2730 dl_type=0x8100),
2731 scapy.Ether(dst=dl_dst, src=dl_src)/ \
Christian Dickmann8ac55252012-10-08 22:53:49 -07002732 scapy.Dot1Q(prio=5, vlan=1000)/ \
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002733 scapy.IP(),
2734 self.RESULT_NOMATCH
2735 )
2736 testPacket("Ether matching with double VLAN tag - Wrong type match",
2737 self.createMatch(dl_dst=parse_mac(dl_dst), dl_src=parse_mac(dl_src),
2738 dl_type=0x800),
2739 scapy.Ether(dst=dl_dst, src=dl_src)/ \
Christian Dickmann8ac55252012-10-08 22:53:49 -07002740 scapy.Dot1Q(prio=5, vlan=1000)/ \
2741 scapy.Dot1Q(prio=3, vlan=1005)/ \
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002742 scapy.IP(),
2743 self.RESULT_NOMATCH
2744 )
2745 testPacket("Ether matching with double VLAN tag - Type match",
2746 self.createMatch(dl_dst=parse_mac(dl_dst), dl_src=parse_mac(dl_src),
2747 dl_type=0x8100),
2748 scapy.Ether(dst=dl_dst, src=dl_src)/ \
Christian Dickmann8ac55252012-10-08 22:53:49 -07002749 scapy.Dot1Q(prio=5, vlan=1000)/ \
2750 scapy.Dot1Q(prio=3, vlan=1005)/ \
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002751 scapy.IP(),
2752 self.RESULT_MATCH
2753 )
2754 testPacket("IP matching - VLAN tag",
2755 self.createMatch(dl_dst=parse_mac(dl_dst), dl_src=parse_mac(dl_src),
2756 dl_type=0x0800,
2757 nw_src=parse_ip(ip_src), nw_dst=parse_ip(ip_dst)),
2758 scapy.Ether(dst=dl_dst, src=dl_src)/ \
Christian Dickmann8ac55252012-10-08 22:53:49 -07002759 scapy.Dot1Q(prio=5, vlan=1000)/ \
Christian Dickmann8b59b4b2012-09-23 16:48:30 -07002760 scapy.IP(src=ip_src, dst=ip_dst),
2761 self.RESULT_MATCH
2762 )
2763 # XXX:
2764 # - Matching on VLAN ID and Prio
2765 # - Actions
2766
2767
2768
Dan Talayco9f47f4d2010-06-03 13:54:37 -07002769if __name__ == "__main__":
2770 print "Please run through oft script: ./oft --test_spec=basic"