blob: e87b7a0818d36b5d8c1e857d19bc0c0ec0eedfe2 [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
Dan Talaycod2ca1032010-03-10 14:40:26 -08007
8try:
9 import scapy.all as scapy
10except:
11 try:
12 import scapy as scapy
13 except:
14 sys.exit("Need to install scapy for packet parsing")
Dan Talayco41eae8b2010-03-10 13:57:06 -080015
Rich Lanecd97d3d2013-01-07 18:50:06 -080016import oftest
17import oftest.controller
18import oftest.dataplane
Rich Lanef6883512013-03-11 17:00:09 -070019import oftest.parse
Rich Lane4c504f32013-06-07 17:24:14 -070020import oftest.ofutils
Rich Lanee717c6e2013-03-12 10:25:50 -070021import ofp
Dan Talaycoc901f4d2010-03-07 21:55:45 -080022
Dan Talaycoba3745c2010-07-21 21:51:08 -070023global skipped_test_count
24skipped_test_count = 0
25
Rich Lane7744e112013-01-11 17:23:57 -080026_import_blacklist = set(locals().keys())
27
Dan Talayco551befa2010-07-15 17:05:32 -070028# Some useful defines
29IP_ETHERTYPE = 0x800
30TCP_PROTOCOL = 0x6
31UDP_PROTOCOL = 0x11
32
Jeffrey Townsend5cb7ed32012-08-17 18:11:01 +000033MINSIZE = 0
34
Rich Lane9a003812012-10-04 17:17:59 -070035def delete_all_flows(ctrl):
Dan Talayco41eae8b2010-03-10 13:57:06 -080036 """
37 Delete all flows on the switch
38 @param ctrl The controller object for the test
Dan Talayco41eae8b2010-03-10 13:57:06 -080039 """
40
Rich Lane9a003812012-10-04 17:17:59 -070041 logging.info("Deleting all flows")
Rich Lanee717c6e2013-03-12 10:25:50 -070042 msg = ofp.message.flow_delete()
Rich Lanec717f442013-06-13 15:49:09 -070043 if ofp.OFP_VERSION in [1, 2]:
44 msg.match.wildcards = ofp.OFPFW_ALL
45 msg.out_port = ofp.OFPP_NONE
46 msg.buffer_id = 0xffffffff
47 elif ofp.OFP_VERSION >= 3:
48 msg.table_id = ofp.OFPTT_ALL
49 msg.buffer_id = ofp.OFP_NO_BUFFER
50 msg.out_port = ofp.OFPP_ANY
51 msg.out_group = ofp.OFPG_ANY
Rich Lane5c3151c2013-01-03 17:15:41 -080052 ctrl.message_send(msg)
Rich Lane44c4e3f2013-07-08 10:17:49 -070053 do_barrier(ctrl)
Rich Lane32bf9482013-01-03 17:26:30 -080054 return 0 # for backwards compatibility
Dan Talayco41eae8b2010-03-10 13:57:06 -080055
Ed Swierk99a74de2012-08-22 06:40:54 -070056def required_wildcards(parent):
Rich Lane2014f9b2012-10-05 15:29:40 -070057 w = test_param_get('required_wildcards', default='default')
Ed Swierk99a74de2012-08-22 06:40:54 -070058 if w == 'l3-l4':
Rich Lanee717c6e2013-03-12 10:25:50 -070059 return (ofp.OFPFW_NW_SRC_ALL | ofp.OFPFW_NW_DST_ALL | ofp.OFPFW_NW_TOS
60 | ofp.OFPFW_NW_PROTO | ofp.OFPFW_TP_SRC | ofp.OFPFW_TP_DST)
Ed Swierk99a74de2012-08-22 06:40:54 -070061 else:
62 return 0
63
Dan Talayco41eae8b2010-03-10 13:57:06 -080064def simple_tcp_packet(pktlen=100,
Rich Laned0478ff2013-03-11 12:46:58 -070065 eth_dst='00:01:02:03:04:05',
66 eth_src='00:06:07:08:09:0a',
Tatsuya Yabe460321e2010-05-25 17:50:49 -070067 dl_vlan_enable=False,
Rich Laned0478ff2013-03-11 12:46:58 -070068 vlan_vid=0,
69 vlan_pcp=0,
Dan Talayco551befa2010-07-15 17:05:32 -070070 dl_vlan_cfi=0,
Dan Talayco41eae8b2010-03-10 13:57:06 -080071 ip_src='192.168.0.1',
72 ip_dst='192.168.0.2',
Tatsuya Yabe460321e2010-05-25 17:50:49 -070073 ip_tos=0,
Gregor Maier9cc93342013-01-29 16:55:28 -080074 ip_ttl=64,
Dan Talayco41eae8b2010-03-10 13:57:06 -080075 tcp_sport=1234,
Christian Dickmann8b59b4b2012-09-23 16:48:30 -070076 tcp_dport=80,
77 ip_ihl=None,
78 ip_options=False
Dan Talayco41eae8b2010-03-10 13:57:06 -080079 ):
80 """
81 Return a simple dataplane TCP packet
82
83 Supports a few parameters:
84 @param len Length of packet in bytes w/o CRC
Rich Laned0478ff2013-03-11 12:46:58 -070085 @param eth_dst Destinatino MAC
86 @param eth_src Source MAC
Tatsuya Yabe460321e2010-05-25 17:50:49 -070087 @param dl_vlan_enable True if the packet is with vlan, False otherwise
Rich Laned0478ff2013-03-11 12:46:58 -070088 @param vlan_vid VLAN ID
89 @param vlan_pcp VLAN priority
Dan Talayco41eae8b2010-03-10 13:57:06 -080090 @param ip_src IP source
91 @param ip_dst IP destination
Tatsuya Yabe460321e2010-05-25 17:50:49 -070092 @param ip_tos IP ToS
Gregor Maier9cc93342013-01-29 16:55:28 -080093 @param ip_ttl IP TTL
Dan Talayco41eae8b2010-03-10 13:57:06 -080094 @param tcp_dport TCP destination port
95 @param ip_sport TCP source port
96
97 Generates a simple TCP request. Users
98 shouldn't assume anything about this packet other than that
99 it is a valid ethernet/IP/TCP frame.
100 """
Jeffrey Townsend5cb7ed32012-08-17 18:11:01 +0000101
102 if MINSIZE > pktlen:
103 pktlen = MINSIZE
104
Dan Talayco551befa2010-07-15 17:05:32 -0700105 # Note Dot1Q.id is really CFI
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800106 if (dl_vlan_enable):
Rich Laned0478ff2013-03-11 12:46:58 -0700107 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
108 scapy.Dot1Q(prio=vlan_pcp, id=dl_vlan_cfi, vlan=vlan_vid)/ \
Gregor Maier9cc93342013-01-29 16:55:28 -0800109 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ttl=ip_ttl, ihl=ip_ihl)/ \
Tatsuya Yabe460321e2010-05-25 17:50:49 -0700110 scapy.TCP(sport=tcp_sport, dport=tcp_dport)
111 else:
Christian Dickmann8b59b4b2012-09-23 16:48:30 -0700112 if not ip_options:
Rich Laned0478ff2013-03-11 12:46:58 -0700113 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
Gregor Maier9cc93342013-01-29 16:55:28 -0800114 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ttl=ip_ttl, ihl=ip_ihl)/ \
Christian Dickmann8b59b4b2012-09-23 16:48:30 -0700115 scapy.TCP(sport=tcp_sport, dport=tcp_dport)
116 else:
Rich Laned0478ff2013-03-11 12:46:58 -0700117 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
Gregor Maier9cc93342013-01-29 16:55:28 -0800118 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 -0700119 scapy.TCP(sport=tcp_sport, dport=tcp_dport)
Tatsuya Yabe460321e2010-05-25 17:50:49 -0700120
Dan Talayco41eae8b2010-03-10 13:57:06 -0800121 pkt = pkt/("D" * (pktlen - len(pkt)))
122
123 return pkt
124
Rich Lane86aceb02013-07-17 18:45:38 -0700125def simple_tcpv6_packet(pktlen=100,
126 eth_dst='00:01:02:03:04:05',
127 eth_src='00:06:07:08:09:0a',
128 dl_vlan_enable=False,
129 vlan_vid=0,
130 vlan_pcp=0,
131 ipv6_src='2001:db8:85a3::8a2e:370:7334',
132 ipv6_dst='2001:db8:85a3::8a2e:370:7335',
133 ipv6_tc=0,
134 ipv6_hlim=64,
135 ipv6_fl=0,
136 tcp_sport=1234,
137 tcp_dport=80):
138 """
139 Return a simple IPv6/TCP packet
140
141 Supports a few parameters:
142 @param len Length of packet in bytes w/o CRC
143 @param eth_dst Destination MAC
144 @param eth_src Source MAC
145 @param dl_vlan_enable True if the packet is with vlan, False otherwise
146 @param vlan_vid VLAN ID
147 @param vlan_pcp VLAN priority
148 @param ipv6_src IPv6 source
149 @param ipv6_dst IPv6 destination
150 @param ipv6_tc IPv6 traffic class
151 @param ipv6_ttl IPv6 hop limit
152 @param ipv6_fl IPv6 flow label
153 @param tcp_dport TCP destination port
154 @param tcp_sport TCP source port
155
156 Generates a simple TCP request. Users shouldn't assume anything about this
157 packet other than that it is a valid ethernet/IPv6/TCP frame.
158 """
159
160 if MINSIZE > pktlen:
161 pktlen = MINSIZE
162
163 pkt = scapy.Ether(dst=eth_dst, src=eth_src)
164 if dl_vlan_enable or vlan_vid or vlan_pcp:
165 pkt /= scapy.Dot1Q(vlan=vlan_vid, prio=vlan_pcp)
166 pkt /= scapy.IPv6(src=ipv6_src, dst=ipv6_dst, fl=ipv6_fl, tc=ipv6_tc, hlim=ipv6_hlim)
167 pkt /= scapy.TCP(sport=tcp_sport, dport=tcp_dport)
168 pkt /= ("D" * (pktlen - len(pkt)))
169
170 return pkt
171
Rich Lane6ee7bea2012-10-26 16:19:29 -0700172def simple_udp_packet(pktlen=100,
Rich Laned0478ff2013-03-11 12:46:58 -0700173 eth_dst='00:01:02:03:04:05',
174 eth_src='00:06:07:08:09:0a',
Rich Lane6ee7bea2012-10-26 16:19:29 -0700175 dl_vlan_enable=False,
Rich Laned0478ff2013-03-11 12:46:58 -0700176 vlan_vid=0,
177 vlan_pcp=0,
Rich Lane6ee7bea2012-10-26 16:19:29 -0700178 dl_vlan_cfi=0,
179 ip_src='192.168.0.1',
180 ip_dst='192.168.0.2',
181 ip_tos=0,
Gregor Maier9cc93342013-01-29 16:55:28 -0800182 ip_ttl=64,
Rich Lane6ee7bea2012-10-26 16:19:29 -0700183 udp_sport=1234,
184 udp_dport=80,
185 ip_ihl=None,
186 ip_options=False
187 ):
188 """
189 Return a simple dataplane UDP packet
190
191 Supports a few parameters:
192 @param len Length of packet in bytes w/o CRC
Rich Laned0478ff2013-03-11 12:46:58 -0700193 @param eth_dst Destination MAC
194 @param eth_src Source MAC
Rich Lane6ee7bea2012-10-26 16:19:29 -0700195 @param dl_vlan_enable True if the packet is with vlan, False otherwise
Rich Laned0478ff2013-03-11 12:46:58 -0700196 @param vlan_vid VLAN ID
197 @param vlan_pcp VLAN priority
Rich Lane6ee7bea2012-10-26 16:19:29 -0700198 @param ip_src IP source
199 @param ip_dst IP destination
200 @param ip_tos IP ToS
Gregor Maier9cc93342013-01-29 16:55:28 -0800201 @param ip_ttl IP TTL
Rich Lane6ee7bea2012-10-26 16:19:29 -0700202 @param udp_dport UDP destination port
203 @param udp_sport UDP source port
204
205 Generates a simple UDP packet. Users shouldn't assume anything about
206 this packet other than that it is a valid ethernet/IP/UDP frame.
207 """
208
209 if MINSIZE > pktlen:
210 pktlen = MINSIZE
211
212 # Note Dot1Q.id is really CFI
213 if (dl_vlan_enable):
Rich Laned0478ff2013-03-11 12:46:58 -0700214 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
215 scapy.Dot1Q(prio=vlan_pcp, id=dl_vlan_cfi, vlan=vlan_vid)/ \
Gregor Maier9cc93342013-01-29 16:55:28 -0800216 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ttl=ip_ttl, ihl=ip_ihl)/ \
Rich Lane6ee7bea2012-10-26 16:19:29 -0700217 scapy.UDP(sport=udp_sport, dport=udp_dport)
218 else:
219 if not ip_options:
Rich Laned0478ff2013-03-11 12:46:58 -0700220 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
Gregor Maier9cc93342013-01-29 16:55:28 -0800221 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ttl=ip_ttl, ihl=ip_ihl)/ \
Rich Lane6ee7bea2012-10-26 16:19:29 -0700222 scapy.UDP(sport=udp_sport, dport=udp_dport)
223 else:
Rich Laned0478ff2013-03-11 12:46:58 -0700224 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
Gregor Maier9cc93342013-01-29 16:55:28 -0800225 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 -0700226 scapy.UDP(sport=udp_sport, dport=udp_dport)
227
228 pkt = pkt/("D" * (pktlen - len(pkt)))
229
230 return pkt
231
Rich Lane86aceb02013-07-17 18:45:38 -0700232def simple_udpv6_packet(pktlen=100,
233 eth_dst='00:01:02:03:04:05',
234 eth_src='00:06:07:08:09:0a',
235 dl_vlan_enable=False,
236 vlan_vid=0,
237 vlan_pcp=0,
238 ipv6_src='2001:db8:85a3::8a2e:370:7334',
239 ipv6_dst='2001:db8:85a3::8a2e:370:7335',
240 ipv6_tc=0,
241 ipv6_hlim=64,
242 ipv6_fl=0,
243 udp_sport=1234,
244 udp_dport=80):
245 """
246 Return a simple IPv6/UDP packet
247
248 Supports a few parameters:
249 @param len Length of packet in bytes w/o CRC
250 @param eth_dst Destination MAC
251 @param eth_src Source MAC
252 @param dl_vlan_enable True if the packet is with vlan, False otherwise
253 @param vlan_vid VLAN ID
254 @param vlan_pcp VLAN priority
255 @param ipv6_src IPv6 source
256 @param ipv6_dst IPv6 destination
257 @param ipv6_tc IPv6 traffic class
258 @param ipv6_ttl IPv6 hop limit
259 @param ipv6_fl IPv6 flow label
260 @param udp_dport UDP destination port
261 @param udp_sport UDP source port
262
263 Generates a simple UDP request. Users shouldn't assume anything about this
264 packet other than that it is a valid ethernet/IPv6/UDP frame.
265 """
266
267 if MINSIZE > pktlen:
268 pktlen = MINSIZE
269
270 pkt = scapy.Ether(dst=eth_dst, src=eth_src)
271 if dl_vlan_enable or vlan_vid or vlan_pcp:
272 pkt /= scapy.Dot1Q(vlan=vlan_vid, prio=vlan_pcp)
273 pkt /= scapy.IPv6(src=ipv6_src, dst=ipv6_dst, fl=ipv6_fl, tc=ipv6_tc, hlim=ipv6_hlim)
274 pkt /= scapy.UDP(sport=udp_sport, dport=udp_dport)
275 pkt /= ("D" * (pktlen - len(pkt)))
276
277 return pkt
278
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700279def simple_icmp_packet(pktlen=60,
Rich Laned0478ff2013-03-11 12:46:58 -0700280 eth_dst='00:01:02:03:04:05',
281 eth_src='00:06:07:08:09:0a',
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700282 dl_vlan_enable=False,
Rich Laned0478ff2013-03-11 12:46:58 -0700283 vlan_vid=0,
284 vlan_pcp=0,
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700285 ip_src='192.168.0.1',
286 ip_dst='192.168.0.2',
287 ip_tos=0,
Gregor Maier9cc93342013-01-29 16:55:28 -0800288 ip_ttl=64,
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700289 icmp_type=8,
290 icmp_code=0
291 ):
292 """
293 Return a simple ICMP packet
294
295 Supports a few parameters:
296 @param len Length of packet in bytes w/o CRC
Rich Laned0478ff2013-03-11 12:46:58 -0700297 @param eth_dst Destinatino MAC
298 @param eth_src Source MAC
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700299 @param dl_vlan_enable True if the packet is with vlan, False otherwise
Rich Laned0478ff2013-03-11 12:46:58 -0700300 @param vlan_vid VLAN ID
301 @param vlan_pcp VLAN priority
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700302 @param ip_src IP source
303 @param ip_dst IP destination
304 @param ip_tos IP ToS
Gregor Maier9cc93342013-01-29 16:55:28 -0800305 @param ip_ttl IP TTL
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700306 @param icmp_type ICMP type
307 @param icmp_code ICMP code
308
309 Generates a simple ICMP ECHO REQUEST. Users
310 shouldn't assume anything about this packet other than that
311 it is a valid ethernet/ICMP frame.
312 """
Jeffrey Townsend5cb7ed32012-08-17 18:11:01 +0000313
314 if MINSIZE > pktlen:
315 pktlen = MINSIZE
316
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700317 if (dl_vlan_enable):
Rich Laned0478ff2013-03-11 12:46:58 -0700318 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
319 scapy.Dot1Q(prio=vlan_pcp, id=0, vlan=vlan_vid)/ \
Gregor Maier9cc93342013-01-29 16:55:28 -0800320 scapy.IP(src=ip_src, dst=ip_dst, ttl=ip_ttl, tos=ip_tos)/ \
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700321 scapy.ICMP(type=icmp_type, code=icmp_code)
322 else:
Rich Laned0478ff2013-03-11 12:46:58 -0700323 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
Gregor Maier9cc93342013-01-29 16:55:28 -0800324 scapy.IP(src=ip_src, dst=ip_dst, ttl=ip_ttl, tos=ip_tos)/ \
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700325 scapy.ICMP(type=icmp_type, code=icmp_code)
326
327 pkt = pkt/("0" * (pktlen - len(pkt)))
328
329 return pkt
330
Rich Lane86aceb02013-07-17 18:45:38 -0700331def simple_icmpv6_packet(pktlen=100,
332 eth_dst='00:01:02:03:04:05',
333 eth_src='00:06:07:08:09:0a',
334 dl_vlan_enable=False,
335 vlan_vid=0,
336 vlan_pcp=0,
337 ipv6_src='2001:db8:85a3::8a2e:370:7334',
338 ipv6_dst='2001:db8:85a3::8a2e:370:7335',
339 ipv6_tc=0,
340 ipv6_hlim=64,
341 ipv6_fl=0,
342 icmp_type=8,
343 icmp_code=0):
344 """
345 Return a simple ICMPv6 packet
346
347 Supports a few parameters:
348 @param len Length of packet in bytes w/o CRC
349 @param eth_dst Destination MAC
350 @param eth_src Source MAC
351 @param dl_vlan_enable True if the packet is with vlan, False otherwise
352 @param vlan_vid VLAN ID
353 @param vlan_pcp VLAN priority
354 @param ipv6_src IPv6 source
355 @param ipv6_dst IPv6 destination
356 @param ipv6_tc IPv6 traffic class
357 @param ipv6_ttl IPv6 hop limit
358 @param ipv6_fl IPv6 flow label
359 @param icmp_type ICMP type
360 @param icmp_code ICMP code
361
362 Generates a simple ICMP ECHO REQUEST. Users shouldn't assume anything
363 about this packet other than that it is a valid ethernet/IPv6/ICMP frame.
364 """
365
366 if MINSIZE > pktlen:
367 pktlen = MINSIZE
368
369 pkt = scapy.Ether(dst=eth_dst, src=eth_src)
370 if dl_vlan_enable or vlan_vid or vlan_pcp:
371 pkt /= scapy.Dot1Q(vlan=vlan_vid, prio=vlan_pcp)
372 pkt /= scapy.IPv6(src=ipv6_src, dst=ipv6_dst, fl=ipv6_fl, tc=ipv6_tc, hlim=ipv6_hlim)
373 pkt /= scapy.ICMPv6Unknown(type=icmp_type, code=icmp_code)
374 pkt /= ("D" * (pktlen - len(pkt)))
375
376 return pkt
377
Shudong Zhouc7562b12013-02-06 01:12:18 -0800378def simple_arp_packet(pktlen=60,
Rich Laned0478ff2013-03-11 12:46:58 -0700379 eth_dst='ff:ff:ff:ff:ff:ff',
380 eth_src='00:06:07:08:09:0a',
Shudong Zhouc7562b12013-02-06 01:12:18 -0800381 arp_op=1,
382 ip_snd='192.168.0.1',
383 ip_tgt='192.168.0.2',
384 hw_snd='00:06:07:08:09:0a',
385 hw_tgt='00:00:00:00:00:00',
386 ):
387 """
388 Return a simple ARP packet
389
390 Supports a few parameters:
391 @param len Length of packet in bytes w/o CRC
Rich Laned0478ff2013-03-11 12:46:58 -0700392 @param eth_dst Destinatino MAC
393 @param eth_src Source MAC
Shudong Zhouc7562b12013-02-06 01:12:18 -0800394 @param arp_op Operation (1=request, 2=reply)
395 @param ip_snd Sender IP
396 @param ip_tgt Target IP
397 @param hw_snd Sender hardware address
398 @param hw_tgt Target hardware address
399
400 Generates a simple ARP REQUEST. Users
401 shouldn't assume anything about this packet other than that
402 it is a valid ethernet/ARP frame.
403 """
404
405 if MINSIZE > pktlen:
406 pktlen = MINSIZE
407
Rich Laned0478ff2013-03-11 12:46:58 -0700408 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
Shudong Zhouc7562b12013-02-06 01:12:18 -0800409 scapy.ARP(hwsrc=hw_snd, hwdst=hw_tgt, pdst=ip_tgt, psrc=ip_snd, op=arp_op)
410
411 pkt = pkt/("0" * (pktlen - len(pkt)))
412
413 return pkt
414
Ed Swierk0aeff8c2012-03-23 20:27:18 -0700415def simple_eth_packet(pktlen=60,
Rich Laneb7dc3e22013-08-02 13:51:06 -0700416 eth_dst='01:80:c2:00:00:00',
417 eth_src='00:01:02:03:04:05',
Rich Laned0478ff2013-03-11 12:46:58 -0700418 eth_type=0x88cc):
Jeffrey Townsend5cb7ed32012-08-17 18:11:01 +0000419
420 if MINSIZE > pktlen:
421 pktlen = MINSIZE
422
Rich Laned0478ff2013-03-11 12:46:58 -0700423 pkt = scapy.Ether(dst=eth_dst, src=eth_src, type=eth_type)
Ed Swierk0aeff8c2012-03-23 20:27:18 -0700424
425 pkt = pkt/("0" * (pktlen - len(pkt)))
426
427 return pkt
428
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800429def qinq_tcp_packet(pktlen=100,
Rich Laned0478ff2013-03-11 12:46:58 -0700430 eth_dst='00:01:02:03:04:05',
431 eth_src='00:06:07:08:09:0a',
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800432 dl_vlan_outer=20,
433 dl_vlan_pcp_outer=0,
434 dl_vlan_cfi_outer=0,
Rich Laned0478ff2013-03-11 12:46:58 -0700435 vlan_vid=10,
436 vlan_pcp=0,
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800437 dl_vlan_cfi=0,
438 ip_src='192.168.0.1',
439 ip_dst='192.168.0.2',
440 ip_tos=0,
Gregor Maier9cc93342013-01-29 16:55:28 -0800441 ip_ttl=64,
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800442 tcp_sport=1234,
443 tcp_dport=80,
444 ip_ihl=None,
445 ip_options=False
446 ):
447 """
448 Return a doubly tagged dataplane TCP packet
449
450 Supports a few parameters:
451 @param len Length of packet in bytes w/o CRC
Rich Laned0478ff2013-03-11 12:46:58 -0700452 @param eth_dst Destinatino MAC
453 @param eth_src Source MAC
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800454 @param dl_vlan_outer Outer VLAN ID
455 @param dl_vlan_pcp_outer Outer VLAN priority
456 @param dl_vlan_cfi_outer Outer VLAN cfi bit
Rich Laned0478ff2013-03-11 12:46:58 -0700457 @param vlan_vid Inner VLAN ID
458 @param vlan_pcp VLAN priority
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800459 @param dl_vlan_cfi VLAN cfi bit
460 @param ip_src IP source
461 @param ip_dst IP destination
462 @param ip_tos IP ToS
463 @param tcp_dport TCP destination port
464 @param ip_sport TCP source port
465
466 Generates a TCP request. Users
467 shouldn't assume anything about this packet other than that
468 it is a valid ethernet/IP/TCP frame.
469 """
470
471 if MINSIZE > pktlen:
472 pktlen = MINSIZE
473
474 # Note Dot1Q.id is really CFI
Rich Laned0478ff2013-03-11 12:46:58 -0700475 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800476 scapy.Dot1Q(prio=dl_vlan_pcp_outer, id=dl_vlan_cfi_outer, vlan=dl_vlan_outer)/ \
Rich Laned0478ff2013-03-11 12:46:58 -0700477 scapy.Dot1Q(prio=vlan_pcp, id=dl_vlan_cfi, vlan=vlan_vid)/ \
Gregor Maier9cc93342013-01-29 16:55:28 -0800478 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ttl=ip_ttl, ihl=ip_ihl)/ \
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800479 scapy.TCP(sport=tcp_sport, dport=tcp_dport)
480
481 pkt = pkt/("D" * (pktlen - len(pkt)))
482
483 return pkt
484
Shudong Zhoub7f12462012-11-20 13:01:12 -0800485def do_barrier(ctrl, timeout=-1):
Dan Talayco0fc08bd2012-04-09 16:56:18 -0700486 """
487 Do a barrier command
488 Return 0 on success, -1 on error
489 """
Rich Lanee717c6e2013-03-12 10:25:50 -0700490 b = ofp.message.barrier_request()
Shudong Zhoub7f12462012-11-20 13:01:12 -0800491 (resp, pkt) = ctrl.transact(b, timeout=timeout)
Rich Lane3a261d52013-01-03 17:45:08 -0800492 if resp is None:
493 raise AssertionError("barrier failed")
Dan Talaycof6b94832012-04-12 21:50:57 -0700494 # We'll trust the transaction processing in the controller that xid matched
Rich Lane3a261d52013-01-03 17:45:08 -0800495 return 0 # for backwards compatibility
Dan Talayco92c99122010-06-03 13:53:18 -0700496
Rich Lane9a003812012-10-04 17:17:59 -0700497def port_config_get(controller, port_no):
Dan Talayco92c99122010-06-03 13:53:18 -0700498 """
499 Get a port's configuration
500
501 Gets the switch feature configuration and grabs one port's
502 configuration
503
504 @returns (hwaddr, config, advert) The hwaddress, configuration and
505 advertised values
506 """
Rich Lane6dc865c2013-07-10 10:12:13 -0700507
508 if ofp.OFP_VERSION <= 3:
509 request = ofp.message.features_request()
510 reply, _ = controller.transact(request)
511 if reply is None:
512 logging.warn("Get feature request failed")
513 return None, None, None
514 logging.debug(reply.show())
515 ports = reply.ports
516 else:
517 request = ofp.message.port_desc_stats_request()
518 # TODO do multipart correctly
519 reply, _ = controller.transact(request)
520 if reply is None:
521 logging.warn("Port desc stats request failed")
522 return None, None, None
523 logging.debug(reply.show())
524 ports = reply.entries
525
526 for port in ports:
527 if port.port_no == port_no:
528 return (port.hw_addr, port.config, port.advertised)
Dan Talayco92c99122010-06-03 13:53:18 -0700529
Rich Lane9a003812012-10-04 17:17:59 -0700530 logging.warn("Did not find port number for port config")
Dan Talayco92c99122010-06-03 13:53:18 -0700531 return None, None, None
532
Rich Lane9a003812012-10-04 17:17:59 -0700533def port_config_set(controller, port_no, config, mask):
Dan Talayco92c99122010-06-03 13:53:18 -0700534 """
535 Set the port configuration according the given parameters
536
537 Gets the switch feature configuration and updates one port's
538 configuration value according to config and mask
539 """
Rich Lane9a003812012-10-04 17:17:59 -0700540 logging.info("Setting port " + str(port_no) + " to config " + str(config))
Rich Lane6dc865c2013-07-10 10:12:13 -0700541
542 hw_addr, _, _ = port_config_get(controller, port_no)
543
Rich Lanee717c6e2013-03-12 10:25:50 -0700544 mod = ofp.message.port_mod()
Dan Talayco92c99122010-06-03 13:53:18 -0700545 mod.port_no = port_no
Rich Lane6dc865c2013-07-10 10:12:13 -0700546 if hw_addr != None:
547 mod.hw_addr = hw_addr
Dan Talayco92c99122010-06-03 13:53:18 -0700548 mod.config = config
549 mod.mask = mask
Rich Lane6dc865c2013-07-10 10:12:13 -0700550 mod.advertise = 0 # No change
Rich Lane5c3151c2013-01-03 17:15:41 -0800551 controller.message_send(mod)
552 return 0
Dan Talayco92c99122010-06-03 13:53:18 -0700553
Rich Lane2014f9b2012-10-05 15:29:40 -0700554def receive_pkt_check(dp, pkt, yes_ports, no_ports, assert_if):
Dan Talayco92c99122010-06-03 13:53:18 -0700555 """
556 Check for proper receive packets across all ports
Ken Chiang1bf01602012-04-04 10:48:23 -0700557 @param dp The dataplane object
Dan Talayco92c99122010-06-03 13:53:18 -0700558 @param pkt Expected packet; may be None if yes_ports is empty
559 @param yes_ports Set or list of ports that should recieve packet
560 @param no_ports Set or list of ports that should not receive packet
561 @param assert_if Object that implements assertXXX
562 """
Rich Lane91765672012-12-06 16:33:04 -0800563
564 # Wait this long for packets that we don't expect to receive.
565 # 100ms is (rarely) too short for positive tests on slow
566 # switches but is definitely not too short for a negative test.
567 negative_timeout = 0.1
568
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700569 exp_pkt_arg = None
Rich Lanecd97d3d2013-01-07 18:50:06 -0800570 if oftest.config["relax"]:
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700571 exp_pkt_arg = pkt
572
Dan Talayco92c99122010-06-03 13:53:18 -0700573 for ofport in yes_ports:
Rich Lane9a003812012-10-04 17:17:59 -0700574 logging.debug("Checking for pkt on port " + str(ofport))
Ken Chiang1bf01602012-04-04 10:48:23 -0700575 (rcv_port, rcv_pkt, pkt_time) = dp.poll(
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700576 port_number=ofport, exp_pkt=exp_pkt_arg)
Dan Talayco92c99122010-06-03 13:53:18 -0700577 assert_if.assertTrue(rcv_pkt is not None,
578 "Did not receive pkt on " + str(ofport))
Rich Lanecd97d3d2013-01-07 18:50:06 -0800579 if not oftest.dataplane.match_exp_pkt(pkt, rcv_pkt):
Rich Lane3c266832013-01-29 18:29:15 -0800580 logging.debug("Expected %s" % format_packet(pkt))
581 logging.debug("Received %s" % format_packet(rcv_pkt))
Rich Lanecd97d3d2013-01-07 18:50:06 -0800582 assert_if.assertTrue(oftest.dataplane.match_exp_pkt(pkt, rcv_pkt),
Rich Lane3c266832013-01-29 18:29:15 -0800583 "Received packet does not match expected packet " +
Ken Chiang1bf01602012-04-04 10:48:23 -0700584 "on port " + str(ofport))
Dan Talayco73f84012012-10-02 09:23:18 -0700585 if len(no_ports) > 0:
Rich Lane91765672012-12-06 16:33:04 -0800586 time.sleep(negative_timeout)
Dan Talayco92c99122010-06-03 13:53:18 -0700587 for ofport in no_ports:
Rich Lane9a003812012-10-04 17:17:59 -0700588 logging.debug("Negative check for pkt on port " + str(ofport))
Ken Chiang1bf01602012-04-04 10:48:23 -0700589 (rcv_port, rcv_pkt, pkt_time) = dp.poll(
Rich Lane91765672012-12-06 16:33:04 -0800590 port_number=ofport, timeout=0, exp_pkt=exp_pkt_arg)
Dan Talayco92c99122010-06-03 13:53:18 -0700591 assert_if.assertTrue(rcv_pkt is None,
592 "Unexpected pkt on port " + str(ofport))
Dan Talayco551befa2010-07-15 17:05:32 -0700593
594
Dan Talaycoc948d0b2012-03-23 12:17:54 -0700595def receive_pkt_verify(parent, egr_ports, exp_pkt, ing_port):
Dan Talayco551befa2010-07-15 17:05:32 -0700596 """
597 Receive a packet and verify it matches an expected value
Dan Talaycof6e76c02012-03-23 10:56:12 -0700598 @param egr_port A single port or list of ports
Dan Talayco551befa2010-07-15 17:05:32 -0700599
600 parent must implement dataplane, assertTrue and assertEqual
601 """
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700602 exp_pkt_arg = None
Rich Lanecd97d3d2013-01-07 18:50:06 -0800603 if oftest.config["relax"]:
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700604 exp_pkt_arg = exp_pkt
605
Dan Talaycof6e76c02012-03-23 10:56:12 -0700606 if type(egr_ports) == type([]):
607 egr_port_list = egr_ports
608 else:
609 egr_port_list = [egr_ports]
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700610
Dan Talaycof6e76c02012-03-23 10:56:12 -0700611 # Expect a packet from each port on egr port list
612 for egr_port in egr_port_list:
Dan Talaycod8ae7582012-03-23 12:24:56 -0700613 check_port = egr_port
Rich Lanee717c6e2013-03-12 10:25:50 -0700614 if egr_port == ofp.OFPP_IN_PORT:
Dan Talaycod8ae7582012-03-23 12:24:56 -0700615 check_port = ing_port
Dan Talaycof6e76c02012-03-23 10:56:12 -0700616 (rcv_port, rcv_pkt, pkt_time) = parent.dataplane.poll(
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700617 port_number=check_port, exp_pkt=exp_pkt_arg)
Dan Talayco551befa2010-07-15 17:05:32 -0700618
Dan Talaycof6e76c02012-03-23 10:56:12 -0700619 if rcv_pkt is None:
Rich Lane9a003812012-10-04 17:17:59 -0700620 logging.error("ERROR: No packet received from " +
Dan Talaycod8ae7582012-03-23 12:24:56 -0700621 str(check_port))
Dan Talayco551befa2010-07-15 17:05:32 -0700622
Dan Talaycof6e76c02012-03-23 10:56:12 -0700623 parent.assertTrue(rcv_pkt is not None,
Dan Talaycod8ae7582012-03-23 12:24:56 -0700624 "Did not receive packet port " + str(check_port))
Rich Lane9a003812012-10-04 17:17:59 -0700625 logging.debug("Packet len " + str(len(rcv_pkt)) + " in on " +
Dan Talaycof6e76c02012-03-23 10:56:12 -0700626 str(rcv_port))
627
628 if str(exp_pkt) != str(rcv_pkt):
Rich Lane9a003812012-10-04 17:17:59 -0700629 logging.error("ERROR: Packet match failed.")
630 logging.debug("Expected len " + str(len(exp_pkt)) + ": "
Dan Talaycof6e76c02012-03-23 10:56:12 -0700631 + str(exp_pkt).encode('hex'))
Rich Lane9a003812012-10-04 17:17:59 -0700632 logging.debug("Received len " + str(len(rcv_pkt)) + ": "
Dan Talaycof6e76c02012-03-23 10:56:12 -0700633 + str(rcv_pkt).encode('hex'))
Rich Lane5d7e89a2012-10-26 16:43:13 -0700634 logging.debug("Expected packet: " + inspect_packet(scapy.Ether(str(exp_pkt))))
635 logging.debug("Received packet: " + inspect_packet(scapy.Ether(str(rcv_pkt))))
Dan Talaycof6e76c02012-03-23 10:56:12 -0700636 parent.assertEqual(str(exp_pkt), str(rcv_pkt),
Dan Talaycod8ae7582012-03-23 12:24:56 -0700637 "Packet match error on port " + str(check_port))
Dan Talaycof6e76c02012-03-23 10:56:12 -0700638
Dan Talayco551befa2010-07-15 17:05:32 -0700639def match_verify(parent, req_match, res_match):
640 """
641 Verify flow matches agree; if they disagree, report where
642
643 parent must implement assertEqual
644 Use str() to ensure content is compared and not pointers
645 """
646
647 parent.assertEqual(req_match.wildcards, res_match.wildcards,
648 'Match failed: wildcards: ' + hex(req_match.wildcards) +
649 " != " + hex(res_match.wildcards))
650 parent.assertEqual(req_match.in_port, res_match.in_port,
651 'Match failed: in_port: ' + str(req_match.in_port) +
652 " != " + str(res_match.in_port))
Rich Laned0478ff2013-03-11 12:46:58 -0700653 parent.assertEqual(str(req_match.eth_src), str(res_match.eth_src),
654 'Match failed: eth_src: ' + str(req_match.eth_src) +
655 " != " + str(res_match.eth_src))
656 parent.assertEqual(str(req_match.eth_dst), str(res_match.eth_dst),
657 'Match failed: eth_dst: ' + str(req_match.eth_dst) +
658 " != " + str(res_match.eth_dst))
659 parent.assertEqual(req_match.vlan_vid, res_match.vlan_vid,
660 'Match failed: vlan_vid: ' + str(req_match.vlan_vid) +
661 " != " + str(res_match.vlan_vid))
662 parent.assertEqual(req_match.vlan_pcp, res_match.vlan_pcp,
663 'Match failed: vlan_pcp: ' +
664 str(req_match.vlan_pcp) + " != " +
665 str(res_match.vlan_pcp))
666 parent.assertEqual(req_match.eth_type, res_match.eth_type,
667 'Match failed: eth_type: ' + str(req_match.eth_type) +
668 " != " + str(res_match.eth_type))
Dan Talayco551befa2010-07-15 17:05:32 -0700669
Rich Lanee717c6e2013-03-12 10:25:50 -0700670 if (not(req_match.wildcards & ofp.OFPFW_DL_TYPE)
Rich Laned0478ff2013-03-11 12:46:58 -0700671 and (req_match.eth_type == IP_ETHERTYPE)):
672 parent.assertEqual(req_match.ip_dscp, res_match.ip_dscp,
673 'Match failed: ip_dscp: ' + str(req_match.ip_dscp) +
674 " != " + str(res_match.ip_dscp))
675 parent.assertEqual(req_match.ip_proto, res_match.ip_proto,
676 'Match failed: ip_proto: ' + str(req_match.ip_proto) +
677 " != " + str(res_match.ip_proto))
678 parent.assertEqual(req_match.ipv4_src, res_match.ipv4_src,
679 'Match failed: ipv4_src: ' + str(req_match.ipv4_src) +
680 " != " + str(res_match.ipv4_src))
681 parent.assertEqual(req_match.ipv4_dst, res_match.ipv4_dst,
682 'Match failed: ipv4_dst: ' + str(req_match.ipv4_dst) +
683 " != " + str(res_match.ipv4_dst))
Dan Talayco551befa2010-07-15 17:05:32 -0700684
Rich Lanee717c6e2013-03-12 10:25:50 -0700685 if (not(req_match.wildcards & ofp.OFPFW_NW_PROTO)
Rich Laned0478ff2013-03-11 12:46:58 -0700686 and ((req_match.ip_proto == TCP_PROTOCOL)
687 or (req_match.ip_proto == UDP_PROTOCOL))):
688 parent.assertEqual(req_match.tcp_src, res_match.tcp_src,
689 'Match failed: tcp_src: ' +
690 str(req_match.tcp_src) +
691 " != " + str(res_match.tcp_src))
692 parent.assertEqual(req_match.tcp_dst, res_match.tcp_dst,
693 'Match failed: tcp_dst: ' +
694 str(req_match.tcp_dst) +
695 " != " + str(res_match.tcp_dst))
Dan Talayco551befa2010-07-15 17:05:32 -0700696
Ed Swierk99a74de2012-08-22 06:40:54 -0700697def packet_to_flow_match(parent, packet):
Rich Lanef6883512013-03-11 17:00:09 -0700698 match = oftest.parse.packet_to_flow_match(packet)
Rich Laneab7476f2013-06-13 15:53:52 -0700699 if ofp.OFP_VERSION in [1, 2]:
700 match.wildcards |= required_wildcards(parent)
701 else:
702 # TODO remove incompatible OXM entries
703 pass
Ed Swierk99a74de2012-08-22 06:40:54 -0700704 return match
705
706def flow_msg_create(parent, pkt, ing_port=None, action_list=None, wildcards=None,
Dan Talaycof6e76c02012-03-23 10:56:12 -0700707 egr_ports=None, egr_queue=None, check_expire=False, in_band=False):
Dan Talayco551befa2010-07-15 17:05:32 -0700708 """
709 Create a flow message
710
711 Match on packet with given wildcards.
712 See flow_match_test for other parameter descriptoins
713 @param egr_queue if not None, make the output an enqueue action
Dan Talayco677c0b72011-08-23 22:53:38 -0700714 @param in_band if True, do not wildcard ingress port
Dan Talaycof6e76c02012-03-23 10:56:12 -0700715 @param egr_ports None (drop), single port or list of ports
Dan Talayco551befa2010-07-15 17:05:32 -0700716 """
Rich Lanef6883512013-03-11 17:00:09 -0700717 match = oftest.parse.packet_to_flow_match(pkt)
Dan Talayco551befa2010-07-15 17:05:32 -0700718 parent.assertTrue(match is not None, "Flow match from pkt failed")
Ed Swierk99a74de2012-08-22 06:40:54 -0700719 if wildcards is None:
720 wildcards = required_wildcards(parent)
Dan Talayco677c0b72011-08-23 22:53:38 -0700721 if in_band:
Rich Lanee717c6e2013-03-12 10:25:50 -0700722 wildcards &= ~ofp.OFPFW_IN_PORT
Dan Talayco551befa2010-07-15 17:05:32 -0700723 match.wildcards = wildcards
724 match.in_port = ing_port
725
Dan Talaycof6e76c02012-03-23 10:56:12 -0700726 if type(egr_ports) == type([]):
727 egr_port_list = egr_ports
728 else:
729 egr_port_list = [egr_ports]
730
Rich Lanee717c6e2013-03-12 10:25:50 -0700731 request = ofp.message.flow_add()
Dan Talayco551befa2010-07-15 17:05:32 -0700732 request.match = match
733 request.buffer_id = 0xffffffff
734 if check_expire:
Rich Lanee717c6e2013-03-12 10:25:50 -0700735 request.flags |= ofp.OFPFF_SEND_FLOW_REM
Dan Talayco551befa2010-07-15 17:05:32 -0700736 request.hard_timeout = 1
737
738 if action_list is not None:
739 for act in action_list:
Rich Lane9a003812012-10-04 17:17:59 -0700740 logging.debug("Adding action " + act.show())
Rich Lanec495d9e2013-03-08 17:43:36 -0800741 request.actions.append(act)
Dan Talayco551befa2010-07-15 17:05:32 -0700742
743 # Set up output/enqueue action if directed
744 if egr_queue is not None:
Dan Talaycof6e76c02012-03-23 10:56:12 -0700745 parent.assertTrue(egr_ports is not None, "Egress port not set")
Rich Lanee717c6e2013-03-12 10:25:50 -0700746 act = ofp.action.enqueue()
Dan Talaycof6e76c02012-03-23 10:56:12 -0700747 for egr_port in egr_port_list:
748 act.port = egr_port
749 act.queue_id = egr_queue
Rich Lanec495d9e2013-03-08 17:43:36 -0800750 request.actions.append(act)
Dan Talaycof6e76c02012-03-23 10:56:12 -0700751 elif egr_ports is not None:
752 for egr_port in egr_port_list:
Rich Lanee717c6e2013-03-12 10:25:50 -0700753 act = ofp.action.output()
Dan Talaycof6e76c02012-03-23 10:56:12 -0700754 act.port = egr_port
Rich Lanec495d9e2013-03-08 17:43:36 -0800755 request.actions.append(act)
Dan Talayco551befa2010-07-15 17:05:32 -0700756
Rich Lane9a003812012-10-04 17:17:59 -0700757 logging.debug(request.show())
Dan Talayco551befa2010-07-15 17:05:32 -0700758
759 return request
760
Jeffrey Townsendf3eae9c2012-03-28 18:23:21 -0700761def flow_msg_install(parent, request, clear_table_override=None):
Dan Talayco551befa2010-07-15 17:05:32 -0700762 """
763 Install a flow mod message in the switch
764
765 @param parent Must implement controller, assertEqual, assertTrue
766 @param request The request, all set to go
767 @param clear_table If true, clear the flow table before installing
768 """
Dan Talayco8a64e332012-03-28 14:53:20 -0700769
Rich Lane2014f9b2012-10-05 15:29:40 -0700770 clear_table = test_param_get('clear_table', default=True)
Jeffrey Townsendf3eae9c2012-03-28 18:23:21 -0700771 if(clear_table_override != None):
772 clear_table = clear_table_override
773
774 if clear_table:
Rich Lane9a003812012-10-04 17:17:59 -0700775 logging.debug("Clear flow table")
Rich Lane32bf9482013-01-03 17:26:30 -0800776 delete_all_flows(parent.controller)
Dan Talayco551befa2010-07-15 17:05:32 -0700777
Rich Lane9a003812012-10-04 17:17:59 -0700778 logging.debug("Insert flow")
Rich Lane5c3151c2013-01-03 17:15:41 -0800779 parent.controller.message_send(request)
Rich Lanee912d032012-12-22 14:28:33 -0800780
Rich Lane3a261d52013-01-03 17:45:08 -0800781 do_barrier(parent.controller)
Dan Talayco551befa2010-07-15 17:05:32 -0700782
Ed Swierk99a74de2012-08-22 06:40:54 -0700783def flow_match_test_port_pair(parent, ing_port, egr_ports, wildcards=None,
Rich Laned0478ff2013-03-11 12:46:58 -0700784 vlan_vid=-1, pkt=None, exp_pkt=None,
Rich Lanee5779d32012-10-05 17:56:04 -0700785 action_list=None):
Dan Talayco551befa2010-07-15 17:05:32 -0700786 """
787 Flow match test on single TCP packet
Dan Talaycof6e76c02012-03-23 10:56:12 -0700788 @param egr_ports A single port or list of ports
Dan Talayco551befa2010-07-15 17:05:32 -0700789
790 Run test with packet through switch from ing_port to egr_port
791 See flow_match_test for parameter descriptions
792 """
793
Ed Swierk99a74de2012-08-22 06:40:54 -0700794 if wildcards is None:
795 wildcards = required_wildcards(parent)
Rich Lane9a003812012-10-04 17:17:59 -0700796 logging.info("Pkt match test: " + str(ing_port) + " to " +
Dan Talaycof6e76c02012-03-23 10:56:12 -0700797 str(egr_ports))
Rich Laned0478ff2013-03-11 12:46:58 -0700798 logging.debug(" WC: " + hex(wildcards) + " vlan: " + str(vlan_vid))
Dan Talayco551befa2010-07-15 17:05:32 -0700799 if pkt is None:
Rich Laned0478ff2013-03-11 12:46:58 -0700800 pkt = simple_tcp_packet(dl_vlan_enable=(vlan_vid >= 0), vlan_vid=vlan_vid)
Dan Talayco551befa2010-07-15 17:05:32 -0700801
802 request = flow_msg_create(parent, pkt, ing_port=ing_port,
Dan Talaycof6e76c02012-03-23 10:56:12 -0700803 wildcards=wildcards, egr_ports=egr_ports,
Dan Talayco551befa2010-07-15 17:05:32 -0700804 action_list=action_list)
805
806 flow_msg_install(parent, request)
807
Rich Lane9a003812012-10-04 17:17:59 -0700808 logging.debug("Send packet: " + str(ing_port) + " to " +
Dan Talaycof6e76c02012-03-23 10:56:12 -0700809 str(egr_ports))
Dan Talayco551befa2010-07-15 17:05:32 -0700810 parent.dataplane.send(ing_port, str(pkt))
811
812 if exp_pkt is None:
813 exp_pkt = pkt
Dan Talaycoc948d0b2012-03-23 12:17:54 -0700814 receive_pkt_verify(parent, egr_ports, exp_pkt, ing_port)
Dan Talayco551befa2010-07-15 17:05:32 -0700815
Rich Lane89725bb2012-12-03 16:23:27 -0800816def flow_match_test_pktout(parent, ing_port, egr_ports,
Rich Laned0478ff2013-03-11 12:46:58 -0700817 vlan_vid=-1, pkt=None, exp_pkt=None,
Rich Lane89725bb2012-12-03 16:23:27 -0800818 action_list=None):
819 """
820 Packet-out test on single TCP packet
821 @param egr_ports A single port or list of ports
822
823 Run test sending packet-out to egr_ports. The goal is to test the actions
824 taken on the packet, not the matching which is of course irrelevant.
825 See flow_match_test for parameter descriptions
826 """
827
828 if pkt is None:
Rich Laned0478ff2013-03-11 12:46:58 -0700829 pkt = simple_tcp_packet(dl_vlan_enable=(vlan_vid >= 0), vlan_vid=vlan_vid)
Rich Lane89725bb2012-12-03 16:23:27 -0800830
Rich Lanee717c6e2013-03-12 10:25:50 -0700831 msg = ofp.message.packet_out()
Rich Lane89725bb2012-12-03 16:23:27 -0800832 msg.in_port = ing_port
Rich Laneea8c4722013-04-04 15:30:20 -0700833 msg.buffer_id = 0xffffffff
Rich Lane89725bb2012-12-03 16:23:27 -0800834 msg.data = str(pkt)
835 if action_list is not None:
836 for act in action_list:
Rich Lanec495d9e2013-03-08 17:43:36 -0800837 msg.actions.append(act)
Rich Lane89725bb2012-12-03 16:23:27 -0800838
839 # Set up output action
840 if egr_ports is not None:
841 for egr_port in egr_ports:
Rich Lanee717c6e2013-03-12 10:25:50 -0700842 act = ofp.action.output()
Rich Lane89725bb2012-12-03 16:23:27 -0800843 act.port = egr_port
Rich Lanec495d9e2013-03-08 17:43:36 -0800844 msg.actions.append(act)
Rich Lane89725bb2012-12-03 16:23:27 -0800845
846 logging.debug(msg.show())
Rich Lane5c3151c2013-01-03 17:15:41 -0800847 parent.controller.message_send(msg)
Rich Lane89725bb2012-12-03 16:23:27 -0800848
849 if exp_pkt is None:
850 exp_pkt = pkt
851 receive_pkt_verify(parent, egr_ports, exp_pkt, ing_port)
852
Dan Talaycof6e76c02012-03-23 10:56:12 -0700853def get_egr_list(parent, of_ports, how_many, exclude_list=[]):
854 """
855 Generate a list of ports avoiding those in the exclude list
Rich Lane9a003812012-10-04 17:17:59 -0700856 @param parent Supplies logging
Dan Talaycof6e76c02012-03-23 10:56:12 -0700857 @param of_ports List of OF port numbers
858 @param how_many Number of ports to be added to the list
859 @param exclude_list List of ports not to be used
860 @returns An empty list if unable to find enough ports
861 """
862
Dan Talaycoc948d0b2012-03-23 12:17:54 -0700863 if how_many == 0:
864 return []
865
Dan Talaycof6e76c02012-03-23 10:56:12 -0700866 count = 0
867 egr_ports = []
868 for egr_idx in range(len(of_ports)):
869 if of_ports[egr_idx] not in exclude_list:
870 egr_ports.append(of_ports[egr_idx])
871 count += 1
872 if count >= how_many:
873 return egr_ports
Rich Lane9a003812012-10-04 17:17:59 -0700874 logging.debug("Could not generate enough egress ports for test")
Dan Talaycof6e76c02012-03-23 10:56:12 -0700875 return []
876
Rich Laned0478ff2013-03-11 12:46:58 -0700877def flow_match_test(parent, port_map, wildcards=None, vlan_vid=-1, pkt=None,
Rich Lanee5779d32012-10-05 17:56:04 -0700878 exp_pkt=None, action_list=None,
Dan Talaycoc948d0b2012-03-23 12:17:54 -0700879 max_test=0, egr_count=1, ing_port=False):
Dan Talayco551befa2010-07-15 17:05:32 -0700880 """
Rich Lane89725bb2012-12-03 16:23:27 -0800881 Run flow_match_test_port_pair on all port pairs and packet-out
Dan Talayco551befa2010-07-15 17:05:32 -0700882
883 @param max_test If > 0 no more than this number of tests are executed.
884 @param parent Must implement controller, dataplane, assertTrue, assertEqual
Rich Lane9a003812012-10-04 17:17:59 -0700885 and logging
Dan Talayco551befa2010-07-15 17:05:32 -0700886 @param pkt If not None, use this packet for ingress
887 @param wildcards For flow match entry
Rich Laned0478ff2013-03-11 12:46:58 -0700888 @param vlan_vid If not -1, and pkt is None, create a pkt w/ VLAN tag
Dan Talayco551befa2010-07-15 17:05:32 -0700889 @param exp_pkt If not None, use this as the expected output pkt; els use pkt
890 @param action_list Additional actions to add to flow mod
Dan Talaycocfa172f2012-03-23 12:03:00 -0700891 @param egr_count Number of egress ports; -1 means get from config w/ dflt 2
Dan Talayco551befa2010-07-15 17:05:32 -0700892 """
Ed Swierk99a74de2012-08-22 06:40:54 -0700893 if wildcards is None:
894 wildcards = required_wildcards(parent)
Dan Talayco551befa2010-07-15 17:05:32 -0700895 of_ports = port_map.keys()
896 of_ports.sort()
897 parent.assertTrue(len(of_ports) > 1, "Not enough ports for test")
898 test_count = 0
899
Dan Talaycocfa172f2012-03-23 12:03:00 -0700900 if egr_count == -1:
Rich Lane2014f9b2012-10-05 15:29:40 -0700901 egr_count = test_param_get('egr_count', default=2)
Dan Talaycocfa172f2012-03-23 12:03:00 -0700902
Dan Talayco551befa2010-07-15 17:05:32 -0700903 for ing_idx in range(len(of_ports)):
904 ingress_port = of_ports[ing_idx]
Dan Talaycof6e76c02012-03-23 10:56:12 -0700905 egr_ports = get_egr_list(parent, of_ports, egr_count,
906 exclude_list=[ingress_port])
Dan Talaycoc948d0b2012-03-23 12:17:54 -0700907 if ing_port:
Rich Lanee717c6e2013-03-12 10:25:50 -0700908 egr_ports.append(ofp.OFPP_IN_PORT)
Dan Talaycof6e76c02012-03-23 10:56:12 -0700909 if len(egr_ports) == 0:
910 parent.assertTrue(0, "Failed to generate egress port list")
911
912 flow_match_test_port_pair(parent, ingress_port, egr_ports,
Rich Laned0478ff2013-03-11 12:46:58 -0700913 wildcards=wildcards, vlan_vid=vlan_vid,
Dan Talaycof6e76c02012-03-23 10:56:12 -0700914 pkt=pkt, exp_pkt=exp_pkt,
Rich Lanee5779d32012-10-05 17:56:04 -0700915 action_list=action_list)
Dan Talaycof6e76c02012-03-23 10:56:12 -0700916 test_count += 1
917 if (max_test > 0) and (test_count > max_test):
Rich Lane9a003812012-10-04 17:17:59 -0700918 logging.info("Ran " + str(test_count) + " tests; exiting")
Rich Lane89725bb2012-12-03 16:23:27 -0800919 break
920
Ed Swierk38eea082013-01-02 19:46:20 -0800921 if not test_param_get('pktout_actions', default=True):
922 return
Rich Lane89725bb2012-12-03 16:23:27 -0800923
924 ingress_port = of_ports[0]
925 egr_ports = get_egr_list(parent, of_ports, egr_count,
926 exclude_list=[ingress_port])
927 if ing_port:
Rich Lanee717c6e2013-03-12 10:25:50 -0700928 egr_ports.append(ofp.OFPP_IN_PORT)
Rich Lane89725bb2012-12-03 16:23:27 -0800929 flow_match_test_pktout(parent, ingress_port, egr_ports,
Rich Laned0478ff2013-03-11 12:46:58 -0700930 vlan_vid=vlan_vid,
Rich Lane89725bb2012-12-03 16:23:27 -0800931 pkt=pkt, exp_pkt=exp_pkt,
932 action_list=action_list)
Dan Talayco551befa2010-07-15 17:05:32 -0700933
Rich Lane2014f9b2012-10-05 15:29:40 -0700934def test_param_get(key, default=None):
Dan Talayco4b2bee62010-07-20 14:10:05 -0700935 """
936 Return value passed via test-params if present
937
Dan Talayco4b2bee62010-07-20 14:10:05 -0700938 @param key The lookup key
939 @param default Default value to use if not found
940
941 If the pair 'key=val' appeared in the string passed to --test-params
942 on the command line, return val (as interpreted by exec). Otherwise
943 return default value.
Dan Talaycof6e76c02012-03-23 10:56:12 -0700944
945 WARNING: TEST PARAMETERS MUST BE PYTHON IDENTIFIERS;
946 eg egr_count, not egr-count.
Dan Talayco4b2bee62010-07-20 14:10:05 -0700947 """
948 try:
Rich Lanecd97d3d2013-01-07 18:50:06 -0800949 exec oftest.config["test_params"]
Dan Talayco4b2bee62010-07-20 14:10:05 -0700950 except:
951 return default
952
953 s = "val = " + str(key)
954 try:
955 exec s
956 return val
957 except:
958 return default
959
960def action_generate(parent, field_to_mod, mod_field_vals):
961 """
962 Create an action to modify the field indicated in field_to_mod
963
964 @param parent Must implement, assertTrue
965 @param field_to_mod The field to modify as a string name
966 @param mod_field_vals Hash of values to use for modified values
967 """
968
969 act = None
970
971 if field_to_mod in ['pktlen']:
972 return None
973
Rich Laned0478ff2013-03-11 12:46:58 -0700974 if field_to_mod == 'eth_dst':
Rich Lanee717c6e2013-03-12 10:25:50 -0700975 act = ofp.action.set_dl_dst()
Rich Lanef6883512013-03-11 17:00:09 -0700976 act.dl_addr = oftest.parse.parse_mac(mod_field_vals['eth_dst'])
Rich Laned0478ff2013-03-11 12:46:58 -0700977 elif field_to_mod == 'eth_src':
Rich Lanee717c6e2013-03-12 10:25:50 -0700978 act = ofp.action.set_dl_src()
Rich Lanef6883512013-03-11 17:00:09 -0700979 act.dl_addr = oftest.parse.parse_mac(mod_field_vals['eth_src'])
Dan Talayco4b2bee62010-07-20 14:10:05 -0700980 elif field_to_mod == 'dl_vlan_enable':
981 if not mod_field_vals['dl_vlan_enable']: # Strip VLAN tag
Rich Lanee717c6e2013-03-12 10:25:50 -0700982 act = ofp.action.strip_vlan()
Rich Laned0478ff2013-03-11 12:46:58 -0700983 # Add VLAN tag is handled by vlan_vid field
Dan Talayco4b2bee62010-07-20 14:10:05 -0700984 # Will return None in this case
Rich Laned0478ff2013-03-11 12:46:58 -0700985 elif field_to_mod == 'vlan_vid':
Rich Lanee717c6e2013-03-12 10:25:50 -0700986 act = ofp.action.set_vlan_vid()
Rich Laned0478ff2013-03-11 12:46:58 -0700987 act.vlan_vid = mod_field_vals['vlan_vid']
988 elif field_to_mod == 'vlan_pcp':
Rich Lanee717c6e2013-03-12 10:25:50 -0700989 act = ofp.action.set_vlan_pcp()
Rich Laned0478ff2013-03-11 12:46:58 -0700990 act.vlan_pcp = mod_field_vals['vlan_pcp']
Dan Talayco4b2bee62010-07-20 14:10:05 -0700991 elif field_to_mod == 'ip_src':
Rich Lanee717c6e2013-03-12 10:25:50 -0700992 act = ofp.action.set_nw_src()
Rich Lanef6883512013-03-11 17:00:09 -0700993 act.nw_addr = oftest.parse.parse_ip(mod_field_vals['ip_src'])
Dan Talayco4b2bee62010-07-20 14:10:05 -0700994 elif field_to_mod == 'ip_dst':
Rich Lanee717c6e2013-03-12 10:25:50 -0700995 act = ofp.action.set_nw_dst()
Rich Lanef6883512013-03-11 17:00:09 -0700996 act.nw_addr = oftest.parse.parse_ip(mod_field_vals['ip_dst'])
Dan Talayco4b2bee62010-07-20 14:10:05 -0700997 elif field_to_mod == 'ip_tos':
Rich Lanee717c6e2013-03-12 10:25:50 -0700998 act = ofp.action.set_nw_tos()
Dan Talayco4b2bee62010-07-20 14:10:05 -0700999 act.nw_tos = mod_field_vals['ip_tos']
1000 elif field_to_mod == 'tcp_sport':
Rich Lanee717c6e2013-03-12 10:25:50 -07001001 act = ofp.action.set_tp_src()
Dan Talayco4b2bee62010-07-20 14:10:05 -07001002 act.tp_port = mod_field_vals['tcp_sport']
1003 elif field_to_mod == 'tcp_dport':
Rich Lanee717c6e2013-03-12 10:25:50 -07001004 act = ofp.action.set_tp_dst()
Dan Talayco4b2bee62010-07-20 14:10:05 -07001005 act.tp_port = mod_field_vals['tcp_dport']
Rich Lane110e0e32012-10-26 16:21:46 -07001006 elif field_to_mod == 'udp_sport':
Rich Lanee717c6e2013-03-12 10:25:50 -07001007 act = ofp.action.set_tp_src()
Rich Lane110e0e32012-10-26 16:21:46 -07001008 act.tp_port = mod_field_vals['udp_sport']
1009 elif field_to_mod == 'udp_dport':
Rich Lanee717c6e2013-03-12 10:25:50 -07001010 act = ofp.action.set_tp_dst()
Rich Lane110e0e32012-10-26 16:21:46 -07001011 act.tp_port = mod_field_vals['udp_dport']
Dan Talayco4b2bee62010-07-20 14:10:05 -07001012 else:
1013 parent.assertTrue(0, "Unknown field to modify: " + str(field_to_mod))
1014
1015 return act
1016
1017def pkt_action_setup(parent, start_field_vals={}, mod_field_vals={},
Rich Lane110e0e32012-10-26 16:21:46 -07001018 mod_fields=[], tp="tcp", check_test_params=False):
Dan Talayco4b2bee62010-07-20 14:10:05 -07001019 """
1020 Set up the ingress and expected packet and action list for a test
1021
Rich Lane2014f9b2012-10-05 15:29:40 -07001022 @param parent Must implement assertTrue
Dan Talayco4b2bee62010-07-20 14:10:05 -07001023 @param start_field_values Field values to use for ingress packet (optional)
1024 @param mod_field_values Field values to use for modified packet (optional)
1025 @param mod_fields The list of fields to be modified by the switch in the test.
1026 @params check_test_params If True, will check the parameters vid, add_vlan
1027 and strip_vlan from the command line.
1028
1029 Returns a triple: pkt-to-send, expected-pkt, action-list
1030 """
1031
1032 new_actions = []
1033
Dan Talayco4b2bee62010-07-20 14:10:05 -07001034 base_pkt_params = {}
1035 base_pkt_params['pktlen'] = 100
Rich Laned0478ff2013-03-11 12:46:58 -07001036 base_pkt_params['eth_dst'] = '00:DE:F0:12:34:56'
1037 base_pkt_params['eth_src'] = '00:23:45:67:89:AB'
Dan Talayco4b2bee62010-07-20 14:10:05 -07001038 base_pkt_params['dl_vlan_enable'] = False
Rich Laned0478ff2013-03-11 12:46:58 -07001039 base_pkt_params['vlan_vid'] = 2
1040 base_pkt_params['vlan_pcp'] = 0
Dan Talayco4b2bee62010-07-20 14:10:05 -07001041 base_pkt_params['ip_src'] = '192.168.0.1'
1042 base_pkt_params['ip_dst'] = '192.168.0.2'
1043 base_pkt_params['ip_tos'] = 0
Rich Lane110e0e32012-10-26 16:21:46 -07001044 if tp == "tcp":
1045 base_pkt_params['tcp_sport'] = 1234
1046 base_pkt_params['tcp_dport'] = 80
1047 elif tp == "udp":
1048 base_pkt_params['udp_sport'] = 1234
1049 base_pkt_params['udp_dport'] = 80
Dan Talayco4b2bee62010-07-20 14:10:05 -07001050 for keyname in start_field_vals.keys():
1051 base_pkt_params[keyname] = start_field_vals[keyname]
1052
1053 mod_pkt_params = {}
1054 mod_pkt_params['pktlen'] = 100
Rich Laned0478ff2013-03-11 12:46:58 -07001055 mod_pkt_params['eth_dst'] = '00:21:0F:ED:CB:A9'
1056 mod_pkt_params['eth_src'] = '00:ED:CB:A9:87:65'
Dan Talayco4b2bee62010-07-20 14:10:05 -07001057 mod_pkt_params['dl_vlan_enable'] = False
Rich Laned0478ff2013-03-11 12:46:58 -07001058 mod_pkt_params['vlan_vid'] = 3
1059 mod_pkt_params['vlan_pcp'] = 7
Dan Talayco4b2bee62010-07-20 14:10:05 -07001060 mod_pkt_params['ip_src'] = '10.20.30.40'
1061 mod_pkt_params['ip_dst'] = '50.60.70.80'
1062 mod_pkt_params['ip_tos'] = 0xf0
Rich Lane110e0e32012-10-26 16:21:46 -07001063 if tp == "tcp":
1064 mod_pkt_params['tcp_sport'] = 4321
1065 mod_pkt_params['tcp_dport'] = 8765
1066 elif tp == "udp":
1067 mod_pkt_params['udp_sport'] = 4321
1068 mod_pkt_params['udp_dport'] = 8765
Dan Talayco4b2bee62010-07-20 14:10:05 -07001069 for keyname in mod_field_vals.keys():
1070 mod_pkt_params[keyname] = mod_field_vals[keyname]
1071
1072 # Check for test param modifications
1073 strip = False
1074 if check_test_params:
Rich Lane2014f9b2012-10-05 15:29:40 -07001075 add_vlan = test_param_get('add_vlan')
1076 strip_vlan = test_param_get('strip_vlan')
1077 vid = test_param_get('vid')
Dan Talayco4b2bee62010-07-20 14:10:05 -07001078
1079 if add_vlan and strip_vlan:
1080 parent.assertTrue(0, "Add and strip VLAN both specified")
1081
1082 if vid:
1083 base_pkt_params['dl_vlan_enable'] = True
Rich Laned0478ff2013-03-11 12:46:58 -07001084 base_pkt_params['vlan_vid'] = vid
1085 if 'vlan_vid' in mod_fields:
1086 mod_pkt_params['vlan_vid'] = vid + 1
Dan Talayco4b2bee62010-07-20 14:10:05 -07001087
1088 if add_vlan:
1089 base_pkt_params['dl_vlan_enable'] = False
1090 mod_pkt_params['dl_vlan_enable'] = True
1091 mod_pkt_params['pktlen'] = base_pkt_params['pktlen'] + 4
1092 mod_fields.append('pktlen')
1093 mod_fields.append('dl_vlan_enable')
Rich Laned0478ff2013-03-11 12:46:58 -07001094 if 'vlan_vid' not in mod_fields:
1095 mod_fields.append('vlan_vid')
Dan Talayco4b2bee62010-07-20 14:10:05 -07001096 elif strip_vlan:
1097 base_pkt_params['dl_vlan_enable'] = True
1098 mod_pkt_params['dl_vlan_enable'] = False
1099 mod_pkt_params['pktlen'] = base_pkt_params['pktlen'] - 4
1100 mod_fields.append('dl_vlan_enable')
1101 mod_fields.append('pktlen')
1102
Rich Lane110e0e32012-10-26 16:21:46 -07001103 if tp == "tcp":
1104 packet_builder = simple_tcp_packet
1105 elif tp == "udp":
1106 packet_builder = simple_udp_packet
1107 else:
1108 raise NotImplementedError("unknown transport protocol %s" % tp)
1109
Dan Talayco4b2bee62010-07-20 14:10:05 -07001110 # Build the ingress packet
Rich Lane110e0e32012-10-26 16:21:46 -07001111 ingress_pkt = packet_builder(**base_pkt_params)
Dan Talayco4b2bee62010-07-20 14:10:05 -07001112
1113 # Build the expected packet, modifying the indicated fields
1114 for item in mod_fields:
1115 base_pkt_params[item] = mod_pkt_params[item]
1116 act = action_generate(parent, item, mod_pkt_params)
1117 if act:
1118 new_actions.append(act)
1119
Rich Lane110e0e32012-10-26 16:21:46 -07001120 expected_pkt = packet_builder(**base_pkt_params)
Dan Talayco4b2bee62010-07-20 14:10:05 -07001121
1122 return (ingress_pkt, expected_pkt, new_actions)
Dan Talayco677c0b72011-08-23 22:53:38 -07001123
1124# Generate a simple "drop" flow mod
1125# If in_band is true, then only drop from first test port
1126def flow_mod_gen(port_map, in_band):
Rich Lanee717c6e2013-03-12 10:25:50 -07001127 request = ofp.message.flow_add()
1128 request.match.wildcards = ofp.OFPFW_ALL
Dan Talayco677c0b72011-08-23 22:53:38 -07001129 if in_band:
Rich Lanee717c6e2013-03-12 10:25:50 -07001130 request.match.wildcards = ofp.OFPFW_ALL - ofp.OFPFW_IN_PORT
Dan Talayco677c0b72011-08-23 22:53:38 -07001131 for of_port, ifname in port_map.items(): # Grab first port
1132 break
1133 request.match.in_port = of_port
1134 request.buffer_id = 0xffffffff
1135 return request
Dan Talaycoba3745c2010-07-21 21:51:08 -07001136
1137def skip_message_emit(parent, s):
1138 """
1139 Print out a 'skipped' message to stderr
1140
1141 @param s The string to print out to the log file
Dan Talaycoba3745c2010-07-21 21:51:08 -07001142 """
1143 global skipped_test_count
1144
1145 skipped_test_count += 1
Rich Lane9a003812012-10-04 17:17:59 -07001146 logging.info("Skipping: " + s)
Dan Talayco2940fdd2013-02-06 15:01:35 -08001147 if oftest.config["debug"] < logging.WARNING:
Dan Talaycoba3745c2010-07-21 21:51:08 -07001148 sys.stderr.write("(skipped) ")
1149 else:
1150 sys.stderr.write("(S)")
Dan Talayco677c0b72011-08-23 22:53:38 -07001151
Dan Talayco8a64e332012-03-28 14:53:20 -07001152
1153def all_stats_get(parent):
1154 """
1155 Get the aggregate stats for all flows in the table
1156 @param parent Test instance with controller connection and assert
1157 @returns dict with keys flows, packets, bytes, active (flows),
1158 lookups, matched
1159 """
Rich Lanee717c6e2013-03-12 10:25:50 -07001160 stat_req = ofp.message.aggregate_stats_request()
1161 stat_req.match = ofp.match()
1162 stat_req.match.wildcards = ofp.OFPFW_ALL
Dan Talayco8a64e332012-03-28 14:53:20 -07001163 stat_req.table_id = 0xff
Rich Lanee717c6e2013-03-12 10:25:50 -07001164 stat_req.out_port = ofp.OFPP_NONE
Dan Talayco8a64e332012-03-28 14:53:20 -07001165
1166 rv = {}
1167
Rich Lanec8aaa3e2012-07-26 19:28:02 -07001168 (reply, pkt) = parent.controller.transact(stat_req)
Rich Lane5fd6faf2013-03-11 13:30:20 -07001169 parent.assertTrue(len(reply.entries) == 1, "Did not receive flow stats reply")
Dan Talayco8a64e332012-03-28 14:53:20 -07001170
Rich Lane5fd6faf2013-03-11 13:30:20 -07001171 for obj in reply.entries:
Dan Talayco8a64e332012-03-28 14:53:20 -07001172 (rv["flows"], rv["packets"], rv["bytes"]) = (obj.flow_count,
1173 obj.packet_count, obj.byte_count)
1174 break
1175
Rich Lanee717c6e2013-03-12 10:25:50 -07001176 request = ofp.message.table_stats_request()
Rich Lanec8aaa3e2012-07-26 19:28:02 -07001177 (reply , pkt) = parent.controller.transact(request)
Dan Talayco8a64e332012-03-28 14:53:20 -07001178
1179
1180 (rv["active"], rv["lookups"], rv["matched"]) = (0,0,0)
Rich Lane5fd6faf2013-03-11 13:30:20 -07001181 for obj in reply.entries:
Dan Talayco8a64e332012-03-28 14:53:20 -07001182 rv["active"] += obj.active_count
1183 rv["lookups"] += obj.lookup_count
1184 rv["matched"] += obj.matched_count
1185
1186 return rv
Dan Talayco2baf8b52012-03-30 09:55:42 -07001187
Rich Lane7744e112013-01-11 17:23:57 -08001188_import_blacklist.add('FILTER')
Dan Talayco2baf8b52012-03-30 09:55:42 -07001189FILTER=''.join([(len(repr(chr(x)))==3) and chr(x) or '.'
1190 for x in range(256)])
1191
1192def hex_dump_buffer(src, length=16):
1193 """
1194 Convert src to a hex dump string and return the string
1195 @param src The source buffer
1196 @param length The number of bytes shown in each line
1197 @returns A string showing the hex dump
1198 """
Dan Talaycoc516fa02012-04-12 22:28:43 -07001199 result = ["\n"]
Dan Talayco2baf8b52012-03-30 09:55:42 -07001200 for i in xrange(0, len(src), length):
1201 chars = src[i:i+length]
1202 hex = ' '.join(["%02x" % ord(x) for x in chars])
1203 printable = ''.join(["%s" % ((ord(x) <= 127 and
1204 FILTER[ord(x)]) or '.') for x in chars])
1205 result.append("%04x %-*s %s\n" % (i, length*3, hex, printable))
1206 return ''.join(result)
1207
1208def format_packet(pkt):
1209 return "Packet length %d \n%s" % (len(str(pkt)),
1210 hex_dump_buffer(str(pkt)))
Rich Lane5d7e89a2012-10-26 16:43:13 -07001211
1212def inspect_packet(pkt):
1213 """
1214 Wrapper around scapy's show() method.
1215 @returns A string showing the dissected packet.
1216 """
1217 from cStringIO import StringIO
1218 out = None
1219 backup = sys.stdout
1220 try:
1221 sys.stdout = StringIO()
1222 pkt.show2()
1223 out = sys.stdout.getvalue()
1224 sys.stdout.close()
1225 finally:
1226 sys.stdout = backup
1227 return out
Rich Lane0a4f6372013-01-02 14:40:22 -08001228
1229def nonstandard(cls):
1230 """
Rich Lanecc45b8e2013-01-02 15:55:02 -08001231 Testcase decorator that marks the test as being non-standard.
1232 These tests are not automatically added to the "standard" group.
Rich Lane0a4f6372013-01-02 14:40:22 -08001233 """
Rich Lanecc45b8e2013-01-02 15:55:02 -08001234 cls._nonstandard = True
Rich Lane0a4f6372013-01-02 14:40:22 -08001235 return cls
1236
1237def disabled(cls):
1238 """
Rich Lanecc45b8e2013-01-02 15:55:02 -08001239 Testcase decorator that marks the test as being disabled.
1240 These tests are not automatically added to the "standard" group or
1241 their module's group.
Rich Lane0a4f6372013-01-02 14:40:22 -08001242 """
Rich Lanecc45b8e2013-01-02 15:55:02 -08001243 cls._disabled = True
Rich Lane0a4f6372013-01-02 14:40:22 -08001244 return cls
Rich Lane97e99652013-01-02 17:23:20 -08001245
1246def group(name):
1247 """
1248 Testcase decorator that adds the test to a group.
1249 """
1250 def fn(cls):
1251 if not hasattr(cls, "_groups"):
1252 cls._groups = []
1253 cls._groups.append(name)
1254 return cls
1255 return fn
Rich Lane5a9a1922013-01-11 14:29:30 -08001256
1257def version(ver):
1258 """
1259 Testcase decorator that specifies which versions of OpenFlow the test
1260 supports. The default is 1.0+. This decorator may only be used once.
1261
1262 Supported syntax:
1263 1.0 -> 1.0
1264 1.0,1.2,1.3 -> 1.0, 1.2, 1.3
1265 1.0+ -> 1.0, 1.1, 1.2, 1.3
1266 """
1267 versions = parse_version(ver)
1268 def fn(cls):
1269 cls._versions = versions
1270 return cls
1271 return fn
1272
1273def parse_version(ver):
1274 allowed_versions = ["1.0", "1.1", "1.2", "1.3"]
1275 if re.match("^1\.\d+$", ver):
1276 versions = set([ver])
1277 elif re.match("^(1\.\d+)\+$", ver):
1278 if not ver[:-1] in allowed_versions:
1279 raise ValueError("invalid OpenFlow version %s" % ver[:-1])
1280 versions = set()
1281 if ver != "1.1+": versions.add("1.0")
1282 if ver != "1.2+": versions.add("1.1")
1283 if ver != "1.3+": versions.add("1.2")
1284 versions.add("1.3")
1285 else:
1286 versions = set(ver.split(','))
1287
1288 for version in versions:
1289 if not version in allowed_versions:
1290 raise ValueError("invalid OpenFlow version %s" % version)
1291
1292 return versions
1293
1294assert(parse_version("1.0") == set(["1.0"]))
1295assert(parse_version("1.0,1.2,1.3") == set(["1.0", "1.2", "1.3"]))
1296assert(parse_version("1.0+") == set(["1.0", "1.1", "1.2", "1.3"]))
Rich Lane7744e112013-01-11 17:23:57 -08001297
Rich Laneae3428c2013-03-07 14:37:42 -08001298def get_stats(test, req):
1299 """
1300 Retrieve a list of stats entries. Handles OFPSF_REPLY_MORE.
1301 """
Rich Lanebd56ed62013-07-10 15:49:44 -07001302 if ofp.OFP_VERSION <= 3:
1303 more_flag = ofp.OFPSF_REPLY_MORE
1304 else:
1305 more_flag = ofp.OFPMPF_REPLY_MORE
Rich Laneae3428c2013-03-07 14:37:42 -08001306 stats = []
1307 reply, _ = test.controller.transact(req)
1308 test.assertTrue(reply is not None, "No response to stats request")
Rich Lane5fd6faf2013-03-11 13:30:20 -07001309 stats.extend(reply.entries)
Rich Lanebd56ed62013-07-10 15:49:44 -07001310 while reply.flags & more_flag != 0:
Rich Lanee717c6e2013-03-12 10:25:50 -07001311 reply, pkt = self.controller.poll(exp_msg=ofp.OFPT_STATS_REPLY)
Rich Laneae3428c2013-03-07 14:37:42 -08001312 test.assertTrue(reply is not None, "No response to stats request")
Rich Lane5fd6faf2013-03-11 13:30:20 -07001313 stats.extend(reply.entries)
Rich Laneae3428c2013-03-07 14:37:42 -08001314 return stats
1315
Rich Lanebd56ed62013-07-10 15:49:44 -07001316def get_flow_stats(test, match, table_id=None,
1317 out_port=None, out_group=None,
1318 cookie=0, cookie_mask=0):
Rich Laneae3428c2013-03-07 14:37:42 -08001319 """
1320 Retrieve a list of flow stats entries.
1321 """
Rich Lanebd56ed62013-07-10 15:49:44 -07001322
1323 if table_id == None:
1324 if ofp.OFP_VERSION <= 2:
1325 table_id = 0xff
1326 else:
1327 table_id = ofp.OFPTT_ALL
1328
Rich Lanef3bc48c2013-05-03 17:39:35 -07001329 if out_port == None:
Rich Lanebd56ed62013-07-10 15:49:44 -07001330 if ofp.OFP_VERSION == 1:
1331 out_port = ofp.OFPP_NONE
1332 else:
1333 out_port = ofp.OFPP_ANY
1334
1335 if out_group == None:
1336 if ofp.OFP_VERSION > 1:
1337 out_group = ofp.OFPP_ANY
1338
Rich Lanee717c6e2013-03-12 10:25:50 -07001339 req = ofp.message.flow_stats_request(match=match,
Rich Lanebd56ed62013-07-10 15:49:44 -07001340 table_id=table_id,
1341 out_port=out_port)
1342 if ofp.OFP_VERSION > 1:
1343 req.out_group = out_group
1344 req.cookie = cookie
1345 req.cookie_mask = cookie_mask
1346
Rich Laneae3428c2013-03-07 14:37:42 -08001347 return get_stats(test, req)
1348
Rich Lane968b6192013-03-07 15:34:43 -08001349def get_port_stats(test, port_no):
1350 """
1351 Retrieve a list of port stats entries.
1352 """
Rich Lanee717c6e2013-03-12 10:25:50 -07001353 req = ofp.message.port_stats_request(port_no=port_no)
Rich Lane968b6192013-03-07 15:34:43 -08001354 return get_stats(test, req)
1355
Rich Lane6a334922013-03-07 16:14:52 -08001356def get_queue_stats(test, port_no, queue_id):
1357 """
1358 Retrieve a list of queue stats entries.
1359 """
Rich Lanee717c6e2013-03-12 10:25:50 -07001360 req = ofp.message.queue_stats_request(port_no=port_no, queue_id=queue_id)
Rich Lane6a334922013-03-07 16:14:52 -08001361 return get_stats(test, req)
1362
Rich Laneae3428c2013-03-07 14:37:42 -08001363def verify_flow_stats(test, match, table_id=0xff,
Rich Lanef3bc48c2013-05-03 17:39:35 -07001364 out_port=None,
Rich Laneae3428c2013-03-07 14:37:42 -08001365 initial=[],
1366 pkts=None, bytes=None):
1367 """
1368 Verify that flow stats changed as expected.
1369
1370 Optionally takes an 'initial' list of stats entries, as returned by
1371 get_flow_stats(). If 'initial' is not given the counters are assumed to
1372 begin at 0.
1373 """
Rich Lanef3bc48c2013-05-03 17:39:35 -07001374 if out_port == None:
1375 out_port = ofp.OFPP_NONE
1376
Rich Laneae3428c2013-03-07 14:37:42 -08001377 def accumulate(stats):
1378 pkts_acc = bytes_acc = 0
1379 for stat in stats:
1380 pkts_acc += stat.packet_count
1381 bytes_acc += stat.byte_count
1382 return (pkts_acc, bytes_acc)
1383
1384 pkts_before, bytes_before = accumulate(initial)
1385
1386 # Wait 10s for counters to update
1387 pkt_diff = byte_diff = None
1388 for i in range(0, 100):
1389 stats = get_flow_stats(test, match, table_id=table_id, out_port=out_port)
1390 pkts_after, bytes_after = accumulate(stats)
1391 pkt_diff = pkts_after - pkts_before
1392 byte_diff = bytes_after - bytes_before
1393 if (pkts == None or pkt_diff >= pkts) and \
1394 (bytes == None or byte_diff >= bytes):
1395 break
Dan Talayco53724732013-03-08 23:54:02 -08001396 time.sleep(0.1)
Rich Laneae3428c2013-03-07 14:37:42 -08001397
1398 if pkts != None:
1399 test.assertEquals(pkt_diff, pkts, "Flow packet counter not updated properly (expected increase of %d, got increase of %d)" % (pkts, pkt_diff))
1400
1401 if bytes != None:
Rich Lane53b96812013-03-07 16:54:50 -08001402 test.assertTrue(byte_diff >= bytes and byte_diff <= bytes*1.1,
1403 "Flow byte counter not updated properly (expected increase of %d, got increase of %d)" % (bytes, byte_diff))
Rich Laneae3428c2013-03-07 14:37:42 -08001404
Rich Lane968b6192013-03-07 15:34:43 -08001405def verify_port_stats(test, port,
1406 initial=[],
1407 tx_pkts=None, rx_pkts=None,
1408 tx_bytes=None, rx_bytes=None):
1409 """
1410 Verify that port stats changed as expected.
1411
1412 Optionally takes an 'initial' list of stats entries, as returned by
1413 get_port_stats(). If 'initial' is not given the counters are assumed to
1414 begin at 0.
1415 """
1416 def accumulate(stats):
1417 tx_pkts_acc = rx_pkts_acc = tx_bytes_acc = rx_bytes_acc = 0
1418 for stat in stats:
1419 tx_pkts_acc += stat.tx_packets
1420 rx_pkts_acc += stat.rx_packets
1421 tx_bytes_acc += stat.tx_bytes
1422 rx_bytes_acc += stat.rx_bytes
1423 return (tx_pkts_acc, rx_pkts_acc, tx_bytes_acc, rx_bytes_acc)
1424
1425 tx_pkts_before, rx_pkts_before, \
1426 tx_bytes_before, rx_bytes_before = accumulate(initial)
1427
1428 # Wait 10s for counters to update
1429 for i in range(0, 100):
1430 stats = get_port_stats(test, port)
1431 tx_pkts_after, rx_pkts_after, \
1432 tx_bytes_after, rx_bytes_after = accumulate(stats)
1433 tx_pkts_diff = tx_pkts_after - tx_pkts_before
1434 rx_pkts_diff = rx_pkts_after - rx_pkts_before
1435 tx_bytes_diff = tx_bytes_after - tx_bytes_before
1436 rx_bytes_diff = rx_bytes_after - rx_bytes_before
1437 if (tx_pkts == None or tx_pkts == tx_pkts_diff) and \
1438 (rx_pkts == None or rx_pkts == rx_pkts_diff) and \
Rich Lane53b96812013-03-07 16:54:50 -08001439 (tx_bytes == None or tx_bytes <= tx_bytes_diff) and \
1440 (rx_bytes == None or rx_bytes <= rx_bytes_diff):
Rich Lane968b6192013-03-07 15:34:43 -08001441 break
1442 time.sleep(0.1)
1443
1444 if (tx_pkts != None):
1445 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))
1446 if (rx_pkts != None):
1447 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))
1448 if (tx_bytes != None):
Rich Lane53b96812013-03-07 16:54:50 -08001449 test.assertTrue(tx_bytes_diff >= tx_bytes and tx_bytes_diff <= tx_bytes*1.1,
1450 "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 -08001451 if (rx_bytes != None):
Rich Lane53b96812013-03-07 16:54:50 -08001452 test.assertTrue(rx_bytes_diff >= rx_bytes and rx_bytes_diff <= rx_bytes*1.1,
1453 "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 -08001454
Rich Lane6a334922013-03-07 16:14:52 -08001455def verify_queue_stats(test, port_no, queue_id,
1456 initial=[],
1457 pkts=None, bytes=None):
1458 """
1459 Verify that queue stats changed as expected.
1460
1461 Optionally takes an 'initial' list of stats entries, as returned by
1462 get_queue_stats(). If 'initial' is not given the counters are assumed to
1463 begin at 0.
1464 """
1465 def accumulate(stats):
1466 pkts_acc = bytes_acc = 0
1467 for stat in stats:
1468 pkts_acc += stat.tx_packets
1469 bytes_acc += stat.tx_bytes
1470 return (pkts_acc, bytes_acc)
1471
1472 pkts_before, bytes_before = accumulate(initial)
1473
1474 # Wait 10s for counters to update
1475 pkt_diff = byte_diff = None
1476 for i in range(0, 100):
1477 stats = get_queue_stats(test, port_no, queue_id)
1478 pkts_after, bytes_after = accumulate(stats)
1479 pkt_diff = pkts_after - pkts_before
1480 byte_diff = bytes_after - bytes_before
1481 if (pkts == None or pkt_diff >= pkts) and \
1482 (bytes == None or byte_diff >= bytes):
1483 break
Dan Talayco53724732013-03-08 23:54:02 -08001484 time.sleep(0.1)
Rich Lane6a334922013-03-07 16:14:52 -08001485
1486 if pkts != None:
1487 test.assertEquals(pkt_diff, pkts, "Queue packet counter not updated properly (expected increase of %d, got increase of %d)" % (pkts, pkt_diff))
1488
1489 if bytes != None:
Rich Lane53b96812013-03-07 16:54:50 -08001490 test.assertTrue(byte_diff >= bytes and byte_diff <= bytes*1.1,
1491 "Queue byte counter not updated properly (expected increase of %d, got increase of %d)" % (bytes, byte_diff))
Rich Laneae3428c2013-03-07 14:37:42 -08001492
Rich Lane4c504f32013-06-07 17:24:14 -07001493def packet_in_match(msg, data, in_port=None, reason=None):
1494 """
1495 Check whether the packet_in message 'msg' has fields matching 'data',
1496 'in_port', and 'reason'.
1497
1498 This function handles truncated packet_in data. The 'in_port' and 'reason'
1499 parameters are optional.
1500
1501 @param msg packet_in message
1502 @param data Expected packet_in data
1503 @param in_port Expected packet_in in_port, or None
1504 @param reason Expected packet_in reason, or None
1505 """
1506
Rich Lanec0d26dd2013-07-10 12:46:03 -07001507 if ofp.OFP_VERSION <= 2:
1508 pkt_in_port = msg.in_port
1509 else:
1510 oxms = { type(oxm): oxm for oxm in msg.match.oxm_list }
1511 if ofp.oxm.in_port in oxms:
1512 pkt_in_port = oxms[ofp.oxm.in_port].value
1513 else:
1514 logging.warn("Missing in_port in packet-in message")
1515 pkt_in_port = None
1516
1517 if in_port != None and in_port != pkt_in_port:
Rich Lane4c504f32013-06-07 17:24:14 -07001518 logging.debug("Incorrect packet_in in_port (expected %d, received %d)", in_port, msg.in_port)
1519 return False
1520
Rich Lanec0d26dd2013-07-10 12:46:03 -07001521 if reason != None and reason != msg.reason:
Rich Lane4c504f32013-06-07 17:24:14 -07001522 logging.debug("Incorrect packet_in reason (expected %d, received %d)", reason, msg.reason)
1523 return False
1524
1525 # Check that one of the packets is a prefix of the other.
1526 # The received packet may be either truncated or padded, but not both.
1527 # (Some of the padding may be truncated but that's irrelevant). We
1528 # need to check that the smaller packet is a prefix of the larger one.
1529 # Note that this check succeeds if the switch sends a zero-length
1530 # packet-in.
1531 compare_len = min(len(msg.data), len(data))
1532 if data[:compare_len] != msg.data[:compare_len]:
1533 logging.debug("Incorrect packet_in data")
1534 logging.debug("Expected %s" % format_packet(data[:compare_len]))
1535 logging.debug("Received %s" % format_packet(msg.data[:compare_len]))
1536 return False
1537
1538 return True
1539
1540def verify_packet_in(test, data, in_port, reason, controller=None):
1541 """
1542 Assert that the controller receives a packet_in message matching data 'data'
1543 from port 'in_port' with reason 'reason'. Does not trigger the packet_in
1544 itself, that's up to the test case.
1545
1546 @param test Instance of base_tests.SimpleProtocol
1547 @param pkt String to expect as the packet_in data
1548 @param in_port OpenFlow port number to expect as the packet_in in_port
1549 @param reason One of OFPR_* to expect as the packet_in reason
1550 @param controller Controller instance, defaults to test.controller
1551 @returns The received packet-in message
1552 """
1553
1554 if controller == None:
1555 controller = test.controller
1556
1557 end_time = time.time() + oftest.ofutils.default_timeout
1558
1559 while True:
1560 msg, _ = controller.poll(ofp.OFPT_PACKET_IN, end_time - time.time())
1561 if not msg:
1562 # Timeout
1563 break
1564 elif packet_in_match(msg, data, in_port, reason):
1565 # Found a matching message
1566 break
1567
1568 test.assertTrue(msg is not None, 'Packet in message not received on port %d' % in_port)
1569 return msg
1570
1571def verify_no_packet_in(test, data, in_port, controller=None):
1572 """
1573 Assert that the controller does not receive a packet_in message matching
1574 data 'data' from port 'in_port'.
1575
1576 @param test Instance of base_tests.SimpleProtocol
1577 @param pkt String to expect as the packet_in data
1578 @param in_port OpenFlow port number to expect as the packet_in in_port
1579 @param controller Controller instance, defaults to test.controller
1580 """
1581
1582 if controller == None:
1583 controller = test.controller
1584
1585 # Negative test, need to wait a short amount of time before checking we
1586 # didn't receive the message.
1587 time.sleep(0.5)
1588
1589 # Check every packet_in queued in the controller
1590 while True:
1591 msg, _ = controller.poll(ofp.OFPT_PACKET_IN, timeout=0)
1592 if msg == None:
1593 # No more queued packet_in messages
1594 break
1595 elif packet_in_match(msg, data, in_port, None):
1596 # Found a matching message
1597 break
1598
1599 test.assertTrue(msg == None, "Did not expect a packet-in message on port %d" % in_port)
1600
Rich Lane045db072013-08-06 13:16:30 -07001601def openflow_ports(num=None):
1602 """
1603 Return a list of 'num' OpenFlow port numbers
1604
1605 If 'num' is None, return all available ports. Otherwise, limit the length
1606 of the result to 'num' and raise an exception if not enough ports are
1607 available.
1608 """
1609 ports = sorted(oftest.config["port_map"].keys())
1610 if num != None and len(ports) < num:
1611 raise Exception("test requires %d ports but only %d are available" % (num, len(ports)))
1612 return ports[:num]
1613
Rich Lane7744e112013-01-11 17:23:57 -08001614__all__ = list(set(locals()) - _import_blacklist)