blob: f6e72985a0d163e4acfd390556e7ed187d20bc66 [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
Rich Lane400fb9b2013-10-10 17:20:54 -0700747 if ofp.OFP_VERSION == 1:
748 actions = request.actions
749 else:
750 actions = []
751 request.instructions.append(ofp.instruction.apply_actions(actions))
752
Dan Talayco551befa2010-07-15 17:05:32 -0700753 if action_list is not None:
Rich Lane400fb9b2013-10-10 17:20:54 -0700754 actions.extend(action_list)
Dan Talayco551befa2010-07-15 17:05:32 -0700755
756 # Set up output/enqueue action if directed
757 if egr_queue is not None:
Dan Talaycof6e76c02012-03-23 10:56:12 -0700758 parent.assertTrue(egr_ports is not None, "Egress port not set")
Rich Lanee717c6e2013-03-12 10:25:50 -0700759 act = ofp.action.enqueue()
Dan Talaycof6e76c02012-03-23 10:56:12 -0700760 for egr_port in egr_port_list:
761 act.port = egr_port
762 act.queue_id = egr_queue
Rich Lane400fb9b2013-10-10 17:20:54 -0700763 actions.append(act)
Dan Talaycof6e76c02012-03-23 10:56:12 -0700764 elif egr_ports is not None:
765 for egr_port in egr_port_list:
Rich Lanee717c6e2013-03-12 10:25:50 -0700766 act = ofp.action.output()
Dan Talaycof6e76c02012-03-23 10:56:12 -0700767 act.port = egr_port
Rich Lane400fb9b2013-10-10 17:20:54 -0700768 actions.append(act)
Dan Talayco551befa2010-07-15 17:05:32 -0700769
Rich Lane9a003812012-10-04 17:17:59 -0700770 logging.debug(request.show())
Dan Talayco551befa2010-07-15 17:05:32 -0700771
772 return request
773
Jeffrey Townsendf3eae9c2012-03-28 18:23:21 -0700774def flow_msg_install(parent, request, clear_table_override=None):
Dan Talayco551befa2010-07-15 17:05:32 -0700775 """
776 Install a flow mod message in the switch
777
778 @param parent Must implement controller, assertEqual, assertTrue
779 @param request The request, all set to go
780 @param clear_table If true, clear the flow table before installing
781 """
Dan Talayco8a64e332012-03-28 14:53:20 -0700782
Rich Lane2014f9b2012-10-05 15:29:40 -0700783 clear_table = test_param_get('clear_table', default=True)
Jeffrey Townsendf3eae9c2012-03-28 18:23:21 -0700784 if(clear_table_override != None):
785 clear_table = clear_table_override
786
787 if clear_table:
Rich Lane9a003812012-10-04 17:17:59 -0700788 logging.debug("Clear flow table")
Rich Lane32bf9482013-01-03 17:26:30 -0800789 delete_all_flows(parent.controller)
Dan Talayco551befa2010-07-15 17:05:32 -0700790
Rich Lane9a003812012-10-04 17:17:59 -0700791 logging.debug("Insert flow")
Rich Lane5c3151c2013-01-03 17:15:41 -0800792 parent.controller.message_send(request)
Rich Lanee912d032012-12-22 14:28:33 -0800793
Rich Lane3a261d52013-01-03 17:45:08 -0800794 do_barrier(parent.controller)
Dan Talayco551befa2010-07-15 17:05:32 -0700795
Ed Swierk99a74de2012-08-22 06:40:54 -0700796def flow_match_test_port_pair(parent, ing_port, egr_ports, wildcards=None,
Rich Laned0478ff2013-03-11 12:46:58 -0700797 vlan_vid=-1, pkt=None, exp_pkt=None,
Rich Lanee5779d32012-10-05 17:56:04 -0700798 action_list=None):
Dan Talayco551befa2010-07-15 17:05:32 -0700799 """
800 Flow match test on single TCP packet
Dan Talaycof6e76c02012-03-23 10:56:12 -0700801 @param egr_ports A single port or list of ports
Dan Talayco551befa2010-07-15 17:05:32 -0700802
803 Run test with packet through switch from ing_port to egr_port
804 See flow_match_test for parameter descriptions
805 """
806
Ed Swierk99a74de2012-08-22 06:40:54 -0700807 if wildcards is None:
808 wildcards = required_wildcards(parent)
Rich Lane9a003812012-10-04 17:17:59 -0700809 logging.info("Pkt match test: " + str(ing_port) + " to " +
Dan Talaycof6e76c02012-03-23 10:56:12 -0700810 str(egr_ports))
Rich Laned0478ff2013-03-11 12:46:58 -0700811 logging.debug(" WC: " + hex(wildcards) + " vlan: " + str(vlan_vid))
Dan Talayco551befa2010-07-15 17:05:32 -0700812 if pkt is None:
Rich Laned0478ff2013-03-11 12:46:58 -0700813 pkt = simple_tcp_packet(dl_vlan_enable=(vlan_vid >= 0), vlan_vid=vlan_vid)
Rich Lanec41fbec2013-10-02 00:27:59 -0700814 if exp_pkt is None:
815 exp_pkt = pkt
Dan Talayco551befa2010-07-15 17:05:32 -0700816
817 request = flow_msg_create(parent, pkt, ing_port=ing_port,
Dan Talaycof6e76c02012-03-23 10:56:12 -0700818 wildcards=wildcards, egr_ports=egr_ports,
Dan Talayco551befa2010-07-15 17:05:32 -0700819 action_list=action_list)
820
821 flow_msg_install(parent, request)
822
Rich Lane9a003812012-10-04 17:17:59 -0700823 logging.debug("Send packet: " + str(ing_port) + " to " +
Dan Talaycof6e76c02012-03-23 10:56:12 -0700824 str(egr_ports))
Dan Talayco551befa2010-07-15 17:05:32 -0700825 parent.dataplane.send(ing_port, str(pkt))
826
Rich Lane8f45e2d2013-10-01 16:06:54 -0700827 exp_ports = [ing_port if port == ofp.OFPP_IN_PORT else port for port in egr_ports]
Rich Lanee4b384d2013-09-13 14:33:40 -0700828 verify_packets(parent, exp_pkt, exp_ports)
Dan Talayco551befa2010-07-15 17:05:32 -0700829
Rich Lane89725bb2012-12-03 16:23:27 -0800830def flow_match_test_pktout(parent, ing_port, egr_ports,
Rich Laned0478ff2013-03-11 12:46:58 -0700831 vlan_vid=-1, pkt=None, exp_pkt=None,
Rich Lane89725bb2012-12-03 16:23:27 -0800832 action_list=None):
833 """
834 Packet-out test on single TCP packet
835 @param egr_ports A single port or list of ports
836
837 Run test sending packet-out to egr_ports. The goal is to test the actions
838 taken on the packet, not the matching which is of course irrelevant.
839 See flow_match_test for parameter descriptions
840 """
841
842 if pkt is None:
Rich Laned0478ff2013-03-11 12:46:58 -0700843 pkt = simple_tcp_packet(dl_vlan_enable=(vlan_vid >= 0), vlan_vid=vlan_vid)
Rich Lanec41fbec2013-10-02 00:27:59 -0700844 if exp_pkt is None:
845 exp_pkt = pkt
Rich Lane89725bb2012-12-03 16:23:27 -0800846
Rich Lanee717c6e2013-03-12 10:25:50 -0700847 msg = ofp.message.packet_out()
Rich Lane89725bb2012-12-03 16:23:27 -0800848 msg.in_port = ing_port
Rich Laneea8c4722013-04-04 15:30:20 -0700849 msg.buffer_id = 0xffffffff
Rich Lane89725bb2012-12-03 16:23:27 -0800850 msg.data = str(pkt)
851 if action_list is not None:
852 for act in action_list:
Rich Lanec495d9e2013-03-08 17:43:36 -0800853 msg.actions.append(act)
Rich Lane89725bb2012-12-03 16:23:27 -0800854
855 # Set up output action
856 if egr_ports is not None:
857 for egr_port in egr_ports:
Rich Lanee717c6e2013-03-12 10:25:50 -0700858 act = ofp.action.output()
Rich Lane89725bb2012-12-03 16:23:27 -0800859 act.port = egr_port
Rich Lanec495d9e2013-03-08 17:43:36 -0800860 msg.actions.append(act)
Rich Lane89725bb2012-12-03 16:23:27 -0800861
862 logging.debug(msg.show())
Rich Lane5c3151c2013-01-03 17:15:41 -0800863 parent.controller.message_send(msg)
Rich Lane89725bb2012-12-03 16:23:27 -0800864
Rich Lane8f45e2d2013-10-01 16:06:54 -0700865 exp_ports = [ing_port if port == ofp.OFPP_IN_PORT else port for port in egr_ports]
Rich Lanee4b384d2013-09-13 14:33:40 -0700866 verify_packets(parent, exp_pkt, exp_ports)
Rich Lane89725bb2012-12-03 16:23:27 -0800867
Dan Talaycof6e76c02012-03-23 10:56:12 -0700868def get_egr_list(parent, of_ports, how_many, exclude_list=[]):
869 """
870 Generate a list of ports avoiding those in the exclude list
Rich Lane9a003812012-10-04 17:17:59 -0700871 @param parent Supplies logging
Dan Talaycof6e76c02012-03-23 10:56:12 -0700872 @param of_ports List of OF port numbers
873 @param how_many Number of ports to be added to the list
874 @param exclude_list List of ports not to be used
875 @returns An empty list if unable to find enough ports
876 """
877
Dan Talaycoc948d0b2012-03-23 12:17:54 -0700878 if how_many == 0:
879 return []
880
Dan Talaycof6e76c02012-03-23 10:56:12 -0700881 count = 0
882 egr_ports = []
883 for egr_idx in range(len(of_ports)):
884 if of_ports[egr_idx] not in exclude_list:
885 egr_ports.append(of_ports[egr_idx])
886 count += 1
887 if count >= how_many:
888 return egr_ports
Rich Lane9a003812012-10-04 17:17:59 -0700889 logging.debug("Could not generate enough egress ports for test")
Dan Talaycof6e76c02012-03-23 10:56:12 -0700890 return []
891
Rich Laned0478ff2013-03-11 12:46:58 -0700892def flow_match_test(parent, port_map, wildcards=None, vlan_vid=-1, pkt=None,
Rich Lanee5779d32012-10-05 17:56:04 -0700893 exp_pkt=None, action_list=None,
Dan Talaycoc948d0b2012-03-23 12:17:54 -0700894 max_test=0, egr_count=1, ing_port=False):
Dan Talayco551befa2010-07-15 17:05:32 -0700895 """
Rich Lane89725bb2012-12-03 16:23:27 -0800896 Run flow_match_test_port_pair on all port pairs and packet-out
Dan Talayco551befa2010-07-15 17:05:32 -0700897
898 @param max_test If > 0 no more than this number of tests are executed.
899 @param parent Must implement controller, dataplane, assertTrue, assertEqual
Rich Lane9a003812012-10-04 17:17:59 -0700900 and logging
Dan Talayco551befa2010-07-15 17:05:32 -0700901 @param pkt If not None, use this packet for ingress
902 @param wildcards For flow match entry
Rich Laned0478ff2013-03-11 12:46:58 -0700903 @param vlan_vid If not -1, and pkt is None, create a pkt w/ VLAN tag
Dan Talayco551befa2010-07-15 17:05:32 -0700904 @param exp_pkt If not None, use this as the expected output pkt; els use pkt
905 @param action_list Additional actions to add to flow mod
Dan Talaycocfa172f2012-03-23 12:03:00 -0700906 @param egr_count Number of egress ports; -1 means get from config w/ dflt 2
Dan Talayco551befa2010-07-15 17:05:32 -0700907 """
Ed Swierk99a74de2012-08-22 06:40:54 -0700908 if wildcards is None:
909 wildcards = required_wildcards(parent)
Dan Talayco551befa2010-07-15 17:05:32 -0700910 of_ports = port_map.keys()
911 of_ports.sort()
912 parent.assertTrue(len(of_ports) > 1, "Not enough ports for test")
913 test_count = 0
914
Dan Talaycocfa172f2012-03-23 12:03:00 -0700915 if egr_count == -1:
Rich Lane2014f9b2012-10-05 15:29:40 -0700916 egr_count = test_param_get('egr_count', default=2)
Dan Talaycocfa172f2012-03-23 12:03:00 -0700917
Dan Talayco551befa2010-07-15 17:05:32 -0700918 for ing_idx in range(len(of_ports)):
919 ingress_port = of_ports[ing_idx]
Dan Talaycof6e76c02012-03-23 10:56:12 -0700920 egr_ports = get_egr_list(parent, of_ports, egr_count,
921 exclude_list=[ingress_port])
Dan Talaycoc948d0b2012-03-23 12:17:54 -0700922 if ing_port:
Rich Lanee717c6e2013-03-12 10:25:50 -0700923 egr_ports.append(ofp.OFPP_IN_PORT)
Dan Talaycof6e76c02012-03-23 10:56:12 -0700924 if len(egr_ports) == 0:
925 parent.assertTrue(0, "Failed to generate egress port list")
926
927 flow_match_test_port_pair(parent, ingress_port, egr_ports,
Rich Laned0478ff2013-03-11 12:46:58 -0700928 wildcards=wildcards, vlan_vid=vlan_vid,
Dan Talaycof6e76c02012-03-23 10:56:12 -0700929 pkt=pkt, exp_pkt=exp_pkt,
Rich Lanee5779d32012-10-05 17:56:04 -0700930 action_list=action_list)
Dan Talaycof6e76c02012-03-23 10:56:12 -0700931 test_count += 1
932 if (max_test > 0) and (test_count > max_test):
Rich Lane9a003812012-10-04 17:17:59 -0700933 logging.info("Ran " + str(test_count) + " tests; exiting")
Rich Lane89725bb2012-12-03 16:23:27 -0800934 break
935
Ed Swierk38eea082013-01-02 19:46:20 -0800936 if not test_param_get('pktout_actions', default=True):
937 return
Rich Lane89725bb2012-12-03 16:23:27 -0800938
939 ingress_port = of_ports[0]
940 egr_ports = get_egr_list(parent, of_ports, egr_count,
941 exclude_list=[ingress_port])
942 if ing_port:
Rich Lanee717c6e2013-03-12 10:25:50 -0700943 egr_ports.append(ofp.OFPP_IN_PORT)
Rich Lane89725bb2012-12-03 16:23:27 -0800944 flow_match_test_pktout(parent, ingress_port, egr_ports,
Rich Laned0478ff2013-03-11 12:46:58 -0700945 vlan_vid=vlan_vid,
Rich Lane89725bb2012-12-03 16:23:27 -0800946 pkt=pkt, exp_pkt=exp_pkt,
947 action_list=action_list)
Dan Talayco551befa2010-07-15 17:05:32 -0700948
Rich Lane2014f9b2012-10-05 15:29:40 -0700949def test_param_get(key, default=None):
Dan Talayco4b2bee62010-07-20 14:10:05 -0700950 """
951 Return value passed via test-params if present
952
Dan Talayco4b2bee62010-07-20 14:10:05 -0700953 @param key The lookup key
954 @param default Default value to use if not found
955
956 If the pair 'key=val' appeared in the string passed to --test-params
957 on the command line, return val (as interpreted by exec). Otherwise
958 return default value.
Dan Talaycof6e76c02012-03-23 10:56:12 -0700959
960 WARNING: TEST PARAMETERS MUST BE PYTHON IDENTIFIERS;
961 eg egr_count, not egr-count.
Dan Talayco4b2bee62010-07-20 14:10:05 -0700962 """
963 try:
Rich Lanecd97d3d2013-01-07 18:50:06 -0800964 exec oftest.config["test_params"]
Dan Talayco4b2bee62010-07-20 14:10:05 -0700965 except:
966 return default
967
Dan Talayco4b2bee62010-07-20 14:10:05 -0700968 try:
Rich Lanefdec0fb2013-08-09 18:01:05 -0700969 return eval(str(key))
Dan Talayco4b2bee62010-07-20 14:10:05 -0700970 except:
971 return default
972
973def action_generate(parent, field_to_mod, mod_field_vals):
974 """
975 Create an action to modify the field indicated in field_to_mod
976
977 @param parent Must implement, assertTrue
978 @param field_to_mod The field to modify as a string name
979 @param mod_field_vals Hash of values to use for modified values
980 """
981
982 act = None
983
984 if field_to_mod in ['pktlen']:
985 return None
986
Rich Laned0478ff2013-03-11 12:46:58 -0700987 if field_to_mod == 'eth_dst':
Rich Lanee717c6e2013-03-12 10:25:50 -0700988 act = ofp.action.set_dl_dst()
Rich Lanef6883512013-03-11 17:00:09 -0700989 act.dl_addr = oftest.parse.parse_mac(mod_field_vals['eth_dst'])
Rich Laned0478ff2013-03-11 12:46:58 -0700990 elif field_to_mod == 'eth_src':
Rich Lanee717c6e2013-03-12 10:25:50 -0700991 act = ofp.action.set_dl_src()
Rich Lanef6883512013-03-11 17:00:09 -0700992 act.dl_addr = oftest.parse.parse_mac(mod_field_vals['eth_src'])
Dan Talayco4b2bee62010-07-20 14:10:05 -0700993 elif field_to_mod == 'dl_vlan_enable':
994 if not mod_field_vals['dl_vlan_enable']: # Strip VLAN tag
Rich Lanee717c6e2013-03-12 10:25:50 -0700995 act = ofp.action.strip_vlan()
Rich Laned0478ff2013-03-11 12:46:58 -0700996 # Add VLAN tag is handled by vlan_vid field
Dan Talayco4b2bee62010-07-20 14:10:05 -0700997 # Will return None in this case
Rich Laned0478ff2013-03-11 12:46:58 -0700998 elif field_to_mod == 'vlan_vid':
Rich Lanee717c6e2013-03-12 10:25:50 -0700999 act = ofp.action.set_vlan_vid()
Rich Laned0478ff2013-03-11 12:46:58 -07001000 act.vlan_vid = mod_field_vals['vlan_vid']
1001 elif field_to_mod == 'vlan_pcp':
Rich Lanee717c6e2013-03-12 10:25:50 -07001002 act = ofp.action.set_vlan_pcp()
Rich Laned0478ff2013-03-11 12:46:58 -07001003 act.vlan_pcp = mod_field_vals['vlan_pcp']
Dan Talayco4b2bee62010-07-20 14:10:05 -07001004 elif field_to_mod == 'ip_src':
Rich Lanee717c6e2013-03-12 10:25:50 -07001005 act = ofp.action.set_nw_src()
Rich Lanef6883512013-03-11 17:00:09 -07001006 act.nw_addr = oftest.parse.parse_ip(mod_field_vals['ip_src'])
Dan Talayco4b2bee62010-07-20 14:10:05 -07001007 elif field_to_mod == 'ip_dst':
Rich Lanee717c6e2013-03-12 10:25:50 -07001008 act = ofp.action.set_nw_dst()
Rich Lanef6883512013-03-11 17:00:09 -07001009 act.nw_addr = oftest.parse.parse_ip(mod_field_vals['ip_dst'])
Dan Talayco4b2bee62010-07-20 14:10:05 -07001010 elif field_to_mod == 'ip_tos':
Rich Lanee717c6e2013-03-12 10:25:50 -07001011 act = ofp.action.set_nw_tos()
Dan Talayco4b2bee62010-07-20 14:10:05 -07001012 act.nw_tos = mod_field_vals['ip_tos']
1013 elif field_to_mod == 'tcp_sport':
Rich Lanee717c6e2013-03-12 10:25:50 -07001014 act = ofp.action.set_tp_src()
Dan Talayco4b2bee62010-07-20 14:10:05 -07001015 act.tp_port = mod_field_vals['tcp_sport']
1016 elif field_to_mod == 'tcp_dport':
Rich Lanee717c6e2013-03-12 10:25:50 -07001017 act = ofp.action.set_tp_dst()
Dan Talayco4b2bee62010-07-20 14:10:05 -07001018 act.tp_port = mod_field_vals['tcp_dport']
Rich Lane110e0e32012-10-26 16:21:46 -07001019 elif field_to_mod == 'udp_sport':
Rich Lanee717c6e2013-03-12 10:25:50 -07001020 act = ofp.action.set_tp_src()
Rich Lane110e0e32012-10-26 16:21:46 -07001021 act.tp_port = mod_field_vals['udp_sport']
1022 elif field_to_mod == 'udp_dport':
Rich Lanee717c6e2013-03-12 10:25:50 -07001023 act = ofp.action.set_tp_dst()
Rich Lane110e0e32012-10-26 16:21:46 -07001024 act.tp_port = mod_field_vals['udp_dport']
Dan Talayco4b2bee62010-07-20 14:10:05 -07001025 else:
1026 parent.assertTrue(0, "Unknown field to modify: " + str(field_to_mod))
1027
1028 return act
1029
1030def pkt_action_setup(parent, start_field_vals={}, mod_field_vals={},
Rich Lane110e0e32012-10-26 16:21:46 -07001031 mod_fields=[], tp="tcp", check_test_params=False):
Dan Talayco4b2bee62010-07-20 14:10:05 -07001032 """
1033 Set up the ingress and expected packet and action list for a test
1034
Rich Lane2014f9b2012-10-05 15:29:40 -07001035 @param parent Must implement assertTrue
Dan Talayco4b2bee62010-07-20 14:10:05 -07001036 @param start_field_values Field values to use for ingress packet (optional)
1037 @param mod_field_values Field values to use for modified packet (optional)
1038 @param mod_fields The list of fields to be modified by the switch in the test.
1039 @params check_test_params If True, will check the parameters vid, add_vlan
1040 and strip_vlan from the command line.
1041
1042 Returns a triple: pkt-to-send, expected-pkt, action-list
1043 """
1044
1045 new_actions = []
1046
Dan Talayco4b2bee62010-07-20 14:10:05 -07001047 base_pkt_params = {}
1048 base_pkt_params['pktlen'] = 100
Rich Laned0478ff2013-03-11 12:46:58 -07001049 base_pkt_params['eth_dst'] = '00:DE:F0:12:34:56'
1050 base_pkt_params['eth_src'] = '00:23:45:67:89:AB'
Dan Talayco4b2bee62010-07-20 14:10:05 -07001051 base_pkt_params['dl_vlan_enable'] = False
Rich Laned0478ff2013-03-11 12:46:58 -07001052 base_pkt_params['vlan_vid'] = 2
1053 base_pkt_params['vlan_pcp'] = 0
Dan Talayco4b2bee62010-07-20 14:10:05 -07001054 base_pkt_params['ip_src'] = '192.168.0.1'
1055 base_pkt_params['ip_dst'] = '192.168.0.2'
1056 base_pkt_params['ip_tos'] = 0
Rich Lane110e0e32012-10-26 16:21:46 -07001057 if tp == "tcp":
1058 base_pkt_params['tcp_sport'] = 1234
1059 base_pkt_params['tcp_dport'] = 80
1060 elif tp == "udp":
1061 base_pkt_params['udp_sport'] = 1234
1062 base_pkt_params['udp_dport'] = 80
Dan Talayco4b2bee62010-07-20 14:10:05 -07001063 for keyname in start_field_vals.keys():
1064 base_pkt_params[keyname] = start_field_vals[keyname]
1065
1066 mod_pkt_params = {}
1067 mod_pkt_params['pktlen'] = 100
Rich Laned0478ff2013-03-11 12:46:58 -07001068 mod_pkt_params['eth_dst'] = '00:21:0F:ED:CB:A9'
1069 mod_pkt_params['eth_src'] = '00:ED:CB:A9:87:65'
Dan Talayco4b2bee62010-07-20 14:10:05 -07001070 mod_pkt_params['dl_vlan_enable'] = False
Rich Laned0478ff2013-03-11 12:46:58 -07001071 mod_pkt_params['vlan_vid'] = 3
1072 mod_pkt_params['vlan_pcp'] = 7
Dan Talayco4b2bee62010-07-20 14:10:05 -07001073 mod_pkt_params['ip_src'] = '10.20.30.40'
1074 mod_pkt_params['ip_dst'] = '50.60.70.80'
1075 mod_pkt_params['ip_tos'] = 0xf0
Rich Lane110e0e32012-10-26 16:21:46 -07001076 if tp == "tcp":
1077 mod_pkt_params['tcp_sport'] = 4321
1078 mod_pkt_params['tcp_dport'] = 8765
1079 elif tp == "udp":
1080 mod_pkt_params['udp_sport'] = 4321
1081 mod_pkt_params['udp_dport'] = 8765
Dan Talayco4b2bee62010-07-20 14:10:05 -07001082 for keyname in mod_field_vals.keys():
1083 mod_pkt_params[keyname] = mod_field_vals[keyname]
1084
1085 # Check for test param modifications
1086 strip = False
1087 if check_test_params:
Rich Lane2014f9b2012-10-05 15:29:40 -07001088 add_vlan = test_param_get('add_vlan')
1089 strip_vlan = test_param_get('strip_vlan')
1090 vid = test_param_get('vid')
Dan Talayco4b2bee62010-07-20 14:10:05 -07001091
1092 if add_vlan and strip_vlan:
1093 parent.assertTrue(0, "Add and strip VLAN both specified")
1094
1095 if vid:
1096 base_pkt_params['dl_vlan_enable'] = True
Rich Laned0478ff2013-03-11 12:46:58 -07001097 base_pkt_params['vlan_vid'] = vid
1098 if 'vlan_vid' in mod_fields:
1099 mod_pkt_params['vlan_vid'] = vid + 1
Dan Talayco4b2bee62010-07-20 14:10:05 -07001100
1101 if add_vlan:
1102 base_pkt_params['dl_vlan_enable'] = False
1103 mod_pkt_params['dl_vlan_enable'] = True
1104 mod_pkt_params['pktlen'] = base_pkt_params['pktlen'] + 4
1105 mod_fields.append('pktlen')
1106 mod_fields.append('dl_vlan_enable')
Rich Laned0478ff2013-03-11 12:46:58 -07001107 if 'vlan_vid' not in mod_fields:
1108 mod_fields.append('vlan_vid')
Dan Talayco4b2bee62010-07-20 14:10:05 -07001109 elif strip_vlan:
1110 base_pkt_params['dl_vlan_enable'] = True
1111 mod_pkt_params['dl_vlan_enable'] = False
1112 mod_pkt_params['pktlen'] = base_pkt_params['pktlen'] - 4
1113 mod_fields.append('dl_vlan_enable')
1114 mod_fields.append('pktlen')
1115
Rich Lane110e0e32012-10-26 16:21:46 -07001116 if tp == "tcp":
1117 packet_builder = simple_tcp_packet
1118 elif tp == "udp":
1119 packet_builder = simple_udp_packet
1120 else:
1121 raise NotImplementedError("unknown transport protocol %s" % tp)
1122
Dan Talayco4b2bee62010-07-20 14:10:05 -07001123 # Build the ingress packet
Rich Lane110e0e32012-10-26 16:21:46 -07001124 ingress_pkt = packet_builder(**base_pkt_params)
Dan Talayco4b2bee62010-07-20 14:10:05 -07001125
1126 # Build the expected packet, modifying the indicated fields
1127 for item in mod_fields:
1128 base_pkt_params[item] = mod_pkt_params[item]
1129 act = action_generate(parent, item, mod_pkt_params)
1130 if act:
1131 new_actions.append(act)
1132
Rich Lane110e0e32012-10-26 16:21:46 -07001133 expected_pkt = packet_builder(**base_pkt_params)
Dan Talayco4b2bee62010-07-20 14:10:05 -07001134
1135 return (ingress_pkt, expected_pkt, new_actions)
Dan Talayco677c0b72011-08-23 22:53:38 -07001136
1137# Generate a simple "drop" flow mod
1138# If in_band is true, then only drop from first test port
1139def flow_mod_gen(port_map, in_band):
Rich Lanee717c6e2013-03-12 10:25:50 -07001140 request = ofp.message.flow_add()
1141 request.match.wildcards = ofp.OFPFW_ALL
Dan Talayco677c0b72011-08-23 22:53:38 -07001142 if in_band:
Rich Lanee717c6e2013-03-12 10:25:50 -07001143 request.match.wildcards = ofp.OFPFW_ALL - ofp.OFPFW_IN_PORT
Dan Talayco677c0b72011-08-23 22:53:38 -07001144 for of_port, ifname in port_map.items(): # Grab first port
1145 break
1146 request.match.in_port = of_port
1147 request.buffer_id = 0xffffffff
1148 return request
Dan Talaycoba3745c2010-07-21 21:51:08 -07001149
1150def skip_message_emit(parent, s):
1151 """
1152 Print out a 'skipped' message to stderr
1153
1154 @param s The string to print out to the log file
Dan Talaycoba3745c2010-07-21 21:51:08 -07001155 """
1156 global skipped_test_count
1157
1158 skipped_test_count += 1
Rich Lane9a003812012-10-04 17:17:59 -07001159 logging.info("Skipping: " + s)
Dan Talayco2940fdd2013-02-06 15:01:35 -08001160 if oftest.config["debug"] < logging.WARNING:
Dan Talaycoba3745c2010-07-21 21:51:08 -07001161 sys.stderr.write("(skipped) ")
1162 else:
1163 sys.stderr.write("(S)")
Dan Talayco677c0b72011-08-23 22:53:38 -07001164
Dan Talayco8a64e332012-03-28 14:53:20 -07001165
1166def all_stats_get(parent):
1167 """
1168 Get the aggregate stats for all flows in the table
1169 @param parent Test instance with controller connection and assert
1170 @returns dict with keys flows, packets, bytes, active (flows),
1171 lookups, matched
1172 """
Rich Lanee717c6e2013-03-12 10:25:50 -07001173 stat_req = ofp.message.aggregate_stats_request()
1174 stat_req.match = ofp.match()
1175 stat_req.match.wildcards = ofp.OFPFW_ALL
Dan Talayco8a64e332012-03-28 14:53:20 -07001176 stat_req.table_id = 0xff
Rich Lanee717c6e2013-03-12 10:25:50 -07001177 stat_req.out_port = ofp.OFPP_NONE
Dan Talayco8a64e332012-03-28 14:53:20 -07001178
1179 rv = {}
1180
Rich Lanec8aaa3e2012-07-26 19:28:02 -07001181 (reply, pkt) = parent.controller.transact(stat_req)
Rich Lane5fd6faf2013-03-11 13:30:20 -07001182 parent.assertTrue(len(reply.entries) == 1, "Did not receive flow stats reply")
Dan Talayco8a64e332012-03-28 14:53:20 -07001183
Rich Lane5fd6faf2013-03-11 13:30:20 -07001184 for obj in reply.entries:
Dan Talayco8a64e332012-03-28 14:53:20 -07001185 (rv["flows"], rv["packets"], rv["bytes"]) = (obj.flow_count,
1186 obj.packet_count, obj.byte_count)
1187 break
1188
Rich Lanee717c6e2013-03-12 10:25:50 -07001189 request = ofp.message.table_stats_request()
Rich Lanec8aaa3e2012-07-26 19:28:02 -07001190 (reply , pkt) = parent.controller.transact(request)
Dan Talayco8a64e332012-03-28 14:53:20 -07001191
1192
1193 (rv["active"], rv["lookups"], rv["matched"]) = (0,0,0)
Rich Lane5fd6faf2013-03-11 13:30:20 -07001194 for obj in reply.entries:
Dan Talayco8a64e332012-03-28 14:53:20 -07001195 rv["active"] += obj.active_count
1196 rv["lookups"] += obj.lookup_count
1197 rv["matched"] += obj.matched_count
1198
1199 return rv
Dan Talayco2baf8b52012-03-30 09:55:42 -07001200
Rich Lane7744e112013-01-11 17:23:57 -08001201_import_blacklist.add('FILTER')
Dan Talayco2baf8b52012-03-30 09:55:42 -07001202FILTER=''.join([(len(repr(chr(x)))==3) and chr(x) or '.'
1203 for x in range(256)])
1204
1205def hex_dump_buffer(src, length=16):
1206 """
1207 Convert src to a hex dump string and return the string
1208 @param src The source buffer
1209 @param length The number of bytes shown in each line
1210 @returns A string showing the hex dump
1211 """
Dan Talaycoc516fa02012-04-12 22:28:43 -07001212 result = ["\n"]
Dan Talayco2baf8b52012-03-30 09:55:42 -07001213 for i in xrange(0, len(src), length):
1214 chars = src[i:i+length]
1215 hex = ' '.join(["%02x" % ord(x) for x in chars])
1216 printable = ''.join(["%s" % ((ord(x) <= 127 and
1217 FILTER[ord(x)]) or '.') for x in chars])
1218 result.append("%04x %-*s %s\n" % (i, length*3, hex, printable))
1219 return ''.join(result)
1220
1221def format_packet(pkt):
1222 return "Packet length %d \n%s" % (len(str(pkt)),
1223 hex_dump_buffer(str(pkt)))
Rich Lane5d7e89a2012-10-26 16:43:13 -07001224
1225def inspect_packet(pkt):
1226 """
1227 Wrapper around scapy's show() method.
1228 @returns A string showing the dissected packet.
1229 """
1230 from cStringIO import StringIO
1231 out = None
1232 backup = sys.stdout
1233 try:
Rich Lanefdec0fb2013-08-09 18:01:05 -07001234 tmp = StringIO()
1235 sys.stdout = tmp
Rich Lane5d7e89a2012-10-26 16:43:13 -07001236 pkt.show2()
Rich Lanefdec0fb2013-08-09 18:01:05 -07001237 out = tmp.getvalue()
1238 tmp.close()
Rich Lane5d7e89a2012-10-26 16:43:13 -07001239 finally:
1240 sys.stdout = backup
1241 return out
Rich Lane0a4f6372013-01-02 14:40:22 -08001242
1243def nonstandard(cls):
1244 """
Rich Lanecc45b8e2013-01-02 15:55:02 -08001245 Testcase decorator that marks the test as being non-standard.
1246 These tests are not automatically added to the "standard" group.
Rich Lane0a4f6372013-01-02 14:40:22 -08001247 """
Rich Lanecc45b8e2013-01-02 15:55:02 -08001248 cls._nonstandard = True
Rich Lane0a4f6372013-01-02 14:40:22 -08001249 return cls
1250
1251def disabled(cls):
1252 """
Rich Lanecc45b8e2013-01-02 15:55:02 -08001253 Testcase decorator that marks the test as being disabled.
1254 These tests are not automatically added to the "standard" group or
1255 their module's group.
Rich Lane0a4f6372013-01-02 14:40:22 -08001256 """
Rich Lanecc45b8e2013-01-02 15:55:02 -08001257 cls._disabled = True
Rich Lane0a4f6372013-01-02 14:40:22 -08001258 return cls
Rich Lane97e99652013-01-02 17:23:20 -08001259
1260def group(name):
1261 """
1262 Testcase decorator that adds the test to a group.
1263 """
1264 def fn(cls):
1265 if not hasattr(cls, "_groups"):
1266 cls._groups = []
1267 cls._groups.append(name)
1268 return cls
1269 return fn
Rich Lane5a9a1922013-01-11 14:29:30 -08001270
1271def version(ver):
1272 """
1273 Testcase decorator that specifies which versions of OpenFlow the test
1274 supports. The default is 1.0+. This decorator may only be used once.
1275
1276 Supported syntax:
1277 1.0 -> 1.0
1278 1.0,1.2,1.3 -> 1.0, 1.2, 1.3
1279 1.0+ -> 1.0, 1.1, 1.2, 1.3
1280 """
1281 versions = parse_version(ver)
1282 def fn(cls):
1283 cls._versions = versions
1284 return cls
1285 return fn
1286
1287def parse_version(ver):
1288 allowed_versions = ["1.0", "1.1", "1.2", "1.3"]
1289 if re.match("^1\.\d+$", ver):
1290 versions = set([ver])
1291 elif re.match("^(1\.\d+)\+$", ver):
1292 if not ver[:-1] in allowed_versions:
1293 raise ValueError("invalid OpenFlow version %s" % ver[:-1])
1294 versions = set()
1295 if ver != "1.1+": versions.add("1.0")
1296 if ver != "1.2+": versions.add("1.1")
1297 if ver != "1.3+": versions.add("1.2")
1298 versions.add("1.3")
1299 else:
1300 versions = set(ver.split(','))
1301
1302 for version in versions:
1303 if not version in allowed_versions:
1304 raise ValueError("invalid OpenFlow version %s" % version)
1305
1306 return versions
1307
1308assert(parse_version("1.0") == set(["1.0"]))
1309assert(parse_version("1.0,1.2,1.3") == set(["1.0", "1.2", "1.3"]))
1310assert(parse_version("1.0+") == set(["1.0", "1.1", "1.2", "1.3"]))
Rich Lane7744e112013-01-11 17:23:57 -08001311
Rich Laneae3428c2013-03-07 14:37:42 -08001312def get_stats(test, req):
1313 """
1314 Retrieve a list of stats entries. Handles OFPSF_REPLY_MORE.
1315 """
Rich Lanebd56ed62013-07-10 15:49:44 -07001316 if ofp.OFP_VERSION <= 3:
1317 more_flag = ofp.OFPSF_REPLY_MORE
1318 else:
1319 more_flag = ofp.OFPMPF_REPLY_MORE
Rich Laneae3428c2013-03-07 14:37:42 -08001320 stats = []
1321 reply, _ = test.controller.transact(req)
1322 test.assertTrue(reply is not None, "No response to stats request")
Rich Lane5fd6faf2013-03-11 13:30:20 -07001323 stats.extend(reply.entries)
Rich Lanebd56ed62013-07-10 15:49:44 -07001324 while reply.flags & more_flag != 0:
Rich Lane720eaf22013-08-09 18:00:45 -07001325 reply, pkt = test.controller.poll(exp_msg=ofp.OFPT_STATS_REPLY)
Rich Laneae3428c2013-03-07 14:37:42 -08001326 test.assertTrue(reply is not None, "No response to stats request")
Rich Lane5fd6faf2013-03-11 13:30:20 -07001327 stats.extend(reply.entries)
Rich Laneae3428c2013-03-07 14:37:42 -08001328 return stats
1329
Rich Lanebd56ed62013-07-10 15:49:44 -07001330def get_flow_stats(test, match, table_id=None,
1331 out_port=None, out_group=None,
1332 cookie=0, cookie_mask=0):
Rich Laneae3428c2013-03-07 14:37:42 -08001333 """
1334 Retrieve a list of flow stats entries.
1335 """
Rich Lanebd56ed62013-07-10 15:49:44 -07001336
1337 if table_id == None:
1338 if ofp.OFP_VERSION <= 2:
1339 table_id = 0xff
1340 else:
1341 table_id = ofp.OFPTT_ALL
1342
Rich Lanef3bc48c2013-05-03 17:39:35 -07001343 if out_port == None:
Rich Lanebd56ed62013-07-10 15:49:44 -07001344 if ofp.OFP_VERSION == 1:
1345 out_port = ofp.OFPP_NONE
1346 else:
1347 out_port = ofp.OFPP_ANY
1348
1349 if out_group == None:
1350 if ofp.OFP_VERSION > 1:
1351 out_group = ofp.OFPP_ANY
1352
Rich Lanee717c6e2013-03-12 10:25:50 -07001353 req = ofp.message.flow_stats_request(match=match,
Rich Lanebd56ed62013-07-10 15:49:44 -07001354 table_id=table_id,
1355 out_port=out_port)
1356 if ofp.OFP_VERSION > 1:
1357 req.out_group = out_group
1358 req.cookie = cookie
1359 req.cookie_mask = cookie_mask
1360
Rich Laneae3428c2013-03-07 14:37:42 -08001361 return get_stats(test, req)
1362
Rich Lane968b6192013-03-07 15:34:43 -08001363def get_port_stats(test, port_no):
1364 """
1365 Retrieve a list of port stats entries.
1366 """
Rich Lanee717c6e2013-03-12 10:25:50 -07001367 req = ofp.message.port_stats_request(port_no=port_no)
Rich Lane968b6192013-03-07 15:34:43 -08001368 return get_stats(test, req)
1369
Rich Lane6a334922013-03-07 16:14:52 -08001370def get_queue_stats(test, port_no, queue_id):
1371 """
1372 Retrieve a list of queue stats entries.
1373 """
Rich Lanee717c6e2013-03-12 10:25:50 -07001374 req = ofp.message.queue_stats_request(port_no=port_no, queue_id=queue_id)
Rich Lane6a334922013-03-07 16:14:52 -08001375 return get_stats(test, req)
1376
Rich Laneae3428c2013-03-07 14:37:42 -08001377def verify_flow_stats(test, match, table_id=0xff,
Rich Lanef3bc48c2013-05-03 17:39:35 -07001378 out_port=None,
Rich Laneae3428c2013-03-07 14:37:42 -08001379 initial=[],
1380 pkts=None, bytes=None):
1381 """
1382 Verify that flow stats changed as expected.
1383
1384 Optionally takes an 'initial' list of stats entries, as returned by
1385 get_flow_stats(). If 'initial' is not given the counters are assumed to
1386 begin at 0.
1387 """
Rich Lanef3bc48c2013-05-03 17:39:35 -07001388 if out_port == None:
1389 out_port = ofp.OFPP_NONE
1390
Rich Laneae3428c2013-03-07 14:37:42 -08001391 def accumulate(stats):
1392 pkts_acc = bytes_acc = 0
1393 for stat in stats:
1394 pkts_acc += stat.packet_count
1395 bytes_acc += stat.byte_count
1396 return (pkts_acc, bytes_acc)
1397
1398 pkts_before, bytes_before = accumulate(initial)
1399
1400 # Wait 10s for counters to update
1401 pkt_diff = byte_diff = None
1402 for i in range(0, 100):
1403 stats = get_flow_stats(test, match, table_id=table_id, out_port=out_port)
1404 pkts_after, bytes_after = accumulate(stats)
1405 pkt_diff = pkts_after - pkts_before
1406 byte_diff = bytes_after - bytes_before
1407 if (pkts == None or pkt_diff >= pkts) and \
1408 (bytes == None or byte_diff >= bytes):
1409 break
Dan Talayco53724732013-03-08 23:54:02 -08001410 time.sleep(0.1)
Rich Laneae3428c2013-03-07 14:37:42 -08001411
1412 if pkts != None:
1413 test.assertEquals(pkt_diff, pkts, "Flow packet counter not updated properly (expected increase of %d, got increase of %d)" % (pkts, pkt_diff))
1414
1415 if bytes != None:
Rich Lane53b96812013-03-07 16:54:50 -08001416 test.assertTrue(byte_diff >= bytes and byte_diff <= bytes*1.1,
1417 "Flow byte counter not updated properly (expected increase of %d, got increase of %d)" % (bytes, byte_diff))
Rich Laneae3428c2013-03-07 14:37:42 -08001418
Rich Lane968b6192013-03-07 15:34:43 -08001419def verify_port_stats(test, port,
1420 initial=[],
1421 tx_pkts=None, rx_pkts=None,
1422 tx_bytes=None, rx_bytes=None):
1423 """
1424 Verify that port stats changed as expected.
1425
1426 Optionally takes an 'initial' list of stats entries, as returned by
1427 get_port_stats(). If 'initial' is not given the counters are assumed to
1428 begin at 0.
1429 """
1430 def accumulate(stats):
1431 tx_pkts_acc = rx_pkts_acc = tx_bytes_acc = rx_bytes_acc = 0
1432 for stat in stats:
1433 tx_pkts_acc += stat.tx_packets
1434 rx_pkts_acc += stat.rx_packets
1435 tx_bytes_acc += stat.tx_bytes
1436 rx_bytes_acc += stat.rx_bytes
1437 return (tx_pkts_acc, rx_pkts_acc, tx_bytes_acc, rx_bytes_acc)
1438
1439 tx_pkts_before, rx_pkts_before, \
1440 tx_bytes_before, rx_bytes_before = accumulate(initial)
1441
1442 # Wait 10s for counters to update
1443 for i in range(0, 100):
1444 stats = get_port_stats(test, port)
1445 tx_pkts_after, rx_pkts_after, \
1446 tx_bytes_after, rx_bytes_after = accumulate(stats)
1447 tx_pkts_diff = tx_pkts_after - tx_pkts_before
1448 rx_pkts_diff = rx_pkts_after - rx_pkts_before
1449 tx_bytes_diff = tx_bytes_after - tx_bytes_before
1450 rx_bytes_diff = rx_bytes_after - rx_bytes_before
1451 if (tx_pkts == None or tx_pkts == tx_pkts_diff) and \
1452 (rx_pkts == None or rx_pkts == rx_pkts_diff) and \
Rich Lane53b96812013-03-07 16:54:50 -08001453 (tx_bytes == None or tx_bytes <= tx_bytes_diff) and \
1454 (rx_bytes == None or rx_bytes <= rx_bytes_diff):
Rich Lane968b6192013-03-07 15:34:43 -08001455 break
1456 time.sleep(0.1)
1457
1458 if (tx_pkts != None):
1459 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))
1460 if (rx_pkts != None):
1461 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))
1462 if (tx_bytes != None):
Rich Lane53b96812013-03-07 16:54:50 -08001463 test.assertTrue(tx_bytes_diff >= tx_bytes and tx_bytes_diff <= tx_bytes*1.1,
1464 "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 -08001465 if (rx_bytes != None):
Rich Lane53b96812013-03-07 16:54:50 -08001466 test.assertTrue(rx_bytes_diff >= rx_bytes and rx_bytes_diff <= rx_bytes*1.1,
1467 "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 -08001468
Rich Lane6a334922013-03-07 16:14:52 -08001469def verify_queue_stats(test, port_no, queue_id,
1470 initial=[],
1471 pkts=None, bytes=None):
1472 """
1473 Verify that queue stats changed as expected.
1474
1475 Optionally takes an 'initial' list of stats entries, as returned by
1476 get_queue_stats(). If 'initial' is not given the counters are assumed to
1477 begin at 0.
1478 """
1479 def accumulate(stats):
1480 pkts_acc = bytes_acc = 0
1481 for stat in stats:
1482 pkts_acc += stat.tx_packets
1483 bytes_acc += stat.tx_bytes
1484 return (pkts_acc, bytes_acc)
1485
1486 pkts_before, bytes_before = accumulate(initial)
1487
1488 # Wait 10s for counters to update
1489 pkt_diff = byte_diff = None
1490 for i in range(0, 100):
1491 stats = get_queue_stats(test, port_no, queue_id)
1492 pkts_after, bytes_after = accumulate(stats)
1493 pkt_diff = pkts_after - pkts_before
1494 byte_diff = bytes_after - bytes_before
1495 if (pkts == None or pkt_diff >= pkts) and \
1496 (bytes == None or byte_diff >= bytes):
1497 break
Dan Talayco53724732013-03-08 23:54:02 -08001498 time.sleep(0.1)
Rich Lane6a334922013-03-07 16:14:52 -08001499
1500 if pkts != None:
1501 test.assertEquals(pkt_diff, pkts, "Queue packet counter not updated properly (expected increase of %d, got increase of %d)" % (pkts, pkt_diff))
1502
1503 if bytes != None:
Rich Lane53b96812013-03-07 16:54:50 -08001504 test.assertTrue(byte_diff >= bytes and byte_diff <= bytes*1.1,
1505 "Queue byte counter not updated properly (expected increase of %d, got increase of %d)" % (bytes, byte_diff))
Rich Laneae3428c2013-03-07 14:37:42 -08001506
Rich Lane4c504f32013-06-07 17:24:14 -07001507def packet_in_match(msg, data, in_port=None, reason=None):
1508 """
1509 Check whether the packet_in message 'msg' has fields matching 'data',
1510 'in_port', and 'reason'.
1511
1512 This function handles truncated packet_in data. The 'in_port' and 'reason'
1513 parameters are optional.
1514
1515 @param msg packet_in message
1516 @param data Expected packet_in data
1517 @param in_port Expected packet_in in_port, or None
1518 @param reason Expected packet_in reason, or None
1519 """
1520
Rich Lanec0d26dd2013-07-10 12:46:03 -07001521 if ofp.OFP_VERSION <= 2:
1522 pkt_in_port = msg.in_port
1523 else:
1524 oxms = { type(oxm): oxm for oxm in msg.match.oxm_list }
1525 if ofp.oxm.in_port in oxms:
1526 pkt_in_port = oxms[ofp.oxm.in_port].value
1527 else:
1528 logging.warn("Missing in_port in packet-in message")
1529 pkt_in_port = None
1530
1531 if in_port != None and in_port != pkt_in_port:
Rich Lane9f2f17e2013-09-13 13:19:37 -07001532 logging.debug("Incorrect packet_in in_port (expected %d, received %d)", in_port, pkt_in_port)
Rich Lane4c504f32013-06-07 17:24:14 -07001533 return False
1534
Rich Lanec0d26dd2013-07-10 12:46:03 -07001535 if reason != None and reason != msg.reason:
Rich Lane4c504f32013-06-07 17:24:14 -07001536 logging.debug("Incorrect packet_in reason (expected %d, received %d)", reason, msg.reason)
1537 return False
1538
1539 # Check that one of the packets is a prefix of the other.
1540 # The received packet may be either truncated or padded, but not both.
1541 # (Some of the padding may be truncated but that's irrelevant). We
1542 # need to check that the smaller packet is a prefix of the larger one.
1543 # Note that this check succeeds if the switch sends a zero-length
1544 # packet-in.
1545 compare_len = min(len(msg.data), len(data))
1546 if data[:compare_len] != msg.data[:compare_len]:
1547 logging.debug("Incorrect packet_in data")
1548 logging.debug("Expected %s" % format_packet(data[:compare_len]))
1549 logging.debug("Received %s" % format_packet(msg.data[:compare_len]))
1550 return False
1551
1552 return True
1553
1554def verify_packet_in(test, data, in_port, reason, controller=None):
1555 """
1556 Assert that the controller receives a packet_in message matching data 'data'
1557 from port 'in_port' with reason 'reason'. Does not trigger the packet_in
1558 itself, that's up to the test case.
1559
1560 @param test Instance of base_tests.SimpleProtocol
1561 @param pkt String to expect as the packet_in data
1562 @param in_port OpenFlow port number to expect as the packet_in in_port
1563 @param reason One of OFPR_* to expect as the packet_in reason
1564 @param controller Controller instance, defaults to test.controller
1565 @returns The received packet-in message
1566 """
1567
1568 if controller == None:
1569 controller = test.controller
1570
1571 end_time = time.time() + oftest.ofutils.default_timeout
1572
1573 while True:
1574 msg, _ = controller.poll(ofp.OFPT_PACKET_IN, end_time - time.time())
1575 if not msg:
1576 # Timeout
1577 break
1578 elif packet_in_match(msg, data, in_port, reason):
1579 # Found a matching message
1580 break
1581
1582 test.assertTrue(msg is not None, 'Packet in message not received on port %d' % in_port)
1583 return msg
1584
1585def verify_no_packet_in(test, data, in_port, controller=None):
1586 """
1587 Assert that the controller does not receive a packet_in message matching
1588 data 'data' from port 'in_port'.
1589
1590 @param test Instance of base_tests.SimpleProtocol
1591 @param pkt String to expect as the packet_in data
1592 @param in_port OpenFlow port number to expect as the packet_in in_port
1593 @param controller Controller instance, defaults to test.controller
1594 """
1595
1596 if controller == None:
1597 controller = test.controller
1598
1599 # Negative test, need to wait a short amount of time before checking we
1600 # didn't receive the message.
1601 time.sleep(0.5)
1602
1603 # Check every packet_in queued in the controller
1604 while True:
1605 msg, _ = controller.poll(ofp.OFPT_PACKET_IN, timeout=0)
1606 if msg == None:
1607 # No more queued packet_in messages
1608 break
1609 elif packet_in_match(msg, data, in_port, None):
1610 # Found a matching message
1611 break
1612
Rich Lane82c882d2013-08-09 17:13:52 -07001613 if in_port == None:
1614 test.assertTrue(msg == None, "Did not expect a packet-in message on any port")
1615 else:
1616 test.assertTrue(msg == None, "Did not expect a packet-in message on port %d" % in_port)
Rich Lane4c504f32013-06-07 17:24:14 -07001617
Rich Lane045db072013-08-06 13:16:30 -07001618def openflow_ports(num=None):
1619 """
1620 Return a list of 'num' OpenFlow port numbers
1621
1622 If 'num' is None, return all available ports. Otherwise, limit the length
1623 of the result to 'num' and raise an exception if not enough ports are
1624 available.
1625 """
1626 ports = sorted(oftest.config["port_map"].keys())
1627 if num != None and len(ports) < num:
1628 raise Exception("test requires %d ports but only %d are available" % (num, len(ports)))
1629 return ports[:num]
1630
Rich Lanee4b384d2013-09-13 14:33:40 -07001631def verify_packet(test, pkt, ofport):
1632 """
1633 Check that an expected packet is received
1634 """
1635 logging.debug("Checking for pkt on port %r", ofport)
1636 (rcv_port, rcv_pkt, pkt_time) = test.dataplane.poll(port_number=ofport, exp_pkt=str(pkt))
1637 test.assertTrue(rcv_pkt != None, "Did not receive pkt on %r" % ofport)
1638
1639def verify_no_packet(test, pkt, ofport):
1640 """
1641 Check that a particular packet is not received
1642 """
1643 logging.debug("Negative check for pkt on port %r", ofport)
1644 (rcv_port, rcv_pkt, pkt_time) = test.dataplane.poll(port_number=ofport, exp_pkt=str(pkt), timeout=0.01)
1645 test.assertTrue(rcv_pkt == None, "Received packet on %r" % ofport)
1646
1647def verify_no_other_packets(test):
1648 """
1649 Check that no unexpected packets are received
1650
1651 This is a no-op if the --relax option is in effect.
1652 """
1653 if oftest.config["relax"]:
1654 return
1655 logging.debug("Checking for unexpected packets on all ports")
1656 (rcv_port, rcv_pkt, pkt_time) = test.dataplane.poll(timeout=0.01)
1657 if rcv_pkt != None:
1658 logging.debug("Received unexpected packet on port %r: %s", rcv_port, format_packet(rcv_pkt))
1659 test.assertTrue(rcv_pkt == None, "Unexpected packet on port %r" % rcv_port)
1660
1661def verify_packets(test, pkt, ofports):
1662 """
1663 Check that a packet is received on certain ports
1664
1665 Also verifies that the packet is not received on any other ports, and that no
1666 other packets are received (unless --relax is in effect).
1667
1668 This covers the common and simplest cases for checking dataplane outputs.
1669 For more complex usage, like multiple different packets being output, or
1670 multiple packets on the same port, use the primitive verify_packet,
1671 verify_no_packet, and verify_no_other_packets functions directly.
1672 """
1673 pkt = str(pkt)
1674 for ofport in openflow_ports():
1675 if ofport in ofports:
1676 verify_packet(test, pkt, ofport)
1677 else:
1678 verify_no_packet(test, pkt, ofport)
1679 verify_no_other_packets(test)
1680
1681
Rich Lane7744e112013-01-11 17:23:57 -08001682__all__ = list(set(locals()) - _import_blacklist)