blob: d6fa850074b0bbec391795d5150c2d48d18ee642 [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
Tony van der Peet80c5b202013-11-20 11:47:48 +130028def delete_all_flows(ctrl, send_barrier=True):
Dan Talayco41eae8b2010-03-10 13:57:06 -080029 """
30 Delete all flows on the switch
31 @param ctrl The controller object for the test
Tony van der Peet80c5b202013-11-20 11:47:48 +130032 @param send_barrier Whether or not to send a barrier message
Dan Talayco41eae8b2010-03-10 13:57:06 -080033 """
34
Rich Lane9a003812012-10-04 17:17:59 -070035 logging.info("Deleting all flows")
Rich Lanee717c6e2013-03-12 10:25:50 -070036 msg = ofp.message.flow_delete()
Rich Lanec717f442013-06-13 15:49:09 -070037 if ofp.OFP_VERSION in [1, 2]:
38 msg.match.wildcards = ofp.OFPFW_ALL
39 msg.out_port = ofp.OFPP_NONE
40 msg.buffer_id = 0xffffffff
41 elif ofp.OFP_VERSION >= 3:
42 msg.table_id = ofp.OFPTT_ALL
43 msg.buffer_id = ofp.OFP_NO_BUFFER
44 msg.out_port = ofp.OFPP_ANY
45 msg.out_group = ofp.OFPG_ANY
Rich Lane5c3151c2013-01-03 17:15:41 -080046 ctrl.message_send(msg)
Tony van der Peet80c5b202013-11-20 11:47:48 +130047 if send_barrier:
48 do_barrier(ctrl)
Rich Lane32bf9482013-01-03 17:26:30 -080049 return 0 # for backwards compatibility
Dan Talayco41eae8b2010-03-10 13:57:06 -080050
Rich Lane5f3c9b22013-10-10 17:20:30 -070051def delete_all_groups(ctrl):
52 """
53 Delete all groups on the switch
54 @param ctrl The controller object for the test
55 """
56
57 logging.info("Deleting all groups")
Rich Lane5de5e632013-11-24 10:15:25 -080058 msg = ofp.message.group_delete(group_id=ofp.OFPG_ALL)
Rich Lane5f3c9b22013-10-10 17:20:30 -070059 ctrl.message_send(msg)
60 do_barrier(ctrl)
61
Ed Swierk99a74de2012-08-22 06:40:54 -070062def required_wildcards(parent):
Rich Lane2014f9b2012-10-05 15:29:40 -070063 w = test_param_get('required_wildcards', default='default')
Ed Swierk99a74de2012-08-22 06:40:54 -070064 if w == 'l3-l4':
Rich Lanee717c6e2013-03-12 10:25:50 -070065 return (ofp.OFPFW_NW_SRC_ALL | ofp.OFPFW_NW_DST_ALL | ofp.OFPFW_NW_TOS
66 | ofp.OFPFW_NW_PROTO | ofp.OFPFW_TP_SRC | ofp.OFPFW_TP_DST)
Ed Swierk99a74de2012-08-22 06:40:54 -070067 else:
68 return 0
69
Dan Talayco41eae8b2010-03-10 13:57:06 -080070def simple_tcp_packet(pktlen=100,
Rich Laned0478ff2013-03-11 12:46:58 -070071 eth_dst='00:01:02:03:04:05',
72 eth_src='00:06:07:08:09:0a',
Tatsuya Yabe460321e2010-05-25 17:50:49 -070073 dl_vlan_enable=False,
Rich Laned0478ff2013-03-11 12:46:58 -070074 vlan_vid=0,
75 vlan_pcp=0,
Dan Talayco551befa2010-07-15 17:05:32 -070076 dl_vlan_cfi=0,
Dan Talayco41eae8b2010-03-10 13:57:06 -080077 ip_src='192.168.0.1',
78 ip_dst='192.168.0.2',
Tatsuya Yabe460321e2010-05-25 17:50:49 -070079 ip_tos=0,
Gregor Maier9cc93342013-01-29 16:55:28 -080080 ip_ttl=64,
Dan Talayco41eae8b2010-03-10 13:57:06 -080081 tcp_sport=1234,
Christian Dickmann8b59b4b2012-09-23 16:48:30 -070082 tcp_dport=80,
83 ip_ihl=None,
84 ip_options=False
Dan Talayco41eae8b2010-03-10 13:57:06 -080085 ):
86 """
87 Return a simple dataplane TCP packet
88
89 Supports a few parameters:
90 @param len Length of packet in bytes w/o CRC
Rich Laned0478ff2013-03-11 12:46:58 -070091 @param eth_dst Destinatino MAC
92 @param eth_src Source MAC
Tatsuya Yabe460321e2010-05-25 17:50:49 -070093 @param dl_vlan_enable True if the packet is with vlan, False otherwise
Rich Laned0478ff2013-03-11 12:46:58 -070094 @param vlan_vid VLAN ID
95 @param vlan_pcp VLAN priority
Dan Talayco41eae8b2010-03-10 13:57:06 -080096 @param ip_src IP source
97 @param ip_dst IP destination
Tatsuya Yabe460321e2010-05-25 17:50:49 -070098 @param ip_tos IP ToS
Gregor Maier9cc93342013-01-29 16:55:28 -080099 @param ip_ttl IP TTL
Dan Talayco41eae8b2010-03-10 13:57:06 -0800100 @param tcp_dport TCP destination port
101 @param ip_sport TCP source port
102
103 Generates a simple TCP request. Users
104 shouldn't assume anything about this packet other than that
105 it is a valid ethernet/IP/TCP frame.
106 """
Jeffrey Townsend5cb7ed32012-08-17 18:11:01 +0000107
108 if MINSIZE > pktlen:
109 pktlen = MINSIZE
110
Dan Talayco551befa2010-07-15 17:05:32 -0700111 # Note Dot1Q.id is really CFI
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800112 if (dl_vlan_enable):
Rich Laned0478ff2013-03-11 12:46:58 -0700113 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
114 scapy.Dot1Q(prio=vlan_pcp, id=dl_vlan_cfi, vlan=vlan_vid)/ \
Gregor Maier9cc93342013-01-29 16:55:28 -0800115 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ttl=ip_ttl, ihl=ip_ihl)/ \
Tatsuya Yabe460321e2010-05-25 17:50:49 -0700116 scapy.TCP(sport=tcp_sport, dport=tcp_dport)
117 else:
Christian Dickmann8b59b4b2012-09-23 16:48:30 -0700118 if not ip_options:
Rich Laned0478ff2013-03-11 12:46:58 -0700119 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
Gregor Maier9cc93342013-01-29 16:55:28 -0800120 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ttl=ip_ttl, ihl=ip_ihl)/ \
Christian Dickmann8b59b4b2012-09-23 16:48:30 -0700121 scapy.TCP(sport=tcp_sport, dport=tcp_dport)
122 else:
Rich Laned0478ff2013-03-11 12:46:58 -0700123 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
Gregor Maier9cc93342013-01-29 16:55:28 -0800124 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 -0700125 scapy.TCP(sport=tcp_sport, dport=tcp_dport)
Tatsuya Yabe460321e2010-05-25 17:50:49 -0700126
Dan Talayco41eae8b2010-03-10 13:57:06 -0800127 pkt = pkt/("D" * (pktlen - len(pkt)))
128
129 return pkt
130
Rich Lane86aceb02013-07-17 18:45:38 -0700131def simple_tcpv6_packet(pktlen=100,
132 eth_dst='00:01:02:03:04:05',
133 eth_src='00:06:07:08:09:0a',
134 dl_vlan_enable=False,
135 vlan_vid=0,
136 vlan_pcp=0,
137 ipv6_src='2001:db8:85a3::8a2e:370:7334',
138 ipv6_dst='2001:db8:85a3::8a2e:370:7335',
139 ipv6_tc=0,
140 ipv6_hlim=64,
141 ipv6_fl=0,
142 tcp_sport=1234,
143 tcp_dport=80):
144 """
145 Return a simple IPv6/TCP packet
146
147 Supports a few parameters:
148 @param len Length of packet in bytes w/o CRC
149 @param eth_dst Destination MAC
150 @param eth_src Source MAC
151 @param dl_vlan_enable True if the packet is with vlan, False otherwise
152 @param vlan_vid VLAN ID
153 @param vlan_pcp VLAN priority
154 @param ipv6_src IPv6 source
155 @param ipv6_dst IPv6 destination
156 @param ipv6_tc IPv6 traffic class
157 @param ipv6_ttl IPv6 hop limit
158 @param ipv6_fl IPv6 flow label
159 @param tcp_dport TCP destination port
160 @param tcp_sport TCP source port
161
162 Generates a simple TCP request. Users shouldn't assume anything about this
163 packet other than that it is a valid ethernet/IPv6/TCP frame.
164 """
165
166 if MINSIZE > pktlen:
167 pktlen = MINSIZE
168
169 pkt = scapy.Ether(dst=eth_dst, src=eth_src)
170 if dl_vlan_enable or vlan_vid or vlan_pcp:
171 pkt /= scapy.Dot1Q(vlan=vlan_vid, prio=vlan_pcp)
172 pkt /= scapy.IPv6(src=ipv6_src, dst=ipv6_dst, fl=ipv6_fl, tc=ipv6_tc, hlim=ipv6_hlim)
173 pkt /= scapy.TCP(sport=tcp_sport, dport=tcp_dport)
174 pkt /= ("D" * (pktlen - len(pkt)))
175
176 return pkt
177
Rich Lane6ee7bea2012-10-26 16:19:29 -0700178def simple_udp_packet(pktlen=100,
Rich Laned0478ff2013-03-11 12:46:58 -0700179 eth_dst='00:01:02:03:04:05',
180 eth_src='00:06:07:08:09:0a',
Rich Lane6ee7bea2012-10-26 16:19:29 -0700181 dl_vlan_enable=False,
Rich Laned0478ff2013-03-11 12:46:58 -0700182 vlan_vid=0,
183 vlan_pcp=0,
Rich Lane6ee7bea2012-10-26 16:19:29 -0700184 dl_vlan_cfi=0,
185 ip_src='192.168.0.1',
186 ip_dst='192.168.0.2',
187 ip_tos=0,
Gregor Maier9cc93342013-01-29 16:55:28 -0800188 ip_ttl=64,
Rich Lane6ee7bea2012-10-26 16:19:29 -0700189 udp_sport=1234,
190 udp_dport=80,
191 ip_ihl=None,
192 ip_options=False
193 ):
194 """
195 Return a simple dataplane UDP packet
196
197 Supports a few parameters:
198 @param len Length of packet in bytes w/o CRC
Rich Laned0478ff2013-03-11 12:46:58 -0700199 @param eth_dst Destination MAC
200 @param eth_src Source MAC
Rich Lane6ee7bea2012-10-26 16:19:29 -0700201 @param dl_vlan_enable True if the packet is with vlan, False otherwise
Rich Laned0478ff2013-03-11 12:46:58 -0700202 @param vlan_vid VLAN ID
203 @param vlan_pcp VLAN priority
Rich Lane6ee7bea2012-10-26 16:19:29 -0700204 @param ip_src IP source
205 @param ip_dst IP destination
206 @param ip_tos IP ToS
Gregor Maier9cc93342013-01-29 16:55:28 -0800207 @param ip_ttl IP TTL
Rich Lane6ee7bea2012-10-26 16:19:29 -0700208 @param udp_dport UDP destination port
209 @param udp_sport UDP source port
210
211 Generates a simple UDP packet. Users shouldn't assume anything about
212 this packet other than that it is a valid ethernet/IP/UDP frame.
213 """
214
215 if MINSIZE > pktlen:
216 pktlen = MINSIZE
217
218 # Note Dot1Q.id is really CFI
219 if (dl_vlan_enable):
Rich Laned0478ff2013-03-11 12:46:58 -0700220 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
221 scapy.Dot1Q(prio=vlan_pcp, id=dl_vlan_cfi, vlan=vlan_vid)/ \
Gregor Maier9cc93342013-01-29 16:55:28 -0800222 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ttl=ip_ttl, ihl=ip_ihl)/ \
Rich Lane6ee7bea2012-10-26 16:19:29 -0700223 scapy.UDP(sport=udp_sport, dport=udp_dport)
224 else:
225 if not ip_options:
Rich Laned0478ff2013-03-11 12:46:58 -0700226 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
Gregor Maier9cc93342013-01-29 16:55:28 -0800227 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ttl=ip_ttl, ihl=ip_ihl)/ \
Rich Lane6ee7bea2012-10-26 16:19:29 -0700228 scapy.UDP(sport=udp_sport, dport=udp_dport)
229 else:
Rich Laned0478ff2013-03-11 12:46:58 -0700230 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
Gregor Maier9cc93342013-01-29 16:55:28 -0800231 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 -0700232 scapy.UDP(sport=udp_sport, dport=udp_dport)
233
234 pkt = pkt/("D" * (pktlen - len(pkt)))
235
236 return pkt
237
Rich Lane86aceb02013-07-17 18:45:38 -0700238def simple_udpv6_packet(pktlen=100,
239 eth_dst='00:01:02:03:04:05',
240 eth_src='00:06:07:08:09:0a',
241 dl_vlan_enable=False,
242 vlan_vid=0,
243 vlan_pcp=0,
244 ipv6_src='2001:db8:85a3::8a2e:370:7334',
245 ipv6_dst='2001:db8:85a3::8a2e:370:7335',
246 ipv6_tc=0,
247 ipv6_hlim=64,
248 ipv6_fl=0,
249 udp_sport=1234,
250 udp_dport=80):
251 """
252 Return a simple IPv6/UDP packet
253
254 Supports a few parameters:
255 @param len Length of packet in bytes w/o CRC
256 @param eth_dst Destination MAC
257 @param eth_src Source MAC
258 @param dl_vlan_enable True if the packet is with vlan, False otherwise
259 @param vlan_vid VLAN ID
260 @param vlan_pcp VLAN priority
261 @param ipv6_src IPv6 source
262 @param ipv6_dst IPv6 destination
263 @param ipv6_tc IPv6 traffic class
264 @param ipv6_ttl IPv6 hop limit
265 @param ipv6_fl IPv6 flow label
266 @param udp_dport UDP destination port
267 @param udp_sport UDP source port
268
269 Generates a simple UDP request. Users shouldn't assume anything about this
270 packet other than that it is a valid ethernet/IPv6/UDP frame.
271 """
272
273 if MINSIZE > pktlen:
274 pktlen = MINSIZE
275
276 pkt = scapy.Ether(dst=eth_dst, src=eth_src)
277 if dl_vlan_enable or vlan_vid or vlan_pcp:
278 pkt /= scapy.Dot1Q(vlan=vlan_vid, prio=vlan_pcp)
279 pkt /= scapy.IPv6(src=ipv6_src, dst=ipv6_dst, fl=ipv6_fl, tc=ipv6_tc, hlim=ipv6_hlim)
280 pkt /= scapy.UDP(sport=udp_sport, dport=udp_dport)
281 pkt /= ("D" * (pktlen - len(pkt)))
282
283 return pkt
284
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700285def simple_icmp_packet(pktlen=60,
Rich Laned0478ff2013-03-11 12:46:58 -0700286 eth_dst='00:01:02:03:04:05',
287 eth_src='00:06:07:08:09:0a',
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700288 dl_vlan_enable=False,
Rich Laned0478ff2013-03-11 12:46:58 -0700289 vlan_vid=0,
290 vlan_pcp=0,
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700291 ip_src='192.168.0.1',
292 ip_dst='192.168.0.2',
293 ip_tos=0,
Gregor Maier9cc93342013-01-29 16:55:28 -0800294 ip_ttl=64,
Harshmeet Singhd209c0b2014-01-28 09:48:58 -0600295 ip_id=1,
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700296 icmp_type=8,
Harshmeet Singhd209c0b2014-01-28 09:48:58 -0600297 icmp_code=0,
298 icmp_checksum=None,
299 icmp_data="0"):
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700300 """
301 Return a simple ICMP packet
302
303 Supports a few parameters:
304 @param len Length of packet in bytes w/o CRC
Rich Laned0478ff2013-03-11 12:46:58 -0700305 @param eth_dst Destinatino MAC
306 @param eth_src Source MAC
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700307 @param dl_vlan_enable True if the packet is with vlan, False otherwise
Rich Laned0478ff2013-03-11 12:46:58 -0700308 @param vlan_vid VLAN ID
309 @param vlan_pcp VLAN priority
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700310 @param ip_src IP source
311 @param ip_dst IP destination
312 @param ip_tos IP ToS
Gregor Maier9cc93342013-01-29 16:55:28 -0800313 @param ip_ttl IP TTL
Harshmeet Singhd209c0b2014-01-28 09:48:58 -0600314 @param ip_id IP Identification
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700315 @param icmp_type ICMP type
316 @param icmp_code ICMP code
Harshmeet Singhd209c0b2014-01-28 09:48:58 -0600317 @param icmp_checksum ICMP checksum
318 @param icmp_data ICMP data
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700319
320 Generates a simple ICMP ECHO REQUEST. Users
321 shouldn't assume anything about this packet other than that
322 it is a valid ethernet/ICMP frame.
323 """
Jeffrey Townsend5cb7ed32012-08-17 18:11:01 +0000324
325 if MINSIZE > pktlen:
326 pktlen = MINSIZE
327
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700328 if (dl_vlan_enable):
Rich Laned0478ff2013-03-11 12:46:58 -0700329 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
330 scapy.Dot1Q(prio=vlan_pcp, id=0, vlan=vlan_vid)/ \
Harshmeet Singhd209c0b2014-01-28 09:48:58 -0600331 scapy.IP(src=ip_src, dst=ip_dst, ttl=ip_ttl, tos=ip_tos, id=ip_id)/ \
332 scapy.ICMP(type=icmp_type, code=icmp_code, chksum=icmp_checksum)/ \
333 icmp_data
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700334 else:
Rich Laned0478ff2013-03-11 12:46:58 -0700335 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
Harshmeet Singhd209c0b2014-01-28 09:48:58 -0600336 scapy.IP(src=ip_src, dst=ip_dst, ttl=ip_ttl, tos=ip_tos, id=ip_id)/ \
337 scapy.ICMP(type=icmp_type, code=icmp_code, chksum=icmp_checksum)/ \
338 icmp_data
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700339
340 pkt = pkt/("0" * (pktlen - len(pkt)))
341
342 return pkt
343
Rich Lane86aceb02013-07-17 18:45:38 -0700344def simple_icmpv6_packet(pktlen=100,
345 eth_dst='00:01:02:03:04:05',
346 eth_src='00:06:07:08:09:0a',
347 dl_vlan_enable=False,
348 vlan_vid=0,
349 vlan_pcp=0,
350 ipv6_src='2001:db8:85a3::8a2e:370:7334',
351 ipv6_dst='2001:db8:85a3::8a2e:370:7335',
352 ipv6_tc=0,
353 ipv6_hlim=64,
354 ipv6_fl=0,
355 icmp_type=8,
356 icmp_code=0):
357 """
358 Return a simple ICMPv6 packet
359
360 Supports a few parameters:
361 @param len Length of packet in bytes w/o CRC
362 @param eth_dst Destination MAC
363 @param eth_src Source MAC
364 @param dl_vlan_enable True if the packet is with vlan, False otherwise
365 @param vlan_vid VLAN ID
366 @param vlan_pcp VLAN priority
367 @param ipv6_src IPv6 source
368 @param ipv6_dst IPv6 destination
369 @param ipv6_tc IPv6 traffic class
370 @param ipv6_ttl IPv6 hop limit
371 @param ipv6_fl IPv6 flow label
372 @param icmp_type ICMP type
373 @param icmp_code ICMP code
374
375 Generates a simple ICMP ECHO REQUEST. Users shouldn't assume anything
376 about this packet other than that it is a valid ethernet/IPv6/ICMP frame.
377 """
378
379 if MINSIZE > pktlen:
380 pktlen = MINSIZE
381
382 pkt = scapy.Ether(dst=eth_dst, src=eth_src)
383 if dl_vlan_enable or vlan_vid or vlan_pcp:
384 pkt /= scapy.Dot1Q(vlan=vlan_vid, prio=vlan_pcp)
385 pkt /= scapy.IPv6(src=ipv6_src, dst=ipv6_dst, fl=ipv6_fl, tc=ipv6_tc, hlim=ipv6_hlim)
386 pkt /= scapy.ICMPv6Unknown(type=icmp_type, code=icmp_code)
387 pkt /= ("D" * (pktlen - len(pkt)))
388
389 return pkt
390
Shudong Zhouc7562b12013-02-06 01:12:18 -0800391def simple_arp_packet(pktlen=60,
Rich Laned0478ff2013-03-11 12:46:58 -0700392 eth_dst='ff:ff:ff:ff:ff:ff',
393 eth_src='00:06:07:08:09:0a',
Rich Lanee01611f2014-01-15 14:55:11 -0800394 vlan_vid=0,
395 vlan_pcp=0,
Shudong Zhouc7562b12013-02-06 01:12:18 -0800396 arp_op=1,
397 ip_snd='192.168.0.1',
398 ip_tgt='192.168.0.2',
399 hw_snd='00:06:07:08:09:0a',
400 hw_tgt='00:00:00:00:00:00',
401 ):
402 """
403 Return a simple ARP packet
404
405 Supports a few parameters:
406 @param len Length of packet in bytes w/o CRC
Rich Laned0478ff2013-03-11 12:46:58 -0700407 @param eth_dst Destinatino MAC
408 @param eth_src Source MAC
Shudong Zhouc7562b12013-02-06 01:12:18 -0800409 @param arp_op Operation (1=request, 2=reply)
410 @param ip_snd Sender IP
411 @param ip_tgt Target IP
412 @param hw_snd Sender hardware address
413 @param hw_tgt Target hardware address
414
415 Generates a simple ARP REQUEST. Users
416 shouldn't assume anything about this packet other than that
417 it is a valid ethernet/ARP frame.
418 """
419
420 if MINSIZE > pktlen:
421 pktlen = MINSIZE
422
Rich Lanee01611f2014-01-15 14:55:11 -0800423 pkt = scapy.Ether(dst=eth_dst, src=eth_src)
424 if vlan_vid or vlan_pcp:
425 pkt /= scapy.Dot1Q(vlan=vlan_vid, prio=vlan_pcp)
426 pkt /= scapy.ARP(hwsrc=hw_snd, hwdst=hw_tgt, pdst=ip_tgt, psrc=ip_snd, op=arp_op)
Shudong Zhouc7562b12013-02-06 01:12:18 -0800427
Rich Laned459ce52014-01-24 12:09:54 -0800428 pkt = pkt/("\0" * (pktlen - len(pkt)))
Shudong Zhouc7562b12013-02-06 01:12:18 -0800429
430 return pkt
431
Ed Swierk0aeff8c2012-03-23 20:27:18 -0700432def simple_eth_packet(pktlen=60,
Rich Lane53275082013-11-18 23:26:22 -0800433 eth_dst='00:01:02:03:04:05',
434 eth_src='00:06:07:08:09:0a',
Rich Laned0478ff2013-03-11 12:46:58 -0700435 eth_type=0x88cc):
Jeffrey Townsend5cb7ed32012-08-17 18:11:01 +0000436
437 if MINSIZE > pktlen:
438 pktlen = MINSIZE
439
Rich Laned0478ff2013-03-11 12:46:58 -0700440 pkt = scapy.Ether(dst=eth_dst, src=eth_src, type=eth_type)
Ed Swierk0aeff8c2012-03-23 20:27:18 -0700441
442 pkt = pkt/("0" * (pktlen - len(pkt)))
443
444 return pkt
445
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800446def qinq_tcp_packet(pktlen=100,
Rich Laned0478ff2013-03-11 12:46:58 -0700447 eth_dst='00:01:02:03:04:05',
448 eth_src='00:06:07:08:09:0a',
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800449 dl_vlan_outer=20,
450 dl_vlan_pcp_outer=0,
451 dl_vlan_cfi_outer=0,
Rich Laned0478ff2013-03-11 12:46:58 -0700452 vlan_vid=10,
453 vlan_pcp=0,
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800454 dl_vlan_cfi=0,
455 ip_src='192.168.0.1',
456 ip_dst='192.168.0.2',
457 ip_tos=0,
Gregor Maier9cc93342013-01-29 16:55:28 -0800458 ip_ttl=64,
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800459 tcp_sport=1234,
460 tcp_dport=80,
461 ip_ihl=None,
462 ip_options=False
463 ):
464 """
465 Return a doubly tagged dataplane TCP packet
466
467 Supports a few parameters:
468 @param len Length of packet in bytes w/o CRC
Rich Laned0478ff2013-03-11 12:46:58 -0700469 @param eth_dst Destinatino MAC
470 @param eth_src Source MAC
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800471 @param dl_vlan_outer Outer VLAN ID
472 @param dl_vlan_pcp_outer Outer VLAN priority
473 @param dl_vlan_cfi_outer Outer VLAN cfi bit
Rich Laned0478ff2013-03-11 12:46:58 -0700474 @param vlan_vid Inner VLAN ID
475 @param vlan_pcp VLAN priority
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800476 @param dl_vlan_cfi VLAN cfi bit
477 @param ip_src IP source
478 @param ip_dst IP destination
479 @param ip_tos IP ToS
480 @param tcp_dport TCP destination port
481 @param ip_sport TCP source port
482
483 Generates a TCP request. Users
484 shouldn't assume anything about this packet other than that
485 it is a valid ethernet/IP/TCP frame.
486 """
487
488 if MINSIZE > pktlen:
489 pktlen = MINSIZE
490
491 # Note Dot1Q.id is really CFI
Rich Laned0478ff2013-03-11 12:46:58 -0700492 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800493 scapy.Dot1Q(prio=dl_vlan_pcp_outer, id=dl_vlan_cfi_outer, vlan=dl_vlan_outer)/ \
Rich Laned0478ff2013-03-11 12:46:58 -0700494 scapy.Dot1Q(prio=vlan_pcp, id=dl_vlan_cfi, vlan=vlan_vid)/ \
Gregor Maier9cc93342013-01-29 16:55:28 -0800495 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ttl=ip_ttl, ihl=ip_ihl)/ \
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800496 scapy.TCP(sport=tcp_sport, dport=tcp_dport)
497
498 pkt = pkt/("D" * (pktlen - len(pkt)))
499
500 return pkt
501
Shudong Zhoub7f12462012-11-20 13:01:12 -0800502def do_barrier(ctrl, timeout=-1):
Dan Talayco0fc08bd2012-04-09 16:56:18 -0700503 """
504 Do a barrier command
505 Return 0 on success, -1 on error
506 """
Rich Lanee717c6e2013-03-12 10:25:50 -0700507 b = ofp.message.barrier_request()
Shudong Zhoub7f12462012-11-20 13:01:12 -0800508 (resp, pkt) = ctrl.transact(b, timeout=timeout)
Rich Lane3a261d52013-01-03 17:45:08 -0800509 if resp is None:
510 raise AssertionError("barrier failed")
Dan Talaycof6b94832012-04-12 21:50:57 -0700511 # We'll trust the transaction processing in the controller that xid matched
Rich Lane3a261d52013-01-03 17:45:08 -0800512 return 0 # for backwards compatibility
Dan Talayco92c99122010-06-03 13:53:18 -0700513
Rich Lane9a003812012-10-04 17:17:59 -0700514def port_config_get(controller, port_no):
Dan Talayco92c99122010-06-03 13:53:18 -0700515 """
516 Get a port's configuration
517
518 Gets the switch feature configuration and grabs one port's
519 configuration
520
521 @returns (hwaddr, config, advert) The hwaddress, configuration and
522 advertised values
523 """
Rich Lane6dc865c2013-07-10 10:12:13 -0700524
525 if ofp.OFP_VERSION <= 3:
526 request = ofp.message.features_request()
527 reply, _ = controller.transact(request)
528 if reply is None:
529 logging.warn("Get feature request failed")
530 return None, None, None
531 logging.debug(reply.show())
532 ports = reply.ports
533 else:
534 request = ofp.message.port_desc_stats_request()
535 # TODO do multipart correctly
536 reply, _ = controller.transact(request)
537 if reply is None:
538 logging.warn("Port desc stats request failed")
539 return None, None, None
540 logging.debug(reply.show())
541 ports = reply.entries
542
543 for port in ports:
544 if port.port_no == port_no:
545 return (port.hw_addr, port.config, port.advertised)
Dan Talayco92c99122010-06-03 13:53:18 -0700546
Rich Lane9a003812012-10-04 17:17:59 -0700547 logging.warn("Did not find port number for port config")
Dan Talayco92c99122010-06-03 13:53:18 -0700548 return None, None, None
549
Rich Lane9a003812012-10-04 17:17:59 -0700550def port_config_set(controller, port_no, config, mask):
Dan Talayco92c99122010-06-03 13:53:18 -0700551 """
552 Set the port configuration according the given parameters
553
554 Gets the switch feature configuration and updates one port's
555 configuration value according to config and mask
556 """
Rich Lane9a003812012-10-04 17:17:59 -0700557 logging.info("Setting port " + str(port_no) + " to config " + str(config))
Rich Lane6dc865c2013-07-10 10:12:13 -0700558
559 hw_addr, _, _ = port_config_get(controller, port_no)
560
Rich Lanee717c6e2013-03-12 10:25:50 -0700561 mod = ofp.message.port_mod()
Dan Talayco92c99122010-06-03 13:53:18 -0700562 mod.port_no = port_no
Rich Lane6dc865c2013-07-10 10:12:13 -0700563 if hw_addr != None:
564 mod.hw_addr = hw_addr
Dan Talayco92c99122010-06-03 13:53:18 -0700565 mod.config = config
566 mod.mask = mask
Rich Lane6dc865c2013-07-10 10:12:13 -0700567 mod.advertise = 0 # No change
Rich Lane5c3151c2013-01-03 17:15:41 -0800568 controller.message_send(mod)
569 return 0
Dan Talayco92c99122010-06-03 13:53:18 -0700570
Rich Lane2014f9b2012-10-05 15:29:40 -0700571def receive_pkt_check(dp, pkt, yes_ports, no_ports, assert_if):
Dan Talayco92c99122010-06-03 13:53:18 -0700572 """
573 Check for proper receive packets across all ports
Ken Chiang1bf01602012-04-04 10:48:23 -0700574 @param dp The dataplane object
Dan Talayco92c99122010-06-03 13:53:18 -0700575 @param pkt Expected packet; may be None if yes_ports is empty
576 @param yes_ports Set or list of ports that should recieve packet
577 @param no_ports Set or list of ports that should not receive packet
578 @param assert_if Object that implements assertXXX
Rich Lanee4b384d2013-09-13 14:33:40 -0700579
580 DEPRECATED in favor in verify_packets
Dan Talayco92c99122010-06-03 13:53:18 -0700581 """
Rich Lane91765672012-12-06 16:33:04 -0800582
583 # Wait this long for packets that we don't expect to receive.
584 # 100ms is (rarely) too short for positive tests on slow
585 # switches but is definitely not too short for a negative test.
586 negative_timeout = 0.1
587
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700588 exp_pkt_arg = None
Rich Lanecd97d3d2013-01-07 18:50:06 -0800589 if oftest.config["relax"]:
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700590 exp_pkt_arg = pkt
591
Dan Talayco92c99122010-06-03 13:53:18 -0700592 for ofport in yes_ports:
Rich Lane9a003812012-10-04 17:17:59 -0700593 logging.debug("Checking for pkt on port " + str(ofport))
Ken Chiang1bf01602012-04-04 10:48:23 -0700594 (rcv_port, rcv_pkt, pkt_time) = dp.poll(
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700595 port_number=ofport, exp_pkt=exp_pkt_arg)
Dan Talayco92c99122010-06-03 13:53:18 -0700596 assert_if.assertTrue(rcv_pkt is not None,
597 "Did not receive pkt on " + str(ofport))
Rich Lanecd97d3d2013-01-07 18:50:06 -0800598 if not oftest.dataplane.match_exp_pkt(pkt, rcv_pkt):
Rich Lane3c266832013-01-29 18:29:15 -0800599 logging.debug("Expected %s" % format_packet(pkt))
600 logging.debug("Received %s" % format_packet(rcv_pkt))
Rich Lanecd97d3d2013-01-07 18:50:06 -0800601 assert_if.assertTrue(oftest.dataplane.match_exp_pkt(pkt, rcv_pkt),
Rich Lane3c266832013-01-29 18:29:15 -0800602 "Received packet does not match expected packet " +
Ken Chiang1bf01602012-04-04 10:48:23 -0700603 "on port " + str(ofport))
Dan Talayco73f84012012-10-02 09:23:18 -0700604 if len(no_ports) > 0:
Rich Lane91765672012-12-06 16:33:04 -0800605 time.sleep(negative_timeout)
Dan Talayco92c99122010-06-03 13:53:18 -0700606 for ofport in no_ports:
Rich Lane9a003812012-10-04 17:17:59 -0700607 logging.debug("Negative check for pkt on port " + str(ofport))
Ken Chiang1bf01602012-04-04 10:48:23 -0700608 (rcv_port, rcv_pkt, pkt_time) = dp.poll(
Rich Lane91765672012-12-06 16:33:04 -0800609 port_number=ofport, timeout=0, exp_pkt=exp_pkt_arg)
Dan Talayco92c99122010-06-03 13:53:18 -0700610 assert_if.assertTrue(rcv_pkt is None,
611 "Unexpected pkt on port " + str(ofport))
Dan Talayco551befa2010-07-15 17:05:32 -0700612
613
Dan Talaycoc948d0b2012-03-23 12:17:54 -0700614def receive_pkt_verify(parent, egr_ports, exp_pkt, ing_port):
Dan Talayco551befa2010-07-15 17:05:32 -0700615 """
616 Receive a packet and verify it matches an expected value
Dan Talaycof6e76c02012-03-23 10:56:12 -0700617 @param egr_port A single port or list of ports
Dan Talayco551befa2010-07-15 17:05:32 -0700618
619 parent must implement dataplane, assertTrue and assertEqual
Rich Lanee4b384d2013-09-13 14:33:40 -0700620
621 DEPRECATED in favor in verify_packets
Dan Talayco551befa2010-07-15 17:05:32 -0700622 """
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700623 exp_pkt_arg = None
Rich Lanecd97d3d2013-01-07 18:50:06 -0800624 if oftest.config["relax"]:
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700625 exp_pkt_arg = exp_pkt
626
Dan Talaycof6e76c02012-03-23 10:56:12 -0700627 if type(egr_ports) == type([]):
628 egr_port_list = egr_ports
629 else:
630 egr_port_list = [egr_ports]
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700631
Dan Talaycof6e76c02012-03-23 10:56:12 -0700632 # Expect a packet from each port on egr port list
633 for egr_port in egr_port_list:
Dan Talaycod8ae7582012-03-23 12:24:56 -0700634 check_port = egr_port
Rich Lanee717c6e2013-03-12 10:25:50 -0700635 if egr_port == ofp.OFPP_IN_PORT:
Dan Talaycod8ae7582012-03-23 12:24:56 -0700636 check_port = ing_port
Dan Talaycof6e76c02012-03-23 10:56:12 -0700637 (rcv_port, rcv_pkt, pkt_time) = parent.dataplane.poll(
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700638 port_number=check_port, exp_pkt=exp_pkt_arg)
Dan Talayco551befa2010-07-15 17:05:32 -0700639
Dan Talaycof6e76c02012-03-23 10:56:12 -0700640 if rcv_pkt is None:
Rich Lane9a003812012-10-04 17:17:59 -0700641 logging.error("ERROR: No packet received from " +
Dan Talaycod8ae7582012-03-23 12:24:56 -0700642 str(check_port))
Dan Talayco551befa2010-07-15 17:05:32 -0700643
Dan Talaycof6e76c02012-03-23 10:56:12 -0700644 parent.assertTrue(rcv_pkt is not None,
Dan Talaycod8ae7582012-03-23 12:24:56 -0700645 "Did not receive packet port " + str(check_port))
Rich Lane9a003812012-10-04 17:17:59 -0700646 logging.debug("Packet len " + str(len(rcv_pkt)) + " in on " +
Dan Talaycof6e76c02012-03-23 10:56:12 -0700647 str(rcv_port))
648
649 if str(exp_pkt) != str(rcv_pkt):
Rich Lane9a003812012-10-04 17:17:59 -0700650 logging.error("ERROR: Packet match failed.")
651 logging.debug("Expected len " + str(len(exp_pkt)) + ": "
Dan Talaycof6e76c02012-03-23 10:56:12 -0700652 + str(exp_pkt).encode('hex'))
Rich Lane9a003812012-10-04 17:17:59 -0700653 logging.debug("Received len " + str(len(rcv_pkt)) + ": "
Dan Talaycof6e76c02012-03-23 10:56:12 -0700654 + str(rcv_pkt).encode('hex'))
Rich Lane5d7e89a2012-10-26 16:43:13 -0700655 logging.debug("Expected packet: " + inspect_packet(scapy.Ether(str(exp_pkt))))
656 logging.debug("Received packet: " + inspect_packet(scapy.Ether(str(rcv_pkt))))
Dan Talaycof6e76c02012-03-23 10:56:12 -0700657 parent.assertEqual(str(exp_pkt), str(rcv_pkt),
Dan Talaycod8ae7582012-03-23 12:24:56 -0700658 "Packet match error on port " + str(check_port))
Dan Talaycof6e76c02012-03-23 10:56:12 -0700659
Dan Talayco551befa2010-07-15 17:05:32 -0700660def match_verify(parent, req_match, res_match):
661 """
662 Verify flow matches agree; if they disagree, report where
663
664 parent must implement assertEqual
665 Use str() to ensure content is compared and not pointers
666 """
667
668 parent.assertEqual(req_match.wildcards, res_match.wildcards,
669 'Match failed: wildcards: ' + hex(req_match.wildcards) +
670 " != " + hex(res_match.wildcards))
671 parent.assertEqual(req_match.in_port, res_match.in_port,
672 'Match failed: in_port: ' + str(req_match.in_port) +
673 " != " + str(res_match.in_port))
Rich Laned0478ff2013-03-11 12:46:58 -0700674 parent.assertEqual(str(req_match.eth_src), str(res_match.eth_src),
675 'Match failed: eth_src: ' + str(req_match.eth_src) +
676 " != " + str(res_match.eth_src))
677 parent.assertEqual(str(req_match.eth_dst), str(res_match.eth_dst),
678 'Match failed: eth_dst: ' + str(req_match.eth_dst) +
679 " != " + str(res_match.eth_dst))
680 parent.assertEqual(req_match.vlan_vid, res_match.vlan_vid,
681 'Match failed: vlan_vid: ' + str(req_match.vlan_vid) +
682 " != " + str(res_match.vlan_vid))
683 parent.assertEqual(req_match.vlan_pcp, res_match.vlan_pcp,
684 'Match failed: vlan_pcp: ' +
685 str(req_match.vlan_pcp) + " != " +
686 str(res_match.vlan_pcp))
687 parent.assertEqual(req_match.eth_type, res_match.eth_type,
688 'Match failed: eth_type: ' + str(req_match.eth_type) +
689 " != " + str(res_match.eth_type))
Dan Talayco551befa2010-07-15 17:05:32 -0700690
Rich Lanee717c6e2013-03-12 10:25:50 -0700691 if (not(req_match.wildcards & ofp.OFPFW_DL_TYPE)
Rich Laned0478ff2013-03-11 12:46:58 -0700692 and (req_match.eth_type == IP_ETHERTYPE)):
693 parent.assertEqual(req_match.ip_dscp, res_match.ip_dscp,
694 'Match failed: ip_dscp: ' + str(req_match.ip_dscp) +
695 " != " + str(res_match.ip_dscp))
696 parent.assertEqual(req_match.ip_proto, res_match.ip_proto,
697 'Match failed: ip_proto: ' + str(req_match.ip_proto) +
698 " != " + str(res_match.ip_proto))
699 parent.assertEqual(req_match.ipv4_src, res_match.ipv4_src,
700 'Match failed: ipv4_src: ' + str(req_match.ipv4_src) +
701 " != " + str(res_match.ipv4_src))
702 parent.assertEqual(req_match.ipv4_dst, res_match.ipv4_dst,
703 'Match failed: ipv4_dst: ' + str(req_match.ipv4_dst) +
704 " != " + str(res_match.ipv4_dst))
Dan Talayco551befa2010-07-15 17:05:32 -0700705
Rich Lanee717c6e2013-03-12 10:25:50 -0700706 if (not(req_match.wildcards & ofp.OFPFW_NW_PROTO)
Rich Laned0478ff2013-03-11 12:46:58 -0700707 and ((req_match.ip_proto == TCP_PROTOCOL)
708 or (req_match.ip_proto == UDP_PROTOCOL))):
709 parent.assertEqual(req_match.tcp_src, res_match.tcp_src,
710 'Match failed: tcp_src: ' +
711 str(req_match.tcp_src) +
712 " != " + str(res_match.tcp_src))
713 parent.assertEqual(req_match.tcp_dst, res_match.tcp_dst,
714 'Match failed: tcp_dst: ' +
715 str(req_match.tcp_dst) +
716 " != " + str(res_match.tcp_dst))
Dan Talayco551befa2010-07-15 17:05:32 -0700717
Ed Swierk99a74de2012-08-22 06:40:54 -0700718def packet_to_flow_match(parent, packet):
Rich Lanef6883512013-03-11 17:00:09 -0700719 match = oftest.parse.packet_to_flow_match(packet)
Rich Laneab7476f2013-06-13 15:53:52 -0700720 if ofp.OFP_VERSION in [1, 2]:
721 match.wildcards |= required_wildcards(parent)
722 else:
723 # TODO remove incompatible OXM entries
724 pass
Ed Swierk99a74de2012-08-22 06:40:54 -0700725 return match
726
727def flow_msg_create(parent, pkt, ing_port=None, action_list=None, wildcards=None,
Dan Talaycof6e76c02012-03-23 10:56:12 -0700728 egr_ports=None, egr_queue=None, check_expire=False, in_band=False):
Dan Talayco551befa2010-07-15 17:05:32 -0700729 """
730 Create a flow message
731
732 Match on packet with given wildcards.
733 See flow_match_test for other parameter descriptoins
734 @param egr_queue if not None, make the output an enqueue action
Dan Talayco677c0b72011-08-23 22:53:38 -0700735 @param in_band if True, do not wildcard ingress port
Dan Talaycof6e76c02012-03-23 10:56:12 -0700736 @param egr_ports None (drop), single port or list of ports
Dan Talayco551befa2010-07-15 17:05:32 -0700737 """
Rich Lanef6883512013-03-11 17:00:09 -0700738 match = oftest.parse.packet_to_flow_match(pkt)
Dan Talayco551befa2010-07-15 17:05:32 -0700739 parent.assertTrue(match is not None, "Flow match from pkt failed")
Ed Swierk99a74de2012-08-22 06:40:54 -0700740 if wildcards is None:
741 wildcards = required_wildcards(parent)
Dan Talayco677c0b72011-08-23 22:53:38 -0700742 if in_band:
Rich Lanee717c6e2013-03-12 10:25:50 -0700743 wildcards &= ~ofp.OFPFW_IN_PORT
Dan Talayco551befa2010-07-15 17:05:32 -0700744 match.wildcards = wildcards
745 match.in_port = ing_port
746
Dan Talaycof6e76c02012-03-23 10:56:12 -0700747 if type(egr_ports) == type([]):
748 egr_port_list = egr_ports
749 else:
750 egr_port_list = [egr_ports]
751
Rich Lanee717c6e2013-03-12 10:25:50 -0700752 request = ofp.message.flow_add()
Dan Talayco551befa2010-07-15 17:05:32 -0700753 request.match = match
754 request.buffer_id = 0xffffffff
755 if check_expire:
Rich Lanee717c6e2013-03-12 10:25:50 -0700756 request.flags |= ofp.OFPFF_SEND_FLOW_REM
Dan Talayco551befa2010-07-15 17:05:32 -0700757 request.hard_timeout = 1
758
Rich Lane400fb9b2013-10-10 17:20:54 -0700759 if ofp.OFP_VERSION == 1:
760 actions = request.actions
761 else:
762 actions = []
763 request.instructions.append(ofp.instruction.apply_actions(actions))
764
Dan Talayco551befa2010-07-15 17:05:32 -0700765 if action_list is not None:
Rich Lane400fb9b2013-10-10 17:20:54 -0700766 actions.extend(action_list)
Dan Talayco551befa2010-07-15 17:05:32 -0700767
768 # Set up output/enqueue action if directed
769 if egr_queue is not None:
Dan Talaycof6e76c02012-03-23 10:56:12 -0700770 parent.assertTrue(egr_ports is not None, "Egress port not set")
Rich Lanee717c6e2013-03-12 10:25:50 -0700771 act = ofp.action.enqueue()
Dan Talaycof6e76c02012-03-23 10:56:12 -0700772 for egr_port in egr_port_list:
773 act.port = egr_port
774 act.queue_id = egr_queue
Rich Lane400fb9b2013-10-10 17:20:54 -0700775 actions.append(act)
Dan Talaycof6e76c02012-03-23 10:56:12 -0700776 elif egr_ports is not None:
777 for egr_port in egr_port_list:
Rich Lanee717c6e2013-03-12 10:25:50 -0700778 act = ofp.action.output()
Dan Talaycof6e76c02012-03-23 10:56:12 -0700779 act.port = egr_port
Rich Lane400fb9b2013-10-10 17:20:54 -0700780 actions.append(act)
Dan Talayco551befa2010-07-15 17:05:32 -0700781
Rich Lane9a003812012-10-04 17:17:59 -0700782 logging.debug(request.show())
Dan Talayco551befa2010-07-15 17:05:32 -0700783
784 return request
785
Jeffrey Townsendf3eae9c2012-03-28 18:23:21 -0700786def flow_msg_install(parent, request, clear_table_override=None):
Dan Talayco551befa2010-07-15 17:05:32 -0700787 """
788 Install a flow mod message in the switch
789
790 @param parent Must implement controller, assertEqual, assertTrue
791 @param request The request, all set to go
792 @param clear_table If true, clear the flow table before installing
793 """
Dan Talayco8a64e332012-03-28 14:53:20 -0700794
Rich Lane2014f9b2012-10-05 15:29:40 -0700795 clear_table = test_param_get('clear_table', default=True)
Jeffrey Townsendf3eae9c2012-03-28 18:23:21 -0700796 if(clear_table_override != None):
797 clear_table = clear_table_override
798
799 if clear_table:
Rich Lane9a003812012-10-04 17:17:59 -0700800 logging.debug("Clear flow table")
Rich Lane32bf9482013-01-03 17:26:30 -0800801 delete_all_flows(parent.controller)
Dan Talayco551befa2010-07-15 17:05:32 -0700802
Rich Lane9a003812012-10-04 17:17:59 -0700803 logging.debug("Insert flow")
Rich Lane5c3151c2013-01-03 17:15:41 -0800804 parent.controller.message_send(request)
Rich Lanee912d032012-12-22 14:28:33 -0800805
Rich Lane3a261d52013-01-03 17:45:08 -0800806 do_barrier(parent.controller)
Dan Talayco551befa2010-07-15 17:05:32 -0700807
Ed Swierk99a74de2012-08-22 06:40:54 -0700808def flow_match_test_port_pair(parent, ing_port, egr_ports, wildcards=None,
Rich Laned0478ff2013-03-11 12:46:58 -0700809 vlan_vid=-1, pkt=None, exp_pkt=None,
Rich Lanee5779d32012-10-05 17:56:04 -0700810 action_list=None):
Dan Talayco551befa2010-07-15 17:05:32 -0700811 """
812 Flow match test on single TCP packet
Dan Talaycof6e76c02012-03-23 10:56:12 -0700813 @param egr_ports A single port or list of ports
Dan Talayco551befa2010-07-15 17:05:32 -0700814
815 Run test with packet through switch from ing_port to egr_port
816 See flow_match_test for parameter descriptions
817 """
818
Ed Swierk99a74de2012-08-22 06:40:54 -0700819 if wildcards is None:
820 wildcards = required_wildcards(parent)
Rich Lane9a003812012-10-04 17:17:59 -0700821 logging.info("Pkt match test: " + str(ing_port) + " to " +
Dan Talaycof6e76c02012-03-23 10:56:12 -0700822 str(egr_ports))
Rich Laned0478ff2013-03-11 12:46:58 -0700823 logging.debug(" WC: " + hex(wildcards) + " vlan: " + str(vlan_vid))
Dan Talayco551befa2010-07-15 17:05:32 -0700824 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 Lanec41fbec2013-10-02 00:27:59 -0700826 if exp_pkt is None:
827 exp_pkt = pkt
Dan Talayco551befa2010-07-15 17:05:32 -0700828
829 request = flow_msg_create(parent, pkt, ing_port=ing_port,
Dan Talaycof6e76c02012-03-23 10:56:12 -0700830 wildcards=wildcards, egr_ports=egr_ports,
Dan Talayco551befa2010-07-15 17:05:32 -0700831 action_list=action_list)
832
833 flow_msg_install(parent, request)
834
Rich Lane9a003812012-10-04 17:17:59 -0700835 logging.debug("Send packet: " + str(ing_port) + " to " +
Dan Talaycof6e76c02012-03-23 10:56:12 -0700836 str(egr_ports))
Dan Talayco551befa2010-07-15 17:05:32 -0700837 parent.dataplane.send(ing_port, str(pkt))
838
Rich Lane8f45e2d2013-10-01 16:06:54 -0700839 exp_ports = [ing_port if port == ofp.OFPP_IN_PORT else port for port in egr_ports]
Rich Lanee4b384d2013-09-13 14:33:40 -0700840 verify_packets(parent, exp_pkt, exp_ports)
Dan Talayco551befa2010-07-15 17:05:32 -0700841
Rich Lane89725bb2012-12-03 16:23:27 -0800842def flow_match_test_pktout(parent, ing_port, egr_ports,
Rich Laned0478ff2013-03-11 12:46:58 -0700843 vlan_vid=-1, pkt=None, exp_pkt=None,
Rich Lane89725bb2012-12-03 16:23:27 -0800844 action_list=None):
845 """
846 Packet-out test on single TCP packet
847 @param egr_ports A single port or list of ports
848
849 Run test sending packet-out to egr_ports. The goal is to test the actions
850 taken on the packet, not the matching which is of course irrelevant.
851 See flow_match_test for parameter descriptions
852 """
853
854 if pkt is None:
Rich Laned0478ff2013-03-11 12:46:58 -0700855 pkt = simple_tcp_packet(dl_vlan_enable=(vlan_vid >= 0), vlan_vid=vlan_vid)
Rich Lanec41fbec2013-10-02 00:27:59 -0700856 if exp_pkt is None:
857 exp_pkt = pkt
Rich Lane89725bb2012-12-03 16:23:27 -0800858
Rich Lanee717c6e2013-03-12 10:25:50 -0700859 msg = ofp.message.packet_out()
Rich Lane89725bb2012-12-03 16:23:27 -0800860 msg.in_port = ing_port
Rich Laneea8c4722013-04-04 15:30:20 -0700861 msg.buffer_id = 0xffffffff
Rich Lane89725bb2012-12-03 16:23:27 -0800862 msg.data = str(pkt)
863 if action_list is not None:
864 for act in action_list:
Rich Lanec495d9e2013-03-08 17:43:36 -0800865 msg.actions.append(act)
Rich Lane89725bb2012-12-03 16:23:27 -0800866
867 # Set up output action
868 if egr_ports is not None:
869 for egr_port in egr_ports:
Rich Lanee717c6e2013-03-12 10:25:50 -0700870 act = ofp.action.output()
Rich Lane89725bb2012-12-03 16:23:27 -0800871 act.port = egr_port
Rich Lanec495d9e2013-03-08 17:43:36 -0800872 msg.actions.append(act)
Rich Lane89725bb2012-12-03 16:23:27 -0800873
874 logging.debug(msg.show())
Rich Lane5c3151c2013-01-03 17:15:41 -0800875 parent.controller.message_send(msg)
Rich Lane89725bb2012-12-03 16:23:27 -0800876
Rich Lane8f45e2d2013-10-01 16:06:54 -0700877 exp_ports = [ing_port if port == ofp.OFPP_IN_PORT else port for port in egr_ports]
Rich Lanee4b384d2013-09-13 14:33:40 -0700878 verify_packets(parent, exp_pkt, exp_ports)
Rich Lane89725bb2012-12-03 16:23:27 -0800879
Dan Talaycof6e76c02012-03-23 10:56:12 -0700880def get_egr_list(parent, of_ports, how_many, exclude_list=[]):
881 """
882 Generate a list of ports avoiding those in the exclude list
Rich Lane9a003812012-10-04 17:17:59 -0700883 @param parent Supplies logging
Dan Talaycof6e76c02012-03-23 10:56:12 -0700884 @param of_ports List of OF port numbers
885 @param how_many Number of ports to be added to the list
886 @param exclude_list List of ports not to be used
887 @returns An empty list if unable to find enough ports
888 """
889
Dan Talaycoc948d0b2012-03-23 12:17:54 -0700890 if how_many == 0:
891 return []
892
Dan Talaycof6e76c02012-03-23 10:56:12 -0700893 count = 0
894 egr_ports = []
895 for egr_idx in range(len(of_ports)):
896 if of_ports[egr_idx] not in exclude_list:
897 egr_ports.append(of_ports[egr_idx])
898 count += 1
899 if count >= how_many:
900 return egr_ports
Rich Lane9a003812012-10-04 17:17:59 -0700901 logging.debug("Could not generate enough egress ports for test")
Dan Talaycof6e76c02012-03-23 10:56:12 -0700902 return []
903
Rich Laned0478ff2013-03-11 12:46:58 -0700904def flow_match_test(parent, port_map, wildcards=None, vlan_vid=-1, pkt=None,
Rich Lanee5779d32012-10-05 17:56:04 -0700905 exp_pkt=None, action_list=None,
Dan Talaycoc948d0b2012-03-23 12:17:54 -0700906 max_test=0, egr_count=1, ing_port=False):
Dan Talayco551befa2010-07-15 17:05:32 -0700907 """
Rich Lane89725bb2012-12-03 16:23:27 -0800908 Run flow_match_test_port_pair on all port pairs and packet-out
Dan Talayco551befa2010-07-15 17:05:32 -0700909
910 @param max_test If > 0 no more than this number of tests are executed.
911 @param parent Must implement controller, dataplane, assertTrue, assertEqual
Rich Lane9a003812012-10-04 17:17:59 -0700912 and logging
Dan Talayco551befa2010-07-15 17:05:32 -0700913 @param pkt If not None, use this packet for ingress
914 @param wildcards For flow match entry
Rich Laned0478ff2013-03-11 12:46:58 -0700915 @param vlan_vid If not -1, and pkt is None, create a pkt w/ VLAN tag
Dan Talayco551befa2010-07-15 17:05:32 -0700916 @param exp_pkt If not None, use this as the expected output pkt; els use pkt
917 @param action_list Additional actions to add to flow mod
Dan Talaycocfa172f2012-03-23 12:03:00 -0700918 @param egr_count Number of egress ports; -1 means get from config w/ dflt 2
Dan Talayco551befa2010-07-15 17:05:32 -0700919 """
Ed Swierk99a74de2012-08-22 06:40:54 -0700920 if wildcards is None:
921 wildcards = required_wildcards(parent)
Dan Talayco551befa2010-07-15 17:05:32 -0700922 of_ports = port_map.keys()
923 of_ports.sort()
924 parent.assertTrue(len(of_ports) > 1, "Not enough ports for test")
925 test_count = 0
926
Dan Talaycocfa172f2012-03-23 12:03:00 -0700927 if egr_count == -1:
Rich Lane2014f9b2012-10-05 15:29:40 -0700928 egr_count = test_param_get('egr_count', default=2)
Dan Talaycocfa172f2012-03-23 12:03:00 -0700929
Dan Talayco551befa2010-07-15 17:05:32 -0700930 for ing_idx in range(len(of_ports)):
931 ingress_port = of_ports[ing_idx]
Dan Talaycof6e76c02012-03-23 10:56:12 -0700932 egr_ports = get_egr_list(parent, of_ports, egr_count,
933 exclude_list=[ingress_port])
Dan Talaycoc948d0b2012-03-23 12:17:54 -0700934 if ing_port:
Rich Lanee717c6e2013-03-12 10:25:50 -0700935 egr_ports.append(ofp.OFPP_IN_PORT)
Dan Talaycof6e76c02012-03-23 10:56:12 -0700936 if len(egr_ports) == 0:
937 parent.assertTrue(0, "Failed to generate egress port list")
938
939 flow_match_test_port_pair(parent, ingress_port, egr_ports,
Rich Laned0478ff2013-03-11 12:46:58 -0700940 wildcards=wildcards, vlan_vid=vlan_vid,
Dan Talaycof6e76c02012-03-23 10:56:12 -0700941 pkt=pkt, exp_pkt=exp_pkt,
Rich Lanee5779d32012-10-05 17:56:04 -0700942 action_list=action_list)
Dan Talaycof6e76c02012-03-23 10:56:12 -0700943 test_count += 1
944 if (max_test > 0) and (test_count > max_test):
Rich Lane9a003812012-10-04 17:17:59 -0700945 logging.info("Ran " + str(test_count) + " tests; exiting")
Rich Lane89725bb2012-12-03 16:23:27 -0800946 break
947
Ed Swierk38eea082013-01-02 19:46:20 -0800948 if not test_param_get('pktout_actions', default=True):
949 return
Rich Lane89725bb2012-12-03 16:23:27 -0800950
951 ingress_port = of_ports[0]
952 egr_ports = get_egr_list(parent, of_ports, egr_count,
953 exclude_list=[ingress_port])
954 if ing_port:
Rich Lanee717c6e2013-03-12 10:25:50 -0700955 egr_ports.append(ofp.OFPP_IN_PORT)
Rich Lane89725bb2012-12-03 16:23:27 -0800956 flow_match_test_pktout(parent, ingress_port, egr_ports,
Rich Laned0478ff2013-03-11 12:46:58 -0700957 vlan_vid=vlan_vid,
Rich Lane89725bb2012-12-03 16:23:27 -0800958 pkt=pkt, exp_pkt=exp_pkt,
959 action_list=action_list)
Dan Talayco551befa2010-07-15 17:05:32 -0700960
Rich Lane2014f9b2012-10-05 15:29:40 -0700961def test_param_get(key, default=None):
Dan Talayco4b2bee62010-07-20 14:10:05 -0700962 """
963 Return value passed via test-params if present
964
Dan Talayco4b2bee62010-07-20 14:10:05 -0700965 @param key The lookup key
966 @param default Default value to use if not found
967
968 If the pair 'key=val' appeared in the string passed to --test-params
969 on the command line, return val (as interpreted by exec). Otherwise
970 return default value.
Dan Talaycof6e76c02012-03-23 10:56:12 -0700971
972 WARNING: TEST PARAMETERS MUST BE PYTHON IDENTIFIERS;
973 eg egr_count, not egr-count.
Dan Talayco4b2bee62010-07-20 14:10:05 -0700974 """
975 try:
Rich Lanecd97d3d2013-01-07 18:50:06 -0800976 exec oftest.config["test_params"]
Dan Talayco4b2bee62010-07-20 14:10:05 -0700977 except:
978 return default
979
Dan Talayco4b2bee62010-07-20 14:10:05 -0700980 try:
Rich Lanefdec0fb2013-08-09 18:01:05 -0700981 return eval(str(key))
Dan Talayco4b2bee62010-07-20 14:10:05 -0700982 except:
983 return default
984
985def action_generate(parent, field_to_mod, mod_field_vals):
986 """
987 Create an action to modify the field indicated in field_to_mod
988
989 @param parent Must implement, assertTrue
990 @param field_to_mod The field to modify as a string name
991 @param mod_field_vals Hash of values to use for modified values
992 """
993
994 act = None
995
996 if field_to_mod in ['pktlen']:
997 return None
998
Rich Laned0478ff2013-03-11 12:46:58 -0700999 if field_to_mod == 'eth_dst':
Rich Lanee717c6e2013-03-12 10:25:50 -07001000 act = ofp.action.set_dl_dst()
Rich Lanef6883512013-03-11 17:00:09 -07001001 act.dl_addr = oftest.parse.parse_mac(mod_field_vals['eth_dst'])
Rich Laned0478ff2013-03-11 12:46:58 -07001002 elif field_to_mod == 'eth_src':
Rich Lanee717c6e2013-03-12 10:25:50 -07001003 act = ofp.action.set_dl_src()
Rich Lanef6883512013-03-11 17:00:09 -07001004 act.dl_addr = oftest.parse.parse_mac(mod_field_vals['eth_src'])
Dan Talayco4b2bee62010-07-20 14:10:05 -07001005 elif field_to_mod == 'dl_vlan_enable':
1006 if not mod_field_vals['dl_vlan_enable']: # Strip VLAN tag
Rich Lanee717c6e2013-03-12 10:25:50 -07001007 act = ofp.action.strip_vlan()
Rich Laned0478ff2013-03-11 12:46:58 -07001008 # Add VLAN tag is handled by vlan_vid field
Dan Talayco4b2bee62010-07-20 14:10:05 -07001009 # Will return None in this case
Rich Laned0478ff2013-03-11 12:46:58 -07001010 elif field_to_mod == 'vlan_vid':
Rich Lanee717c6e2013-03-12 10:25:50 -07001011 act = ofp.action.set_vlan_vid()
Rich Laned0478ff2013-03-11 12:46:58 -07001012 act.vlan_vid = mod_field_vals['vlan_vid']
1013 elif field_to_mod == 'vlan_pcp':
Rich Lanee717c6e2013-03-12 10:25:50 -07001014 act = ofp.action.set_vlan_pcp()
Rich Laned0478ff2013-03-11 12:46:58 -07001015 act.vlan_pcp = mod_field_vals['vlan_pcp']
Dan Talayco4b2bee62010-07-20 14:10:05 -07001016 elif field_to_mod == 'ip_src':
Rich Lanee717c6e2013-03-12 10:25:50 -07001017 act = ofp.action.set_nw_src()
Rich Lanef6883512013-03-11 17:00:09 -07001018 act.nw_addr = oftest.parse.parse_ip(mod_field_vals['ip_src'])
Dan Talayco4b2bee62010-07-20 14:10:05 -07001019 elif field_to_mod == 'ip_dst':
Rich Lanee717c6e2013-03-12 10:25:50 -07001020 act = ofp.action.set_nw_dst()
Rich Lanef6883512013-03-11 17:00:09 -07001021 act.nw_addr = oftest.parse.parse_ip(mod_field_vals['ip_dst'])
Dan Talayco4b2bee62010-07-20 14:10:05 -07001022 elif field_to_mod == 'ip_tos':
Rich Lanee717c6e2013-03-12 10:25:50 -07001023 act = ofp.action.set_nw_tos()
Dan Talayco4b2bee62010-07-20 14:10:05 -07001024 act.nw_tos = mod_field_vals['ip_tos']
1025 elif field_to_mod == 'tcp_sport':
Rich Lanee717c6e2013-03-12 10:25:50 -07001026 act = ofp.action.set_tp_src()
Dan Talayco4b2bee62010-07-20 14:10:05 -07001027 act.tp_port = mod_field_vals['tcp_sport']
1028 elif field_to_mod == 'tcp_dport':
Rich Lanee717c6e2013-03-12 10:25:50 -07001029 act = ofp.action.set_tp_dst()
Dan Talayco4b2bee62010-07-20 14:10:05 -07001030 act.tp_port = mod_field_vals['tcp_dport']
Rich Lane110e0e32012-10-26 16:21:46 -07001031 elif field_to_mod == 'udp_sport':
Rich Lanee717c6e2013-03-12 10:25:50 -07001032 act = ofp.action.set_tp_src()
Rich Lane110e0e32012-10-26 16:21:46 -07001033 act.tp_port = mod_field_vals['udp_sport']
1034 elif field_to_mod == 'udp_dport':
Rich Lanee717c6e2013-03-12 10:25:50 -07001035 act = ofp.action.set_tp_dst()
Rich Lane110e0e32012-10-26 16:21:46 -07001036 act.tp_port = mod_field_vals['udp_dport']
Dan Talayco4b2bee62010-07-20 14:10:05 -07001037 else:
1038 parent.assertTrue(0, "Unknown field to modify: " + str(field_to_mod))
1039
1040 return act
1041
1042def pkt_action_setup(parent, start_field_vals={}, mod_field_vals={},
Rich Lane110e0e32012-10-26 16:21:46 -07001043 mod_fields=[], tp="tcp", check_test_params=False):
Dan Talayco4b2bee62010-07-20 14:10:05 -07001044 """
1045 Set up the ingress and expected packet and action list for a test
1046
Rich Lane2014f9b2012-10-05 15:29:40 -07001047 @param parent Must implement assertTrue
Dan Talayco4b2bee62010-07-20 14:10:05 -07001048 @param start_field_values Field values to use for ingress packet (optional)
1049 @param mod_field_values Field values to use for modified packet (optional)
1050 @param mod_fields The list of fields to be modified by the switch in the test.
1051 @params check_test_params If True, will check the parameters vid, add_vlan
1052 and strip_vlan from the command line.
1053
1054 Returns a triple: pkt-to-send, expected-pkt, action-list
1055 """
1056
1057 new_actions = []
1058
Dan Talayco4b2bee62010-07-20 14:10:05 -07001059 base_pkt_params = {}
1060 base_pkt_params['pktlen'] = 100
Rich Laned0478ff2013-03-11 12:46:58 -07001061 base_pkt_params['eth_dst'] = '00:DE:F0:12:34:56'
1062 base_pkt_params['eth_src'] = '00:23:45:67:89:AB'
Dan Talayco4b2bee62010-07-20 14:10:05 -07001063 base_pkt_params['dl_vlan_enable'] = False
Rich Laned0478ff2013-03-11 12:46:58 -07001064 base_pkt_params['vlan_vid'] = 2
1065 base_pkt_params['vlan_pcp'] = 0
Dan Talayco4b2bee62010-07-20 14:10:05 -07001066 base_pkt_params['ip_src'] = '192.168.0.1'
1067 base_pkt_params['ip_dst'] = '192.168.0.2'
1068 base_pkt_params['ip_tos'] = 0
Rich Lane110e0e32012-10-26 16:21:46 -07001069 if tp == "tcp":
1070 base_pkt_params['tcp_sport'] = 1234
1071 base_pkt_params['tcp_dport'] = 80
1072 elif tp == "udp":
1073 base_pkt_params['udp_sport'] = 1234
1074 base_pkt_params['udp_dport'] = 80
Dan Talayco4b2bee62010-07-20 14:10:05 -07001075 for keyname in start_field_vals.keys():
1076 base_pkt_params[keyname] = start_field_vals[keyname]
1077
1078 mod_pkt_params = {}
1079 mod_pkt_params['pktlen'] = 100
Rich Laned0478ff2013-03-11 12:46:58 -07001080 mod_pkt_params['eth_dst'] = '00:21:0F:ED:CB:A9'
1081 mod_pkt_params['eth_src'] = '00:ED:CB:A9:87:65'
Dan Talayco4b2bee62010-07-20 14:10:05 -07001082 mod_pkt_params['dl_vlan_enable'] = False
Rich Laned0478ff2013-03-11 12:46:58 -07001083 mod_pkt_params['vlan_vid'] = 3
1084 mod_pkt_params['vlan_pcp'] = 7
Dan Talayco4b2bee62010-07-20 14:10:05 -07001085 mod_pkt_params['ip_src'] = '10.20.30.40'
1086 mod_pkt_params['ip_dst'] = '50.60.70.80'
1087 mod_pkt_params['ip_tos'] = 0xf0
Rich Lane110e0e32012-10-26 16:21:46 -07001088 if tp == "tcp":
1089 mod_pkt_params['tcp_sport'] = 4321
1090 mod_pkt_params['tcp_dport'] = 8765
1091 elif tp == "udp":
1092 mod_pkt_params['udp_sport'] = 4321
1093 mod_pkt_params['udp_dport'] = 8765
Dan Talayco4b2bee62010-07-20 14:10:05 -07001094 for keyname in mod_field_vals.keys():
1095 mod_pkt_params[keyname] = mod_field_vals[keyname]
1096
1097 # Check for test param modifications
1098 strip = False
1099 if check_test_params:
Rich Lane2014f9b2012-10-05 15:29:40 -07001100 add_vlan = test_param_get('add_vlan')
1101 strip_vlan = test_param_get('strip_vlan')
1102 vid = test_param_get('vid')
Dan Talayco4b2bee62010-07-20 14:10:05 -07001103
1104 if add_vlan and strip_vlan:
1105 parent.assertTrue(0, "Add and strip VLAN both specified")
1106
1107 if vid:
1108 base_pkt_params['dl_vlan_enable'] = True
Rich Laned0478ff2013-03-11 12:46:58 -07001109 base_pkt_params['vlan_vid'] = vid
1110 if 'vlan_vid' in mod_fields:
1111 mod_pkt_params['vlan_vid'] = vid + 1
Dan Talayco4b2bee62010-07-20 14:10:05 -07001112
1113 if add_vlan:
1114 base_pkt_params['dl_vlan_enable'] = False
1115 mod_pkt_params['dl_vlan_enable'] = True
1116 mod_pkt_params['pktlen'] = base_pkt_params['pktlen'] + 4
1117 mod_fields.append('pktlen')
1118 mod_fields.append('dl_vlan_enable')
Rich Laned0478ff2013-03-11 12:46:58 -07001119 if 'vlan_vid' not in mod_fields:
1120 mod_fields.append('vlan_vid')
Dan Talayco4b2bee62010-07-20 14:10:05 -07001121 elif strip_vlan:
1122 base_pkt_params['dl_vlan_enable'] = True
1123 mod_pkt_params['dl_vlan_enable'] = False
1124 mod_pkt_params['pktlen'] = base_pkt_params['pktlen'] - 4
1125 mod_fields.append('dl_vlan_enable')
1126 mod_fields.append('pktlen')
1127
Rich Lane110e0e32012-10-26 16:21:46 -07001128 if tp == "tcp":
1129 packet_builder = simple_tcp_packet
1130 elif tp == "udp":
1131 packet_builder = simple_udp_packet
1132 else:
1133 raise NotImplementedError("unknown transport protocol %s" % tp)
1134
Dan Talayco4b2bee62010-07-20 14:10:05 -07001135 # Build the ingress packet
Rich Lane110e0e32012-10-26 16:21:46 -07001136 ingress_pkt = packet_builder(**base_pkt_params)
Dan Talayco4b2bee62010-07-20 14:10:05 -07001137
1138 # Build the expected packet, modifying the indicated fields
1139 for item in mod_fields:
1140 base_pkt_params[item] = mod_pkt_params[item]
1141 act = action_generate(parent, item, mod_pkt_params)
1142 if act:
1143 new_actions.append(act)
1144
Rich Lane110e0e32012-10-26 16:21:46 -07001145 expected_pkt = packet_builder(**base_pkt_params)
Dan Talayco4b2bee62010-07-20 14:10:05 -07001146
1147 return (ingress_pkt, expected_pkt, new_actions)
Dan Talayco677c0b72011-08-23 22:53:38 -07001148
1149# Generate a simple "drop" flow mod
1150# If in_band is true, then only drop from first test port
1151def flow_mod_gen(port_map, in_band):
Rich Lanee717c6e2013-03-12 10:25:50 -07001152 request = ofp.message.flow_add()
1153 request.match.wildcards = ofp.OFPFW_ALL
Dan Talayco677c0b72011-08-23 22:53:38 -07001154 if in_band:
Rich Lanee717c6e2013-03-12 10:25:50 -07001155 request.match.wildcards = ofp.OFPFW_ALL - ofp.OFPFW_IN_PORT
Dan Talayco677c0b72011-08-23 22:53:38 -07001156 for of_port, ifname in port_map.items(): # Grab first port
1157 break
1158 request.match.in_port = of_port
1159 request.buffer_id = 0xffffffff
1160 return request
Dan Talaycoba3745c2010-07-21 21:51:08 -07001161
1162def skip_message_emit(parent, s):
1163 """
1164 Print out a 'skipped' message to stderr
1165
1166 @param s The string to print out to the log file
Dan Talaycoba3745c2010-07-21 21:51:08 -07001167 """
1168 global skipped_test_count
1169
1170 skipped_test_count += 1
Rich Lane9a003812012-10-04 17:17:59 -07001171 logging.info("Skipping: " + s)
Dan Talayco2940fdd2013-02-06 15:01:35 -08001172 if oftest.config["debug"] < logging.WARNING:
Dan Talaycoba3745c2010-07-21 21:51:08 -07001173 sys.stderr.write("(skipped) ")
1174 else:
1175 sys.stderr.write("(S)")
Dan Talayco677c0b72011-08-23 22:53:38 -07001176
Dan Talayco8a64e332012-03-28 14:53:20 -07001177
1178def all_stats_get(parent):
1179 """
1180 Get the aggregate stats for all flows in the table
1181 @param parent Test instance with controller connection and assert
1182 @returns dict with keys flows, packets, bytes, active (flows),
1183 lookups, matched
1184 """
Rich Lanee717c6e2013-03-12 10:25:50 -07001185 stat_req = ofp.message.aggregate_stats_request()
1186 stat_req.match = ofp.match()
1187 stat_req.match.wildcards = ofp.OFPFW_ALL
Dan Talayco8a64e332012-03-28 14:53:20 -07001188 stat_req.table_id = 0xff
Rich Lanee717c6e2013-03-12 10:25:50 -07001189 stat_req.out_port = ofp.OFPP_NONE
Dan Talayco8a64e332012-03-28 14:53:20 -07001190
1191 rv = {}
1192
Rich Lanec8aaa3e2012-07-26 19:28:02 -07001193 (reply, pkt) = parent.controller.transact(stat_req)
Rich Lane5fd6faf2013-03-11 13:30:20 -07001194 parent.assertTrue(len(reply.entries) == 1, "Did not receive flow stats reply")
Dan Talayco8a64e332012-03-28 14:53:20 -07001195
Rich Lane5fd6faf2013-03-11 13:30:20 -07001196 for obj in reply.entries:
Dan Talayco8a64e332012-03-28 14:53:20 -07001197 (rv["flows"], rv["packets"], rv["bytes"]) = (obj.flow_count,
1198 obj.packet_count, obj.byte_count)
1199 break
1200
Rich Lanee717c6e2013-03-12 10:25:50 -07001201 request = ofp.message.table_stats_request()
Rich Lanec8aaa3e2012-07-26 19:28:02 -07001202 (reply , pkt) = parent.controller.transact(request)
Dan Talayco8a64e332012-03-28 14:53:20 -07001203
1204
1205 (rv["active"], rv["lookups"], rv["matched"]) = (0,0,0)
Rich Lane5fd6faf2013-03-11 13:30:20 -07001206 for obj in reply.entries:
Dan Talayco8a64e332012-03-28 14:53:20 -07001207 rv["active"] += obj.active_count
1208 rv["lookups"] += obj.lookup_count
1209 rv["matched"] += obj.matched_count
1210
1211 return rv
Dan Talayco2baf8b52012-03-30 09:55:42 -07001212
Rich Lane7744e112013-01-11 17:23:57 -08001213_import_blacklist.add('FILTER')
Dan Talayco2baf8b52012-03-30 09:55:42 -07001214FILTER=''.join([(len(repr(chr(x)))==3) and chr(x) or '.'
1215 for x in range(256)])
1216
1217def hex_dump_buffer(src, length=16):
1218 """
1219 Convert src to a hex dump string and return the string
1220 @param src The source buffer
1221 @param length The number of bytes shown in each line
1222 @returns A string showing the hex dump
1223 """
Dan Talaycoc516fa02012-04-12 22:28:43 -07001224 result = ["\n"]
Dan Talayco2baf8b52012-03-30 09:55:42 -07001225 for i in xrange(0, len(src), length):
1226 chars = src[i:i+length]
1227 hex = ' '.join(["%02x" % ord(x) for x in chars])
1228 printable = ''.join(["%s" % ((ord(x) <= 127 and
1229 FILTER[ord(x)]) or '.') for x in chars])
1230 result.append("%04x %-*s %s\n" % (i, length*3, hex, printable))
1231 return ''.join(result)
1232
1233def format_packet(pkt):
1234 return "Packet length %d \n%s" % (len(str(pkt)),
1235 hex_dump_buffer(str(pkt)))
Rich Lane5d7e89a2012-10-26 16:43:13 -07001236
1237def inspect_packet(pkt):
1238 """
1239 Wrapper around scapy's show() method.
1240 @returns A string showing the dissected packet.
1241 """
1242 from cStringIO import StringIO
1243 out = None
1244 backup = sys.stdout
1245 try:
Rich Lanefdec0fb2013-08-09 18:01:05 -07001246 tmp = StringIO()
1247 sys.stdout = tmp
Rich Lane5d7e89a2012-10-26 16:43:13 -07001248 pkt.show2()
Rich Lanefdec0fb2013-08-09 18:01:05 -07001249 out = tmp.getvalue()
1250 tmp.close()
Rich Lane5d7e89a2012-10-26 16:43:13 -07001251 finally:
1252 sys.stdout = backup
1253 return out
Rich Lane0a4f6372013-01-02 14:40:22 -08001254
1255def nonstandard(cls):
1256 """
Rich Lanecc45b8e2013-01-02 15:55:02 -08001257 Testcase decorator that marks the test as being non-standard.
1258 These tests are not automatically added to the "standard" group.
Rich Lane0a4f6372013-01-02 14:40:22 -08001259 """
Rich Lanecc45b8e2013-01-02 15:55:02 -08001260 cls._nonstandard = True
Rich Lane0a4f6372013-01-02 14:40:22 -08001261 return cls
1262
1263def disabled(cls):
1264 """
Rich Lanecc45b8e2013-01-02 15:55:02 -08001265 Testcase decorator that marks the test as being disabled.
1266 These tests are not automatically added to the "standard" group or
1267 their module's group.
Rich Lane0a4f6372013-01-02 14:40:22 -08001268 """
Rich Lanecc45b8e2013-01-02 15:55:02 -08001269 cls._disabled = True
Rich Lane0a4f6372013-01-02 14:40:22 -08001270 return cls
Rich Lane97e99652013-01-02 17:23:20 -08001271
1272def group(name):
1273 """
1274 Testcase decorator that adds the test to a group.
1275 """
1276 def fn(cls):
1277 if not hasattr(cls, "_groups"):
1278 cls._groups = []
1279 cls._groups.append(name)
1280 return cls
1281 return fn
Rich Lane5a9a1922013-01-11 14:29:30 -08001282
1283def version(ver):
1284 """
1285 Testcase decorator that specifies which versions of OpenFlow the test
1286 supports. The default is 1.0+. This decorator may only be used once.
1287
1288 Supported syntax:
1289 1.0 -> 1.0
1290 1.0,1.2,1.3 -> 1.0, 1.2, 1.3
1291 1.0+ -> 1.0, 1.1, 1.2, 1.3
1292 """
1293 versions = parse_version(ver)
1294 def fn(cls):
1295 cls._versions = versions
1296 return cls
1297 return fn
1298
1299def parse_version(ver):
1300 allowed_versions = ["1.0", "1.1", "1.2", "1.3"]
1301 if re.match("^1\.\d+$", ver):
1302 versions = set([ver])
1303 elif re.match("^(1\.\d+)\+$", ver):
1304 if not ver[:-1] in allowed_versions:
1305 raise ValueError("invalid OpenFlow version %s" % ver[:-1])
1306 versions = set()
1307 if ver != "1.1+": versions.add("1.0")
1308 if ver != "1.2+": versions.add("1.1")
1309 if ver != "1.3+": versions.add("1.2")
1310 versions.add("1.3")
1311 else:
1312 versions = set(ver.split(','))
1313
1314 for version in versions:
1315 if not version in allowed_versions:
1316 raise ValueError("invalid OpenFlow version %s" % version)
1317
1318 return versions
1319
1320assert(parse_version("1.0") == set(["1.0"]))
1321assert(parse_version("1.0,1.2,1.3") == set(["1.0", "1.2", "1.3"]))
1322assert(parse_version("1.0+") == set(["1.0", "1.1", "1.2", "1.3"]))
Rich Lane7744e112013-01-11 17:23:57 -08001323
Rich Laneae3428c2013-03-07 14:37:42 -08001324def get_stats(test, req):
1325 """
1326 Retrieve a list of stats entries. Handles OFPSF_REPLY_MORE.
1327 """
Rich Lane609194f2013-10-21 06:17:37 -07001328 msgtype = ofp.OFPT_STATS_REPLY
1329 more_flag = ofp.OFPSF_REPLY_MORE
Rich Laneae3428c2013-03-07 14:37:42 -08001330 stats = []
1331 reply, _ = test.controller.transact(req)
1332 test.assertTrue(reply is not None, "No response to stats request")
Rich Lane34c68d52013-10-11 10:38:21 -07001333 test.assertEquals(reply.type, msgtype, "Response had unexpected message type")
Rich Lane5fd6faf2013-03-11 13:30:20 -07001334 stats.extend(reply.entries)
Rich Lanebd56ed62013-07-10 15:49:44 -07001335 while reply.flags & more_flag != 0:
Rich Lane34c68d52013-10-11 10:38:21 -07001336 reply, pkt = test.controller.poll(exp_msg=msgtype)
Rich Laneae3428c2013-03-07 14:37:42 -08001337 test.assertTrue(reply is not None, "No response to stats request")
Rich Lane5fd6faf2013-03-11 13:30:20 -07001338 stats.extend(reply.entries)
Rich Laneae3428c2013-03-07 14:37:42 -08001339 return stats
1340
Rich Lanebd56ed62013-07-10 15:49:44 -07001341def get_flow_stats(test, match, table_id=None,
1342 out_port=None, out_group=None,
1343 cookie=0, cookie_mask=0):
Rich Laneae3428c2013-03-07 14:37:42 -08001344 """
1345 Retrieve a list of flow stats entries.
1346 """
Rich Lanebd56ed62013-07-10 15:49:44 -07001347
1348 if table_id == None:
1349 if ofp.OFP_VERSION <= 2:
1350 table_id = 0xff
1351 else:
1352 table_id = ofp.OFPTT_ALL
1353
Rich Lanef3bc48c2013-05-03 17:39:35 -07001354 if out_port == None:
Rich Lanebd56ed62013-07-10 15:49:44 -07001355 if ofp.OFP_VERSION == 1:
1356 out_port = ofp.OFPP_NONE
1357 else:
1358 out_port = ofp.OFPP_ANY
1359
1360 if out_group == None:
1361 if ofp.OFP_VERSION > 1:
1362 out_group = ofp.OFPP_ANY
1363
Rich Lanee717c6e2013-03-12 10:25:50 -07001364 req = ofp.message.flow_stats_request(match=match,
Rich Lanebd56ed62013-07-10 15:49:44 -07001365 table_id=table_id,
1366 out_port=out_port)
1367 if ofp.OFP_VERSION > 1:
1368 req.out_group = out_group
1369 req.cookie = cookie
1370 req.cookie_mask = cookie_mask
1371
Rich Laneae3428c2013-03-07 14:37:42 -08001372 return get_stats(test, req)
1373
Rich Lane968b6192013-03-07 15:34:43 -08001374def get_port_stats(test, port_no):
1375 """
1376 Retrieve a list of port stats entries.
1377 """
Rich Lanee717c6e2013-03-12 10:25:50 -07001378 req = ofp.message.port_stats_request(port_no=port_no)
Rich Lane968b6192013-03-07 15:34:43 -08001379 return get_stats(test, req)
1380
Rich Lane6a334922013-03-07 16:14:52 -08001381def get_queue_stats(test, port_no, queue_id):
1382 """
1383 Retrieve a list of queue stats entries.
1384 """
Rich Lanee717c6e2013-03-12 10:25:50 -07001385 req = ofp.message.queue_stats_request(port_no=port_no, queue_id=queue_id)
Rich Lane6a334922013-03-07 16:14:52 -08001386 return get_stats(test, req)
1387
Rich Laneae3428c2013-03-07 14:37:42 -08001388def verify_flow_stats(test, match, table_id=0xff,
Rich Lanef3bc48c2013-05-03 17:39:35 -07001389 out_port=None,
Rich Laneae3428c2013-03-07 14:37:42 -08001390 initial=[],
1391 pkts=None, bytes=None):
1392 """
1393 Verify that flow stats changed as expected.
1394
1395 Optionally takes an 'initial' list of stats entries, as returned by
1396 get_flow_stats(). If 'initial' is not given the counters are assumed to
1397 begin at 0.
1398 """
Rich Lanef3bc48c2013-05-03 17:39:35 -07001399 if out_port == None:
1400 out_port = ofp.OFPP_NONE
1401
Rich Laneae3428c2013-03-07 14:37:42 -08001402 def accumulate(stats):
1403 pkts_acc = bytes_acc = 0
1404 for stat in stats:
1405 pkts_acc += stat.packet_count
1406 bytes_acc += stat.byte_count
1407 return (pkts_acc, bytes_acc)
1408
1409 pkts_before, bytes_before = accumulate(initial)
1410
1411 # Wait 10s for counters to update
1412 pkt_diff = byte_diff = None
1413 for i in range(0, 100):
1414 stats = get_flow_stats(test, match, table_id=table_id, out_port=out_port)
1415 pkts_after, bytes_after = accumulate(stats)
1416 pkt_diff = pkts_after - pkts_before
1417 byte_diff = bytes_after - bytes_before
1418 if (pkts == None or pkt_diff >= pkts) and \
1419 (bytes == None or byte_diff >= bytes):
1420 break
Dan Talayco53724732013-03-08 23:54:02 -08001421 time.sleep(0.1)
Rich Laneae3428c2013-03-07 14:37:42 -08001422
1423 if pkts != None:
1424 test.assertEquals(pkt_diff, pkts, "Flow packet counter not updated properly (expected increase of %d, got increase of %d)" % (pkts, pkt_diff))
1425
1426 if bytes != None:
Rich Lane53b96812013-03-07 16:54:50 -08001427 test.assertTrue(byte_diff >= bytes and byte_diff <= bytes*1.1,
1428 "Flow byte counter not updated properly (expected increase of %d, got increase of %d)" % (bytes, byte_diff))
Rich Laneae3428c2013-03-07 14:37:42 -08001429
Rich Lane968b6192013-03-07 15:34:43 -08001430def verify_port_stats(test, port,
1431 initial=[],
1432 tx_pkts=None, rx_pkts=None,
1433 tx_bytes=None, rx_bytes=None):
1434 """
1435 Verify that port stats changed as expected.
1436
1437 Optionally takes an 'initial' list of stats entries, as returned by
1438 get_port_stats(). If 'initial' is not given the counters are assumed to
1439 begin at 0.
1440 """
1441 def accumulate(stats):
1442 tx_pkts_acc = rx_pkts_acc = tx_bytes_acc = rx_bytes_acc = 0
1443 for stat in stats:
1444 tx_pkts_acc += stat.tx_packets
1445 rx_pkts_acc += stat.rx_packets
1446 tx_bytes_acc += stat.tx_bytes
1447 rx_bytes_acc += stat.rx_bytes
1448 return (tx_pkts_acc, rx_pkts_acc, tx_bytes_acc, rx_bytes_acc)
1449
1450 tx_pkts_before, rx_pkts_before, \
1451 tx_bytes_before, rx_bytes_before = accumulate(initial)
1452
1453 # Wait 10s for counters to update
1454 for i in range(0, 100):
1455 stats = get_port_stats(test, port)
1456 tx_pkts_after, rx_pkts_after, \
1457 tx_bytes_after, rx_bytes_after = accumulate(stats)
1458 tx_pkts_diff = tx_pkts_after - tx_pkts_before
1459 rx_pkts_diff = rx_pkts_after - rx_pkts_before
1460 tx_bytes_diff = tx_bytes_after - tx_bytes_before
1461 rx_bytes_diff = rx_bytes_after - rx_bytes_before
1462 if (tx_pkts == None or tx_pkts == tx_pkts_diff) and \
1463 (rx_pkts == None or rx_pkts == rx_pkts_diff) and \
Rich Lane53b96812013-03-07 16:54:50 -08001464 (tx_bytes == None or tx_bytes <= tx_bytes_diff) and \
1465 (rx_bytes == None or rx_bytes <= rx_bytes_diff):
Rich Lane968b6192013-03-07 15:34:43 -08001466 break
1467 time.sleep(0.1)
1468
1469 if (tx_pkts != None):
1470 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))
1471 if (rx_pkts != None):
1472 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))
1473 if (tx_bytes != None):
Rich Lane53b96812013-03-07 16:54:50 -08001474 test.assertTrue(tx_bytes_diff >= tx_bytes and tx_bytes_diff <= tx_bytes*1.1,
1475 "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 -08001476 if (rx_bytes != None):
Rich Lane53b96812013-03-07 16:54:50 -08001477 test.assertTrue(rx_bytes_diff >= rx_bytes and rx_bytes_diff <= rx_bytes*1.1,
1478 "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 -08001479
Rich Lane6a334922013-03-07 16:14:52 -08001480def verify_queue_stats(test, port_no, queue_id,
1481 initial=[],
1482 pkts=None, bytes=None):
1483 """
1484 Verify that queue stats changed as expected.
1485
1486 Optionally takes an 'initial' list of stats entries, as returned by
1487 get_queue_stats(). If 'initial' is not given the counters are assumed to
1488 begin at 0.
1489 """
1490 def accumulate(stats):
1491 pkts_acc = bytes_acc = 0
1492 for stat in stats:
1493 pkts_acc += stat.tx_packets
1494 bytes_acc += stat.tx_bytes
1495 return (pkts_acc, bytes_acc)
1496
1497 pkts_before, bytes_before = accumulate(initial)
1498
1499 # Wait 10s for counters to update
1500 pkt_diff = byte_diff = None
1501 for i in range(0, 100):
1502 stats = get_queue_stats(test, port_no, queue_id)
1503 pkts_after, bytes_after = accumulate(stats)
1504 pkt_diff = pkts_after - pkts_before
1505 byte_diff = bytes_after - bytes_before
1506 if (pkts == None or pkt_diff >= pkts) and \
1507 (bytes == None or byte_diff >= bytes):
1508 break
Dan Talayco53724732013-03-08 23:54:02 -08001509 time.sleep(0.1)
Rich Lane6a334922013-03-07 16:14:52 -08001510
1511 if pkts != None:
1512 test.assertEquals(pkt_diff, pkts, "Queue packet counter not updated properly (expected increase of %d, got increase of %d)" % (pkts, pkt_diff))
1513
1514 if bytes != None:
Rich Lane53b96812013-03-07 16:54:50 -08001515 test.assertTrue(byte_diff >= bytes and byte_diff <= bytes*1.1,
1516 "Queue byte counter not updated properly (expected increase of %d, got increase of %d)" % (bytes, byte_diff))
Rich Laneae3428c2013-03-07 14:37:42 -08001517
Rich Lane4c504f32013-06-07 17:24:14 -07001518def packet_in_match(msg, data, in_port=None, reason=None):
1519 """
1520 Check whether the packet_in message 'msg' has fields matching 'data',
1521 'in_port', and 'reason'.
1522
1523 This function handles truncated packet_in data. The 'in_port' and 'reason'
1524 parameters are optional.
1525
1526 @param msg packet_in message
1527 @param data Expected packet_in data
1528 @param in_port Expected packet_in in_port, or None
1529 @param reason Expected packet_in reason, or None
1530 """
1531
Rich Lanec0d26dd2013-07-10 12:46:03 -07001532 if ofp.OFP_VERSION <= 2:
1533 pkt_in_port = msg.in_port
1534 else:
1535 oxms = { type(oxm): oxm for oxm in msg.match.oxm_list }
1536 if ofp.oxm.in_port in oxms:
1537 pkt_in_port = oxms[ofp.oxm.in_port].value
1538 else:
1539 logging.warn("Missing in_port in packet-in message")
1540 pkt_in_port = None
1541
1542 if in_port != None and in_port != pkt_in_port:
Rich Lane9f2f17e2013-09-13 13:19:37 -07001543 logging.debug("Incorrect packet_in in_port (expected %d, received %d)", in_port, pkt_in_port)
Rich Lane4c504f32013-06-07 17:24:14 -07001544 return False
1545
Rich Lanec0d26dd2013-07-10 12:46:03 -07001546 if reason != None and reason != msg.reason:
Rich Lane4c504f32013-06-07 17:24:14 -07001547 logging.debug("Incorrect packet_in reason (expected %d, received %d)", reason, msg.reason)
1548 return False
1549
1550 # Check that one of the packets is a prefix of the other.
1551 # The received packet may be either truncated or padded, but not both.
1552 # (Some of the padding may be truncated but that's irrelevant). We
1553 # need to check that the smaller packet is a prefix of the larger one.
1554 # Note that this check succeeds if the switch sends a zero-length
1555 # packet-in.
1556 compare_len = min(len(msg.data), len(data))
1557 if data[:compare_len] != msg.data[:compare_len]:
1558 logging.debug("Incorrect packet_in data")
1559 logging.debug("Expected %s" % format_packet(data[:compare_len]))
1560 logging.debug("Received %s" % format_packet(msg.data[:compare_len]))
1561 return False
1562
1563 return True
1564
1565def verify_packet_in(test, data, in_port, reason, controller=None):
1566 """
1567 Assert that the controller receives a packet_in message matching data 'data'
1568 from port 'in_port' with reason 'reason'. Does not trigger the packet_in
1569 itself, that's up to the test case.
1570
1571 @param test Instance of base_tests.SimpleProtocol
1572 @param pkt String to expect as the packet_in data
1573 @param in_port OpenFlow port number to expect as the packet_in in_port
1574 @param reason One of OFPR_* to expect as the packet_in reason
1575 @param controller Controller instance, defaults to test.controller
1576 @returns The received packet-in message
1577 """
1578
1579 if controller == None:
1580 controller = test.controller
1581
1582 end_time = time.time() + oftest.ofutils.default_timeout
1583
1584 while True:
1585 msg, _ = controller.poll(ofp.OFPT_PACKET_IN, end_time - time.time())
1586 if not msg:
1587 # Timeout
1588 break
1589 elif packet_in_match(msg, data, in_port, reason):
1590 # Found a matching message
1591 break
1592
1593 test.assertTrue(msg is not None, 'Packet in message not received on port %d' % in_port)
1594 return msg
1595
1596def verify_no_packet_in(test, data, in_port, controller=None):
1597 """
1598 Assert that the controller does not receive a packet_in message matching
1599 data 'data' from port 'in_port'.
1600
1601 @param test Instance of base_tests.SimpleProtocol
1602 @param pkt String to expect as the packet_in data
1603 @param in_port OpenFlow port number to expect as the packet_in in_port
1604 @param controller Controller instance, defaults to test.controller
1605 """
1606
1607 if controller == None:
1608 controller = test.controller
1609
1610 # Negative test, need to wait a short amount of time before checking we
1611 # didn't receive the message.
1612 time.sleep(0.5)
1613
1614 # Check every packet_in queued in the controller
1615 while True:
1616 msg, _ = controller.poll(ofp.OFPT_PACKET_IN, timeout=0)
1617 if msg == None:
1618 # No more queued packet_in messages
1619 break
1620 elif packet_in_match(msg, data, in_port, None):
1621 # Found a matching message
1622 break
1623
Rich Lane82c882d2013-08-09 17:13:52 -07001624 if in_port == None:
1625 test.assertTrue(msg == None, "Did not expect a packet-in message on any port")
1626 else:
1627 test.assertTrue(msg == None, "Did not expect a packet-in message on port %d" % in_port)
Rich Lane4c504f32013-06-07 17:24:14 -07001628
Rich Lane045db072013-08-06 13:16:30 -07001629def openflow_ports(num=None):
1630 """
1631 Return a list of 'num' OpenFlow port numbers
1632
1633 If 'num' is None, return all available ports. Otherwise, limit the length
1634 of the result to 'num' and raise an exception if not enough ports are
1635 available.
1636 """
1637 ports = sorted(oftest.config["port_map"].keys())
1638 if num != None and len(ports) < num:
1639 raise Exception("test requires %d ports but only %d are available" % (num, len(ports)))
1640 return ports[:num]
1641
Rich Lanee4b384d2013-09-13 14:33:40 -07001642def verify_packet(test, pkt, ofport):
1643 """
1644 Check that an expected packet is received
1645 """
1646 logging.debug("Checking for pkt on port %r", ofport)
1647 (rcv_port, rcv_pkt, pkt_time) = test.dataplane.poll(port_number=ofport, exp_pkt=str(pkt))
1648 test.assertTrue(rcv_pkt != None, "Did not receive pkt on %r" % ofport)
1649
1650def verify_no_packet(test, pkt, ofport):
1651 """
1652 Check that a particular packet is not received
1653 """
1654 logging.debug("Negative check for pkt on port %r", ofport)
1655 (rcv_port, rcv_pkt, pkt_time) = test.dataplane.poll(port_number=ofport, exp_pkt=str(pkt), timeout=0.01)
1656 test.assertTrue(rcv_pkt == None, "Received packet on %r" % ofport)
1657
1658def verify_no_other_packets(test):
1659 """
1660 Check that no unexpected packets are received
1661
1662 This is a no-op if the --relax option is in effect.
1663 """
1664 if oftest.config["relax"]:
1665 return
1666 logging.debug("Checking for unexpected packets on all ports")
1667 (rcv_port, rcv_pkt, pkt_time) = test.dataplane.poll(timeout=0.01)
1668 if rcv_pkt != None:
1669 logging.debug("Received unexpected packet on port %r: %s", rcv_port, format_packet(rcv_pkt))
1670 test.assertTrue(rcv_pkt == None, "Unexpected packet on port %r" % rcv_port)
1671
1672def verify_packets(test, pkt, ofports):
1673 """
1674 Check that a packet is received on certain ports
1675
1676 Also verifies that the packet is not received on any other ports, and that no
1677 other packets are received (unless --relax is in effect).
1678
1679 This covers the common and simplest cases for checking dataplane outputs.
1680 For more complex usage, like multiple different packets being output, or
1681 multiple packets on the same port, use the primitive verify_packet,
1682 verify_no_packet, and verify_no_other_packets functions directly.
1683 """
1684 pkt = str(pkt)
1685 for ofport in openflow_ports():
1686 if ofport in ofports:
1687 verify_packet(test, pkt, ofport)
1688 else:
1689 verify_no_packet(test, pkt, ofport)
1690 verify_no_other_packets(test)
1691
Rich Lane12d04592013-10-10 17:21:07 -07001692def verify_no_errors(ctrl):
1693 error, _ = ctrl.poll(ofp.OFPT_ERROR, 0)
1694 if error:
1695 raise AssertionError("unexpected error type=%d code=%d" % (error.err_type, error.code))
Rich Lanee4b384d2013-09-13 14:33:40 -07001696
Jonathan Stoutfcee3142014-01-28 15:46:22 -05001697def verify_capability(test, capability):
1698 """
Jonathan Stout073642d2014-02-04 13:41:48 -05001699 Return True if DUT supports the specified capability.
Jonathan Stoutfcee3142014-01-28 15:46:22 -05001700
1701 @param test Instance of base_tests.SimpleProtocol
1702 @param capability One of ofp_capabilities.
1703 """
1704 logging.info("Verifing that capability code is valid.")
1705 test.assertIn(capability, ofp.const.ofp_capabilities_map,
1706 "Capability code %d does not exist." % capability)
1707 capability_str = ofp.const.ofp_capabilities_map[capability]
1708
1709 logging.info(("Sending features_request to test if capability "
Jonathan Stout97e458a2014-01-28 16:08:04 -05001710 "%s is supported."), capability_str)
Jonathan Stoutfcee3142014-01-28 15:46:22 -05001711 req = ofp.message.features_request()
1712 res, raw = test.controller.transact(req)
1713 test.assertIsNotNone(res, "Did not receive a response from the DUT.")
1714 test.assertEqual(res.type, ofp.OFPT_FEATURES_REPLY,
1715 ("Unexpected packet type %d received in response to "
1716 "OFPT_FEATURES_REQUEST") % res.type)
Jonathan Stout641167f2014-02-04 12:07:10 -05001717 logging.info("Received features_reply.")
Jonathan Stoutfcee3142014-01-28 15:46:22 -05001718
Jonathan Stout641167f2014-02-04 12:07:10 -05001719 if (res.capabilities & capability) > 0:
1720 logging.info("Switch capabilities bitmask claims to support %s",
1721 capability_str)
1722 return True, res.capabilities
1723 else:
1724 logging.info("Capabilities bitmask does not support %s.",
1725 capability_str)
1726 return False, res.capabilities
Jonathan Stoutfcee3142014-01-28 15:46:22 -05001727
Rich Lane7744e112013-01-11 17:23:57 -08001728__all__ = list(set(locals()) - _import_blacklist)