blob: a7245fabc5480acdec66defef23f68a2ff83bd8d [file] [log] [blame]
Dan Talaycod2ca1032010-03-10 14:40:26 -08001import sys
Dan Talayco92c99122010-06-03 13:53:18 -07002import copy
Rich Lane6242d9f2013-01-06 17:35:39 -08003import logging
4import types
5import time
Rich Lane5a9a1922013-01-11 14:29:30 -08006import re
Rich Lanea68176f2013-08-09 17:41:05 -07007import packet as scapy
Dan Talayco41eae8b2010-03-10 13:57:06 -08008
Rich Lanecd97d3d2013-01-07 18:50:06 -08009import oftest
10import oftest.controller
11import oftest.dataplane
Rich Lanef6883512013-03-11 17:00:09 -070012import oftest.parse
Rich Lane4c504f32013-06-07 17:24:14 -070013import oftest.ofutils
Rich Lanee717c6e2013-03-12 10:25:50 -070014import ofp
Dan Talaycoc901f4d2010-03-07 21:55:45 -080015
Dan Talaycoba3745c2010-07-21 21:51:08 -070016global skipped_test_count
17skipped_test_count = 0
18
Rich Lane7744e112013-01-11 17:23:57 -080019_import_blacklist = set(locals().keys())
20
Dan Talayco551befa2010-07-15 17:05:32 -070021# Some useful defines
22IP_ETHERTYPE = 0x800
23TCP_PROTOCOL = 0x6
24UDP_PROTOCOL = 0x11
25
Jeffrey Townsend5cb7ed32012-08-17 18:11:01 +000026MINSIZE = 0
27
Rich Lane9a003812012-10-04 17:17:59 -070028def delete_all_flows(ctrl):
Dan Talayco41eae8b2010-03-10 13:57:06 -080029 """
30 Delete all flows on the switch
31 @param ctrl The controller object for the test
Dan Talayco41eae8b2010-03-10 13:57:06 -080032 """
33
Rich Lane9a003812012-10-04 17:17:59 -070034 logging.info("Deleting all flows")
Rich Lanee717c6e2013-03-12 10:25:50 -070035 msg = ofp.message.flow_delete()
Rich Lanec717f442013-06-13 15:49:09 -070036 if ofp.OFP_VERSION in [1, 2]:
37 msg.match.wildcards = ofp.OFPFW_ALL
38 msg.out_port = ofp.OFPP_NONE
39 msg.buffer_id = 0xffffffff
40 elif ofp.OFP_VERSION >= 3:
41 msg.table_id = ofp.OFPTT_ALL
42 msg.buffer_id = ofp.OFP_NO_BUFFER
43 msg.out_port = ofp.OFPP_ANY
44 msg.out_group = ofp.OFPG_ANY
Rich Lane5c3151c2013-01-03 17:15:41 -080045 ctrl.message_send(msg)
Rich Lane44c4e3f2013-07-08 10:17:49 -070046 do_barrier(ctrl)
Rich Lane32bf9482013-01-03 17:26:30 -080047 return 0 # for backwards compatibility
Dan Talayco41eae8b2010-03-10 13:57:06 -080048
Ed Swierk99a74de2012-08-22 06:40:54 -070049def required_wildcards(parent):
Rich Lane2014f9b2012-10-05 15:29:40 -070050 w = test_param_get('required_wildcards', default='default')
Ed Swierk99a74de2012-08-22 06:40:54 -070051 if w == 'l3-l4':
Rich Lanee717c6e2013-03-12 10:25:50 -070052 return (ofp.OFPFW_NW_SRC_ALL | ofp.OFPFW_NW_DST_ALL | ofp.OFPFW_NW_TOS
53 | ofp.OFPFW_NW_PROTO | ofp.OFPFW_TP_SRC | ofp.OFPFW_TP_DST)
Ed Swierk99a74de2012-08-22 06:40:54 -070054 else:
55 return 0
56
Dan Talayco41eae8b2010-03-10 13:57:06 -080057def simple_tcp_packet(pktlen=100,
Rich Laned0478ff2013-03-11 12:46:58 -070058 eth_dst='00:01:02:03:04:05',
59 eth_src='00:06:07:08:09:0a',
Tatsuya Yabe460321e2010-05-25 17:50:49 -070060 dl_vlan_enable=False,
Rich Laned0478ff2013-03-11 12:46:58 -070061 vlan_vid=0,
62 vlan_pcp=0,
Dan Talayco551befa2010-07-15 17:05:32 -070063 dl_vlan_cfi=0,
Dan Talayco41eae8b2010-03-10 13:57:06 -080064 ip_src='192.168.0.1',
65 ip_dst='192.168.0.2',
Tatsuya Yabe460321e2010-05-25 17:50:49 -070066 ip_tos=0,
Gregor Maier9cc93342013-01-29 16:55:28 -080067 ip_ttl=64,
Dan Talayco41eae8b2010-03-10 13:57:06 -080068 tcp_sport=1234,
Christian Dickmann8b59b4b2012-09-23 16:48:30 -070069 tcp_dport=80,
70 ip_ihl=None,
71 ip_options=False
Dan Talayco41eae8b2010-03-10 13:57:06 -080072 ):
73 """
74 Return a simple dataplane TCP packet
75
76 Supports a few parameters:
77 @param len Length of packet in bytes w/o CRC
Rich Laned0478ff2013-03-11 12:46:58 -070078 @param eth_dst Destinatino MAC
79 @param eth_src Source MAC
Tatsuya Yabe460321e2010-05-25 17:50:49 -070080 @param dl_vlan_enable True if the packet is with vlan, False otherwise
Rich Laned0478ff2013-03-11 12:46:58 -070081 @param vlan_vid VLAN ID
82 @param vlan_pcp VLAN priority
Dan Talayco41eae8b2010-03-10 13:57:06 -080083 @param ip_src IP source
84 @param ip_dst IP destination
Tatsuya Yabe460321e2010-05-25 17:50:49 -070085 @param ip_tos IP ToS
Gregor Maier9cc93342013-01-29 16:55:28 -080086 @param ip_ttl IP TTL
Dan Talayco41eae8b2010-03-10 13:57:06 -080087 @param tcp_dport TCP destination port
88 @param ip_sport TCP source port
89
90 Generates a simple TCP request. Users
91 shouldn't assume anything about this packet other than that
92 it is a valid ethernet/IP/TCP frame.
93 """
Jeffrey Townsend5cb7ed32012-08-17 18:11:01 +000094
95 if MINSIZE > pktlen:
96 pktlen = MINSIZE
97
Dan Talayco551befa2010-07-15 17:05:32 -070098 # Note Dot1Q.id is really CFI
Shudong Zhou43ee54c2012-12-13 15:52:37 -080099 if (dl_vlan_enable):
Rich Laned0478ff2013-03-11 12:46:58 -0700100 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
101 scapy.Dot1Q(prio=vlan_pcp, id=dl_vlan_cfi, vlan=vlan_vid)/ \
Gregor Maier9cc93342013-01-29 16:55:28 -0800102 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ttl=ip_ttl, ihl=ip_ihl)/ \
Tatsuya Yabe460321e2010-05-25 17:50:49 -0700103 scapy.TCP(sport=tcp_sport, dport=tcp_dport)
104 else:
Christian Dickmann8b59b4b2012-09-23 16:48:30 -0700105 if not ip_options:
Rich Laned0478ff2013-03-11 12:46:58 -0700106 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
Gregor Maier9cc93342013-01-29 16:55:28 -0800107 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ttl=ip_ttl, ihl=ip_ihl)/ \
Christian Dickmann8b59b4b2012-09-23 16:48:30 -0700108 scapy.TCP(sport=tcp_sport, dport=tcp_dport)
109 else:
Rich Laned0478ff2013-03-11 12:46:58 -0700110 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
Gregor Maier9cc93342013-01-29 16:55:28 -0800111 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ttl=ip_ttl, ihl=ip_ihl, options=ip_options)/ \
Christian Dickmann8b59b4b2012-09-23 16:48:30 -0700112 scapy.TCP(sport=tcp_sport, dport=tcp_dport)
Tatsuya Yabe460321e2010-05-25 17:50:49 -0700113
Dan Talayco41eae8b2010-03-10 13:57:06 -0800114 pkt = pkt/("D" * (pktlen - len(pkt)))
115
116 return pkt
117
Rich Lane86aceb02013-07-17 18:45:38 -0700118def simple_tcpv6_packet(pktlen=100,
119 eth_dst='00:01:02:03:04:05',
120 eth_src='00:06:07:08:09:0a',
121 dl_vlan_enable=False,
122 vlan_vid=0,
123 vlan_pcp=0,
124 ipv6_src='2001:db8:85a3::8a2e:370:7334',
125 ipv6_dst='2001:db8:85a3::8a2e:370:7335',
126 ipv6_tc=0,
127 ipv6_hlim=64,
128 ipv6_fl=0,
129 tcp_sport=1234,
130 tcp_dport=80):
131 """
132 Return a simple IPv6/TCP packet
133
134 Supports a few parameters:
135 @param len Length of packet in bytes w/o CRC
136 @param eth_dst Destination MAC
137 @param eth_src Source MAC
138 @param dl_vlan_enable True if the packet is with vlan, False otherwise
139 @param vlan_vid VLAN ID
140 @param vlan_pcp VLAN priority
141 @param ipv6_src IPv6 source
142 @param ipv6_dst IPv6 destination
143 @param ipv6_tc IPv6 traffic class
144 @param ipv6_ttl IPv6 hop limit
145 @param ipv6_fl IPv6 flow label
146 @param tcp_dport TCP destination port
147 @param tcp_sport TCP source port
148
149 Generates a simple TCP request. Users shouldn't assume anything about this
150 packet other than that it is a valid ethernet/IPv6/TCP frame.
151 """
152
153 if MINSIZE > pktlen:
154 pktlen = MINSIZE
155
156 pkt = scapy.Ether(dst=eth_dst, src=eth_src)
157 if dl_vlan_enable or vlan_vid or vlan_pcp:
158 pkt /= scapy.Dot1Q(vlan=vlan_vid, prio=vlan_pcp)
159 pkt /= scapy.IPv6(src=ipv6_src, dst=ipv6_dst, fl=ipv6_fl, tc=ipv6_tc, hlim=ipv6_hlim)
160 pkt /= scapy.TCP(sport=tcp_sport, dport=tcp_dport)
161 pkt /= ("D" * (pktlen - len(pkt)))
162
163 return pkt
164
Rich Lane6ee7bea2012-10-26 16:19:29 -0700165def simple_udp_packet(pktlen=100,
Rich Laned0478ff2013-03-11 12:46:58 -0700166 eth_dst='00:01:02:03:04:05',
167 eth_src='00:06:07:08:09:0a',
Rich Lane6ee7bea2012-10-26 16:19:29 -0700168 dl_vlan_enable=False,
Rich Laned0478ff2013-03-11 12:46:58 -0700169 vlan_vid=0,
170 vlan_pcp=0,
Rich Lane6ee7bea2012-10-26 16:19:29 -0700171 dl_vlan_cfi=0,
172 ip_src='192.168.0.1',
173 ip_dst='192.168.0.2',
174 ip_tos=0,
Gregor Maier9cc93342013-01-29 16:55:28 -0800175 ip_ttl=64,
Rich Lane6ee7bea2012-10-26 16:19:29 -0700176 udp_sport=1234,
177 udp_dport=80,
178 ip_ihl=None,
179 ip_options=False
180 ):
181 """
182 Return a simple dataplane UDP packet
183
184 Supports a few parameters:
185 @param len Length of packet in bytes w/o CRC
Rich Laned0478ff2013-03-11 12:46:58 -0700186 @param eth_dst Destination MAC
187 @param eth_src Source MAC
Rich Lane6ee7bea2012-10-26 16:19:29 -0700188 @param dl_vlan_enable True if the packet is with vlan, False otherwise
Rich Laned0478ff2013-03-11 12:46:58 -0700189 @param vlan_vid VLAN ID
190 @param vlan_pcp VLAN priority
Rich Lane6ee7bea2012-10-26 16:19:29 -0700191 @param ip_src IP source
192 @param ip_dst IP destination
193 @param ip_tos IP ToS
Gregor Maier9cc93342013-01-29 16:55:28 -0800194 @param ip_ttl IP TTL
Rich Lane6ee7bea2012-10-26 16:19:29 -0700195 @param udp_dport UDP destination port
196 @param udp_sport UDP source port
197
198 Generates a simple UDP packet. Users shouldn't assume anything about
199 this packet other than that it is a valid ethernet/IP/UDP frame.
200 """
201
202 if MINSIZE > pktlen:
203 pktlen = MINSIZE
204
205 # Note Dot1Q.id is really CFI
206 if (dl_vlan_enable):
Rich Laned0478ff2013-03-11 12:46:58 -0700207 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
208 scapy.Dot1Q(prio=vlan_pcp, id=dl_vlan_cfi, vlan=vlan_vid)/ \
Gregor Maier9cc93342013-01-29 16:55:28 -0800209 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ttl=ip_ttl, ihl=ip_ihl)/ \
Rich Lane6ee7bea2012-10-26 16:19:29 -0700210 scapy.UDP(sport=udp_sport, dport=udp_dport)
211 else:
212 if not ip_options:
Rich Laned0478ff2013-03-11 12:46:58 -0700213 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
Gregor Maier9cc93342013-01-29 16:55:28 -0800214 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ttl=ip_ttl, ihl=ip_ihl)/ \
Rich Lane6ee7bea2012-10-26 16:19:29 -0700215 scapy.UDP(sport=udp_sport, dport=udp_dport)
216 else:
Rich Laned0478ff2013-03-11 12:46:58 -0700217 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
Gregor Maier9cc93342013-01-29 16:55:28 -0800218 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ttl=ip_ttl, ihl=ip_ihl, options=ip_options)/ \
Rich Lane6ee7bea2012-10-26 16:19:29 -0700219 scapy.UDP(sport=udp_sport, dport=udp_dport)
220
221 pkt = pkt/("D" * (pktlen - len(pkt)))
222
223 return pkt
224
Rich Lane86aceb02013-07-17 18:45:38 -0700225def simple_udpv6_packet(pktlen=100,
226 eth_dst='00:01:02:03:04:05',
227 eth_src='00:06:07:08:09:0a',
228 dl_vlan_enable=False,
229 vlan_vid=0,
230 vlan_pcp=0,
231 ipv6_src='2001:db8:85a3::8a2e:370:7334',
232 ipv6_dst='2001:db8:85a3::8a2e:370:7335',
233 ipv6_tc=0,
234 ipv6_hlim=64,
235 ipv6_fl=0,
236 udp_sport=1234,
237 udp_dport=80):
238 """
239 Return a simple IPv6/UDP packet
240
241 Supports a few parameters:
242 @param len Length of packet in bytes w/o CRC
243 @param eth_dst Destination MAC
244 @param eth_src Source MAC
245 @param dl_vlan_enable True if the packet is with vlan, False otherwise
246 @param vlan_vid VLAN ID
247 @param vlan_pcp VLAN priority
248 @param ipv6_src IPv6 source
249 @param ipv6_dst IPv6 destination
250 @param ipv6_tc IPv6 traffic class
251 @param ipv6_ttl IPv6 hop limit
252 @param ipv6_fl IPv6 flow label
253 @param udp_dport UDP destination port
254 @param udp_sport UDP source port
255
256 Generates a simple UDP request. Users shouldn't assume anything about this
257 packet other than that it is a valid ethernet/IPv6/UDP frame.
258 """
259
260 if MINSIZE > pktlen:
261 pktlen = MINSIZE
262
263 pkt = scapy.Ether(dst=eth_dst, src=eth_src)
264 if dl_vlan_enable or vlan_vid or vlan_pcp:
265 pkt /= scapy.Dot1Q(vlan=vlan_vid, prio=vlan_pcp)
266 pkt /= scapy.IPv6(src=ipv6_src, dst=ipv6_dst, fl=ipv6_fl, tc=ipv6_tc, hlim=ipv6_hlim)
267 pkt /= scapy.UDP(sport=udp_sport, dport=udp_dport)
268 pkt /= ("D" * (pktlen - len(pkt)))
269
270 return pkt
271
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700272def simple_icmp_packet(pktlen=60,
Rich Laned0478ff2013-03-11 12:46:58 -0700273 eth_dst='00:01:02:03:04:05',
274 eth_src='00:06:07:08:09:0a',
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700275 dl_vlan_enable=False,
Rich Laned0478ff2013-03-11 12:46:58 -0700276 vlan_vid=0,
277 vlan_pcp=0,
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700278 ip_src='192.168.0.1',
279 ip_dst='192.168.0.2',
280 ip_tos=0,
Gregor Maier9cc93342013-01-29 16:55:28 -0800281 ip_ttl=64,
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700282 icmp_type=8,
283 icmp_code=0
284 ):
285 """
286 Return a simple ICMP packet
287
288 Supports a few parameters:
289 @param len Length of packet in bytes w/o CRC
Rich Laned0478ff2013-03-11 12:46:58 -0700290 @param eth_dst Destinatino MAC
291 @param eth_src Source MAC
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700292 @param dl_vlan_enable True if the packet is with vlan, False otherwise
Rich Laned0478ff2013-03-11 12:46:58 -0700293 @param vlan_vid VLAN ID
294 @param vlan_pcp VLAN priority
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700295 @param ip_src IP source
296 @param ip_dst IP destination
297 @param ip_tos IP ToS
Gregor Maier9cc93342013-01-29 16:55:28 -0800298 @param ip_ttl IP TTL
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700299 @param icmp_type ICMP type
300 @param icmp_code ICMP code
301
302 Generates a simple ICMP ECHO REQUEST. Users
303 shouldn't assume anything about this packet other than that
304 it is a valid ethernet/ICMP frame.
305 """
Jeffrey Townsend5cb7ed32012-08-17 18:11:01 +0000306
307 if MINSIZE > pktlen:
308 pktlen = MINSIZE
309
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700310 if (dl_vlan_enable):
Rich Laned0478ff2013-03-11 12:46:58 -0700311 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
312 scapy.Dot1Q(prio=vlan_pcp, id=0, vlan=vlan_vid)/ \
Gregor Maier9cc93342013-01-29 16:55:28 -0800313 scapy.IP(src=ip_src, dst=ip_dst, ttl=ip_ttl, tos=ip_tos)/ \
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700314 scapy.ICMP(type=icmp_type, code=icmp_code)
315 else:
Rich Laned0478ff2013-03-11 12:46:58 -0700316 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
Gregor Maier9cc93342013-01-29 16:55:28 -0800317 scapy.IP(src=ip_src, dst=ip_dst, ttl=ip_ttl, tos=ip_tos)/ \
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700318 scapy.ICMP(type=icmp_type, code=icmp_code)
319
320 pkt = pkt/("0" * (pktlen - len(pkt)))
321
322 return pkt
323
Rich Lane86aceb02013-07-17 18:45:38 -0700324def simple_icmpv6_packet(pktlen=100,
325 eth_dst='00:01:02:03:04:05',
326 eth_src='00:06:07:08:09:0a',
327 dl_vlan_enable=False,
328 vlan_vid=0,
329 vlan_pcp=0,
330 ipv6_src='2001:db8:85a3::8a2e:370:7334',
331 ipv6_dst='2001:db8:85a3::8a2e:370:7335',
332 ipv6_tc=0,
333 ipv6_hlim=64,
334 ipv6_fl=0,
335 icmp_type=8,
336 icmp_code=0):
337 """
338 Return a simple ICMPv6 packet
339
340 Supports a few parameters:
341 @param len Length of packet in bytes w/o CRC
342 @param eth_dst Destination MAC
343 @param eth_src Source MAC
344 @param dl_vlan_enable True if the packet is with vlan, False otherwise
345 @param vlan_vid VLAN ID
346 @param vlan_pcp VLAN priority
347 @param ipv6_src IPv6 source
348 @param ipv6_dst IPv6 destination
349 @param ipv6_tc IPv6 traffic class
350 @param ipv6_ttl IPv6 hop limit
351 @param ipv6_fl IPv6 flow label
352 @param icmp_type ICMP type
353 @param icmp_code ICMP code
354
355 Generates a simple ICMP ECHO REQUEST. Users shouldn't assume anything
356 about this packet other than that it is a valid ethernet/IPv6/ICMP frame.
357 """
358
359 if MINSIZE > pktlen:
360 pktlen = MINSIZE
361
362 pkt = scapy.Ether(dst=eth_dst, src=eth_src)
363 if dl_vlan_enable or vlan_vid or vlan_pcp:
364 pkt /= scapy.Dot1Q(vlan=vlan_vid, prio=vlan_pcp)
365 pkt /= scapy.IPv6(src=ipv6_src, dst=ipv6_dst, fl=ipv6_fl, tc=ipv6_tc, hlim=ipv6_hlim)
366 pkt /= scapy.ICMPv6Unknown(type=icmp_type, code=icmp_code)
367 pkt /= ("D" * (pktlen - len(pkt)))
368
369 return pkt
370
Shudong Zhouc7562b12013-02-06 01:12:18 -0800371def simple_arp_packet(pktlen=60,
Rich Laned0478ff2013-03-11 12:46:58 -0700372 eth_dst='ff:ff:ff:ff:ff:ff',
373 eth_src='00:06:07:08:09:0a',
Shudong Zhouc7562b12013-02-06 01:12:18 -0800374 arp_op=1,
375 ip_snd='192.168.0.1',
376 ip_tgt='192.168.0.2',
377 hw_snd='00:06:07:08:09:0a',
378 hw_tgt='00:00:00:00:00:00',
379 ):
380 """
381 Return a simple ARP packet
382
383 Supports a few parameters:
384 @param len Length of packet in bytes w/o CRC
Rich Laned0478ff2013-03-11 12:46:58 -0700385 @param eth_dst Destinatino MAC
386 @param eth_src Source MAC
Shudong Zhouc7562b12013-02-06 01:12:18 -0800387 @param arp_op Operation (1=request, 2=reply)
388 @param ip_snd Sender IP
389 @param ip_tgt Target IP
390 @param hw_snd Sender hardware address
391 @param hw_tgt Target hardware address
392
393 Generates a simple ARP REQUEST. Users
394 shouldn't assume anything about this packet other than that
395 it is a valid ethernet/ARP frame.
396 """
397
398 if MINSIZE > pktlen:
399 pktlen = MINSIZE
400
Rich Laned0478ff2013-03-11 12:46:58 -0700401 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
Shudong Zhouc7562b12013-02-06 01:12:18 -0800402 scapy.ARP(hwsrc=hw_snd, hwdst=hw_tgt, pdst=ip_tgt, psrc=ip_snd, op=arp_op)
403
404 pkt = pkt/("0" * (pktlen - len(pkt)))
405
406 return pkt
407
Ed Swierk0aeff8c2012-03-23 20:27:18 -0700408def simple_eth_packet(pktlen=60,
Rich Laneb7dc3e22013-08-02 13:51:06 -0700409 eth_dst='01:80:c2:00:00:00',
410 eth_src='00:01:02:03:04:05',
Rich Laned0478ff2013-03-11 12:46:58 -0700411 eth_type=0x88cc):
Jeffrey Townsend5cb7ed32012-08-17 18:11:01 +0000412
413 if MINSIZE > pktlen:
414 pktlen = MINSIZE
415
Rich Laned0478ff2013-03-11 12:46:58 -0700416 pkt = scapy.Ether(dst=eth_dst, src=eth_src, type=eth_type)
Ed Swierk0aeff8c2012-03-23 20:27:18 -0700417
418 pkt = pkt/("0" * (pktlen - len(pkt)))
419
420 return pkt
421
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800422def qinq_tcp_packet(pktlen=100,
Rich Laned0478ff2013-03-11 12:46:58 -0700423 eth_dst='00:01:02:03:04:05',
424 eth_src='00:06:07:08:09:0a',
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800425 dl_vlan_outer=20,
426 dl_vlan_pcp_outer=0,
427 dl_vlan_cfi_outer=0,
Rich Laned0478ff2013-03-11 12:46:58 -0700428 vlan_vid=10,
429 vlan_pcp=0,
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800430 dl_vlan_cfi=0,
431 ip_src='192.168.0.1',
432 ip_dst='192.168.0.2',
433 ip_tos=0,
Gregor Maier9cc93342013-01-29 16:55:28 -0800434 ip_ttl=64,
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800435 tcp_sport=1234,
436 tcp_dport=80,
437 ip_ihl=None,
438 ip_options=False
439 ):
440 """
441 Return a doubly tagged dataplane TCP packet
442
443 Supports a few parameters:
444 @param len Length of packet in bytes w/o CRC
Rich Laned0478ff2013-03-11 12:46:58 -0700445 @param eth_dst Destinatino MAC
446 @param eth_src Source MAC
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800447 @param dl_vlan_outer Outer VLAN ID
448 @param dl_vlan_pcp_outer Outer VLAN priority
449 @param dl_vlan_cfi_outer Outer VLAN cfi bit
Rich Laned0478ff2013-03-11 12:46:58 -0700450 @param vlan_vid Inner VLAN ID
451 @param vlan_pcp VLAN priority
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800452 @param dl_vlan_cfi VLAN cfi bit
453 @param ip_src IP source
454 @param ip_dst IP destination
455 @param ip_tos IP ToS
456 @param tcp_dport TCP destination port
457 @param ip_sport TCP source port
458
459 Generates a TCP request. Users
460 shouldn't assume anything about this packet other than that
461 it is a valid ethernet/IP/TCP frame.
462 """
463
464 if MINSIZE > pktlen:
465 pktlen = MINSIZE
466
467 # Note Dot1Q.id is really CFI
Rich Laned0478ff2013-03-11 12:46:58 -0700468 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800469 scapy.Dot1Q(prio=dl_vlan_pcp_outer, id=dl_vlan_cfi_outer, vlan=dl_vlan_outer)/ \
Rich Laned0478ff2013-03-11 12:46:58 -0700470 scapy.Dot1Q(prio=vlan_pcp, id=dl_vlan_cfi, vlan=vlan_vid)/ \
Gregor Maier9cc93342013-01-29 16:55:28 -0800471 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ttl=ip_ttl, ihl=ip_ihl)/ \
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800472 scapy.TCP(sport=tcp_sport, dport=tcp_dport)
473
474 pkt = pkt/("D" * (pktlen - len(pkt)))
475
476 return pkt
477
Shudong Zhoub7f12462012-11-20 13:01:12 -0800478def do_barrier(ctrl, timeout=-1):
Dan Talayco0fc08bd2012-04-09 16:56:18 -0700479 """
480 Do a barrier command
481 Return 0 on success, -1 on error
482 """
Rich Lanee717c6e2013-03-12 10:25:50 -0700483 b = ofp.message.barrier_request()
Shudong Zhoub7f12462012-11-20 13:01:12 -0800484 (resp, pkt) = ctrl.transact(b, timeout=timeout)
Rich Lane3a261d52013-01-03 17:45:08 -0800485 if resp is None:
486 raise AssertionError("barrier failed")
Dan Talaycof6b94832012-04-12 21:50:57 -0700487 # We'll trust the transaction processing in the controller that xid matched
Rich Lane3a261d52013-01-03 17:45:08 -0800488 return 0 # for backwards compatibility
Dan Talayco92c99122010-06-03 13:53:18 -0700489
Rich Lane9a003812012-10-04 17:17:59 -0700490def port_config_get(controller, port_no):
Dan Talayco92c99122010-06-03 13:53:18 -0700491 """
492 Get a port's configuration
493
494 Gets the switch feature configuration and grabs one port's
495 configuration
496
497 @returns (hwaddr, config, advert) The hwaddress, configuration and
498 advertised values
499 """
Rich Lane6dc865c2013-07-10 10:12:13 -0700500
501 if ofp.OFP_VERSION <= 3:
502 request = ofp.message.features_request()
503 reply, _ = controller.transact(request)
504 if reply is None:
505 logging.warn("Get feature request failed")
506 return None, None, None
507 logging.debug(reply.show())
508 ports = reply.ports
509 else:
510 request = ofp.message.port_desc_stats_request()
511 # TODO do multipart correctly
512 reply, _ = controller.transact(request)
513 if reply is None:
514 logging.warn("Port desc stats request failed")
515 return None, None, None
516 logging.debug(reply.show())
517 ports = reply.entries
518
519 for port in ports:
520 if port.port_no == port_no:
521 return (port.hw_addr, port.config, port.advertised)
Dan Talayco92c99122010-06-03 13:53:18 -0700522
Rich Lane9a003812012-10-04 17:17:59 -0700523 logging.warn("Did not find port number for port config")
Dan Talayco92c99122010-06-03 13:53:18 -0700524 return None, None, None
525
Rich Lane9a003812012-10-04 17:17:59 -0700526def port_config_set(controller, port_no, config, mask):
Dan Talayco92c99122010-06-03 13:53:18 -0700527 """
528 Set the port configuration according the given parameters
529
530 Gets the switch feature configuration and updates one port's
531 configuration value according to config and mask
532 """
Rich Lane9a003812012-10-04 17:17:59 -0700533 logging.info("Setting port " + str(port_no) + " to config " + str(config))
Rich Lane6dc865c2013-07-10 10:12:13 -0700534
535 hw_addr, _, _ = port_config_get(controller, port_no)
536
Rich Lanee717c6e2013-03-12 10:25:50 -0700537 mod = ofp.message.port_mod()
Dan Talayco92c99122010-06-03 13:53:18 -0700538 mod.port_no = port_no
Rich Lane6dc865c2013-07-10 10:12:13 -0700539 if hw_addr != None:
540 mod.hw_addr = hw_addr
Dan Talayco92c99122010-06-03 13:53:18 -0700541 mod.config = config
542 mod.mask = mask
Rich Lane6dc865c2013-07-10 10:12:13 -0700543 mod.advertise = 0 # No change
Rich Lane5c3151c2013-01-03 17:15:41 -0800544 controller.message_send(mod)
545 return 0
Dan Talayco92c99122010-06-03 13:53:18 -0700546
Rich Lane2014f9b2012-10-05 15:29:40 -0700547def receive_pkt_check(dp, pkt, yes_ports, no_ports, assert_if):
Dan Talayco92c99122010-06-03 13:53:18 -0700548 """
549 Check for proper receive packets across all ports
Ken Chiang1bf01602012-04-04 10:48:23 -0700550 @param dp The dataplane object
Dan Talayco92c99122010-06-03 13:53:18 -0700551 @param pkt Expected packet; may be None if yes_ports is empty
552 @param yes_ports Set or list of ports that should recieve packet
553 @param no_ports Set or list of ports that should not receive packet
554 @param assert_if Object that implements assertXXX
Rich Lanee4b384d2013-09-13 14:33:40 -0700555
556 DEPRECATED in favor in verify_packets
Dan Talayco92c99122010-06-03 13:53:18 -0700557 """
Rich Lane91765672012-12-06 16:33:04 -0800558
559 # Wait this long for packets that we don't expect to receive.
560 # 100ms is (rarely) too short for positive tests on slow
561 # switches but is definitely not too short for a negative test.
562 negative_timeout = 0.1
563
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700564 exp_pkt_arg = None
Rich Lanecd97d3d2013-01-07 18:50:06 -0800565 if oftest.config["relax"]:
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700566 exp_pkt_arg = pkt
567
Dan Talayco92c99122010-06-03 13:53:18 -0700568 for ofport in yes_ports:
Rich Lane9a003812012-10-04 17:17:59 -0700569 logging.debug("Checking for pkt on port " + str(ofport))
Ken Chiang1bf01602012-04-04 10:48:23 -0700570 (rcv_port, rcv_pkt, pkt_time) = dp.poll(
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700571 port_number=ofport, exp_pkt=exp_pkt_arg)
Dan Talayco92c99122010-06-03 13:53:18 -0700572 assert_if.assertTrue(rcv_pkt is not None,
573 "Did not receive pkt on " + str(ofport))
Rich Lanecd97d3d2013-01-07 18:50:06 -0800574 if not oftest.dataplane.match_exp_pkt(pkt, rcv_pkt):
Rich Lane3c266832013-01-29 18:29:15 -0800575 logging.debug("Expected %s" % format_packet(pkt))
576 logging.debug("Received %s" % format_packet(rcv_pkt))
Rich Lanecd97d3d2013-01-07 18:50:06 -0800577 assert_if.assertTrue(oftest.dataplane.match_exp_pkt(pkt, rcv_pkt),
Rich Lane3c266832013-01-29 18:29:15 -0800578 "Received packet does not match expected packet " +
Ken Chiang1bf01602012-04-04 10:48:23 -0700579 "on port " + str(ofport))
Dan Talayco73f84012012-10-02 09:23:18 -0700580 if len(no_ports) > 0:
Rich Lane91765672012-12-06 16:33:04 -0800581 time.sleep(negative_timeout)
Dan Talayco92c99122010-06-03 13:53:18 -0700582 for ofport in no_ports:
Rich Lane9a003812012-10-04 17:17:59 -0700583 logging.debug("Negative check for pkt on port " + str(ofport))
Ken Chiang1bf01602012-04-04 10:48:23 -0700584 (rcv_port, rcv_pkt, pkt_time) = dp.poll(
Rich Lane91765672012-12-06 16:33:04 -0800585 port_number=ofport, timeout=0, exp_pkt=exp_pkt_arg)
Dan Talayco92c99122010-06-03 13:53:18 -0700586 assert_if.assertTrue(rcv_pkt is None,
587 "Unexpected pkt on port " + str(ofport))
Dan Talayco551befa2010-07-15 17:05:32 -0700588
589
Dan Talaycoc948d0b2012-03-23 12:17:54 -0700590def receive_pkt_verify(parent, egr_ports, exp_pkt, ing_port):
Dan Talayco551befa2010-07-15 17:05:32 -0700591 """
592 Receive a packet and verify it matches an expected value
Dan Talaycof6e76c02012-03-23 10:56:12 -0700593 @param egr_port A single port or list of ports
Dan Talayco551befa2010-07-15 17:05:32 -0700594
595 parent must implement dataplane, assertTrue and assertEqual
Rich Lanee4b384d2013-09-13 14:33:40 -0700596
597 DEPRECATED in favor in verify_packets
Dan Talayco551befa2010-07-15 17:05:32 -0700598 """
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700599 exp_pkt_arg = None
Rich Lanecd97d3d2013-01-07 18:50:06 -0800600 if oftest.config["relax"]:
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700601 exp_pkt_arg = exp_pkt
602
Dan Talaycof6e76c02012-03-23 10:56:12 -0700603 if type(egr_ports) == type([]):
604 egr_port_list = egr_ports
605 else:
606 egr_port_list = [egr_ports]
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700607
Dan Talaycof6e76c02012-03-23 10:56:12 -0700608 # Expect a packet from each port on egr port list
609 for egr_port in egr_port_list:
Dan Talaycod8ae7582012-03-23 12:24:56 -0700610 check_port = egr_port
Rich Lanee717c6e2013-03-12 10:25:50 -0700611 if egr_port == ofp.OFPP_IN_PORT:
Dan Talaycod8ae7582012-03-23 12:24:56 -0700612 check_port = ing_port
Dan Talaycof6e76c02012-03-23 10:56:12 -0700613 (rcv_port, rcv_pkt, pkt_time) = parent.dataplane.poll(
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700614 port_number=check_port, exp_pkt=exp_pkt_arg)
Dan Talayco551befa2010-07-15 17:05:32 -0700615
Dan Talaycof6e76c02012-03-23 10:56:12 -0700616 if rcv_pkt is None:
Rich Lane9a003812012-10-04 17:17:59 -0700617 logging.error("ERROR: No packet received from " +
Dan Talaycod8ae7582012-03-23 12:24:56 -0700618 str(check_port))
Dan Talayco551befa2010-07-15 17:05:32 -0700619
Dan Talaycof6e76c02012-03-23 10:56:12 -0700620 parent.assertTrue(rcv_pkt is not None,
Dan Talaycod8ae7582012-03-23 12:24:56 -0700621 "Did not receive packet port " + str(check_port))
Rich Lane9a003812012-10-04 17:17:59 -0700622 logging.debug("Packet len " + str(len(rcv_pkt)) + " in on " +
Dan Talaycof6e76c02012-03-23 10:56:12 -0700623 str(rcv_port))
624
625 if str(exp_pkt) != str(rcv_pkt):
Rich Lane9a003812012-10-04 17:17:59 -0700626 logging.error("ERROR: Packet match failed.")
627 logging.debug("Expected len " + str(len(exp_pkt)) + ": "
Dan Talaycof6e76c02012-03-23 10:56:12 -0700628 + str(exp_pkt).encode('hex'))
Rich Lane9a003812012-10-04 17:17:59 -0700629 logging.debug("Received len " + str(len(rcv_pkt)) + ": "
Dan Talaycof6e76c02012-03-23 10:56:12 -0700630 + str(rcv_pkt).encode('hex'))
Rich Lane5d7e89a2012-10-26 16:43:13 -0700631 logging.debug("Expected packet: " + inspect_packet(scapy.Ether(str(exp_pkt))))
632 logging.debug("Received packet: " + inspect_packet(scapy.Ether(str(rcv_pkt))))
Dan Talaycof6e76c02012-03-23 10:56:12 -0700633 parent.assertEqual(str(exp_pkt), str(rcv_pkt),
Dan Talaycod8ae7582012-03-23 12:24:56 -0700634 "Packet match error on port " + str(check_port))
Dan Talaycof6e76c02012-03-23 10:56:12 -0700635
Dan Talayco551befa2010-07-15 17:05:32 -0700636def match_verify(parent, req_match, res_match):
637 """
638 Verify flow matches agree; if they disagree, report where
639
640 parent must implement assertEqual
641 Use str() to ensure content is compared and not pointers
642 """
643
644 parent.assertEqual(req_match.wildcards, res_match.wildcards,
645 'Match failed: wildcards: ' + hex(req_match.wildcards) +
646 " != " + hex(res_match.wildcards))
647 parent.assertEqual(req_match.in_port, res_match.in_port,
648 'Match failed: in_port: ' + str(req_match.in_port) +
649 " != " + str(res_match.in_port))
Rich Laned0478ff2013-03-11 12:46:58 -0700650 parent.assertEqual(str(req_match.eth_src), str(res_match.eth_src),
651 'Match failed: eth_src: ' + str(req_match.eth_src) +
652 " != " + str(res_match.eth_src))
653 parent.assertEqual(str(req_match.eth_dst), str(res_match.eth_dst),
654 'Match failed: eth_dst: ' + str(req_match.eth_dst) +
655 " != " + str(res_match.eth_dst))
656 parent.assertEqual(req_match.vlan_vid, res_match.vlan_vid,
657 'Match failed: vlan_vid: ' + str(req_match.vlan_vid) +
658 " != " + str(res_match.vlan_vid))
659 parent.assertEqual(req_match.vlan_pcp, res_match.vlan_pcp,
660 'Match failed: vlan_pcp: ' +
661 str(req_match.vlan_pcp) + " != " +
662 str(res_match.vlan_pcp))
663 parent.assertEqual(req_match.eth_type, res_match.eth_type,
664 'Match failed: eth_type: ' + str(req_match.eth_type) +
665 " != " + str(res_match.eth_type))
Dan Talayco551befa2010-07-15 17:05:32 -0700666
Rich Lanee717c6e2013-03-12 10:25:50 -0700667 if (not(req_match.wildcards & ofp.OFPFW_DL_TYPE)
Rich Laned0478ff2013-03-11 12:46:58 -0700668 and (req_match.eth_type == IP_ETHERTYPE)):
669 parent.assertEqual(req_match.ip_dscp, res_match.ip_dscp,
670 'Match failed: ip_dscp: ' + str(req_match.ip_dscp) +
671 " != " + str(res_match.ip_dscp))
672 parent.assertEqual(req_match.ip_proto, res_match.ip_proto,
673 'Match failed: ip_proto: ' + str(req_match.ip_proto) +
674 " != " + str(res_match.ip_proto))
675 parent.assertEqual(req_match.ipv4_src, res_match.ipv4_src,
676 'Match failed: ipv4_src: ' + str(req_match.ipv4_src) +
677 " != " + str(res_match.ipv4_src))
678 parent.assertEqual(req_match.ipv4_dst, res_match.ipv4_dst,
679 'Match failed: ipv4_dst: ' + str(req_match.ipv4_dst) +
680 " != " + str(res_match.ipv4_dst))
Dan Talayco551befa2010-07-15 17:05:32 -0700681
Rich Lanee717c6e2013-03-12 10:25:50 -0700682 if (not(req_match.wildcards & ofp.OFPFW_NW_PROTO)
Rich Laned0478ff2013-03-11 12:46:58 -0700683 and ((req_match.ip_proto == TCP_PROTOCOL)
684 or (req_match.ip_proto == UDP_PROTOCOL))):
685 parent.assertEqual(req_match.tcp_src, res_match.tcp_src,
686 'Match failed: tcp_src: ' +
687 str(req_match.tcp_src) +
688 " != " + str(res_match.tcp_src))
689 parent.assertEqual(req_match.tcp_dst, res_match.tcp_dst,
690 'Match failed: tcp_dst: ' +
691 str(req_match.tcp_dst) +
692 " != " + str(res_match.tcp_dst))
Dan Talayco551befa2010-07-15 17:05:32 -0700693
Ed Swierk99a74de2012-08-22 06:40:54 -0700694def packet_to_flow_match(parent, packet):
Rich Lanef6883512013-03-11 17:00:09 -0700695 match = oftest.parse.packet_to_flow_match(packet)
Rich Laneab7476f2013-06-13 15:53:52 -0700696 if ofp.OFP_VERSION in [1, 2]:
697 match.wildcards |= required_wildcards(parent)
698 else:
699 # TODO remove incompatible OXM entries
700 pass
Ed Swierk99a74de2012-08-22 06:40:54 -0700701 return match
702
703def flow_msg_create(parent, pkt, ing_port=None, action_list=None, wildcards=None,
Dan Talaycof6e76c02012-03-23 10:56:12 -0700704 egr_ports=None, egr_queue=None, check_expire=False, in_band=False):
Dan Talayco551befa2010-07-15 17:05:32 -0700705 """
706 Create a flow message
707
708 Match on packet with given wildcards.
709 See flow_match_test for other parameter descriptoins
710 @param egr_queue if not None, make the output an enqueue action
Dan Talayco677c0b72011-08-23 22:53:38 -0700711 @param in_band if True, do not wildcard ingress port
Dan Talaycof6e76c02012-03-23 10:56:12 -0700712 @param egr_ports None (drop), single port or list of ports
Dan Talayco551befa2010-07-15 17:05:32 -0700713 """
Rich Lanef6883512013-03-11 17:00:09 -0700714 match = oftest.parse.packet_to_flow_match(pkt)
Dan Talayco551befa2010-07-15 17:05:32 -0700715 parent.assertTrue(match is not None, "Flow match from pkt failed")
Ed Swierk99a74de2012-08-22 06:40:54 -0700716 if wildcards is None:
717 wildcards = required_wildcards(parent)
Dan Talayco677c0b72011-08-23 22:53:38 -0700718 if in_band:
Rich Lanee717c6e2013-03-12 10:25:50 -0700719 wildcards &= ~ofp.OFPFW_IN_PORT
Dan Talayco551befa2010-07-15 17:05:32 -0700720 match.wildcards = wildcards
721 match.in_port = ing_port
722
Dan Talaycof6e76c02012-03-23 10:56:12 -0700723 if type(egr_ports) == type([]):
724 egr_port_list = egr_ports
725 else:
726 egr_port_list = [egr_ports]
727
Rich Lanee717c6e2013-03-12 10:25:50 -0700728 request = ofp.message.flow_add()
Dan Talayco551befa2010-07-15 17:05:32 -0700729 request.match = match
730 request.buffer_id = 0xffffffff
731 if check_expire:
Rich Lanee717c6e2013-03-12 10:25:50 -0700732 request.flags |= ofp.OFPFF_SEND_FLOW_REM
Dan Talayco551befa2010-07-15 17:05:32 -0700733 request.hard_timeout = 1
734
735 if action_list is not None:
736 for act in action_list:
Rich Lane9a003812012-10-04 17:17:59 -0700737 logging.debug("Adding action " + act.show())
Rich Lanec495d9e2013-03-08 17:43:36 -0800738 request.actions.append(act)
Dan Talayco551befa2010-07-15 17:05:32 -0700739
740 # Set up output/enqueue action if directed
741 if egr_queue is not None:
Dan Talaycof6e76c02012-03-23 10:56:12 -0700742 parent.assertTrue(egr_ports is not None, "Egress port not set")
Rich Lanee717c6e2013-03-12 10:25:50 -0700743 act = ofp.action.enqueue()
Dan Talaycof6e76c02012-03-23 10:56:12 -0700744 for egr_port in egr_port_list:
745 act.port = egr_port
746 act.queue_id = egr_queue
Rich Lanec495d9e2013-03-08 17:43:36 -0800747 request.actions.append(act)
Dan Talaycof6e76c02012-03-23 10:56:12 -0700748 elif egr_ports is not None:
749 for egr_port in egr_port_list:
Rich Lanee717c6e2013-03-12 10:25:50 -0700750 act = ofp.action.output()
Dan Talaycof6e76c02012-03-23 10:56:12 -0700751 act.port = egr_port
Rich Lanec495d9e2013-03-08 17:43:36 -0800752 request.actions.append(act)
Dan Talayco551befa2010-07-15 17:05:32 -0700753
Rich Lane9a003812012-10-04 17:17:59 -0700754 logging.debug(request.show())
Dan Talayco551befa2010-07-15 17:05:32 -0700755
756 return request
757
Jeffrey Townsendf3eae9c2012-03-28 18:23:21 -0700758def flow_msg_install(parent, request, clear_table_override=None):
Dan Talayco551befa2010-07-15 17:05:32 -0700759 """
760 Install a flow mod message in the switch
761
762 @param parent Must implement controller, assertEqual, assertTrue
763 @param request The request, all set to go
764 @param clear_table If true, clear the flow table before installing
765 """
Dan Talayco8a64e332012-03-28 14:53:20 -0700766
Rich Lane2014f9b2012-10-05 15:29:40 -0700767 clear_table = test_param_get('clear_table', default=True)
Jeffrey Townsendf3eae9c2012-03-28 18:23:21 -0700768 if(clear_table_override != None):
769 clear_table = clear_table_override
770
771 if clear_table:
Rich Lane9a003812012-10-04 17:17:59 -0700772 logging.debug("Clear flow table")
Rich Lane32bf9482013-01-03 17:26:30 -0800773 delete_all_flows(parent.controller)
Dan Talayco551befa2010-07-15 17:05:32 -0700774
Rich Lane9a003812012-10-04 17:17:59 -0700775 logging.debug("Insert flow")
Rich Lane5c3151c2013-01-03 17:15:41 -0800776 parent.controller.message_send(request)
Rich Lanee912d032012-12-22 14:28:33 -0800777
Rich Lane3a261d52013-01-03 17:45:08 -0800778 do_barrier(parent.controller)
Dan Talayco551befa2010-07-15 17:05:32 -0700779
Ed Swierk99a74de2012-08-22 06:40:54 -0700780def flow_match_test_port_pair(parent, ing_port, egr_ports, wildcards=None,
Rich Laned0478ff2013-03-11 12:46:58 -0700781 vlan_vid=-1, pkt=None, exp_pkt=None,
Rich Lanee5779d32012-10-05 17:56:04 -0700782 action_list=None):
Dan Talayco551befa2010-07-15 17:05:32 -0700783 """
784 Flow match test on single TCP packet
Dan Talaycof6e76c02012-03-23 10:56:12 -0700785 @param egr_ports A single port or list of ports
Dan Talayco551befa2010-07-15 17:05:32 -0700786
787 Run test with packet through switch from ing_port to egr_port
788 See flow_match_test for parameter descriptions
789 """
790
Ed Swierk99a74de2012-08-22 06:40:54 -0700791 if wildcards is None:
792 wildcards = required_wildcards(parent)
Rich Lane9a003812012-10-04 17:17:59 -0700793 logging.info("Pkt match test: " + str(ing_port) + " to " +
Dan Talaycof6e76c02012-03-23 10:56:12 -0700794 str(egr_ports))
Rich Laned0478ff2013-03-11 12:46:58 -0700795 logging.debug(" WC: " + hex(wildcards) + " vlan: " + str(vlan_vid))
Dan Talayco551befa2010-07-15 17:05:32 -0700796 if pkt is None:
Rich Laned0478ff2013-03-11 12:46:58 -0700797 pkt = simple_tcp_packet(dl_vlan_enable=(vlan_vid >= 0), vlan_vid=vlan_vid)
Dan Talayco551befa2010-07-15 17:05:32 -0700798
799 request = flow_msg_create(parent, pkt, ing_port=ing_port,
Dan Talaycof6e76c02012-03-23 10:56:12 -0700800 wildcards=wildcards, egr_ports=egr_ports,
Dan Talayco551befa2010-07-15 17:05:32 -0700801 action_list=action_list)
802
803 flow_msg_install(parent, request)
804
Rich Lane9a003812012-10-04 17:17:59 -0700805 logging.debug("Send packet: " + str(ing_port) + " to " +
Dan Talaycof6e76c02012-03-23 10:56:12 -0700806 str(egr_ports))
Dan Talayco551befa2010-07-15 17:05:32 -0700807 parent.dataplane.send(ing_port, str(pkt))
808
Rich Lane8f45e2d2013-10-01 16:06:54 -0700809 exp_ports = [ing_port if port == ofp.OFPP_IN_PORT else port for port in egr_ports]
Rich Lanee4b384d2013-09-13 14:33:40 -0700810 verify_packets(parent, exp_pkt, exp_ports)
Dan Talayco551befa2010-07-15 17:05:32 -0700811
Rich Lane89725bb2012-12-03 16:23:27 -0800812def flow_match_test_pktout(parent, ing_port, egr_ports,
Rich Laned0478ff2013-03-11 12:46:58 -0700813 vlan_vid=-1, pkt=None, exp_pkt=None,
Rich Lane89725bb2012-12-03 16:23:27 -0800814 action_list=None):
815 """
816 Packet-out test on single TCP packet
817 @param egr_ports A single port or list of ports
818
819 Run test sending packet-out to egr_ports. The goal is to test the actions
820 taken on the packet, not the matching which is of course irrelevant.
821 See flow_match_test for parameter descriptions
822 """
823
824 if pkt is None:
Rich Laned0478ff2013-03-11 12:46:58 -0700825 pkt = simple_tcp_packet(dl_vlan_enable=(vlan_vid >= 0), vlan_vid=vlan_vid)
Rich Lane89725bb2012-12-03 16:23:27 -0800826
Rich Lanee717c6e2013-03-12 10:25:50 -0700827 msg = ofp.message.packet_out()
Rich Lane89725bb2012-12-03 16:23:27 -0800828 msg.in_port = ing_port
Rich Laneea8c4722013-04-04 15:30:20 -0700829 msg.buffer_id = 0xffffffff
Rich Lane89725bb2012-12-03 16:23:27 -0800830 msg.data = str(pkt)
831 if action_list is not None:
832 for act in action_list:
Rich Lanec495d9e2013-03-08 17:43:36 -0800833 msg.actions.append(act)
Rich Lane89725bb2012-12-03 16:23:27 -0800834
835 # Set up output action
836 if egr_ports is not None:
837 for egr_port in egr_ports:
Rich Lanee717c6e2013-03-12 10:25:50 -0700838 act = ofp.action.output()
Rich Lane89725bb2012-12-03 16:23:27 -0800839 act.port = egr_port
Rich Lanec495d9e2013-03-08 17:43:36 -0800840 msg.actions.append(act)
Rich Lane89725bb2012-12-03 16:23:27 -0800841
842 logging.debug(msg.show())
Rich Lane5c3151c2013-01-03 17:15:41 -0800843 parent.controller.message_send(msg)
Rich Lane89725bb2012-12-03 16:23:27 -0800844
Rich Lane8f45e2d2013-10-01 16:06:54 -0700845 exp_ports = [ing_port if port == ofp.OFPP_IN_PORT else port for port in egr_ports]
Rich Lanee4b384d2013-09-13 14:33:40 -0700846 verify_packets(parent, exp_pkt, exp_ports)
Rich Lane89725bb2012-12-03 16:23:27 -0800847
Dan Talaycof6e76c02012-03-23 10:56:12 -0700848def get_egr_list(parent, of_ports, how_many, exclude_list=[]):
849 """
850 Generate a list of ports avoiding those in the exclude list
Rich Lane9a003812012-10-04 17:17:59 -0700851 @param parent Supplies logging
Dan Talaycof6e76c02012-03-23 10:56:12 -0700852 @param of_ports List of OF port numbers
853 @param how_many Number of ports to be added to the list
854 @param exclude_list List of ports not to be used
855 @returns An empty list if unable to find enough ports
856 """
857
Dan Talaycoc948d0b2012-03-23 12:17:54 -0700858 if how_many == 0:
859 return []
860
Dan Talaycof6e76c02012-03-23 10:56:12 -0700861 count = 0
862 egr_ports = []
863 for egr_idx in range(len(of_ports)):
864 if of_ports[egr_idx] not in exclude_list:
865 egr_ports.append(of_ports[egr_idx])
866 count += 1
867 if count >= how_many:
868 return egr_ports
Rich Lane9a003812012-10-04 17:17:59 -0700869 logging.debug("Could not generate enough egress ports for test")
Dan Talaycof6e76c02012-03-23 10:56:12 -0700870 return []
871
Rich Laned0478ff2013-03-11 12:46:58 -0700872def flow_match_test(parent, port_map, wildcards=None, vlan_vid=-1, pkt=None,
Rich Lanee5779d32012-10-05 17:56:04 -0700873 exp_pkt=None, action_list=None,
Dan Talaycoc948d0b2012-03-23 12:17:54 -0700874 max_test=0, egr_count=1, ing_port=False):
Dan Talayco551befa2010-07-15 17:05:32 -0700875 """
Rich Lane89725bb2012-12-03 16:23:27 -0800876 Run flow_match_test_port_pair on all port pairs and packet-out
Dan Talayco551befa2010-07-15 17:05:32 -0700877
878 @param max_test If > 0 no more than this number of tests are executed.
879 @param parent Must implement controller, dataplane, assertTrue, assertEqual
Rich Lane9a003812012-10-04 17:17:59 -0700880 and logging
Dan Talayco551befa2010-07-15 17:05:32 -0700881 @param pkt If not None, use this packet for ingress
882 @param wildcards For flow match entry
Rich Laned0478ff2013-03-11 12:46:58 -0700883 @param vlan_vid If not -1, and pkt is None, create a pkt w/ VLAN tag
Dan Talayco551befa2010-07-15 17:05:32 -0700884 @param exp_pkt If not None, use this as the expected output pkt; els use pkt
885 @param action_list Additional actions to add to flow mod
Dan Talaycocfa172f2012-03-23 12:03:00 -0700886 @param egr_count Number of egress ports; -1 means get from config w/ dflt 2
Dan Talayco551befa2010-07-15 17:05:32 -0700887 """
Ed Swierk99a74de2012-08-22 06:40:54 -0700888 if wildcards is None:
889 wildcards = required_wildcards(parent)
Dan Talayco551befa2010-07-15 17:05:32 -0700890 of_ports = port_map.keys()
891 of_ports.sort()
892 parent.assertTrue(len(of_ports) > 1, "Not enough ports for test")
893 test_count = 0
894
Dan Talaycocfa172f2012-03-23 12:03:00 -0700895 if egr_count == -1:
Rich Lane2014f9b2012-10-05 15:29:40 -0700896 egr_count = test_param_get('egr_count', default=2)
Dan Talaycocfa172f2012-03-23 12:03:00 -0700897
Dan Talayco551befa2010-07-15 17:05:32 -0700898 for ing_idx in range(len(of_ports)):
899 ingress_port = of_ports[ing_idx]
Dan Talaycof6e76c02012-03-23 10:56:12 -0700900 egr_ports = get_egr_list(parent, of_ports, egr_count,
901 exclude_list=[ingress_port])
Dan Talaycoc948d0b2012-03-23 12:17:54 -0700902 if ing_port:
Rich Lanee717c6e2013-03-12 10:25:50 -0700903 egr_ports.append(ofp.OFPP_IN_PORT)
Dan Talaycof6e76c02012-03-23 10:56:12 -0700904 if len(egr_ports) == 0:
905 parent.assertTrue(0, "Failed to generate egress port list")
906
907 flow_match_test_port_pair(parent, ingress_port, egr_ports,
Rich Laned0478ff2013-03-11 12:46:58 -0700908 wildcards=wildcards, vlan_vid=vlan_vid,
Dan Talaycof6e76c02012-03-23 10:56:12 -0700909 pkt=pkt, exp_pkt=exp_pkt,
Rich Lanee5779d32012-10-05 17:56:04 -0700910 action_list=action_list)
Dan Talaycof6e76c02012-03-23 10:56:12 -0700911 test_count += 1
912 if (max_test > 0) and (test_count > max_test):
Rich Lane9a003812012-10-04 17:17:59 -0700913 logging.info("Ran " + str(test_count) + " tests; exiting")
Rich Lane89725bb2012-12-03 16:23:27 -0800914 break
915
Ed Swierk38eea082013-01-02 19:46:20 -0800916 if not test_param_get('pktout_actions', default=True):
917 return
Rich Lane89725bb2012-12-03 16:23:27 -0800918
919 ingress_port = of_ports[0]
920 egr_ports = get_egr_list(parent, of_ports, egr_count,
921 exclude_list=[ingress_port])
922 if ing_port:
Rich Lanee717c6e2013-03-12 10:25:50 -0700923 egr_ports.append(ofp.OFPP_IN_PORT)
Rich Lane89725bb2012-12-03 16:23:27 -0800924 flow_match_test_pktout(parent, ingress_port, egr_ports,
Rich Laned0478ff2013-03-11 12:46:58 -0700925 vlan_vid=vlan_vid,
Rich Lane89725bb2012-12-03 16:23:27 -0800926 pkt=pkt, exp_pkt=exp_pkt,
927 action_list=action_list)
Dan Talayco551befa2010-07-15 17:05:32 -0700928
Rich Lane2014f9b2012-10-05 15:29:40 -0700929def test_param_get(key, default=None):
Dan Talayco4b2bee62010-07-20 14:10:05 -0700930 """
931 Return value passed via test-params if present
932
Dan Talayco4b2bee62010-07-20 14:10:05 -0700933 @param key The lookup key
934 @param default Default value to use if not found
935
936 If the pair 'key=val' appeared in the string passed to --test-params
937 on the command line, return val (as interpreted by exec). Otherwise
938 return default value.
Dan Talaycof6e76c02012-03-23 10:56:12 -0700939
940 WARNING: TEST PARAMETERS MUST BE PYTHON IDENTIFIERS;
941 eg egr_count, not egr-count.
Dan Talayco4b2bee62010-07-20 14:10:05 -0700942 """
943 try:
Rich Lanecd97d3d2013-01-07 18:50:06 -0800944 exec oftest.config["test_params"]
Dan Talayco4b2bee62010-07-20 14:10:05 -0700945 except:
946 return default
947
Dan Talayco4b2bee62010-07-20 14:10:05 -0700948 try:
Rich Lanefdec0fb2013-08-09 18:01:05 -0700949 return eval(str(key))
Dan Talayco4b2bee62010-07-20 14:10:05 -0700950 except:
951 return default
952
953def action_generate(parent, field_to_mod, mod_field_vals):
954 """
955 Create an action to modify the field indicated in field_to_mod
956
957 @param parent Must implement, assertTrue
958 @param field_to_mod The field to modify as a string name
959 @param mod_field_vals Hash of values to use for modified values
960 """
961
962 act = None
963
964 if field_to_mod in ['pktlen']:
965 return None
966
Rich Laned0478ff2013-03-11 12:46:58 -0700967 if field_to_mod == 'eth_dst':
Rich Lanee717c6e2013-03-12 10:25:50 -0700968 act = ofp.action.set_dl_dst()
Rich Lanef6883512013-03-11 17:00:09 -0700969 act.dl_addr = oftest.parse.parse_mac(mod_field_vals['eth_dst'])
Rich Laned0478ff2013-03-11 12:46:58 -0700970 elif field_to_mod == 'eth_src':
Rich Lanee717c6e2013-03-12 10:25:50 -0700971 act = ofp.action.set_dl_src()
Rich Lanef6883512013-03-11 17:00:09 -0700972 act.dl_addr = oftest.parse.parse_mac(mod_field_vals['eth_src'])
Dan Talayco4b2bee62010-07-20 14:10:05 -0700973 elif field_to_mod == 'dl_vlan_enable':
974 if not mod_field_vals['dl_vlan_enable']: # Strip VLAN tag
Rich Lanee717c6e2013-03-12 10:25:50 -0700975 act = ofp.action.strip_vlan()
Rich Laned0478ff2013-03-11 12:46:58 -0700976 # Add VLAN tag is handled by vlan_vid field
Dan Talayco4b2bee62010-07-20 14:10:05 -0700977 # Will return None in this case
Rich Laned0478ff2013-03-11 12:46:58 -0700978 elif field_to_mod == 'vlan_vid':
Rich Lanee717c6e2013-03-12 10:25:50 -0700979 act = ofp.action.set_vlan_vid()
Rich Laned0478ff2013-03-11 12:46:58 -0700980 act.vlan_vid = mod_field_vals['vlan_vid']
981 elif field_to_mod == 'vlan_pcp':
Rich Lanee717c6e2013-03-12 10:25:50 -0700982 act = ofp.action.set_vlan_pcp()
Rich Laned0478ff2013-03-11 12:46:58 -0700983 act.vlan_pcp = mod_field_vals['vlan_pcp']
Dan Talayco4b2bee62010-07-20 14:10:05 -0700984 elif field_to_mod == 'ip_src':
Rich Lanee717c6e2013-03-12 10:25:50 -0700985 act = ofp.action.set_nw_src()
Rich Lanef6883512013-03-11 17:00:09 -0700986 act.nw_addr = oftest.parse.parse_ip(mod_field_vals['ip_src'])
Dan Talayco4b2bee62010-07-20 14:10:05 -0700987 elif field_to_mod == 'ip_dst':
Rich Lanee717c6e2013-03-12 10:25:50 -0700988 act = ofp.action.set_nw_dst()
Rich Lanef6883512013-03-11 17:00:09 -0700989 act.nw_addr = oftest.parse.parse_ip(mod_field_vals['ip_dst'])
Dan Talayco4b2bee62010-07-20 14:10:05 -0700990 elif field_to_mod == 'ip_tos':
Rich Lanee717c6e2013-03-12 10:25:50 -0700991 act = ofp.action.set_nw_tos()
Dan Talayco4b2bee62010-07-20 14:10:05 -0700992 act.nw_tos = mod_field_vals['ip_tos']
993 elif field_to_mod == 'tcp_sport':
Rich Lanee717c6e2013-03-12 10:25:50 -0700994 act = ofp.action.set_tp_src()
Dan Talayco4b2bee62010-07-20 14:10:05 -0700995 act.tp_port = mod_field_vals['tcp_sport']
996 elif field_to_mod == 'tcp_dport':
Rich Lanee717c6e2013-03-12 10:25:50 -0700997 act = ofp.action.set_tp_dst()
Dan Talayco4b2bee62010-07-20 14:10:05 -0700998 act.tp_port = mod_field_vals['tcp_dport']
Rich Lane110e0e32012-10-26 16:21:46 -0700999 elif field_to_mod == 'udp_sport':
Rich Lanee717c6e2013-03-12 10:25:50 -07001000 act = ofp.action.set_tp_src()
Rich Lane110e0e32012-10-26 16:21:46 -07001001 act.tp_port = mod_field_vals['udp_sport']
1002 elif field_to_mod == 'udp_dport':
Rich Lanee717c6e2013-03-12 10:25:50 -07001003 act = ofp.action.set_tp_dst()
Rich Lane110e0e32012-10-26 16:21:46 -07001004 act.tp_port = mod_field_vals['udp_dport']
Dan Talayco4b2bee62010-07-20 14:10:05 -07001005 else:
1006 parent.assertTrue(0, "Unknown field to modify: " + str(field_to_mod))
1007
1008 return act
1009
1010def pkt_action_setup(parent, start_field_vals={}, mod_field_vals={},
Rich Lane110e0e32012-10-26 16:21:46 -07001011 mod_fields=[], tp="tcp", check_test_params=False):
Dan Talayco4b2bee62010-07-20 14:10:05 -07001012 """
1013 Set up the ingress and expected packet and action list for a test
1014
Rich Lane2014f9b2012-10-05 15:29:40 -07001015 @param parent Must implement assertTrue
Dan Talayco4b2bee62010-07-20 14:10:05 -07001016 @param start_field_values Field values to use for ingress packet (optional)
1017 @param mod_field_values Field values to use for modified packet (optional)
1018 @param mod_fields The list of fields to be modified by the switch in the test.
1019 @params check_test_params If True, will check the parameters vid, add_vlan
1020 and strip_vlan from the command line.
1021
1022 Returns a triple: pkt-to-send, expected-pkt, action-list
1023 """
1024
1025 new_actions = []
1026
Dan Talayco4b2bee62010-07-20 14:10:05 -07001027 base_pkt_params = {}
1028 base_pkt_params['pktlen'] = 100
Rich Laned0478ff2013-03-11 12:46:58 -07001029 base_pkt_params['eth_dst'] = '00:DE:F0:12:34:56'
1030 base_pkt_params['eth_src'] = '00:23:45:67:89:AB'
Dan Talayco4b2bee62010-07-20 14:10:05 -07001031 base_pkt_params['dl_vlan_enable'] = False
Rich Laned0478ff2013-03-11 12:46:58 -07001032 base_pkt_params['vlan_vid'] = 2
1033 base_pkt_params['vlan_pcp'] = 0
Dan Talayco4b2bee62010-07-20 14:10:05 -07001034 base_pkt_params['ip_src'] = '192.168.0.1'
1035 base_pkt_params['ip_dst'] = '192.168.0.2'
1036 base_pkt_params['ip_tos'] = 0
Rich Lane110e0e32012-10-26 16:21:46 -07001037 if tp == "tcp":
1038 base_pkt_params['tcp_sport'] = 1234
1039 base_pkt_params['tcp_dport'] = 80
1040 elif tp == "udp":
1041 base_pkt_params['udp_sport'] = 1234
1042 base_pkt_params['udp_dport'] = 80
Dan Talayco4b2bee62010-07-20 14:10:05 -07001043 for keyname in start_field_vals.keys():
1044 base_pkt_params[keyname] = start_field_vals[keyname]
1045
1046 mod_pkt_params = {}
1047 mod_pkt_params['pktlen'] = 100
Rich Laned0478ff2013-03-11 12:46:58 -07001048 mod_pkt_params['eth_dst'] = '00:21:0F:ED:CB:A9'
1049 mod_pkt_params['eth_src'] = '00:ED:CB:A9:87:65'
Dan Talayco4b2bee62010-07-20 14:10:05 -07001050 mod_pkt_params['dl_vlan_enable'] = False
Rich Laned0478ff2013-03-11 12:46:58 -07001051 mod_pkt_params['vlan_vid'] = 3
1052 mod_pkt_params['vlan_pcp'] = 7
Dan Talayco4b2bee62010-07-20 14:10:05 -07001053 mod_pkt_params['ip_src'] = '10.20.30.40'
1054 mod_pkt_params['ip_dst'] = '50.60.70.80'
1055 mod_pkt_params['ip_tos'] = 0xf0
Rich Lane110e0e32012-10-26 16:21:46 -07001056 if tp == "tcp":
1057 mod_pkt_params['tcp_sport'] = 4321
1058 mod_pkt_params['tcp_dport'] = 8765
1059 elif tp == "udp":
1060 mod_pkt_params['udp_sport'] = 4321
1061 mod_pkt_params['udp_dport'] = 8765
Dan Talayco4b2bee62010-07-20 14:10:05 -07001062 for keyname in mod_field_vals.keys():
1063 mod_pkt_params[keyname] = mod_field_vals[keyname]
1064
1065 # Check for test param modifications
1066 strip = False
1067 if check_test_params:
Rich Lane2014f9b2012-10-05 15:29:40 -07001068 add_vlan = test_param_get('add_vlan')
1069 strip_vlan = test_param_get('strip_vlan')
1070 vid = test_param_get('vid')
Dan Talayco4b2bee62010-07-20 14:10:05 -07001071
1072 if add_vlan and strip_vlan:
1073 parent.assertTrue(0, "Add and strip VLAN both specified")
1074
1075 if vid:
1076 base_pkt_params['dl_vlan_enable'] = True
Rich Laned0478ff2013-03-11 12:46:58 -07001077 base_pkt_params['vlan_vid'] = vid
1078 if 'vlan_vid' in mod_fields:
1079 mod_pkt_params['vlan_vid'] = vid + 1
Dan Talayco4b2bee62010-07-20 14:10:05 -07001080
1081 if add_vlan:
1082 base_pkt_params['dl_vlan_enable'] = False
1083 mod_pkt_params['dl_vlan_enable'] = True
1084 mod_pkt_params['pktlen'] = base_pkt_params['pktlen'] + 4
1085 mod_fields.append('pktlen')
1086 mod_fields.append('dl_vlan_enable')
Rich Laned0478ff2013-03-11 12:46:58 -07001087 if 'vlan_vid' not in mod_fields:
1088 mod_fields.append('vlan_vid')
Dan Talayco4b2bee62010-07-20 14:10:05 -07001089 elif strip_vlan:
1090 base_pkt_params['dl_vlan_enable'] = True
1091 mod_pkt_params['dl_vlan_enable'] = False
1092 mod_pkt_params['pktlen'] = base_pkt_params['pktlen'] - 4
1093 mod_fields.append('dl_vlan_enable')
1094 mod_fields.append('pktlen')
1095
Rich Lane110e0e32012-10-26 16:21:46 -07001096 if tp == "tcp":
1097 packet_builder = simple_tcp_packet
1098 elif tp == "udp":
1099 packet_builder = simple_udp_packet
1100 else:
1101 raise NotImplementedError("unknown transport protocol %s" % tp)
1102
Dan Talayco4b2bee62010-07-20 14:10:05 -07001103 # Build the ingress packet
Rich Lane110e0e32012-10-26 16:21:46 -07001104 ingress_pkt = packet_builder(**base_pkt_params)
Dan Talayco4b2bee62010-07-20 14:10:05 -07001105
1106 # Build the expected packet, modifying the indicated fields
1107 for item in mod_fields:
1108 base_pkt_params[item] = mod_pkt_params[item]
1109 act = action_generate(parent, item, mod_pkt_params)
1110 if act:
1111 new_actions.append(act)
1112
Rich Lane110e0e32012-10-26 16:21:46 -07001113 expected_pkt = packet_builder(**base_pkt_params)
Dan Talayco4b2bee62010-07-20 14:10:05 -07001114
1115 return (ingress_pkt, expected_pkt, new_actions)
Dan Talayco677c0b72011-08-23 22:53:38 -07001116
1117# Generate a simple "drop" flow mod
1118# If in_band is true, then only drop from first test port
1119def flow_mod_gen(port_map, in_band):
Rich Lanee717c6e2013-03-12 10:25:50 -07001120 request = ofp.message.flow_add()
1121 request.match.wildcards = ofp.OFPFW_ALL
Dan Talayco677c0b72011-08-23 22:53:38 -07001122 if in_band:
Rich Lanee717c6e2013-03-12 10:25:50 -07001123 request.match.wildcards = ofp.OFPFW_ALL - ofp.OFPFW_IN_PORT
Dan Talayco677c0b72011-08-23 22:53:38 -07001124 for of_port, ifname in port_map.items(): # Grab first port
1125 break
1126 request.match.in_port = of_port
1127 request.buffer_id = 0xffffffff
1128 return request
Dan Talaycoba3745c2010-07-21 21:51:08 -07001129
1130def skip_message_emit(parent, s):
1131 """
1132 Print out a 'skipped' message to stderr
1133
1134 @param s The string to print out to the log file
Dan Talaycoba3745c2010-07-21 21:51:08 -07001135 """
1136 global skipped_test_count
1137
1138 skipped_test_count += 1
Rich Lane9a003812012-10-04 17:17:59 -07001139 logging.info("Skipping: " + s)
Dan Talayco2940fdd2013-02-06 15:01:35 -08001140 if oftest.config["debug"] < logging.WARNING:
Dan Talaycoba3745c2010-07-21 21:51:08 -07001141 sys.stderr.write("(skipped) ")
1142 else:
1143 sys.stderr.write("(S)")
Dan Talayco677c0b72011-08-23 22:53:38 -07001144
Dan Talayco8a64e332012-03-28 14:53:20 -07001145
1146def all_stats_get(parent):
1147 """
1148 Get the aggregate stats for all flows in the table
1149 @param parent Test instance with controller connection and assert
1150 @returns dict with keys flows, packets, bytes, active (flows),
1151 lookups, matched
1152 """
Rich Lanee717c6e2013-03-12 10:25:50 -07001153 stat_req = ofp.message.aggregate_stats_request()
1154 stat_req.match = ofp.match()
1155 stat_req.match.wildcards = ofp.OFPFW_ALL
Dan Talayco8a64e332012-03-28 14:53:20 -07001156 stat_req.table_id = 0xff
Rich Lanee717c6e2013-03-12 10:25:50 -07001157 stat_req.out_port = ofp.OFPP_NONE
Dan Talayco8a64e332012-03-28 14:53:20 -07001158
1159 rv = {}
1160
Rich Lanec8aaa3e2012-07-26 19:28:02 -07001161 (reply, pkt) = parent.controller.transact(stat_req)
Rich Lane5fd6faf2013-03-11 13:30:20 -07001162 parent.assertTrue(len(reply.entries) == 1, "Did not receive flow stats reply")
Dan Talayco8a64e332012-03-28 14:53:20 -07001163
Rich Lane5fd6faf2013-03-11 13:30:20 -07001164 for obj in reply.entries:
Dan Talayco8a64e332012-03-28 14:53:20 -07001165 (rv["flows"], rv["packets"], rv["bytes"]) = (obj.flow_count,
1166 obj.packet_count, obj.byte_count)
1167 break
1168
Rich Lanee717c6e2013-03-12 10:25:50 -07001169 request = ofp.message.table_stats_request()
Rich Lanec8aaa3e2012-07-26 19:28:02 -07001170 (reply , pkt) = parent.controller.transact(request)
Dan Talayco8a64e332012-03-28 14:53:20 -07001171
1172
1173 (rv["active"], rv["lookups"], rv["matched"]) = (0,0,0)
Rich Lane5fd6faf2013-03-11 13:30:20 -07001174 for obj in reply.entries:
Dan Talayco8a64e332012-03-28 14:53:20 -07001175 rv["active"] += obj.active_count
1176 rv["lookups"] += obj.lookup_count
1177 rv["matched"] += obj.matched_count
1178
1179 return rv
Dan Talayco2baf8b52012-03-30 09:55:42 -07001180
Rich Lane7744e112013-01-11 17:23:57 -08001181_import_blacklist.add('FILTER')
Dan Talayco2baf8b52012-03-30 09:55:42 -07001182FILTER=''.join([(len(repr(chr(x)))==3) and chr(x) or '.'
1183 for x in range(256)])
1184
1185def hex_dump_buffer(src, length=16):
1186 """
1187 Convert src to a hex dump string and return the string
1188 @param src The source buffer
1189 @param length The number of bytes shown in each line
1190 @returns A string showing the hex dump
1191 """
Dan Talaycoc516fa02012-04-12 22:28:43 -07001192 result = ["\n"]
Dan Talayco2baf8b52012-03-30 09:55:42 -07001193 for i in xrange(0, len(src), length):
1194 chars = src[i:i+length]
1195 hex = ' '.join(["%02x" % ord(x) for x in chars])
1196 printable = ''.join(["%s" % ((ord(x) <= 127 and
1197 FILTER[ord(x)]) or '.') for x in chars])
1198 result.append("%04x %-*s %s\n" % (i, length*3, hex, printable))
1199 return ''.join(result)
1200
1201def format_packet(pkt):
1202 return "Packet length %d \n%s" % (len(str(pkt)),
1203 hex_dump_buffer(str(pkt)))
Rich Lane5d7e89a2012-10-26 16:43:13 -07001204
1205def inspect_packet(pkt):
1206 """
1207 Wrapper around scapy's show() method.
1208 @returns A string showing the dissected packet.
1209 """
1210 from cStringIO import StringIO
1211 out = None
1212 backup = sys.stdout
1213 try:
Rich Lanefdec0fb2013-08-09 18:01:05 -07001214 tmp = StringIO()
1215 sys.stdout = tmp
Rich Lane5d7e89a2012-10-26 16:43:13 -07001216 pkt.show2()
Rich Lanefdec0fb2013-08-09 18:01:05 -07001217 out = tmp.getvalue()
1218 tmp.close()
Rich Lane5d7e89a2012-10-26 16:43:13 -07001219 finally:
1220 sys.stdout = backup
1221 return out
Rich Lane0a4f6372013-01-02 14:40:22 -08001222
1223def nonstandard(cls):
1224 """
Rich Lanecc45b8e2013-01-02 15:55:02 -08001225 Testcase decorator that marks the test as being non-standard.
1226 These tests are not automatically added to the "standard" group.
Rich Lane0a4f6372013-01-02 14:40:22 -08001227 """
Rich Lanecc45b8e2013-01-02 15:55:02 -08001228 cls._nonstandard = True
Rich Lane0a4f6372013-01-02 14:40:22 -08001229 return cls
1230
1231def disabled(cls):
1232 """
Rich Lanecc45b8e2013-01-02 15:55:02 -08001233 Testcase decorator that marks the test as being disabled.
1234 These tests are not automatically added to the "standard" group or
1235 their module's group.
Rich Lane0a4f6372013-01-02 14:40:22 -08001236 """
Rich Lanecc45b8e2013-01-02 15:55:02 -08001237 cls._disabled = True
Rich Lane0a4f6372013-01-02 14:40:22 -08001238 return cls
Rich Lane97e99652013-01-02 17:23:20 -08001239
1240def group(name):
1241 """
1242 Testcase decorator that adds the test to a group.
1243 """
1244 def fn(cls):
1245 if not hasattr(cls, "_groups"):
1246 cls._groups = []
1247 cls._groups.append(name)
1248 return cls
1249 return fn
Rich Lane5a9a1922013-01-11 14:29:30 -08001250
1251def version(ver):
1252 """
1253 Testcase decorator that specifies which versions of OpenFlow the test
1254 supports. The default is 1.0+. This decorator may only be used once.
1255
1256 Supported syntax:
1257 1.0 -> 1.0
1258 1.0,1.2,1.3 -> 1.0, 1.2, 1.3
1259 1.0+ -> 1.0, 1.1, 1.2, 1.3
1260 """
1261 versions = parse_version(ver)
1262 def fn(cls):
1263 cls._versions = versions
1264 return cls
1265 return fn
1266
1267def parse_version(ver):
1268 allowed_versions = ["1.0", "1.1", "1.2", "1.3"]
1269 if re.match("^1\.\d+$", ver):
1270 versions = set([ver])
1271 elif re.match("^(1\.\d+)\+$", ver):
1272 if not ver[:-1] in allowed_versions:
1273 raise ValueError("invalid OpenFlow version %s" % ver[:-1])
1274 versions = set()
1275 if ver != "1.1+": versions.add("1.0")
1276 if ver != "1.2+": versions.add("1.1")
1277 if ver != "1.3+": versions.add("1.2")
1278 versions.add("1.3")
1279 else:
1280 versions = set(ver.split(','))
1281
1282 for version in versions:
1283 if not version in allowed_versions:
1284 raise ValueError("invalid OpenFlow version %s" % version)
1285
1286 return versions
1287
1288assert(parse_version("1.0") == set(["1.0"]))
1289assert(parse_version("1.0,1.2,1.3") == set(["1.0", "1.2", "1.3"]))
1290assert(parse_version("1.0+") == set(["1.0", "1.1", "1.2", "1.3"]))
Rich Lane7744e112013-01-11 17:23:57 -08001291
Rich Laneae3428c2013-03-07 14:37:42 -08001292def get_stats(test, req):
1293 """
1294 Retrieve a list of stats entries. Handles OFPSF_REPLY_MORE.
1295 """
Rich Lanebd56ed62013-07-10 15:49:44 -07001296 if ofp.OFP_VERSION <= 3:
1297 more_flag = ofp.OFPSF_REPLY_MORE
1298 else:
1299 more_flag = ofp.OFPMPF_REPLY_MORE
Rich Laneae3428c2013-03-07 14:37:42 -08001300 stats = []
1301 reply, _ = test.controller.transact(req)
1302 test.assertTrue(reply is not None, "No response to stats request")
Rich Lane5fd6faf2013-03-11 13:30:20 -07001303 stats.extend(reply.entries)
Rich Lanebd56ed62013-07-10 15:49:44 -07001304 while reply.flags & more_flag != 0:
Rich Lane720eaf22013-08-09 18:00:45 -07001305 reply, pkt = test.controller.poll(exp_msg=ofp.OFPT_STATS_REPLY)
Rich Laneae3428c2013-03-07 14:37:42 -08001306 test.assertTrue(reply is not None, "No response to stats request")
Rich Lane5fd6faf2013-03-11 13:30:20 -07001307 stats.extend(reply.entries)
Rich Laneae3428c2013-03-07 14:37:42 -08001308 return stats
1309
Rich Lanebd56ed62013-07-10 15:49:44 -07001310def get_flow_stats(test, match, table_id=None,
1311 out_port=None, out_group=None,
1312 cookie=0, cookie_mask=0):
Rich Laneae3428c2013-03-07 14:37:42 -08001313 """
1314 Retrieve a list of flow stats entries.
1315 """
Rich Lanebd56ed62013-07-10 15:49:44 -07001316
1317 if table_id == None:
1318 if ofp.OFP_VERSION <= 2:
1319 table_id = 0xff
1320 else:
1321 table_id = ofp.OFPTT_ALL
1322
Rich Lanef3bc48c2013-05-03 17:39:35 -07001323 if out_port == None:
Rich Lanebd56ed62013-07-10 15:49:44 -07001324 if ofp.OFP_VERSION == 1:
1325 out_port = ofp.OFPP_NONE
1326 else:
1327 out_port = ofp.OFPP_ANY
1328
1329 if out_group == None:
1330 if ofp.OFP_VERSION > 1:
1331 out_group = ofp.OFPP_ANY
1332
Rich Lanee717c6e2013-03-12 10:25:50 -07001333 req = ofp.message.flow_stats_request(match=match,
Rich Lanebd56ed62013-07-10 15:49:44 -07001334 table_id=table_id,
1335 out_port=out_port)
1336 if ofp.OFP_VERSION > 1:
1337 req.out_group = out_group
1338 req.cookie = cookie
1339 req.cookie_mask = cookie_mask
1340
Rich Laneae3428c2013-03-07 14:37:42 -08001341 return get_stats(test, req)
1342
Rich Lane968b6192013-03-07 15:34:43 -08001343def get_port_stats(test, port_no):
1344 """
1345 Retrieve a list of port stats entries.
1346 """
Rich Lanee717c6e2013-03-12 10:25:50 -07001347 req = ofp.message.port_stats_request(port_no=port_no)
Rich Lane968b6192013-03-07 15:34:43 -08001348 return get_stats(test, req)
1349
Rich Lane6a334922013-03-07 16:14:52 -08001350def get_queue_stats(test, port_no, queue_id):
1351 """
1352 Retrieve a list of queue stats entries.
1353 """
Rich Lanee717c6e2013-03-12 10:25:50 -07001354 req = ofp.message.queue_stats_request(port_no=port_no, queue_id=queue_id)
Rich Lane6a334922013-03-07 16:14:52 -08001355 return get_stats(test, req)
1356
Rich Laneae3428c2013-03-07 14:37:42 -08001357def verify_flow_stats(test, match, table_id=0xff,
Rich Lanef3bc48c2013-05-03 17:39:35 -07001358 out_port=None,
Rich Laneae3428c2013-03-07 14:37:42 -08001359 initial=[],
1360 pkts=None, bytes=None):
1361 """
1362 Verify that flow stats changed as expected.
1363
1364 Optionally takes an 'initial' list of stats entries, as returned by
1365 get_flow_stats(). If 'initial' is not given the counters are assumed to
1366 begin at 0.
1367 """
Rich Lanef3bc48c2013-05-03 17:39:35 -07001368 if out_port == None:
1369 out_port = ofp.OFPP_NONE
1370
Rich Laneae3428c2013-03-07 14:37:42 -08001371 def accumulate(stats):
1372 pkts_acc = bytes_acc = 0
1373 for stat in stats:
1374 pkts_acc += stat.packet_count
1375 bytes_acc += stat.byte_count
1376 return (pkts_acc, bytes_acc)
1377
1378 pkts_before, bytes_before = accumulate(initial)
1379
1380 # Wait 10s for counters to update
1381 pkt_diff = byte_diff = None
1382 for i in range(0, 100):
1383 stats = get_flow_stats(test, match, table_id=table_id, out_port=out_port)
1384 pkts_after, bytes_after = accumulate(stats)
1385 pkt_diff = pkts_after - pkts_before
1386 byte_diff = bytes_after - bytes_before
1387 if (pkts == None or pkt_diff >= pkts) and \
1388 (bytes == None or byte_diff >= bytes):
1389 break
Dan Talayco53724732013-03-08 23:54:02 -08001390 time.sleep(0.1)
Rich Laneae3428c2013-03-07 14:37:42 -08001391
1392 if pkts != None:
1393 test.assertEquals(pkt_diff, pkts, "Flow packet counter not updated properly (expected increase of %d, got increase of %d)" % (pkts, pkt_diff))
1394
1395 if bytes != None:
Rich Lane53b96812013-03-07 16:54:50 -08001396 test.assertTrue(byte_diff >= bytes and byte_diff <= bytes*1.1,
1397 "Flow byte counter not updated properly (expected increase of %d, got increase of %d)" % (bytes, byte_diff))
Rich Laneae3428c2013-03-07 14:37:42 -08001398
Rich Lane968b6192013-03-07 15:34:43 -08001399def verify_port_stats(test, port,
1400 initial=[],
1401 tx_pkts=None, rx_pkts=None,
1402 tx_bytes=None, rx_bytes=None):
1403 """
1404 Verify that port stats changed as expected.
1405
1406 Optionally takes an 'initial' list of stats entries, as returned by
1407 get_port_stats(). If 'initial' is not given the counters are assumed to
1408 begin at 0.
1409 """
1410 def accumulate(stats):
1411 tx_pkts_acc = rx_pkts_acc = tx_bytes_acc = rx_bytes_acc = 0
1412 for stat in stats:
1413 tx_pkts_acc += stat.tx_packets
1414 rx_pkts_acc += stat.rx_packets
1415 tx_bytes_acc += stat.tx_bytes
1416 rx_bytes_acc += stat.rx_bytes
1417 return (tx_pkts_acc, rx_pkts_acc, tx_bytes_acc, rx_bytes_acc)
1418
1419 tx_pkts_before, rx_pkts_before, \
1420 tx_bytes_before, rx_bytes_before = accumulate(initial)
1421
1422 # Wait 10s for counters to update
1423 for i in range(0, 100):
1424 stats = get_port_stats(test, port)
1425 tx_pkts_after, rx_pkts_after, \
1426 tx_bytes_after, rx_bytes_after = accumulate(stats)
1427 tx_pkts_diff = tx_pkts_after - tx_pkts_before
1428 rx_pkts_diff = rx_pkts_after - rx_pkts_before
1429 tx_bytes_diff = tx_bytes_after - tx_bytes_before
1430 rx_bytes_diff = rx_bytes_after - rx_bytes_before
1431 if (tx_pkts == None or tx_pkts == tx_pkts_diff) and \
1432 (rx_pkts == None or rx_pkts == rx_pkts_diff) and \
Rich Lane53b96812013-03-07 16:54:50 -08001433 (tx_bytes == None or tx_bytes <= tx_bytes_diff) and \
1434 (rx_bytes == None or rx_bytes <= rx_bytes_diff):
Rich Lane968b6192013-03-07 15:34:43 -08001435 break
1436 time.sleep(0.1)
1437
1438 if (tx_pkts != None):
1439 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))
1440 if (rx_pkts != None):
1441 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))
1442 if (tx_bytes != None):
Rich Lane53b96812013-03-07 16:54:50 -08001443 test.assertTrue(tx_bytes_diff >= tx_bytes and tx_bytes_diff <= tx_bytes*1.1,
1444 "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 -08001445 if (rx_bytes != None):
Rich Lane53b96812013-03-07 16:54:50 -08001446 test.assertTrue(rx_bytes_diff >= rx_bytes and rx_bytes_diff <= rx_bytes*1.1,
1447 "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 -08001448
Rich Lane6a334922013-03-07 16:14:52 -08001449def verify_queue_stats(test, port_no, queue_id,
1450 initial=[],
1451 pkts=None, bytes=None):
1452 """
1453 Verify that queue stats changed as expected.
1454
1455 Optionally takes an 'initial' list of stats entries, as returned by
1456 get_queue_stats(). If 'initial' is not given the counters are assumed to
1457 begin at 0.
1458 """
1459 def accumulate(stats):
1460 pkts_acc = bytes_acc = 0
1461 for stat in stats:
1462 pkts_acc += stat.tx_packets
1463 bytes_acc += stat.tx_bytes
1464 return (pkts_acc, bytes_acc)
1465
1466 pkts_before, bytes_before = accumulate(initial)
1467
1468 # Wait 10s for counters to update
1469 pkt_diff = byte_diff = None
1470 for i in range(0, 100):
1471 stats = get_queue_stats(test, port_no, queue_id)
1472 pkts_after, bytes_after = accumulate(stats)
1473 pkt_diff = pkts_after - pkts_before
1474 byte_diff = bytes_after - bytes_before
1475 if (pkts == None or pkt_diff >= pkts) and \
1476 (bytes == None or byte_diff >= bytes):
1477 break
Dan Talayco53724732013-03-08 23:54:02 -08001478 time.sleep(0.1)
Rich Lane6a334922013-03-07 16:14:52 -08001479
1480 if pkts != None:
1481 test.assertEquals(pkt_diff, pkts, "Queue packet counter not updated properly (expected increase of %d, got increase of %d)" % (pkts, pkt_diff))
1482
1483 if bytes != None:
Rich Lane53b96812013-03-07 16:54:50 -08001484 test.assertTrue(byte_diff >= bytes and byte_diff <= bytes*1.1,
1485 "Queue byte counter not updated properly (expected increase of %d, got increase of %d)" % (bytes, byte_diff))
Rich Laneae3428c2013-03-07 14:37:42 -08001486
Rich Lane4c504f32013-06-07 17:24:14 -07001487def packet_in_match(msg, data, in_port=None, reason=None):
1488 """
1489 Check whether the packet_in message 'msg' has fields matching 'data',
1490 'in_port', and 'reason'.
1491
1492 This function handles truncated packet_in data. The 'in_port' and 'reason'
1493 parameters are optional.
1494
1495 @param msg packet_in message
1496 @param data Expected packet_in data
1497 @param in_port Expected packet_in in_port, or None
1498 @param reason Expected packet_in reason, or None
1499 """
1500
Rich Lanec0d26dd2013-07-10 12:46:03 -07001501 if ofp.OFP_VERSION <= 2:
1502 pkt_in_port = msg.in_port
1503 else:
1504 oxms = { type(oxm): oxm for oxm in msg.match.oxm_list }
1505 if ofp.oxm.in_port in oxms:
1506 pkt_in_port = oxms[ofp.oxm.in_port].value
1507 else:
1508 logging.warn("Missing in_port in packet-in message")
1509 pkt_in_port = None
1510
1511 if in_port != None and in_port != pkt_in_port:
Rich Lane9f2f17e2013-09-13 13:19:37 -07001512 logging.debug("Incorrect packet_in in_port (expected %d, received %d)", in_port, pkt_in_port)
Rich Lane4c504f32013-06-07 17:24:14 -07001513 return False
1514
Rich Lanec0d26dd2013-07-10 12:46:03 -07001515 if reason != None and reason != msg.reason:
Rich Lane4c504f32013-06-07 17:24:14 -07001516 logging.debug("Incorrect packet_in reason (expected %d, received %d)", reason, msg.reason)
1517 return False
1518
1519 # Check that one of the packets is a prefix of the other.
1520 # The received packet may be either truncated or padded, but not both.
1521 # (Some of the padding may be truncated but that's irrelevant). We
1522 # need to check that the smaller packet is a prefix of the larger one.
1523 # Note that this check succeeds if the switch sends a zero-length
1524 # packet-in.
1525 compare_len = min(len(msg.data), len(data))
1526 if data[:compare_len] != msg.data[:compare_len]:
1527 logging.debug("Incorrect packet_in data")
1528 logging.debug("Expected %s" % format_packet(data[:compare_len]))
1529 logging.debug("Received %s" % format_packet(msg.data[:compare_len]))
1530 return False
1531
1532 return True
1533
1534def verify_packet_in(test, data, in_port, reason, controller=None):
1535 """
1536 Assert that the controller receives a packet_in message matching data 'data'
1537 from port 'in_port' with reason 'reason'. Does not trigger the packet_in
1538 itself, that's up to the test case.
1539
1540 @param test Instance of base_tests.SimpleProtocol
1541 @param pkt String to expect as the packet_in data
1542 @param in_port OpenFlow port number to expect as the packet_in in_port
1543 @param reason One of OFPR_* to expect as the packet_in reason
1544 @param controller Controller instance, defaults to test.controller
1545 @returns The received packet-in message
1546 """
1547
1548 if controller == None:
1549 controller = test.controller
1550
1551 end_time = time.time() + oftest.ofutils.default_timeout
1552
1553 while True:
1554 msg, _ = controller.poll(ofp.OFPT_PACKET_IN, end_time - time.time())
1555 if not msg:
1556 # Timeout
1557 break
1558 elif packet_in_match(msg, data, in_port, reason):
1559 # Found a matching message
1560 break
1561
1562 test.assertTrue(msg is not None, 'Packet in message not received on port %d' % in_port)
1563 return msg
1564
1565def verify_no_packet_in(test, data, in_port, controller=None):
1566 """
1567 Assert that the controller does not receive a packet_in message matching
1568 data 'data' from port 'in_port'.
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 controller Controller instance, defaults to test.controller
1574 """
1575
1576 if controller == None:
1577 controller = test.controller
1578
1579 # Negative test, need to wait a short amount of time before checking we
1580 # didn't receive the message.
1581 time.sleep(0.5)
1582
1583 # Check every packet_in queued in the controller
1584 while True:
1585 msg, _ = controller.poll(ofp.OFPT_PACKET_IN, timeout=0)
1586 if msg == None:
1587 # No more queued packet_in messages
1588 break
1589 elif packet_in_match(msg, data, in_port, None):
1590 # Found a matching message
1591 break
1592
Rich Lane82c882d2013-08-09 17:13:52 -07001593 if in_port == None:
1594 test.assertTrue(msg == None, "Did not expect a packet-in message on any port")
1595 else:
1596 test.assertTrue(msg == None, "Did not expect a packet-in message on port %d" % in_port)
Rich Lane4c504f32013-06-07 17:24:14 -07001597
Rich Lane045db072013-08-06 13:16:30 -07001598def openflow_ports(num=None):
1599 """
1600 Return a list of 'num' OpenFlow port numbers
1601
1602 If 'num' is None, return all available ports. Otherwise, limit the length
1603 of the result to 'num' and raise an exception if not enough ports are
1604 available.
1605 """
1606 ports = sorted(oftest.config["port_map"].keys())
1607 if num != None and len(ports) < num:
1608 raise Exception("test requires %d ports but only %d are available" % (num, len(ports)))
1609 return ports[:num]
1610
Rich Lanee4b384d2013-09-13 14:33:40 -07001611def verify_packet(test, pkt, ofport):
1612 """
1613 Check that an expected packet is received
1614 """
1615 logging.debug("Checking for pkt on port %r", ofport)
1616 (rcv_port, rcv_pkt, pkt_time) = test.dataplane.poll(port_number=ofport, exp_pkt=str(pkt))
1617 test.assertTrue(rcv_pkt != None, "Did not receive pkt on %r" % ofport)
1618
1619def verify_no_packet(test, pkt, ofport):
1620 """
1621 Check that a particular packet is not received
1622 """
1623 logging.debug("Negative check for pkt on port %r", ofport)
1624 (rcv_port, rcv_pkt, pkt_time) = test.dataplane.poll(port_number=ofport, exp_pkt=str(pkt), timeout=0.01)
1625 test.assertTrue(rcv_pkt == None, "Received packet on %r" % ofport)
1626
1627def verify_no_other_packets(test):
1628 """
1629 Check that no unexpected packets are received
1630
1631 This is a no-op if the --relax option is in effect.
1632 """
1633 if oftest.config["relax"]:
1634 return
1635 logging.debug("Checking for unexpected packets on all ports")
1636 (rcv_port, rcv_pkt, pkt_time) = test.dataplane.poll(timeout=0.01)
1637 if rcv_pkt != None:
1638 logging.debug("Received unexpected packet on port %r: %s", rcv_port, format_packet(rcv_pkt))
1639 test.assertTrue(rcv_pkt == None, "Unexpected packet on port %r" % rcv_port)
1640
1641def verify_packets(test, pkt, ofports):
1642 """
1643 Check that a packet is received on certain ports
1644
1645 Also verifies that the packet is not received on any other ports, and that no
1646 other packets are received (unless --relax is in effect).
1647
1648 This covers the common and simplest cases for checking dataplane outputs.
1649 For more complex usage, like multiple different packets being output, or
1650 multiple packets on the same port, use the primitive verify_packet,
1651 verify_no_packet, and verify_no_other_packets functions directly.
1652 """
1653 pkt = str(pkt)
1654 for ofport in openflow_ports():
1655 if ofport in ofports:
1656 verify_packet(test, pkt, ofport)
1657 else:
1658 verify_no_packet(test, pkt, ofport)
1659 verify_no_other_packets(test)
1660
1661
Rich Lane7744e112013-01-11 17:23:57 -08001662__all__ = list(set(locals()) - _import_blacklist)