blob: e8dec6e56e4a53b38866d2d598fe7e08225a7683 [file] [log] [blame]
Dan Talaycoc901f4d2010-03-07 21:55:45 -08001
Dan Talaycod2ca1032010-03-10 14:40:26 -08002import sys
Dan Talayco92c99122010-06-03 13:53:18 -07003import copy
Dan Talaycod2ca1032010-03-10 14:40:26 -08004
5try:
6 import scapy.all as scapy
7except:
8 try:
9 import scapy as scapy
10 except:
11 sys.exit("Need to install scapy for packet parsing")
Dan Talayco41eae8b2010-03-10 13:57:06 -080012
Rich Lane477f4812012-10-04 22:49:00 -070013from oftest import config
Dan Talaycoc901f4d2010-03-07 21:55:45 -080014import oftest.controller as controller
15import oftest.cstruct as ofp
16import oftest.message as message
17import oftest.dataplane as dataplane
18import oftest.action as action
Dan Talayco41eae8b2010-03-10 13:57:06 -080019import oftest.parse as parse
Dan Talaycoc901f4d2010-03-07 21:55:45 -080020import logging
Dan Talayco4b2bee62010-07-20 14:10:05 -070021import types
Dan Talayco73f84012012-10-02 09:23:18 -070022import time
Dan Talaycoc901f4d2010-03-07 21:55:45 -080023
Dan Talaycoba3745c2010-07-21 21:51:08 -070024global skipped_test_count
25skipped_test_count = 0
26
Dan Talayco551befa2010-07-15 17:05:32 -070027# Some useful defines
28IP_ETHERTYPE = 0x800
29TCP_PROTOCOL = 0x6
30UDP_PROTOCOL = 0x11
31
Jeffrey Townsend5cb7ed32012-08-17 18:11:01 +000032MINSIZE = 0
33
Rich Lane9a003812012-10-04 17:17:59 -070034def delete_all_flows(ctrl):
Dan Talayco41eae8b2010-03-10 13:57:06 -080035 """
36 Delete all flows on the switch
37 @param ctrl The controller object for the test
Dan Talayco41eae8b2010-03-10 13:57:06 -080038 """
39
Rich Lane9a003812012-10-04 17:17:59 -070040 logging.info("Deleting all flows")
Dan Talaycoc901f4d2010-03-07 21:55:45 -080041 msg = message.flow_mod()
42 msg.match.wildcards = ofp.OFPFW_ALL
Dan Talayco41eae8b2010-03-10 13:57:06 -080043 msg.out_port = ofp.OFPP_NONE
Dan Talaycoc901f4d2010-03-07 21:55:45 -080044 msg.command = ofp.OFPFC_DELETE
45 msg.buffer_id = 0xffffffff
Rich Lane5c3151c2013-01-03 17:15:41 -080046 ctrl.message_send(msg)
Rich Lane32bf9482013-01-03 17:26:30 -080047 return 0 # for backwards compatibility
Dan Talayco41eae8b2010-03-10 13:57:06 -080048
Ed Swierk99a74de2012-08-22 06:40:54 -070049def required_wildcards(parent):
Rich Lane2014f9b2012-10-05 15:29:40 -070050 w = test_param_get('required_wildcards', default='default')
Ed Swierk99a74de2012-08-22 06:40:54 -070051 if w == 'l3-l4':
52 return (ofp.OFPFW_NW_SRC_ALL | ofp.OFPFW_NW_DST_ALL | ofp.OFPFW_NW_TOS
53 | ofp.OFPFW_NW_PROTO | ofp.OFPFW_TP_SRC | ofp.OFPFW_TP_DST)
54 else:
55 return 0
56
Dan Talayco41eae8b2010-03-10 13:57:06 -080057def simple_tcp_packet(pktlen=100,
58 dl_dst='00:01:02:03:04:05',
59 dl_src='00:06:07:08:09:0a',
Tatsuya Yabe460321e2010-05-25 17:50:49 -070060 dl_vlan_enable=False,
61 dl_vlan=0,
62 dl_vlan_pcp=0,
Dan Talayco551befa2010-07-15 17:05:32 -070063 dl_vlan_cfi=0,
Dan Talayco41eae8b2010-03-10 13:57:06 -080064 ip_src='192.168.0.1',
65 ip_dst='192.168.0.2',
Tatsuya Yabe460321e2010-05-25 17:50:49 -070066 ip_tos=0,
Dan Talayco41eae8b2010-03-10 13:57:06 -080067 tcp_sport=1234,
Christian Dickmann8b59b4b2012-09-23 16:48:30 -070068 tcp_dport=80,
69 ip_ihl=None,
70 ip_options=False
Dan Talayco41eae8b2010-03-10 13:57:06 -080071 ):
72 """
73 Return a simple dataplane TCP packet
74
75 Supports a few parameters:
76 @param len Length of packet in bytes w/o CRC
77 @param dl_dst Destinatino MAC
78 @param dl_src Source MAC
Tatsuya Yabe460321e2010-05-25 17:50:49 -070079 @param dl_vlan_enable True if the packet is with vlan, False otherwise
80 @param dl_vlan VLAN ID
81 @param dl_vlan_pcp VLAN priority
Dan Talayco41eae8b2010-03-10 13:57:06 -080082 @param ip_src IP source
83 @param ip_dst IP destination
Tatsuya Yabe460321e2010-05-25 17:50:49 -070084 @param ip_tos IP ToS
Dan Talayco41eae8b2010-03-10 13:57:06 -080085 @param tcp_dport TCP destination port
86 @param ip_sport TCP source port
87
88 Generates a simple TCP request. Users
89 shouldn't assume anything about this packet other than that
90 it is a valid ethernet/IP/TCP frame.
91 """
Jeffrey Townsend5cb7ed32012-08-17 18:11:01 +000092
93 if MINSIZE > pktlen:
94 pktlen = MINSIZE
95
Dan Talayco551befa2010-07-15 17:05:32 -070096 # Note Dot1Q.id is really CFI
Shudong Zhou43ee54c2012-12-13 15:52:37 -080097 if (dl_vlan_enable):
Tatsuya Yabe460321e2010-05-25 17:50:49 -070098 pkt = scapy.Ether(dst=dl_dst, src=dl_src)/ \
Dan Talayco551befa2010-07-15 17:05:32 -070099 scapy.Dot1Q(prio=dl_vlan_pcp, id=dl_vlan_cfi, vlan=dl_vlan)/ \
Christian Dickmann8b59b4b2012-09-23 16:48:30 -0700100 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ihl=ip_ihl)/ \
Tatsuya Yabe460321e2010-05-25 17:50:49 -0700101 scapy.TCP(sport=tcp_sport, dport=tcp_dport)
102 else:
Christian Dickmann8b59b4b2012-09-23 16:48:30 -0700103 if not ip_options:
104 pkt = scapy.Ether(dst=dl_dst, src=dl_src)/ \
105 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ihl=ip_ihl)/ \
106 scapy.TCP(sport=tcp_sport, dport=tcp_dport)
107 else:
108 pkt = scapy.Ether(dst=dl_dst, src=dl_src)/ \
109 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ihl=ip_ihl, options=ip_options)/ \
110 scapy.TCP(sport=tcp_sport, dport=tcp_dport)
Tatsuya Yabe460321e2010-05-25 17:50:49 -0700111
Dan Talayco41eae8b2010-03-10 13:57:06 -0800112 pkt = pkt/("D" * (pktlen - len(pkt)))
113
114 return pkt
115
Rich Lane6ee7bea2012-10-26 16:19:29 -0700116def simple_udp_packet(pktlen=100,
117 dl_dst='00:01:02:03:04:05',
118 dl_src='00:06:07:08:09:0a',
119 dl_vlan_enable=False,
120 dl_vlan=0,
121 dl_vlan_pcp=0,
122 dl_vlan_cfi=0,
123 ip_src='192.168.0.1',
124 ip_dst='192.168.0.2',
125 ip_tos=0,
126 udp_sport=1234,
127 udp_dport=80,
128 ip_ihl=None,
129 ip_options=False
130 ):
131 """
132 Return a simple dataplane UDP packet
133
134 Supports a few parameters:
135 @param len Length of packet in bytes w/o CRC
136 @param dl_dst Destination MAC
137 @param dl_src Source MAC
138 @param dl_vlan_enable True if the packet is with vlan, False otherwise
139 @param dl_vlan VLAN ID
140 @param dl_vlan_pcp VLAN priority
141 @param ip_src IP source
142 @param ip_dst IP destination
143 @param ip_tos IP ToS
144 @param udp_dport UDP destination port
145 @param udp_sport UDP source port
146
147 Generates a simple UDP packet. Users shouldn't assume anything about
148 this packet other than that it is a valid ethernet/IP/UDP frame.
149 """
150
151 if MINSIZE > pktlen:
152 pktlen = MINSIZE
153
154 # Note Dot1Q.id is really CFI
155 if (dl_vlan_enable):
156 pkt = scapy.Ether(dst=dl_dst, src=dl_src)/ \
157 scapy.Dot1Q(prio=dl_vlan_pcp, id=dl_vlan_cfi, vlan=dl_vlan)/ \
158 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ihl=ip_ihl)/ \
159 scapy.UDP(sport=udp_sport, dport=udp_dport)
160 else:
161 if not ip_options:
162 pkt = scapy.Ether(dst=dl_dst, src=dl_src)/ \
163 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ihl=ip_ihl)/ \
164 scapy.UDP(sport=udp_sport, dport=udp_dport)
165 else:
166 pkt = scapy.Ether(dst=dl_dst, src=dl_src)/ \
167 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ihl=ip_ihl, options=ip_options)/ \
168 scapy.UDP(sport=udp_sport, dport=udp_dport)
169
170 pkt = pkt/("D" * (pktlen - len(pkt)))
171
172 return pkt
173
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700174def simple_icmp_packet(pktlen=60,
175 dl_dst='00:01:02:03:04:05',
176 dl_src='00:06:07:08:09:0a',
177 dl_vlan_enable=False,
178 dl_vlan=0,
179 dl_vlan_pcp=0,
180 ip_src='192.168.0.1',
181 ip_dst='192.168.0.2',
182 ip_tos=0,
183 icmp_type=8,
184 icmp_code=0
185 ):
186 """
187 Return a simple ICMP packet
188
189 Supports a few parameters:
190 @param len Length of packet in bytes w/o CRC
191 @param dl_dst Destinatino MAC
192 @param dl_src Source MAC
193 @param dl_vlan_enable True if the packet is with vlan, False otherwise
194 @param dl_vlan VLAN ID
195 @param dl_vlan_pcp VLAN priority
196 @param ip_src IP source
197 @param ip_dst IP destination
198 @param ip_tos IP ToS
199 @param icmp_type ICMP type
200 @param icmp_code ICMP code
201
202 Generates a simple ICMP ECHO REQUEST. Users
203 shouldn't assume anything about this packet other than that
204 it is a valid ethernet/ICMP frame.
205 """
Jeffrey Townsend5cb7ed32012-08-17 18:11:01 +0000206
207 if MINSIZE > pktlen:
208 pktlen = MINSIZE
209
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700210 if (dl_vlan_enable):
211 pkt = scapy.Ether(dst=dl_dst, src=dl_src)/ \
212 scapy.Dot1Q(prio=dl_vlan_pcp, id=0, vlan=dl_vlan)/ \
213 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos)/ \
214 scapy.ICMP(type=icmp_type, code=icmp_code)
215 else:
216 pkt = scapy.Ether(dst=dl_dst, src=dl_src)/ \
217 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos)/ \
218 scapy.ICMP(type=icmp_type, code=icmp_code)
219
220 pkt = pkt/("0" * (pktlen - len(pkt)))
221
222 return pkt
223
Ed Swierk0aeff8c2012-03-23 20:27:18 -0700224def simple_eth_packet(pktlen=60,
225 dl_dst='00:01:02:03:04:05',
226 dl_src='01:80:c2:00:00:00',
227 dl_type=0x88cc):
Jeffrey Townsend5cb7ed32012-08-17 18:11:01 +0000228
229 if MINSIZE > pktlen:
230 pktlen = MINSIZE
231
Ed Swierk0aeff8c2012-03-23 20:27:18 -0700232 pkt = scapy.Ether(dst=dl_dst, src=dl_src, type=dl_type)
233
234 pkt = pkt/("0" * (pktlen - len(pkt)))
235
236 return pkt
237
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800238def qinq_tcp_packet(pktlen=100,
239 dl_dst='00:01:02:03:04:05',
240 dl_src='00:06:07:08:09:0a',
241 dl_vlan_outer=20,
242 dl_vlan_pcp_outer=0,
243 dl_vlan_cfi_outer=0,
244 dl_vlan=10,
245 dl_vlan_pcp=0,
246 dl_vlan_cfi=0,
247 ip_src='192.168.0.1',
248 ip_dst='192.168.0.2',
249 ip_tos=0,
250 tcp_sport=1234,
251 tcp_dport=80,
252 ip_ihl=None,
253 ip_options=False
254 ):
255 """
256 Return a doubly tagged dataplane TCP packet
257
258 Supports a few parameters:
259 @param len Length of packet in bytes w/o CRC
260 @param dl_dst Destinatino MAC
261 @param dl_src Source MAC
262 @param dl_vlan_outer Outer VLAN ID
263 @param dl_vlan_pcp_outer Outer VLAN priority
264 @param dl_vlan_cfi_outer Outer VLAN cfi bit
265 @param dl_vlan Inner VLAN ID
266 @param dl_vlan_pcp VLAN priority
267 @param dl_vlan_cfi VLAN cfi bit
268 @param ip_src IP source
269 @param ip_dst IP destination
270 @param ip_tos IP ToS
271 @param tcp_dport TCP destination port
272 @param ip_sport TCP source port
273
274 Generates a TCP request. Users
275 shouldn't assume anything about this packet other than that
276 it is a valid ethernet/IP/TCP frame.
277 """
278
279 if MINSIZE > pktlen:
280 pktlen = MINSIZE
281
282 # Note Dot1Q.id is really CFI
283 pkt = scapy.Ether(dst=dl_dst, src=dl_src)/ \
284 scapy.Dot1Q(prio=dl_vlan_pcp_outer, id=dl_vlan_cfi_outer, vlan=dl_vlan_outer)/ \
285 scapy.Dot1Q(prio=dl_vlan_pcp, id=dl_vlan_cfi, vlan=dl_vlan)/ \
286 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ihl=ip_ihl)/ \
287 scapy.TCP(sport=tcp_sport, dport=tcp_dport)
288
289 pkt = pkt/("D" * (pktlen - len(pkt)))
290
291 return pkt
292
Shudong Zhoub7f12462012-11-20 13:01:12 -0800293def do_barrier(ctrl, timeout=-1):
Dan Talayco0fc08bd2012-04-09 16:56:18 -0700294 """
295 Do a barrier command
296 Return 0 on success, -1 on error
297 """
Dan Talayco41eae8b2010-03-10 13:57:06 -0800298 b = message.barrier_request()
Shudong Zhoub7f12462012-11-20 13:01:12 -0800299 (resp, pkt) = ctrl.transact(b, timeout=timeout)
Rich Lane3a261d52013-01-03 17:45:08 -0800300 if resp is None:
301 raise AssertionError("barrier failed")
Dan Talaycof6b94832012-04-12 21:50:57 -0700302 # We'll trust the transaction processing in the controller that xid matched
Rich Lane3a261d52013-01-03 17:45:08 -0800303 return 0 # for backwards compatibility
Dan Talayco92c99122010-06-03 13:53:18 -0700304
Rich Lane9a003812012-10-04 17:17:59 -0700305def port_config_get(controller, port_no):
Dan Talayco92c99122010-06-03 13:53:18 -0700306 """
307 Get a port's configuration
308
309 Gets the switch feature configuration and grabs one port's
310 configuration
311
312 @returns (hwaddr, config, advert) The hwaddress, configuration and
313 advertised values
314 """
315 request = message.features_request()
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700316 reply, pkt = controller.transact(request)
Rich Lane9a003812012-10-04 17:17:59 -0700317 logging.debug(reply.show())
Dan Talayco92c99122010-06-03 13:53:18 -0700318 if reply is None:
Rich Lane9a003812012-10-04 17:17:59 -0700319 logging.warn("Get feature request failed")
Dan Talayco92c99122010-06-03 13:53:18 -0700320 return None, None, None
321 for idx in range(len(reply.ports)):
322 if reply.ports[idx].port_no == port_no:
323 return (reply.ports[idx].hw_addr, reply.ports[idx].config,
324 reply.ports[idx].advertised)
325
Rich Lane9a003812012-10-04 17:17:59 -0700326 logging.warn("Did not find port number for port config")
Dan Talayco92c99122010-06-03 13:53:18 -0700327 return None, None, None
328
Rich Lane9a003812012-10-04 17:17:59 -0700329def port_config_set(controller, port_no, config, mask):
Dan Talayco92c99122010-06-03 13:53:18 -0700330 """
331 Set the port configuration according the given parameters
332
333 Gets the switch feature configuration and updates one port's
334 configuration value according to config and mask
335 """
Rich Lane9a003812012-10-04 17:17:59 -0700336 logging.info("Setting port " + str(port_no) + " to config " + str(config))
Dan Talayco92c99122010-06-03 13:53:18 -0700337 request = message.features_request()
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700338 reply, pkt = controller.transact(request)
Dan Talayco92c99122010-06-03 13:53:18 -0700339 if reply is None:
340 return -1
Rich Lane9a003812012-10-04 17:17:59 -0700341 logging.debug(reply.show())
Dan Talayco92c99122010-06-03 13:53:18 -0700342 for idx in range(len(reply.ports)):
343 if reply.ports[idx].port_no == port_no:
344 break
345 if idx >= len(reply.ports):
346 return -1
347 mod = message.port_mod()
348 mod.port_no = port_no
349 mod.hw_addr = reply.ports[idx].hw_addr
350 mod.config = config
351 mod.mask = mask
352 mod.advertise = reply.ports[idx].advertised
Rich Lane5c3151c2013-01-03 17:15:41 -0800353 controller.message_send(mod)
354 return 0
Dan Talayco92c99122010-06-03 13:53:18 -0700355
Rich Lane2014f9b2012-10-05 15:29:40 -0700356def receive_pkt_check(dp, pkt, yes_ports, no_ports, assert_if):
Dan Talayco92c99122010-06-03 13:53:18 -0700357 """
358 Check for proper receive packets across all ports
Ken Chiang1bf01602012-04-04 10:48:23 -0700359 @param dp The dataplane object
Dan Talayco92c99122010-06-03 13:53:18 -0700360 @param pkt Expected packet; may be None if yes_ports is empty
361 @param yes_ports Set or list of ports that should recieve packet
362 @param no_ports Set or list of ports that should not receive packet
363 @param assert_if Object that implements assertXXX
364 """
Rich Lane91765672012-12-06 16:33:04 -0800365
366 # Wait this long for packets that we don't expect to receive.
367 # 100ms is (rarely) too short for positive tests on slow
368 # switches but is definitely not too short for a negative test.
369 negative_timeout = 0.1
370
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700371 exp_pkt_arg = None
Rich Lane2014f9b2012-10-05 15:29:40 -0700372 if config["relax"]:
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700373 exp_pkt_arg = pkt
374
Dan Talayco92c99122010-06-03 13:53:18 -0700375 for ofport in yes_ports:
Rich Lane9a003812012-10-04 17:17:59 -0700376 logging.debug("Checking for pkt on port " + str(ofport))
Ken Chiang1bf01602012-04-04 10:48:23 -0700377 (rcv_port, rcv_pkt, pkt_time) = dp.poll(
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700378 port_number=ofport, exp_pkt=exp_pkt_arg)
Dan Talayco92c99122010-06-03 13:53:18 -0700379 assert_if.assertTrue(rcv_pkt is not None,
380 "Did not receive pkt on " + str(ofport))
Ken Chiang1bf01602012-04-04 10:48:23 -0700381 if not dataplane.match_exp_pkt(pkt, rcv_pkt):
Rich Lane9a003812012-10-04 17:17:59 -0700382 logging.debug("Sent %s" % format_packet(pkt))
383 logging.debug("Resp %s" % format_packet(rcv_pkt))
Ken Chiang1bf01602012-04-04 10:48:23 -0700384 assert_if.assertTrue(dataplane.match_exp_pkt(pkt, rcv_pkt),
385 "Response packet does not match send packet " +
386 "on port " + str(ofport))
Dan Talayco73f84012012-10-02 09:23:18 -0700387 if len(no_ports) > 0:
Rich Lane91765672012-12-06 16:33:04 -0800388 time.sleep(negative_timeout)
Dan Talayco92c99122010-06-03 13:53:18 -0700389 for ofport in no_ports:
Rich Lane9a003812012-10-04 17:17:59 -0700390 logging.debug("Negative check for pkt on port " + str(ofport))
Ken Chiang1bf01602012-04-04 10:48:23 -0700391 (rcv_port, rcv_pkt, pkt_time) = dp.poll(
Rich Lane91765672012-12-06 16:33:04 -0800392 port_number=ofport, timeout=0, exp_pkt=exp_pkt_arg)
Dan Talayco92c99122010-06-03 13:53:18 -0700393 assert_if.assertTrue(rcv_pkt is None,
394 "Unexpected pkt on port " + str(ofport))
Dan Talayco551befa2010-07-15 17:05:32 -0700395
396
Dan Talaycoc948d0b2012-03-23 12:17:54 -0700397def receive_pkt_verify(parent, egr_ports, exp_pkt, ing_port):
Dan Talayco551befa2010-07-15 17:05:32 -0700398 """
399 Receive a packet and verify it matches an expected value
Dan Talaycof6e76c02012-03-23 10:56:12 -0700400 @param egr_port A single port or list of ports
Dan Talayco551befa2010-07-15 17:05:32 -0700401
402 parent must implement dataplane, assertTrue and assertEqual
403 """
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700404 exp_pkt_arg = None
Rich Lane477f4812012-10-04 22:49:00 -0700405 if config["relax"]:
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700406 exp_pkt_arg = exp_pkt
407
Dan Talaycof6e76c02012-03-23 10:56:12 -0700408 if type(egr_ports) == type([]):
409 egr_port_list = egr_ports
410 else:
411 egr_port_list = [egr_ports]
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700412
Dan Talaycof6e76c02012-03-23 10:56:12 -0700413 # Expect a packet from each port on egr port list
414 for egr_port in egr_port_list:
Dan Talaycod8ae7582012-03-23 12:24:56 -0700415 check_port = egr_port
Dan Talaycoc948d0b2012-03-23 12:17:54 -0700416 if egr_port == ofp.OFPP_IN_PORT:
Dan Talaycod8ae7582012-03-23 12:24:56 -0700417 check_port = ing_port
Dan Talaycof6e76c02012-03-23 10:56:12 -0700418 (rcv_port, rcv_pkt, pkt_time) = parent.dataplane.poll(
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700419 port_number=check_port, exp_pkt=exp_pkt_arg)
Dan Talayco551befa2010-07-15 17:05:32 -0700420
Dan Talaycof6e76c02012-03-23 10:56:12 -0700421 if rcv_pkt is None:
Rich Lane9a003812012-10-04 17:17:59 -0700422 logging.error("ERROR: No packet received from " +
Dan Talaycod8ae7582012-03-23 12:24:56 -0700423 str(check_port))
Dan Talayco551befa2010-07-15 17:05:32 -0700424
Dan Talaycof6e76c02012-03-23 10:56:12 -0700425 parent.assertTrue(rcv_pkt is not None,
Dan Talaycod8ae7582012-03-23 12:24:56 -0700426 "Did not receive packet port " + str(check_port))
Rich Lane9a003812012-10-04 17:17:59 -0700427 logging.debug("Packet len " + str(len(rcv_pkt)) + " in on " +
Dan Talaycof6e76c02012-03-23 10:56:12 -0700428 str(rcv_port))
429
430 if str(exp_pkt) != str(rcv_pkt):
Rich Lane9a003812012-10-04 17:17:59 -0700431 logging.error("ERROR: Packet match failed.")
432 logging.debug("Expected len " + str(len(exp_pkt)) + ": "
Dan Talaycof6e76c02012-03-23 10:56:12 -0700433 + str(exp_pkt).encode('hex'))
Rich Lane9a003812012-10-04 17:17:59 -0700434 logging.debug("Received len " + str(len(rcv_pkt)) + ": "
Dan Talaycof6e76c02012-03-23 10:56:12 -0700435 + str(rcv_pkt).encode('hex'))
Rich Lane5d7e89a2012-10-26 16:43:13 -0700436 logging.debug("Expected packet: " + inspect_packet(scapy.Ether(str(exp_pkt))))
437 logging.debug("Received packet: " + inspect_packet(scapy.Ether(str(rcv_pkt))))
Dan Talaycof6e76c02012-03-23 10:56:12 -0700438 parent.assertEqual(str(exp_pkt), str(rcv_pkt),
Dan Talaycod8ae7582012-03-23 12:24:56 -0700439 "Packet match error on port " + str(check_port))
Dan Talaycof6e76c02012-03-23 10:56:12 -0700440
Dan Talayco551befa2010-07-15 17:05:32 -0700441def match_verify(parent, req_match, res_match):
442 """
443 Verify flow matches agree; if they disagree, report where
444
445 parent must implement assertEqual
446 Use str() to ensure content is compared and not pointers
447 """
448
449 parent.assertEqual(req_match.wildcards, res_match.wildcards,
450 'Match failed: wildcards: ' + hex(req_match.wildcards) +
451 " != " + hex(res_match.wildcards))
452 parent.assertEqual(req_match.in_port, res_match.in_port,
453 'Match failed: in_port: ' + str(req_match.in_port) +
454 " != " + str(res_match.in_port))
455 parent.assertEqual(str(req_match.dl_src), str(res_match.dl_src),
456 'Match failed: dl_src: ' + str(req_match.dl_src) +
457 " != " + str(res_match.dl_src))
458 parent.assertEqual(str(req_match.dl_dst), str(res_match.dl_dst),
459 'Match failed: dl_dst: ' + str(req_match.dl_dst) +
460 " != " + str(res_match.dl_dst))
461 parent.assertEqual(req_match.dl_vlan, res_match.dl_vlan,
462 'Match failed: dl_vlan: ' + str(req_match.dl_vlan) +
463 " != " + str(res_match.dl_vlan))
464 parent.assertEqual(req_match.dl_vlan_pcp, res_match.dl_vlan_pcp,
465 'Match failed: dl_vlan_pcp: ' +
466 str(req_match.dl_vlan_pcp) + " != " +
467 str(res_match.dl_vlan_pcp))
468 parent.assertEqual(req_match.dl_type, res_match.dl_type,
469 'Match failed: dl_type: ' + str(req_match.dl_type) +
470 " != " + str(res_match.dl_type))
471
472 if (not(req_match.wildcards & ofp.OFPFW_DL_TYPE)
473 and (req_match.dl_type == IP_ETHERTYPE)):
474 parent.assertEqual(req_match.nw_tos, res_match.nw_tos,
475 'Match failed: nw_tos: ' + str(req_match.nw_tos) +
476 " != " + str(res_match.nw_tos))
477 parent.assertEqual(req_match.nw_proto, res_match.nw_proto,
478 'Match failed: nw_proto: ' + str(req_match.nw_proto) +
479 " != " + str(res_match.nw_proto))
480 parent.assertEqual(req_match.nw_src, res_match.nw_src,
481 'Match failed: nw_src: ' + str(req_match.nw_src) +
482 " != " + str(res_match.nw_src))
483 parent.assertEqual(req_match.nw_dst, res_match.nw_dst,
484 'Match failed: nw_dst: ' + str(req_match.nw_dst) +
485 " != " + str(res_match.nw_dst))
486
487 if (not(req_match.wildcards & ofp.OFPFW_NW_PROTO)
488 and ((req_match.nw_proto == TCP_PROTOCOL)
489 or (req_match.nw_proto == UDP_PROTOCOL))):
490 parent.assertEqual(req_match.tp_src, res_match.tp_src,
491 'Match failed: tp_src: ' +
492 str(req_match.tp_src) +
493 " != " + str(res_match.tp_src))
494 parent.assertEqual(req_match.tp_dst, res_match.tp_dst,
495 'Match failed: tp_dst: ' +
496 str(req_match.tp_dst) +
497 " != " + str(res_match.tp_dst))
498
Ed Swierk99a74de2012-08-22 06:40:54 -0700499def packet_to_flow_match(parent, packet):
500 match = parse.packet_to_flow_match(packet)
501 match.wildcards |= required_wildcards(parent)
502 return match
503
504def flow_msg_create(parent, pkt, ing_port=None, action_list=None, wildcards=None,
Dan Talaycof6e76c02012-03-23 10:56:12 -0700505 egr_ports=None, egr_queue=None, check_expire=False, in_band=False):
Dan Talayco551befa2010-07-15 17:05:32 -0700506 """
507 Create a flow message
508
509 Match on packet with given wildcards.
510 See flow_match_test for other parameter descriptoins
511 @param egr_queue if not None, make the output an enqueue action
Dan Talayco677c0b72011-08-23 22:53:38 -0700512 @param in_band if True, do not wildcard ingress port
Dan Talaycof6e76c02012-03-23 10:56:12 -0700513 @param egr_ports None (drop), single port or list of ports
Dan Talayco551befa2010-07-15 17:05:32 -0700514 """
515 match = parse.packet_to_flow_match(pkt)
516 parent.assertTrue(match is not None, "Flow match from pkt failed")
Ed Swierk99a74de2012-08-22 06:40:54 -0700517 if wildcards is None:
518 wildcards = required_wildcards(parent)
Dan Talayco677c0b72011-08-23 22:53:38 -0700519 if in_band:
520 wildcards &= ~ofp.OFPFW_IN_PORT
Dan Talayco551befa2010-07-15 17:05:32 -0700521 match.wildcards = wildcards
522 match.in_port = ing_port
523
Dan Talaycof6e76c02012-03-23 10:56:12 -0700524 if type(egr_ports) == type([]):
525 egr_port_list = egr_ports
526 else:
527 egr_port_list = [egr_ports]
528
Dan Talayco551befa2010-07-15 17:05:32 -0700529 request = message.flow_mod()
530 request.match = match
531 request.buffer_id = 0xffffffff
532 if check_expire:
533 request.flags |= ofp.OFPFF_SEND_FLOW_REM
534 request.hard_timeout = 1
535
536 if action_list is not None:
537 for act in action_list:
Rich Lane9a003812012-10-04 17:17:59 -0700538 logging.debug("Adding action " + act.show())
Rich Lanee30455b2013-01-03 16:24:44 -0800539 request.actions.add(act)
Dan Talayco551befa2010-07-15 17:05:32 -0700540
541 # Set up output/enqueue action if directed
542 if egr_queue is not None:
Dan Talaycof6e76c02012-03-23 10:56:12 -0700543 parent.assertTrue(egr_ports is not None, "Egress port not set")
Dan Talayco551befa2010-07-15 17:05:32 -0700544 act = action.action_enqueue()
Dan Talaycof6e76c02012-03-23 10:56:12 -0700545 for egr_port in egr_port_list:
546 act.port = egr_port
547 act.queue_id = egr_queue
Rich Lanee30455b2013-01-03 16:24:44 -0800548 request.actions.add(act)
Dan Talaycof6e76c02012-03-23 10:56:12 -0700549 elif egr_ports is not None:
550 for egr_port in egr_port_list:
551 act = action.action_output()
552 act.port = egr_port
Rich Lanee30455b2013-01-03 16:24:44 -0800553 request.actions.add(act)
Dan Talayco551befa2010-07-15 17:05:32 -0700554
Rich Lane9a003812012-10-04 17:17:59 -0700555 logging.debug(request.show())
Dan Talayco551befa2010-07-15 17:05:32 -0700556
557 return request
558
Jeffrey Townsendf3eae9c2012-03-28 18:23:21 -0700559def flow_msg_install(parent, request, clear_table_override=None):
Dan Talayco551befa2010-07-15 17:05:32 -0700560 """
561 Install a flow mod message in the switch
562
563 @param parent Must implement controller, assertEqual, assertTrue
564 @param request The request, all set to go
565 @param clear_table If true, clear the flow table before installing
566 """
Dan Talayco8a64e332012-03-28 14:53:20 -0700567
Rich Lane2014f9b2012-10-05 15:29:40 -0700568 clear_table = test_param_get('clear_table', default=True)
Jeffrey Townsendf3eae9c2012-03-28 18:23:21 -0700569 if(clear_table_override != None):
570 clear_table = clear_table_override
571
572 if clear_table:
Rich Lane9a003812012-10-04 17:17:59 -0700573 logging.debug("Clear flow table")
Rich Lane32bf9482013-01-03 17:26:30 -0800574 delete_all_flows(parent.controller)
Dan Talayco551befa2010-07-15 17:05:32 -0700575
Rich Lane9a003812012-10-04 17:17:59 -0700576 logging.debug("Insert flow")
Rich Lane5c3151c2013-01-03 17:15:41 -0800577 parent.controller.message_send(request)
Rich Lanee912d032012-12-22 14:28:33 -0800578
Rich Lane3a261d52013-01-03 17:45:08 -0800579 do_barrier(parent.controller)
Dan Talayco551befa2010-07-15 17:05:32 -0700580
Ed Swierk99a74de2012-08-22 06:40:54 -0700581def flow_match_test_port_pair(parent, ing_port, egr_ports, wildcards=None,
Dan Talayco551befa2010-07-15 17:05:32 -0700582 dl_vlan=-1, pkt=None, exp_pkt=None,
Rich Lanee5779d32012-10-05 17:56:04 -0700583 action_list=None):
Dan Talayco551befa2010-07-15 17:05:32 -0700584 """
585 Flow match test on single TCP packet
Dan Talaycof6e76c02012-03-23 10:56:12 -0700586 @param egr_ports A single port or list of ports
Dan Talayco551befa2010-07-15 17:05:32 -0700587
588 Run test with packet through switch from ing_port to egr_port
589 See flow_match_test for parameter descriptions
590 """
591
Ed Swierk99a74de2012-08-22 06:40:54 -0700592 if wildcards is None:
593 wildcards = required_wildcards(parent)
Rich Lane9a003812012-10-04 17:17:59 -0700594 logging.info("Pkt match test: " + str(ing_port) + " to " +
Dan Talaycof6e76c02012-03-23 10:56:12 -0700595 str(egr_ports))
Rich Lanee5779d32012-10-05 17:56:04 -0700596 logging.debug(" WC: " + hex(wildcards) + " vlan: " + str(dl_vlan))
Dan Talayco551befa2010-07-15 17:05:32 -0700597 if pkt is None:
598 pkt = simple_tcp_packet(dl_vlan_enable=(dl_vlan >= 0), dl_vlan=dl_vlan)
599
600 request = flow_msg_create(parent, pkt, ing_port=ing_port,
Dan Talaycof6e76c02012-03-23 10:56:12 -0700601 wildcards=wildcards, egr_ports=egr_ports,
Dan Talayco551befa2010-07-15 17:05:32 -0700602 action_list=action_list)
603
604 flow_msg_install(parent, request)
605
Rich Lane9a003812012-10-04 17:17:59 -0700606 logging.debug("Send packet: " + str(ing_port) + " to " +
Dan Talaycof6e76c02012-03-23 10:56:12 -0700607 str(egr_ports))
Dan Talayco551befa2010-07-15 17:05:32 -0700608 parent.dataplane.send(ing_port, str(pkt))
609
610 if exp_pkt is None:
611 exp_pkt = pkt
Dan Talaycoc948d0b2012-03-23 12:17:54 -0700612 receive_pkt_verify(parent, egr_ports, exp_pkt, ing_port)
Dan Talayco551befa2010-07-15 17:05:32 -0700613
Rich Lane89725bb2012-12-03 16:23:27 -0800614def flow_match_test_pktout(parent, ing_port, egr_ports,
615 dl_vlan=-1, pkt=None, exp_pkt=None,
616 action_list=None):
617 """
618 Packet-out test on single TCP packet
619 @param egr_ports A single port or list of ports
620
621 Run test sending packet-out to egr_ports. The goal is to test the actions
622 taken on the packet, not the matching which is of course irrelevant.
623 See flow_match_test for parameter descriptions
624 """
625
626 if pkt is None:
627 pkt = simple_tcp_packet(dl_vlan_enable=(dl_vlan >= 0), dl_vlan=dl_vlan)
628
629 msg = message.packet_out()
630 msg.in_port = ing_port
631 msg.data = str(pkt)
632 if action_list is not None:
633 for act in action_list:
Rich Lanee30455b2013-01-03 16:24:44 -0800634 msg.actions.add(act)
Rich Lane89725bb2012-12-03 16:23:27 -0800635
636 # Set up output action
637 if egr_ports is not None:
638 for egr_port in egr_ports:
639 act = action.action_output()
640 act.port = egr_port
Rich Lanee30455b2013-01-03 16:24:44 -0800641 msg.actions.add(act)
Rich Lane89725bb2012-12-03 16:23:27 -0800642
643 logging.debug(msg.show())
Rich Lane5c3151c2013-01-03 17:15:41 -0800644 parent.controller.message_send(msg)
Rich Lane89725bb2012-12-03 16:23:27 -0800645
646 if exp_pkt is None:
647 exp_pkt = pkt
648 receive_pkt_verify(parent, egr_ports, exp_pkt, ing_port)
649
Dan Talaycof6e76c02012-03-23 10:56:12 -0700650def get_egr_list(parent, of_ports, how_many, exclude_list=[]):
651 """
652 Generate a list of ports avoiding those in the exclude list
Rich Lane9a003812012-10-04 17:17:59 -0700653 @param parent Supplies logging
Dan Talaycof6e76c02012-03-23 10:56:12 -0700654 @param of_ports List of OF port numbers
655 @param how_many Number of ports to be added to the list
656 @param exclude_list List of ports not to be used
657 @returns An empty list if unable to find enough ports
658 """
659
Dan Talaycoc948d0b2012-03-23 12:17:54 -0700660 if how_many == 0:
661 return []
662
Dan Talaycof6e76c02012-03-23 10:56:12 -0700663 count = 0
664 egr_ports = []
665 for egr_idx in range(len(of_ports)):
666 if of_ports[egr_idx] not in exclude_list:
667 egr_ports.append(of_ports[egr_idx])
668 count += 1
669 if count >= how_many:
670 return egr_ports
Rich Lane9a003812012-10-04 17:17:59 -0700671 logging.debug("Could not generate enough egress ports for test")
Dan Talaycof6e76c02012-03-23 10:56:12 -0700672 return []
673
Ed Swierk99a74de2012-08-22 06:40:54 -0700674def flow_match_test(parent, port_map, wildcards=None, dl_vlan=-1, pkt=None,
Rich Lanee5779d32012-10-05 17:56:04 -0700675 exp_pkt=None, action_list=None,
Dan Talaycoc948d0b2012-03-23 12:17:54 -0700676 max_test=0, egr_count=1, ing_port=False):
Dan Talayco551befa2010-07-15 17:05:32 -0700677 """
Rich Lane89725bb2012-12-03 16:23:27 -0800678 Run flow_match_test_port_pair on all port pairs and packet-out
Dan Talayco551befa2010-07-15 17:05:32 -0700679
680 @param max_test If > 0 no more than this number of tests are executed.
681 @param parent Must implement controller, dataplane, assertTrue, assertEqual
Rich Lane9a003812012-10-04 17:17:59 -0700682 and logging
Dan Talayco551befa2010-07-15 17:05:32 -0700683 @param pkt If not None, use this packet for ingress
684 @param wildcards For flow match entry
Dan Talayco79184222010-11-01 12:24:29 -0700685 @param dl_vlan If not -1, and pkt is None, create a pkt w/ VLAN tag
Dan Talayco551befa2010-07-15 17:05:32 -0700686 @param exp_pkt If not None, use this as the expected output pkt; els use pkt
687 @param action_list Additional actions to add to flow mod
Dan Talaycocfa172f2012-03-23 12:03:00 -0700688 @param egr_count Number of egress ports; -1 means get from config w/ dflt 2
Dan Talayco551befa2010-07-15 17:05:32 -0700689 """
Ed Swierk99a74de2012-08-22 06:40:54 -0700690 if wildcards is None:
691 wildcards = required_wildcards(parent)
Dan Talayco551befa2010-07-15 17:05:32 -0700692 of_ports = port_map.keys()
693 of_ports.sort()
694 parent.assertTrue(len(of_ports) > 1, "Not enough ports for test")
695 test_count = 0
696
Dan Talaycocfa172f2012-03-23 12:03:00 -0700697 if egr_count == -1:
Rich Lane2014f9b2012-10-05 15:29:40 -0700698 egr_count = test_param_get('egr_count', default=2)
Dan Talaycocfa172f2012-03-23 12:03:00 -0700699
Dan Talayco551befa2010-07-15 17:05:32 -0700700 for ing_idx in range(len(of_ports)):
701 ingress_port = of_ports[ing_idx]
Dan Talaycof6e76c02012-03-23 10:56:12 -0700702 egr_ports = get_egr_list(parent, of_ports, egr_count,
703 exclude_list=[ingress_port])
Dan Talaycoc948d0b2012-03-23 12:17:54 -0700704 if ing_port:
705 egr_ports.append(ofp.OFPP_IN_PORT)
Dan Talaycof6e76c02012-03-23 10:56:12 -0700706 if len(egr_ports) == 0:
707 parent.assertTrue(0, "Failed to generate egress port list")
708
709 flow_match_test_port_pair(parent, ingress_port, egr_ports,
710 wildcards=wildcards, dl_vlan=dl_vlan,
711 pkt=pkt, exp_pkt=exp_pkt,
Rich Lanee5779d32012-10-05 17:56:04 -0700712 action_list=action_list)
Dan Talaycof6e76c02012-03-23 10:56:12 -0700713 test_count += 1
714 if (max_test > 0) and (test_count > max_test):
Rich Lane9a003812012-10-04 17:17:59 -0700715 logging.info("Ran " + str(test_count) + " tests; exiting")
Rich Lane89725bb2012-12-03 16:23:27 -0800716 break
717
718
719 ingress_port = of_ports[0]
720 egr_ports = get_egr_list(parent, of_ports, egr_count,
721 exclude_list=[ingress_port])
722 if ing_port:
723 egr_ports.append(ofp.OFPP_IN_PORT)
724 flow_match_test_pktout(parent, ingress_port, egr_ports,
725 dl_vlan=dl_vlan,
726 pkt=pkt, exp_pkt=exp_pkt,
727 action_list=action_list)
Dan Talayco551befa2010-07-15 17:05:32 -0700728
Rich Lane2014f9b2012-10-05 15:29:40 -0700729def test_param_get(key, default=None):
Dan Talayco4b2bee62010-07-20 14:10:05 -0700730 """
731 Return value passed via test-params if present
732
Dan Talayco4b2bee62010-07-20 14:10:05 -0700733 @param key The lookup key
734 @param default Default value to use if not found
735
736 If the pair 'key=val' appeared in the string passed to --test-params
737 on the command line, return val (as interpreted by exec). Otherwise
738 return default value.
Dan Talaycof6e76c02012-03-23 10:56:12 -0700739
740 WARNING: TEST PARAMETERS MUST BE PYTHON IDENTIFIERS;
741 eg egr_count, not egr-count.
Dan Talayco4b2bee62010-07-20 14:10:05 -0700742 """
743 try:
744 exec config["test_params"]
745 except:
746 return default
747
748 s = "val = " + str(key)
749 try:
750 exec s
751 return val
752 except:
753 return default
754
755def action_generate(parent, field_to_mod, mod_field_vals):
756 """
757 Create an action to modify the field indicated in field_to_mod
758
759 @param parent Must implement, assertTrue
760 @param field_to_mod The field to modify as a string name
761 @param mod_field_vals Hash of values to use for modified values
762 """
763
764 act = None
765
766 if field_to_mod in ['pktlen']:
767 return None
768
769 if field_to_mod == 'dl_dst':
770 act = action.action_set_dl_dst()
771 act.dl_addr = parse.parse_mac(mod_field_vals['dl_dst'])
772 elif field_to_mod == 'dl_src':
773 act = action.action_set_dl_src()
774 act.dl_addr = parse.parse_mac(mod_field_vals['dl_src'])
775 elif field_to_mod == 'dl_vlan_enable':
776 if not mod_field_vals['dl_vlan_enable']: # Strip VLAN tag
777 act = action.action_strip_vlan()
778 # Add VLAN tag is handled by dl_vlan field
779 # Will return None in this case
780 elif field_to_mod == 'dl_vlan':
781 act = action.action_set_vlan_vid()
782 act.vlan_vid = mod_field_vals['dl_vlan']
783 elif field_to_mod == 'dl_vlan_pcp':
784 act = action.action_set_vlan_pcp()
785 act.vlan_pcp = mod_field_vals['dl_vlan_pcp']
786 elif field_to_mod == 'ip_src':
787 act = action.action_set_nw_src()
788 act.nw_addr = parse.parse_ip(mod_field_vals['ip_src'])
789 elif field_to_mod == 'ip_dst':
790 act = action.action_set_nw_dst()
791 act.nw_addr = parse.parse_ip(mod_field_vals['ip_dst'])
792 elif field_to_mod == 'ip_tos':
793 act = action.action_set_nw_tos()
794 act.nw_tos = mod_field_vals['ip_tos']
795 elif field_to_mod == 'tcp_sport':
796 act = action.action_set_tp_src()
797 act.tp_port = mod_field_vals['tcp_sport']
798 elif field_to_mod == 'tcp_dport':
799 act = action.action_set_tp_dst()
800 act.tp_port = mod_field_vals['tcp_dport']
Rich Lane110e0e32012-10-26 16:21:46 -0700801 elif field_to_mod == 'udp_sport':
802 act = action.action_set_tp_src()
803 act.tp_port = mod_field_vals['udp_sport']
804 elif field_to_mod == 'udp_dport':
805 act = action.action_set_tp_dst()
806 act.tp_port = mod_field_vals['udp_dport']
Dan Talayco4b2bee62010-07-20 14:10:05 -0700807 else:
808 parent.assertTrue(0, "Unknown field to modify: " + str(field_to_mod))
809
810 return act
811
812def pkt_action_setup(parent, start_field_vals={}, mod_field_vals={},
Rich Lane110e0e32012-10-26 16:21:46 -0700813 mod_fields=[], tp="tcp", check_test_params=False):
Dan Talayco4b2bee62010-07-20 14:10:05 -0700814 """
815 Set up the ingress and expected packet and action list for a test
816
Rich Lane2014f9b2012-10-05 15:29:40 -0700817 @param parent Must implement assertTrue
Dan Talayco4b2bee62010-07-20 14:10:05 -0700818 @param start_field_values Field values to use for ingress packet (optional)
819 @param mod_field_values Field values to use for modified packet (optional)
820 @param mod_fields The list of fields to be modified by the switch in the test.
821 @params check_test_params If True, will check the parameters vid, add_vlan
822 and strip_vlan from the command line.
823
824 Returns a triple: pkt-to-send, expected-pkt, action-list
825 """
826
827 new_actions = []
828
Dan Talayco4b2bee62010-07-20 14:10:05 -0700829 base_pkt_params = {}
830 base_pkt_params['pktlen'] = 100
831 base_pkt_params['dl_dst'] = '00:DE:F0:12:34:56'
832 base_pkt_params['dl_src'] = '00:23:45:67:89:AB'
833 base_pkt_params['dl_vlan_enable'] = False
834 base_pkt_params['dl_vlan'] = 2
835 base_pkt_params['dl_vlan_pcp'] = 0
836 base_pkt_params['ip_src'] = '192.168.0.1'
837 base_pkt_params['ip_dst'] = '192.168.0.2'
838 base_pkt_params['ip_tos'] = 0
Rich Lane110e0e32012-10-26 16:21:46 -0700839 if tp == "tcp":
840 base_pkt_params['tcp_sport'] = 1234
841 base_pkt_params['tcp_dport'] = 80
842 elif tp == "udp":
843 base_pkt_params['udp_sport'] = 1234
844 base_pkt_params['udp_dport'] = 80
Dan Talayco4b2bee62010-07-20 14:10:05 -0700845 for keyname in start_field_vals.keys():
846 base_pkt_params[keyname] = start_field_vals[keyname]
847
848 mod_pkt_params = {}
849 mod_pkt_params['pktlen'] = 100
850 mod_pkt_params['dl_dst'] = '00:21:0F:ED:CB:A9'
851 mod_pkt_params['dl_src'] = '00:ED:CB:A9:87:65'
852 mod_pkt_params['dl_vlan_enable'] = False
853 mod_pkt_params['dl_vlan'] = 3
854 mod_pkt_params['dl_vlan_pcp'] = 7
855 mod_pkt_params['ip_src'] = '10.20.30.40'
856 mod_pkt_params['ip_dst'] = '50.60.70.80'
857 mod_pkt_params['ip_tos'] = 0xf0
Rich Lane110e0e32012-10-26 16:21:46 -0700858 if tp == "tcp":
859 mod_pkt_params['tcp_sport'] = 4321
860 mod_pkt_params['tcp_dport'] = 8765
861 elif tp == "udp":
862 mod_pkt_params['udp_sport'] = 4321
863 mod_pkt_params['udp_dport'] = 8765
Dan Talayco4b2bee62010-07-20 14:10:05 -0700864 for keyname in mod_field_vals.keys():
865 mod_pkt_params[keyname] = mod_field_vals[keyname]
866
867 # Check for test param modifications
868 strip = False
869 if check_test_params:
Rich Lane2014f9b2012-10-05 15:29:40 -0700870 add_vlan = test_param_get('add_vlan')
871 strip_vlan = test_param_get('strip_vlan')
872 vid = test_param_get('vid')
Dan Talayco4b2bee62010-07-20 14:10:05 -0700873
874 if add_vlan and strip_vlan:
875 parent.assertTrue(0, "Add and strip VLAN both specified")
876
877 if vid:
878 base_pkt_params['dl_vlan_enable'] = True
879 base_pkt_params['dl_vlan'] = vid
880 if 'dl_vlan' in mod_fields:
881 mod_pkt_params['dl_vlan'] = vid + 1
882
883 if add_vlan:
884 base_pkt_params['dl_vlan_enable'] = False
885 mod_pkt_params['dl_vlan_enable'] = True
886 mod_pkt_params['pktlen'] = base_pkt_params['pktlen'] + 4
887 mod_fields.append('pktlen')
888 mod_fields.append('dl_vlan_enable')
889 if 'dl_vlan' not in mod_fields:
890 mod_fields.append('dl_vlan')
891 elif strip_vlan:
892 base_pkt_params['dl_vlan_enable'] = True
893 mod_pkt_params['dl_vlan_enable'] = False
894 mod_pkt_params['pktlen'] = base_pkt_params['pktlen'] - 4
895 mod_fields.append('dl_vlan_enable')
896 mod_fields.append('pktlen')
897
Rich Lane110e0e32012-10-26 16:21:46 -0700898 if tp == "tcp":
899 packet_builder = simple_tcp_packet
900 elif tp == "udp":
901 packet_builder = simple_udp_packet
902 else:
903 raise NotImplementedError("unknown transport protocol %s" % tp)
904
Dan Talayco4b2bee62010-07-20 14:10:05 -0700905 # Build the ingress packet
Rich Lane110e0e32012-10-26 16:21:46 -0700906 ingress_pkt = packet_builder(**base_pkt_params)
Dan Talayco4b2bee62010-07-20 14:10:05 -0700907
908 # Build the expected packet, modifying the indicated fields
909 for item in mod_fields:
910 base_pkt_params[item] = mod_pkt_params[item]
911 act = action_generate(parent, item, mod_pkt_params)
912 if act:
913 new_actions.append(act)
914
Rich Lane110e0e32012-10-26 16:21:46 -0700915 expected_pkt = packet_builder(**base_pkt_params)
Dan Talayco4b2bee62010-07-20 14:10:05 -0700916
917 return (ingress_pkt, expected_pkt, new_actions)
Dan Talayco677c0b72011-08-23 22:53:38 -0700918
919# Generate a simple "drop" flow mod
920# If in_band is true, then only drop from first test port
921def flow_mod_gen(port_map, in_band):
922 request = message.flow_mod()
923 request.match.wildcards = ofp.OFPFW_ALL
924 if in_band:
925 request.match.wildcards = ofp.OFPFW_ALL - ofp.OFPFW_IN_PORT
926 for of_port, ifname in port_map.items(): # Grab first port
927 break
928 request.match.in_port = of_port
929 request.buffer_id = 0xffffffff
930 return request
Dan Talaycoba3745c2010-07-21 21:51:08 -0700931
932def skip_message_emit(parent, s):
933 """
934 Print out a 'skipped' message to stderr
935
936 @param s The string to print out to the log file
Rich Lane9a003812012-10-04 17:17:59 -0700937 @param parent Must implement config object
Dan Talaycoba3745c2010-07-21 21:51:08 -0700938 """
939 global skipped_test_count
940
941 skipped_test_count += 1
Rich Lane9a003812012-10-04 17:17:59 -0700942 logging.info("Skipping: " + s)
Rich Lane477f4812012-10-04 22:49:00 -0700943 if config["dbg_level"] < logging.WARNING:
Dan Talaycoba3745c2010-07-21 21:51:08 -0700944 sys.stderr.write("(skipped) ")
945 else:
946 sys.stderr.write("(S)")
Dan Talayco677c0b72011-08-23 22:53:38 -0700947
Dan Talayco8a64e332012-03-28 14:53:20 -0700948
949def all_stats_get(parent):
950 """
951 Get the aggregate stats for all flows in the table
952 @param parent Test instance with controller connection and assert
953 @returns dict with keys flows, packets, bytes, active (flows),
954 lookups, matched
955 """
956 stat_req = message.aggregate_stats_request()
957 stat_req.match = ofp.ofp_match()
958 stat_req.match.wildcards = ofp.OFPFW_ALL
959 stat_req.table_id = 0xff
960 stat_req.out_port = ofp.OFPP_NONE
961
962 rv = {}
963
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700964 (reply, pkt) = parent.controller.transact(stat_req)
Dan Talayco8a64e332012-03-28 14:53:20 -0700965 parent.assertTrue(len(reply.stats) == 1, "Did not receive flow stats reply")
966
967 for obj in reply.stats:
968 (rv["flows"], rv["packets"], rv["bytes"]) = (obj.flow_count,
969 obj.packet_count, obj.byte_count)
970 break
971
972 request = message.table_stats_request()
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700973 (reply , pkt) = parent.controller.transact(request)
Dan Talayco8a64e332012-03-28 14:53:20 -0700974
975
976 (rv["active"], rv["lookups"], rv["matched"]) = (0,0,0)
977 for obj in reply.stats:
978 rv["active"] += obj.active_count
979 rv["lookups"] += obj.lookup_count
980 rv["matched"] += obj.matched_count
981
982 return rv
Dan Talayco2baf8b52012-03-30 09:55:42 -0700983
984FILTER=''.join([(len(repr(chr(x)))==3) and chr(x) or '.'
985 for x in range(256)])
986
987def hex_dump_buffer(src, length=16):
988 """
989 Convert src to a hex dump string and return the string
990 @param src The source buffer
991 @param length The number of bytes shown in each line
992 @returns A string showing the hex dump
993 """
Dan Talaycoc516fa02012-04-12 22:28:43 -0700994 result = ["\n"]
Dan Talayco2baf8b52012-03-30 09:55:42 -0700995 for i in xrange(0, len(src), length):
996 chars = src[i:i+length]
997 hex = ' '.join(["%02x" % ord(x) for x in chars])
998 printable = ''.join(["%s" % ((ord(x) <= 127 and
999 FILTER[ord(x)]) or '.') for x in chars])
1000 result.append("%04x %-*s %s\n" % (i, length*3, hex, printable))
1001 return ''.join(result)
1002
1003def format_packet(pkt):
1004 return "Packet length %d \n%s" % (len(str(pkt)),
1005 hex_dump_buffer(str(pkt)))
Rich Lane5d7e89a2012-10-26 16:43:13 -07001006
1007def inspect_packet(pkt):
1008 """
1009 Wrapper around scapy's show() method.
1010 @returns A string showing the dissected packet.
1011 """
1012 from cStringIO import StringIO
1013 out = None
1014 backup = sys.stdout
1015 try:
1016 sys.stdout = StringIO()
1017 pkt.show2()
1018 out = sys.stdout.getvalue()
1019 sys.stdout.close()
1020 finally:
1021 sys.stdout = backup
1022 return out
Rich Lane0a4f6372013-01-02 14:40:22 -08001023
1024def nonstandard(cls):
1025 """
Rich Lanecc45b8e2013-01-02 15:55:02 -08001026 Testcase decorator that marks the test as being non-standard.
1027 These tests are not automatically added to the "standard" group.
Rich Lane0a4f6372013-01-02 14:40:22 -08001028 """
Rich Lanecc45b8e2013-01-02 15:55:02 -08001029 cls._nonstandard = True
Rich Lane0a4f6372013-01-02 14:40:22 -08001030 return cls
1031
1032def disabled(cls):
1033 """
Rich Lanecc45b8e2013-01-02 15:55:02 -08001034 Testcase decorator that marks the test as being disabled.
1035 These tests are not automatically added to the "standard" group or
1036 their module's group.
Rich Lane0a4f6372013-01-02 14:40:22 -08001037 """
Rich Lanecc45b8e2013-01-02 15:55:02 -08001038 cls._disabled = True
Rich Lane0a4f6372013-01-02 14:40:22 -08001039 return cls
Rich Lane97e99652013-01-02 17:23:20 -08001040
1041def group(name):
1042 """
1043 Testcase decorator that adds the test to a group.
1044 """
1045 def fn(cls):
1046 if not hasattr(cls, "_groups"):
1047 cls._groups = []
1048 cls._groups.append(name)
1049 return cls
1050 return fn