blob: 45e5357bc81474ea44467ac5e4301dd08ce4432b [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
Wilson Ng42df57a2013-10-28 17:54:57 -0700973def test_param_get_table():
974 """
975 Return table_id to use.
976
977 The default table_id is 0.
978 This can be overridden by specifying "table" in --test-params.
979
980 e.g: --test-params table=1
981 """
982 return test_param_get("table", 0)
983
Dan Talayco4b2bee62010-07-20 14:10:05 -0700984def action_generate(parent, field_to_mod, mod_field_vals):
985 """
986 Create an action to modify the field indicated in field_to_mod
987
988 @param parent Must implement, assertTrue
989 @param field_to_mod The field to modify as a string name
990 @param mod_field_vals Hash of values to use for modified values
991 """
992
993 act = None
994
995 if field_to_mod in ['pktlen']:
996 return None
997
Rich Laned0478ff2013-03-11 12:46:58 -0700998 if field_to_mod == 'eth_dst':
Rich Lanee717c6e2013-03-12 10:25:50 -0700999 act = ofp.action.set_dl_dst()
Rich Lanef6883512013-03-11 17:00:09 -07001000 act.dl_addr = oftest.parse.parse_mac(mod_field_vals['eth_dst'])
Rich Laned0478ff2013-03-11 12:46:58 -07001001 elif field_to_mod == 'eth_src':
Rich Lanee717c6e2013-03-12 10:25:50 -07001002 act = ofp.action.set_dl_src()
Rich Lanef6883512013-03-11 17:00:09 -07001003 act.dl_addr = oftest.parse.parse_mac(mod_field_vals['eth_src'])
Dan Talayco4b2bee62010-07-20 14:10:05 -07001004 elif field_to_mod == 'dl_vlan_enable':
1005 if not mod_field_vals['dl_vlan_enable']: # Strip VLAN tag
Rich Lanee717c6e2013-03-12 10:25:50 -07001006 act = ofp.action.strip_vlan()
Rich Laned0478ff2013-03-11 12:46:58 -07001007 # Add VLAN tag is handled by vlan_vid field
Dan Talayco4b2bee62010-07-20 14:10:05 -07001008 # Will return None in this case
Rich Laned0478ff2013-03-11 12:46:58 -07001009 elif field_to_mod == 'vlan_vid':
Rich Lanee717c6e2013-03-12 10:25:50 -07001010 act = ofp.action.set_vlan_vid()
Rich Laned0478ff2013-03-11 12:46:58 -07001011 act.vlan_vid = mod_field_vals['vlan_vid']
1012 elif field_to_mod == 'vlan_pcp':
Rich Lanee717c6e2013-03-12 10:25:50 -07001013 act = ofp.action.set_vlan_pcp()
Rich Laned0478ff2013-03-11 12:46:58 -07001014 act.vlan_pcp = mod_field_vals['vlan_pcp']
Dan Talayco4b2bee62010-07-20 14:10:05 -07001015 elif field_to_mod == 'ip_src':
Rich Lanee717c6e2013-03-12 10:25:50 -07001016 act = ofp.action.set_nw_src()
Rich Lanef6883512013-03-11 17:00:09 -07001017 act.nw_addr = oftest.parse.parse_ip(mod_field_vals['ip_src'])
Dan Talayco4b2bee62010-07-20 14:10:05 -07001018 elif field_to_mod == 'ip_dst':
Rich Lanee717c6e2013-03-12 10:25:50 -07001019 act = ofp.action.set_nw_dst()
Rich Lanef6883512013-03-11 17:00:09 -07001020 act.nw_addr = oftest.parse.parse_ip(mod_field_vals['ip_dst'])
Dan Talayco4b2bee62010-07-20 14:10:05 -07001021 elif field_to_mod == 'ip_tos':
Rich Lanee717c6e2013-03-12 10:25:50 -07001022 act = ofp.action.set_nw_tos()
Dan Talayco4b2bee62010-07-20 14:10:05 -07001023 act.nw_tos = mod_field_vals['ip_tos']
1024 elif field_to_mod == 'tcp_sport':
Rich Lanee717c6e2013-03-12 10:25:50 -07001025 act = ofp.action.set_tp_src()
Dan Talayco4b2bee62010-07-20 14:10:05 -07001026 act.tp_port = mod_field_vals['tcp_sport']
1027 elif field_to_mod == 'tcp_dport':
Rich Lanee717c6e2013-03-12 10:25:50 -07001028 act = ofp.action.set_tp_dst()
Dan Talayco4b2bee62010-07-20 14:10:05 -07001029 act.tp_port = mod_field_vals['tcp_dport']
Rich Lane110e0e32012-10-26 16:21:46 -07001030 elif field_to_mod == 'udp_sport':
Rich Lanee717c6e2013-03-12 10:25:50 -07001031 act = ofp.action.set_tp_src()
Rich Lane110e0e32012-10-26 16:21:46 -07001032 act.tp_port = mod_field_vals['udp_sport']
1033 elif field_to_mod == 'udp_dport':
Rich Lanee717c6e2013-03-12 10:25:50 -07001034 act = ofp.action.set_tp_dst()
Rich Lane110e0e32012-10-26 16:21:46 -07001035 act.tp_port = mod_field_vals['udp_dport']
Dan Talayco4b2bee62010-07-20 14:10:05 -07001036 else:
1037 parent.assertTrue(0, "Unknown field to modify: " + str(field_to_mod))
1038
1039 return act
1040
1041def pkt_action_setup(parent, start_field_vals={}, mod_field_vals={},
Rich Lane110e0e32012-10-26 16:21:46 -07001042 mod_fields=[], tp="tcp", check_test_params=False):
Dan Talayco4b2bee62010-07-20 14:10:05 -07001043 """
1044 Set up the ingress and expected packet and action list for a test
1045
Rich Lane2014f9b2012-10-05 15:29:40 -07001046 @param parent Must implement assertTrue
Dan Talayco4b2bee62010-07-20 14:10:05 -07001047 @param start_field_values Field values to use for ingress packet (optional)
1048 @param mod_field_values Field values to use for modified packet (optional)
1049 @param mod_fields The list of fields to be modified by the switch in the test.
1050 @params check_test_params If True, will check the parameters vid, add_vlan
1051 and strip_vlan from the command line.
1052
1053 Returns a triple: pkt-to-send, expected-pkt, action-list
1054 """
1055
1056 new_actions = []
1057
Dan Talayco4b2bee62010-07-20 14:10:05 -07001058 base_pkt_params = {}
1059 base_pkt_params['pktlen'] = 100
Rich Laned0478ff2013-03-11 12:46:58 -07001060 base_pkt_params['eth_dst'] = '00:DE:F0:12:34:56'
1061 base_pkt_params['eth_src'] = '00:23:45:67:89:AB'
Dan Talayco4b2bee62010-07-20 14:10:05 -07001062 base_pkt_params['dl_vlan_enable'] = False
Rich Laned0478ff2013-03-11 12:46:58 -07001063 base_pkt_params['vlan_vid'] = 2
1064 base_pkt_params['vlan_pcp'] = 0
Dan Talayco4b2bee62010-07-20 14:10:05 -07001065 base_pkt_params['ip_src'] = '192.168.0.1'
1066 base_pkt_params['ip_dst'] = '192.168.0.2'
1067 base_pkt_params['ip_tos'] = 0
Rich Lane110e0e32012-10-26 16:21:46 -07001068 if tp == "tcp":
1069 base_pkt_params['tcp_sport'] = 1234
1070 base_pkt_params['tcp_dport'] = 80
1071 elif tp == "udp":
1072 base_pkt_params['udp_sport'] = 1234
1073 base_pkt_params['udp_dport'] = 80
Dan Talayco4b2bee62010-07-20 14:10:05 -07001074 for keyname in start_field_vals.keys():
1075 base_pkt_params[keyname] = start_field_vals[keyname]
1076
1077 mod_pkt_params = {}
1078 mod_pkt_params['pktlen'] = 100
Rich Laned0478ff2013-03-11 12:46:58 -07001079 mod_pkt_params['eth_dst'] = '00:21:0F:ED:CB:A9'
1080 mod_pkt_params['eth_src'] = '00:ED:CB:A9:87:65'
Dan Talayco4b2bee62010-07-20 14:10:05 -07001081 mod_pkt_params['dl_vlan_enable'] = False
Rich Laned0478ff2013-03-11 12:46:58 -07001082 mod_pkt_params['vlan_vid'] = 3
1083 mod_pkt_params['vlan_pcp'] = 7
Dan Talayco4b2bee62010-07-20 14:10:05 -07001084 mod_pkt_params['ip_src'] = '10.20.30.40'
1085 mod_pkt_params['ip_dst'] = '50.60.70.80'
1086 mod_pkt_params['ip_tos'] = 0xf0
Rich Lane110e0e32012-10-26 16:21:46 -07001087 if tp == "tcp":
1088 mod_pkt_params['tcp_sport'] = 4321
1089 mod_pkt_params['tcp_dport'] = 8765
1090 elif tp == "udp":
1091 mod_pkt_params['udp_sport'] = 4321
1092 mod_pkt_params['udp_dport'] = 8765
Dan Talayco4b2bee62010-07-20 14:10:05 -07001093 for keyname in mod_field_vals.keys():
1094 mod_pkt_params[keyname] = mod_field_vals[keyname]
1095
1096 # Check for test param modifications
1097 strip = False
1098 if check_test_params:
Rich Lane2014f9b2012-10-05 15:29:40 -07001099 add_vlan = test_param_get('add_vlan')
1100 strip_vlan = test_param_get('strip_vlan')
1101 vid = test_param_get('vid')
Dan Talayco4b2bee62010-07-20 14:10:05 -07001102
1103 if add_vlan and strip_vlan:
1104 parent.assertTrue(0, "Add and strip VLAN both specified")
1105
1106 if vid:
1107 base_pkt_params['dl_vlan_enable'] = True
Rich Laned0478ff2013-03-11 12:46:58 -07001108 base_pkt_params['vlan_vid'] = vid
1109 if 'vlan_vid' in mod_fields:
1110 mod_pkt_params['vlan_vid'] = vid + 1
Dan Talayco4b2bee62010-07-20 14:10:05 -07001111
1112 if add_vlan:
1113 base_pkt_params['dl_vlan_enable'] = False
1114 mod_pkt_params['dl_vlan_enable'] = True
1115 mod_pkt_params['pktlen'] = base_pkt_params['pktlen'] + 4
1116 mod_fields.append('pktlen')
1117 mod_fields.append('dl_vlan_enable')
Rich Laned0478ff2013-03-11 12:46:58 -07001118 if 'vlan_vid' not in mod_fields:
1119 mod_fields.append('vlan_vid')
Dan Talayco4b2bee62010-07-20 14:10:05 -07001120 elif strip_vlan:
1121 base_pkt_params['dl_vlan_enable'] = True
1122 mod_pkt_params['dl_vlan_enable'] = False
1123 mod_pkt_params['pktlen'] = base_pkt_params['pktlen'] - 4
1124 mod_fields.append('dl_vlan_enable')
1125 mod_fields.append('pktlen')
1126
Rich Lane110e0e32012-10-26 16:21:46 -07001127 if tp == "tcp":
1128 packet_builder = simple_tcp_packet
1129 elif tp == "udp":
1130 packet_builder = simple_udp_packet
1131 else:
1132 raise NotImplementedError("unknown transport protocol %s" % tp)
1133
Dan Talayco4b2bee62010-07-20 14:10:05 -07001134 # Build the ingress packet
Rich Lane110e0e32012-10-26 16:21:46 -07001135 ingress_pkt = packet_builder(**base_pkt_params)
Dan Talayco4b2bee62010-07-20 14:10:05 -07001136
1137 # Build the expected packet, modifying the indicated fields
1138 for item in mod_fields:
1139 base_pkt_params[item] = mod_pkt_params[item]
1140 act = action_generate(parent, item, mod_pkt_params)
1141 if act:
1142 new_actions.append(act)
1143
Rich Lane110e0e32012-10-26 16:21:46 -07001144 expected_pkt = packet_builder(**base_pkt_params)
Dan Talayco4b2bee62010-07-20 14:10:05 -07001145
1146 return (ingress_pkt, expected_pkt, new_actions)
Dan Talayco677c0b72011-08-23 22:53:38 -07001147
1148# Generate a simple "drop" flow mod
1149# If in_band is true, then only drop from first test port
1150def flow_mod_gen(port_map, in_band):
Rich Lanee717c6e2013-03-12 10:25:50 -07001151 request = ofp.message.flow_add()
1152 request.match.wildcards = ofp.OFPFW_ALL
Dan Talayco677c0b72011-08-23 22:53:38 -07001153 if in_band:
Rich Lanee717c6e2013-03-12 10:25:50 -07001154 request.match.wildcards = ofp.OFPFW_ALL - ofp.OFPFW_IN_PORT
Dan Talayco677c0b72011-08-23 22:53:38 -07001155 for of_port, ifname in port_map.items(): # Grab first port
1156 break
1157 request.match.in_port = of_port
1158 request.buffer_id = 0xffffffff
1159 return request
Dan Talaycoba3745c2010-07-21 21:51:08 -07001160
1161def skip_message_emit(parent, s):
1162 """
1163 Print out a 'skipped' message to stderr
1164
1165 @param s The string to print out to the log file
Dan Talaycoba3745c2010-07-21 21:51:08 -07001166 """
1167 global skipped_test_count
1168
1169 skipped_test_count += 1
Rich Lane9a003812012-10-04 17:17:59 -07001170 logging.info("Skipping: " + s)
Dan Talayco2940fdd2013-02-06 15:01:35 -08001171 if oftest.config["debug"] < logging.WARNING:
Dan Talaycoba3745c2010-07-21 21:51:08 -07001172 sys.stderr.write("(skipped) ")
1173 else:
1174 sys.stderr.write("(S)")
Dan Talayco677c0b72011-08-23 22:53:38 -07001175
Dan Talayco8a64e332012-03-28 14:53:20 -07001176
1177def all_stats_get(parent):
1178 """
1179 Get the aggregate stats for all flows in the table
1180 @param parent Test instance with controller connection and assert
1181 @returns dict with keys flows, packets, bytes, active (flows),
1182 lookups, matched
1183 """
Rich Lanee717c6e2013-03-12 10:25:50 -07001184 stat_req = ofp.message.aggregate_stats_request()
1185 stat_req.match = ofp.match()
1186 stat_req.match.wildcards = ofp.OFPFW_ALL
Dan Talayco8a64e332012-03-28 14:53:20 -07001187 stat_req.table_id = 0xff
Rich Lanee717c6e2013-03-12 10:25:50 -07001188 stat_req.out_port = ofp.OFPP_NONE
Dan Talayco8a64e332012-03-28 14:53:20 -07001189
1190 rv = {}
1191
Rich Lanec8aaa3e2012-07-26 19:28:02 -07001192 (reply, pkt) = parent.controller.transact(stat_req)
Rich Lane5fd6faf2013-03-11 13:30:20 -07001193 parent.assertTrue(len(reply.entries) == 1, "Did not receive flow stats reply")
Dan Talayco8a64e332012-03-28 14:53:20 -07001194
Rich Lane5fd6faf2013-03-11 13:30:20 -07001195 for obj in reply.entries:
Dan Talayco8a64e332012-03-28 14:53:20 -07001196 (rv["flows"], rv["packets"], rv["bytes"]) = (obj.flow_count,
1197 obj.packet_count, obj.byte_count)
1198 break
1199
Rich Lanee717c6e2013-03-12 10:25:50 -07001200 request = ofp.message.table_stats_request()
Rich Lanec8aaa3e2012-07-26 19:28:02 -07001201 (reply , pkt) = parent.controller.transact(request)
Dan Talayco8a64e332012-03-28 14:53:20 -07001202
1203
1204 (rv["active"], rv["lookups"], rv["matched"]) = (0,0,0)
Rich Lane5fd6faf2013-03-11 13:30:20 -07001205 for obj in reply.entries:
Dan Talayco8a64e332012-03-28 14:53:20 -07001206 rv["active"] += obj.active_count
1207 rv["lookups"] += obj.lookup_count
1208 rv["matched"] += obj.matched_count
1209
1210 return rv
Dan Talayco2baf8b52012-03-30 09:55:42 -07001211
Rich Lane7744e112013-01-11 17:23:57 -08001212_import_blacklist.add('FILTER')
Dan Talayco2baf8b52012-03-30 09:55:42 -07001213FILTER=''.join([(len(repr(chr(x)))==3) and chr(x) or '.'
1214 for x in range(256)])
1215
1216def hex_dump_buffer(src, length=16):
1217 """
1218 Convert src to a hex dump string and return the string
1219 @param src The source buffer
1220 @param length The number of bytes shown in each line
1221 @returns A string showing the hex dump
1222 """
Dan Talaycoc516fa02012-04-12 22:28:43 -07001223 result = ["\n"]
Dan Talayco2baf8b52012-03-30 09:55:42 -07001224 for i in xrange(0, len(src), length):
1225 chars = src[i:i+length]
1226 hex = ' '.join(["%02x" % ord(x) for x in chars])
1227 printable = ''.join(["%s" % ((ord(x) <= 127 and
1228 FILTER[ord(x)]) or '.') for x in chars])
1229 result.append("%04x %-*s %s\n" % (i, length*3, hex, printable))
1230 return ''.join(result)
1231
1232def format_packet(pkt):
1233 return "Packet length %d \n%s" % (len(str(pkt)),
1234 hex_dump_buffer(str(pkt)))
Rich Lane5d7e89a2012-10-26 16:43:13 -07001235
1236def inspect_packet(pkt):
1237 """
1238 Wrapper around scapy's show() method.
1239 @returns A string showing the dissected packet.
1240 """
1241 from cStringIO import StringIO
1242 out = None
1243 backup = sys.stdout
1244 try:
Rich Lanefdec0fb2013-08-09 18:01:05 -07001245 tmp = StringIO()
1246 sys.stdout = tmp
Rich Lane5d7e89a2012-10-26 16:43:13 -07001247 pkt.show2()
Rich Lanefdec0fb2013-08-09 18:01:05 -07001248 out = tmp.getvalue()
1249 tmp.close()
Rich Lane5d7e89a2012-10-26 16:43:13 -07001250 finally:
1251 sys.stdout = backup
1252 return out
Rich Lane0a4f6372013-01-02 14:40:22 -08001253
1254def nonstandard(cls):
1255 """
Rich Lanecc45b8e2013-01-02 15:55:02 -08001256 Testcase decorator that marks the test as being non-standard.
1257 These tests are not automatically added to the "standard" group.
Rich Lane0a4f6372013-01-02 14:40:22 -08001258 """
Rich Lanecc45b8e2013-01-02 15:55:02 -08001259 cls._nonstandard = True
Rich Lane0a4f6372013-01-02 14:40:22 -08001260 return cls
1261
1262def disabled(cls):
1263 """
Rich Lanecc45b8e2013-01-02 15:55:02 -08001264 Testcase decorator that marks the test as being disabled.
1265 These tests are not automatically added to the "standard" group or
1266 their module's group.
Rich Lane0a4f6372013-01-02 14:40:22 -08001267 """
Rich Lanecc45b8e2013-01-02 15:55:02 -08001268 cls._disabled = True
Rich Lane0a4f6372013-01-02 14:40:22 -08001269 return cls
Rich Lane97e99652013-01-02 17:23:20 -08001270
1271def group(name):
1272 """
1273 Testcase decorator that adds the test to a group.
1274 """
1275 def fn(cls):
1276 if not hasattr(cls, "_groups"):
1277 cls._groups = []
1278 cls._groups.append(name)
1279 return cls
1280 return fn
Rich Lane5a9a1922013-01-11 14:29:30 -08001281
1282def version(ver):
1283 """
1284 Testcase decorator that specifies which versions of OpenFlow the test
1285 supports. The default is 1.0+. This decorator may only be used once.
1286
1287 Supported syntax:
1288 1.0 -> 1.0
1289 1.0,1.2,1.3 -> 1.0, 1.2, 1.3
1290 1.0+ -> 1.0, 1.1, 1.2, 1.3
1291 """
1292 versions = parse_version(ver)
1293 def fn(cls):
1294 cls._versions = versions
1295 return cls
1296 return fn
1297
1298def parse_version(ver):
1299 allowed_versions = ["1.0", "1.1", "1.2", "1.3"]
1300 if re.match("^1\.\d+$", ver):
1301 versions = set([ver])
1302 elif re.match("^(1\.\d+)\+$", ver):
1303 if not ver[:-1] in allowed_versions:
1304 raise ValueError("invalid OpenFlow version %s" % ver[:-1])
1305 versions = set()
1306 if ver != "1.1+": versions.add("1.0")
1307 if ver != "1.2+": versions.add("1.1")
1308 if ver != "1.3+": versions.add("1.2")
1309 versions.add("1.3")
1310 else:
1311 versions = set(ver.split(','))
1312
1313 for version in versions:
1314 if not version in allowed_versions:
1315 raise ValueError("invalid OpenFlow version %s" % version)
1316
1317 return versions
1318
1319assert(parse_version("1.0") == set(["1.0"]))
1320assert(parse_version("1.0,1.2,1.3") == set(["1.0", "1.2", "1.3"]))
1321assert(parse_version("1.0+") == set(["1.0", "1.1", "1.2", "1.3"]))
Rich Lane7744e112013-01-11 17:23:57 -08001322
Rich Laneae3428c2013-03-07 14:37:42 -08001323def get_stats(test, req):
1324 """
1325 Retrieve a list of stats entries. Handles OFPSF_REPLY_MORE.
1326 """
Rich Lane609194f2013-10-21 06:17:37 -07001327 msgtype = ofp.OFPT_STATS_REPLY
1328 more_flag = ofp.OFPSF_REPLY_MORE
Rich Laneae3428c2013-03-07 14:37:42 -08001329 stats = []
1330 reply, _ = test.controller.transact(req)
1331 test.assertTrue(reply is not None, "No response to stats request")
Rich Lane34c68d52013-10-11 10:38:21 -07001332 test.assertEquals(reply.type, msgtype, "Response had unexpected message type")
Rich Lane5fd6faf2013-03-11 13:30:20 -07001333 stats.extend(reply.entries)
Rich Lanebd56ed62013-07-10 15:49:44 -07001334 while reply.flags & more_flag != 0:
Rich Lane34c68d52013-10-11 10:38:21 -07001335 reply, pkt = test.controller.poll(exp_msg=msgtype)
Rich Laneae3428c2013-03-07 14:37:42 -08001336 test.assertTrue(reply is not None, "No response to stats request")
Rich Lane5fd6faf2013-03-11 13:30:20 -07001337 stats.extend(reply.entries)
Rich Laneae3428c2013-03-07 14:37:42 -08001338 return stats
1339
Rich Lanebd56ed62013-07-10 15:49:44 -07001340def get_flow_stats(test, match, table_id=None,
1341 out_port=None, out_group=None,
1342 cookie=0, cookie_mask=0):
Rich Laneae3428c2013-03-07 14:37:42 -08001343 """
1344 Retrieve a list of flow stats entries.
1345 """
Rich Lanebd56ed62013-07-10 15:49:44 -07001346
1347 if table_id == None:
1348 if ofp.OFP_VERSION <= 2:
1349 table_id = 0xff
1350 else:
1351 table_id = ofp.OFPTT_ALL
1352
Rich Lanef3bc48c2013-05-03 17:39:35 -07001353 if out_port == None:
Rich Lanebd56ed62013-07-10 15:49:44 -07001354 if ofp.OFP_VERSION == 1:
1355 out_port = ofp.OFPP_NONE
1356 else:
1357 out_port = ofp.OFPP_ANY
1358
1359 if out_group == None:
1360 if ofp.OFP_VERSION > 1:
1361 out_group = ofp.OFPP_ANY
1362
Rich Lanee717c6e2013-03-12 10:25:50 -07001363 req = ofp.message.flow_stats_request(match=match,
Rich Lanebd56ed62013-07-10 15:49:44 -07001364 table_id=table_id,
1365 out_port=out_port)
1366 if ofp.OFP_VERSION > 1:
1367 req.out_group = out_group
1368 req.cookie = cookie
1369 req.cookie_mask = cookie_mask
1370
Rich Laneae3428c2013-03-07 14:37:42 -08001371 return get_stats(test, req)
1372
Rich Lane968b6192013-03-07 15:34:43 -08001373def get_port_stats(test, port_no):
1374 """
1375 Retrieve a list of port stats entries.
1376 """
Rich Lanee717c6e2013-03-12 10:25:50 -07001377 req = ofp.message.port_stats_request(port_no=port_no)
Rich Lane968b6192013-03-07 15:34:43 -08001378 return get_stats(test, req)
1379
Rich Lane6a334922013-03-07 16:14:52 -08001380def get_queue_stats(test, port_no, queue_id):
1381 """
1382 Retrieve a list of queue stats entries.
1383 """
Rich Lanee717c6e2013-03-12 10:25:50 -07001384 req = ofp.message.queue_stats_request(port_no=port_no, queue_id=queue_id)
Rich Lane6a334922013-03-07 16:14:52 -08001385 return get_stats(test, req)
1386
Rich Laneae3428c2013-03-07 14:37:42 -08001387def verify_flow_stats(test, match, table_id=0xff,
Rich Lanef3bc48c2013-05-03 17:39:35 -07001388 out_port=None,
Rich Laneae3428c2013-03-07 14:37:42 -08001389 initial=[],
1390 pkts=None, bytes=None):
1391 """
1392 Verify that flow stats changed as expected.
1393
1394 Optionally takes an 'initial' list of stats entries, as returned by
1395 get_flow_stats(). If 'initial' is not given the counters are assumed to
1396 begin at 0.
1397 """
Rich Lanef3bc48c2013-05-03 17:39:35 -07001398 if out_port == None:
1399 out_port = ofp.OFPP_NONE
1400
Rich Laneae3428c2013-03-07 14:37:42 -08001401 def accumulate(stats):
1402 pkts_acc = bytes_acc = 0
1403 for stat in stats:
1404 pkts_acc += stat.packet_count
1405 bytes_acc += stat.byte_count
1406 return (pkts_acc, bytes_acc)
1407
1408 pkts_before, bytes_before = accumulate(initial)
1409
1410 # Wait 10s for counters to update
1411 pkt_diff = byte_diff = None
1412 for i in range(0, 100):
1413 stats = get_flow_stats(test, match, table_id=table_id, out_port=out_port)
1414 pkts_after, bytes_after = accumulate(stats)
1415 pkt_diff = pkts_after - pkts_before
1416 byte_diff = bytes_after - bytes_before
1417 if (pkts == None or pkt_diff >= pkts) and \
1418 (bytes == None or byte_diff >= bytes):
1419 break
Dan Talayco53724732013-03-08 23:54:02 -08001420 time.sleep(0.1)
Rich Laneae3428c2013-03-07 14:37:42 -08001421
1422 if pkts != None:
1423 test.assertEquals(pkt_diff, pkts, "Flow packet counter not updated properly (expected increase of %d, got increase of %d)" % (pkts, pkt_diff))
1424
1425 if bytes != None:
Rich Lane53b96812013-03-07 16:54:50 -08001426 test.assertTrue(byte_diff >= bytes and byte_diff <= bytes*1.1,
1427 "Flow byte counter not updated properly (expected increase of %d, got increase of %d)" % (bytes, byte_diff))
Rich Laneae3428c2013-03-07 14:37:42 -08001428
Rich Lane968b6192013-03-07 15:34:43 -08001429def verify_port_stats(test, port,
1430 initial=[],
1431 tx_pkts=None, rx_pkts=None,
1432 tx_bytes=None, rx_bytes=None):
1433 """
1434 Verify that port stats changed as expected.
1435
1436 Optionally takes an 'initial' list of stats entries, as returned by
1437 get_port_stats(). If 'initial' is not given the counters are assumed to
1438 begin at 0.
1439 """
1440 def accumulate(stats):
1441 tx_pkts_acc = rx_pkts_acc = tx_bytes_acc = rx_bytes_acc = 0
1442 for stat in stats:
1443 tx_pkts_acc += stat.tx_packets
1444 rx_pkts_acc += stat.rx_packets
1445 tx_bytes_acc += stat.tx_bytes
1446 rx_bytes_acc += stat.rx_bytes
1447 return (tx_pkts_acc, rx_pkts_acc, tx_bytes_acc, rx_bytes_acc)
1448
1449 tx_pkts_before, rx_pkts_before, \
1450 tx_bytes_before, rx_bytes_before = accumulate(initial)
1451
1452 # Wait 10s for counters to update
1453 for i in range(0, 100):
1454 stats = get_port_stats(test, port)
1455 tx_pkts_after, rx_pkts_after, \
1456 tx_bytes_after, rx_bytes_after = accumulate(stats)
1457 tx_pkts_diff = tx_pkts_after - tx_pkts_before
1458 rx_pkts_diff = rx_pkts_after - rx_pkts_before
1459 tx_bytes_diff = tx_bytes_after - tx_bytes_before
1460 rx_bytes_diff = rx_bytes_after - rx_bytes_before
1461 if (tx_pkts == None or tx_pkts == tx_pkts_diff) and \
1462 (rx_pkts == None or rx_pkts == rx_pkts_diff) and \
Rich Lane53b96812013-03-07 16:54:50 -08001463 (tx_bytes == None or tx_bytes <= tx_bytes_diff) and \
1464 (rx_bytes == None or rx_bytes <= rx_bytes_diff):
Rich Lane968b6192013-03-07 15:34:43 -08001465 break
1466 time.sleep(0.1)
1467
1468 if (tx_pkts != None):
1469 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))
1470 if (rx_pkts != None):
1471 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))
1472 if (tx_bytes != None):
Rich Lane53b96812013-03-07 16:54:50 -08001473 test.assertTrue(tx_bytes_diff >= tx_bytes and tx_bytes_diff <= tx_bytes*1.1,
1474 "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 -08001475 if (rx_bytes != None):
Rich Lane53b96812013-03-07 16:54:50 -08001476 test.assertTrue(rx_bytes_diff >= rx_bytes and rx_bytes_diff <= rx_bytes*1.1,
1477 "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 -08001478
Rich Lane6a334922013-03-07 16:14:52 -08001479def verify_queue_stats(test, port_no, queue_id,
1480 initial=[],
1481 pkts=None, bytes=None):
1482 """
1483 Verify that queue stats changed as expected.
1484
1485 Optionally takes an 'initial' list of stats entries, as returned by
1486 get_queue_stats(). If 'initial' is not given the counters are assumed to
1487 begin at 0.
1488 """
1489 def accumulate(stats):
1490 pkts_acc = bytes_acc = 0
1491 for stat in stats:
1492 pkts_acc += stat.tx_packets
1493 bytes_acc += stat.tx_bytes
1494 return (pkts_acc, bytes_acc)
1495
1496 pkts_before, bytes_before = accumulate(initial)
1497
1498 # Wait 10s for counters to update
1499 pkt_diff = byte_diff = None
1500 for i in range(0, 100):
1501 stats = get_queue_stats(test, port_no, queue_id)
1502 pkts_after, bytes_after = accumulate(stats)
1503 pkt_diff = pkts_after - pkts_before
1504 byte_diff = bytes_after - bytes_before
1505 if (pkts == None or pkt_diff >= pkts) and \
1506 (bytes == None or byte_diff >= bytes):
1507 break
Dan Talayco53724732013-03-08 23:54:02 -08001508 time.sleep(0.1)
Rich Lane6a334922013-03-07 16:14:52 -08001509
1510 if pkts != None:
1511 test.assertEquals(pkt_diff, pkts, "Queue packet counter not updated properly (expected increase of %d, got increase of %d)" % (pkts, pkt_diff))
1512
1513 if bytes != None:
Rich Lane53b96812013-03-07 16:54:50 -08001514 test.assertTrue(byte_diff >= bytes and byte_diff <= bytes*1.1,
1515 "Queue byte counter not updated properly (expected increase of %d, got increase of %d)" % (bytes, byte_diff))
Rich Laneae3428c2013-03-07 14:37:42 -08001516
Rich Lane4c504f32013-06-07 17:24:14 -07001517def packet_in_match(msg, data, in_port=None, reason=None):
1518 """
1519 Check whether the packet_in message 'msg' has fields matching 'data',
1520 'in_port', and 'reason'.
1521
1522 This function handles truncated packet_in data. The 'in_port' and 'reason'
1523 parameters are optional.
1524
1525 @param msg packet_in message
1526 @param data Expected packet_in data
1527 @param in_port Expected packet_in in_port, or None
1528 @param reason Expected packet_in reason, or None
1529 """
1530
Rich Lanec0d26dd2013-07-10 12:46:03 -07001531 if ofp.OFP_VERSION <= 2:
1532 pkt_in_port = msg.in_port
1533 else:
1534 oxms = { type(oxm): oxm for oxm in msg.match.oxm_list }
1535 if ofp.oxm.in_port in oxms:
1536 pkt_in_port = oxms[ofp.oxm.in_port].value
1537 else:
1538 logging.warn("Missing in_port in packet-in message")
1539 pkt_in_port = None
1540
1541 if in_port != None and in_port != pkt_in_port:
Rich Lane9f2f17e2013-09-13 13:19:37 -07001542 logging.debug("Incorrect packet_in in_port (expected %d, received %d)", in_port, pkt_in_port)
Rich Lane4c504f32013-06-07 17:24:14 -07001543 return False
1544
Rich Lanec0d26dd2013-07-10 12:46:03 -07001545 if reason != None and reason != msg.reason:
Rich Lane4c504f32013-06-07 17:24:14 -07001546 logging.debug("Incorrect packet_in reason (expected %d, received %d)", reason, msg.reason)
1547 return False
1548
1549 # Check that one of the packets is a prefix of the other.
1550 # The received packet may be either truncated or padded, but not both.
1551 # (Some of the padding may be truncated but that's irrelevant). We
1552 # need to check that the smaller packet is a prefix of the larger one.
1553 # Note that this check succeeds if the switch sends a zero-length
1554 # packet-in.
1555 compare_len = min(len(msg.data), len(data))
1556 if data[:compare_len] != msg.data[:compare_len]:
1557 logging.debug("Incorrect packet_in data")
1558 logging.debug("Expected %s" % format_packet(data[:compare_len]))
1559 logging.debug("Received %s" % format_packet(msg.data[:compare_len]))
1560 return False
1561
1562 return True
1563
1564def verify_packet_in(test, data, in_port, reason, controller=None):
1565 """
1566 Assert that the controller receives a packet_in message matching data 'data'
1567 from port 'in_port' with reason 'reason'. Does not trigger the packet_in
1568 itself, that's up to the test case.
1569
1570 @param test Instance of base_tests.SimpleProtocol
1571 @param pkt String to expect as the packet_in data
1572 @param in_port OpenFlow port number to expect as the packet_in in_port
1573 @param reason One of OFPR_* to expect as the packet_in reason
1574 @param controller Controller instance, defaults to test.controller
1575 @returns The received packet-in message
1576 """
1577
1578 if controller == None:
1579 controller = test.controller
1580
1581 end_time = time.time() + oftest.ofutils.default_timeout
1582
1583 while True:
1584 msg, _ = controller.poll(ofp.OFPT_PACKET_IN, end_time - time.time())
1585 if not msg:
1586 # Timeout
1587 break
1588 elif packet_in_match(msg, data, in_port, reason):
1589 # Found a matching message
1590 break
1591
1592 test.assertTrue(msg is not None, 'Packet in message not received on port %d' % in_port)
1593 return msg
1594
1595def verify_no_packet_in(test, data, in_port, controller=None):
1596 """
1597 Assert that the controller does not receive a packet_in message matching
1598 data 'data' from port 'in_port'.
1599
1600 @param test Instance of base_tests.SimpleProtocol
1601 @param pkt String to expect as the packet_in data
1602 @param in_port OpenFlow port number to expect as the packet_in in_port
1603 @param controller Controller instance, defaults to test.controller
1604 """
1605
1606 if controller == None:
1607 controller = test.controller
1608
1609 # Negative test, need to wait a short amount of time before checking we
1610 # didn't receive the message.
1611 time.sleep(0.5)
1612
1613 # Check every packet_in queued in the controller
1614 while True:
1615 msg, _ = controller.poll(ofp.OFPT_PACKET_IN, timeout=0)
1616 if msg == None:
1617 # No more queued packet_in messages
1618 break
1619 elif packet_in_match(msg, data, in_port, None):
1620 # Found a matching message
1621 break
1622
Rich Lane82c882d2013-08-09 17:13:52 -07001623 if in_port == None:
1624 test.assertTrue(msg == None, "Did not expect a packet-in message on any port")
1625 else:
1626 test.assertTrue(msg == None, "Did not expect a packet-in message on port %d" % in_port)
Rich Lane4c504f32013-06-07 17:24:14 -07001627
Rich Lane045db072013-08-06 13:16:30 -07001628def openflow_ports(num=None):
1629 """
1630 Return a list of 'num' OpenFlow port numbers
1631
1632 If 'num' is None, return all available ports. Otherwise, limit the length
1633 of the result to 'num' and raise an exception if not enough ports are
1634 available.
1635 """
1636 ports = sorted(oftest.config["port_map"].keys())
1637 if num != None and len(ports) < num:
1638 raise Exception("test requires %d ports but only %d are available" % (num, len(ports)))
1639 return ports[:num]
1640
Rich Lanee4b384d2013-09-13 14:33:40 -07001641def verify_packet(test, pkt, ofport):
1642 """
1643 Check that an expected packet is received
1644 """
1645 logging.debug("Checking for pkt on port %r", ofport)
1646 (rcv_port, rcv_pkt, pkt_time) = test.dataplane.poll(port_number=ofport, exp_pkt=str(pkt))
1647 test.assertTrue(rcv_pkt != None, "Did not receive pkt on %r" % ofport)
1648
1649def verify_no_packet(test, pkt, ofport):
1650 """
1651 Check that a particular packet is not received
1652 """
1653 logging.debug("Negative check for pkt on port %r", ofport)
1654 (rcv_port, rcv_pkt, pkt_time) = test.dataplane.poll(port_number=ofport, exp_pkt=str(pkt), timeout=0.01)
1655 test.assertTrue(rcv_pkt == None, "Received packet on %r" % ofport)
1656
1657def verify_no_other_packets(test):
1658 """
1659 Check that no unexpected packets are received
1660
1661 This is a no-op if the --relax option is in effect.
1662 """
1663 if oftest.config["relax"]:
1664 return
1665 logging.debug("Checking for unexpected packets on all ports")
1666 (rcv_port, rcv_pkt, pkt_time) = test.dataplane.poll(timeout=0.01)
1667 if rcv_pkt != None:
1668 logging.debug("Received unexpected packet on port %r: %s", rcv_port, format_packet(rcv_pkt))
1669 test.assertTrue(rcv_pkt == None, "Unexpected packet on port %r" % rcv_port)
1670
1671def verify_packets(test, pkt, ofports):
1672 """
1673 Check that a packet is received on certain ports
1674
1675 Also verifies that the packet is not received on any other ports, and that no
1676 other packets are received (unless --relax is in effect).
1677
1678 This covers the common and simplest cases for checking dataplane outputs.
1679 For more complex usage, like multiple different packets being output, or
1680 multiple packets on the same port, use the primitive verify_packet,
1681 verify_no_packet, and verify_no_other_packets functions directly.
1682 """
1683 pkt = str(pkt)
1684 for ofport in openflow_ports():
1685 if ofport in ofports:
1686 verify_packet(test, pkt, ofport)
1687 else:
1688 verify_no_packet(test, pkt, ofport)
1689 verify_no_other_packets(test)
1690
Rich Lane12d04592013-10-10 17:21:07 -07001691def verify_no_errors(ctrl):
1692 error, _ = ctrl.poll(ofp.OFPT_ERROR, 0)
1693 if error:
1694 raise AssertionError("unexpected error type=%d code=%d" % (error.err_type, error.code))
Rich Lanee4b384d2013-09-13 14:33:40 -07001695
Rich Lane7744e112013-01-11 17:23:57 -08001696__all__ = list(set(locals()) - _import_blacklist)