blob: cc8308a00a39f4c52ccfa1076f31fb0ac41b6c2f [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
Rich Lane5f3c9b22013-10-10 17:20:30 -070049def delete_all_groups(ctrl):
50 """
51 Delete all groups on the switch
52 @param ctrl The controller object for the test
53 """
54
55 logging.info("Deleting all groups")
56 msg = ofp.message.group_mod(
57 command=ofp.OFPGC_DELETE, group_id=ofp.OFPG_ALL)
58 ctrl.message_send(msg)
59 do_barrier(ctrl)
60
Ed Swierk99a74de2012-08-22 06:40:54 -070061def required_wildcards(parent):
Rich Lane2014f9b2012-10-05 15:29:40 -070062 w = test_param_get('required_wildcards', default='default')
Ed Swierk99a74de2012-08-22 06:40:54 -070063 if w == 'l3-l4':
Rich Lanee717c6e2013-03-12 10:25:50 -070064 return (ofp.OFPFW_NW_SRC_ALL | ofp.OFPFW_NW_DST_ALL | ofp.OFPFW_NW_TOS
65 | ofp.OFPFW_NW_PROTO | ofp.OFPFW_TP_SRC | ofp.OFPFW_TP_DST)
Ed Swierk99a74de2012-08-22 06:40:54 -070066 else:
67 return 0
68
Dan Talayco41eae8b2010-03-10 13:57:06 -080069def simple_tcp_packet(pktlen=100,
Rich Laned0478ff2013-03-11 12:46:58 -070070 eth_dst='00:01:02:03:04:05',
71 eth_src='00:06:07:08:09:0a',
Tatsuya Yabe460321e2010-05-25 17:50:49 -070072 dl_vlan_enable=False,
Rich Laned0478ff2013-03-11 12:46:58 -070073 vlan_vid=0,
74 vlan_pcp=0,
Dan Talayco551befa2010-07-15 17:05:32 -070075 dl_vlan_cfi=0,
Dan Talayco41eae8b2010-03-10 13:57:06 -080076 ip_src='192.168.0.1',
77 ip_dst='192.168.0.2',
Tatsuya Yabe460321e2010-05-25 17:50:49 -070078 ip_tos=0,
Gregor Maier9cc93342013-01-29 16:55:28 -080079 ip_ttl=64,
Dan Talayco41eae8b2010-03-10 13:57:06 -080080 tcp_sport=1234,
Christian Dickmann8b59b4b2012-09-23 16:48:30 -070081 tcp_dport=80,
82 ip_ihl=None,
83 ip_options=False
Dan Talayco41eae8b2010-03-10 13:57:06 -080084 ):
85 """
86 Return a simple dataplane TCP packet
87
88 Supports a few parameters:
89 @param len Length of packet in bytes w/o CRC
Rich Laned0478ff2013-03-11 12:46:58 -070090 @param eth_dst Destinatino MAC
91 @param eth_src Source MAC
Tatsuya Yabe460321e2010-05-25 17:50:49 -070092 @param dl_vlan_enable True if the packet is with vlan, False otherwise
Rich Laned0478ff2013-03-11 12:46:58 -070093 @param vlan_vid VLAN ID
94 @param vlan_pcp VLAN priority
Dan Talayco41eae8b2010-03-10 13:57:06 -080095 @param ip_src IP source
96 @param ip_dst IP destination
Tatsuya Yabe460321e2010-05-25 17:50:49 -070097 @param ip_tos IP ToS
Gregor Maier9cc93342013-01-29 16:55:28 -080098 @param ip_ttl IP TTL
Dan Talayco41eae8b2010-03-10 13:57:06 -080099 @param tcp_dport TCP destination port
100 @param ip_sport TCP source port
101
102 Generates a simple TCP request. Users
103 shouldn't assume anything about this packet other than that
104 it is a valid ethernet/IP/TCP frame.
105 """
Jeffrey Townsend5cb7ed32012-08-17 18:11:01 +0000106
107 if MINSIZE > pktlen:
108 pktlen = MINSIZE
109
Dan Talayco551befa2010-07-15 17:05:32 -0700110 # Note Dot1Q.id is really CFI
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800111 if (dl_vlan_enable):
Rich Laned0478ff2013-03-11 12:46:58 -0700112 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
113 scapy.Dot1Q(prio=vlan_pcp, id=dl_vlan_cfi, vlan=vlan_vid)/ \
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)/ \
Tatsuya Yabe460321e2010-05-25 17:50:49 -0700115 scapy.TCP(sport=tcp_sport, dport=tcp_dport)
116 else:
Christian Dickmann8b59b4b2012-09-23 16:48:30 -0700117 if not ip_options:
Rich Laned0478ff2013-03-11 12:46:58 -0700118 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
Gregor Maier9cc93342013-01-29 16:55:28 -0800119 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ttl=ip_ttl, ihl=ip_ihl)/ \
Christian Dickmann8b59b4b2012-09-23 16:48:30 -0700120 scapy.TCP(sport=tcp_sport, dport=tcp_dport)
121 else:
Rich Laned0478ff2013-03-11 12:46:58 -0700122 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
Gregor Maier9cc93342013-01-29 16:55:28 -0800123 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 -0700124 scapy.TCP(sport=tcp_sport, dport=tcp_dport)
Tatsuya Yabe460321e2010-05-25 17:50:49 -0700125
Dan Talayco41eae8b2010-03-10 13:57:06 -0800126 pkt = pkt/("D" * (pktlen - len(pkt)))
127
128 return pkt
129
Rich Lane86aceb02013-07-17 18:45:38 -0700130def simple_tcpv6_packet(pktlen=100,
131 eth_dst='00:01:02:03:04:05',
132 eth_src='00:06:07:08:09:0a',
133 dl_vlan_enable=False,
134 vlan_vid=0,
135 vlan_pcp=0,
136 ipv6_src='2001:db8:85a3::8a2e:370:7334',
137 ipv6_dst='2001:db8:85a3::8a2e:370:7335',
138 ipv6_tc=0,
139 ipv6_hlim=64,
140 ipv6_fl=0,
141 tcp_sport=1234,
142 tcp_dport=80):
143 """
144 Return a simple IPv6/TCP packet
145
146 Supports a few parameters:
147 @param len Length of packet in bytes w/o CRC
148 @param eth_dst Destination MAC
149 @param eth_src Source MAC
150 @param dl_vlan_enable True if the packet is with vlan, False otherwise
151 @param vlan_vid VLAN ID
152 @param vlan_pcp VLAN priority
153 @param ipv6_src IPv6 source
154 @param ipv6_dst IPv6 destination
155 @param ipv6_tc IPv6 traffic class
156 @param ipv6_ttl IPv6 hop limit
157 @param ipv6_fl IPv6 flow label
158 @param tcp_dport TCP destination port
159 @param tcp_sport TCP source port
160
161 Generates a simple TCP request. Users shouldn't assume anything about this
162 packet other than that it is a valid ethernet/IPv6/TCP frame.
163 """
164
165 if MINSIZE > pktlen:
166 pktlen = MINSIZE
167
168 pkt = scapy.Ether(dst=eth_dst, src=eth_src)
169 if dl_vlan_enable or vlan_vid or vlan_pcp:
170 pkt /= scapy.Dot1Q(vlan=vlan_vid, prio=vlan_pcp)
171 pkt /= scapy.IPv6(src=ipv6_src, dst=ipv6_dst, fl=ipv6_fl, tc=ipv6_tc, hlim=ipv6_hlim)
172 pkt /= scapy.TCP(sport=tcp_sport, dport=tcp_dport)
173 pkt /= ("D" * (pktlen - len(pkt)))
174
175 return pkt
176
Rich Lane6ee7bea2012-10-26 16:19:29 -0700177def simple_udp_packet(pktlen=100,
Rich Laned0478ff2013-03-11 12:46:58 -0700178 eth_dst='00:01:02:03:04:05',
179 eth_src='00:06:07:08:09:0a',
Rich Lane6ee7bea2012-10-26 16:19:29 -0700180 dl_vlan_enable=False,
Rich Laned0478ff2013-03-11 12:46:58 -0700181 vlan_vid=0,
182 vlan_pcp=0,
Rich Lane6ee7bea2012-10-26 16:19:29 -0700183 dl_vlan_cfi=0,
184 ip_src='192.168.0.1',
185 ip_dst='192.168.0.2',
186 ip_tos=0,
Gregor Maier9cc93342013-01-29 16:55:28 -0800187 ip_ttl=64,
Rich Lane6ee7bea2012-10-26 16:19:29 -0700188 udp_sport=1234,
189 udp_dport=80,
190 ip_ihl=None,
191 ip_options=False
192 ):
193 """
194 Return a simple dataplane UDP packet
195
196 Supports a few parameters:
197 @param len Length of packet in bytes w/o CRC
Rich Laned0478ff2013-03-11 12:46:58 -0700198 @param eth_dst Destination MAC
199 @param eth_src Source MAC
Rich Lane6ee7bea2012-10-26 16:19:29 -0700200 @param dl_vlan_enable True if the packet is with vlan, False otherwise
Rich Laned0478ff2013-03-11 12:46:58 -0700201 @param vlan_vid VLAN ID
202 @param vlan_pcp VLAN priority
Rich Lane6ee7bea2012-10-26 16:19:29 -0700203 @param ip_src IP source
204 @param ip_dst IP destination
205 @param ip_tos IP ToS
Gregor Maier9cc93342013-01-29 16:55:28 -0800206 @param ip_ttl IP TTL
Rich Lane6ee7bea2012-10-26 16:19:29 -0700207 @param udp_dport UDP destination port
208 @param udp_sport UDP source port
209
210 Generates a simple UDP packet. Users shouldn't assume anything about
211 this packet other than that it is a valid ethernet/IP/UDP frame.
212 """
213
214 if MINSIZE > pktlen:
215 pktlen = MINSIZE
216
217 # Note Dot1Q.id is really CFI
218 if (dl_vlan_enable):
Rich Laned0478ff2013-03-11 12:46:58 -0700219 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
220 scapy.Dot1Q(prio=vlan_pcp, id=dl_vlan_cfi, vlan=vlan_vid)/ \
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:
224 if not ip_options:
Rich Laned0478ff2013-03-11 12:46:58 -0700225 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
Gregor Maier9cc93342013-01-29 16:55:28 -0800226 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ttl=ip_ttl, ihl=ip_ihl)/ \
Rich Lane6ee7bea2012-10-26 16:19:29 -0700227 scapy.UDP(sport=udp_sport, dport=udp_dport)
228 else:
Rich Laned0478ff2013-03-11 12:46:58 -0700229 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
Gregor Maier9cc93342013-01-29 16:55:28 -0800230 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 -0700231 scapy.UDP(sport=udp_sport, dport=udp_dport)
232
233 pkt = pkt/("D" * (pktlen - len(pkt)))
234
235 return pkt
236
Rich Lane86aceb02013-07-17 18:45:38 -0700237def simple_udpv6_packet(pktlen=100,
238 eth_dst='00:01:02:03:04:05',
239 eth_src='00:06:07:08:09:0a',
240 dl_vlan_enable=False,
241 vlan_vid=0,
242 vlan_pcp=0,
243 ipv6_src='2001:db8:85a3::8a2e:370:7334',
244 ipv6_dst='2001:db8:85a3::8a2e:370:7335',
245 ipv6_tc=0,
246 ipv6_hlim=64,
247 ipv6_fl=0,
248 udp_sport=1234,
249 udp_dport=80):
250 """
251 Return a simple IPv6/UDP packet
252
253 Supports a few parameters:
254 @param len Length of packet in bytes w/o CRC
255 @param eth_dst Destination MAC
256 @param eth_src Source MAC
257 @param dl_vlan_enable True if the packet is with vlan, False otherwise
258 @param vlan_vid VLAN ID
259 @param vlan_pcp VLAN priority
260 @param ipv6_src IPv6 source
261 @param ipv6_dst IPv6 destination
262 @param ipv6_tc IPv6 traffic class
263 @param ipv6_ttl IPv6 hop limit
264 @param ipv6_fl IPv6 flow label
265 @param udp_dport UDP destination port
266 @param udp_sport UDP source port
267
268 Generates a simple UDP request. Users shouldn't assume anything about this
269 packet other than that it is a valid ethernet/IPv6/UDP frame.
270 """
271
272 if MINSIZE > pktlen:
273 pktlen = MINSIZE
274
275 pkt = scapy.Ether(dst=eth_dst, src=eth_src)
276 if dl_vlan_enable or vlan_vid or vlan_pcp:
277 pkt /= scapy.Dot1Q(vlan=vlan_vid, prio=vlan_pcp)
278 pkt /= scapy.IPv6(src=ipv6_src, dst=ipv6_dst, fl=ipv6_fl, tc=ipv6_tc, hlim=ipv6_hlim)
279 pkt /= scapy.UDP(sport=udp_sport, dport=udp_dport)
280 pkt /= ("D" * (pktlen - len(pkt)))
281
282 return pkt
283
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700284def simple_icmp_packet(pktlen=60,
Rich Laned0478ff2013-03-11 12:46:58 -0700285 eth_dst='00:01:02:03:04:05',
286 eth_src='00:06:07:08:09:0a',
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700287 dl_vlan_enable=False,
Rich Laned0478ff2013-03-11 12:46:58 -0700288 vlan_vid=0,
289 vlan_pcp=0,
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700290 ip_src='192.168.0.1',
291 ip_dst='192.168.0.2',
292 ip_tos=0,
Gregor Maier9cc93342013-01-29 16:55:28 -0800293 ip_ttl=64,
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700294 icmp_type=8,
295 icmp_code=0
296 ):
297 """
298 Return a simple ICMP packet
299
300 Supports a few parameters:
301 @param len Length of packet in bytes w/o CRC
Rich Laned0478ff2013-03-11 12:46:58 -0700302 @param eth_dst Destinatino MAC
303 @param eth_src Source MAC
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700304 @param dl_vlan_enable True if the packet is with vlan, False otherwise
Rich Laned0478ff2013-03-11 12:46:58 -0700305 @param vlan_vid VLAN ID
306 @param vlan_pcp VLAN priority
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700307 @param ip_src IP source
308 @param ip_dst IP destination
309 @param ip_tos IP ToS
Gregor Maier9cc93342013-01-29 16:55:28 -0800310 @param ip_ttl IP TTL
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700311 @param icmp_type ICMP type
312 @param icmp_code ICMP code
313
314 Generates a simple ICMP ECHO REQUEST. Users
315 shouldn't assume anything about this packet other than that
316 it is a valid ethernet/ICMP frame.
317 """
Jeffrey Townsend5cb7ed32012-08-17 18:11:01 +0000318
319 if MINSIZE > pktlen:
320 pktlen = MINSIZE
321
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700322 if (dl_vlan_enable):
Rich Laned0478ff2013-03-11 12:46:58 -0700323 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
324 scapy.Dot1Q(prio=vlan_pcp, id=0, vlan=vlan_vid)/ \
Gregor Maier9cc93342013-01-29 16:55:28 -0800325 scapy.IP(src=ip_src, dst=ip_dst, ttl=ip_ttl, tos=ip_tos)/ \
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700326 scapy.ICMP(type=icmp_type, code=icmp_code)
327 else:
Rich Laned0478ff2013-03-11 12:46:58 -0700328 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
Gregor Maier9cc93342013-01-29 16:55:28 -0800329 scapy.IP(src=ip_src, dst=ip_dst, ttl=ip_ttl, tos=ip_tos)/ \
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700330 scapy.ICMP(type=icmp_type, code=icmp_code)
331
332 pkt = pkt/("0" * (pktlen - len(pkt)))
333
334 return pkt
335
Rich Lane86aceb02013-07-17 18:45:38 -0700336def simple_icmpv6_packet(pktlen=100,
337 eth_dst='00:01:02:03:04:05',
338 eth_src='00:06:07:08:09:0a',
339 dl_vlan_enable=False,
340 vlan_vid=0,
341 vlan_pcp=0,
342 ipv6_src='2001:db8:85a3::8a2e:370:7334',
343 ipv6_dst='2001:db8:85a3::8a2e:370:7335',
344 ipv6_tc=0,
345 ipv6_hlim=64,
346 ipv6_fl=0,
347 icmp_type=8,
348 icmp_code=0):
349 """
350 Return a simple ICMPv6 packet
351
352 Supports a few parameters:
353 @param len Length of packet in bytes w/o CRC
354 @param eth_dst Destination MAC
355 @param eth_src Source MAC
356 @param dl_vlan_enable True if the packet is with vlan, False otherwise
357 @param vlan_vid VLAN ID
358 @param vlan_pcp VLAN priority
359 @param ipv6_src IPv6 source
360 @param ipv6_dst IPv6 destination
361 @param ipv6_tc IPv6 traffic class
362 @param ipv6_ttl IPv6 hop limit
363 @param ipv6_fl IPv6 flow label
364 @param icmp_type ICMP type
365 @param icmp_code ICMP code
366
367 Generates a simple ICMP ECHO REQUEST. Users shouldn't assume anything
368 about this packet other than that it is a valid ethernet/IPv6/ICMP frame.
369 """
370
371 if MINSIZE > pktlen:
372 pktlen = MINSIZE
373
374 pkt = scapy.Ether(dst=eth_dst, src=eth_src)
375 if dl_vlan_enable or vlan_vid or vlan_pcp:
376 pkt /= scapy.Dot1Q(vlan=vlan_vid, prio=vlan_pcp)
377 pkt /= scapy.IPv6(src=ipv6_src, dst=ipv6_dst, fl=ipv6_fl, tc=ipv6_tc, hlim=ipv6_hlim)
378 pkt /= scapy.ICMPv6Unknown(type=icmp_type, code=icmp_code)
379 pkt /= ("D" * (pktlen - len(pkt)))
380
381 return pkt
382
Shudong Zhouc7562b12013-02-06 01:12:18 -0800383def simple_arp_packet(pktlen=60,
Rich Laned0478ff2013-03-11 12:46:58 -0700384 eth_dst='ff:ff:ff:ff:ff:ff',
385 eth_src='00:06:07:08:09:0a',
Shudong Zhouc7562b12013-02-06 01:12:18 -0800386 arp_op=1,
387 ip_snd='192.168.0.1',
388 ip_tgt='192.168.0.2',
389 hw_snd='00:06:07:08:09:0a',
390 hw_tgt='00:00:00:00:00:00',
391 ):
392 """
393 Return a simple ARP packet
394
395 Supports a few parameters:
396 @param len Length of packet in bytes w/o CRC
Rich Laned0478ff2013-03-11 12:46:58 -0700397 @param eth_dst Destinatino MAC
398 @param eth_src Source MAC
Shudong Zhouc7562b12013-02-06 01:12:18 -0800399 @param arp_op Operation (1=request, 2=reply)
400 @param ip_snd Sender IP
401 @param ip_tgt Target IP
402 @param hw_snd Sender hardware address
403 @param hw_tgt Target hardware address
404
405 Generates a simple ARP REQUEST. Users
406 shouldn't assume anything about this packet other than that
407 it is a valid ethernet/ARP frame.
408 """
409
410 if MINSIZE > pktlen:
411 pktlen = MINSIZE
412
Rich Laned0478ff2013-03-11 12:46:58 -0700413 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
Shudong Zhouc7562b12013-02-06 01:12:18 -0800414 scapy.ARP(hwsrc=hw_snd, hwdst=hw_tgt, pdst=ip_tgt, psrc=ip_snd, op=arp_op)
415
416 pkt = pkt/("0" * (pktlen - len(pkt)))
417
418 return pkt
419
Ed Swierk0aeff8c2012-03-23 20:27:18 -0700420def simple_eth_packet(pktlen=60,
Rich Laneb7dc3e22013-08-02 13:51:06 -0700421 eth_dst='01:80:c2:00:00:00',
422 eth_src='00:01:02:03:04:05',
Rich Laned0478ff2013-03-11 12:46:58 -0700423 eth_type=0x88cc):
Jeffrey Townsend5cb7ed32012-08-17 18:11:01 +0000424
425 if MINSIZE > pktlen:
426 pktlen = MINSIZE
427
Rich Laned0478ff2013-03-11 12:46:58 -0700428 pkt = scapy.Ether(dst=eth_dst, src=eth_src, type=eth_type)
Ed Swierk0aeff8c2012-03-23 20:27:18 -0700429
430 pkt = pkt/("0" * (pktlen - len(pkt)))
431
432 return pkt
433
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800434def qinq_tcp_packet(pktlen=100,
Rich Laned0478ff2013-03-11 12:46:58 -0700435 eth_dst='00:01:02:03:04:05',
436 eth_src='00:06:07:08:09:0a',
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800437 dl_vlan_outer=20,
438 dl_vlan_pcp_outer=0,
439 dl_vlan_cfi_outer=0,
Rich Laned0478ff2013-03-11 12:46:58 -0700440 vlan_vid=10,
441 vlan_pcp=0,
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800442 dl_vlan_cfi=0,
443 ip_src='192.168.0.1',
444 ip_dst='192.168.0.2',
445 ip_tos=0,
Gregor Maier9cc93342013-01-29 16:55:28 -0800446 ip_ttl=64,
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800447 tcp_sport=1234,
448 tcp_dport=80,
449 ip_ihl=None,
450 ip_options=False
451 ):
452 """
453 Return a doubly tagged dataplane TCP packet
454
455 Supports a few parameters:
456 @param len Length of packet in bytes w/o CRC
Rich Laned0478ff2013-03-11 12:46:58 -0700457 @param eth_dst Destinatino MAC
458 @param eth_src Source MAC
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800459 @param dl_vlan_outer Outer VLAN ID
460 @param dl_vlan_pcp_outer Outer VLAN priority
461 @param dl_vlan_cfi_outer Outer VLAN cfi bit
Rich Laned0478ff2013-03-11 12:46:58 -0700462 @param vlan_vid Inner VLAN ID
463 @param vlan_pcp VLAN priority
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800464 @param dl_vlan_cfi VLAN cfi bit
465 @param ip_src IP source
466 @param ip_dst IP destination
467 @param ip_tos IP ToS
468 @param tcp_dport TCP destination port
469 @param ip_sport TCP source port
470
471 Generates a TCP request. Users
472 shouldn't assume anything about this packet other than that
473 it is a valid ethernet/IP/TCP frame.
474 """
475
476 if MINSIZE > pktlen:
477 pktlen = MINSIZE
478
479 # Note Dot1Q.id is really CFI
Rich Laned0478ff2013-03-11 12:46:58 -0700480 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800481 scapy.Dot1Q(prio=dl_vlan_pcp_outer, id=dl_vlan_cfi_outer, vlan=dl_vlan_outer)/ \
Rich Laned0478ff2013-03-11 12:46:58 -0700482 scapy.Dot1Q(prio=vlan_pcp, id=dl_vlan_cfi, vlan=vlan_vid)/ \
Gregor Maier9cc93342013-01-29 16:55:28 -0800483 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ttl=ip_ttl, ihl=ip_ihl)/ \
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800484 scapy.TCP(sport=tcp_sport, dport=tcp_dport)
485
486 pkt = pkt/("D" * (pktlen - len(pkt)))
487
488 return pkt
489
Shudong Zhoub7f12462012-11-20 13:01:12 -0800490def do_barrier(ctrl, timeout=-1):
Dan Talayco0fc08bd2012-04-09 16:56:18 -0700491 """
492 Do a barrier command
493 Return 0 on success, -1 on error
494 """
Rich Lanee717c6e2013-03-12 10:25:50 -0700495 b = ofp.message.barrier_request()
Shudong Zhoub7f12462012-11-20 13:01:12 -0800496 (resp, pkt) = ctrl.transact(b, timeout=timeout)
Rich Lane3a261d52013-01-03 17:45:08 -0800497 if resp is None:
498 raise AssertionError("barrier failed")
Dan Talaycof6b94832012-04-12 21:50:57 -0700499 # We'll trust the transaction processing in the controller that xid matched
Rich Lane3a261d52013-01-03 17:45:08 -0800500 return 0 # for backwards compatibility
Dan Talayco92c99122010-06-03 13:53:18 -0700501
Rich Lane9a003812012-10-04 17:17:59 -0700502def port_config_get(controller, port_no):
Dan Talayco92c99122010-06-03 13:53:18 -0700503 """
504 Get a port's configuration
505
506 Gets the switch feature configuration and grabs one port's
507 configuration
508
509 @returns (hwaddr, config, advert) The hwaddress, configuration and
510 advertised values
511 """
Rich Lane6dc865c2013-07-10 10:12:13 -0700512
513 if ofp.OFP_VERSION <= 3:
514 request = ofp.message.features_request()
515 reply, _ = controller.transact(request)
516 if reply is None:
517 logging.warn("Get feature request failed")
518 return None, None, None
519 logging.debug(reply.show())
520 ports = reply.ports
521 else:
522 request = ofp.message.port_desc_stats_request()
523 # TODO do multipart correctly
524 reply, _ = controller.transact(request)
525 if reply is None:
526 logging.warn("Port desc stats request failed")
527 return None, None, None
528 logging.debug(reply.show())
529 ports = reply.entries
530
531 for port in ports:
532 if port.port_no == port_no:
533 return (port.hw_addr, port.config, port.advertised)
Dan Talayco92c99122010-06-03 13:53:18 -0700534
Rich Lane9a003812012-10-04 17:17:59 -0700535 logging.warn("Did not find port number for port config")
Dan Talayco92c99122010-06-03 13:53:18 -0700536 return None, None, None
537
Rich Lane9a003812012-10-04 17:17:59 -0700538def port_config_set(controller, port_no, config, mask):
Dan Talayco92c99122010-06-03 13:53:18 -0700539 """
540 Set the port configuration according the given parameters
541
542 Gets the switch feature configuration and updates one port's
543 configuration value according to config and mask
544 """
Rich Lane9a003812012-10-04 17:17:59 -0700545 logging.info("Setting port " + str(port_no) + " to config " + str(config))
Rich Lane6dc865c2013-07-10 10:12:13 -0700546
547 hw_addr, _, _ = port_config_get(controller, port_no)
548
Rich Lanee717c6e2013-03-12 10:25:50 -0700549 mod = ofp.message.port_mod()
Dan Talayco92c99122010-06-03 13:53:18 -0700550 mod.port_no = port_no
Rich Lane6dc865c2013-07-10 10:12:13 -0700551 if hw_addr != None:
552 mod.hw_addr = hw_addr
Dan Talayco92c99122010-06-03 13:53:18 -0700553 mod.config = config
554 mod.mask = mask
Rich Lane6dc865c2013-07-10 10:12:13 -0700555 mod.advertise = 0 # No change
Rich Lane5c3151c2013-01-03 17:15:41 -0800556 controller.message_send(mod)
557 return 0
Dan Talayco92c99122010-06-03 13:53:18 -0700558
Rich Lane2014f9b2012-10-05 15:29:40 -0700559def receive_pkt_check(dp, pkt, yes_ports, no_ports, assert_if):
Dan Talayco92c99122010-06-03 13:53:18 -0700560 """
561 Check for proper receive packets across all ports
Ken Chiang1bf01602012-04-04 10:48:23 -0700562 @param dp The dataplane object
Dan Talayco92c99122010-06-03 13:53:18 -0700563 @param pkt Expected packet; may be None if yes_ports is empty
564 @param yes_ports Set or list of ports that should recieve packet
565 @param no_ports Set or list of ports that should not receive packet
566 @param assert_if Object that implements assertXXX
Rich Lanee4b384d2013-09-13 14:33:40 -0700567
568 DEPRECATED in favor in verify_packets
Dan Talayco92c99122010-06-03 13:53:18 -0700569 """
Rich Lane91765672012-12-06 16:33:04 -0800570
571 # Wait this long for packets that we don't expect to receive.
572 # 100ms is (rarely) too short for positive tests on slow
573 # switches but is definitely not too short for a negative test.
574 negative_timeout = 0.1
575
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700576 exp_pkt_arg = None
Rich Lanecd97d3d2013-01-07 18:50:06 -0800577 if oftest.config["relax"]:
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700578 exp_pkt_arg = pkt
579
Dan Talayco92c99122010-06-03 13:53:18 -0700580 for ofport in yes_ports:
Rich Lane9a003812012-10-04 17:17:59 -0700581 logging.debug("Checking for pkt on port " + str(ofport))
Ken Chiang1bf01602012-04-04 10:48:23 -0700582 (rcv_port, rcv_pkt, pkt_time) = dp.poll(
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700583 port_number=ofport, exp_pkt=exp_pkt_arg)
Dan Talayco92c99122010-06-03 13:53:18 -0700584 assert_if.assertTrue(rcv_pkt is not None,
585 "Did not receive pkt on " + str(ofport))
Rich Lanecd97d3d2013-01-07 18:50:06 -0800586 if not oftest.dataplane.match_exp_pkt(pkt, rcv_pkt):
Rich Lane3c266832013-01-29 18:29:15 -0800587 logging.debug("Expected %s" % format_packet(pkt))
588 logging.debug("Received %s" % format_packet(rcv_pkt))
Rich Lanecd97d3d2013-01-07 18:50:06 -0800589 assert_if.assertTrue(oftest.dataplane.match_exp_pkt(pkt, rcv_pkt),
Rich Lane3c266832013-01-29 18:29:15 -0800590 "Received packet does not match expected packet " +
Ken Chiang1bf01602012-04-04 10:48:23 -0700591 "on port " + str(ofport))
Dan Talayco73f84012012-10-02 09:23:18 -0700592 if len(no_ports) > 0:
Rich Lane91765672012-12-06 16:33:04 -0800593 time.sleep(negative_timeout)
Dan Talayco92c99122010-06-03 13:53:18 -0700594 for ofport in no_ports:
Rich Lane9a003812012-10-04 17:17:59 -0700595 logging.debug("Negative check for pkt on port " + str(ofport))
Ken Chiang1bf01602012-04-04 10:48:23 -0700596 (rcv_port, rcv_pkt, pkt_time) = dp.poll(
Rich Lane91765672012-12-06 16:33:04 -0800597 port_number=ofport, timeout=0, exp_pkt=exp_pkt_arg)
Dan Talayco92c99122010-06-03 13:53:18 -0700598 assert_if.assertTrue(rcv_pkt is None,
599 "Unexpected pkt on port " + str(ofport))
Dan Talayco551befa2010-07-15 17:05:32 -0700600
601
Dan Talaycoc948d0b2012-03-23 12:17:54 -0700602def receive_pkt_verify(parent, egr_ports, exp_pkt, ing_port):
Dan Talayco551befa2010-07-15 17:05:32 -0700603 """
604 Receive a packet and verify it matches an expected value
Dan Talaycof6e76c02012-03-23 10:56:12 -0700605 @param egr_port A single port or list of ports
Dan Talayco551befa2010-07-15 17:05:32 -0700606
607 parent must implement dataplane, assertTrue and assertEqual
Rich Lanee4b384d2013-09-13 14:33:40 -0700608
609 DEPRECATED in favor in verify_packets
Dan Talayco551befa2010-07-15 17:05:32 -0700610 """
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700611 exp_pkt_arg = None
Rich Lanecd97d3d2013-01-07 18:50:06 -0800612 if oftest.config["relax"]:
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700613 exp_pkt_arg = exp_pkt
614
Dan Talaycof6e76c02012-03-23 10:56:12 -0700615 if type(egr_ports) == type([]):
616 egr_port_list = egr_ports
617 else:
618 egr_port_list = [egr_ports]
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700619
Dan Talaycof6e76c02012-03-23 10:56:12 -0700620 # Expect a packet from each port on egr port list
621 for egr_port in egr_port_list:
Dan Talaycod8ae7582012-03-23 12:24:56 -0700622 check_port = egr_port
Rich Lanee717c6e2013-03-12 10:25:50 -0700623 if egr_port == ofp.OFPP_IN_PORT:
Dan Talaycod8ae7582012-03-23 12:24:56 -0700624 check_port = ing_port
Dan Talaycof6e76c02012-03-23 10:56:12 -0700625 (rcv_port, rcv_pkt, pkt_time) = parent.dataplane.poll(
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700626 port_number=check_port, exp_pkt=exp_pkt_arg)
Dan Talayco551befa2010-07-15 17:05:32 -0700627
Dan Talaycof6e76c02012-03-23 10:56:12 -0700628 if rcv_pkt is None:
Rich Lane9a003812012-10-04 17:17:59 -0700629 logging.error("ERROR: No packet received from " +
Dan Talaycod8ae7582012-03-23 12:24:56 -0700630 str(check_port))
Dan Talayco551befa2010-07-15 17:05:32 -0700631
Dan Talaycof6e76c02012-03-23 10:56:12 -0700632 parent.assertTrue(rcv_pkt is not None,
Dan Talaycod8ae7582012-03-23 12:24:56 -0700633 "Did not receive packet port " + str(check_port))
Rich Lane9a003812012-10-04 17:17:59 -0700634 logging.debug("Packet len " + str(len(rcv_pkt)) + " in on " +
Dan Talaycof6e76c02012-03-23 10:56:12 -0700635 str(rcv_port))
636
637 if str(exp_pkt) != str(rcv_pkt):
Rich Lane9a003812012-10-04 17:17:59 -0700638 logging.error("ERROR: Packet match failed.")
639 logging.debug("Expected len " + str(len(exp_pkt)) + ": "
Dan Talaycof6e76c02012-03-23 10:56:12 -0700640 + str(exp_pkt).encode('hex'))
Rich Lane9a003812012-10-04 17:17:59 -0700641 logging.debug("Received len " + str(len(rcv_pkt)) + ": "
Dan Talaycof6e76c02012-03-23 10:56:12 -0700642 + str(rcv_pkt).encode('hex'))
Rich Lane5d7e89a2012-10-26 16:43:13 -0700643 logging.debug("Expected packet: " + inspect_packet(scapy.Ether(str(exp_pkt))))
644 logging.debug("Received packet: " + inspect_packet(scapy.Ether(str(rcv_pkt))))
Dan Talaycof6e76c02012-03-23 10:56:12 -0700645 parent.assertEqual(str(exp_pkt), str(rcv_pkt),
Dan Talaycod8ae7582012-03-23 12:24:56 -0700646 "Packet match error on port " + str(check_port))
Dan Talaycof6e76c02012-03-23 10:56:12 -0700647
Dan Talayco551befa2010-07-15 17:05:32 -0700648def match_verify(parent, req_match, res_match):
649 """
650 Verify flow matches agree; if they disagree, report where
651
652 parent must implement assertEqual
653 Use str() to ensure content is compared and not pointers
654 """
655
656 parent.assertEqual(req_match.wildcards, res_match.wildcards,
657 'Match failed: wildcards: ' + hex(req_match.wildcards) +
658 " != " + hex(res_match.wildcards))
659 parent.assertEqual(req_match.in_port, res_match.in_port,
660 'Match failed: in_port: ' + str(req_match.in_port) +
661 " != " + str(res_match.in_port))
Rich Laned0478ff2013-03-11 12:46:58 -0700662 parent.assertEqual(str(req_match.eth_src), str(res_match.eth_src),
663 'Match failed: eth_src: ' + str(req_match.eth_src) +
664 " != " + str(res_match.eth_src))
665 parent.assertEqual(str(req_match.eth_dst), str(res_match.eth_dst),
666 'Match failed: eth_dst: ' + str(req_match.eth_dst) +
667 " != " + str(res_match.eth_dst))
668 parent.assertEqual(req_match.vlan_vid, res_match.vlan_vid,
669 'Match failed: vlan_vid: ' + str(req_match.vlan_vid) +
670 " != " + str(res_match.vlan_vid))
671 parent.assertEqual(req_match.vlan_pcp, res_match.vlan_pcp,
672 'Match failed: vlan_pcp: ' +
673 str(req_match.vlan_pcp) + " != " +
674 str(res_match.vlan_pcp))
675 parent.assertEqual(req_match.eth_type, res_match.eth_type,
676 'Match failed: eth_type: ' + str(req_match.eth_type) +
677 " != " + str(res_match.eth_type))
Dan Talayco551befa2010-07-15 17:05:32 -0700678
Rich Lanee717c6e2013-03-12 10:25:50 -0700679 if (not(req_match.wildcards & ofp.OFPFW_DL_TYPE)
Rich Laned0478ff2013-03-11 12:46:58 -0700680 and (req_match.eth_type == IP_ETHERTYPE)):
681 parent.assertEqual(req_match.ip_dscp, res_match.ip_dscp,
682 'Match failed: ip_dscp: ' + str(req_match.ip_dscp) +
683 " != " + str(res_match.ip_dscp))
684 parent.assertEqual(req_match.ip_proto, res_match.ip_proto,
685 'Match failed: ip_proto: ' + str(req_match.ip_proto) +
686 " != " + str(res_match.ip_proto))
687 parent.assertEqual(req_match.ipv4_src, res_match.ipv4_src,
688 'Match failed: ipv4_src: ' + str(req_match.ipv4_src) +
689 " != " + str(res_match.ipv4_src))
690 parent.assertEqual(req_match.ipv4_dst, res_match.ipv4_dst,
691 'Match failed: ipv4_dst: ' + str(req_match.ipv4_dst) +
692 " != " + str(res_match.ipv4_dst))
Dan Talayco551befa2010-07-15 17:05:32 -0700693
Rich Lanee717c6e2013-03-12 10:25:50 -0700694 if (not(req_match.wildcards & ofp.OFPFW_NW_PROTO)
Rich Laned0478ff2013-03-11 12:46:58 -0700695 and ((req_match.ip_proto == TCP_PROTOCOL)
696 or (req_match.ip_proto == UDP_PROTOCOL))):
697 parent.assertEqual(req_match.tcp_src, res_match.tcp_src,
698 'Match failed: tcp_src: ' +
699 str(req_match.tcp_src) +
700 " != " + str(res_match.tcp_src))
701 parent.assertEqual(req_match.tcp_dst, res_match.tcp_dst,
702 'Match failed: tcp_dst: ' +
703 str(req_match.tcp_dst) +
704 " != " + str(res_match.tcp_dst))
Dan Talayco551befa2010-07-15 17:05:32 -0700705
Ed Swierk99a74de2012-08-22 06:40:54 -0700706def packet_to_flow_match(parent, packet):
Rich Lanef6883512013-03-11 17:00:09 -0700707 match = oftest.parse.packet_to_flow_match(packet)
Rich Laneab7476f2013-06-13 15:53:52 -0700708 if ofp.OFP_VERSION in [1, 2]:
709 match.wildcards |= required_wildcards(parent)
710 else:
711 # TODO remove incompatible OXM entries
712 pass
Ed Swierk99a74de2012-08-22 06:40:54 -0700713 return match
714
715def flow_msg_create(parent, pkt, ing_port=None, action_list=None, wildcards=None,
Dan Talaycof6e76c02012-03-23 10:56:12 -0700716 egr_ports=None, egr_queue=None, check_expire=False, in_band=False):
Dan Talayco551befa2010-07-15 17:05:32 -0700717 """
718 Create a flow message
719
720 Match on packet with given wildcards.
721 See flow_match_test for other parameter descriptoins
722 @param egr_queue if not None, make the output an enqueue action
Dan Talayco677c0b72011-08-23 22:53:38 -0700723 @param in_band if True, do not wildcard ingress port
Dan Talaycof6e76c02012-03-23 10:56:12 -0700724 @param egr_ports None (drop), single port or list of ports
Dan Talayco551befa2010-07-15 17:05:32 -0700725 """
Rich Lanef6883512013-03-11 17:00:09 -0700726 match = oftest.parse.packet_to_flow_match(pkt)
Dan Talayco551befa2010-07-15 17:05:32 -0700727 parent.assertTrue(match is not None, "Flow match from pkt failed")
Ed Swierk99a74de2012-08-22 06:40:54 -0700728 if wildcards is None:
729 wildcards = required_wildcards(parent)
Dan Talayco677c0b72011-08-23 22:53:38 -0700730 if in_band:
Rich Lanee717c6e2013-03-12 10:25:50 -0700731 wildcards &= ~ofp.OFPFW_IN_PORT
Dan Talayco551befa2010-07-15 17:05:32 -0700732 match.wildcards = wildcards
733 match.in_port = ing_port
734
Dan Talaycof6e76c02012-03-23 10:56:12 -0700735 if type(egr_ports) == type([]):
736 egr_port_list = egr_ports
737 else:
738 egr_port_list = [egr_ports]
739
Rich Lanee717c6e2013-03-12 10:25:50 -0700740 request = ofp.message.flow_add()
Dan Talayco551befa2010-07-15 17:05:32 -0700741 request.match = match
742 request.buffer_id = 0xffffffff
743 if check_expire:
Rich Lanee717c6e2013-03-12 10:25:50 -0700744 request.flags |= ofp.OFPFF_SEND_FLOW_REM
Dan Talayco551befa2010-07-15 17:05:32 -0700745 request.hard_timeout = 1
746
747 if action_list is not None:
748 for act in action_list:
Rich Lane9a003812012-10-04 17:17:59 -0700749 logging.debug("Adding action " + act.show())
Rich Lanec495d9e2013-03-08 17:43:36 -0800750 request.actions.append(act)
Dan Talayco551befa2010-07-15 17:05:32 -0700751
752 # Set up output/enqueue action if directed
753 if egr_queue is not None:
Dan Talaycof6e76c02012-03-23 10:56:12 -0700754 parent.assertTrue(egr_ports is not None, "Egress port not set")
Rich Lanee717c6e2013-03-12 10:25:50 -0700755 act = ofp.action.enqueue()
Dan Talaycof6e76c02012-03-23 10:56:12 -0700756 for egr_port in egr_port_list:
757 act.port = egr_port
758 act.queue_id = egr_queue
Rich Lanec495d9e2013-03-08 17:43:36 -0800759 request.actions.append(act)
Dan Talaycof6e76c02012-03-23 10:56:12 -0700760 elif egr_ports is not None:
761 for egr_port in egr_port_list:
Rich Lanee717c6e2013-03-12 10:25:50 -0700762 act = ofp.action.output()
Dan Talaycof6e76c02012-03-23 10:56:12 -0700763 act.port = egr_port
Rich Lanec495d9e2013-03-08 17:43:36 -0800764 request.actions.append(act)
Dan Talayco551befa2010-07-15 17:05:32 -0700765
Rich Lane9a003812012-10-04 17:17:59 -0700766 logging.debug(request.show())
Dan Talayco551befa2010-07-15 17:05:32 -0700767
768 return request
769
Jeffrey Townsendf3eae9c2012-03-28 18:23:21 -0700770def flow_msg_install(parent, request, clear_table_override=None):
Dan Talayco551befa2010-07-15 17:05:32 -0700771 """
772 Install a flow mod message in the switch
773
774 @param parent Must implement controller, assertEqual, assertTrue
775 @param request The request, all set to go
776 @param clear_table If true, clear the flow table before installing
777 """
Dan Talayco8a64e332012-03-28 14:53:20 -0700778
Rich Lane2014f9b2012-10-05 15:29:40 -0700779 clear_table = test_param_get('clear_table', default=True)
Jeffrey Townsendf3eae9c2012-03-28 18:23:21 -0700780 if(clear_table_override != None):
781 clear_table = clear_table_override
782
783 if clear_table:
Rich Lane9a003812012-10-04 17:17:59 -0700784 logging.debug("Clear flow table")
Rich Lane32bf9482013-01-03 17:26:30 -0800785 delete_all_flows(parent.controller)
Dan Talayco551befa2010-07-15 17:05:32 -0700786
Rich Lane9a003812012-10-04 17:17:59 -0700787 logging.debug("Insert flow")
Rich Lane5c3151c2013-01-03 17:15:41 -0800788 parent.controller.message_send(request)
Rich Lanee912d032012-12-22 14:28:33 -0800789
Rich Lane3a261d52013-01-03 17:45:08 -0800790 do_barrier(parent.controller)
Dan Talayco551befa2010-07-15 17:05:32 -0700791
Ed Swierk99a74de2012-08-22 06:40:54 -0700792def flow_match_test_port_pair(parent, ing_port, egr_ports, wildcards=None,
Rich Laned0478ff2013-03-11 12:46:58 -0700793 vlan_vid=-1, pkt=None, exp_pkt=None,
Rich Lanee5779d32012-10-05 17:56:04 -0700794 action_list=None):
Dan Talayco551befa2010-07-15 17:05:32 -0700795 """
796 Flow match test on single TCP packet
Dan Talaycof6e76c02012-03-23 10:56:12 -0700797 @param egr_ports A single port or list of ports
Dan Talayco551befa2010-07-15 17:05:32 -0700798
799 Run test with packet through switch from ing_port to egr_port
800 See flow_match_test for parameter descriptions
801 """
802
Ed Swierk99a74de2012-08-22 06:40:54 -0700803 if wildcards is None:
804 wildcards = required_wildcards(parent)
Rich Lane9a003812012-10-04 17:17:59 -0700805 logging.info("Pkt match test: " + str(ing_port) + " to " +
Dan Talaycof6e76c02012-03-23 10:56:12 -0700806 str(egr_ports))
Rich Laned0478ff2013-03-11 12:46:58 -0700807 logging.debug(" WC: " + hex(wildcards) + " vlan: " + str(vlan_vid))
Dan Talayco551befa2010-07-15 17:05:32 -0700808 if pkt is None:
Rich Laned0478ff2013-03-11 12:46:58 -0700809 pkt = simple_tcp_packet(dl_vlan_enable=(vlan_vid >= 0), vlan_vid=vlan_vid)
Rich Lanec41fbec2013-10-02 00:27:59 -0700810 if exp_pkt is None:
811 exp_pkt = pkt
Dan Talayco551befa2010-07-15 17:05:32 -0700812
813 request = flow_msg_create(parent, pkt, ing_port=ing_port,
Dan Talaycof6e76c02012-03-23 10:56:12 -0700814 wildcards=wildcards, egr_ports=egr_ports,
Dan Talayco551befa2010-07-15 17:05:32 -0700815 action_list=action_list)
816
817 flow_msg_install(parent, request)
818
Rich Lane9a003812012-10-04 17:17:59 -0700819 logging.debug("Send packet: " + str(ing_port) + " to " +
Dan Talaycof6e76c02012-03-23 10:56:12 -0700820 str(egr_ports))
Dan Talayco551befa2010-07-15 17:05:32 -0700821 parent.dataplane.send(ing_port, str(pkt))
822
Rich Lane8f45e2d2013-10-01 16:06:54 -0700823 exp_ports = [ing_port if port == ofp.OFPP_IN_PORT else port for port in egr_ports]
Rich Lanee4b384d2013-09-13 14:33:40 -0700824 verify_packets(parent, exp_pkt, exp_ports)
Dan Talayco551befa2010-07-15 17:05:32 -0700825
Rich Lane89725bb2012-12-03 16:23:27 -0800826def flow_match_test_pktout(parent, ing_port, egr_ports,
Rich Laned0478ff2013-03-11 12:46:58 -0700827 vlan_vid=-1, pkt=None, exp_pkt=None,
Rich Lane89725bb2012-12-03 16:23:27 -0800828 action_list=None):
829 """
830 Packet-out test on single TCP packet
831 @param egr_ports A single port or list of ports
832
833 Run test sending packet-out to egr_ports. The goal is to test the actions
834 taken on the packet, not the matching which is of course irrelevant.
835 See flow_match_test for parameter descriptions
836 """
837
838 if pkt is None:
Rich Laned0478ff2013-03-11 12:46:58 -0700839 pkt = simple_tcp_packet(dl_vlan_enable=(vlan_vid >= 0), vlan_vid=vlan_vid)
Rich Lanec41fbec2013-10-02 00:27:59 -0700840 if exp_pkt is None:
841 exp_pkt = pkt
Rich Lane89725bb2012-12-03 16:23:27 -0800842
Rich Lanee717c6e2013-03-12 10:25:50 -0700843 msg = ofp.message.packet_out()
Rich Lane89725bb2012-12-03 16:23:27 -0800844 msg.in_port = ing_port
Rich Laneea8c4722013-04-04 15:30:20 -0700845 msg.buffer_id = 0xffffffff
Rich Lane89725bb2012-12-03 16:23:27 -0800846 msg.data = str(pkt)
847 if action_list is not None:
848 for act in action_list:
Rich Lanec495d9e2013-03-08 17:43:36 -0800849 msg.actions.append(act)
Rich Lane89725bb2012-12-03 16:23:27 -0800850
851 # Set up output action
852 if egr_ports is not None:
853 for egr_port in egr_ports:
Rich Lanee717c6e2013-03-12 10:25:50 -0700854 act = ofp.action.output()
Rich Lane89725bb2012-12-03 16:23:27 -0800855 act.port = egr_port
Rich Lanec495d9e2013-03-08 17:43:36 -0800856 msg.actions.append(act)
Rich Lane89725bb2012-12-03 16:23:27 -0800857
858 logging.debug(msg.show())
Rich Lane5c3151c2013-01-03 17:15:41 -0800859 parent.controller.message_send(msg)
Rich Lane89725bb2012-12-03 16:23:27 -0800860
Rich Lane8f45e2d2013-10-01 16:06:54 -0700861 exp_ports = [ing_port if port == ofp.OFPP_IN_PORT else port for port in egr_ports]
Rich Lanee4b384d2013-09-13 14:33:40 -0700862 verify_packets(parent, exp_pkt, exp_ports)
Rich Lane89725bb2012-12-03 16:23:27 -0800863
Dan Talaycof6e76c02012-03-23 10:56:12 -0700864def get_egr_list(parent, of_ports, how_many, exclude_list=[]):
865 """
866 Generate a list of ports avoiding those in the exclude list
Rich Lane9a003812012-10-04 17:17:59 -0700867 @param parent Supplies logging
Dan Talaycof6e76c02012-03-23 10:56:12 -0700868 @param of_ports List of OF port numbers
869 @param how_many Number of ports to be added to the list
870 @param exclude_list List of ports not to be used
871 @returns An empty list if unable to find enough ports
872 """
873
Dan Talaycoc948d0b2012-03-23 12:17:54 -0700874 if how_many == 0:
875 return []
876
Dan Talaycof6e76c02012-03-23 10:56:12 -0700877 count = 0
878 egr_ports = []
879 for egr_idx in range(len(of_ports)):
880 if of_ports[egr_idx] not in exclude_list:
881 egr_ports.append(of_ports[egr_idx])
882 count += 1
883 if count >= how_many:
884 return egr_ports
Rich Lane9a003812012-10-04 17:17:59 -0700885 logging.debug("Could not generate enough egress ports for test")
Dan Talaycof6e76c02012-03-23 10:56:12 -0700886 return []
887
Rich Laned0478ff2013-03-11 12:46:58 -0700888def flow_match_test(parent, port_map, wildcards=None, vlan_vid=-1, pkt=None,
Rich Lanee5779d32012-10-05 17:56:04 -0700889 exp_pkt=None, action_list=None,
Dan Talaycoc948d0b2012-03-23 12:17:54 -0700890 max_test=0, egr_count=1, ing_port=False):
Dan Talayco551befa2010-07-15 17:05:32 -0700891 """
Rich Lane89725bb2012-12-03 16:23:27 -0800892 Run flow_match_test_port_pair on all port pairs and packet-out
Dan Talayco551befa2010-07-15 17:05:32 -0700893
894 @param max_test If > 0 no more than this number of tests are executed.
895 @param parent Must implement controller, dataplane, assertTrue, assertEqual
Rich Lane9a003812012-10-04 17:17:59 -0700896 and logging
Dan Talayco551befa2010-07-15 17:05:32 -0700897 @param pkt If not None, use this packet for ingress
898 @param wildcards For flow match entry
Rich Laned0478ff2013-03-11 12:46:58 -0700899 @param vlan_vid If not -1, and pkt is None, create a pkt w/ VLAN tag
Dan Talayco551befa2010-07-15 17:05:32 -0700900 @param exp_pkt If not None, use this as the expected output pkt; els use pkt
901 @param action_list Additional actions to add to flow mod
Dan Talaycocfa172f2012-03-23 12:03:00 -0700902 @param egr_count Number of egress ports; -1 means get from config w/ dflt 2
Dan Talayco551befa2010-07-15 17:05:32 -0700903 """
Ed Swierk99a74de2012-08-22 06:40:54 -0700904 if wildcards is None:
905 wildcards = required_wildcards(parent)
Dan Talayco551befa2010-07-15 17:05:32 -0700906 of_ports = port_map.keys()
907 of_ports.sort()
908 parent.assertTrue(len(of_ports) > 1, "Not enough ports for test")
909 test_count = 0
910
Dan Talaycocfa172f2012-03-23 12:03:00 -0700911 if egr_count == -1:
Rich Lane2014f9b2012-10-05 15:29:40 -0700912 egr_count = test_param_get('egr_count', default=2)
Dan Talaycocfa172f2012-03-23 12:03:00 -0700913
Dan Talayco551befa2010-07-15 17:05:32 -0700914 for ing_idx in range(len(of_ports)):
915 ingress_port = of_ports[ing_idx]
Dan Talaycof6e76c02012-03-23 10:56:12 -0700916 egr_ports = get_egr_list(parent, of_ports, egr_count,
917 exclude_list=[ingress_port])
Dan Talaycoc948d0b2012-03-23 12:17:54 -0700918 if ing_port:
Rich Lanee717c6e2013-03-12 10:25:50 -0700919 egr_ports.append(ofp.OFPP_IN_PORT)
Dan Talaycof6e76c02012-03-23 10:56:12 -0700920 if len(egr_ports) == 0:
921 parent.assertTrue(0, "Failed to generate egress port list")
922
923 flow_match_test_port_pair(parent, ingress_port, egr_ports,
Rich Laned0478ff2013-03-11 12:46:58 -0700924 wildcards=wildcards, vlan_vid=vlan_vid,
Dan Talaycof6e76c02012-03-23 10:56:12 -0700925 pkt=pkt, exp_pkt=exp_pkt,
Rich Lanee5779d32012-10-05 17:56:04 -0700926 action_list=action_list)
Dan Talaycof6e76c02012-03-23 10:56:12 -0700927 test_count += 1
928 if (max_test > 0) and (test_count > max_test):
Rich Lane9a003812012-10-04 17:17:59 -0700929 logging.info("Ran " + str(test_count) + " tests; exiting")
Rich Lane89725bb2012-12-03 16:23:27 -0800930 break
931
Ed Swierk38eea082013-01-02 19:46:20 -0800932 if not test_param_get('pktout_actions', default=True):
933 return
Rich Lane89725bb2012-12-03 16:23:27 -0800934
935 ingress_port = of_ports[0]
936 egr_ports = get_egr_list(parent, of_ports, egr_count,
937 exclude_list=[ingress_port])
938 if ing_port:
Rich Lanee717c6e2013-03-12 10:25:50 -0700939 egr_ports.append(ofp.OFPP_IN_PORT)
Rich Lane89725bb2012-12-03 16:23:27 -0800940 flow_match_test_pktout(parent, ingress_port, egr_ports,
Rich Laned0478ff2013-03-11 12:46:58 -0700941 vlan_vid=vlan_vid,
Rich Lane89725bb2012-12-03 16:23:27 -0800942 pkt=pkt, exp_pkt=exp_pkt,
943 action_list=action_list)
Dan Talayco551befa2010-07-15 17:05:32 -0700944
Rich Lane2014f9b2012-10-05 15:29:40 -0700945def test_param_get(key, default=None):
Dan Talayco4b2bee62010-07-20 14:10:05 -0700946 """
947 Return value passed via test-params if present
948
Dan Talayco4b2bee62010-07-20 14:10:05 -0700949 @param key The lookup key
950 @param default Default value to use if not found
951
952 If the pair 'key=val' appeared in the string passed to --test-params
953 on the command line, return val (as interpreted by exec). Otherwise
954 return default value.
Dan Talaycof6e76c02012-03-23 10:56:12 -0700955
956 WARNING: TEST PARAMETERS MUST BE PYTHON IDENTIFIERS;
957 eg egr_count, not egr-count.
Dan Talayco4b2bee62010-07-20 14:10:05 -0700958 """
959 try:
Rich Lanecd97d3d2013-01-07 18:50:06 -0800960 exec oftest.config["test_params"]
Dan Talayco4b2bee62010-07-20 14:10:05 -0700961 except:
962 return default
963
Dan Talayco4b2bee62010-07-20 14:10:05 -0700964 try:
Rich Lanefdec0fb2013-08-09 18:01:05 -0700965 return eval(str(key))
Dan Talayco4b2bee62010-07-20 14:10:05 -0700966 except:
967 return default
968
969def action_generate(parent, field_to_mod, mod_field_vals):
970 """
971 Create an action to modify the field indicated in field_to_mod
972
973 @param parent Must implement, assertTrue
974 @param field_to_mod The field to modify as a string name
975 @param mod_field_vals Hash of values to use for modified values
976 """
977
978 act = None
979
980 if field_to_mod in ['pktlen']:
981 return None
982
Rich Laned0478ff2013-03-11 12:46:58 -0700983 if field_to_mod == 'eth_dst':
Rich Lanee717c6e2013-03-12 10:25:50 -0700984 act = ofp.action.set_dl_dst()
Rich Lanef6883512013-03-11 17:00:09 -0700985 act.dl_addr = oftest.parse.parse_mac(mod_field_vals['eth_dst'])
Rich Laned0478ff2013-03-11 12:46:58 -0700986 elif field_to_mod == 'eth_src':
Rich Lanee717c6e2013-03-12 10:25:50 -0700987 act = ofp.action.set_dl_src()
Rich Lanef6883512013-03-11 17:00:09 -0700988 act.dl_addr = oftest.parse.parse_mac(mod_field_vals['eth_src'])
Dan Talayco4b2bee62010-07-20 14:10:05 -0700989 elif field_to_mod == 'dl_vlan_enable':
990 if not mod_field_vals['dl_vlan_enable']: # Strip VLAN tag
Rich Lanee717c6e2013-03-12 10:25:50 -0700991 act = ofp.action.strip_vlan()
Rich Laned0478ff2013-03-11 12:46:58 -0700992 # Add VLAN tag is handled by vlan_vid field
Dan Talayco4b2bee62010-07-20 14:10:05 -0700993 # Will return None in this case
Rich Laned0478ff2013-03-11 12:46:58 -0700994 elif field_to_mod == 'vlan_vid':
Rich Lanee717c6e2013-03-12 10:25:50 -0700995 act = ofp.action.set_vlan_vid()
Rich Laned0478ff2013-03-11 12:46:58 -0700996 act.vlan_vid = mod_field_vals['vlan_vid']
997 elif field_to_mod == 'vlan_pcp':
Rich Lanee717c6e2013-03-12 10:25:50 -0700998 act = ofp.action.set_vlan_pcp()
Rich Laned0478ff2013-03-11 12:46:58 -0700999 act.vlan_pcp = mod_field_vals['vlan_pcp']
Dan Talayco4b2bee62010-07-20 14:10:05 -07001000 elif field_to_mod == 'ip_src':
Rich Lanee717c6e2013-03-12 10:25:50 -07001001 act = ofp.action.set_nw_src()
Rich Lanef6883512013-03-11 17:00:09 -07001002 act.nw_addr = oftest.parse.parse_ip(mod_field_vals['ip_src'])
Dan Talayco4b2bee62010-07-20 14:10:05 -07001003 elif field_to_mod == 'ip_dst':
Rich Lanee717c6e2013-03-12 10:25:50 -07001004 act = ofp.action.set_nw_dst()
Rich Lanef6883512013-03-11 17:00:09 -07001005 act.nw_addr = oftest.parse.parse_ip(mod_field_vals['ip_dst'])
Dan Talayco4b2bee62010-07-20 14:10:05 -07001006 elif field_to_mod == 'ip_tos':
Rich Lanee717c6e2013-03-12 10:25:50 -07001007 act = ofp.action.set_nw_tos()
Dan Talayco4b2bee62010-07-20 14:10:05 -07001008 act.nw_tos = mod_field_vals['ip_tos']
1009 elif field_to_mod == 'tcp_sport':
Rich Lanee717c6e2013-03-12 10:25:50 -07001010 act = ofp.action.set_tp_src()
Dan Talayco4b2bee62010-07-20 14:10:05 -07001011 act.tp_port = mod_field_vals['tcp_sport']
1012 elif field_to_mod == 'tcp_dport':
Rich Lanee717c6e2013-03-12 10:25:50 -07001013 act = ofp.action.set_tp_dst()
Dan Talayco4b2bee62010-07-20 14:10:05 -07001014 act.tp_port = mod_field_vals['tcp_dport']
Rich Lane110e0e32012-10-26 16:21:46 -07001015 elif field_to_mod == 'udp_sport':
Rich Lanee717c6e2013-03-12 10:25:50 -07001016 act = ofp.action.set_tp_src()
Rich Lane110e0e32012-10-26 16:21:46 -07001017 act.tp_port = mod_field_vals['udp_sport']
1018 elif field_to_mod == 'udp_dport':
Rich Lanee717c6e2013-03-12 10:25:50 -07001019 act = ofp.action.set_tp_dst()
Rich Lane110e0e32012-10-26 16:21:46 -07001020 act.tp_port = mod_field_vals['udp_dport']
Dan Talayco4b2bee62010-07-20 14:10:05 -07001021 else:
1022 parent.assertTrue(0, "Unknown field to modify: " + str(field_to_mod))
1023
1024 return act
1025
1026def pkt_action_setup(parent, start_field_vals={}, mod_field_vals={},
Rich Lane110e0e32012-10-26 16:21:46 -07001027 mod_fields=[], tp="tcp", check_test_params=False):
Dan Talayco4b2bee62010-07-20 14:10:05 -07001028 """
1029 Set up the ingress and expected packet and action list for a test
1030
Rich Lane2014f9b2012-10-05 15:29:40 -07001031 @param parent Must implement assertTrue
Dan Talayco4b2bee62010-07-20 14:10:05 -07001032 @param start_field_values Field values to use for ingress packet (optional)
1033 @param mod_field_values Field values to use for modified packet (optional)
1034 @param mod_fields The list of fields to be modified by the switch in the test.
1035 @params check_test_params If True, will check the parameters vid, add_vlan
1036 and strip_vlan from the command line.
1037
1038 Returns a triple: pkt-to-send, expected-pkt, action-list
1039 """
1040
1041 new_actions = []
1042
Dan Talayco4b2bee62010-07-20 14:10:05 -07001043 base_pkt_params = {}
1044 base_pkt_params['pktlen'] = 100
Rich Laned0478ff2013-03-11 12:46:58 -07001045 base_pkt_params['eth_dst'] = '00:DE:F0:12:34:56'
1046 base_pkt_params['eth_src'] = '00:23:45:67:89:AB'
Dan Talayco4b2bee62010-07-20 14:10:05 -07001047 base_pkt_params['dl_vlan_enable'] = False
Rich Laned0478ff2013-03-11 12:46:58 -07001048 base_pkt_params['vlan_vid'] = 2
1049 base_pkt_params['vlan_pcp'] = 0
Dan Talayco4b2bee62010-07-20 14:10:05 -07001050 base_pkt_params['ip_src'] = '192.168.0.1'
1051 base_pkt_params['ip_dst'] = '192.168.0.2'
1052 base_pkt_params['ip_tos'] = 0
Rich Lane110e0e32012-10-26 16:21:46 -07001053 if tp == "tcp":
1054 base_pkt_params['tcp_sport'] = 1234
1055 base_pkt_params['tcp_dport'] = 80
1056 elif tp == "udp":
1057 base_pkt_params['udp_sport'] = 1234
1058 base_pkt_params['udp_dport'] = 80
Dan Talayco4b2bee62010-07-20 14:10:05 -07001059 for keyname in start_field_vals.keys():
1060 base_pkt_params[keyname] = start_field_vals[keyname]
1061
1062 mod_pkt_params = {}
1063 mod_pkt_params['pktlen'] = 100
Rich Laned0478ff2013-03-11 12:46:58 -07001064 mod_pkt_params['eth_dst'] = '00:21:0F:ED:CB:A9'
1065 mod_pkt_params['eth_src'] = '00:ED:CB:A9:87:65'
Dan Talayco4b2bee62010-07-20 14:10:05 -07001066 mod_pkt_params['dl_vlan_enable'] = False
Rich Laned0478ff2013-03-11 12:46:58 -07001067 mod_pkt_params['vlan_vid'] = 3
1068 mod_pkt_params['vlan_pcp'] = 7
Dan Talayco4b2bee62010-07-20 14:10:05 -07001069 mod_pkt_params['ip_src'] = '10.20.30.40'
1070 mod_pkt_params['ip_dst'] = '50.60.70.80'
1071 mod_pkt_params['ip_tos'] = 0xf0
Rich Lane110e0e32012-10-26 16:21:46 -07001072 if tp == "tcp":
1073 mod_pkt_params['tcp_sport'] = 4321
1074 mod_pkt_params['tcp_dport'] = 8765
1075 elif tp == "udp":
1076 mod_pkt_params['udp_sport'] = 4321
1077 mod_pkt_params['udp_dport'] = 8765
Dan Talayco4b2bee62010-07-20 14:10:05 -07001078 for keyname in mod_field_vals.keys():
1079 mod_pkt_params[keyname] = mod_field_vals[keyname]
1080
1081 # Check for test param modifications
1082 strip = False
1083 if check_test_params:
Rich Lane2014f9b2012-10-05 15:29:40 -07001084 add_vlan = test_param_get('add_vlan')
1085 strip_vlan = test_param_get('strip_vlan')
1086 vid = test_param_get('vid')
Dan Talayco4b2bee62010-07-20 14:10:05 -07001087
1088 if add_vlan and strip_vlan:
1089 parent.assertTrue(0, "Add and strip VLAN both specified")
1090
1091 if vid:
1092 base_pkt_params['dl_vlan_enable'] = True
Rich Laned0478ff2013-03-11 12:46:58 -07001093 base_pkt_params['vlan_vid'] = vid
1094 if 'vlan_vid' in mod_fields:
1095 mod_pkt_params['vlan_vid'] = vid + 1
Dan Talayco4b2bee62010-07-20 14:10:05 -07001096
1097 if add_vlan:
1098 base_pkt_params['dl_vlan_enable'] = False
1099 mod_pkt_params['dl_vlan_enable'] = True
1100 mod_pkt_params['pktlen'] = base_pkt_params['pktlen'] + 4
1101 mod_fields.append('pktlen')
1102 mod_fields.append('dl_vlan_enable')
Rich Laned0478ff2013-03-11 12:46:58 -07001103 if 'vlan_vid' not in mod_fields:
1104 mod_fields.append('vlan_vid')
Dan Talayco4b2bee62010-07-20 14:10:05 -07001105 elif strip_vlan:
1106 base_pkt_params['dl_vlan_enable'] = True
1107 mod_pkt_params['dl_vlan_enable'] = False
1108 mod_pkt_params['pktlen'] = base_pkt_params['pktlen'] - 4
1109 mod_fields.append('dl_vlan_enable')
1110 mod_fields.append('pktlen')
1111
Rich Lane110e0e32012-10-26 16:21:46 -07001112 if tp == "tcp":
1113 packet_builder = simple_tcp_packet
1114 elif tp == "udp":
1115 packet_builder = simple_udp_packet
1116 else:
1117 raise NotImplementedError("unknown transport protocol %s" % tp)
1118
Dan Talayco4b2bee62010-07-20 14:10:05 -07001119 # Build the ingress packet
Rich Lane110e0e32012-10-26 16:21:46 -07001120 ingress_pkt = packet_builder(**base_pkt_params)
Dan Talayco4b2bee62010-07-20 14:10:05 -07001121
1122 # Build the expected packet, modifying the indicated fields
1123 for item in mod_fields:
1124 base_pkt_params[item] = mod_pkt_params[item]
1125 act = action_generate(parent, item, mod_pkt_params)
1126 if act:
1127 new_actions.append(act)
1128
Rich Lane110e0e32012-10-26 16:21:46 -07001129 expected_pkt = packet_builder(**base_pkt_params)
Dan Talayco4b2bee62010-07-20 14:10:05 -07001130
1131 return (ingress_pkt, expected_pkt, new_actions)
Dan Talayco677c0b72011-08-23 22:53:38 -07001132
1133# Generate a simple "drop" flow mod
1134# If in_band is true, then only drop from first test port
1135def flow_mod_gen(port_map, in_band):
Rich Lanee717c6e2013-03-12 10:25:50 -07001136 request = ofp.message.flow_add()
1137 request.match.wildcards = ofp.OFPFW_ALL
Dan Talayco677c0b72011-08-23 22:53:38 -07001138 if in_band:
Rich Lanee717c6e2013-03-12 10:25:50 -07001139 request.match.wildcards = ofp.OFPFW_ALL - ofp.OFPFW_IN_PORT
Dan Talayco677c0b72011-08-23 22:53:38 -07001140 for of_port, ifname in port_map.items(): # Grab first port
1141 break
1142 request.match.in_port = of_port
1143 request.buffer_id = 0xffffffff
1144 return request
Dan Talaycoba3745c2010-07-21 21:51:08 -07001145
1146def skip_message_emit(parent, s):
1147 """
1148 Print out a 'skipped' message to stderr
1149
1150 @param s The string to print out to the log file
Dan Talaycoba3745c2010-07-21 21:51:08 -07001151 """
1152 global skipped_test_count
1153
1154 skipped_test_count += 1
Rich Lane9a003812012-10-04 17:17:59 -07001155 logging.info("Skipping: " + s)
Dan Talayco2940fdd2013-02-06 15:01:35 -08001156 if oftest.config["debug"] < logging.WARNING:
Dan Talaycoba3745c2010-07-21 21:51:08 -07001157 sys.stderr.write("(skipped) ")
1158 else:
1159 sys.stderr.write("(S)")
Dan Talayco677c0b72011-08-23 22:53:38 -07001160
Dan Talayco8a64e332012-03-28 14:53:20 -07001161
1162def all_stats_get(parent):
1163 """
1164 Get the aggregate stats for all flows in the table
1165 @param parent Test instance with controller connection and assert
1166 @returns dict with keys flows, packets, bytes, active (flows),
1167 lookups, matched
1168 """
Rich Lanee717c6e2013-03-12 10:25:50 -07001169 stat_req = ofp.message.aggregate_stats_request()
1170 stat_req.match = ofp.match()
1171 stat_req.match.wildcards = ofp.OFPFW_ALL
Dan Talayco8a64e332012-03-28 14:53:20 -07001172 stat_req.table_id = 0xff
Rich Lanee717c6e2013-03-12 10:25:50 -07001173 stat_req.out_port = ofp.OFPP_NONE
Dan Talayco8a64e332012-03-28 14:53:20 -07001174
1175 rv = {}
1176
Rich Lanec8aaa3e2012-07-26 19:28:02 -07001177 (reply, pkt) = parent.controller.transact(stat_req)
Rich Lane5fd6faf2013-03-11 13:30:20 -07001178 parent.assertTrue(len(reply.entries) == 1, "Did not receive flow stats reply")
Dan Talayco8a64e332012-03-28 14:53:20 -07001179
Rich Lane5fd6faf2013-03-11 13:30:20 -07001180 for obj in reply.entries:
Dan Talayco8a64e332012-03-28 14:53:20 -07001181 (rv["flows"], rv["packets"], rv["bytes"]) = (obj.flow_count,
1182 obj.packet_count, obj.byte_count)
1183 break
1184
Rich Lanee717c6e2013-03-12 10:25:50 -07001185 request = ofp.message.table_stats_request()
Rich Lanec8aaa3e2012-07-26 19:28:02 -07001186 (reply , pkt) = parent.controller.transact(request)
Dan Talayco8a64e332012-03-28 14:53:20 -07001187
1188
1189 (rv["active"], rv["lookups"], rv["matched"]) = (0,0,0)
Rich Lane5fd6faf2013-03-11 13:30:20 -07001190 for obj in reply.entries:
Dan Talayco8a64e332012-03-28 14:53:20 -07001191 rv["active"] += obj.active_count
1192 rv["lookups"] += obj.lookup_count
1193 rv["matched"] += obj.matched_count
1194
1195 return rv
Dan Talayco2baf8b52012-03-30 09:55:42 -07001196
Rich Lane7744e112013-01-11 17:23:57 -08001197_import_blacklist.add('FILTER')
Dan Talayco2baf8b52012-03-30 09:55:42 -07001198FILTER=''.join([(len(repr(chr(x)))==3) and chr(x) or '.'
1199 for x in range(256)])
1200
1201def hex_dump_buffer(src, length=16):
1202 """
1203 Convert src to a hex dump string and return the string
1204 @param src The source buffer
1205 @param length The number of bytes shown in each line
1206 @returns A string showing the hex dump
1207 """
Dan Talaycoc516fa02012-04-12 22:28:43 -07001208 result = ["\n"]
Dan Talayco2baf8b52012-03-30 09:55:42 -07001209 for i in xrange(0, len(src), length):
1210 chars = src[i:i+length]
1211 hex = ' '.join(["%02x" % ord(x) for x in chars])
1212 printable = ''.join(["%s" % ((ord(x) <= 127 and
1213 FILTER[ord(x)]) or '.') for x in chars])
1214 result.append("%04x %-*s %s\n" % (i, length*3, hex, printable))
1215 return ''.join(result)
1216
1217def format_packet(pkt):
1218 return "Packet length %d \n%s" % (len(str(pkt)),
1219 hex_dump_buffer(str(pkt)))
Rich Lane5d7e89a2012-10-26 16:43:13 -07001220
1221def inspect_packet(pkt):
1222 """
1223 Wrapper around scapy's show() method.
1224 @returns A string showing the dissected packet.
1225 """
1226 from cStringIO import StringIO
1227 out = None
1228 backup = sys.stdout
1229 try:
Rich Lanefdec0fb2013-08-09 18:01:05 -07001230 tmp = StringIO()
1231 sys.stdout = tmp
Rich Lane5d7e89a2012-10-26 16:43:13 -07001232 pkt.show2()
Rich Lanefdec0fb2013-08-09 18:01:05 -07001233 out = tmp.getvalue()
1234 tmp.close()
Rich Lane5d7e89a2012-10-26 16:43:13 -07001235 finally:
1236 sys.stdout = backup
1237 return out
Rich Lane0a4f6372013-01-02 14:40:22 -08001238
1239def nonstandard(cls):
1240 """
Rich Lanecc45b8e2013-01-02 15:55:02 -08001241 Testcase decorator that marks the test as being non-standard.
1242 These tests are not automatically added to the "standard" group.
Rich Lane0a4f6372013-01-02 14:40:22 -08001243 """
Rich Lanecc45b8e2013-01-02 15:55:02 -08001244 cls._nonstandard = True
Rich Lane0a4f6372013-01-02 14:40:22 -08001245 return cls
1246
1247def disabled(cls):
1248 """
Rich Lanecc45b8e2013-01-02 15:55:02 -08001249 Testcase decorator that marks the test as being disabled.
1250 These tests are not automatically added to the "standard" group or
1251 their module's group.
Rich Lane0a4f6372013-01-02 14:40:22 -08001252 """
Rich Lanecc45b8e2013-01-02 15:55:02 -08001253 cls._disabled = True
Rich Lane0a4f6372013-01-02 14:40:22 -08001254 return cls
Rich Lane97e99652013-01-02 17:23:20 -08001255
1256def group(name):
1257 """
1258 Testcase decorator that adds the test to a group.
1259 """
1260 def fn(cls):
1261 if not hasattr(cls, "_groups"):
1262 cls._groups = []
1263 cls._groups.append(name)
1264 return cls
1265 return fn
Rich Lane5a9a1922013-01-11 14:29:30 -08001266
1267def version(ver):
1268 """
1269 Testcase decorator that specifies which versions of OpenFlow the test
1270 supports. The default is 1.0+. This decorator may only be used once.
1271
1272 Supported syntax:
1273 1.0 -> 1.0
1274 1.0,1.2,1.3 -> 1.0, 1.2, 1.3
1275 1.0+ -> 1.0, 1.1, 1.2, 1.3
1276 """
1277 versions = parse_version(ver)
1278 def fn(cls):
1279 cls._versions = versions
1280 return cls
1281 return fn
1282
1283def parse_version(ver):
1284 allowed_versions = ["1.0", "1.1", "1.2", "1.3"]
1285 if re.match("^1\.\d+$", ver):
1286 versions = set([ver])
1287 elif re.match("^(1\.\d+)\+$", ver):
1288 if not ver[:-1] in allowed_versions:
1289 raise ValueError("invalid OpenFlow version %s" % ver[:-1])
1290 versions = set()
1291 if ver != "1.1+": versions.add("1.0")
1292 if ver != "1.2+": versions.add("1.1")
1293 if ver != "1.3+": versions.add("1.2")
1294 versions.add("1.3")
1295 else:
1296 versions = set(ver.split(','))
1297
1298 for version in versions:
1299 if not version in allowed_versions:
1300 raise ValueError("invalid OpenFlow version %s" % version)
1301
1302 return versions
1303
1304assert(parse_version("1.0") == set(["1.0"]))
1305assert(parse_version("1.0,1.2,1.3") == set(["1.0", "1.2", "1.3"]))
1306assert(parse_version("1.0+") == set(["1.0", "1.1", "1.2", "1.3"]))
Rich Lane7744e112013-01-11 17:23:57 -08001307
Rich Laneae3428c2013-03-07 14:37:42 -08001308def get_stats(test, req):
1309 """
1310 Retrieve a list of stats entries. Handles OFPSF_REPLY_MORE.
1311 """
Rich Lanebd56ed62013-07-10 15:49:44 -07001312 if ofp.OFP_VERSION <= 3:
1313 more_flag = ofp.OFPSF_REPLY_MORE
1314 else:
1315 more_flag = ofp.OFPMPF_REPLY_MORE
Rich Laneae3428c2013-03-07 14:37:42 -08001316 stats = []
1317 reply, _ = test.controller.transact(req)
1318 test.assertTrue(reply is not None, "No response to stats request")
Rich Lane5fd6faf2013-03-11 13:30:20 -07001319 stats.extend(reply.entries)
Rich Lanebd56ed62013-07-10 15:49:44 -07001320 while reply.flags & more_flag != 0:
Rich Lane720eaf22013-08-09 18:00:45 -07001321 reply, pkt = test.controller.poll(exp_msg=ofp.OFPT_STATS_REPLY)
Rich Laneae3428c2013-03-07 14:37:42 -08001322 test.assertTrue(reply is not None, "No response to stats request")
Rich Lane5fd6faf2013-03-11 13:30:20 -07001323 stats.extend(reply.entries)
Rich Laneae3428c2013-03-07 14:37:42 -08001324 return stats
1325
Rich Lanebd56ed62013-07-10 15:49:44 -07001326def get_flow_stats(test, match, table_id=None,
1327 out_port=None, out_group=None,
1328 cookie=0, cookie_mask=0):
Rich Laneae3428c2013-03-07 14:37:42 -08001329 """
1330 Retrieve a list of flow stats entries.
1331 """
Rich Lanebd56ed62013-07-10 15:49:44 -07001332
1333 if table_id == None:
1334 if ofp.OFP_VERSION <= 2:
1335 table_id = 0xff
1336 else:
1337 table_id = ofp.OFPTT_ALL
1338
Rich Lanef3bc48c2013-05-03 17:39:35 -07001339 if out_port == None:
Rich Lanebd56ed62013-07-10 15:49:44 -07001340 if ofp.OFP_VERSION == 1:
1341 out_port = ofp.OFPP_NONE
1342 else:
1343 out_port = ofp.OFPP_ANY
1344
1345 if out_group == None:
1346 if ofp.OFP_VERSION > 1:
1347 out_group = ofp.OFPP_ANY
1348
Rich Lanee717c6e2013-03-12 10:25:50 -07001349 req = ofp.message.flow_stats_request(match=match,
Rich Lanebd56ed62013-07-10 15:49:44 -07001350 table_id=table_id,
1351 out_port=out_port)
1352 if ofp.OFP_VERSION > 1:
1353 req.out_group = out_group
1354 req.cookie = cookie
1355 req.cookie_mask = cookie_mask
1356
Rich Laneae3428c2013-03-07 14:37:42 -08001357 return get_stats(test, req)
1358
Rich Lane968b6192013-03-07 15:34:43 -08001359def get_port_stats(test, port_no):
1360 """
1361 Retrieve a list of port stats entries.
1362 """
Rich Lanee717c6e2013-03-12 10:25:50 -07001363 req = ofp.message.port_stats_request(port_no=port_no)
Rich Lane968b6192013-03-07 15:34:43 -08001364 return get_stats(test, req)
1365
Rich Lane6a334922013-03-07 16:14:52 -08001366def get_queue_stats(test, port_no, queue_id):
1367 """
1368 Retrieve a list of queue stats entries.
1369 """
Rich Lanee717c6e2013-03-12 10:25:50 -07001370 req = ofp.message.queue_stats_request(port_no=port_no, queue_id=queue_id)
Rich Lane6a334922013-03-07 16:14:52 -08001371 return get_stats(test, req)
1372
Rich Laneae3428c2013-03-07 14:37:42 -08001373def verify_flow_stats(test, match, table_id=0xff,
Rich Lanef3bc48c2013-05-03 17:39:35 -07001374 out_port=None,
Rich Laneae3428c2013-03-07 14:37:42 -08001375 initial=[],
1376 pkts=None, bytes=None):
1377 """
1378 Verify that flow stats changed as expected.
1379
1380 Optionally takes an 'initial' list of stats entries, as returned by
1381 get_flow_stats(). If 'initial' is not given the counters are assumed to
1382 begin at 0.
1383 """
Rich Lanef3bc48c2013-05-03 17:39:35 -07001384 if out_port == None:
1385 out_port = ofp.OFPP_NONE
1386
Rich Laneae3428c2013-03-07 14:37:42 -08001387 def accumulate(stats):
1388 pkts_acc = bytes_acc = 0
1389 for stat in stats:
1390 pkts_acc += stat.packet_count
1391 bytes_acc += stat.byte_count
1392 return (pkts_acc, bytes_acc)
1393
1394 pkts_before, bytes_before = accumulate(initial)
1395
1396 # Wait 10s for counters to update
1397 pkt_diff = byte_diff = None
1398 for i in range(0, 100):
1399 stats = get_flow_stats(test, match, table_id=table_id, out_port=out_port)
1400 pkts_after, bytes_after = accumulate(stats)
1401 pkt_diff = pkts_after - pkts_before
1402 byte_diff = bytes_after - bytes_before
1403 if (pkts == None or pkt_diff >= pkts) and \
1404 (bytes == None or byte_diff >= bytes):
1405 break
Dan Talayco53724732013-03-08 23:54:02 -08001406 time.sleep(0.1)
Rich Laneae3428c2013-03-07 14:37:42 -08001407
1408 if pkts != None:
1409 test.assertEquals(pkt_diff, pkts, "Flow packet counter not updated properly (expected increase of %d, got increase of %d)" % (pkts, pkt_diff))
1410
1411 if bytes != None:
Rich Lane53b96812013-03-07 16:54:50 -08001412 test.assertTrue(byte_diff >= bytes and byte_diff <= bytes*1.1,
1413 "Flow byte counter not updated properly (expected increase of %d, got increase of %d)" % (bytes, byte_diff))
Rich Laneae3428c2013-03-07 14:37:42 -08001414
Rich Lane968b6192013-03-07 15:34:43 -08001415def verify_port_stats(test, port,
1416 initial=[],
1417 tx_pkts=None, rx_pkts=None,
1418 tx_bytes=None, rx_bytes=None):
1419 """
1420 Verify that port stats changed as expected.
1421
1422 Optionally takes an 'initial' list of stats entries, as returned by
1423 get_port_stats(). If 'initial' is not given the counters are assumed to
1424 begin at 0.
1425 """
1426 def accumulate(stats):
1427 tx_pkts_acc = rx_pkts_acc = tx_bytes_acc = rx_bytes_acc = 0
1428 for stat in stats:
1429 tx_pkts_acc += stat.tx_packets
1430 rx_pkts_acc += stat.rx_packets
1431 tx_bytes_acc += stat.tx_bytes
1432 rx_bytes_acc += stat.rx_bytes
1433 return (tx_pkts_acc, rx_pkts_acc, tx_bytes_acc, rx_bytes_acc)
1434
1435 tx_pkts_before, rx_pkts_before, \
1436 tx_bytes_before, rx_bytes_before = accumulate(initial)
1437
1438 # Wait 10s for counters to update
1439 for i in range(0, 100):
1440 stats = get_port_stats(test, port)
1441 tx_pkts_after, rx_pkts_after, \
1442 tx_bytes_after, rx_bytes_after = accumulate(stats)
1443 tx_pkts_diff = tx_pkts_after - tx_pkts_before
1444 rx_pkts_diff = rx_pkts_after - rx_pkts_before
1445 tx_bytes_diff = tx_bytes_after - tx_bytes_before
1446 rx_bytes_diff = rx_bytes_after - rx_bytes_before
1447 if (tx_pkts == None or tx_pkts == tx_pkts_diff) and \
1448 (rx_pkts == None or rx_pkts == rx_pkts_diff) and \
Rich Lane53b96812013-03-07 16:54:50 -08001449 (tx_bytes == None or tx_bytes <= tx_bytes_diff) and \
1450 (rx_bytes == None or rx_bytes <= rx_bytes_diff):
Rich Lane968b6192013-03-07 15:34:43 -08001451 break
1452 time.sleep(0.1)
1453
1454 if (tx_pkts != None):
1455 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))
1456 if (rx_pkts != None):
1457 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))
1458 if (tx_bytes != None):
Rich Lane53b96812013-03-07 16:54:50 -08001459 test.assertTrue(tx_bytes_diff >= tx_bytes and tx_bytes_diff <= tx_bytes*1.1,
1460 "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 -08001461 if (rx_bytes != None):
Rich Lane53b96812013-03-07 16:54:50 -08001462 test.assertTrue(rx_bytes_diff >= rx_bytes and rx_bytes_diff <= rx_bytes*1.1,
1463 "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 -08001464
Rich Lane6a334922013-03-07 16:14:52 -08001465def verify_queue_stats(test, port_no, queue_id,
1466 initial=[],
1467 pkts=None, bytes=None):
1468 """
1469 Verify that queue stats changed as expected.
1470
1471 Optionally takes an 'initial' list of stats entries, as returned by
1472 get_queue_stats(). If 'initial' is not given the counters are assumed to
1473 begin at 0.
1474 """
1475 def accumulate(stats):
1476 pkts_acc = bytes_acc = 0
1477 for stat in stats:
1478 pkts_acc += stat.tx_packets
1479 bytes_acc += stat.tx_bytes
1480 return (pkts_acc, bytes_acc)
1481
1482 pkts_before, bytes_before = accumulate(initial)
1483
1484 # Wait 10s for counters to update
1485 pkt_diff = byte_diff = None
1486 for i in range(0, 100):
1487 stats = get_queue_stats(test, port_no, queue_id)
1488 pkts_after, bytes_after = accumulate(stats)
1489 pkt_diff = pkts_after - pkts_before
1490 byte_diff = bytes_after - bytes_before
1491 if (pkts == None or pkt_diff >= pkts) and \
1492 (bytes == None or byte_diff >= bytes):
1493 break
Dan Talayco53724732013-03-08 23:54:02 -08001494 time.sleep(0.1)
Rich Lane6a334922013-03-07 16:14:52 -08001495
1496 if pkts != None:
1497 test.assertEquals(pkt_diff, pkts, "Queue packet counter not updated properly (expected increase of %d, got increase of %d)" % (pkts, pkt_diff))
1498
1499 if bytes != None:
Rich Lane53b96812013-03-07 16:54:50 -08001500 test.assertTrue(byte_diff >= bytes and byte_diff <= bytes*1.1,
1501 "Queue byte counter not updated properly (expected increase of %d, got increase of %d)" % (bytes, byte_diff))
Rich Laneae3428c2013-03-07 14:37:42 -08001502
Rich Lane4c504f32013-06-07 17:24:14 -07001503def packet_in_match(msg, data, in_port=None, reason=None):
1504 """
1505 Check whether the packet_in message 'msg' has fields matching 'data',
1506 'in_port', and 'reason'.
1507
1508 This function handles truncated packet_in data. The 'in_port' and 'reason'
1509 parameters are optional.
1510
1511 @param msg packet_in message
1512 @param data Expected packet_in data
1513 @param in_port Expected packet_in in_port, or None
1514 @param reason Expected packet_in reason, or None
1515 """
1516
Rich Lanec0d26dd2013-07-10 12:46:03 -07001517 if ofp.OFP_VERSION <= 2:
1518 pkt_in_port = msg.in_port
1519 else:
1520 oxms = { type(oxm): oxm for oxm in msg.match.oxm_list }
1521 if ofp.oxm.in_port in oxms:
1522 pkt_in_port = oxms[ofp.oxm.in_port].value
1523 else:
1524 logging.warn("Missing in_port in packet-in message")
1525 pkt_in_port = None
1526
1527 if in_port != None and in_port != pkt_in_port:
Rich Lane9f2f17e2013-09-13 13:19:37 -07001528 logging.debug("Incorrect packet_in in_port (expected %d, received %d)", in_port, pkt_in_port)
Rich Lane4c504f32013-06-07 17:24:14 -07001529 return False
1530
Rich Lanec0d26dd2013-07-10 12:46:03 -07001531 if reason != None and reason != msg.reason:
Rich Lane4c504f32013-06-07 17:24:14 -07001532 logging.debug("Incorrect packet_in reason (expected %d, received %d)", reason, msg.reason)
1533 return False
1534
1535 # Check that one of the packets is a prefix of the other.
1536 # The received packet may be either truncated or padded, but not both.
1537 # (Some of the padding may be truncated but that's irrelevant). We
1538 # need to check that the smaller packet is a prefix of the larger one.
1539 # Note that this check succeeds if the switch sends a zero-length
1540 # packet-in.
1541 compare_len = min(len(msg.data), len(data))
1542 if data[:compare_len] != msg.data[:compare_len]:
1543 logging.debug("Incorrect packet_in data")
1544 logging.debug("Expected %s" % format_packet(data[:compare_len]))
1545 logging.debug("Received %s" % format_packet(msg.data[:compare_len]))
1546 return False
1547
1548 return True
1549
1550def verify_packet_in(test, data, in_port, reason, controller=None):
1551 """
1552 Assert that the controller receives a packet_in message matching data 'data'
1553 from port 'in_port' with reason 'reason'. Does not trigger the packet_in
1554 itself, that's up to the test case.
1555
1556 @param test Instance of base_tests.SimpleProtocol
1557 @param pkt String to expect as the packet_in data
1558 @param in_port OpenFlow port number to expect as the packet_in in_port
1559 @param reason One of OFPR_* to expect as the packet_in reason
1560 @param controller Controller instance, defaults to test.controller
1561 @returns The received packet-in message
1562 """
1563
1564 if controller == None:
1565 controller = test.controller
1566
1567 end_time = time.time() + oftest.ofutils.default_timeout
1568
1569 while True:
1570 msg, _ = controller.poll(ofp.OFPT_PACKET_IN, end_time - time.time())
1571 if not msg:
1572 # Timeout
1573 break
1574 elif packet_in_match(msg, data, in_port, reason):
1575 # Found a matching message
1576 break
1577
1578 test.assertTrue(msg is not None, 'Packet in message not received on port %d' % in_port)
1579 return msg
1580
1581def verify_no_packet_in(test, data, in_port, controller=None):
1582 """
1583 Assert that the controller does not receive a packet_in message matching
1584 data 'data' from port 'in_port'.
1585
1586 @param test Instance of base_tests.SimpleProtocol
1587 @param pkt String to expect as the packet_in data
1588 @param in_port OpenFlow port number to expect as the packet_in in_port
1589 @param controller Controller instance, defaults to test.controller
1590 """
1591
1592 if controller == None:
1593 controller = test.controller
1594
1595 # Negative test, need to wait a short amount of time before checking we
1596 # didn't receive the message.
1597 time.sleep(0.5)
1598
1599 # Check every packet_in queued in the controller
1600 while True:
1601 msg, _ = controller.poll(ofp.OFPT_PACKET_IN, timeout=0)
1602 if msg == None:
1603 # No more queued packet_in messages
1604 break
1605 elif packet_in_match(msg, data, in_port, None):
1606 # Found a matching message
1607 break
1608
Rich Lane82c882d2013-08-09 17:13:52 -07001609 if in_port == None:
1610 test.assertTrue(msg == None, "Did not expect a packet-in message on any port")
1611 else:
1612 test.assertTrue(msg == None, "Did not expect a packet-in message on port %d" % in_port)
Rich Lane4c504f32013-06-07 17:24:14 -07001613
Rich Lane045db072013-08-06 13:16:30 -07001614def openflow_ports(num=None):
1615 """
1616 Return a list of 'num' OpenFlow port numbers
1617
1618 If 'num' is None, return all available ports. Otherwise, limit the length
1619 of the result to 'num' and raise an exception if not enough ports are
1620 available.
1621 """
1622 ports = sorted(oftest.config["port_map"].keys())
1623 if num != None and len(ports) < num:
1624 raise Exception("test requires %d ports but only %d are available" % (num, len(ports)))
1625 return ports[:num]
1626
Rich Lanee4b384d2013-09-13 14:33:40 -07001627def verify_packet(test, pkt, ofport):
1628 """
1629 Check that an expected packet is received
1630 """
1631 logging.debug("Checking for pkt on port %r", ofport)
1632 (rcv_port, rcv_pkt, pkt_time) = test.dataplane.poll(port_number=ofport, exp_pkt=str(pkt))
1633 test.assertTrue(rcv_pkt != None, "Did not receive pkt on %r" % ofport)
1634
1635def verify_no_packet(test, pkt, ofport):
1636 """
1637 Check that a particular packet is not received
1638 """
1639 logging.debug("Negative check for pkt on port %r", ofport)
1640 (rcv_port, rcv_pkt, pkt_time) = test.dataplane.poll(port_number=ofport, exp_pkt=str(pkt), timeout=0.01)
1641 test.assertTrue(rcv_pkt == None, "Received packet on %r" % ofport)
1642
1643def verify_no_other_packets(test):
1644 """
1645 Check that no unexpected packets are received
1646
1647 This is a no-op if the --relax option is in effect.
1648 """
1649 if oftest.config["relax"]:
1650 return
1651 logging.debug("Checking for unexpected packets on all ports")
1652 (rcv_port, rcv_pkt, pkt_time) = test.dataplane.poll(timeout=0.01)
1653 if rcv_pkt != None:
1654 logging.debug("Received unexpected packet on port %r: %s", rcv_port, format_packet(rcv_pkt))
1655 test.assertTrue(rcv_pkt == None, "Unexpected packet on port %r" % rcv_port)
1656
1657def verify_packets(test, pkt, ofports):
1658 """
1659 Check that a packet is received on certain ports
1660
1661 Also verifies that the packet is not received on any other ports, and that no
1662 other packets are received (unless --relax is in effect).
1663
1664 This covers the common and simplest cases for checking dataplane outputs.
1665 For more complex usage, like multiple different packets being output, or
1666 multiple packets on the same port, use the primitive verify_packet,
1667 verify_no_packet, and verify_no_other_packets functions directly.
1668 """
1669 pkt = str(pkt)
1670 for ofport in openflow_ports():
1671 if ofport in ofports:
1672 verify_packet(test, pkt, ofport)
1673 else:
1674 verify_no_packet(test, pkt, ofport)
1675 verify_no_other_packets(test)
1676
1677
Rich Lane7744e112013-01-11 17:23:57 -08001678__all__ = list(set(locals()) - _import_blacklist)