blob: fef34f400b9fcf035fac5279e841d94a9ce881d0 [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
Dan Talayco41eae8b2010-03-10 13:57:06 -080046 return ctrl.message_send(msg)
47
Ed Swierk99a74de2012-08-22 06:40:54 -070048def required_wildcards(parent):
Rich Lane2014f9b2012-10-05 15:29:40 -070049 w = test_param_get('required_wildcards', default='default')
Ed Swierk99a74de2012-08-22 06:40:54 -070050 if w == 'l3-l4':
51 return (ofp.OFPFW_NW_SRC_ALL | ofp.OFPFW_NW_DST_ALL | ofp.OFPFW_NW_TOS
52 | ofp.OFPFW_NW_PROTO | ofp.OFPFW_TP_SRC | ofp.OFPFW_TP_DST)
53 else:
54 return 0
55
Dan Talayco41eae8b2010-03-10 13:57:06 -080056def simple_tcp_packet(pktlen=100,
57 dl_dst='00:01:02:03:04:05',
58 dl_src='00:06:07:08:09:0a',
Tatsuya Yabe460321e2010-05-25 17:50:49 -070059 dl_vlan_enable=False,
60 dl_vlan=0,
61 dl_vlan_pcp=0,
Dan Talayco551befa2010-07-15 17:05:32 -070062 dl_vlan_cfi=0,
Dan Talayco41eae8b2010-03-10 13:57:06 -080063 ip_src='192.168.0.1',
64 ip_dst='192.168.0.2',
Tatsuya Yabe460321e2010-05-25 17:50:49 -070065 ip_tos=0,
Dan Talayco41eae8b2010-03-10 13:57:06 -080066 tcp_sport=1234,
Christian Dickmann8b59b4b2012-09-23 16:48:30 -070067 tcp_dport=80,
68 ip_ihl=None,
69 ip_options=False
Dan Talayco41eae8b2010-03-10 13:57:06 -080070 ):
71 """
72 Return a simple dataplane TCP packet
73
74 Supports a few parameters:
75 @param len Length of packet in bytes w/o CRC
76 @param dl_dst Destinatino MAC
77 @param dl_src Source MAC
Tatsuya Yabe460321e2010-05-25 17:50:49 -070078 @param dl_vlan_enable True if the packet is with vlan, False otherwise
79 @param dl_vlan VLAN ID
80 @param dl_vlan_pcp VLAN priority
Dan Talayco41eae8b2010-03-10 13:57:06 -080081 @param ip_src IP source
82 @param ip_dst IP destination
Tatsuya Yabe460321e2010-05-25 17:50:49 -070083 @param ip_tos IP ToS
Dan Talayco41eae8b2010-03-10 13:57:06 -080084 @param tcp_dport TCP destination port
85 @param ip_sport TCP source port
86
87 Generates a simple TCP request. Users
88 shouldn't assume anything about this packet other than that
89 it is a valid ethernet/IP/TCP frame.
90 """
Jeffrey Townsend5cb7ed32012-08-17 18:11:01 +000091
92 if MINSIZE > pktlen:
93 pktlen = MINSIZE
94
Dan Talayco551befa2010-07-15 17:05:32 -070095 # Note Dot1Q.id is really CFI
Shudong Zhou43ee54c2012-12-13 15:52:37 -080096 if (dl_vlan_enable):
Tatsuya Yabe460321e2010-05-25 17:50:49 -070097 pkt = scapy.Ether(dst=dl_dst, src=dl_src)/ \
Dan Talayco551befa2010-07-15 17:05:32 -070098 scapy.Dot1Q(prio=dl_vlan_pcp, id=dl_vlan_cfi, vlan=dl_vlan)/ \
Christian Dickmann8b59b4b2012-09-23 16:48:30 -070099 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ihl=ip_ihl)/ \
Tatsuya Yabe460321e2010-05-25 17:50:49 -0700100 scapy.TCP(sport=tcp_sport, dport=tcp_dport)
101 else:
Christian Dickmann8b59b4b2012-09-23 16:48:30 -0700102 if not ip_options:
103 pkt = scapy.Ether(dst=dl_dst, src=dl_src)/ \
104 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ihl=ip_ihl)/ \
105 scapy.TCP(sport=tcp_sport, dport=tcp_dport)
106 else:
107 pkt = scapy.Ether(dst=dl_dst, src=dl_src)/ \
108 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ihl=ip_ihl, options=ip_options)/ \
109 scapy.TCP(sport=tcp_sport, dport=tcp_dport)
Tatsuya Yabe460321e2010-05-25 17:50:49 -0700110
Dan Talayco41eae8b2010-03-10 13:57:06 -0800111 pkt = pkt/("D" * (pktlen - len(pkt)))
112
113 return pkt
114
Rich Lane6ee7bea2012-10-26 16:19:29 -0700115def simple_udp_packet(pktlen=100,
116 dl_dst='00:01:02:03:04:05',
117 dl_src='00:06:07:08:09:0a',
118 dl_vlan_enable=False,
119 dl_vlan=0,
120 dl_vlan_pcp=0,
121 dl_vlan_cfi=0,
122 ip_src='192.168.0.1',
123 ip_dst='192.168.0.2',
124 ip_tos=0,
125 udp_sport=1234,
126 udp_dport=80,
127 ip_ihl=None,
128 ip_options=False
129 ):
130 """
131 Return a simple dataplane UDP packet
132
133 Supports a few parameters:
134 @param len Length of packet in bytes w/o CRC
135 @param dl_dst Destination MAC
136 @param dl_src Source MAC
137 @param dl_vlan_enable True if the packet is with vlan, False otherwise
138 @param dl_vlan VLAN ID
139 @param dl_vlan_pcp VLAN priority
140 @param ip_src IP source
141 @param ip_dst IP destination
142 @param ip_tos IP ToS
143 @param udp_dport UDP destination port
144 @param udp_sport UDP source port
145
146 Generates a simple UDP packet. Users shouldn't assume anything about
147 this packet other than that it is a valid ethernet/IP/UDP frame.
148 """
149
150 if MINSIZE > pktlen:
151 pktlen = MINSIZE
152
153 # Note Dot1Q.id is really CFI
154 if (dl_vlan_enable):
155 pkt = scapy.Ether(dst=dl_dst, src=dl_src)/ \
156 scapy.Dot1Q(prio=dl_vlan_pcp, id=dl_vlan_cfi, vlan=dl_vlan)/ \
157 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ihl=ip_ihl)/ \
158 scapy.UDP(sport=udp_sport, dport=udp_dport)
159 else:
160 if not ip_options:
161 pkt = scapy.Ether(dst=dl_dst, src=dl_src)/ \
162 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ihl=ip_ihl)/ \
163 scapy.UDP(sport=udp_sport, dport=udp_dport)
164 else:
165 pkt = scapy.Ether(dst=dl_dst, src=dl_src)/ \
166 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ihl=ip_ihl, options=ip_options)/ \
167 scapy.UDP(sport=udp_sport, dport=udp_dport)
168
169 pkt = pkt/("D" * (pktlen - len(pkt)))
170
171 return pkt
172
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700173def simple_icmp_packet(pktlen=60,
174 dl_dst='00:01:02:03:04:05',
175 dl_src='00:06:07:08:09:0a',
176 dl_vlan_enable=False,
177 dl_vlan=0,
178 dl_vlan_pcp=0,
179 ip_src='192.168.0.1',
180 ip_dst='192.168.0.2',
181 ip_tos=0,
182 icmp_type=8,
183 icmp_code=0
184 ):
185 """
186 Return a simple ICMP packet
187
188 Supports a few parameters:
189 @param len Length of packet in bytes w/o CRC
190 @param dl_dst Destinatino MAC
191 @param dl_src Source MAC
192 @param dl_vlan_enable True if the packet is with vlan, False otherwise
193 @param dl_vlan VLAN ID
194 @param dl_vlan_pcp VLAN priority
195 @param ip_src IP source
196 @param ip_dst IP destination
197 @param ip_tos IP ToS
198 @param icmp_type ICMP type
199 @param icmp_code ICMP code
200
201 Generates a simple ICMP ECHO REQUEST. Users
202 shouldn't assume anything about this packet other than that
203 it is a valid ethernet/ICMP frame.
204 """
Jeffrey Townsend5cb7ed32012-08-17 18:11:01 +0000205
206 if MINSIZE > pktlen:
207 pktlen = MINSIZE
208
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700209 if (dl_vlan_enable):
210 pkt = scapy.Ether(dst=dl_dst, src=dl_src)/ \
211 scapy.Dot1Q(prio=dl_vlan_pcp, id=0, vlan=dl_vlan)/ \
212 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos)/ \
213 scapy.ICMP(type=icmp_type, code=icmp_code)
214 else:
215 pkt = scapy.Ether(dst=dl_dst, src=dl_src)/ \
216 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos)/ \
217 scapy.ICMP(type=icmp_type, code=icmp_code)
218
219 pkt = pkt/("0" * (pktlen - len(pkt)))
220
221 return pkt
222
Ed Swierk0aeff8c2012-03-23 20:27:18 -0700223def simple_eth_packet(pktlen=60,
224 dl_dst='00:01:02:03:04:05',
225 dl_src='01:80:c2:00:00:00',
226 dl_type=0x88cc):
Jeffrey Townsend5cb7ed32012-08-17 18:11:01 +0000227
228 if MINSIZE > pktlen:
229 pktlen = MINSIZE
230
Ed Swierk0aeff8c2012-03-23 20:27:18 -0700231 pkt = scapy.Ether(dst=dl_dst, src=dl_src, type=dl_type)
232
233 pkt = pkt/("0" * (pktlen - len(pkt)))
234
235 return pkt
236
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800237def qinq_tcp_packet(pktlen=100,
238 dl_dst='00:01:02:03:04:05',
239 dl_src='00:06:07:08:09:0a',
240 dl_vlan_outer=20,
241 dl_vlan_pcp_outer=0,
242 dl_vlan_cfi_outer=0,
243 dl_vlan=10,
244 dl_vlan_pcp=0,
245 dl_vlan_cfi=0,
246 ip_src='192.168.0.1',
247 ip_dst='192.168.0.2',
248 ip_tos=0,
249 tcp_sport=1234,
250 tcp_dport=80,
251 ip_ihl=None,
252 ip_options=False
253 ):
254 """
255 Return a doubly tagged dataplane TCP packet
256
257 Supports a few parameters:
258 @param len Length of packet in bytes w/o CRC
259 @param dl_dst Destinatino MAC
260 @param dl_src Source MAC
261 @param dl_vlan_outer Outer VLAN ID
262 @param dl_vlan_pcp_outer Outer VLAN priority
263 @param dl_vlan_cfi_outer Outer VLAN cfi bit
264 @param dl_vlan Inner VLAN ID
265 @param dl_vlan_pcp VLAN priority
266 @param dl_vlan_cfi VLAN cfi bit
267 @param ip_src IP source
268 @param ip_dst IP destination
269 @param ip_tos IP ToS
270 @param tcp_dport TCP destination port
271 @param ip_sport TCP source port
272
273 Generates a TCP request. Users
274 shouldn't assume anything about this packet other than that
275 it is a valid ethernet/IP/TCP frame.
276 """
277
278 if MINSIZE > pktlen:
279 pktlen = MINSIZE
280
281 # Note Dot1Q.id is really CFI
282 pkt = scapy.Ether(dst=dl_dst, src=dl_src)/ \
283 scapy.Dot1Q(prio=dl_vlan_pcp_outer, id=dl_vlan_cfi_outer, vlan=dl_vlan_outer)/ \
284 scapy.Dot1Q(prio=dl_vlan_pcp, id=dl_vlan_cfi, vlan=dl_vlan)/ \
285 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ihl=ip_ihl)/ \
286 scapy.TCP(sport=tcp_sport, dport=tcp_dport)
287
288 pkt = pkt/("D" * (pktlen - len(pkt)))
289
290 return pkt
291
Shudong Zhoub7f12462012-11-20 13:01:12 -0800292def do_barrier(ctrl, timeout=-1):
Dan Talayco0fc08bd2012-04-09 16:56:18 -0700293 """
294 Do a barrier command
295 Return 0 on success, -1 on error
296 """
Dan Talayco41eae8b2010-03-10 13:57:06 -0800297 b = message.barrier_request()
Shudong Zhoub7f12462012-11-20 13:01:12 -0800298 (resp, pkt) = ctrl.transact(b, timeout=timeout)
Dan Talaycof6b94832012-04-12 21:50:57 -0700299 # We'll trust the transaction processing in the controller that xid matched
Dan Talayco0fc08bd2012-04-09 16:56:18 -0700300 if not resp:
301 return -1
302 return 0
Dan Talayco92c99122010-06-03 13:53:18 -0700303
Rich Lane9a003812012-10-04 17:17:59 -0700304def port_config_get(controller, port_no):
Dan Talayco92c99122010-06-03 13:53:18 -0700305 """
306 Get a port's configuration
307
308 Gets the switch feature configuration and grabs one port's
309 configuration
310
311 @returns (hwaddr, config, advert) The hwaddress, configuration and
312 advertised values
313 """
314 request = message.features_request()
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700315 reply, pkt = controller.transact(request)
Rich Lane9a003812012-10-04 17:17:59 -0700316 logging.debug(reply.show())
Dan Talayco92c99122010-06-03 13:53:18 -0700317 if reply is None:
Rich Lane9a003812012-10-04 17:17:59 -0700318 logging.warn("Get feature request failed")
Dan Talayco92c99122010-06-03 13:53:18 -0700319 return None, None, None
320 for idx in range(len(reply.ports)):
321 if reply.ports[idx].port_no == port_no:
322 return (reply.ports[idx].hw_addr, reply.ports[idx].config,
323 reply.ports[idx].advertised)
324
Rich Lane9a003812012-10-04 17:17:59 -0700325 logging.warn("Did not find port number for port config")
Dan Talayco92c99122010-06-03 13:53:18 -0700326 return None, None, None
327
Rich Lane9a003812012-10-04 17:17:59 -0700328def port_config_set(controller, port_no, config, mask):
Dan Talayco92c99122010-06-03 13:53:18 -0700329 """
330 Set the port configuration according the given parameters
331
332 Gets the switch feature configuration and updates one port's
333 configuration value according to config and mask
334 """
Rich Lane9a003812012-10-04 17:17:59 -0700335 logging.info("Setting port " + str(port_no) + " to config " + str(config))
Dan Talayco92c99122010-06-03 13:53:18 -0700336 request = message.features_request()
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700337 reply, pkt = controller.transact(request)
Dan Talayco92c99122010-06-03 13:53:18 -0700338 if reply is None:
339 return -1
Rich Lane9a003812012-10-04 17:17:59 -0700340 logging.debug(reply.show())
Dan Talayco92c99122010-06-03 13:53:18 -0700341 for idx in range(len(reply.ports)):
342 if reply.ports[idx].port_no == port_no:
343 break
344 if idx >= len(reply.ports):
345 return -1
346 mod = message.port_mod()
347 mod.port_no = port_no
348 mod.hw_addr = reply.ports[idx].hw_addr
349 mod.config = config
350 mod.mask = mask
351 mod.advertise = reply.ports[idx].advertised
352 rv = controller.message_send(mod)
353 return rv
354
Rich Lane2014f9b2012-10-05 15:29:40 -0700355def receive_pkt_check(dp, pkt, yes_ports, no_ports, assert_if):
Dan Talayco92c99122010-06-03 13:53:18 -0700356 """
357 Check for proper receive packets across all ports
Ken Chiang1bf01602012-04-04 10:48:23 -0700358 @param dp The dataplane object
Dan Talayco92c99122010-06-03 13:53:18 -0700359 @param pkt Expected packet; may be None if yes_ports is empty
360 @param yes_ports Set or list of ports that should recieve packet
361 @param no_ports Set or list of ports that should not receive packet
362 @param assert_if Object that implements assertXXX
363 """
Rich Lane91765672012-12-06 16:33:04 -0800364
365 # Wait this long for packets that we don't expect to receive.
366 # 100ms is (rarely) too short for positive tests on slow
367 # switches but is definitely not too short for a negative test.
368 negative_timeout = 0.1
369
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700370 exp_pkt_arg = None
Rich Lane2014f9b2012-10-05 15:29:40 -0700371 if config["relax"]:
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700372 exp_pkt_arg = pkt
373
Dan Talayco92c99122010-06-03 13:53:18 -0700374 for ofport in yes_ports:
Rich Lane9a003812012-10-04 17:17:59 -0700375 logging.debug("Checking for pkt on port " + str(ofport))
Ken Chiang1bf01602012-04-04 10:48:23 -0700376 (rcv_port, rcv_pkt, pkt_time) = dp.poll(
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700377 port_number=ofport, exp_pkt=exp_pkt_arg)
Dan Talayco92c99122010-06-03 13:53:18 -0700378 assert_if.assertTrue(rcv_pkt is not None,
379 "Did not receive pkt on " + str(ofport))
Ken Chiang1bf01602012-04-04 10:48:23 -0700380 if not dataplane.match_exp_pkt(pkt, rcv_pkt):
Rich Lane9a003812012-10-04 17:17:59 -0700381 logging.debug("Sent %s" % format_packet(pkt))
382 logging.debug("Resp %s" % format_packet(rcv_pkt))
Ken Chiang1bf01602012-04-04 10:48:23 -0700383 assert_if.assertTrue(dataplane.match_exp_pkt(pkt, rcv_pkt),
384 "Response packet does not match send packet " +
385 "on port " + str(ofport))
Dan Talayco73f84012012-10-02 09:23:18 -0700386 if len(no_ports) > 0:
Rich Lane91765672012-12-06 16:33:04 -0800387 time.sleep(negative_timeout)
Dan Talayco92c99122010-06-03 13:53:18 -0700388 for ofport in no_ports:
Rich Lane9a003812012-10-04 17:17:59 -0700389 logging.debug("Negative check for pkt on port " + str(ofport))
Ken Chiang1bf01602012-04-04 10:48:23 -0700390 (rcv_port, rcv_pkt, pkt_time) = dp.poll(
Rich Lane91765672012-12-06 16:33:04 -0800391 port_number=ofport, timeout=0, exp_pkt=exp_pkt_arg)
Dan Talayco92c99122010-06-03 13:53:18 -0700392 assert_if.assertTrue(rcv_pkt is None,
393 "Unexpected pkt on port " + str(ofport))
Dan Talayco551befa2010-07-15 17:05:32 -0700394
395
Dan Talaycoc948d0b2012-03-23 12:17:54 -0700396def receive_pkt_verify(parent, egr_ports, exp_pkt, ing_port):
Dan Talayco551befa2010-07-15 17:05:32 -0700397 """
398 Receive a packet and verify it matches an expected value
Dan Talaycof6e76c02012-03-23 10:56:12 -0700399 @param egr_port A single port or list of ports
Dan Talayco551befa2010-07-15 17:05:32 -0700400
401 parent must implement dataplane, assertTrue and assertEqual
402 """
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700403 exp_pkt_arg = None
Rich Lane477f4812012-10-04 22:49:00 -0700404 if config["relax"]:
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700405 exp_pkt_arg = exp_pkt
406
Dan Talaycof6e76c02012-03-23 10:56:12 -0700407 if type(egr_ports) == type([]):
408 egr_port_list = egr_ports
409 else:
410 egr_port_list = [egr_ports]
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700411
Dan Talaycof6e76c02012-03-23 10:56:12 -0700412 # Expect a packet from each port on egr port list
413 for egr_port in egr_port_list:
Dan Talaycod8ae7582012-03-23 12:24:56 -0700414 check_port = egr_port
Dan Talaycoc948d0b2012-03-23 12:17:54 -0700415 if egr_port == ofp.OFPP_IN_PORT:
Dan Talaycod8ae7582012-03-23 12:24:56 -0700416 check_port = ing_port
Dan Talaycof6e76c02012-03-23 10:56:12 -0700417 (rcv_port, rcv_pkt, pkt_time) = parent.dataplane.poll(
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700418 port_number=check_port, exp_pkt=exp_pkt_arg)
Dan Talayco551befa2010-07-15 17:05:32 -0700419
Dan Talaycof6e76c02012-03-23 10:56:12 -0700420 if rcv_pkt is None:
Rich Lane9a003812012-10-04 17:17:59 -0700421 logging.error("ERROR: No packet received from " +
Dan Talaycod8ae7582012-03-23 12:24:56 -0700422 str(check_port))
Dan Talayco551befa2010-07-15 17:05:32 -0700423
Dan Talaycof6e76c02012-03-23 10:56:12 -0700424 parent.assertTrue(rcv_pkt is not None,
Dan Talaycod8ae7582012-03-23 12:24:56 -0700425 "Did not receive packet port " + str(check_port))
Rich Lane9a003812012-10-04 17:17:59 -0700426 logging.debug("Packet len " + str(len(rcv_pkt)) + " in on " +
Dan Talaycof6e76c02012-03-23 10:56:12 -0700427 str(rcv_port))
428
429 if str(exp_pkt) != str(rcv_pkt):
Rich Lane9a003812012-10-04 17:17:59 -0700430 logging.error("ERROR: Packet match failed.")
431 logging.debug("Expected len " + str(len(exp_pkt)) + ": "
Dan Talaycof6e76c02012-03-23 10:56:12 -0700432 + str(exp_pkt).encode('hex'))
Rich Lane9a003812012-10-04 17:17:59 -0700433 logging.debug("Received len " + str(len(rcv_pkt)) + ": "
Dan Talaycof6e76c02012-03-23 10:56:12 -0700434 + str(rcv_pkt).encode('hex'))
Rich Lane5d7e89a2012-10-26 16:43:13 -0700435 logging.debug("Expected packet: " + inspect_packet(scapy.Ether(str(exp_pkt))))
436 logging.debug("Received packet: " + inspect_packet(scapy.Ether(str(rcv_pkt))))
Dan Talaycof6e76c02012-03-23 10:56:12 -0700437 parent.assertEqual(str(exp_pkt), str(rcv_pkt),
Dan Talaycod8ae7582012-03-23 12:24:56 -0700438 "Packet match error on port " + str(check_port))
Dan Talaycof6e76c02012-03-23 10:56:12 -0700439
Dan Talayco551befa2010-07-15 17:05:32 -0700440def match_verify(parent, req_match, res_match):
441 """
442 Verify flow matches agree; if they disagree, report where
443
444 parent must implement assertEqual
445 Use str() to ensure content is compared and not pointers
446 """
447
448 parent.assertEqual(req_match.wildcards, res_match.wildcards,
449 'Match failed: wildcards: ' + hex(req_match.wildcards) +
450 " != " + hex(res_match.wildcards))
451 parent.assertEqual(req_match.in_port, res_match.in_port,
452 'Match failed: in_port: ' + str(req_match.in_port) +
453 " != " + str(res_match.in_port))
454 parent.assertEqual(str(req_match.dl_src), str(res_match.dl_src),
455 'Match failed: dl_src: ' + str(req_match.dl_src) +
456 " != " + str(res_match.dl_src))
457 parent.assertEqual(str(req_match.dl_dst), str(res_match.dl_dst),
458 'Match failed: dl_dst: ' + str(req_match.dl_dst) +
459 " != " + str(res_match.dl_dst))
460 parent.assertEqual(req_match.dl_vlan, res_match.dl_vlan,
461 'Match failed: dl_vlan: ' + str(req_match.dl_vlan) +
462 " != " + str(res_match.dl_vlan))
463 parent.assertEqual(req_match.dl_vlan_pcp, res_match.dl_vlan_pcp,
464 'Match failed: dl_vlan_pcp: ' +
465 str(req_match.dl_vlan_pcp) + " != " +
466 str(res_match.dl_vlan_pcp))
467 parent.assertEqual(req_match.dl_type, res_match.dl_type,
468 'Match failed: dl_type: ' + str(req_match.dl_type) +
469 " != " + str(res_match.dl_type))
470
471 if (not(req_match.wildcards & ofp.OFPFW_DL_TYPE)
472 and (req_match.dl_type == IP_ETHERTYPE)):
473 parent.assertEqual(req_match.nw_tos, res_match.nw_tos,
474 'Match failed: nw_tos: ' + str(req_match.nw_tos) +
475 " != " + str(res_match.nw_tos))
476 parent.assertEqual(req_match.nw_proto, res_match.nw_proto,
477 'Match failed: nw_proto: ' + str(req_match.nw_proto) +
478 " != " + str(res_match.nw_proto))
479 parent.assertEqual(req_match.nw_src, res_match.nw_src,
480 'Match failed: nw_src: ' + str(req_match.nw_src) +
481 " != " + str(res_match.nw_src))
482 parent.assertEqual(req_match.nw_dst, res_match.nw_dst,
483 'Match failed: nw_dst: ' + str(req_match.nw_dst) +
484 " != " + str(res_match.nw_dst))
485
486 if (not(req_match.wildcards & ofp.OFPFW_NW_PROTO)
487 and ((req_match.nw_proto == TCP_PROTOCOL)
488 or (req_match.nw_proto == UDP_PROTOCOL))):
489 parent.assertEqual(req_match.tp_src, res_match.tp_src,
490 'Match failed: tp_src: ' +
491 str(req_match.tp_src) +
492 " != " + str(res_match.tp_src))
493 parent.assertEqual(req_match.tp_dst, res_match.tp_dst,
494 'Match failed: tp_dst: ' +
495 str(req_match.tp_dst) +
496 " != " + str(res_match.tp_dst))
497
Ed Swierk99a74de2012-08-22 06:40:54 -0700498def packet_to_flow_match(parent, packet):
499 match = parse.packet_to_flow_match(packet)
500 match.wildcards |= required_wildcards(parent)
501 return match
502
503def flow_msg_create(parent, pkt, ing_port=None, action_list=None, wildcards=None,
Dan Talaycof6e76c02012-03-23 10:56:12 -0700504 egr_ports=None, egr_queue=None, check_expire=False, in_band=False):
Dan Talayco551befa2010-07-15 17:05:32 -0700505 """
506 Create a flow message
507
508 Match on packet with given wildcards.
509 See flow_match_test for other parameter descriptoins
510 @param egr_queue if not None, make the output an enqueue action
Dan Talayco677c0b72011-08-23 22:53:38 -0700511 @param in_band if True, do not wildcard ingress port
Dan Talaycof6e76c02012-03-23 10:56:12 -0700512 @param egr_ports None (drop), single port or list of ports
Dan Talayco551befa2010-07-15 17:05:32 -0700513 """
514 match = parse.packet_to_flow_match(pkt)
515 parent.assertTrue(match is not None, "Flow match from pkt failed")
Ed Swierk99a74de2012-08-22 06:40:54 -0700516 if wildcards is None:
517 wildcards = required_wildcards(parent)
Dan Talayco677c0b72011-08-23 22:53:38 -0700518 if in_band:
519 wildcards &= ~ofp.OFPFW_IN_PORT
Dan Talayco551befa2010-07-15 17:05:32 -0700520 match.wildcards = wildcards
521 match.in_port = ing_port
522
Dan Talaycof6e76c02012-03-23 10:56:12 -0700523 if type(egr_ports) == type([]):
524 egr_port_list = egr_ports
525 else:
526 egr_port_list = [egr_ports]
527
Dan Talayco551befa2010-07-15 17:05:32 -0700528 request = message.flow_mod()
529 request.match = match
530 request.buffer_id = 0xffffffff
531 if check_expire:
532 request.flags |= ofp.OFPFF_SEND_FLOW_REM
533 request.hard_timeout = 1
534
535 if action_list is not None:
536 for act in action_list:
Rich Lane9a003812012-10-04 17:17:59 -0700537 logging.debug("Adding action " + act.show())
Dan Talayco551befa2010-07-15 17:05:32 -0700538 rv = request.actions.add(act)
539 parent.assertTrue(rv, "Could not add action" + act.show())
540
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
548 rv = request.actions.add(act)
549 parent.assertTrue(rv, "Could not add enqueue action " +
550 str(egr_port) + " Q: " + str(egr_queue))
551 elif egr_ports is not None:
552 for egr_port in egr_port_list:
553 act = action.action_output()
554 act.port = egr_port
555 rv = request.actions.add(act)
556 parent.assertTrue(rv, "Could not add output action " +
557 str(egr_port))
Dan Talayco551befa2010-07-15 17:05:32 -0700558
Rich Lane9a003812012-10-04 17:17:59 -0700559 logging.debug(request.show())
Dan Talayco551befa2010-07-15 17:05:32 -0700560
561 return request
562
Jeffrey Townsendf3eae9c2012-03-28 18:23:21 -0700563def flow_msg_install(parent, request, clear_table_override=None):
Dan Talayco551befa2010-07-15 17:05:32 -0700564 """
565 Install a flow mod message in the switch
566
567 @param parent Must implement controller, assertEqual, assertTrue
568 @param request The request, all set to go
569 @param clear_table If true, clear the flow table before installing
570 """
Dan Talayco8a64e332012-03-28 14:53:20 -0700571
Rich Lane2014f9b2012-10-05 15:29:40 -0700572 clear_table = test_param_get('clear_table', default=True)
Jeffrey Townsendf3eae9c2012-03-28 18:23:21 -0700573 if(clear_table_override != None):
574 clear_table = clear_table_override
575
576 if clear_table:
Rich Lane9a003812012-10-04 17:17:59 -0700577 logging.debug("Clear flow table")
578 rc = delete_all_flows(parent.controller)
Dan Talayco551befa2010-07-15 17:05:32 -0700579 parent.assertEqual(rc, 0, "Failed to delete all flows")
Dan Talayco551befa2010-07-15 17:05:32 -0700580
Rich Lane9a003812012-10-04 17:17:59 -0700581 logging.debug("Insert flow")
Dan Talayco551befa2010-07-15 17:05:32 -0700582 rv = parent.controller.message_send(request)
583 parent.assertTrue(rv != -1, "Error installing flow mod")
Rich Lanee912d032012-12-22 14:28:33 -0800584
Dan Talayco0fc08bd2012-04-09 16:56:18 -0700585 parent.assertEqual(do_barrier(parent.controller), 0, "Barrier failed")
Dan Talayco551befa2010-07-15 17:05:32 -0700586
Ed Swierk99a74de2012-08-22 06:40:54 -0700587def flow_match_test_port_pair(parent, ing_port, egr_ports, wildcards=None,
Dan Talayco551befa2010-07-15 17:05:32 -0700588 dl_vlan=-1, pkt=None, exp_pkt=None,
Rich Lanee5779d32012-10-05 17:56:04 -0700589 action_list=None):
Dan Talayco551befa2010-07-15 17:05:32 -0700590 """
591 Flow match test on single TCP packet
Dan Talaycof6e76c02012-03-23 10:56:12 -0700592 @param egr_ports A single port or list of ports
Dan Talayco551befa2010-07-15 17:05:32 -0700593
594 Run test with packet through switch from ing_port to egr_port
595 See flow_match_test for parameter descriptions
596 """
597
Ed Swierk99a74de2012-08-22 06:40:54 -0700598 if wildcards is None:
599 wildcards = required_wildcards(parent)
Rich Lane9a003812012-10-04 17:17:59 -0700600 logging.info("Pkt match test: " + str(ing_port) + " to " +
Dan Talaycof6e76c02012-03-23 10:56:12 -0700601 str(egr_ports))
Rich Lanee5779d32012-10-05 17:56:04 -0700602 logging.debug(" WC: " + hex(wildcards) + " vlan: " + str(dl_vlan))
Dan Talayco551befa2010-07-15 17:05:32 -0700603 if pkt is None:
604 pkt = simple_tcp_packet(dl_vlan_enable=(dl_vlan >= 0), dl_vlan=dl_vlan)
605
606 request = flow_msg_create(parent, pkt, ing_port=ing_port,
Dan Talaycof6e76c02012-03-23 10:56:12 -0700607 wildcards=wildcards, egr_ports=egr_ports,
Dan Talayco551befa2010-07-15 17:05:32 -0700608 action_list=action_list)
609
610 flow_msg_install(parent, request)
611
Rich Lane9a003812012-10-04 17:17:59 -0700612 logging.debug("Send packet: " + str(ing_port) + " to " +
Dan Talaycof6e76c02012-03-23 10:56:12 -0700613 str(egr_ports))
Dan Talayco551befa2010-07-15 17:05:32 -0700614 parent.dataplane.send(ing_port, str(pkt))
615
616 if exp_pkt is None:
617 exp_pkt = pkt
Dan Talaycoc948d0b2012-03-23 12:17:54 -0700618 receive_pkt_verify(parent, egr_ports, exp_pkt, ing_port)
Dan Talayco551befa2010-07-15 17:05:32 -0700619
Rich Lane89725bb2012-12-03 16:23:27 -0800620def flow_match_test_pktout(parent, ing_port, egr_ports,
621 dl_vlan=-1, pkt=None, exp_pkt=None,
622 action_list=None):
623 """
624 Packet-out test on single TCP packet
625 @param egr_ports A single port or list of ports
626
627 Run test sending packet-out to egr_ports. The goal is to test the actions
628 taken on the packet, not the matching which is of course irrelevant.
629 See flow_match_test for parameter descriptions
630 """
631
632 if pkt is None:
633 pkt = simple_tcp_packet(dl_vlan_enable=(dl_vlan >= 0), dl_vlan=dl_vlan)
634
635 msg = message.packet_out()
636 msg.in_port = ing_port
637 msg.data = str(pkt)
638 if action_list is not None:
639 for act in action_list:
640 assert(msg.actions.add(act))
641
642 # Set up output action
643 if egr_ports is not None:
644 for egr_port in egr_ports:
645 act = action.action_output()
646 act.port = egr_port
647 assert(msg.actions.add(act))
648
649 logging.debug(msg.show())
650 rv = parent.controller.message_send(msg)
651 parent.assertTrue(rv == 0, "Error sending out message")
652
653 if exp_pkt is None:
654 exp_pkt = pkt
655 receive_pkt_verify(parent, egr_ports, exp_pkt, ing_port)
656
Dan Talaycof6e76c02012-03-23 10:56:12 -0700657def get_egr_list(parent, of_ports, how_many, exclude_list=[]):
658 """
659 Generate a list of ports avoiding those in the exclude list
Rich Lane9a003812012-10-04 17:17:59 -0700660 @param parent Supplies logging
Dan Talaycof6e76c02012-03-23 10:56:12 -0700661 @param of_ports List of OF port numbers
662 @param how_many Number of ports to be added to the list
663 @param exclude_list List of ports not to be used
664 @returns An empty list if unable to find enough ports
665 """
666
Dan Talaycoc948d0b2012-03-23 12:17:54 -0700667 if how_many == 0:
668 return []
669
Dan Talaycof6e76c02012-03-23 10:56:12 -0700670 count = 0
671 egr_ports = []
672 for egr_idx in range(len(of_ports)):
673 if of_ports[egr_idx] not in exclude_list:
674 egr_ports.append(of_ports[egr_idx])
675 count += 1
676 if count >= how_many:
677 return egr_ports
Rich Lane9a003812012-10-04 17:17:59 -0700678 logging.debug("Could not generate enough egress ports for test")
Dan Talaycof6e76c02012-03-23 10:56:12 -0700679 return []
680
Ed Swierk99a74de2012-08-22 06:40:54 -0700681def flow_match_test(parent, port_map, wildcards=None, dl_vlan=-1, pkt=None,
Rich Lanee5779d32012-10-05 17:56:04 -0700682 exp_pkt=None, action_list=None,
Dan Talaycoc948d0b2012-03-23 12:17:54 -0700683 max_test=0, egr_count=1, ing_port=False):
Dan Talayco551befa2010-07-15 17:05:32 -0700684 """
Rich Lane89725bb2012-12-03 16:23:27 -0800685 Run flow_match_test_port_pair on all port pairs and packet-out
Dan Talayco551befa2010-07-15 17:05:32 -0700686
687 @param max_test If > 0 no more than this number of tests are executed.
688 @param parent Must implement controller, dataplane, assertTrue, assertEqual
Rich Lane9a003812012-10-04 17:17:59 -0700689 and logging
Dan Talayco551befa2010-07-15 17:05:32 -0700690 @param pkt If not None, use this packet for ingress
691 @param wildcards For flow match entry
Dan Talayco79184222010-11-01 12:24:29 -0700692 @param dl_vlan If not -1, and pkt is None, create a pkt w/ VLAN tag
Dan Talayco551befa2010-07-15 17:05:32 -0700693 @param exp_pkt If not None, use this as the expected output pkt; els use pkt
694 @param action_list Additional actions to add to flow mod
Dan Talaycocfa172f2012-03-23 12:03:00 -0700695 @param egr_count Number of egress ports; -1 means get from config w/ dflt 2
Dan Talayco551befa2010-07-15 17:05:32 -0700696 """
Ed Swierk99a74de2012-08-22 06:40:54 -0700697 if wildcards is None:
698 wildcards = required_wildcards(parent)
Dan Talayco551befa2010-07-15 17:05:32 -0700699 of_ports = port_map.keys()
700 of_ports.sort()
701 parent.assertTrue(len(of_ports) > 1, "Not enough ports for test")
702 test_count = 0
703
Dan Talaycocfa172f2012-03-23 12:03:00 -0700704 if egr_count == -1:
Rich Lane2014f9b2012-10-05 15:29:40 -0700705 egr_count = test_param_get('egr_count', default=2)
Dan Talaycocfa172f2012-03-23 12:03:00 -0700706
Dan Talayco551befa2010-07-15 17:05:32 -0700707 for ing_idx in range(len(of_ports)):
708 ingress_port = of_ports[ing_idx]
Dan Talaycof6e76c02012-03-23 10:56:12 -0700709 egr_ports = get_egr_list(parent, of_ports, egr_count,
710 exclude_list=[ingress_port])
Dan Talaycoc948d0b2012-03-23 12:17:54 -0700711 if ing_port:
712 egr_ports.append(ofp.OFPP_IN_PORT)
Dan Talaycof6e76c02012-03-23 10:56:12 -0700713 if len(egr_ports) == 0:
714 parent.assertTrue(0, "Failed to generate egress port list")
715
716 flow_match_test_port_pair(parent, ingress_port, egr_ports,
717 wildcards=wildcards, dl_vlan=dl_vlan,
718 pkt=pkt, exp_pkt=exp_pkt,
Rich Lanee5779d32012-10-05 17:56:04 -0700719 action_list=action_list)
Dan Talaycof6e76c02012-03-23 10:56:12 -0700720 test_count += 1
721 if (max_test > 0) and (test_count > max_test):
Rich Lane9a003812012-10-04 17:17:59 -0700722 logging.info("Ran " + str(test_count) + " tests; exiting")
Rich Lane89725bb2012-12-03 16:23:27 -0800723 break
724
725
726 ingress_port = of_ports[0]
727 egr_ports = get_egr_list(parent, of_ports, egr_count,
728 exclude_list=[ingress_port])
729 if ing_port:
730 egr_ports.append(ofp.OFPP_IN_PORT)
731 flow_match_test_pktout(parent, ingress_port, egr_ports,
732 dl_vlan=dl_vlan,
733 pkt=pkt, exp_pkt=exp_pkt,
734 action_list=action_list)
Dan Talayco551befa2010-07-15 17:05:32 -0700735
Rich Lane2014f9b2012-10-05 15:29:40 -0700736def test_param_get(key, default=None):
Dan Talayco4b2bee62010-07-20 14:10:05 -0700737 """
738 Return value passed via test-params if present
739
Dan Talayco4b2bee62010-07-20 14:10:05 -0700740 @param key The lookup key
741 @param default Default value to use if not found
742
743 If the pair 'key=val' appeared in the string passed to --test-params
744 on the command line, return val (as interpreted by exec). Otherwise
745 return default value.
Dan Talaycof6e76c02012-03-23 10:56:12 -0700746
747 WARNING: TEST PARAMETERS MUST BE PYTHON IDENTIFIERS;
748 eg egr_count, not egr-count.
Dan Talayco4b2bee62010-07-20 14:10:05 -0700749 """
750 try:
751 exec config["test_params"]
752 except:
753 return default
754
755 s = "val = " + str(key)
756 try:
757 exec s
758 return val
759 except:
760 return default
761
762def action_generate(parent, field_to_mod, mod_field_vals):
763 """
764 Create an action to modify the field indicated in field_to_mod
765
766 @param parent Must implement, assertTrue
767 @param field_to_mod The field to modify as a string name
768 @param mod_field_vals Hash of values to use for modified values
769 """
770
771 act = None
772
773 if field_to_mod in ['pktlen']:
774 return None
775
776 if field_to_mod == 'dl_dst':
777 act = action.action_set_dl_dst()
778 act.dl_addr = parse.parse_mac(mod_field_vals['dl_dst'])
779 elif field_to_mod == 'dl_src':
780 act = action.action_set_dl_src()
781 act.dl_addr = parse.parse_mac(mod_field_vals['dl_src'])
782 elif field_to_mod == 'dl_vlan_enable':
783 if not mod_field_vals['dl_vlan_enable']: # Strip VLAN tag
784 act = action.action_strip_vlan()
785 # Add VLAN tag is handled by dl_vlan field
786 # Will return None in this case
787 elif field_to_mod == 'dl_vlan':
788 act = action.action_set_vlan_vid()
789 act.vlan_vid = mod_field_vals['dl_vlan']
790 elif field_to_mod == 'dl_vlan_pcp':
791 act = action.action_set_vlan_pcp()
792 act.vlan_pcp = mod_field_vals['dl_vlan_pcp']
793 elif field_to_mod == 'ip_src':
794 act = action.action_set_nw_src()
795 act.nw_addr = parse.parse_ip(mod_field_vals['ip_src'])
796 elif field_to_mod == 'ip_dst':
797 act = action.action_set_nw_dst()
798 act.nw_addr = parse.parse_ip(mod_field_vals['ip_dst'])
799 elif field_to_mod == 'ip_tos':
800 act = action.action_set_nw_tos()
801 act.nw_tos = mod_field_vals['ip_tos']
802 elif field_to_mod == 'tcp_sport':
803 act = action.action_set_tp_src()
804 act.tp_port = mod_field_vals['tcp_sport']
805 elif field_to_mod == 'tcp_dport':
806 act = action.action_set_tp_dst()
807 act.tp_port = mod_field_vals['tcp_dport']
Rich Lane110e0e32012-10-26 16:21:46 -0700808 elif field_to_mod == 'udp_sport':
809 act = action.action_set_tp_src()
810 act.tp_port = mod_field_vals['udp_sport']
811 elif field_to_mod == 'udp_dport':
812 act = action.action_set_tp_dst()
813 act.tp_port = mod_field_vals['udp_dport']
Dan Talayco4b2bee62010-07-20 14:10:05 -0700814 else:
815 parent.assertTrue(0, "Unknown field to modify: " + str(field_to_mod))
816
817 return act
818
819def pkt_action_setup(parent, start_field_vals={}, mod_field_vals={},
Rich Lane110e0e32012-10-26 16:21:46 -0700820 mod_fields=[], tp="tcp", check_test_params=False):
Dan Talayco4b2bee62010-07-20 14:10:05 -0700821 """
822 Set up the ingress and expected packet and action list for a test
823
Rich Lane2014f9b2012-10-05 15:29:40 -0700824 @param parent Must implement assertTrue
Dan Talayco4b2bee62010-07-20 14:10:05 -0700825 @param start_field_values Field values to use for ingress packet (optional)
826 @param mod_field_values Field values to use for modified packet (optional)
827 @param mod_fields The list of fields to be modified by the switch in the test.
828 @params check_test_params If True, will check the parameters vid, add_vlan
829 and strip_vlan from the command line.
830
831 Returns a triple: pkt-to-send, expected-pkt, action-list
832 """
833
834 new_actions = []
835
Dan Talayco4b2bee62010-07-20 14:10:05 -0700836 base_pkt_params = {}
837 base_pkt_params['pktlen'] = 100
838 base_pkt_params['dl_dst'] = '00:DE:F0:12:34:56'
839 base_pkt_params['dl_src'] = '00:23:45:67:89:AB'
840 base_pkt_params['dl_vlan_enable'] = False
841 base_pkt_params['dl_vlan'] = 2
842 base_pkt_params['dl_vlan_pcp'] = 0
843 base_pkt_params['ip_src'] = '192.168.0.1'
844 base_pkt_params['ip_dst'] = '192.168.0.2'
845 base_pkt_params['ip_tos'] = 0
Rich Lane110e0e32012-10-26 16:21:46 -0700846 if tp == "tcp":
847 base_pkt_params['tcp_sport'] = 1234
848 base_pkt_params['tcp_dport'] = 80
849 elif tp == "udp":
850 base_pkt_params['udp_sport'] = 1234
851 base_pkt_params['udp_dport'] = 80
Dan Talayco4b2bee62010-07-20 14:10:05 -0700852 for keyname in start_field_vals.keys():
853 base_pkt_params[keyname] = start_field_vals[keyname]
854
855 mod_pkt_params = {}
856 mod_pkt_params['pktlen'] = 100
857 mod_pkt_params['dl_dst'] = '00:21:0F:ED:CB:A9'
858 mod_pkt_params['dl_src'] = '00:ED:CB:A9:87:65'
859 mod_pkt_params['dl_vlan_enable'] = False
860 mod_pkt_params['dl_vlan'] = 3
861 mod_pkt_params['dl_vlan_pcp'] = 7
862 mod_pkt_params['ip_src'] = '10.20.30.40'
863 mod_pkt_params['ip_dst'] = '50.60.70.80'
864 mod_pkt_params['ip_tos'] = 0xf0
Rich Lane110e0e32012-10-26 16:21:46 -0700865 if tp == "tcp":
866 mod_pkt_params['tcp_sport'] = 4321
867 mod_pkt_params['tcp_dport'] = 8765
868 elif tp == "udp":
869 mod_pkt_params['udp_sport'] = 4321
870 mod_pkt_params['udp_dport'] = 8765
Dan Talayco4b2bee62010-07-20 14:10:05 -0700871 for keyname in mod_field_vals.keys():
872 mod_pkt_params[keyname] = mod_field_vals[keyname]
873
874 # Check for test param modifications
875 strip = False
876 if check_test_params:
Rich Lane2014f9b2012-10-05 15:29:40 -0700877 add_vlan = test_param_get('add_vlan')
878 strip_vlan = test_param_get('strip_vlan')
879 vid = test_param_get('vid')
Dan Talayco4b2bee62010-07-20 14:10:05 -0700880
881 if add_vlan and strip_vlan:
882 parent.assertTrue(0, "Add and strip VLAN both specified")
883
884 if vid:
885 base_pkt_params['dl_vlan_enable'] = True
886 base_pkt_params['dl_vlan'] = vid
887 if 'dl_vlan' in mod_fields:
888 mod_pkt_params['dl_vlan'] = vid + 1
889
890 if add_vlan:
891 base_pkt_params['dl_vlan_enable'] = False
892 mod_pkt_params['dl_vlan_enable'] = True
893 mod_pkt_params['pktlen'] = base_pkt_params['pktlen'] + 4
894 mod_fields.append('pktlen')
895 mod_fields.append('dl_vlan_enable')
896 if 'dl_vlan' not in mod_fields:
897 mod_fields.append('dl_vlan')
898 elif strip_vlan:
899 base_pkt_params['dl_vlan_enable'] = True
900 mod_pkt_params['dl_vlan_enable'] = False
901 mod_pkt_params['pktlen'] = base_pkt_params['pktlen'] - 4
902 mod_fields.append('dl_vlan_enable')
903 mod_fields.append('pktlen')
904
Rich Lane110e0e32012-10-26 16:21:46 -0700905 if tp == "tcp":
906 packet_builder = simple_tcp_packet
907 elif tp == "udp":
908 packet_builder = simple_udp_packet
909 else:
910 raise NotImplementedError("unknown transport protocol %s" % tp)
911
Dan Talayco4b2bee62010-07-20 14:10:05 -0700912 # Build the ingress packet
Rich Lane110e0e32012-10-26 16:21:46 -0700913 ingress_pkt = packet_builder(**base_pkt_params)
Dan Talayco4b2bee62010-07-20 14:10:05 -0700914
915 # Build the expected packet, modifying the indicated fields
916 for item in mod_fields:
917 base_pkt_params[item] = mod_pkt_params[item]
918 act = action_generate(parent, item, mod_pkt_params)
919 if act:
920 new_actions.append(act)
921
Rich Lane110e0e32012-10-26 16:21:46 -0700922 expected_pkt = packet_builder(**base_pkt_params)
Dan Talayco4b2bee62010-07-20 14:10:05 -0700923
924 return (ingress_pkt, expected_pkt, new_actions)
Dan Talayco677c0b72011-08-23 22:53:38 -0700925
926# Generate a simple "drop" flow mod
927# If in_band is true, then only drop from first test port
928def flow_mod_gen(port_map, in_band):
929 request = message.flow_mod()
930 request.match.wildcards = ofp.OFPFW_ALL
931 if in_band:
932 request.match.wildcards = ofp.OFPFW_ALL - ofp.OFPFW_IN_PORT
933 for of_port, ifname in port_map.items(): # Grab first port
934 break
935 request.match.in_port = of_port
936 request.buffer_id = 0xffffffff
937 return request
Dan Talaycoba3745c2010-07-21 21:51:08 -0700938
939def skip_message_emit(parent, s):
940 """
941 Print out a 'skipped' message to stderr
942
943 @param s The string to print out to the log file
Rich Lane9a003812012-10-04 17:17:59 -0700944 @param parent Must implement config object
Dan Talaycoba3745c2010-07-21 21:51:08 -0700945 """
946 global skipped_test_count
947
948 skipped_test_count += 1
Rich Lane9a003812012-10-04 17:17:59 -0700949 logging.info("Skipping: " + s)
Rich Lane477f4812012-10-04 22:49:00 -0700950 if config["dbg_level"] < logging.WARNING:
Dan Talaycoba3745c2010-07-21 21:51:08 -0700951 sys.stderr.write("(skipped) ")
952 else:
953 sys.stderr.write("(S)")
Dan Talayco677c0b72011-08-23 22:53:38 -0700954
Dan Talayco8a64e332012-03-28 14:53:20 -0700955
956def all_stats_get(parent):
957 """
958 Get the aggregate stats for all flows in the table
959 @param parent Test instance with controller connection and assert
960 @returns dict with keys flows, packets, bytes, active (flows),
961 lookups, matched
962 """
963 stat_req = message.aggregate_stats_request()
964 stat_req.match = ofp.ofp_match()
965 stat_req.match.wildcards = ofp.OFPFW_ALL
966 stat_req.table_id = 0xff
967 stat_req.out_port = ofp.OFPP_NONE
968
969 rv = {}
970
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700971 (reply, pkt) = parent.controller.transact(stat_req)
Dan Talayco8a64e332012-03-28 14:53:20 -0700972 parent.assertTrue(len(reply.stats) == 1, "Did not receive flow stats reply")
973
974 for obj in reply.stats:
975 (rv["flows"], rv["packets"], rv["bytes"]) = (obj.flow_count,
976 obj.packet_count, obj.byte_count)
977 break
978
979 request = message.table_stats_request()
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700980 (reply , pkt) = parent.controller.transact(request)
Dan Talayco8a64e332012-03-28 14:53:20 -0700981
982
983 (rv["active"], rv["lookups"], rv["matched"]) = (0,0,0)
984 for obj in reply.stats:
985 rv["active"] += obj.active_count
986 rv["lookups"] += obj.lookup_count
987 rv["matched"] += obj.matched_count
988
989 return rv
Dan Talayco2baf8b52012-03-30 09:55:42 -0700990
991FILTER=''.join([(len(repr(chr(x)))==3) and chr(x) or '.'
992 for x in range(256)])
993
994def hex_dump_buffer(src, length=16):
995 """
996 Convert src to a hex dump string and return the string
997 @param src The source buffer
998 @param length The number of bytes shown in each line
999 @returns A string showing the hex dump
1000 """
Dan Talaycoc516fa02012-04-12 22:28:43 -07001001 result = ["\n"]
Dan Talayco2baf8b52012-03-30 09:55:42 -07001002 for i in xrange(0, len(src), length):
1003 chars = src[i:i+length]
1004 hex = ' '.join(["%02x" % ord(x) for x in chars])
1005 printable = ''.join(["%s" % ((ord(x) <= 127 and
1006 FILTER[ord(x)]) or '.') for x in chars])
1007 result.append("%04x %-*s %s\n" % (i, length*3, hex, printable))
1008 return ''.join(result)
1009
1010def format_packet(pkt):
1011 return "Packet length %d \n%s" % (len(str(pkt)),
1012 hex_dump_buffer(str(pkt)))
Rich Lane5d7e89a2012-10-26 16:43:13 -07001013
1014def inspect_packet(pkt):
1015 """
1016 Wrapper around scapy's show() method.
1017 @returns A string showing the dissected packet.
1018 """
1019 from cStringIO import StringIO
1020 out = None
1021 backup = sys.stdout
1022 try:
1023 sys.stdout = StringIO()
1024 pkt.show2()
1025 out = sys.stdout.getvalue()
1026 sys.stdout.close()
1027 finally:
1028 sys.stdout = backup
1029 return out
Rich Lane0a4f6372013-01-02 14:40:22 -08001030
1031def nonstandard(cls):
1032 """
Rich Lanecc45b8e2013-01-02 15:55:02 -08001033 Testcase decorator that marks the test as being non-standard.
1034 These tests are not automatically added to the "standard" group.
Rich Lane0a4f6372013-01-02 14:40:22 -08001035 """
Rich Lanecc45b8e2013-01-02 15:55:02 -08001036 cls._nonstandard = True
Rich Lane0a4f6372013-01-02 14:40:22 -08001037 return cls
1038
1039def disabled(cls):
1040 """
Rich Lanecc45b8e2013-01-02 15:55:02 -08001041 Testcase decorator that marks the test as being disabled.
1042 These tests are not automatically added to the "standard" group or
1043 their module's group.
Rich Lane0a4f6372013-01-02 14:40:22 -08001044 """
Rich Lanecc45b8e2013-01-02 15:55:02 -08001045 cls._disabled = True
Rich Lane0a4f6372013-01-02 14:40:22 -08001046 return cls