blob: 49f47933351b5997442e5c8f6347f1d525388b9e [file] [log] [blame]
Dan Talaycod2ca1032010-03-10 14:40:26 -08001import sys
Dan Talayco92c99122010-06-03 13:53:18 -07002import copy
Rich Lane6242d9f2013-01-06 17:35:39 -08003import logging
4import types
5import time
Rich Lane5a9a1922013-01-11 14:29:30 -08006import re
Rich Lanea68176f2013-08-09 17:41:05 -07007import packet as scapy
Dan Talayco41eae8b2010-03-10 13:57:06 -08008
Rich Lanecd97d3d2013-01-07 18:50:06 -08009import oftest
10import oftest.controller
11import oftest.dataplane
Rich Lanef6883512013-03-11 17:00:09 -070012import oftest.parse
Rich Lane4c504f32013-06-07 17:24:14 -070013import oftest.ofutils
Rich Lanee717c6e2013-03-12 10:25:50 -070014import ofp
Dan Talaycoc901f4d2010-03-07 21:55:45 -080015
Dan Talaycoba3745c2010-07-21 21:51:08 -070016global skipped_test_count
17skipped_test_count = 0
18
Rich Lane7744e112013-01-11 17:23:57 -080019_import_blacklist = set(locals().keys())
20
Dan Talayco551befa2010-07-15 17:05:32 -070021# Some useful defines
22IP_ETHERTYPE = 0x800
23TCP_PROTOCOL = 0x6
24UDP_PROTOCOL = 0x11
25
Jeffrey Townsend5cb7ed32012-08-17 18:11:01 +000026MINSIZE = 0
27
Rich Lane9a003812012-10-04 17:17:59 -070028def delete_all_flows(ctrl):
Dan Talayco41eae8b2010-03-10 13:57:06 -080029 """
30 Delete all flows on the switch
31 @param ctrl The controller object for the test
Dan Talayco41eae8b2010-03-10 13:57:06 -080032 """
33
Rich Lane9a003812012-10-04 17:17:59 -070034 logging.info("Deleting all flows")
Rich Lanee717c6e2013-03-12 10:25:50 -070035 msg = ofp.message.flow_delete()
Rich Lanec717f442013-06-13 15:49:09 -070036 if ofp.OFP_VERSION in [1, 2]:
37 msg.match.wildcards = ofp.OFPFW_ALL
38 msg.out_port = ofp.OFPP_NONE
39 msg.buffer_id = 0xffffffff
40 elif ofp.OFP_VERSION >= 3:
41 msg.table_id = ofp.OFPTT_ALL
42 msg.buffer_id = ofp.OFP_NO_BUFFER
43 msg.out_port = ofp.OFPP_ANY
44 msg.out_group = ofp.OFPG_ANY
Rich Lane5c3151c2013-01-03 17:15:41 -080045 ctrl.message_send(msg)
Rich Lane44c4e3f2013-07-08 10:17:49 -070046 do_barrier(ctrl)
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':
Rich Lanee717c6e2013-03-12 10:25:50 -070052 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)
Ed Swierk99a74de2012-08-22 06:40:54 -070054 else:
55 return 0
56
Dan Talayco41eae8b2010-03-10 13:57:06 -080057def simple_tcp_packet(pktlen=100,
Rich Laned0478ff2013-03-11 12:46:58 -070058 eth_dst='00:01:02:03:04:05',
59 eth_src='00:06:07:08:09:0a',
Tatsuya Yabe460321e2010-05-25 17:50:49 -070060 dl_vlan_enable=False,
Rich Laned0478ff2013-03-11 12:46:58 -070061 vlan_vid=0,
62 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,
Gregor Maier9cc93342013-01-29 16:55:28 -080067 ip_ttl=64,
Dan Talayco41eae8b2010-03-10 13:57:06 -080068 tcp_sport=1234,
Christian Dickmann8b59b4b2012-09-23 16:48:30 -070069 tcp_dport=80,
70 ip_ihl=None,
71 ip_options=False
Dan Talayco41eae8b2010-03-10 13:57:06 -080072 ):
73 """
74 Return a simple dataplane TCP packet
75
76 Supports a few parameters:
77 @param len Length of packet in bytes w/o CRC
Rich Laned0478ff2013-03-11 12:46:58 -070078 @param eth_dst Destinatino MAC
79 @param eth_src Source MAC
Tatsuya Yabe460321e2010-05-25 17:50:49 -070080 @param dl_vlan_enable True if the packet is with vlan, False otherwise
Rich Laned0478ff2013-03-11 12:46:58 -070081 @param vlan_vid VLAN ID
82 @param vlan_pcp VLAN priority
Dan Talayco41eae8b2010-03-10 13:57:06 -080083 @param ip_src IP source
84 @param ip_dst IP destination
Tatsuya Yabe460321e2010-05-25 17:50:49 -070085 @param ip_tos IP ToS
Gregor Maier9cc93342013-01-29 16:55:28 -080086 @param ip_ttl IP TTL
Dan Talayco41eae8b2010-03-10 13:57:06 -080087 @param tcp_dport TCP destination port
88 @param ip_sport TCP source port
89
90 Generates a simple TCP request. Users
91 shouldn't assume anything about this packet other than that
92 it is a valid ethernet/IP/TCP frame.
93 """
Jeffrey Townsend5cb7ed32012-08-17 18:11:01 +000094
95 if MINSIZE > pktlen:
96 pktlen = MINSIZE
97
Dan Talayco551befa2010-07-15 17:05:32 -070098 # Note Dot1Q.id is really CFI
Shudong Zhou43ee54c2012-12-13 15:52:37 -080099 if (dl_vlan_enable):
Rich Laned0478ff2013-03-11 12:46:58 -0700100 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
101 scapy.Dot1Q(prio=vlan_pcp, id=dl_vlan_cfi, vlan=vlan_vid)/ \
Gregor Maier9cc93342013-01-29 16:55:28 -0800102 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ttl=ip_ttl, ihl=ip_ihl)/ \
Tatsuya Yabe460321e2010-05-25 17:50:49 -0700103 scapy.TCP(sport=tcp_sport, dport=tcp_dport)
104 else:
Christian Dickmann8b59b4b2012-09-23 16:48:30 -0700105 if not ip_options:
Rich Laned0478ff2013-03-11 12:46:58 -0700106 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
Gregor Maier9cc93342013-01-29 16:55:28 -0800107 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ttl=ip_ttl, ihl=ip_ihl)/ \
Christian Dickmann8b59b4b2012-09-23 16:48:30 -0700108 scapy.TCP(sport=tcp_sport, dport=tcp_dport)
109 else:
Rich Laned0478ff2013-03-11 12:46:58 -0700110 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
Gregor Maier9cc93342013-01-29 16:55:28 -0800111 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ttl=ip_ttl, ihl=ip_ihl, options=ip_options)/ \
Christian Dickmann8b59b4b2012-09-23 16:48:30 -0700112 scapy.TCP(sport=tcp_sport, dport=tcp_dport)
Tatsuya Yabe460321e2010-05-25 17:50:49 -0700113
Dan Talayco41eae8b2010-03-10 13:57:06 -0800114 pkt = pkt/("D" * (pktlen - len(pkt)))
115
116 return pkt
117
Rich Lane86aceb02013-07-17 18:45:38 -0700118def simple_tcpv6_packet(pktlen=100,
119 eth_dst='00:01:02:03:04:05',
120 eth_src='00:06:07:08:09:0a',
121 dl_vlan_enable=False,
122 vlan_vid=0,
123 vlan_pcp=0,
124 ipv6_src='2001:db8:85a3::8a2e:370:7334',
125 ipv6_dst='2001:db8:85a3::8a2e:370:7335',
126 ipv6_tc=0,
127 ipv6_hlim=64,
128 ipv6_fl=0,
129 tcp_sport=1234,
130 tcp_dport=80):
131 """
132 Return a simple IPv6/TCP packet
133
134 Supports a few parameters:
135 @param len Length of packet in bytes w/o CRC
136 @param eth_dst Destination MAC
137 @param eth_src Source MAC
138 @param dl_vlan_enable True if the packet is with vlan, False otherwise
139 @param vlan_vid VLAN ID
140 @param vlan_pcp VLAN priority
141 @param ipv6_src IPv6 source
142 @param ipv6_dst IPv6 destination
143 @param ipv6_tc IPv6 traffic class
144 @param ipv6_ttl IPv6 hop limit
145 @param ipv6_fl IPv6 flow label
146 @param tcp_dport TCP destination port
147 @param tcp_sport TCP source port
148
149 Generates a simple TCP request. Users shouldn't assume anything about this
150 packet other than that it is a valid ethernet/IPv6/TCP frame.
151 """
152
153 if MINSIZE > pktlen:
154 pktlen = MINSIZE
155
156 pkt = scapy.Ether(dst=eth_dst, src=eth_src)
157 if dl_vlan_enable or vlan_vid or vlan_pcp:
158 pkt /= scapy.Dot1Q(vlan=vlan_vid, prio=vlan_pcp)
159 pkt /= scapy.IPv6(src=ipv6_src, dst=ipv6_dst, fl=ipv6_fl, tc=ipv6_tc, hlim=ipv6_hlim)
160 pkt /= scapy.TCP(sport=tcp_sport, dport=tcp_dport)
161 pkt /= ("D" * (pktlen - len(pkt)))
162
163 return pkt
164
Rich Lane6ee7bea2012-10-26 16:19:29 -0700165def simple_udp_packet(pktlen=100,
Rich Laned0478ff2013-03-11 12:46:58 -0700166 eth_dst='00:01:02:03:04:05',
167 eth_src='00:06:07:08:09:0a',
Rich Lane6ee7bea2012-10-26 16:19:29 -0700168 dl_vlan_enable=False,
Rich Laned0478ff2013-03-11 12:46:58 -0700169 vlan_vid=0,
170 vlan_pcp=0,
Rich Lane6ee7bea2012-10-26 16:19:29 -0700171 dl_vlan_cfi=0,
172 ip_src='192.168.0.1',
173 ip_dst='192.168.0.2',
174 ip_tos=0,
Gregor Maier9cc93342013-01-29 16:55:28 -0800175 ip_ttl=64,
Rich Lane6ee7bea2012-10-26 16:19:29 -0700176 udp_sport=1234,
177 udp_dport=80,
178 ip_ihl=None,
179 ip_options=False
180 ):
181 """
182 Return a simple dataplane UDP packet
183
184 Supports a few parameters:
185 @param len Length of packet in bytes w/o CRC
Rich Laned0478ff2013-03-11 12:46:58 -0700186 @param eth_dst Destination MAC
187 @param eth_src Source MAC
Rich Lane6ee7bea2012-10-26 16:19:29 -0700188 @param dl_vlan_enable True if the packet is with vlan, False otherwise
Rich Laned0478ff2013-03-11 12:46:58 -0700189 @param vlan_vid VLAN ID
190 @param vlan_pcp VLAN priority
Rich Lane6ee7bea2012-10-26 16:19:29 -0700191 @param ip_src IP source
192 @param ip_dst IP destination
193 @param ip_tos IP ToS
Gregor Maier9cc93342013-01-29 16:55:28 -0800194 @param ip_ttl IP TTL
Rich Lane6ee7bea2012-10-26 16:19:29 -0700195 @param udp_dport UDP destination port
196 @param udp_sport UDP source port
197
198 Generates a simple UDP packet. Users shouldn't assume anything about
199 this packet other than that it is a valid ethernet/IP/UDP frame.
200 """
201
202 if MINSIZE > pktlen:
203 pktlen = MINSIZE
204
205 # Note Dot1Q.id is really CFI
206 if (dl_vlan_enable):
Rich Laned0478ff2013-03-11 12:46:58 -0700207 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
208 scapy.Dot1Q(prio=vlan_pcp, id=dl_vlan_cfi, vlan=vlan_vid)/ \
Gregor Maier9cc93342013-01-29 16:55:28 -0800209 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ttl=ip_ttl, ihl=ip_ihl)/ \
Rich Lane6ee7bea2012-10-26 16:19:29 -0700210 scapy.UDP(sport=udp_sport, dport=udp_dport)
211 else:
212 if not ip_options:
Rich Laned0478ff2013-03-11 12:46:58 -0700213 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
Gregor Maier9cc93342013-01-29 16:55:28 -0800214 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ttl=ip_ttl, ihl=ip_ihl)/ \
Rich Lane6ee7bea2012-10-26 16:19:29 -0700215 scapy.UDP(sport=udp_sport, dport=udp_dport)
216 else:
Rich Laned0478ff2013-03-11 12:46:58 -0700217 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
Gregor Maier9cc93342013-01-29 16:55:28 -0800218 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ttl=ip_ttl, ihl=ip_ihl, options=ip_options)/ \
Rich Lane6ee7bea2012-10-26 16:19:29 -0700219 scapy.UDP(sport=udp_sport, dport=udp_dport)
220
221 pkt = pkt/("D" * (pktlen - len(pkt)))
222
223 return pkt
224
Rich Lane86aceb02013-07-17 18:45:38 -0700225def simple_udpv6_packet(pktlen=100,
226 eth_dst='00:01:02:03:04:05',
227 eth_src='00:06:07:08:09:0a',
228 dl_vlan_enable=False,
229 vlan_vid=0,
230 vlan_pcp=0,
231 ipv6_src='2001:db8:85a3::8a2e:370:7334',
232 ipv6_dst='2001:db8:85a3::8a2e:370:7335',
233 ipv6_tc=0,
234 ipv6_hlim=64,
235 ipv6_fl=0,
236 udp_sport=1234,
237 udp_dport=80):
238 """
239 Return a simple IPv6/UDP packet
240
241 Supports a few parameters:
242 @param len Length of packet in bytes w/o CRC
243 @param eth_dst Destination MAC
244 @param eth_src Source MAC
245 @param dl_vlan_enable True if the packet is with vlan, False otherwise
246 @param vlan_vid VLAN ID
247 @param vlan_pcp VLAN priority
248 @param ipv6_src IPv6 source
249 @param ipv6_dst IPv6 destination
250 @param ipv6_tc IPv6 traffic class
251 @param ipv6_ttl IPv6 hop limit
252 @param ipv6_fl IPv6 flow label
253 @param udp_dport UDP destination port
254 @param udp_sport UDP source port
255
256 Generates a simple UDP request. Users shouldn't assume anything about this
257 packet other than that it is a valid ethernet/IPv6/UDP frame.
258 """
259
260 if MINSIZE > pktlen:
261 pktlen = MINSIZE
262
263 pkt = scapy.Ether(dst=eth_dst, src=eth_src)
264 if dl_vlan_enable or vlan_vid or vlan_pcp:
265 pkt /= scapy.Dot1Q(vlan=vlan_vid, prio=vlan_pcp)
266 pkt /= scapy.IPv6(src=ipv6_src, dst=ipv6_dst, fl=ipv6_fl, tc=ipv6_tc, hlim=ipv6_hlim)
267 pkt /= scapy.UDP(sport=udp_sport, dport=udp_dport)
268 pkt /= ("D" * (pktlen - len(pkt)))
269
270 return pkt
271
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700272def simple_icmp_packet(pktlen=60,
Rich Laned0478ff2013-03-11 12:46:58 -0700273 eth_dst='00:01:02:03:04:05',
274 eth_src='00:06:07:08:09:0a',
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700275 dl_vlan_enable=False,
Rich Laned0478ff2013-03-11 12:46:58 -0700276 vlan_vid=0,
277 vlan_pcp=0,
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700278 ip_src='192.168.0.1',
279 ip_dst='192.168.0.2',
280 ip_tos=0,
Gregor Maier9cc93342013-01-29 16:55:28 -0800281 ip_ttl=64,
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700282 icmp_type=8,
283 icmp_code=0
284 ):
285 """
286 Return a simple ICMP packet
287
288 Supports a few parameters:
289 @param len Length of packet in bytes w/o CRC
Rich Laned0478ff2013-03-11 12:46:58 -0700290 @param eth_dst Destinatino MAC
291 @param eth_src Source MAC
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700292 @param dl_vlan_enable True if the packet is with vlan, False otherwise
Rich Laned0478ff2013-03-11 12:46:58 -0700293 @param vlan_vid VLAN ID
294 @param vlan_pcp VLAN priority
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700295 @param ip_src IP source
296 @param ip_dst IP destination
297 @param ip_tos IP ToS
Gregor Maier9cc93342013-01-29 16:55:28 -0800298 @param ip_ttl IP TTL
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700299 @param icmp_type ICMP type
300 @param icmp_code ICMP code
301
302 Generates a simple ICMP ECHO REQUEST. Users
303 shouldn't assume anything about this packet other than that
304 it is a valid ethernet/ICMP frame.
305 """
Jeffrey Townsend5cb7ed32012-08-17 18:11:01 +0000306
307 if MINSIZE > pktlen:
308 pktlen = MINSIZE
309
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700310 if (dl_vlan_enable):
Rich Laned0478ff2013-03-11 12:46:58 -0700311 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
312 scapy.Dot1Q(prio=vlan_pcp, id=0, vlan=vlan_vid)/ \
Gregor Maier9cc93342013-01-29 16:55:28 -0800313 scapy.IP(src=ip_src, dst=ip_dst, ttl=ip_ttl, tos=ip_tos)/ \
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700314 scapy.ICMP(type=icmp_type, code=icmp_code)
315 else:
Rich Laned0478ff2013-03-11 12:46:58 -0700316 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
Gregor Maier9cc93342013-01-29 16:55:28 -0800317 scapy.IP(src=ip_src, dst=ip_dst, ttl=ip_ttl, tos=ip_tos)/ \
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700318 scapy.ICMP(type=icmp_type, code=icmp_code)
319
320 pkt = pkt/("0" * (pktlen - len(pkt)))
321
322 return pkt
323
Rich Lane86aceb02013-07-17 18:45:38 -0700324def simple_icmpv6_packet(pktlen=100,
325 eth_dst='00:01:02:03:04:05',
326 eth_src='00:06:07:08:09:0a',
327 dl_vlan_enable=False,
328 vlan_vid=0,
329 vlan_pcp=0,
330 ipv6_src='2001:db8:85a3::8a2e:370:7334',
331 ipv6_dst='2001:db8:85a3::8a2e:370:7335',
332 ipv6_tc=0,
333 ipv6_hlim=64,
334 ipv6_fl=0,
335 icmp_type=8,
336 icmp_code=0):
337 """
338 Return a simple ICMPv6 packet
339
340 Supports a few parameters:
341 @param len Length of packet in bytes w/o CRC
342 @param eth_dst Destination MAC
343 @param eth_src Source MAC
344 @param dl_vlan_enable True if the packet is with vlan, False otherwise
345 @param vlan_vid VLAN ID
346 @param vlan_pcp VLAN priority
347 @param ipv6_src IPv6 source
348 @param ipv6_dst IPv6 destination
349 @param ipv6_tc IPv6 traffic class
350 @param ipv6_ttl IPv6 hop limit
351 @param ipv6_fl IPv6 flow label
352 @param icmp_type ICMP type
353 @param icmp_code ICMP code
354
355 Generates a simple ICMP ECHO REQUEST. Users shouldn't assume anything
356 about this packet other than that it is a valid ethernet/IPv6/ICMP frame.
357 """
358
359 if MINSIZE > pktlen:
360 pktlen = MINSIZE
361
362 pkt = scapy.Ether(dst=eth_dst, src=eth_src)
363 if dl_vlan_enable or vlan_vid or vlan_pcp:
364 pkt /= scapy.Dot1Q(vlan=vlan_vid, prio=vlan_pcp)
365 pkt /= scapy.IPv6(src=ipv6_src, dst=ipv6_dst, fl=ipv6_fl, tc=ipv6_tc, hlim=ipv6_hlim)
366 pkt /= scapy.ICMPv6Unknown(type=icmp_type, code=icmp_code)
367 pkt /= ("D" * (pktlen - len(pkt)))
368
369 return pkt
370
Shudong Zhouc7562b12013-02-06 01:12:18 -0800371def simple_arp_packet(pktlen=60,
Rich Laned0478ff2013-03-11 12:46:58 -0700372 eth_dst='ff:ff:ff:ff:ff:ff',
373 eth_src='00:06:07:08:09:0a',
Shudong Zhouc7562b12013-02-06 01:12:18 -0800374 arp_op=1,
375 ip_snd='192.168.0.1',
376 ip_tgt='192.168.0.2',
377 hw_snd='00:06:07:08:09:0a',
378 hw_tgt='00:00:00:00:00:00',
379 ):
380 """
381 Return a simple ARP packet
382
383 Supports a few parameters:
384 @param len Length of packet in bytes w/o CRC
Rich Laned0478ff2013-03-11 12:46:58 -0700385 @param eth_dst Destinatino MAC
386 @param eth_src Source MAC
Shudong Zhouc7562b12013-02-06 01:12:18 -0800387 @param arp_op Operation (1=request, 2=reply)
388 @param ip_snd Sender IP
389 @param ip_tgt Target IP
390 @param hw_snd Sender hardware address
391 @param hw_tgt Target hardware address
392
393 Generates a simple ARP REQUEST. Users
394 shouldn't assume anything about this packet other than that
395 it is a valid ethernet/ARP frame.
396 """
397
398 if MINSIZE > pktlen:
399 pktlen = MINSIZE
400
Rich Laned0478ff2013-03-11 12:46:58 -0700401 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
Shudong Zhouc7562b12013-02-06 01:12:18 -0800402 scapy.ARP(hwsrc=hw_snd, hwdst=hw_tgt, pdst=ip_tgt, psrc=ip_snd, op=arp_op)
403
404 pkt = pkt/("0" * (pktlen - len(pkt)))
405
406 return pkt
407
Ed Swierk0aeff8c2012-03-23 20:27:18 -0700408def simple_eth_packet(pktlen=60,
Rich Laneb7dc3e22013-08-02 13:51:06 -0700409 eth_dst='01:80:c2:00:00:00',
410 eth_src='00:01:02:03:04:05',
Rich Laned0478ff2013-03-11 12:46:58 -0700411 eth_type=0x88cc):
Jeffrey Townsend5cb7ed32012-08-17 18:11:01 +0000412
413 if MINSIZE > pktlen:
414 pktlen = MINSIZE
415
Rich Laned0478ff2013-03-11 12:46:58 -0700416 pkt = scapy.Ether(dst=eth_dst, src=eth_src, type=eth_type)
Ed Swierk0aeff8c2012-03-23 20:27:18 -0700417
418 pkt = pkt/("0" * (pktlen - len(pkt)))
419
420 return pkt
421
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800422def qinq_tcp_packet(pktlen=100,
Rich Laned0478ff2013-03-11 12:46:58 -0700423 eth_dst='00:01:02:03:04:05',
424 eth_src='00:06:07:08:09:0a',
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800425 dl_vlan_outer=20,
426 dl_vlan_pcp_outer=0,
427 dl_vlan_cfi_outer=0,
Rich Laned0478ff2013-03-11 12:46:58 -0700428 vlan_vid=10,
429 vlan_pcp=0,
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800430 dl_vlan_cfi=0,
431 ip_src='192.168.0.1',
432 ip_dst='192.168.0.2',
433 ip_tos=0,
Gregor Maier9cc93342013-01-29 16:55:28 -0800434 ip_ttl=64,
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800435 tcp_sport=1234,
436 tcp_dport=80,
437 ip_ihl=None,
438 ip_options=False
439 ):
440 """
441 Return a doubly tagged dataplane TCP packet
442
443 Supports a few parameters:
444 @param len Length of packet in bytes w/o CRC
Rich Laned0478ff2013-03-11 12:46:58 -0700445 @param eth_dst Destinatino MAC
446 @param eth_src Source MAC
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800447 @param dl_vlan_outer Outer VLAN ID
448 @param dl_vlan_pcp_outer Outer VLAN priority
449 @param dl_vlan_cfi_outer Outer VLAN cfi bit
Rich Laned0478ff2013-03-11 12:46:58 -0700450 @param vlan_vid Inner VLAN ID
451 @param vlan_pcp VLAN priority
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800452 @param dl_vlan_cfi VLAN cfi bit
453 @param ip_src IP source
454 @param ip_dst IP destination
455 @param ip_tos IP ToS
456 @param tcp_dport TCP destination port
457 @param ip_sport TCP source port
458
459 Generates a TCP request. Users
460 shouldn't assume anything about this packet other than that
461 it is a valid ethernet/IP/TCP frame.
462 """
463
464 if MINSIZE > pktlen:
465 pktlen = MINSIZE
466
467 # Note Dot1Q.id is really CFI
Rich Laned0478ff2013-03-11 12:46:58 -0700468 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800469 scapy.Dot1Q(prio=dl_vlan_pcp_outer, id=dl_vlan_cfi_outer, vlan=dl_vlan_outer)/ \
Rich Laned0478ff2013-03-11 12:46:58 -0700470 scapy.Dot1Q(prio=vlan_pcp, id=dl_vlan_cfi, vlan=vlan_vid)/ \
Gregor Maier9cc93342013-01-29 16:55:28 -0800471 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ttl=ip_ttl, ihl=ip_ihl)/ \
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800472 scapy.TCP(sport=tcp_sport, dport=tcp_dport)
473
474 pkt = pkt/("D" * (pktlen - len(pkt)))
475
476 return pkt
477
Shudong Zhoub7f12462012-11-20 13:01:12 -0800478def do_barrier(ctrl, timeout=-1):
Dan Talayco0fc08bd2012-04-09 16:56:18 -0700479 """
480 Do a barrier command
481 Return 0 on success, -1 on error
482 """
Rich Lanee717c6e2013-03-12 10:25:50 -0700483 b = ofp.message.barrier_request()
Shudong Zhoub7f12462012-11-20 13:01:12 -0800484 (resp, pkt) = ctrl.transact(b, timeout=timeout)
Rich Lane3a261d52013-01-03 17:45:08 -0800485 if resp is None:
486 raise AssertionError("barrier failed")
Dan Talaycof6b94832012-04-12 21:50:57 -0700487 # We'll trust the transaction processing in the controller that xid matched
Rich Lane3a261d52013-01-03 17:45:08 -0800488 return 0 # for backwards compatibility
Dan Talayco92c99122010-06-03 13:53:18 -0700489
Rich Lane9a003812012-10-04 17:17:59 -0700490def port_config_get(controller, port_no):
Dan Talayco92c99122010-06-03 13:53:18 -0700491 """
492 Get a port's configuration
493
494 Gets the switch feature configuration and grabs one port's
495 configuration
496
497 @returns (hwaddr, config, advert) The hwaddress, configuration and
498 advertised values
499 """
Rich Lane6dc865c2013-07-10 10:12:13 -0700500
501 if ofp.OFP_VERSION <= 3:
502 request = ofp.message.features_request()
503 reply, _ = controller.transact(request)
504 if reply is None:
505 logging.warn("Get feature request failed")
506 return None, None, None
507 logging.debug(reply.show())
508 ports = reply.ports
509 else:
510 request = ofp.message.port_desc_stats_request()
511 # TODO do multipart correctly
512 reply, _ = controller.transact(request)
513 if reply is None:
514 logging.warn("Port desc stats request failed")
515 return None, None, None
516 logging.debug(reply.show())
517 ports = reply.entries
518
519 for port in ports:
520 if port.port_no == port_no:
521 return (port.hw_addr, port.config, port.advertised)
Dan Talayco92c99122010-06-03 13:53:18 -0700522
Rich Lane9a003812012-10-04 17:17:59 -0700523 logging.warn("Did not find port number for port config")
Dan Talayco92c99122010-06-03 13:53:18 -0700524 return None, None, None
525
Rich Lane9a003812012-10-04 17:17:59 -0700526def port_config_set(controller, port_no, config, mask):
Dan Talayco92c99122010-06-03 13:53:18 -0700527 """
528 Set the port configuration according the given parameters
529
530 Gets the switch feature configuration and updates one port's
531 configuration value according to config and mask
532 """
Rich Lane9a003812012-10-04 17:17:59 -0700533 logging.info("Setting port " + str(port_no) + " to config " + str(config))
Rich Lane6dc865c2013-07-10 10:12:13 -0700534
535 hw_addr, _, _ = port_config_get(controller, port_no)
536
Rich Lanee717c6e2013-03-12 10:25:50 -0700537 mod = ofp.message.port_mod()
Dan Talayco92c99122010-06-03 13:53:18 -0700538 mod.port_no = port_no
Rich Lane6dc865c2013-07-10 10:12:13 -0700539 if hw_addr != None:
540 mod.hw_addr = hw_addr
Dan Talayco92c99122010-06-03 13:53:18 -0700541 mod.config = config
542 mod.mask = mask
Rich Lane6dc865c2013-07-10 10:12:13 -0700543 mod.advertise = 0 # No change
Rich Lane5c3151c2013-01-03 17:15:41 -0800544 controller.message_send(mod)
545 return 0
Dan Talayco92c99122010-06-03 13:53:18 -0700546
Rich Lane2014f9b2012-10-05 15:29:40 -0700547def receive_pkt_check(dp, pkt, yes_ports, no_ports, assert_if):
Dan Talayco92c99122010-06-03 13:53:18 -0700548 """
549 Check for proper receive packets across all ports
Ken Chiang1bf01602012-04-04 10:48:23 -0700550 @param dp The dataplane object
Dan Talayco92c99122010-06-03 13:53:18 -0700551 @param pkt Expected packet; may be None if yes_ports is empty
552 @param yes_ports Set or list of ports that should recieve packet
553 @param no_ports Set or list of ports that should not receive packet
554 @param assert_if Object that implements assertXXX
555 """
Rich Lane91765672012-12-06 16:33:04 -0800556
557 # Wait this long for packets that we don't expect to receive.
558 # 100ms is (rarely) too short for positive tests on slow
559 # switches but is definitely not too short for a negative test.
560 negative_timeout = 0.1
561
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700562 exp_pkt_arg = None
Rich Lanecd97d3d2013-01-07 18:50:06 -0800563 if oftest.config["relax"]:
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700564 exp_pkt_arg = pkt
565
Dan Talayco92c99122010-06-03 13:53:18 -0700566 for ofport in yes_ports:
Rich Lane9a003812012-10-04 17:17:59 -0700567 logging.debug("Checking for pkt on port " + str(ofport))
Ken Chiang1bf01602012-04-04 10:48:23 -0700568 (rcv_port, rcv_pkt, pkt_time) = dp.poll(
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700569 port_number=ofport, exp_pkt=exp_pkt_arg)
Dan Talayco92c99122010-06-03 13:53:18 -0700570 assert_if.assertTrue(rcv_pkt is not None,
571 "Did not receive pkt on " + str(ofport))
Rich Lanecd97d3d2013-01-07 18:50:06 -0800572 if not oftest.dataplane.match_exp_pkt(pkt, rcv_pkt):
Rich Lane3c266832013-01-29 18:29:15 -0800573 logging.debug("Expected %s" % format_packet(pkt))
574 logging.debug("Received %s" % format_packet(rcv_pkt))
Rich Lanecd97d3d2013-01-07 18:50:06 -0800575 assert_if.assertTrue(oftest.dataplane.match_exp_pkt(pkt, rcv_pkt),
Rich Lane3c266832013-01-29 18:29:15 -0800576 "Received packet does not match expected packet " +
Ken Chiang1bf01602012-04-04 10:48:23 -0700577 "on port " + str(ofport))
Dan Talayco73f84012012-10-02 09:23:18 -0700578 if len(no_ports) > 0:
Rich Lane91765672012-12-06 16:33:04 -0800579 time.sleep(negative_timeout)
Dan Talayco92c99122010-06-03 13:53:18 -0700580 for ofport in no_ports:
Rich Lane9a003812012-10-04 17:17:59 -0700581 logging.debug("Negative check for pkt on port " + str(ofport))
Ken Chiang1bf01602012-04-04 10:48:23 -0700582 (rcv_port, rcv_pkt, pkt_time) = dp.poll(
Rich Lane91765672012-12-06 16:33:04 -0800583 port_number=ofport, timeout=0, exp_pkt=exp_pkt_arg)
Dan Talayco92c99122010-06-03 13:53:18 -0700584 assert_if.assertTrue(rcv_pkt is None,
585 "Unexpected pkt on port " + str(ofport))
Dan Talayco551befa2010-07-15 17:05:32 -0700586
587
Dan Talaycoc948d0b2012-03-23 12:17:54 -0700588def receive_pkt_verify(parent, egr_ports, exp_pkt, ing_port):
Dan Talayco551befa2010-07-15 17:05:32 -0700589 """
590 Receive a packet and verify it matches an expected value
Dan Talaycof6e76c02012-03-23 10:56:12 -0700591 @param egr_port A single port or list of ports
Dan Talayco551befa2010-07-15 17:05:32 -0700592
593 parent must implement dataplane, assertTrue and assertEqual
594 """
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700595 exp_pkt_arg = None
Rich Lanecd97d3d2013-01-07 18:50:06 -0800596 if oftest.config["relax"]:
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700597 exp_pkt_arg = exp_pkt
598
Dan Talaycof6e76c02012-03-23 10:56:12 -0700599 if type(egr_ports) == type([]):
600 egr_port_list = egr_ports
601 else:
602 egr_port_list = [egr_ports]
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700603
Dan Talaycof6e76c02012-03-23 10:56:12 -0700604 # Expect a packet from each port on egr port list
605 for egr_port in egr_port_list:
Dan Talaycod8ae7582012-03-23 12:24:56 -0700606 check_port = egr_port
Rich Lanee717c6e2013-03-12 10:25:50 -0700607 if egr_port == ofp.OFPP_IN_PORT:
Dan Talaycod8ae7582012-03-23 12:24:56 -0700608 check_port = ing_port
Dan Talaycof6e76c02012-03-23 10:56:12 -0700609 (rcv_port, rcv_pkt, pkt_time) = parent.dataplane.poll(
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700610 port_number=check_port, exp_pkt=exp_pkt_arg)
Dan Talayco551befa2010-07-15 17:05:32 -0700611
Dan Talaycof6e76c02012-03-23 10:56:12 -0700612 if rcv_pkt is None:
Rich Lane9a003812012-10-04 17:17:59 -0700613 logging.error("ERROR: No packet received from " +
Dan Talaycod8ae7582012-03-23 12:24:56 -0700614 str(check_port))
Dan Talayco551befa2010-07-15 17:05:32 -0700615
Dan Talaycof6e76c02012-03-23 10:56:12 -0700616 parent.assertTrue(rcv_pkt is not None,
Dan Talaycod8ae7582012-03-23 12:24:56 -0700617 "Did not receive packet port " + str(check_port))
Rich Lane9a003812012-10-04 17:17:59 -0700618 logging.debug("Packet len " + str(len(rcv_pkt)) + " in on " +
Dan Talaycof6e76c02012-03-23 10:56:12 -0700619 str(rcv_port))
620
621 if str(exp_pkt) != str(rcv_pkt):
Rich Lane9a003812012-10-04 17:17:59 -0700622 logging.error("ERROR: Packet match failed.")
623 logging.debug("Expected len " + str(len(exp_pkt)) + ": "
Dan Talaycof6e76c02012-03-23 10:56:12 -0700624 + str(exp_pkt).encode('hex'))
Rich Lane9a003812012-10-04 17:17:59 -0700625 logging.debug("Received len " + str(len(rcv_pkt)) + ": "
Dan Talaycof6e76c02012-03-23 10:56:12 -0700626 + str(rcv_pkt).encode('hex'))
Rich Lane5d7e89a2012-10-26 16:43:13 -0700627 logging.debug("Expected packet: " + inspect_packet(scapy.Ether(str(exp_pkt))))
628 logging.debug("Received packet: " + inspect_packet(scapy.Ether(str(rcv_pkt))))
Dan Talaycof6e76c02012-03-23 10:56:12 -0700629 parent.assertEqual(str(exp_pkt), str(rcv_pkt),
Dan Talaycod8ae7582012-03-23 12:24:56 -0700630 "Packet match error on port " + str(check_port))
Dan Talaycof6e76c02012-03-23 10:56:12 -0700631
Dan Talayco551befa2010-07-15 17:05:32 -0700632def match_verify(parent, req_match, res_match):
633 """
634 Verify flow matches agree; if they disagree, report where
635
636 parent must implement assertEqual
637 Use str() to ensure content is compared and not pointers
638 """
639
640 parent.assertEqual(req_match.wildcards, res_match.wildcards,
641 'Match failed: wildcards: ' + hex(req_match.wildcards) +
642 " != " + hex(res_match.wildcards))
643 parent.assertEqual(req_match.in_port, res_match.in_port,
644 'Match failed: in_port: ' + str(req_match.in_port) +
645 " != " + str(res_match.in_port))
Rich Laned0478ff2013-03-11 12:46:58 -0700646 parent.assertEqual(str(req_match.eth_src), str(res_match.eth_src),
647 'Match failed: eth_src: ' + str(req_match.eth_src) +
648 " != " + str(res_match.eth_src))
649 parent.assertEqual(str(req_match.eth_dst), str(res_match.eth_dst),
650 'Match failed: eth_dst: ' + str(req_match.eth_dst) +
651 " != " + str(res_match.eth_dst))
652 parent.assertEqual(req_match.vlan_vid, res_match.vlan_vid,
653 'Match failed: vlan_vid: ' + str(req_match.vlan_vid) +
654 " != " + str(res_match.vlan_vid))
655 parent.assertEqual(req_match.vlan_pcp, res_match.vlan_pcp,
656 'Match failed: vlan_pcp: ' +
657 str(req_match.vlan_pcp) + " != " +
658 str(res_match.vlan_pcp))
659 parent.assertEqual(req_match.eth_type, res_match.eth_type,
660 'Match failed: eth_type: ' + str(req_match.eth_type) +
661 " != " + str(res_match.eth_type))
Dan Talayco551befa2010-07-15 17:05:32 -0700662
Rich Lanee717c6e2013-03-12 10:25:50 -0700663 if (not(req_match.wildcards & ofp.OFPFW_DL_TYPE)
Rich Laned0478ff2013-03-11 12:46:58 -0700664 and (req_match.eth_type == IP_ETHERTYPE)):
665 parent.assertEqual(req_match.ip_dscp, res_match.ip_dscp,
666 'Match failed: ip_dscp: ' + str(req_match.ip_dscp) +
667 " != " + str(res_match.ip_dscp))
668 parent.assertEqual(req_match.ip_proto, res_match.ip_proto,
669 'Match failed: ip_proto: ' + str(req_match.ip_proto) +
670 " != " + str(res_match.ip_proto))
671 parent.assertEqual(req_match.ipv4_src, res_match.ipv4_src,
672 'Match failed: ipv4_src: ' + str(req_match.ipv4_src) +
673 " != " + str(res_match.ipv4_src))
674 parent.assertEqual(req_match.ipv4_dst, res_match.ipv4_dst,
675 'Match failed: ipv4_dst: ' + str(req_match.ipv4_dst) +
676 " != " + str(res_match.ipv4_dst))
Dan Talayco551befa2010-07-15 17:05:32 -0700677
Rich Lanee717c6e2013-03-12 10:25:50 -0700678 if (not(req_match.wildcards & ofp.OFPFW_NW_PROTO)
Rich Laned0478ff2013-03-11 12:46:58 -0700679 and ((req_match.ip_proto == TCP_PROTOCOL)
680 or (req_match.ip_proto == UDP_PROTOCOL))):
681 parent.assertEqual(req_match.tcp_src, res_match.tcp_src,
682 'Match failed: tcp_src: ' +
683 str(req_match.tcp_src) +
684 " != " + str(res_match.tcp_src))
685 parent.assertEqual(req_match.tcp_dst, res_match.tcp_dst,
686 'Match failed: tcp_dst: ' +
687 str(req_match.tcp_dst) +
688 " != " + str(res_match.tcp_dst))
Dan Talayco551befa2010-07-15 17:05:32 -0700689
Ed Swierk99a74de2012-08-22 06:40:54 -0700690def packet_to_flow_match(parent, packet):
Rich Lanef6883512013-03-11 17:00:09 -0700691 match = oftest.parse.packet_to_flow_match(packet)
Rich Laneab7476f2013-06-13 15:53:52 -0700692 if ofp.OFP_VERSION in [1, 2]:
693 match.wildcards |= required_wildcards(parent)
694 else:
695 # TODO remove incompatible OXM entries
696 pass
Ed Swierk99a74de2012-08-22 06:40:54 -0700697 return match
698
699def flow_msg_create(parent, pkt, ing_port=None, action_list=None, wildcards=None,
Dan Talaycof6e76c02012-03-23 10:56:12 -0700700 egr_ports=None, egr_queue=None, check_expire=False, in_band=False):
Dan Talayco551befa2010-07-15 17:05:32 -0700701 """
702 Create a flow message
703
704 Match on packet with given wildcards.
705 See flow_match_test for other parameter descriptoins
706 @param egr_queue if not None, make the output an enqueue action
Dan Talayco677c0b72011-08-23 22:53:38 -0700707 @param in_band if True, do not wildcard ingress port
Dan Talaycof6e76c02012-03-23 10:56:12 -0700708 @param egr_ports None (drop), single port or list of ports
Dan Talayco551befa2010-07-15 17:05:32 -0700709 """
Rich Lanef6883512013-03-11 17:00:09 -0700710 match = oftest.parse.packet_to_flow_match(pkt)
Dan Talayco551befa2010-07-15 17:05:32 -0700711 parent.assertTrue(match is not None, "Flow match from pkt failed")
Ed Swierk99a74de2012-08-22 06:40:54 -0700712 if wildcards is None:
713 wildcards = required_wildcards(parent)
Dan Talayco677c0b72011-08-23 22:53:38 -0700714 if in_band:
Rich Lanee717c6e2013-03-12 10:25:50 -0700715 wildcards &= ~ofp.OFPFW_IN_PORT
Dan Talayco551befa2010-07-15 17:05:32 -0700716 match.wildcards = wildcards
717 match.in_port = ing_port
718
Dan Talaycof6e76c02012-03-23 10:56:12 -0700719 if type(egr_ports) == type([]):
720 egr_port_list = egr_ports
721 else:
722 egr_port_list = [egr_ports]
723
Rich Lanee717c6e2013-03-12 10:25:50 -0700724 request = ofp.message.flow_add()
Dan Talayco551befa2010-07-15 17:05:32 -0700725 request.match = match
726 request.buffer_id = 0xffffffff
727 if check_expire:
Rich Lanee717c6e2013-03-12 10:25:50 -0700728 request.flags |= ofp.OFPFF_SEND_FLOW_REM
Dan Talayco551befa2010-07-15 17:05:32 -0700729 request.hard_timeout = 1
730
731 if action_list is not None:
732 for act in action_list:
Rich Lane9a003812012-10-04 17:17:59 -0700733 logging.debug("Adding action " + act.show())
Rich Lanec495d9e2013-03-08 17:43:36 -0800734 request.actions.append(act)
Dan Talayco551befa2010-07-15 17:05:32 -0700735
736 # Set up output/enqueue action if directed
737 if egr_queue is not None:
Dan Talaycof6e76c02012-03-23 10:56:12 -0700738 parent.assertTrue(egr_ports is not None, "Egress port not set")
Rich Lanee717c6e2013-03-12 10:25:50 -0700739 act = ofp.action.enqueue()
Dan Talaycof6e76c02012-03-23 10:56:12 -0700740 for egr_port in egr_port_list:
741 act.port = egr_port
742 act.queue_id = egr_queue
Rich Lanec495d9e2013-03-08 17:43:36 -0800743 request.actions.append(act)
Dan Talaycof6e76c02012-03-23 10:56:12 -0700744 elif egr_ports is not None:
745 for egr_port in egr_port_list:
Rich Lanee717c6e2013-03-12 10:25:50 -0700746 act = ofp.action.output()
Dan Talaycof6e76c02012-03-23 10:56:12 -0700747 act.port = egr_port
Rich Lanec495d9e2013-03-08 17:43:36 -0800748 request.actions.append(act)
Dan Talayco551befa2010-07-15 17:05:32 -0700749
Rich Lane9a003812012-10-04 17:17:59 -0700750 logging.debug(request.show())
Dan Talayco551befa2010-07-15 17:05:32 -0700751
752 return request
753
Jeffrey Townsendf3eae9c2012-03-28 18:23:21 -0700754def flow_msg_install(parent, request, clear_table_override=None):
Dan Talayco551befa2010-07-15 17:05:32 -0700755 """
756 Install a flow mod message in the switch
757
758 @param parent Must implement controller, assertEqual, assertTrue
759 @param request The request, all set to go
760 @param clear_table If true, clear the flow table before installing
761 """
Dan Talayco8a64e332012-03-28 14:53:20 -0700762
Rich Lane2014f9b2012-10-05 15:29:40 -0700763 clear_table = test_param_get('clear_table', default=True)
Jeffrey Townsendf3eae9c2012-03-28 18:23:21 -0700764 if(clear_table_override != None):
765 clear_table = clear_table_override
766
767 if clear_table:
Rich Lane9a003812012-10-04 17:17:59 -0700768 logging.debug("Clear flow table")
Rich Lane32bf9482013-01-03 17:26:30 -0800769 delete_all_flows(parent.controller)
Dan Talayco551befa2010-07-15 17:05:32 -0700770
Rich Lane9a003812012-10-04 17:17:59 -0700771 logging.debug("Insert flow")
Rich Lane5c3151c2013-01-03 17:15:41 -0800772 parent.controller.message_send(request)
Rich Lanee912d032012-12-22 14:28:33 -0800773
Rich Lane3a261d52013-01-03 17:45:08 -0800774 do_barrier(parent.controller)
Dan Talayco551befa2010-07-15 17:05:32 -0700775
Ed Swierk99a74de2012-08-22 06:40:54 -0700776def flow_match_test_port_pair(parent, ing_port, egr_ports, wildcards=None,
Rich Laned0478ff2013-03-11 12:46:58 -0700777 vlan_vid=-1, pkt=None, exp_pkt=None,
Rich Lanee5779d32012-10-05 17:56:04 -0700778 action_list=None):
Dan Talayco551befa2010-07-15 17:05:32 -0700779 """
780 Flow match test on single TCP packet
Dan Talaycof6e76c02012-03-23 10:56:12 -0700781 @param egr_ports A single port or list of ports
Dan Talayco551befa2010-07-15 17:05:32 -0700782
783 Run test with packet through switch from ing_port to egr_port
784 See flow_match_test for parameter descriptions
785 """
786
Ed Swierk99a74de2012-08-22 06:40:54 -0700787 if wildcards is None:
788 wildcards = required_wildcards(parent)
Rich Lane9a003812012-10-04 17:17:59 -0700789 logging.info("Pkt match test: " + str(ing_port) + " to " +
Dan Talaycof6e76c02012-03-23 10:56:12 -0700790 str(egr_ports))
Rich Laned0478ff2013-03-11 12:46:58 -0700791 logging.debug(" WC: " + hex(wildcards) + " vlan: " + str(vlan_vid))
Dan Talayco551befa2010-07-15 17:05:32 -0700792 if pkt is None:
Rich Laned0478ff2013-03-11 12:46:58 -0700793 pkt = simple_tcp_packet(dl_vlan_enable=(vlan_vid >= 0), vlan_vid=vlan_vid)
Dan Talayco551befa2010-07-15 17:05:32 -0700794
795 request = flow_msg_create(parent, pkt, ing_port=ing_port,
Dan Talaycof6e76c02012-03-23 10:56:12 -0700796 wildcards=wildcards, egr_ports=egr_ports,
Dan Talayco551befa2010-07-15 17:05:32 -0700797 action_list=action_list)
798
799 flow_msg_install(parent, request)
800
Rich Lane9a003812012-10-04 17:17:59 -0700801 logging.debug("Send packet: " + str(ing_port) + " to " +
Dan Talaycof6e76c02012-03-23 10:56:12 -0700802 str(egr_ports))
Dan Talayco551befa2010-07-15 17:05:32 -0700803 parent.dataplane.send(ing_port, str(pkt))
804
805 if exp_pkt is None:
806 exp_pkt = pkt
Dan Talaycoc948d0b2012-03-23 12:17:54 -0700807 receive_pkt_verify(parent, egr_ports, exp_pkt, ing_port)
Dan Talayco551befa2010-07-15 17:05:32 -0700808
Rich Lane89725bb2012-12-03 16:23:27 -0800809def flow_match_test_pktout(parent, ing_port, egr_ports,
Rich Laned0478ff2013-03-11 12:46:58 -0700810 vlan_vid=-1, pkt=None, exp_pkt=None,
Rich Lane89725bb2012-12-03 16:23:27 -0800811 action_list=None):
812 """
813 Packet-out test on single TCP packet
814 @param egr_ports A single port or list of ports
815
816 Run test sending packet-out to egr_ports. The goal is to test the actions
817 taken on the packet, not the matching which is of course irrelevant.
818 See flow_match_test for parameter descriptions
819 """
820
821 if pkt is None:
Rich Laned0478ff2013-03-11 12:46:58 -0700822 pkt = simple_tcp_packet(dl_vlan_enable=(vlan_vid >= 0), vlan_vid=vlan_vid)
Rich Lane89725bb2012-12-03 16:23:27 -0800823
Rich Lanee717c6e2013-03-12 10:25:50 -0700824 msg = ofp.message.packet_out()
Rich Lane89725bb2012-12-03 16:23:27 -0800825 msg.in_port = ing_port
Rich Laneea8c4722013-04-04 15:30:20 -0700826 msg.buffer_id = 0xffffffff
Rich Lane89725bb2012-12-03 16:23:27 -0800827 msg.data = str(pkt)
828 if action_list is not None:
829 for act in action_list:
Rich Lanec495d9e2013-03-08 17:43:36 -0800830 msg.actions.append(act)
Rich Lane89725bb2012-12-03 16:23:27 -0800831
832 # Set up output action
833 if egr_ports is not None:
834 for egr_port in egr_ports:
Rich Lanee717c6e2013-03-12 10:25:50 -0700835 act = ofp.action.output()
Rich Lane89725bb2012-12-03 16:23:27 -0800836 act.port = egr_port
Rich Lanec495d9e2013-03-08 17:43:36 -0800837 msg.actions.append(act)
Rich Lane89725bb2012-12-03 16:23:27 -0800838
839 logging.debug(msg.show())
Rich Lane5c3151c2013-01-03 17:15:41 -0800840 parent.controller.message_send(msg)
Rich Lane89725bb2012-12-03 16:23:27 -0800841
842 if exp_pkt is None:
843 exp_pkt = pkt
844 receive_pkt_verify(parent, egr_ports, exp_pkt, ing_port)
845
Dan Talaycof6e76c02012-03-23 10:56:12 -0700846def get_egr_list(parent, of_ports, how_many, exclude_list=[]):
847 """
848 Generate a list of ports avoiding those in the exclude list
Rich Lane9a003812012-10-04 17:17:59 -0700849 @param parent Supplies logging
Dan Talaycof6e76c02012-03-23 10:56:12 -0700850 @param of_ports List of OF port numbers
851 @param how_many Number of ports to be added to the list
852 @param exclude_list List of ports not to be used
853 @returns An empty list if unable to find enough ports
854 """
855
Dan Talaycoc948d0b2012-03-23 12:17:54 -0700856 if how_many == 0:
857 return []
858
Dan Talaycof6e76c02012-03-23 10:56:12 -0700859 count = 0
860 egr_ports = []
861 for egr_idx in range(len(of_ports)):
862 if of_ports[egr_idx] not in exclude_list:
863 egr_ports.append(of_ports[egr_idx])
864 count += 1
865 if count >= how_many:
866 return egr_ports
Rich Lane9a003812012-10-04 17:17:59 -0700867 logging.debug("Could not generate enough egress ports for test")
Dan Talaycof6e76c02012-03-23 10:56:12 -0700868 return []
869
Rich Laned0478ff2013-03-11 12:46:58 -0700870def flow_match_test(parent, port_map, wildcards=None, vlan_vid=-1, pkt=None,
Rich Lanee5779d32012-10-05 17:56:04 -0700871 exp_pkt=None, action_list=None,
Dan Talaycoc948d0b2012-03-23 12:17:54 -0700872 max_test=0, egr_count=1, ing_port=False):
Dan Talayco551befa2010-07-15 17:05:32 -0700873 """
Rich Lane89725bb2012-12-03 16:23:27 -0800874 Run flow_match_test_port_pair on all port pairs and packet-out
Dan Talayco551befa2010-07-15 17:05:32 -0700875
876 @param max_test If > 0 no more than this number of tests are executed.
877 @param parent Must implement controller, dataplane, assertTrue, assertEqual
Rich Lane9a003812012-10-04 17:17:59 -0700878 and logging
Dan Talayco551befa2010-07-15 17:05:32 -0700879 @param pkt If not None, use this packet for ingress
880 @param wildcards For flow match entry
Rich Laned0478ff2013-03-11 12:46:58 -0700881 @param vlan_vid If not -1, and pkt is None, create a pkt w/ VLAN tag
Dan Talayco551befa2010-07-15 17:05:32 -0700882 @param exp_pkt If not None, use this as the expected output pkt; els use pkt
883 @param action_list Additional actions to add to flow mod
Dan Talaycocfa172f2012-03-23 12:03:00 -0700884 @param egr_count Number of egress ports; -1 means get from config w/ dflt 2
Dan Talayco551befa2010-07-15 17:05:32 -0700885 """
Ed Swierk99a74de2012-08-22 06:40:54 -0700886 if wildcards is None:
887 wildcards = required_wildcards(parent)
Dan Talayco551befa2010-07-15 17:05:32 -0700888 of_ports = port_map.keys()
889 of_ports.sort()
890 parent.assertTrue(len(of_ports) > 1, "Not enough ports for test")
891 test_count = 0
892
Dan Talaycocfa172f2012-03-23 12:03:00 -0700893 if egr_count == -1:
Rich Lane2014f9b2012-10-05 15:29:40 -0700894 egr_count = test_param_get('egr_count', default=2)
Dan Talaycocfa172f2012-03-23 12:03:00 -0700895
Dan Talayco551befa2010-07-15 17:05:32 -0700896 for ing_idx in range(len(of_ports)):
897 ingress_port = of_ports[ing_idx]
Dan Talaycof6e76c02012-03-23 10:56:12 -0700898 egr_ports = get_egr_list(parent, of_ports, egr_count,
899 exclude_list=[ingress_port])
Dan Talaycoc948d0b2012-03-23 12:17:54 -0700900 if ing_port:
Rich Lanee717c6e2013-03-12 10:25:50 -0700901 egr_ports.append(ofp.OFPP_IN_PORT)
Dan Talaycof6e76c02012-03-23 10:56:12 -0700902 if len(egr_ports) == 0:
903 parent.assertTrue(0, "Failed to generate egress port list")
904
905 flow_match_test_port_pair(parent, ingress_port, egr_ports,
Rich Laned0478ff2013-03-11 12:46:58 -0700906 wildcards=wildcards, vlan_vid=vlan_vid,
Dan Talaycof6e76c02012-03-23 10:56:12 -0700907 pkt=pkt, exp_pkt=exp_pkt,
Rich Lanee5779d32012-10-05 17:56:04 -0700908 action_list=action_list)
Dan Talaycof6e76c02012-03-23 10:56:12 -0700909 test_count += 1
910 if (max_test > 0) and (test_count > max_test):
Rich Lane9a003812012-10-04 17:17:59 -0700911 logging.info("Ran " + str(test_count) + " tests; exiting")
Rich Lane89725bb2012-12-03 16:23:27 -0800912 break
913
Ed Swierk38eea082013-01-02 19:46:20 -0800914 if not test_param_get('pktout_actions', default=True):
915 return
Rich Lane89725bb2012-12-03 16:23:27 -0800916
917 ingress_port = of_ports[0]
918 egr_ports = get_egr_list(parent, of_ports, egr_count,
919 exclude_list=[ingress_port])
920 if ing_port:
Rich Lanee717c6e2013-03-12 10:25:50 -0700921 egr_ports.append(ofp.OFPP_IN_PORT)
Rich Lane89725bb2012-12-03 16:23:27 -0800922 flow_match_test_pktout(parent, ingress_port, egr_ports,
Rich Laned0478ff2013-03-11 12:46:58 -0700923 vlan_vid=vlan_vid,
Rich Lane89725bb2012-12-03 16:23:27 -0800924 pkt=pkt, exp_pkt=exp_pkt,
925 action_list=action_list)
Dan Talayco551befa2010-07-15 17:05:32 -0700926
Rich Lane2014f9b2012-10-05 15:29:40 -0700927def test_param_get(key, default=None):
Dan Talayco4b2bee62010-07-20 14:10:05 -0700928 """
929 Return value passed via test-params if present
930
Dan Talayco4b2bee62010-07-20 14:10:05 -0700931 @param key The lookup key
932 @param default Default value to use if not found
933
934 If the pair 'key=val' appeared in the string passed to --test-params
935 on the command line, return val (as interpreted by exec). Otherwise
936 return default value.
Dan Talaycof6e76c02012-03-23 10:56:12 -0700937
938 WARNING: TEST PARAMETERS MUST BE PYTHON IDENTIFIERS;
939 eg egr_count, not egr-count.
Dan Talayco4b2bee62010-07-20 14:10:05 -0700940 """
941 try:
Rich Lanecd97d3d2013-01-07 18:50:06 -0800942 exec oftest.config["test_params"]
Dan Talayco4b2bee62010-07-20 14:10:05 -0700943 except:
944 return default
945
Dan Talayco4b2bee62010-07-20 14:10:05 -0700946 try:
Rich Lanefdec0fb2013-08-09 18:01:05 -0700947 return eval(str(key))
Dan Talayco4b2bee62010-07-20 14:10:05 -0700948 except:
949 return default
950
951def action_generate(parent, field_to_mod, mod_field_vals):
952 """
953 Create an action to modify the field indicated in field_to_mod
954
955 @param parent Must implement, assertTrue
956 @param field_to_mod The field to modify as a string name
957 @param mod_field_vals Hash of values to use for modified values
958 """
959
960 act = None
961
962 if field_to_mod in ['pktlen']:
963 return None
964
Rich Laned0478ff2013-03-11 12:46:58 -0700965 if field_to_mod == 'eth_dst':
Rich Lanee717c6e2013-03-12 10:25:50 -0700966 act = ofp.action.set_dl_dst()
Rich Lanef6883512013-03-11 17:00:09 -0700967 act.dl_addr = oftest.parse.parse_mac(mod_field_vals['eth_dst'])
Rich Laned0478ff2013-03-11 12:46:58 -0700968 elif field_to_mod == 'eth_src':
Rich Lanee717c6e2013-03-12 10:25:50 -0700969 act = ofp.action.set_dl_src()
Rich Lanef6883512013-03-11 17:00:09 -0700970 act.dl_addr = oftest.parse.parse_mac(mod_field_vals['eth_src'])
Dan Talayco4b2bee62010-07-20 14:10:05 -0700971 elif field_to_mod == 'dl_vlan_enable':
972 if not mod_field_vals['dl_vlan_enable']: # Strip VLAN tag
Rich Lanee717c6e2013-03-12 10:25:50 -0700973 act = ofp.action.strip_vlan()
Rich Laned0478ff2013-03-11 12:46:58 -0700974 # Add VLAN tag is handled by vlan_vid field
Dan Talayco4b2bee62010-07-20 14:10:05 -0700975 # Will return None in this case
Rich Laned0478ff2013-03-11 12:46:58 -0700976 elif field_to_mod == 'vlan_vid':
Rich Lanee717c6e2013-03-12 10:25:50 -0700977 act = ofp.action.set_vlan_vid()
Rich Laned0478ff2013-03-11 12:46:58 -0700978 act.vlan_vid = mod_field_vals['vlan_vid']
979 elif field_to_mod == 'vlan_pcp':
Rich Lanee717c6e2013-03-12 10:25:50 -0700980 act = ofp.action.set_vlan_pcp()
Rich Laned0478ff2013-03-11 12:46:58 -0700981 act.vlan_pcp = mod_field_vals['vlan_pcp']
Dan Talayco4b2bee62010-07-20 14:10:05 -0700982 elif field_to_mod == 'ip_src':
Rich Lanee717c6e2013-03-12 10:25:50 -0700983 act = ofp.action.set_nw_src()
Rich Lanef6883512013-03-11 17:00:09 -0700984 act.nw_addr = oftest.parse.parse_ip(mod_field_vals['ip_src'])
Dan Talayco4b2bee62010-07-20 14:10:05 -0700985 elif field_to_mod == 'ip_dst':
Rich Lanee717c6e2013-03-12 10:25:50 -0700986 act = ofp.action.set_nw_dst()
Rich Lanef6883512013-03-11 17:00:09 -0700987 act.nw_addr = oftest.parse.parse_ip(mod_field_vals['ip_dst'])
Dan Talayco4b2bee62010-07-20 14:10:05 -0700988 elif field_to_mod == 'ip_tos':
Rich Lanee717c6e2013-03-12 10:25:50 -0700989 act = ofp.action.set_nw_tos()
Dan Talayco4b2bee62010-07-20 14:10:05 -0700990 act.nw_tos = mod_field_vals['ip_tos']
991 elif field_to_mod == 'tcp_sport':
Rich Lanee717c6e2013-03-12 10:25:50 -0700992 act = ofp.action.set_tp_src()
Dan Talayco4b2bee62010-07-20 14:10:05 -0700993 act.tp_port = mod_field_vals['tcp_sport']
994 elif field_to_mod == 'tcp_dport':
Rich Lanee717c6e2013-03-12 10:25:50 -0700995 act = ofp.action.set_tp_dst()
Dan Talayco4b2bee62010-07-20 14:10:05 -0700996 act.tp_port = mod_field_vals['tcp_dport']
Rich Lane110e0e32012-10-26 16:21:46 -0700997 elif field_to_mod == 'udp_sport':
Rich Lanee717c6e2013-03-12 10:25:50 -0700998 act = ofp.action.set_tp_src()
Rich Lane110e0e32012-10-26 16:21:46 -0700999 act.tp_port = mod_field_vals['udp_sport']
1000 elif field_to_mod == 'udp_dport':
Rich Lanee717c6e2013-03-12 10:25:50 -07001001 act = ofp.action.set_tp_dst()
Rich Lane110e0e32012-10-26 16:21:46 -07001002 act.tp_port = mod_field_vals['udp_dport']
Dan Talayco4b2bee62010-07-20 14:10:05 -07001003 else:
1004 parent.assertTrue(0, "Unknown field to modify: " + str(field_to_mod))
1005
1006 return act
1007
1008def pkt_action_setup(parent, start_field_vals={}, mod_field_vals={},
Rich Lane110e0e32012-10-26 16:21:46 -07001009 mod_fields=[], tp="tcp", check_test_params=False):
Dan Talayco4b2bee62010-07-20 14:10:05 -07001010 """
1011 Set up the ingress and expected packet and action list for a test
1012
Rich Lane2014f9b2012-10-05 15:29:40 -07001013 @param parent Must implement assertTrue
Dan Talayco4b2bee62010-07-20 14:10:05 -07001014 @param start_field_values Field values to use for ingress packet (optional)
1015 @param mod_field_values Field values to use for modified packet (optional)
1016 @param mod_fields The list of fields to be modified by the switch in the test.
1017 @params check_test_params If True, will check the parameters vid, add_vlan
1018 and strip_vlan from the command line.
1019
1020 Returns a triple: pkt-to-send, expected-pkt, action-list
1021 """
1022
1023 new_actions = []
1024
Dan Talayco4b2bee62010-07-20 14:10:05 -07001025 base_pkt_params = {}
1026 base_pkt_params['pktlen'] = 100
Rich Laned0478ff2013-03-11 12:46:58 -07001027 base_pkt_params['eth_dst'] = '00:DE:F0:12:34:56'
1028 base_pkt_params['eth_src'] = '00:23:45:67:89:AB'
Dan Talayco4b2bee62010-07-20 14:10:05 -07001029 base_pkt_params['dl_vlan_enable'] = False
Rich Laned0478ff2013-03-11 12:46:58 -07001030 base_pkt_params['vlan_vid'] = 2
1031 base_pkt_params['vlan_pcp'] = 0
Dan Talayco4b2bee62010-07-20 14:10:05 -07001032 base_pkt_params['ip_src'] = '192.168.0.1'
1033 base_pkt_params['ip_dst'] = '192.168.0.2'
1034 base_pkt_params['ip_tos'] = 0
Rich Lane110e0e32012-10-26 16:21:46 -07001035 if tp == "tcp":
1036 base_pkt_params['tcp_sport'] = 1234
1037 base_pkt_params['tcp_dport'] = 80
1038 elif tp == "udp":
1039 base_pkt_params['udp_sport'] = 1234
1040 base_pkt_params['udp_dport'] = 80
Dan Talayco4b2bee62010-07-20 14:10:05 -07001041 for keyname in start_field_vals.keys():
1042 base_pkt_params[keyname] = start_field_vals[keyname]
1043
1044 mod_pkt_params = {}
1045 mod_pkt_params['pktlen'] = 100
Rich Laned0478ff2013-03-11 12:46:58 -07001046 mod_pkt_params['eth_dst'] = '00:21:0F:ED:CB:A9'
1047 mod_pkt_params['eth_src'] = '00:ED:CB:A9:87:65'
Dan Talayco4b2bee62010-07-20 14:10:05 -07001048 mod_pkt_params['dl_vlan_enable'] = False
Rich Laned0478ff2013-03-11 12:46:58 -07001049 mod_pkt_params['vlan_vid'] = 3
1050 mod_pkt_params['vlan_pcp'] = 7
Dan Talayco4b2bee62010-07-20 14:10:05 -07001051 mod_pkt_params['ip_src'] = '10.20.30.40'
1052 mod_pkt_params['ip_dst'] = '50.60.70.80'
1053 mod_pkt_params['ip_tos'] = 0xf0
Rich Lane110e0e32012-10-26 16:21:46 -07001054 if tp == "tcp":
1055 mod_pkt_params['tcp_sport'] = 4321
1056 mod_pkt_params['tcp_dport'] = 8765
1057 elif tp == "udp":
1058 mod_pkt_params['udp_sport'] = 4321
1059 mod_pkt_params['udp_dport'] = 8765
Dan Talayco4b2bee62010-07-20 14:10:05 -07001060 for keyname in mod_field_vals.keys():
1061 mod_pkt_params[keyname] = mod_field_vals[keyname]
1062
1063 # Check for test param modifications
1064 strip = False
1065 if check_test_params:
Rich Lane2014f9b2012-10-05 15:29:40 -07001066 add_vlan = test_param_get('add_vlan')
1067 strip_vlan = test_param_get('strip_vlan')
1068 vid = test_param_get('vid')
Dan Talayco4b2bee62010-07-20 14:10:05 -07001069
1070 if add_vlan and strip_vlan:
1071 parent.assertTrue(0, "Add and strip VLAN both specified")
1072
1073 if vid:
1074 base_pkt_params['dl_vlan_enable'] = True
Rich Laned0478ff2013-03-11 12:46:58 -07001075 base_pkt_params['vlan_vid'] = vid
1076 if 'vlan_vid' in mod_fields:
1077 mod_pkt_params['vlan_vid'] = vid + 1
Dan Talayco4b2bee62010-07-20 14:10:05 -07001078
1079 if add_vlan:
1080 base_pkt_params['dl_vlan_enable'] = False
1081 mod_pkt_params['dl_vlan_enable'] = True
1082 mod_pkt_params['pktlen'] = base_pkt_params['pktlen'] + 4
1083 mod_fields.append('pktlen')
1084 mod_fields.append('dl_vlan_enable')
Rich Laned0478ff2013-03-11 12:46:58 -07001085 if 'vlan_vid' not in mod_fields:
1086 mod_fields.append('vlan_vid')
Dan Talayco4b2bee62010-07-20 14:10:05 -07001087 elif strip_vlan:
1088 base_pkt_params['dl_vlan_enable'] = True
1089 mod_pkt_params['dl_vlan_enable'] = False
1090 mod_pkt_params['pktlen'] = base_pkt_params['pktlen'] - 4
1091 mod_fields.append('dl_vlan_enable')
1092 mod_fields.append('pktlen')
1093
Rich Lane110e0e32012-10-26 16:21:46 -07001094 if tp == "tcp":
1095 packet_builder = simple_tcp_packet
1096 elif tp == "udp":
1097 packet_builder = simple_udp_packet
1098 else:
1099 raise NotImplementedError("unknown transport protocol %s" % tp)
1100
Dan Talayco4b2bee62010-07-20 14:10:05 -07001101 # Build the ingress packet
Rich Lane110e0e32012-10-26 16:21:46 -07001102 ingress_pkt = packet_builder(**base_pkt_params)
Dan Talayco4b2bee62010-07-20 14:10:05 -07001103
1104 # Build the expected packet, modifying the indicated fields
1105 for item in mod_fields:
1106 base_pkt_params[item] = mod_pkt_params[item]
1107 act = action_generate(parent, item, mod_pkt_params)
1108 if act:
1109 new_actions.append(act)
1110
Rich Lane110e0e32012-10-26 16:21:46 -07001111 expected_pkt = packet_builder(**base_pkt_params)
Dan Talayco4b2bee62010-07-20 14:10:05 -07001112
1113 return (ingress_pkt, expected_pkt, new_actions)
Dan Talayco677c0b72011-08-23 22:53:38 -07001114
1115# Generate a simple "drop" flow mod
1116# If in_band is true, then only drop from first test port
1117def flow_mod_gen(port_map, in_band):
Rich Lanee717c6e2013-03-12 10:25:50 -07001118 request = ofp.message.flow_add()
1119 request.match.wildcards = ofp.OFPFW_ALL
Dan Talayco677c0b72011-08-23 22:53:38 -07001120 if in_band:
Rich Lanee717c6e2013-03-12 10:25:50 -07001121 request.match.wildcards = ofp.OFPFW_ALL - ofp.OFPFW_IN_PORT
Dan Talayco677c0b72011-08-23 22:53:38 -07001122 for of_port, ifname in port_map.items(): # Grab first port
1123 break
1124 request.match.in_port = of_port
1125 request.buffer_id = 0xffffffff
1126 return request
Dan Talaycoba3745c2010-07-21 21:51:08 -07001127
1128def skip_message_emit(parent, s):
1129 """
1130 Print out a 'skipped' message to stderr
1131
1132 @param s The string to print out to the log file
Dan Talaycoba3745c2010-07-21 21:51:08 -07001133 """
1134 global skipped_test_count
1135
1136 skipped_test_count += 1
Rich Lane9a003812012-10-04 17:17:59 -07001137 logging.info("Skipping: " + s)
Dan Talayco2940fdd2013-02-06 15:01:35 -08001138 if oftest.config["debug"] < logging.WARNING:
Dan Talaycoba3745c2010-07-21 21:51:08 -07001139 sys.stderr.write("(skipped) ")
1140 else:
1141 sys.stderr.write("(S)")
Dan Talayco677c0b72011-08-23 22:53:38 -07001142
Dan Talayco8a64e332012-03-28 14:53:20 -07001143
1144def all_stats_get(parent):
1145 """
1146 Get the aggregate stats for all flows in the table
1147 @param parent Test instance with controller connection and assert
1148 @returns dict with keys flows, packets, bytes, active (flows),
1149 lookups, matched
1150 """
Rich Lanee717c6e2013-03-12 10:25:50 -07001151 stat_req = ofp.message.aggregate_stats_request()
1152 stat_req.match = ofp.match()
1153 stat_req.match.wildcards = ofp.OFPFW_ALL
Dan Talayco8a64e332012-03-28 14:53:20 -07001154 stat_req.table_id = 0xff
Rich Lanee717c6e2013-03-12 10:25:50 -07001155 stat_req.out_port = ofp.OFPP_NONE
Dan Talayco8a64e332012-03-28 14:53:20 -07001156
1157 rv = {}
1158
Rich Lanec8aaa3e2012-07-26 19:28:02 -07001159 (reply, pkt) = parent.controller.transact(stat_req)
Rich Lane5fd6faf2013-03-11 13:30:20 -07001160 parent.assertTrue(len(reply.entries) == 1, "Did not receive flow stats reply")
Dan Talayco8a64e332012-03-28 14:53:20 -07001161
Rich Lane5fd6faf2013-03-11 13:30:20 -07001162 for obj in reply.entries:
Dan Talayco8a64e332012-03-28 14:53:20 -07001163 (rv["flows"], rv["packets"], rv["bytes"]) = (obj.flow_count,
1164 obj.packet_count, obj.byte_count)
1165 break
1166
Rich Lanee717c6e2013-03-12 10:25:50 -07001167 request = ofp.message.table_stats_request()
Rich Lanec8aaa3e2012-07-26 19:28:02 -07001168 (reply , pkt) = parent.controller.transact(request)
Dan Talayco8a64e332012-03-28 14:53:20 -07001169
1170
1171 (rv["active"], rv["lookups"], rv["matched"]) = (0,0,0)
Rich Lane5fd6faf2013-03-11 13:30:20 -07001172 for obj in reply.entries:
Dan Talayco8a64e332012-03-28 14:53:20 -07001173 rv["active"] += obj.active_count
1174 rv["lookups"] += obj.lookup_count
1175 rv["matched"] += obj.matched_count
1176
1177 return rv
Dan Talayco2baf8b52012-03-30 09:55:42 -07001178
Rich Lane7744e112013-01-11 17:23:57 -08001179_import_blacklist.add('FILTER')
Dan Talayco2baf8b52012-03-30 09:55:42 -07001180FILTER=''.join([(len(repr(chr(x)))==3) and chr(x) or '.'
1181 for x in range(256)])
1182
1183def hex_dump_buffer(src, length=16):
1184 """
1185 Convert src to a hex dump string and return the string
1186 @param src The source buffer
1187 @param length The number of bytes shown in each line
1188 @returns A string showing the hex dump
1189 """
Dan Talaycoc516fa02012-04-12 22:28:43 -07001190 result = ["\n"]
Dan Talayco2baf8b52012-03-30 09:55:42 -07001191 for i in xrange(0, len(src), length):
1192 chars = src[i:i+length]
1193 hex = ' '.join(["%02x" % ord(x) for x in chars])
1194 printable = ''.join(["%s" % ((ord(x) <= 127 and
1195 FILTER[ord(x)]) or '.') for x in chars])
1196 result.append("%04x %-*s %s\n" % (i, length*3, hex, printable))
1197 return ''.join(result)
1198
1199def format_packet(pkt):
1200 return "Packet length %d \n%s" % (len(str(pkt)),
1201 hex_dump_buffer(str(pkt)))
Rich Lane5d7e89a2012-10-26 16:43:13 -07001202
1203def inspect_packet(pkt):
1204 """
1205 Wrapper around scapy's show() method.
1206 @returns A string showing the dissected packet.
1207 """
1208 from cStringIO import StringIO
1209 out = None
1210 backup = sys.stdout
1211 try:
Rich Lanefdec0fb2013-08-09 18:01:05 -07001212 tmp = StringIO()
1213 sys.stdout = tmp
Rich Lane5d7e89a2012-10-26 16:43:13 -07001214 pkt.show2()
Rich Lanefdec0fb2013-08-09 18:01:05 -07001215 out = tmp.getvalue()
1216 tmp.close()
Rich Lane5d7e89a2012-10-26 16:43:13 -07001217 finally:
1218 sys.stdout = backup
1219 return out
Rich Lane0a4f6372013-01-02 14:40:22 -08001220
1221def nonstandard(cls):
1222 """
Rich Lanecc45b8e2013-01-02 15:55:02 -08001223 Testcase decorator that marks the test as being non-standard.
1224 These tests are not automatically added to the "standard" group.
Rich Lane0a4f6372013-01-02 14:40:22 -08001225 """
Rich Lanecc45b8e2013-01-02 15:55:02 -08001226 cls._nonstandard = True
Rich Lane0a4f6372013-01-02 14:40:22 -08001227 return cls
1228
1229def disabled(cls):
1230 """
Rich Lanecc45b8e2013-01-02 15:55:02 -08001231 Testcase decorator that marks the test as being disabled.
1232 These tests are not automatically added to the "standard" group or
1233 their module's group.
Rich Lane0a4f6372013-01-02 14:40:22 -08001234 """
Rich Lanecc45b8e2013-01-02 15:55:02 -08001235 cls._disabled = True
Rich Lane0a4f6372013-01-02 14:40:22 -08001236 return cls
Rich Lane97e99652013-01-02 17:23:20 -08001237
1238def group(name):
1239 """
1240 Testcase decorator that adds the test to a group.
1241 """
1242 def fn(cls):
1243 if not hasattr(cls, "_groups"):
1244 cls._groups = []
1245 cls._groups.append(name)
1246 return cls
1247 return fn
Rich Lane5a9a1922013-01-11 14:29:30 -08001248
1249def version(ver):
1250 """
1251 Testcase decorator that specifies which versions of OpenFlow the test
1252 supports. The default is 1.0+. This decorator may only be used once.
1253
1254 Supported syntax:
1255 1.0 -> 1.0
1256 1.0,1.2,1.3 -> 1.0, 1.2, 1.3
1257 1.0+ -> 1.0, 1.1, 1.2, 1.3
1258 """
1259 versions = parse_version(ver)
1260 def fn(cls):
1261 cls._versions = versions
1262 return cls
1263 return fn
1264
1265def parse_version(ver):
1266 allowed_versions = ["1.0", "1.1", "1.2", "1.3"]
1267 if re.match("^1\.\d+$", ver):
1268 versions = set([ver])
1269 elif re.match("^(1\.\d+)\+$", ver):
1270 if not ver[:-1] in allowed_versions:
1271 raise ValueError("invalid OpenFlow version %s" % ver[:-1])
1272 versions = set()
1273 if ver != "1.1+": versions.add("1.0")
1274 if ver != "1.2+": versions.add("1.1")
1275 if ver != "1.3+": versions.add("1.2")
1276 versions.add("1.3")
1277 else:
1278 versions = set(ver.split(','))
1279
1280 for version in versions:
1281 if not version in allowed_versions:
1282 raise ValueError("invalid OpenFlow version %s" % version)
1283
1284 return versions
1285
1286assert(parse_version("1.0") == set(["1.0"]))
1287assert(parse_version("1.0,1.2,1.3") == set(["1.0", "1.2", "1.3"]))
1288assert(parse_version("1.0+") == set(["1.0", "1.1", "1.2", "1.3"]))
Rich Lane7744e112013-01-11 17:23:57 -08001289
Rich Laneae3428c2013-03-07 14:37:42 -08001290def get_stats(test, req):
1291 """
1292 Retrieve a list of stats entries. Handles OFPSF_REPLY_MORE.
1293 """
Rich Lanebd56ed62013-07-10 15:49:44 -07001294 if ofp.OFP_VERSION <= 3:
1295 more_flag = ofp.OFPSF_REPLY_MORE
1296 else:
1297 more_flag = ofp.OFPMPF_REPLY_MORE
Rich Laneae3428c2013-03-07 14:37:42 -08001298 stats = []
1299 reply, _ = test.controller.transact(req)
1300 test.assertTrue(reply is not None, "No response to stats request")
Rich Lane5fd6faf2013-03-11 13:30:20 -07001301 stats.extend(reply.entries)
Rich Lanebd56ed62013-07-10 15:49:44 -07001302 while reply.flags & more_flag != 0:
Rich Lane720eaf22013-08-09 18:00:45 -07001303 reply, pkt = test.controller.poll(exp_msg=ofp.OFPT_STATS_REPLY)
Rich Laneae3428c2013-03-07 14:37:42 -08001304 test.assertTrue(reply is not None, "No response to stats request")
Rich Lane5fd6faf2013-03-11 13:30:20 -07001305 stats.extend(reply.entries)
Rich Laneae3428c2013-03-07 14:37:42 -08001306 return stats
1307
Rich Lanebd56ed62013-07-10 15:49:44 -07001308def get_flow_stats(test, match, table_id=None,
1309 out_port=None, out_group=None,
1310 cookie=0, cookie_mask=0):
Rich Laneae3428c2013-03-07 14:37:42 -08001311 """
1312 Retrieve a list of flow stats entries.
1313 """
Rich Lanebd56ed62013-07-10 15:49:44 -07001314
1315 if table_id == None:
1316 if ofp.OFP_VERSION <= 2:
1317 table_id = 0xff
1318 else:
1319 table_id = ofp.OFPTT_ALL
1320
Rich Lanef3bc48c2013-05-03 17:39:35 -07001321 if out_port == None:
Rich Lanebd56ed62013-07-10 15:49:44 -07001322 if ofp.OFP_VERSION == 1:
1323 out_port = ofp.OFPP_NONE
1324 else:
1325 out_port = ofp.OFPP_ANY
1326
1327 if out_group == None:
1328 if ofp.OFP_VERSION > 1:
1329 out_group = ofp.OFPP_ANY
1330
Rich Lanee717c6e2013-03-12 10:25:50 -07001331 req = ofp.message.flow_stats_request(match=match,
Rich Lanebd56ed62013-07-10 15:49:44 -07001332 table_id=table_id,
1333 out_port=out_port)
1334 if ofp.OFP_VERSION > 1:
1335 req.out_group = out_group
1336 req.cookie = cookie
1337 req.cookie_mask = cookie_mask
1338
Rich Laneae3428c2013-03-07 14:37:42 -08001339 return get_stats(test, req)
1340
Rich Lane968b6192013-03-07 15:34:43 -08001341def get_port_stats(test, port_no):
1342 """
1343 Retrieve a list of port stats entries.
1344 """
Rich Lanee717c6e2013-03-12 10:25:50 -07001345 req = ofp.message.port_stats_request(port_no=port_no)
Rich Lane968b6192013-03-07 15:34:43 -08001346 return get_stats(test, req)
1347
Rich Lane6a334922013-03-07 16:14:52 -08001348def get_queue_stats(test, port_no, queue_id):
1349 """
1350 Retrieve a list of queue stats entries.
1351 """
Rich Lanee717c6e2013-03-12 10:25:50 -07001352 req = ofp.message.queue_stats_request(port_no=port_no, queue_id=queue_id)
Rich Lane6a334922013-03-07 16:14:52 -08001353 return get_stats(test, req)
1354
Rich Laneae3428c2013-03-07 14:37:42 -08001355def verify_flow_stats(test, match, table_id=0xff,
Rich Lanef3bc48c2013-05-03 17:39:35 -07001356 out_port=None,
Rich Laneae3428c2013-03-07 14:37:42 -08001357 initial=[],
1358 pkts=None, bytes=None):
1359 """
1360 Verify that flow stats changed as expected.
1361
1362 Optionally takes an 'initial' list of stats entries, as returned by
1363 get_flow_stats(). If 'initial' is not given the counters are assumed to
1364 begin at 0.
1365 """
Rich Lanef3bc48c2013-05-03 17:39:35 -07001366 if out_port == None:
1367 out_port = ofp.OFPP_NONE
1368
Rich Laneae3428c2013-03-07 14:37:42 -08001369 def accumulate(stats):
1370 pkts_acc = bytes_acc = 0
1371 for stat in stats:
1372 pkts_acc += stat.packet_count
1373 bytes_acc += stat.byte_count
1374 return (pkts_acc, bytes_acc)
1375
1376 pkts_before, bytes_before = accumulate(initial)
1377
1378 # Wait 10s for counters to update
1379 pkt_diff = byte_diff = None
1380 for i in range(0, 100):
1381 stats = get_flow_stats(test, match, table_id=table_id, out_port=out_port)
1382 pkts_after, bytes_after = accumulate(stats)
1383 pkt_diff = pkts_after - pkts_before
1384 byte_diff = bytes_after - bytes_before
1385 if (pkts == None or pkt_diff >= pkts) and \
1386 (bytes == None or byte_diff >= bytes):
1387 break
Dan Talayco53724732013-03-08 23:54:02 -08001388 time.sleep(0.1)
Rich Laneae3428c2013-03-07 14:37:42 -08001389
1390 if pkts != None:
1391 test.assertEquals(pkt_diff, pkts, "Flow packet counter not updated properly (expected increase of %d, got increase of %d)" % (pkts, pkt_diff))
1392
1393 if bytes != None:
Rich Lane53b96812013-03-07 16:54:50 -08001394 test.assertTrue(byte_diff >= bytes and byte_diff <= bytes*1.1,
1395 "Flow byte counter not updated properly (expected increase of %d, got increase of %d)" % (bytes, byte_diff))
Rich Laneae3428c2013-03-07 14:37:42 -08001396
Rich Lane968b6192013-03-07 15:34:43 -08001397def verify_port_stats(test, port,
1398 initial=[],
1399 tx_pkts=None, rx_pkts=None,
1400 tx_bytes=None, rx_bytes=None):
1401 """
1402 Verify that port stats changed as expected.
1403
1404 Optionally takes an 'initial' list of stats entries, as returned by
1405 get_port_stats(). If 'initial' is not given the counters are assumed to
1406 begin at 0.
1407 """
1408 def accumulate(stats):
1409 tx_pkts_acc = rx_pkts_acc = tx_bytes_acc = rx_bytes_acc = 0
1410 for stat in stats:
1411 tx_pkts_acc += stat.tx_packets
1412 rx_pkts_acc += stat.rx_packets
1413 tx_bytes_acc += stat.tx_bytes
1414 rx_bytes_acc += stat.rx_bytes
1415 return (tx_pkts_acc, rx_pkts_acc, tx_bytes_acc, rx_bytes_acc)
1416
1417 tx_pkts_before, rx_pkts_before, \
1418 tx_bytes_before, rx_bytes_before = accumulate(initial)
1419
1420 # Wait 10s for counters to update
1421 for i in range(0, 100):
1422 stats = get_port_stats(test, port)
1423 tx_pkts_after, rx_pkts_after, \
1424 tx_bytes_after, rx_bytes_after = accumulate(stats)
1425 tx_pkts_diff = tx_pkts_after - tx_pkts_before
1426 rx_pkts_diff = rx_pkts_after - rx_pkts_before
1427 tx_bytes_diff = tx_bytes_after - tx_bytes_before
1428 rx_bytes_diff = rx_bytes_after - rx_bytes_before
1429 if (tx_pkts == None or tx_pkts == tx_pkts_diff) and \
1430 (rx_pkts == None or rx_pkts == rx_pkts_diff) and \
Rich Lane53b96812013-03-07 16:54:50 -08001431 (tx_bytes == None or tx_bytes <= tx_bytes_diff) and \
1432 (rx_bytes == None or rx_bytes <= rx_bytes_diff):
Rich Lane968b6192013-03-07 15:34:43 -08001433 break
1434 time.sleep(0.1)
1435
1436 if (tx_pkts != None):
1437 test.assertEqual(tx_pkts,tx_pkts_diff,"Port TX packet counter is not updated correctly (expected increase of %d, got increase of %d)" % (tx_pkts, tx_pkts_diff))
1438 if (rx_pkts != None):
1439 test.assertEqual(rx_pkts,rx_pkts_diff,"Port RX packet counter is not updated correctly (expected increase of %d, got increase of %d)" % (rx_pkts, rx_pkts_diff))
1440 if (tx_bytes != None):
Rich Lane53b96812013-03-07 16:54:50 -08001441 test.assertTrue(tx_bytes_diff >= tx_bytes and tx_bytes_diff <= tx_bytes*1.1,
1442 "Port TX byte counter is not updated correctly (expected increase of %d, got increase of %d)" % (tx_bytes, tx_bytes_diff))
Rich Lane968b6192013-03-07 15:34:43 -08001443 if (rx_bytes != None):
Rich Lane53b96812013-03-07 16:54:50 -08001444 test.assertTrue(rx_bytes_diff >= rx_bytes and rx_bytes_diff <= rx_bytes*1.1,
1445 "Port RX byte counter is not updated correctly (expected increase of %d, got increase of %d)" % (rx_bytes, rx_bytes_diff))
Rich Lane968b6192013-03-07 15:34:43 -08001446
Rich Lane6a334922013-03-07 16:14:52 -08001447def verify_queue_stats(test, port_no, queue_id,
1448 initial=[],
1449 pkts=None, bytes=None):
1450 """
1451 Verify that queue stats changed as expected.
1452
1453 Optionally takes an 'initial' list of stats entries, as returned by
1454 get_queue_stats(). If 'initial' is not given the counters are assumed to
1455 begin at 0.
1456 """
1457 def accumulate(stats):
1458 pkts_acc = bytes_acc = 0
1459 for stat in stats:
1460 pkts_acc += stat.tx_packets
1461 bytes_acc += stat.tx_bytes
1462 return (pkts_acc, bytes_acc)
1463
1464 pkts_before, bytes_before = accumulate(initial)
1465
1466 # Wait 10s for counters to update
1467 pkt_diff = byte_diff = None
1468 for i in range(0, 100):
1469 stats = get_queue_stats(test, port_no, queue_id)
1470 pkts_after, bytes_after = accumulate(stats)
1471 pkt_diff = pkts_after - pkts_before
1472 byte_diff = bytes_after - bytes_before
1473 if (pkts == None or pkt_diff >= pkts) and \
1474 (bytes == None or byte_diff >= bytes):
1475 break
Dan Talayco53724732013-03-08 23:54:02 -08001476 time.sleep(0.1)
Rich Lane6a334922013-03-07 16:14:52 -08001477
1478 if pkts != None:
1479 test.assertEquals(pkt_diff, pkts, "Queue packet counter not updated properly (expected increase of %d, got increase of %d)" % (pkts, pkt_diff))
1480
1481 if bytes != None:
Rich Lane53b96812013-03-07 16:54:50 -08001482 test.assertTrue(byte_diff >= bytes and byte_diff <= bytes*1.1,
1483 "Queue byte counter not updated properly (expected increase of %d, got increase of %d)" % (bytes, byte_diff))
Rich Laneae3428c2013-03-07 14:37:42 -08001484
Rich Lane4c504f32013-06-07 17:24:14 -07001485def packet_in_match(msg, data, in_port=None, reason=None):
1486 """
1487 Check whether the packet_in message 'msg' has fields matching 'data',
1488 'in_port', and 'reason'.
1489
1490 This function handles truncated packet_in data. The 'in_port' and 'reason'
1491 parameters are optional.
1492
1493 @param msg packet_in message
1494 @param data Expected packet_in data
1495 @param in_port Expected packet_in in_port, or None
1496 @param reason Expected packet_in reason, or None
1497 """
1498
Rich Lanec0d26dd2013-07-10 12:46:03 -07001499 if ofp.OFP_VERSION <= 2:
1500 pkt_in_port = msg.in_port
1501 else:
1502 oxms = { type(oxm): oxm for oxm in msg.match.oxm_list }
1503 if ofp.oxm.in_port in oxms:
1504 pkt_in_port = oxms[ofp.oxm.in_port].value
1505 else:
1506 logging.warn("Missing in_port in packet-in message")
1507 pkt_in_port = None
1508
1509 if in_port != None and in_port != pkt_in_port:
Rich Lane9f2f17e2013-09-13 13:19:37 -07001510 logging.debug("Incorrect packet_in in_port (expected %d, received %d)", in_port, pkt_in_port)
Rich Lane4c504f32013-06-07 17:24:14 -07001511 return False
1512
Rich Lanec0d26dd2013-07-10 12:46:03 -07001513 if reason != None and reason != msg.reason:
Rich Lane4c504f32013-06-07 17:24:14 -07001514 logging.debug("Incorrect packet_in reason (expected %d, received %d)", reason, msg.reason)
1515 return False
1516
1517 # Check that one of the packets is a prefix of the other.
1518 # The received packet may be either truncated or padded, but not both.
1519 # (Some of the padding may be truncated but that's irrelevant). We
1520 # need to check that the smaller packet is a prefix of the larger one.
1521 # Note that this check succeeds if the switch sends a zero-length
1522 # packet-in.
1523 compare_len = min(len(msg.data), len(data))
1524 if data[:compare_len] != msg.data[:compare_len]:
1525 logging.debug("Incorrect packet_in data")
1526 logging.debug("Expected %s" % format_packet(data[:compare_len]))
1527 logging.debug("Received %s" % format_packet(msg.data[:compare_len]))
1528 return False
1529
1530 return True
1531
1532def verify_packet_in(test, data, in_port, reason, controller=None):
1533 """
1534 Assert that the controller receives a packet_in message matching data 'data'
1535 from port 'in_port' with reason 'reason'. Does not trigger the packet_in
1536 itself, that's up to the test case.
1537
1538 @param test Instance of base_tests.SimpleProtocol
1539 @param pkt String to expect as the packet_in data
1540 @param in_port OpenFlow port number to expect as the packet_in in_port
1541 @param reason One of OFPR_* to expect as the packet_in reason
1542 @param controller Controller instance, defaults to test.controller
1543 @returns The received packet-in message
1544 """
1545
1546 if controller == None:
1547 controller = test.controller
1548
1549 end_time = time.time() + oftest.ofutils.default_timeout
1550
1551 while True:
1552 msg, _ = controller.poll(ofp.OFPT_PACKET_IN, end_time - time.time())
1553 if not msg:
1554 # Timeout
1555 break
1556 elif packet_in_match(msg, data, in_port, reason):
1557 # Found a matching message
1558 break
1559
1560 test.assertTrue(msg is not None, 'Packet in message not received on port %d' % in_port)
1561 return msg
1562
1563def verify_no_packet_in(test, data, in_port, controller=None):
1564 """
1565 Assert that the controller does not receive a packet_in message matching
1566 data 'data' from port 'in_port'.
1567
1568 @param test Instance of base_tests.SimpleProtocol
1569 @param pkt String to expect as the packet_in data
1570 @param in_port OpenFlow port number to expect as the packet_in in_port
1571 @param controller Controller instance, defaults to test.controller
1572 """
1573
1574 if controller == None:
1575 controller = test.controller
1576
1577 # Negative test, need to wait a short amount of time before checking we
1578 # didn't receive the message.
1579 time.sleep(0.5)
1580
1581 # Check every packet_in queued in the controller
1582 while True:
1583 msg, _ = controller.poll(ofp.OFPT_PACKET_IN, timeout=0)
1584 if msg == None:
1585 # No more queued packet_in messages
1586 break
1587 elif packet_in_match(msg, data, in_port, None):
1588 # Found a matching message
1589 break
1590
Rich Lane82c882d2013-08-09 17:13:52 -07001591 if in_port == None:
1592 test.assertTrue(msg == None, "Did not expect a packet-in message on any port")
1593 else:
1594 test.assertTrue(msg == None, "Did not expect a packet-in message on port %d" % in_port)
Rich Lane4c504f32013-06-07 17:24:14 -07001595
Rich Lane045db072013-08-06 13:16:30 -07001596def openflow_ports(num=None):
1597 """
1598 Return a list of 'num' OpenFlow port numbers
1599
1600 If 'num' is None, return all available ports. Otherwise, limit the length
1601 of the result to 'num' and raise an exception if not enough ports are
1602 available.
1603 """
1604 ports = sorted(oftest.config["port_map"].keys())
1605 if num != None and len(ports) < num:
1606 raise Exception("test requires %d ports but only %d are available" % (num, len(ports)))
1607 return ports[:num]
1608
Rich Lane7744e112013-01-11 17:23:57 -08001609__all__ = list(set(locals()) - _import_blacklist)