blob: ae16ee15bec14588fa46ca36a502d8127a179c88 [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,
Harshmeet Singh45b2a9d2014-01-28 13:02:04 -0600298 icmp_data=''):
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700299 """
300 Return a simple ICMP packet
301
302 Supports a few parameters:
303 @param len Length of packet in bytes w/o CRC
Rich Laned0478ff2013-03-11 12:46:58 -0700304 @param eth_dst Destinatino MAC
305 @param eth_src Source MAC
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700306 @param dl_vlan_enable True if the packet is with vlan, False otherwise
Rich Laned0478ff2013-03-11 12:46:58 -0700307 @param vlan_vid VLAN ID
308 @param vlan_pcp VLAN priority
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700309 @param ip_src IP source
310 @param ip_dst IP destination
311 @param ip_tos IP ToS
Gregor Maier9cc93342013-01-29 16:55:28 -0800312 @param ip_ttl IP TTL
Harshmeet Singhd209c0b2014-01-28 09:48:58 -0600313 @param ip_id IP Identification
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700314 @param icmp_type ICMP type
315 @param icmp_code ICMP code
Harshmeet Singhd209c0b2014-01-28 09:48:58 -0600316 @param icmp_data ICMP data
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700317
318 Generates a simple ICMP ECHO REQUEST. Users
319 shouldn't assume anything about this packet other than that
320 it is a valid ethernet/ICMP frame.
321 """
Jeffrey Townsend5cb7ed32012-08-17 18:11:01 +0000322
323 if MINSIZE > pktlen:
324 pktlen = MINSIZE
325
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700326 if (dl_vlan_enable):
Rich Laned0478ff2013-03-11 12:46:58 -0700327 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
328 scapy.Dot1Q(prio=vlan_pcp, id=0, vlan=vlan_vid)/ \
Harshmeet Singhd209c0b2014-01-28 09:48:58 -0600329 scapy.IP(src=ip_src, dst=ip_dst, ttl=ip_ttl, tos=ip_tos, id=ip_id)/ \
Harshmeet Singh45b2a9d2014-01-28 13:02:04 -0600330 scapy.ICMP(type=icmp_type, code=icmp_code)/ icmp_data
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700331 else:
Rich Laned0478ff2013-03-11 12:46:58 -0700332 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
Harshmeet Singhd209c0b2014-01-28 09:48:58 -0600333 scapy.IP(src=ip_src, dst=ip_dst, ttl=ip_ttl, tos=ip_tos, id=ip_id)/ \
Harshmeet Singh45b2a9d2014-01-28 13:02:04 -0600334 scapy.ICMP(type=icmp_type, code=icmp_code)/ icmp_data
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700335
336 pkt = pkt/("0" * (pktlen - len(pkt)))
337
338 return pkt
339
Rich Lane86aceb02013-07-17 18:45:38 -0700340def simple_icmpv6_packet(pktlen=100,
341 eth_dst='00:01:02:03:04:05',
342 eth_src='00:06:07:08:09:0a',
343 dl_vlan_enable=False,
344 vlan_vid=0,
345 vlan_pcp=0,
346 ipv6_src='2001:db8:85a3::8a2e:370:7334',
347 ipv6_dst='2001:db8:85a3::8a2e:370:7335',
348 ipv6_tc=0,
349 ipv6_hlim=64,
350 ipv6_fl=0,
351 icmp_type=8,
352 icmp_code=0):
353 """
354 Return a simple ICMPv6 packet
355
356 Supports a few parameters:
357 @param len Length of packet in bytes w/o CRC
358 @param eth_dst Destination MAC
359 @param eth_src Source MAC
360 @param dl_vlan_enable True if the packet is with vlan, False otherwise
361 @param vlan_vid VLAN ID
362 @param vlan_pcp VLAN priority
363 @param ipv6_src IPv6 source
364 @param ipv6_dst IPv6 destination
365 @param ipv6_tc IPv6 traffic class
366 @param ipv6_ttl IPv6 hop limit
367 @param ipv6_fl IPv6 flow label
368 @param icmp_type ICMP type
369 @param icmp_code ICMP code
370
371 Generates a simple ICMP ECHO REQUEST. Users shouldn't assume anything
372 about this packet other than that it is a valid ethernet/IPv6/ICMP frame.
373 """
374
375 if MINSIZE > pktlen:
376 pktlen = MINSIZE
377
378 pkt = scapy.Ether(dst=eth_dst, src=eth_src)
379 if dl_vlan_enable or vlan_vid or vlan_pcp:
380 pkt /= scapy.Dot1Q(vlan=vlan_vid, prio=vlan_pcp)
381 pkt /= scapy.IPv6(src=ipv6_src, dst=ipv6_dst, fl=ipv6_fl, tc=ipv6_tc, hlim=ipv6_hlim)
382 pkt /= scapy.ICMPv6Unknown(type=icmp_type, code=icmp_code)
383 pkt /= ("D" * (pktlen - len(pkt)))
384
385 return pkt
386
Shudong Zhouc7562b12013-02-06 01:12:18 -0800387def simple_arp_packet(pktlen=60,
Rich Laned0478ff2013-03-11 12:46:58 -0700388 eth_dst='ff:ff:ff:ff:ff:ff',
389 eth_src='00:06:07:08:09:0a',
Rich Lanee01611f2014-01-15 14:55:11 -0800390 vlan_vid=0,
391 vlan_pcp=0,
Shudong Zhouc7562b12013-02-06 01:12:18 -0800392 arp_op=1,
393 ip_snd='192.168.0.1',
394 ip_tgt='192.168.0.2',
395 hw_snd='00:06:07:08:09:0a',
396 hw_tgt='00:00:00:00:00:00',
397 ):
398 """
399 Return a simple ARP packet
400
401 Supports a few parameters:
402 @param len Length of packet in bytes w/o CRC
Rich Laned0478ff2013-03-11 12:46:58 -0700403 @param eth_dst Destinatino MAC
404 @param eth_src Source MAC
Shudong Zhouc7562b12013-02-06 01:12:18 -0800405 @param arp_op Operation (1=request, 2=reply)
406 @param ip_snd Sender IP
407 @param ip_tgt Target IP
408 @param hw_snd Sender hardware address
409 @param hw_tgt Target hardware address
410
411 Generates a simple ARP REQUEST. Users
412 shouldn't assume anything about this packet other than that
413 it is a valid ethernet/ARP frame.
414 """
415
416 if MINSIZE > pktlen:
417 pktlen = MINSIZE
418
Rich Lanee01611f2014-01-15 14:55:11 -0800419 pkt = scapy.Ether(dst=eth_dst, src=eth_src)
420 if vlan_vid or vlan_pcp:
421 pkt /= scapy.Dot1Q(vlan=vlan_vid, prio=vlan_pcp)
422 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 -0800423
Rich Laned459ce52014-01-24 12:09:54 -0800424 pkt = pkt/("\0" * (pktlen - len(pkt)))
Shudong Zhouc7562b12013-02-06 01:12:18 -0800425
426 return pkt
427
Ed Swierk0aeff8c2012-03-23 20:27:18 -0700428def simple_eth_packet(pktlen=60,
Rich Lane53275082013-11-18 23:26:22 -0800429 eth_dst='00:01:02:03:04:05',
430 eth_src='00:06:07:08:09:0a',
Rich Laned0478ff2013-03-11 12:46:58 -0700431 eth_type=0x88cc):
Jeffrey Townsend5cb7ed32012-08-17 18:11:01 +0000432
433 if MINSIZE > pktlen:
434 pktlen = MINSIZE
435
Rich Laned0478ff2013-03-11 12:46:58 -0700436 pkt = scapy.Ether(dst=eth_dst, src=eth_src, type=eth_type)
Ed Swierk0aeff8c2012-03-23 20:27:18 -0700437
438 pkt = pkt/("0" * (pktlen - len(pkt)))
439
440 return pkt
441
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800442def qinq_tcp_packet(pktlen=100,
Rich Laned0478ff2013-03-11 12:46:58 -0700443 eth_dst='00:01:02:03:04:05',
444 eth_src='00:06:07:08:09:0a',
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800445 dl_vlan_outer=20,
446 dl_vlan_pcp_outer=0,
447 dl_vlan_cfi_outer=0,
Rich Laned0478ff2013-03-11 12:46:58 -0700448 vlan_vid=10,
449 vlan_pcp=0,
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800450 dl_vlan_cfi=0,
451 ip_src='192.168.0.1',
452 ip_dst='192.168.0.2',
453 ip_tos=0,
Gregor Maier9cc93342013-01-29 16:55:28 -0800454 ip_ttl=64,
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800455 tcp_sport=1234,
456 tcp_dport=80,
457 ip_ihl=None,
458 ip_options=False
459 ):
460 """
461 Return a doubly tagged dataplane TCP packet
462
463 Supports a few parameters:
464 @param len Length of packet in bytes w/o CRC
Rich Laned0478ff2013-03-11 12:46:58 -0700465 @param eth_dst Destinatino MAC
466 @param eth_src Source MAC
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800467 @param dl_vlan_outer Outer VLAN ID
468 @param dl_vlan_pcp_outer Outer VLAN priority
469 @param dl_vlan_cfi_outer Outer VLAN cfi bit
Rich Laned0478ff2013-03-11 12:46:58 -0700470 @param vlan_vid Inner VLAN ID
471 @param vlan_pcp VLAN priority
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800472 @param dl_vlan_cfi VLAN cfi bit
473 @param ip_src IP source
474 @param ip_dst IP destination
475 @param ip_tos IP ToS
476 @param tcp_dport TCP destination port
477 @param ip_sport TCP source port
478
479 Generates a TCP request. Users
480 shouldn't assume anything about this packet other than that
481 it is a valid ethernet/IP/TCP frame.
482 """
483
484 if MINSIZE > pktlen:
485 pktlen = MINSIZE
486
487 # Note Dot1Q.id is really CFI
Rich Laned0478ff2013-03-11 12:46:58 -0700488 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800489 scapy.Dot1Q(prio=dl_vlan_pcp_outer, id=dl_vlan_cfi_outer, vlan=dl_vlan_outer)/ \
Rich Laned0478ff2013-03-11 12:46:58 -0700490 scapy.Dot1Q(prio=vlan_pcp, id=dl_vlan_cfi, vlan=vlan_vid)/ \
Gregor Maier9cc93342013-01-29 16:55:28 -0800491 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ttl=ip_ttl, ihl=ip_ihl)/ \
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800492 scapy.TCP(sport=tcp_sport, dport=tcp_dport)
493
494 pkt = pkt/("D" * (pktlen - len(pkt)))
495
496 return pkt
497
Shudong Zhoub7f12462012-11-20 13:01:12 -0800498def do_barrier(ctrl, timeout=-1):
Dan Talayco0fc08bd2012-04-09 16:56:18 -0700499 """
500 Do a barrier command
501 Return 0 on success, -1 on error
502 """
Rich Lanee717c6e2013-03-12 10:25:50 -0700503 b = ofp.message.barrier_request()
Shudong Zhoub7f12462012-11-20 13:01:12 -0800504 (resp, pkt) = ctrl.transact(b, timeout=timeout)
Rich Lane3a261d52013-01-03 17:45:08 -0800505 if resp is None:
506 raise AssertionError("barrier failed")
Dan Talaycof6b94832012-04-12 21:50:57 -0700507 # We'll trust the transaction processing in the controller that xid matched
Rich Lane3a261d52013-01-03 17:45:08 -0800508 return 0 # for backwards compatibility
Dan Talayco92c99122010-06-03 13:53:18 -0700509
Rich Lane9a003812012-10-04 17:17:59 -0700510def port_config_get(controller, port_no):
Dan Talayco92c99122010-06-03 13:53:18 -0700511 """
512 Get a port's configuration
513
514 Gets the switch feature configuration and grabs one port's
515 configuration
516
517 @returns (hwaddr, config, advert) The hwaddress, configuration and
518 advertised values
519 """
Rich Lane6dc865c2013-07-10 10:12:13 -0700520
521 if ofp.OFP_VERSION <= 3:
522 request = ofp.message.features_request()
523 reply, _ = controller.transact(request)
524 if reply is None:
525 logging.warn("Get feature request failed")
526 return None, None, None
527 logging.debug(reply.show())
528 ports = reply.ports
529 else:
530 request = ofp.message.port_desc_stats_request()
531 # TODO do multipart correctly
532 reply, _ = controller.transact(request)
533 if reply is None:
534 logging.warn("Port desc stats request failed")
535 return None, None, None
536 logging.debug(reply.show())
537 ports = reply.entries
538
539 for port in ports:
540 if port.port_no == port_no:
541 return (port.hw_addr, port.config, port.advertised)
Dan Talayco92c99122010-06-03 13:53:18 -0700542
Rich Lane9a003812012-10-04 17:17:59 -0700543 logging.warn("Did not find port number for port config")
Dan Talayco92c99122010-06-03 13:53:18 -0700544 return None, None, None
545
Rich Lane9a003812012-10-04 17:17:59 -0700546def port_config_set(controller, port_no, config, mask):
Dan Talayco92c99122010-06-03 13:53:18 -0700547 """
548 Set the port configuration according the given parameters
549
550 Gets the switch feature configuration and updates one port's
551 configuration value according to config and mask
552 """
Rich Lane9a003812012-10-04 17:17:59 -0700553 logging.info("Setting port " + str(port_no) + " to config " + str(config))
Rich Lane6dc865c2013-07-10 10:12:13 -0700554
555 hw_addr, _, _ = port_config_get(controller, port_no)
556
Rich Lanee717c6e2013-03-12 10:25:50 -0700557 mod = ofp.message.port_mod()
Dan Talayco92c99122010-06-03 13:53:18 -0700558 mod.port_no = port_no
Rich Lane6dc865c2013-07-10 10:12:13 -0700559 if hw_addr != None:
560 mod.hw_addr = hw_addr
Dan Talayco92c99122010-06-03 13:53:18 -0700561 mod.config = config
562 mod.mask = mask
Rich Lane6dc865c2013-07-10 10:12:13 -0700563 mod.advertise = 0 # No change
Rich Lane5c3151c2013-01-03 17:15:41 -0800564 controller.message_send(mod)
565 return 0
Dan Talayco92c99122010-06-03 13:53:18 -0700566
Rich Lane2014f9b2012-10-05 15:29:40 -0700567def receive_pkt_check(dp, pkt, yes_ports, no_ports, assert_if):
Dan Talayco92c99122010-06-03 13:53:18 -0700568 """
569 Check for proper receive packets across all ports
Ken Chiang1bf01602012-04-04 10:48:23 -0700570 @param dp The dataplane object
Dan Talayco92c99122010-06-03 13:53:18 -0700571 @param pkt Expected packet; may be None if yes_ports is empty
572 @param yes_ports Set or list of ports that should recieve packet
573 @param no_ports Set or list of ports that should not receive packet
574 @param assert_if Object that implements assertXXX
Rich Lanee4b384d2013-09-13 14:33:40 -0700575
576 DEPRECATED in favor in verify_packets
Dan Talayco92c99122010-06-03 13:53:18 -0700577 """
Rich Lane91765672012-12-06 16:33:04 -0800578
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700579 exp_pkt_arg = None
Rich Lanecd97d3d2013-01-07 18:50:06 -0800580 if oftest.config["relax"]:
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700581 exp_pkt_arg = pkt
582
Dan Talayco92c99122010-06-03 13:53:18 -0700583 for ofport in yes_ports:
Rich Lane9a003812012-10-04 17:17:59 -0700584 logging.debug("Checking for pkt on port " + str(ofport))
Ken Chiang1bf01602012-04-04 10:48:23 -0700585 (rcv_port, rcv_pkt, pkt_time) = dp.poll(
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700586 port_number=ofport, exp_pkt=exp_pkt_arg)
Dan Talayco92c99122010-06-03 13:53:18 -0700587 assert_if.assertTrue(rcv_pkt is not None,
588 "Did not receive pkt on " + str(ofport))
Rich Lanecd97d3d2013-01-07 18:50:06 -0800589 if not oftest.dataplane.match_exp_pkt(pkt, rcv_pkt):
Rich Lane3c266832013-01-29 18:29:15 -0800590 logging.debug("Expected %s" % format_packet(pkt))
591 logging.debug("Received %s" % format_packet(rcv_pkt))
Rich Lanecd97d3d2013-01-07 18:50:06 -0800592 assert_if.assertTrue(oftest.dataplane.match_exp_pkt(pkt, rcv_pkt),
Rich Lane3c266832013-01-29 18:29:15 -0800593 "Received packet does not match expected packet " +
Ken Chiang1bf01602012-04-04 10:48:23 -0700594 "on port " + str(ofport))
Dan Talayco73f84012012-10-02 09:23:18 -0700595 if len(no_ports) > 0:
Rich Lane48f6aed2014-03-23 15:51:02 -0700596 time.sleep(oftest.ofutils.negative_timeout)
Dan Talayco92c99122010-06-03 13:53:18 -0700597 for ofport in no_ports:
Rich Lane9a003812012-10-04 17:17:59 -0700598 logging.debug("Negative check for pkt on port " + str(ofport))
Ken Chiang1bf01602012-04-04 10:48:23 -0700599 (rcv_port, rcv_pkt, pkt_time) = dp.poll(
Rich Lane91765672012-12-06 16:33:04 -0800600 port_number=ofport, timeout=0, exp_pkt=exp_pkt_arg)
Dan Talayco92c99122010-06-03 13:53:18 -0700601 assert_if.assertTrue(rcv_pkt is None,
602 "Unexpected pkt on port " + str(ofport))
Dan Talayco551befa2010-07-15 17:05:32 -0700603
604
Dan Talaycoc948d0b2012-03-23 12:17:54 -0700605def receive_pkt_verify(parent, egr_ports, exp_pkt, ing_port):
Dan Talayco551befa2010-07-15 17:05:32 -0700606 """
607 Receive a packet and verify it matches an expected value
Dan Talaycof6e76c02012-03-23 10:56:12 -0700608 @param egr_port A single port or list of ports
Dan Talayco551befa2010-07-15 17:05:32 -0700609
610 parent must implement dataplane, assertTrue and assertEqual
Rich Lanee4b384d2013-09-13 14:33:40 -0700611
612 DEPRECATED in favor in verify_packets
Dan Talayco551befa2010-07-15 17:05:32 -0700613 """
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700614 exp_pkt_arg = None
Rich Lanecd97d3d2013-01-07 18:50:06 -0800615 if oftest.config["relax"]:
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700616 exp_pkt_arg = exp_pkt
617
Dan Talaycof6e76c02012-03-23 10:56:12 -0700618 if type(egr_ports) == type([]):
619 egr_port_list = egr_ports
620 else:
621 egr_port_list = [egr_ports]
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700622
Dan Talaycof6e76c02012-03-23 10:56:12 -0700623 # Expect a packet from each port on egr port list
624 for egr_port in egr_port_list:
Dan Talaycod8ae7582012-03-23 12:24:56 -0700625 check_port = egr_port
Rich Lanee717c6e2013-03-12 10:25:50 -0700626 if egr_port == ofp.OFPP_IN_PORT:
Dan Talaycod8ae7582012-03-23 12:24:56 -0700627 check_port = ing_port
Dan Talaycof6e76c02012-03-23 10:56:12 -0700628 (rcv_port, rcv_pkt, pkt_time) = parent.dataplane.poll(
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700629 port_number=check_port, exp_pkt=exp_pkt_arg)
Dan Talayco551befa2010-07-15 17:05:32 -0700630
Dan Talaycof6e76c02012-03-23 10:56:12 -0700631 if rcv_pkt is None:
Rich Lane9a003812012-10-04 17:17:59 -0700632 logging.error("ERROR: No packet received from " +
Dan Talaycod8ae7582012-03-23 12:24:56 -0700633 str(check_port))
Dan Talayco551befa2010-07-15 17:05:32 -0700634
Dan Talaycof6e76c02012-03-23 10:56:12 -0700635 parent.assertTrue(rcv_pkt is not None,
Dan Talaycod8ae7582012-03-23 12:24:56 -0700636 "Did not receive packet port " + str(check_port))
Rich Lane9a003812012-10-04 17:17:59 -0700637 logging.debug("Packet len " + str(len(rcv_pkt)) + " in on " +
Dan Talaycof6e76c02012-03-23 10:56:12 -0700638 str(rcv_port))
639
640 if str(exp_pkt) != str(rcv_pkt):
Rich Lane9a003812012-10-04 17:17:59 -0700641 logging.error("ERROR: Packet match failed.")
642 logging.debug("Expected len " + str(len(exp_pkt)) + ": "
Dan Talaycof6e76c02012-03-23 10:56:12 -0700643 + str(exp_pkt).encode('hex'))
Rich Lane9a003812012-10-04 17:17:59 -0700644 logging.debug("Received len " + str(len(rcv_pkt)) + ": "
Dan Talaycof6e76c02012-03-23 10:56:12 -0700645 + str(rcv_pkt).encode('hex'))
Rich Lane5d7e89a2012-10-26 16:43:13 -0700646 logging.debug("Expected packet: " + inspect_packet(scapy.Ether(str(exp_pkt))))
647 logging.debug("Received packet: " + inspect_packet(scapy.Ether(str(rcv_pkt))))
Dan Talaycof6e76c02012-03-23 10:56:12 -0700648 parent.assertEqual(str(exp_pkt), str(rcv_pkt),
Dan Talaycod8ae7582012-03-23 12:24:56 -0700649 "Packet match error on port " + str(check_port))
Dan Talaycof6e76c02012-03-23 10:56:12 -0700650
Dan Talayco551befa2010-07-15 17:05:32 -0700651def match_verify(parent, req_match, res_match):
652 """
653 Verify flow matches agree; if they disagree, report where
654
655 parent must implement assertEqual
656 Use str() to ensure content is compared and not pointers
657 """
658
659 parent.assertEqual(req_match.wildcards, res_match.wildcards,
660 'Match failed: wildcards: ' + hex(req_match.wildcards) +
661 " != " + hex(res_match.wildcards))
662 parent.assertEqual(req_match.in_port, res_match.in_port,
663 'Match failed: in_port: ' + str(req_match.in_port) +
664 " != " + str(res_match.in_port))
Rich Laned0478ff2013-03-11 12:46:58 -0700665 parent.assertEqual(str(req_match.eth_src), str(res_match.eth_src),
666 'Match failed: eth_src: ' + str(req_match.eth_src) +
667 " != " + str(res_match.eth_src))
668 parent.assertEqual(str(req_match.eth_dst), str(res_match.eth_dst),
669 'Match failed: eth_dst: ' + str(req_match.eth_dst) +
670 " != " + str(res_match.eth_dst))
671 parent.assertEqual(req_match.vlan_vid, res_match.vlan_vid,
672 'Match failed: vlan_vid: ' + str(req_match.vlan_vid) +
673 " != " + str(res_match.vlan_vid))
674 parent.assertEqual(req_match.vlan_pcp, res_match.vlan_pcp,
675 'Match failed: vlan_pcp: ' +
676 str(req_match.vlan_pcp) + " != " +
677 str(res_match.vlan_pcp))
678 parent.assertEqual(req_match.eth_type, res_match.eth_type,
679 'Match failed: eth_type: ' + str(req_match.eth_type) +
680 " != " + str(res_match.eth_type))
Dan Talayco551befa2010-07-15 17:05:32 -0700681
Rich Lanee717c6e2013-03-12 10:25:50 -0700682 if (not(req_match.wildcards & ofp.OFPFW_DL_TYPE)
Rich Laned0478ff2013-03-11 12:46:58 -0700683 and (req_match.eth_type == IP_ETHERTYPE)):
684 parent.assertEqual(req_match.ip_dscp, res_match.ip_dscp,
685 'Match failed: ip_dscp: ' + str(req_match.ip_dscp) +
686 " != " + str(res_match.ip_dscp))
687 parent.assertEqual(req_match.ip_proto, res_match.ip_proto,
688 'Match failed: ip_proto: ' + str(req_match.ip_proto) +
689 " != " + str(res_match.ip_proto))
690 parent.assertEqual(req_match.ipv4_src, res_match.ipv4_src,
691 'Match failed: ipv4_src: ' + str(req_match.ipv4_src) +
692 " != " + str(res_match.ipv4_src))
693 parent.assertEqual(req_match.ipv4_dst, res_match.ipv4_dst,
694 'Match failed: ipv4_dst: ' + str(req_match.ipv4_dst) +
695 " != " + str(res_match.ipv4_dst))
Dan Talayco551befa2010-07-15 17:05:32 -0700696
Rich Lanee717c6e2013-03-12 10:25:50 -0700697 if (not(req_match.wildcards & ofp.OFPFW_NW_PROTO)
Rich Laned0478ff2013-03-11 12:46:58 -0700698 and ((req_match.ip_proto == TCP_PROTOCOL)
699 or (req_match.ip_proto == UDP_PROTOCOL))):
700 parent.assertEqual(req_match.tcp_src, res_match.tcp_src,
701 'Match failed: tcp_src: ' +
702 str(req_match.tcp_src) +
703 " != " + str(res_match.tcp_src))
704 parent.assertEqual(req_match.tcp_dst, res_match.tcp_dst,
705 'Match failed: tcp_dst: ' +
706 str(req_match.tcp_dst) +
707 " != " + str(res_match.tcp_dst))
Dan Talayco551befa2010-07-15 17:05:32 -0700708
Ed Swierk99a74de2012-08-22 06:40:54 -0700709def packet_to_flow_match(parent, packet):
Rich Lanef6883512013-03-11 17:00:09 -0700710 match = oftest.parse.packet_to_flow_match(packet)
Rich Laneab7476f2013-06-13 15:53:52 -0700711 if ofp.OFP_VERSION in [1, 2]:
712 match.wildcards |= required_wildcards(parent)
713 else:
714 # TODO remove incompatible OXM entries
715 pass
Ed Swierk99a74de2012-08-22 06:40:54 -0700716 return match
717
718def flow_msg_create(parent, pkt, ing_port=None, action_list=None, wildcards=None,
Dan Talaycof6e76c02012-03-23 10:56:12 -0700719 egr_ports=None, egr_queue=None, check_expire=False, in_band=False):
Dan Talayco551befa2010-07-15 17:05:32 -0700720 """
721 Create a flow message
722
723 Match on packet with given wildcards.
724 See flow_match_test for other parameter descriptoins
725 @param egr_queue if not None, make the output an enqueue action
Dan Talayco677c0b72011-08-23 22:53:38 -0700726 @param in_band if True, do not wildcard ingress port
Dan Talaycof6e76c02012-03-23 10:56:12 -0700727 @param egr_ports None (drop), single port or list of ports
Dan Talayco551befa2010-07-15 17:05:32 -0700728 """
Rich Lanef6883512013-03-11 17:00:09 -0700729 match = oftest.parse.packet_to_flow_match(pkt)
Dan Talayco551befa2010-07-15 17:05:32 -0700730 parent.assertTrue(match is not None, "Flow match from pkt failed")
Ed Swierk99a74de2012-08-22 06:40:54 -0700731 if wildcards is None:
732 wildcards = required_wildcards(parent)
Dan Talayco677c0b72011-08-23 22:53:38 -0700733 if in_band:
Rich Lanee717c6e2013-03-12 10:25:50 -0700734 wildcards &= ~ofp.OFPFW_IN_PORT
Dan Talayco551befa2010-07-15 17:05:32 -0700735 match.wildcards = wildcards
736 match.in_port = ing_port
737
Dan Talaycof6e76c02012-03-23 10:56:12 -0700738 if type(egr_ports) == type([]):
739 egr_port_list = egr_ports
740 else:
741 egr_port_list = [egr_ports]
742
Rich Lanee717c6e2013-03-12 10:25:50 -0700743 request = ofp.message.flow_add()
Dan Talayco551befa2010-07-15 17:05:32 -0700744 request.match = match
745 request.buffer_id = 0xffffffff
746 if check_expire:
Rich Lanee717c6e2013-03-12 10:25:50 -0700747 request.flags |= ofp.OFPFF_SEND_FLOW_REM
Dan Talayco551befa2010-07-15 17:05:32 -0700748 request.hard_timeout = 1
749
Rich Lane400fb9b2013-10-10 17:20:54 -0700750 if ofp.OFP_VERSION == 1:
751 actions = request.actions
752 else:
753 actions = []
754 request.instructions.append(ofp.instruction.apply_actions(actions))
755
Dan Talayco551befa2010-07-15 17:05:32 -0700756 if action_list is not None:
Rich Lane400fb9b2013-10-10 17:20:54 -0700757 actions.extend(action_list)
Dan Talayco551befa2010-07-15 17:05:32 -0700758
759 # Set up output/enqueue action if directed
760 if egr_queue is not None:
Dan Talaycof6e76c02012-03-23 10:56:12 -0700761 parent.assertTrue(egr_ports is not None, "Egress port not set")
Rich Lanee717c6e2013-03-12 10:25:50 -0700762 act = ofp.action.enqueue()
Dan Talaycof6e76c02012-03-23 10:56:12 -0700763 for egr_port in egr_port_list:
764 act.port = egr_port
765 act.queue_id = egr_queue
Rich Lane400fb9b2013-10-10 17:20:54 -0700766 actions.append(act)
Dan Talaycof6e76c02012-03-23 10:56:12 -0700767 elif egr_ports is not None:
768 for egr_port in egr_port_list:
Rich Lanee717c6e2013-03-12 10:25:50 -0700769 act = ofp.action.output()
Dan Talaycof6e76c02012-03-23 10:56:12 -0700770 act.port = egr_port
Rich Lane400fb9b2013-10-10 17:20:54 -0700771 actions.append(act)
Dan Talayco551befa2010-07-15 17:05:32 -0700772
Rich Lane9a003812012-10-04 17:17:59 -0700773 logging.debug(request.show())
Dan Talayco551befa2010-07-15 17:05:32 -0700774
775 return request
776
Jeffrey Townsendf3eae9c2012-03-28 18:23:21 -0700777def flow_msg_install(parent, request, clear_table_override=None):
Dan Talayco551befa2010-07-15 17:05:32 -0700778 """
779 Install a flow mod message in the switch
780
781 @param parent Must implement controller, assertEqual, assertTrue
782 @param request The request, all set to go
783 @param clear_table If true, clear the flow table before installing
784 """
Dan Talayco8a64e332012-03-28 14:53:20 -0700785
Rich Lane2014f9b2012-10-05 15:29:40 -0700786 clear_table = test_param_get('clear_table', default=True)
Jeffrey Townsendf3eae9c2012-03-28 18:23:21 -0700787 if(clear_table_override != None):
788 clear_table = clear_table_override
789
790 if clear_table:
Rich Lane9a003812012-10-04 17:17:59 -0700791 logging.debug("Clear flow table")
Rich Lane32bf9482013-01-03 17:26:30 -0800792 delete_all_flows(parent.controller)
Dan Talayco551befa2010-07-15 17:05:32 -0700793
Rich Lane9a003812012-10-04 17:17:59 -0700794 logging.debug("Insert flow")
Rich Lane5c3151c2013-01-03 17:15:41 -0800795 parent.controller.message_send(request)
Rich Lanee912d032012-12-22 14:28:33 -0800796
Rich Lane3a261d52013-01-03 17:45:08 -0800797 do_barrier(parent.controller)
Dan Talayco551befa2010-07-15 17:05:32 -0700798
Ed Swierk99a74de2012-08-22 06:40:54 -0700799def flow_match_test_port_pair(parent, ing_port, egr_ports, wildcards=None,
Rich Laned0478ff2013-03-11 12:46:58 -0700800 vlan_vid=-1, pkt=None, exp_pkt=None,
Rich Lanee5779d32012-10-05 17:56:04 -0700801 action_list=None):
Dan Talayco551befa2010-07-15 17:05:32 -0700802 """
803 Flow match test on single TCP packet
Dan Talaycof6e76c02012-03-23 10:56:12 -0700804 @param egr_ports A single port or list of ports
Dan Talayco551befa2010-07-15 17:05:32 -0700805
806 Run test with packet through switch from ing_port to egr_port
807 See flow_match_test for parameter descriptions
808 """
809
Ed Swierk99a74de2012-08-22 06:40:54 -0700810 if wildcards is None:
811 wildcards = required_wildcards(parent)
Rich Lane9a003812012-10-04 17:17:59 -0700812 logging.info("Pkt match test: " + str(ing_port) + " to " +
Dan Talaycof6e76c02012-03-23 10:56:12 -0700813 str(egr_ports))
Rich Laned0478ff2013-03-11 12:46:58 -0700814 logging.debug(" WC: " + hex(wildcards) + " vlan: " + str(vlan_vid))
Dan Talayco551befa2010-07-15 17:05:32 -0700815 if pkt is None:
Rich Laned0478ff2013-03-11 12:46:58 -0700816 pkt = simple_tcp_packet(dl_vlan_enable=(vlan_vid >= 0), vlan_vid=vlan_vid)
Rich Lanec41fbec2013-10-02 00:27:59 -0700817 if exp_pkt is None:
818 exp_pkt = pkt
Dan Talayco551befa2010-07-15 17:05:32 -0700819
820 request = flow_msg_create(parent, pkt, ing_port=ing_port,
Dan Talaycof6e76c02012-03-23 10:56:12 -0700821 wildcards=wildcards, egr_ports=egr_ports,
Dan Talayco551befa2010-07-15 17:05:32 -0700822 action_list=action_list)
823
824 flow_msg_install(parent, request)
825
Rich Lane9a003812012-10-04 17:17:59 -0700826 logging.debug("Send packet: " + str(ing_port) + " to " +
Dan Talaycof6e76c02012-03-23 10:56:12 -0700827 str(egr_ports))
Dan Talayco551befa2010-07-15 17:05:32 -0700828 parent.dataplane.send(ing_port, str(pkt))
829
Rich Lane8f45e2d2013-10-01 16:06:54 -0700830 exp_ports = [ing_port if port == ofp.OFPP_IN_PORT else port for port in egr_ports]
Rich Lanee4b384d2013-09-13 14:33:40 -0700831 verify_packets(parent, exp_pkt, exp_ports)
Dan Talayco551befa2010-07-15 17:05:32 -0700832
Rich Lane89725bb2012-12-03 16:23:27 -0800833def flow_match_test_pktout(parent, ing_port, egr_ports,
Rich Laned0478ff2013-03-11 12:46:58 -0700834 vlan_vid=-1, pkt=None, exp_pkt=None,
Rich Lane89725bb2012-12-03 16:23:27 -0800835 action_list=None):
836 """
837 Packet-out test on single TCP packet
838 @param egr_ports A single port or list of ports
839
840 Run test sending packet-out to egr_ports. The goal is to test the actions
841 taken on the packet, not the matching which is of course irrelevant.
842 See flow_match_test for parameter descriptions
843 """
844
845 if pkt is None:
Rich Laned0478ff2013-03-11 12:46:58 -0700846 pkt = simple_tcp_packet(dl_vlan_enable=(vlan_vid >= 0), vlan_vid=vlan_vid)
Rich Lanec41fbec2013-10-02 00:27:59 -0700847 if exp_pkt is None:
848 exp_pkt = pkt
Rich Lane89725bb2012-12-03 16:23:27 -0800849
Rich Lanee717c6e2013-03-12 10:25:50 -0700850 msg = ofp.message.packet_out()
Rich Lane89725bb2012-12-03 16:23:27 -0800851 msg.in_port = ing_port
Rich Laneea8c4722013-04-04 15:30:20 -0700852 msg.buffer_id = 0xffffffff
Rich Lane89725bb2012-12-03 16:23:27 -0800853 msg.data = str(pkt)
854 if action_list is not None:
855 for act in action_list:
Rich Lanec495d9e2013-03-08 17:43:36 -0800856 msg.actions.append(act)
Rich Lane89725bb2012-12-03 16:23:27 -0800857
858 # Set up output action
859 if egr_ports is not None:
860 for egr_port in egr_ports:
Rich Lanee717c6e2013-03-12 10:25:50 -0700861 act = ofp.action.output()
Rich Lane89725bb2012-12-03 16:23:27 -0800862 act.port = egr_port
Rich Lanec495d9e2013-03-08 17:43:36 -0800863 msg.actions.append(act)
Rich Lane89725bb2012-12-03 16:23:27 -0800864
865 logging.debug(msg.show())
Rich Lane5c3151c2013-01-03 17:15:41 -0800866 parent.controller.message_send(msg)
Rich Lane89725bb2012-12-03 16:23:27 -0800867
Rich Lane8f45e2d2013-10-01 16:06:54 -0700868 exp_ports = [ing_port if port == ofp.OFPP_IN_PORT else port for port in egr_ports]
Rich Lanee4b384d2013-09-13 14:33:40 -0700869 verify_packets(parent, exp_pkt, exp_ports)
Rich Lane89725bb2012-12-03 16:23:27 -0800870
Dan Talaycof6e76c02012-03-23 10:56:12 -0700871def get_egr_list(parent, of_ports, how_many, exclude_list=[]):
872 """
873 Generate a list of ports avoiding those in the exclude list
Rich Lane9a003812012-10-04 17:17:59 -0700874 @param parent Supplies logging
Dan Talaycof6e76c02012-03-23 10:56:12 -0700875 @param of_ports List of OF port numbers
876 @param how_many Number of ports to be added to the list
877 @param exclude_list List of ports not to be used
878 @returns An empty list if unable to find enough ports
879 """
880
Dan Talaycoc948d0b2012-03-23 12:17:54 -0700881 if how_many == 0:
882 return []
883
Dan Talaycof6e76c02012-03-23 10:56:12 -0700884 count = 0
885 egr_ports = []
886 for egr_idx in range(len(of_ports)):
887 if of_ports[egr_idx] not in exclude_list:
888 egr_ports.append(of_ports[egr_idx])
889 count += 1
890 if count >= how_many:
891 return egr_ports
Rich Lane9a003812012-10-04 17:17:59 -0700892 logging.debug("Could not generate enough egress ports for test")
Dan Talaycof6e76c02012-03-23 10:56:12 -0700893 return []
894
Rich Laned0478ff2013-03-11 12:46:58 -0700895def flow_match_test(parent, port_map, wildcards=None, vlan_vid=-1, pkt=None,
Rich Lanee5779d32012-10-05 17:56:04 -0700896 exp_pkt=None, action_list=None,
Dan Talaycoc948d0b2012-03-23 12:17:54 -0700897 max_test=0, egr_count=1, ing_port=False):
Dan Talayco551befa2010-07-15 17:05:32 -0700898 """
Rich Lane89725bb2012-12-03 16:23:27 -0800899 Run flow_match_test_port_pair on all port pairs and packet-out
Dan Talayco551befa2010-07-15 17:05:32 -0700900
901 @param max_test If > 0 no more than this number of tests are executed.
902 @param parent Must implement controller, dataplane, assertTrue, assertEqual
Rich Lane9a003812012-10-04 17:17:59 -0700903 and logging
Dan Talayco551befa2010-07-15 17:05:32 -0700904 @param pkt If not None, use this packet for ingress
905 @param wildcards For flow match entry
Rich Laned0478ff2013-03-11 12:46:58 -0700906 @param vlan_vid If not -1, and pkt is None, create a pkt w/ VLAN tag
Dan Talayco551befa2010-07-15 17:05:32 -0700907 @param exp_pkt If not None, use this as the expected output pkt; els use pkt
908 @param action_list Additional actions to add to flow mod
Dan Talaycocfa172f2012-03-23 12:03:00 -0700909 @param egr_count Number of egress ports; -1 means get from config w/ dflt 2
Dan Talayco551befa2010-07-15 17:05:32 -0700910 """
Ed Swierk99a74de2012-08-22 06:40:54 -0700911 if wildcards is None:
912 wildcards = required_wildcards(parent)
Dan Talayco551befa2010-07-15 17:05:32 -0700913 of_ports = port_map.keys()
914 of_ports.sort()
915 parent.assertTrue(len(of_ports) > 1, "Not enough ports for test")
916 test_count = 0
917
Dan Talaycocfa172f2012-03-23 12:03:00 -0700918 if egr_count == -1:
Rich Lane2014f9b2012-10-05 15:29:40 -0700919 egr_count = test_param_get('egr_count', default=2)
Dan Talaycocfa172f2012-03-23 12:03:00 -0700920
Dan Talayco551befa2010-07-15 17:05:32 -0700921 for ing_idx in range(len(of_ports)):
922 ingress_port = of_ports[ing_idx]
Dan Talaycof6e76c02012-03-23 10:56:12 -0700923 egr_ports = get_egr_list(parent, of_ports, egr_count,
924 exclude_list=[ingress_port])
Dan Talaycoc948d0b2012-03-23 12:17:54 -0700925 if ing_port:
Rich Lanee717c6e2013-03-12 10:25:50 -0700926 egr_ports.append(ofp.OFPP_IN_PORT)
Dan Talaycof6e76c02012-03-23 10:56:12 -0700927 if len(egr_ports) == 0:
928 parent.assertTrue(0, "Failed to generate egress port list")
929
930 flow_match_test_port_pair(parent, ingress_port, egr_ports,
Rich Laned0478ff2013-03-11 12:46:58 -0700931 wildcards=wildcards, vlan_vid=vlan_vid,
Dan Talaycof6e76c02012-03-23 10:56:12 -0700932 pkt=pkt, exp_pkt=exp_pkt,
Rich Lanee5779d32012-10-05 17:56:04 -0700933 action_list=action_list)
Dan Talaycof6e76c02012-03-23 10:56:12 -0700934 test_count += 1
935 if (max_test > 0) and (test_count > max_test):
Rich Lane9a003812012-10-04 17:17:59 -0700936 logging.info("Ran " + str(test_count) + " tests; exiting")
Rich Lane89725bb2012-12-03 16:23:27 -0800937 break
938
Ed Swierk38eea082013-01-02 19:46:20 -0800939 if not test_param_get('pktout_actions', default=True):
940 return
Rich Lane89725bb2012-12-03 16:23:27 -0800941
942 ingress_port = of_ports[0]
943 egr_ports = get_egr_list(parent, of_ports, egr_count,
944 exclude_list=[ingress_port])
945 if ing_port:
Rich Lanee717c6e2013-03-12 10:25:50 -0700946 egr_ports.append(ofp.OFPP_IN_PORT)
Rich Lane89725bb2012-12-03 16:23:27 -0800947 flow_match_test_pktout(parent, ingress_port, egr_ports,
Rich Laned0478ff2013-03-11 12:46:58 -0700948 vlan_vid=vlan_vid,
Rich Lane89725bb2012-12-03 16:23:27 -0800949 pkt=pkt, exp_pkt=exp_pkt,
950 action_list=action_list)
Dan Talayco551befa2010-07-15 17:05:32 -0700951
Rich Lane2014f9b2012-10-05 15:29:40 -0700952def test_param_get(key, default=None):
Dan Talayco4b2bee62010-07-20 14:10:05 -0700953 """
954 Return value passed via test-params if present
955
Dan Talayco4b2bee62010-07-20 14:10:05 -0700956 @param key The lookup key
957 @param default Default value to use if not found
958
959 If the pair 'key=val' appeared in the string passed to --test-params
960 on the command line, return val (as interpreted by exec). Otherwise
961 return default value.
Dan Talaycof6e76c02012-03-23 10:56:12 -0700962
963 WARNING: TEST PARAMETERS MUST BE PYTHON IDENTIFIERS;
964 eg egr_count, not egr-count.
Dan Talayco4b2bee62010-07-20 14:10:05 -0700965 """
966 try:
Rich Lanecd97d3d2013-01-07 18:50:06 -0800967 exec oftest.config["test_params"]
Dan Talayco4b2bee62010-07-20 14:10:05 -0700968 except:
969 return default
970
Dan Talayco4b2bee62010-07-20 14:10:05 -0700971 try:
Rich Lanefdec0fb2013-08-09 18:01:05 -0700972 return eval(str(key))
Dan Talayco4b2bee62010-07-20 14:10:05 -0700973 except:
974 return default
975
976def action_generate(parent, field_to_mod, mod_field_vals):
977 """
978 Create an action to modify the field indicated in field_to_mod
979
980 @param parent Must implement, assertTrue
981 @param field_to_mod The field to modify as a string name
982 @param mod_field_vals Hash of values to use for modified values
983 """
984
985 act = None
986
987 if field_to_mod in ['pktlen']:
988 return None
989
Rich Laned0478ff2013-03-11 12:46:58 -0700990 if field_to_mod == 'eth_dst':
Rich Lanee717c6e2013-03-12 10:25:50 -0700991 act = ofp.action.set_dl_dst()
Rich Lanef6883512013-03-11 17:00:09 -0700992 act.dl_addr = oftest.parse.parse_mac(mod_field_vals['eth_dst'])
Rich Laned0478ff2013-03-11 12:46:58 -0700993 elif field_to_mod == 'eth_src':
Rich Lanee717c6e2013-03-12 10:25:50 -0700994 act = ofp.action.set_dl_src()
Rich Lanef6883512013-03-11 17:00:09 -0700995 act.dl_addr = oftest.parse.parse_mac(mod_field_vals['eth_src'])
Dan Talayco4b2bee62010-07-20 14:10:05 -0700996 elif field_to_mod == 'dl_vlan_enable':
997 if not mod_field_vals['dl_vlan_enable']: # Strip VLAN tag
Rich Lanee717c6e2013-03-12 10:25:50 -0700998 act = ofp.action.strip_vlan()
Rich Laned0478ff2013-03-11 12:46:58 -0700999 # Add VLAN tag is handled by vlan_vid field
Dan Talayco4b2bee62010-07-20 14:10:05 -07001000 # Will return None in this case
Rich Laned0478ff2013-03-11 12:46:58 -07001001 elif field_to_mod == 'vlan_vid':
Rich Lanee717c6e2013-03-12 10:25:50 -07001002 act = ofp.action.set_vlan_vid()
Rich Laned0478ff2013-03-11 12:46:58 -07001003 act.vlan_vid = mod_field_vals['vlan_vid']
1004 elif field_to_mod == 'vlan_pcp':
Rich Lanee717c6e2013-03-12 10:25:50 -07001005 act = ofp.action.set_vlan_pcp()
Rich Laned0478ff2013-03-11 12:46:58 -07001006 act.vlan_pcp = mod_field_vals['vlan_pcp']
Dan Talayco4b2bee62010-07-20 14:10:05 -07001007 elif field_to_mod == 'ip_src':
Rich Lanee717c6e2013-03-12 10:25:50 -07001008 act = ofp.action.set_nw_src()
Rich Lanef6883512013-03-11 17:00:09 -07001009 act.nw_addr = oftest.parse.parse_ip(mod_field_vals['ip_src'])
Dan Talayco4b2bee62010-07-20 14:10:05 -07001010 elif field_to_mod == 'ip_dst':
Rich Lanee717c6e2013-03-12 10:25:50 -07001011 act = ofp.action.set_nw_dst()
Rich Lanef6883512013-03-11 17:00:09 -07001012 act.nw_addr = oftest.parse.parse_ip(mod_field_vals['ip_dst'])
Dan Talayco4b2bee62010-07-20 14:10:05 -07001013 elif field_to_mod == 'ip_tos':
Rich Lanee717c6e2013-03-12 10:25:50 -07001014 act = ofp.action.set_nw_tos()
Dan Talayco4b2bee62010-07-20 14:10:05 -07001015 act.nw_tos = mod_field_vals['ip_tos']
1016 elif field_to_mod == 'tcp_sport':
Rich Lanee717c6e2013-03-12 10:25:50 -07001017 act = ofp.action.set_tp_src()
Dan Talayco4b2bee62010-07-20 14:10:05 -07001018 act.tp_port = mod_field_vals['tcp_sport']
1019 elif field_to_mod == 'tcp_dport':
Rich Lanee717c6e2013-03-12 10:25:50 -07001020 act = ofp.action.set_tp_dst()
Dan Talayco4b2bee62010-07-20 14:10:05 -07001021 act.tp_port = mod_field_vals['tcp_dport']
Rich Lane110e0e32012-10-26 16:21:46 -07001022 elif field_to_mod == 'udp_sport':
Rich Lanee717c6e2013-03-12 10:25:50 -07001023 act = ofp.action.set_tp_src()
Rich Lane110e0e32012-10-26 16:21:46 -07001024 act.tp_port = mod_field_vals['udp_sport']
1025 elif field_to_mod == 'udp_dport':
Rich Lanee717c6e2013-03-12 10:25:50 -07001026 act = ofp.action.set_tp_dst()
Rich Lane110e0e32012-10-26 16:21:46 -07001027 act.tp_port = mod_field_vals['udp_dport']
Dan Talayco4b2bee62010-07-20 14:10:05 -07001028 else:
1029 parent.assertTrue(0, "Unknown field to modify: " + str(field_to_mod))
1030
1031 return act
1032
1033def pkt_action_setup(parent, start_field_vals={}, mod_field_vals={},
Rich Lane110e0e32012-10-26 16:21:46 -07001034 mod_fields=[], tp="tcp", check_test_params=False):
Dan Talayco4b2bee62010-07-20 14:10:05 -07001035 """
1036 Set up the ingress and expected packet and action list for a test
1037
Rich Lane2014f9b2012-10-05 15:29:40 -07001038 @param parent Must implement assertTrue
Dan Talayco4b2bee62010-07-20 14:10:05 -07001039 @param start_field_values Field values to use for ingress packet (optional)
1040 @param mod_field_values Field values to use for modified packet (optional)
1041 @param mod_fields The list of fields to be modified by the switch in the test.
1042 @params check_test_params If True, will check the parameters vid, add_vlan
1043 and strip_vlan from the command line.
1044
1045 Returns a triple: pkt-to-send, expected-pkt, action-list
1046 """
1047
1048 new_actions = []
1049
Dan Talayco4b2bee62010-07-20 14:10:05 -07001050 base_pkt_params = {}
1051 base_pkt_params['pktlen'] = 100
Rich Laned0478ff2013-03-11 12:46:58 -07001052 base_pkt_params['eth_dst'] = '00:DE:F0:12:34:56'
1053 base_pkt_params['eth_src'] = '00:23:45:67:89:AB'
Dan Talayco4b2bee62010-07-20 14:10:05 -07001054 base_pkt_params['dl_vlan_enable'] = False
Rich Laned0478ff2013-03-11 12:46:58 -07001055 base_pkt_params['vlan_vid'] = 2
1056 base_pkt_params['vlan_pcp'] = 0
Dan Talayco4b2bee62010-07-20 14:10:05 -07001057 base_pkt_params['ip_src'] = '192.168.0.1'
1058 base_pkt_params['ip_dst'] = '192.168.0.2'
1059 base_pkt_params['ip_tos'] = 0
Rich Lane110e0e32012-10-26 16:21:46 -07001060 if tp == "tcp":
1061 base_pkt_params['tcp_sport'] = 1234
1062 base_pkt_params['tcp_dport'] = 80
1063 elif tp == "udp":
1064 base_pkt_params['udp_sport'] = 1234
1065 base_pkt_params['udp_dport'] = 80
Dan Talayco4b2bee62010-07-20 14:10:05 -07001066 for keyname in start_field_vals.keys():
1067 base_pkt_params[keyname] = start_field_vals[keyname]
1068
1069 mod_pkt_params = {}
1070 mod_pkt_params['pktlen'] = 100
Rich Laned0478ff2013-03-11 12:46:58 -07001071 mod_pkt_params['eth_dst'] = '00:21:0F:ED:CB:A9'
1072 mod_pkt_params['eth_src'] = '00:ED:CB:A9:87:65'
Dan Talayco4b2bee62010-07-20 14:10:05 -07001073 mod_pkt_params['dl_vlan_enable'] = False
Rich Laned0478ff2013-03-11 12:46:58 -07001074 mod_pkt_params['vlan_vid'] = 3
1075 mod_pkt_params['vlan_pcp'] = 7
Dan Talayco4b2bee62010-07-20 14:10:05 -07001076 mod_pkt_params['ip_src'] = '10.20.30.40'
1077 mod_pkt_params['ip_dst'] = '50.60.70.80'
1078 mod_pkt_params['ip_tos'] = 0xf0
Rich Lane110e0e32012-10-26 16:21:46 -07001079 if tp == "tcp":
1080 mod_pkt_params['tcp_sport'] = 4321
1081 mod_pkt_params['tcp_dport'] = 8765
1082 elif tp == "udp":
1083 mod_pkt_params['udp_sport'] = 4321
1084 mod_pkt_params['udp_dport'] = 8765
Dan Talayco4b2bee62010-07-20 14:10:05 -07001085 for keyname in mod_field_vals.keys():
1086 mod_pkt_params[keyname] = mod_field_vals[keyname]
1087
1088 # Check for test param modifications
1089 strip = False
1090 if check_test_params:
Rich Lane2014f9b2012-10-05 15:29:40 -07001091 add_vlan = test_param_get('add_vlan')
1092 strip_vlan = test_param_get('strip_vlan')
1093 vid = test_param_get('vid')
Dan Talayco4b2bee62010-07-20 14:10:05 -07001094
1095 if add_vlan and strip_vlan:
1096 parent.assertTrue(0, "Add and strip VLAN both specified")
1097
1098 if vid:
1099 base_pkt_params['dl_vlan_enable'] = True
Rich Laned0478ff2013-03-11 12:46:58 -07001100 base_pkt_params['vlan_vid'] = vid
1101 if 'vlan_vid' in mod_fields:
1102 mod_pkt_params['vlan_vid'] = vid + 1
Dan Talayco4b2bee62010-07-20 14:10:05 -07001103
1104 if add_vlan:
1105 base_pkt_params['dl_vlan_enable'] = False
1106 mod_pkt_params['dl_vlan_enable'] = True
1107 mod_pkt_params['pktlen'] = base_pkt_params['pktlen'] + 4
1108 mod_fields.append('pktlen')
1109 mod_fields.append('dl_vlan_enable')
Rich Laned0478ff2013-03-11 12:46:58 -07001110 if 'vlan_vid' not in mod_fields:
1111 mod_fields.append('vlan_vid')
Dan Talayco4b2bee62010-07-20 14:10:05 -07001112 elif strip_vlan:
1113 base_pkt_params['dl_vlan_enable'] = True
1114 mod_pkt_params['dl_vlan_enable'] = False
1115 mod_pkt_params['pktlen'] = base_pkt_params['pktlen'] - 4
1116 mod_fields.append('dl_vlan_enable')
1117 mod_fields.append('pktlen')
1118
Rich Lane110e0e32012-10-26 16:21:46 -07001119 if tp == "tcp":
1120 packet_builder = simple_tcp_packet
1121 elif tp == "udp":
1122 packet_builder = simple_udp_packet
1123 else:
1124 raise NotImplementedError("unknown transport protocol %s" % tp)
1125
Dan Talayco4b2bee62010-07-20 14:10:05 -07001126 # Build the ingress packet
Rich Lane110e0e32012-10-26 16:21:46 -07001127 ingress_pkt = packet_builder(**base_pkt_params)
Dan Talayco4b2bee62010-07-20 14:10:05 -07001128
1129 # Build the expected packet, modifying the indicated fields
1130 for item in mod_fields:
1131 base_pkt_params[item] = mod_pkt_params[item]
1132 act = action_generate(parent, item, mod_pkt_params)
1133 if act:
1134 new_actions.append(act)
1135
Rich Lane110e0e32012-10-26 16:21:46 -07001136 expected_pkt = packet_builder(**base_pkt_params)
Dan Talayco4b2bee62010-07-20 14:10:05 -07001137
1138 return (ingress_pkt, expected_pkt, new_actions)
Dan Talayco677c0b72011-08-23 22:53:38 -07001139
1140# Generate a simple "drop" flow mod
1141# If in_band is true, then only drop from first test port
1142def flow_mod_gen(port_map, in_band):
Rich Lanee717c6e2013-03-12 10:25:50 -07001143 request = ofp.message.flow_add()
1144 request.match.wildcards = ofp.OFPFW_ALL
Dan Talayco677c0b72011-08-23 22:53:38 -07001145 if in_band:
Rich Lanee717c6e2013-03-12 10:25:50 -07001146 request.match.wildcards = ofp.OFPFW_ALL - ofp.OFPFW_IN_PORT
Dan Talayco677c0b72011-08-23 22:53:38 -07001147 for of_port, ifname in port_map.items(): # Grab first port
1148 break
1149 request.match.in_port = of_port
1150 request.buffer_id = 0xffffffff
1151 return request
Dan Talaycoba3745c2010-07-21 21:51:08 -07001152
1153def skip_message_emit(parent, s):
1154 """
1155 Print out a 'skipped' message to stderr
1156
1157 @param s The string to print out to the log file
Dan Talaycoba3745c2010-07-21 21:51:08 -07001158 """
1159 global skipped_test_count
1160
1161 skipped_test_count += 1
Rich Lane9a003812012-10-04 17:17:59 -07001162 logging.info("Skipping: " + s)
Dan Talayco2940fdd2013-02-06 15:01:35 -08001163 if oftest.config["debug"] < logging.WARNING:
Dan Talaycoba3745c2010-07-21 21:51:08 -07001164 sys.stderr.write("(skipped) ")
1165 else:
1166 sys.stderr.write("(S)")
Dan Talayco677c0b72011-08-23 22:53:38 -07001167
Dan Talayco8a64e332012-03-28 14:53:20 -07001168
1169def all_stats_get(parent):
1170 """
1171 Get the aggregate stats for all flows in the table
1172 @param parent Test instance with controller connection and assert
1173 @returns dict with keys flows, packets, bytes, active (flows),
1174 lookups, matched
1175 """
Rich Lanee717c6e2013-03-12 10:25:50 -07001176 stat_req = ofp.message.aggregate_stats_request()
1177 stat_req.match = ofp.match()
1178 stat_req.match.wildcards = ofp.OFPFW_ALL
Dan Talayco8a64e332012-03-28 14:53:20 -07001179 stat_req.table_id = 0xff
Rich Lanee717c6e2013-03-12 10:25:50 -07001180 stat_req.out_port = ofp.OFPP_NONE
Dan Talayco8a64e332012-03-28 14:53:20 -07001181
1182 rv = {}
1183
Rich Lanec8aaa3e2012-07-26 19:28:02 -07001184 (reply, pkt) = parent.controller.transact(stat_req)
Rich Lane5fd6faf2013-03-11 13:30:20 -07001185 parent.assertTrue(len(reply.entries) == 1, "Did not receive flow stats reply")
Dan Talayco8a64e332012-03-28 14:53:20 -07001186
Rich Lane5fd6faf2013-03-11 13:30:20 -07001187 for obj in reply.entries:
Dan Talayco8a64e332012-03-28 14:53:20 -07001188 (rv["flows"], rv["packets"], rv["bytes"]) = (obj.flow_count,
1189 obj.packet_count, obj.byte_count)
1190 break
1191
Rich Lanee717c6e2013-03-12 10:25:50 -07001192 request = ofp.message.table_stats_request()
Rich Lanec8aaa3e2012-07-26 19:28:02 -07001193 (reply , pkt) = parent.controller.transact(request)
Dan Talayco8a64e332012-03-28 14:53:20 -07001194
1195
1196 (rv["active"], rv["lookups"], rv["matched"]) = (0,0,0)
Rich Lane5fd6faf2013-03-11 13:30:20 -07001197 for obj in reply.entries:
Dan Talayco8a64e332012-03-28 14:53:20 -07001198 rv["active"] += obj.active_count
1199 rv["lookups"] += obj.lookup_count
1200 rv["matched"] += obj.matched_count
1201
1202 return rv
Dan Talayco2baf8b52012-03-30 09:55:42 -07001203
Rich Lane7744e112013-01-11 17:23:57 -08001204_import_blacklist.add('FILTER')
Dan Talayco2baf8b52012-03-30 09:55:42 -07001205FILTER=''.join([(len(repr(chr(x)))==3) and chr(x) or '.'
1206 for x in range(256)])
1207
1208def hex_dump_buffer(src, length=16):
1209 """
1210 Convert src to a hex dump string and return the string
1211 @param src The source buffer
1212 @param length The number of bytes shown in each line
1213 @returns A string showing the hex dump
1214 """
Dan Talaycoc516fa02012-04-12 22:28:43 -07001215 result = ["\n"]
Dan Talayco2baf8b52012-03-30 09:55:42 -07001216 for i in xrange(0, len(src), length):
1217 chars = src[i:i+length]
1218 hex = ' '.join(["%02x" % ord(x) for x in chars])
1219 printable = ''.join(["%s" % ((ord(x) <= 127 and
1220 FILTER[ord(x)]) or '.') for x in chars])
1221 result.append("%04x %-*s %s\n" % (i, length*3, hex, printable))
1222 return ''.join(result)
1223
1224def format_packet(pkt):
1225 return "Packet length %d \n%s" % (len(str(pkt)),
1226 hex_dump_buffer(str(pkt)))
Rich Lane5d7e89a2012-10-26 16:43:13 -07001227
1228def inspect_packet(pkt):
1229 """
1230 Wrapper around scapy's show() method.
1231 @returns A string showing the dissected packet.
1232 """
1233 from cStringIO import StringIO
1234 out = None
1235 backup = sys.stdout
1236 try:
Rich Lanefdec0fb2013-08-09 18:01:05 -07001237 tmp = StringIO()
1238 sys.stdout = tmp
Rich Lane5d7e89a2012-10-26 16:43:13 -07001239 pkt.show2()
Rich Lanefdec0fb2013-08-09 18:01:05 -07001240 out = tmp.getvalue()
1241 tmp.close()
Rich Lane5d7e89a2012-10-26 16:43:13 -07001242 finally:
1243 sys.stdout = backup
1244 return out
Rich Lane0a4f6372013-01-02 14:40:22 -08001245
1246def nonstandard(cls):
1247 """
Rich Lanecc45b8e2013-01-02 15:55:02 -08001248 Testcase decorator that marks the test as being non-standard.
1249 These tests are not automatically added to the "standard" group.
Rich Lane0a4f6372013-01-02 14:40:22 -08001250 """
Rich Lanecc45b8e2013-01-02 15:55:02 -08001251 cls._nonstandard = True
Rich Lane0a4f6372013-01-02 14:40:22 -08001252 return cls
1253
1254def disabled(cls):
1255 """
Rich Lanecc45b8e2013-01-02 15:55:02 -08001256 Testcase decorator that marks the test as being disabled.
1257 These tests are not automatically added to the "standard" group or
1258 their module's group.
Rich Lane0a4f6372013-01-02 14:40:22 -08001259 """
Rich Lanecc45b8e2013-01-02 15:55:02 -08001260 cls._disabled = True
Rich Lane0a4f6372013-01-02 14:40:22 -08001261 return cls
Rich Lane97e99652013-01-02 17:23:20 -08001262
1263def group(name):
1264 """
1265 Testcase decorator that adds the test to a group.
1266 """
1267 def fn(cls):
1268 if not hasattr(cls, "_groups"):
1269 cls._groups = []
1270 cls._groups.append(name)
1271 return cls
1272 return fn
Rich Lane5a9a1922013-01-11 14:29:30 -08001273
1274def version(ver):
1275 """
1276 Testcase decorator that specifies which versions of OpenFlow the test
1277 supports. The default is 1.0+. This decorator may only be used once.
1278
1279 Supported syntax:
1280 1.0 -> 1.0
1281 1.0,1.2,1.3 -> 1.0, 1.2, 1.3
1282 1.0+ -> 1.0, 1.1, 1.2, 1.3
1283 """
1284 versions = parse_version(ver)
1285 def fn(cls):
1286 cls._versions = versions
1287 return cls
1288 return fn
1289
1290def parse_version(ver):
1291 allowed_versions = ["1.0", "1.1", "1.2", "1.3"]
1292 if re.match("^1\.\d+$", ver):
1293 versions = set([ver])
1294 elif re.match("^(1\.\d+)\+$", ver):
1295 if not ver[:-1] in allowed_versions:
1296 raise ValueError("invalid OpenFlow version %s" % ver[:-1])
1297 versions = set()
1298 if ver != "1.1+": versions.add("1.0")
1299 if ver != "1.2+": versions.add("1.1")
1300 if ver != "1.3+": versions.add("1.2")
1301 versions.add("1.3")
1302 else:
1303 versions = set(ver.split(','))
1304
1305 for version in versions:
1306 if not version in allowed_versions:
1307 raise ValueError("invalid OpenFlow version %s" % version)
1308
1309 return versions
1310
1311assert(parse_version("1.0") == set(["1.0"]))
1312assert(parse_version("1.0,1.2,1.3") == set(["1.0", "1.2", "1.3"]))
1313assert(parse_version("1.0+") == set(["1.0", "1.1", "1.2", "1.3"]))
Rich Lane7744e112013-01-11 17:23:57 -08001314
Rich Laneae3428c2013-03-07 14:37:42 -08001315def get_stats(test, req):
1316 """
1317 Retrieve a list of stats entries. Handles OFPSF_REPLY_MORE.
1318 """
Rich Lane609194f2013-10-21 06:17:37 -07001319 msgtype = ofp.OFPT_STATS_REPLY
1320 more_flag = ofp.OFPSF_REPLY_MORE
Rich Laneae3428c2013-03-07 14:37:42 -08001321 stats = []
1322 reply, _ = test.controller.transact(req)
1323 test.assertTrue(reply is not None, "No response to stats request")
Rich Lane34c68d52013-10-11 10:38:21 -07001324 test.assertEquals(reply.type, msgtype, "Response had unexpected message type")
Rich Lane5fd6faf2013-03-11 13:30:20 -07001325 stats.extend(reply.entries)
Rich Lanebd56ed62013-07-10 15:49:44 -07001326 while reply.flags & more_flag != 0:
Rich Lane34c68d52013-10-11 10:38:21 -07001327 reply, pkt = test.controller.poll(exp_msg=msgtype)
Rich Laneae3428c2013-03-07 14:37:42 -08001328 test.assertTrue(reply is not None, "No response to stats request")
Rich Lane5fd6faf2013-03-11 13:30:20 -07001329 stats.extend(reply.entries)
Rich Laneae3428c2013-03-07 14:37:42 -08001330 return stats
1331
Rich Lanebd56ed62013-07-10 15:49:44 -07001332def get_flow_stats(test, match, table_id=None,
1333 out_port=None, out_group=None,
1334 cookie=0, cookie_mask=0):
Rich Laneae3428c2013-03-07 14:37:42 -08001335 """
1336 Retrieve a list of flow stats entries.
1337 """
Rich Lanebd56ed62013-07-10 15:49:44 -07001338
1339 if table_id == None:
1340 if ofp.OFP_VERSION <= 2:
1341 table_id = 0xff
1342 else:
1343 table_id = ofp.OFPTT_ALL
1344
Rich Lanef3bc48c2013-05-03 17:39:35 -07001345 if out_port == None:
Rich Lanebd56ed62013-07-10 15:49:44 -07001346 if ofp.OFP_VERSION == 1:
1347 out_port = ofp.OFPP_NONE
1348 else:
1349 out_port = ofp.OFPP_ANY
1350
1351 if out_group == None:
1352 if ofp.OFP_VERSION > 1:
1353 out_group = ofp.OFPP_ANY
1354
Rich Lanee717c6e2013-03-12 10:25:50 -07001355 req = ofp.message.flow_stats_request(match=match,
Rich Lanebd56ed62013-07-10 15:49:44 -07001356 table_id=table_id,
1357 out_port=out_port)
1358 if ofp.OFP_VERSION > 1:
1359 req.out_group = out_group
1360 req.cookie = cookie
1361 req.cookie_mask = cookie_mask
1362
Rich Laneae3428c2013-03-07 14:37:42 -08001363 return get_stats(test, req)
1364
Rich Lane968b6192013-03-07 15:34:43 -08001365def get_port_stats(test, port_no):
1366 """
1367 Retrieve a list of port stats entries.
1368 """
Rich Lanee717c6e2013-03-12 10:25:50 -07001369 req = ofp.message.port_stats_request(port_no=port_no)
Rich Lane968b6192013-03-07 15:34:43 -08001370 return get_stats(test, req)
1371
Rich Lane6a334922013-03-07 16:14:52 -08001372def get_queue_stats(test, port_no, queue_id):
1373 """
1374 Retrieve a list of queue stats entries.
1375 """
Rich Lanee717c6e2013-03-12 10:25:50 -07001376 req = ofp.message.queue_stats_request(port_no=port_no, queue_id=queue_id)
Rich Lane6a334922013-03-07 16:14:52 -08001377 return get_stats(test, req)
1378
Rich Laneae3428c2013-03-07 14:37:42 -08001379def verify_flow_stats(test, match, table_id=0xff,
Rich Lanef3bc48c2013-05-03 17:39:35 -07001380 out_port=None,
Rich Laneae3428c2013-03-07 14:37:42 -08001381 initial=[],
1382 pkts=None, bytes=None):
1383 """
1384 Verify that flow stats changed as expected.
1385
1386 Optionally takes an 'initial' list of stats entries, as returned by
1387 get_flow_stats(). If 'initial' is not given the counters are assumed to
1388 begin at 0.
1389 """
Rich Lanef3bc48c2013-05-03 17:39:35 -07001390 if out_port == None:
1391 out_port = ofp.OFPP_NONE
1392
Rich Laneae3428c2013-03-07 14:37:42 -08001393 def accumulate(stats):
1394 pkts_acc = bytes_acc = 0
1395 for stat in stats:
1396 pkts_acc += stat.packet_count
1397 bytes_acc += stat.byte_count
1398 return (pkts_acc, bytes_acc)
1399
1400 pkts_before, bytes_before = accumulate(initial)
1401
1402 # Wait 10s for counters to update
1403 pkt_diff = byte_diff = None
1404 for i in range(0, 100):
1405 stats = get_flow_stats(test, match, table_id=table_id, out_port=out_port)
1406 pkts_after, bytes_after = accumulate(stats)
1407 pkt_diff = pkts_after - pkts_before
1408 byte_diff = bytes_after - bytes_before
1409 if (pkts == None or pkt_diff >= pkts) and \
1410 (bytes == None or byte_diff >= bytes):
1411 break
Dan Talayco53724732013-03-08 23:54:02 -08001412 time.sleep(0.1)
Rich Laneae3428c2013-03-07 14:37:42 -08001413
1414 if pkts != None:
1415 test.assertEquals(pkt_diff, pkts, "Flow packet counter not updated properly (expected increase of %d, got increase of %d)" % (pkts, pkt_diff))
1416
1417 if bytes != None:
Rich Lane53b96812013-03-07 16:54:50 -08001418 test.assertTrue(byte_diff >= bytes and byte_diff <= bytes*1.1,
1419 "Flow byte counter not updated properly (expected increase of %d, got increase of %d)" % (bytes, byte_diff))
Rich Laneae3428c2013-03-07 14:37:42 -08001420
Rich Lane968b6192013-03-07 15:34:43 -08001421def verify_port_stats(test, port,
1422 initial=[],
1423 tx_pkts=None, rx_pkts=None,
1424 tx_bytes=None, rx_bytes=None):
1425 """
1426 Verify that port stats changed as expected.
1427
1428 Optionally takes an 'initial' list of stats entries, as returned by
1429 get_port_stats(). If 'initial' is not given the counters are assumed to
1430 begin at 0.
1431 """
1432 def accumulate(stats):
1433 tx_pkts_acc = rx_pkts_acc = tx_bytes_acc = rx_bytes_acc = 0
1434 for stat in stats:
1435 tx_pkts_acc += stat.tx_packets
1436 rx_pkts_acc += stat.rx_packets
1437 tx_bytes_acc += stat.tx_bytes
1438 rx_bytes_acc += stat.rx_bytes
1439 return (tx_pkts_acc, rx_pkts_acc, tx_bytes_acc, rx_bytes_acc)
1440
1441 tx_pkts_before, rx_pkts_before, \
1442 tx_bytes_before, rx_bytes_before = accumulate(initial)
1443
1444 # Wait 10s for counters to update
1445 for i in range(0, 100):
1446 stats = get_port_stats(test, port)
1447 tx_pkts_after, rx_pkts_after, \
1448 tx_bytes_after, rx_bytes_after = accumulate(stats)
1449 tx_pkts_diff = tx_pkts_after - tx_pkts_before
1450 rx_pkts_diff = rx_pkts_after - rx_pkts_before
1451 tx_bytes_diff = tx_bytes_after - tx_bytes_before
1452 rx_bytes_diff = rx_bytes_after - rx_bytes_before
1453 if (tx_pkts == None or tx_pkts == tx_pkts_diff) and \
1454 (rx_pkts == None or rx_pkts == rx_pkts_diff) and \
Rich Lane53b96812013-03-07 16:54:50 -08001455 (tx_bytes == None or tx_bytes <= tx_bytes_diff) and \
1456 (rx_bytes == None or rx_bytes <= rx_bytes_diff):
Rich Lane968b6192013-03-07 15:34:43 -08001457 break
1458 time.sleep(0.1)
1459
1460 if (tx_pkts != None):
1461 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))
1462 if (rx_pkts != None):
1463 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))
1464 if (tx_bytes != None):
Rich Lane53b96812013-03-07 16:54:50 -08001465 test.assertTrue(tx_bytes_diff >= tx_bytes and tx_bytes_diff <= tx_bytes*1.1,
1466 "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 -08001467 if (rx_bytes != None):
Rich Lane53b96812013-03-07 16:54:50 -08001468 test.assertTrue(rx_bytes_diff >= rx_bytes and rx_bytes_diff <= rx_bytes*1.1,
1469 "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 -08001470
Rich Lane6a334922013-03-07 16:14:52 -08001471def verify_queue_stats(test, port_no, queue_id,
1472 initial=[],
1473 pkts=None, bytes=None):
1474 """
1475 Verify that queue stats changed as expected.
1476
1477 Optionally takes an 'initial' list of stats entries, as returned by
1478 get_queue_stats(). If 'initial' is not given the counters are assumed to
1479 begin at 0.
1480 """
1481 def accumulate(stats):
1482 pkts_acc = bytes_acc = 0
1483 for stat in stats:
1484 pkts_acc += stat.tx_packets
1485 bytes_acc += stat.tx_bytes
1486 return (pkts_acc, bytes_acc)
1487
1488 pkts_before, bytes_before = accumulate(initial)
1489
1490 # Wait 10s for counters to update
1491 pkt_diff = byte_diff = None
1492 for i in range(0, 100):
1493 stats = get_queue_stats(test, port_no, queue_id)
1494 pkts_after, bytes_after = accumulate(stats)
1495 pkt_diff = pkts_after - pkts_before
1496 byte_diff = bytes_after - bytes_before
1497 if (pkts == None or pkt_diff >= pkts) and \
1498 (bytes == None or byte_diff >= bytes):
1499 break
Dan Talayco53724732013-03-08 23:54:02 -08001500 time.sleep(0.1)
Rich Lane6a334922013-03-07 16:14:52 -08001501
1502 if pkts != None:
1503 test.assertEquals(pkt_diff, pkts, "Queue packet counter not updated properly (expected increase of %d, got increase of %d)" % (pkts, pkt_diff))
1504
1505 if bytes != None:
Rich Lane53b96812013-03-07 16:54:50 -08001506 test.assertTrue(byte_diff >= bytes and byte_diff <= bytes*1.1,
1507 "Queue byte counter not updated properly (expected increase of %d, got increase of %d)" % (bytes, byte_diff))
Rich Laneae3428c2013-03-07 14:37:42 -08001508
Rich Lane4c504f32013-06-07 17:24:14 -07001509def packet_in_match(msg, data, in_port=None, reason=None):
1510 """
1511 Check whether the packet_in message 'msg' has fields matching 'data',
1512 'in_port', and 'reason'.
1513
1514 This function handles truncated packet_in data. The 'in_port' and 'reason'
1515 parameters are optional.
1516
1517 @param msg packet_in message
1518 @param data Expected packet_in data
1519 @param in_port Expected packet_in in_port, or None
1520 @param reason Expected packet_in reason, or None
1521 """
1522
Rich Lanec0d26dd2013-07-10 12:46:03 -07001523 if ofp.OFP_VERSION <= 2:
1524 pkt_in_port = msg.in_port
1525 else:
1526 oxms = { type(oxm): oxm for oxm in msg.match.oxm_list }
1527 if ofp.oxm.in_port in oxms:
1528 pkt_in_port = oxms[ofp.oxm.in_port].value
1529 else:
1530 logging.warn("Missing in_port in packet-in message")
1531 pkt_in_port = None
1532
1533 if in_port != None and in_port != pkt_in_port:
Rich Lane9f2f17e2013-09-13 13:19:37 -07001534 logging.debug("Incorrect packet_in in_port (expected %d, received %d)", in_port, pkt_in_port)
Rich Lane4c504f32013-06-07 17:24:14 -07001535 return False
1536
Rich Lanec0d26dd2013-07-10 12:46:03 -07001537 if reason != None and reason != msg.reason:
Rich Lane4c504f32013-06-07 17:24:14 -07001538 logging.debug("Incorrect packet_in reason (expected %d, received %d)", reason, msg.reason)
1539 return False
1540
1541 # Check that one of the packets is a prefix of the other.
1542 # The received packet may be either truncated or padded, but not both.
1543 # (Some of the padding may be truncated but that's irrelevant). We
1544 # need to check that the smaller packet is a prefix of the larger one.
1545 # Note that this check succeeds if the switch sends a zero-length
1546 # packet-in.
1547 compare_len = min(len(msg.data), len(data))
1548 if data[:compare_len] != msg.data[:compare_len]:
1549 logging.debug("Incorrect packet_in data")
1550 logging.debug("Expected %s" % format_packet(data[:compare_len]))
1551 logging.debug("Received %s" % format_packet(msg.data[:compare_len]))
1552 return False
1553
1554 return True
1555
1556def verify_packet_in(test, data, in_port, reason, controller=None):
1557 """
1558 Assert that the controller receives a packet_in message matching data 'data'
1559 from port 'in_port' with reason 'reason'. Does not trigger the packet_in
1560 itself, that's up to the test case.
1561
1562 @param test Instance of base_tests.SimpleProtocol
1563 @param pkt String to expect as the packet_in data
1564 @param in_port OpenFlow port number to expect as the packet_in in_port
1565 @param reason One of OFPR_* to expect as the packet_in reason
1566 @param controller Controller instance, defaults to test.controller
1567 @returns The received packet-in message
1568 """
1569
1570 if controller == None:
1571 controller = test.controller
1572
1573 end_time = time.time() + oftest.ofutils.default_timeout
1574
1575 while True:
1576 msg, _ = controller.poll(ofp.OFPT_PACKET_IN, end_time - time.time())
1577 if not msg:
1578 # Timeout
1579 break
1580 elif packet_in_match(msg, data, in_port, reason):
1581 # Found a matching message
1582 break
1583
1584 test.assertTrue(msg is not None, 'Packet in message not received on port %d' % in_port)
1585 return msg
1586
1587def verify_no_packet_in(test, data, in_port, controller=None):
1588 """
1589 Assert that the controller does not receive a packet_in message matching
1590 data 'data' from port 'in_port'.
1591
1592 @param test Instance of base_tests.SimpleProtocol
1593 @param pkt String to expect as the packet_in data
1594 @param in_port OpenFlow port number to expect as the packet_in in_port
1595 @param controller Controller instance, defaults to test.controller
1596 """
1597
1598 if controller == None:
1599 controller = test.controller
1600
1601 # Negative test, need to wait a short amount of time before checking we
1602 # didn't receive the message.
Rich Lane48f6aed2014-03-23 15:51:02 -07001603 time.sleep(oftest.ofutils.default_negative_timeout)
Rich Lane4c504f32013-06-07 17:24:14 -07001604
1605 # Check every packet_in queued in the controller
1606 while True:
1607 msg, _ = controller.poll(ofp.OFPT_PACKET_IN, timeout=0)
1608 if msg == None:
1609 # No more queued packet_in messages
1610 break
1611 elif packet_in_match(msg, data, in_port, None):
1612 # Found a matching message
1613 break
1614
Rich Lane82c882d2013-08-09 17:13:52 -07001615 if in_port == None:
1616 test.assertTrue(msg == None, "Did not expect a packet-in message on any port")
1617 else:
1618 test.assertTrue(msg == None, "Did not expect a packet-in message on port %d" % in_port)
Rich Lane4c504f32013-06-07 17:24:14 -07001619
Rich Lane045db072013-08-06 13:16:30 -07001620def openflow_ports(num=None):
1621 """
1622 Return a list of 'num' OpenFlow port numbers
1623
1624 If 'num' is None, return all available ports. Otherwise, limit the length
1625 of the result to 'num' and raise an exception if not enough ports are
1626 available.
1627 """
1628 ports = sorted(oftest.config["port_map"].keys())
1629 if num != None and len(ports) < num:
1630 raise Exception("test requires %d ports but only %d are available" % (num, len(ports)))
1631 return ports[:num]
1632
Rich Lanee4b384d2013-09-13 14:33:40 -07001633def verify_packet(test, pkt, ofport):
1634 """
1635 Check that an expected packet is received
1636 """
1637 logging.debug("Checking for pkt on port %r", ofport)
1638 (rcv_port, rcv_pkt, pkt_time) = test.dataplane.poll(port_number=ofport, exp_pkt=str(pkt))
1639 test.assertTrue(rcv_pkt != None, "Did not receive pkt on %r" % ofport)
1640
1641def verify_no_packet(test, pkt, ofport):
1642 """
1643 Check that a particular packet is not received
1644 """
1645 logging.debug("Negative check for pkt on port %r", ofport)
Rich Lane48f6aed2014-03-23 15:51:02 -07001646 (rcv_port, rcv_pkt, pkt_time) = \
1647 test.dataplane.poll(
1648 port_number=ofport, exp_pkt=str(pkt),
1649 timeout=oftest.ofutils.default_negative_timeout)
Rich Lanee4b384d2013-09-13 14:33:40 -07001650 test.assertTrue(rcv_pkt == None, "Received packet on %r" % ofport)
1651
1652def verify_no_other_packets(test):
1653 """
1654 Check that no unexpected packets are received
1655
1656 This is a no-op if the --relax option is in effect.
1657 """
1658 if oftest.config["relax"]:
1659 return
1660 logging.debug("Checking for unexpected packets on all ports")
Rich Lane48f6aed2014-03-23 15:51:02 -07001661 (rcv_port, rcv_pkt, pkt_time) = test.dataplane.poll(timeout=oftest.ofutils.default_negative_timeout)
Rich Lanee4b384d2013-09-13 14:33:40 -07001662 if rcv_pkt != None:
1663 logging.debug("Received unexpected packet on port %r: %s", rcv_port, format_packet(rcv_pkt))
1664 test.assertTrue(rcv_pkt == None, "Unexpected packet on port %r" % rcv_port)
1665
1666def verify_packets(test, pkt, ofports):
1667 """
1668 Check that a packet is received on certain ports
1669
1670 Also verifies that the packet is not received on any other ports, and that no
1671 other packets are received (unless --relax is in effect).
1672
1673 This covers the common and simplest cases for checking dataplane outputs.
1674 For more complex usage, like multiple different packets being output, or
1675 multiple packets on the same port, use the primitive verify_packet,
1676 verify_no_packet, and verify_no_other_packets functions directly.
1677 """
1678 pkt = str(pkt)
1679 for ofport in openflow_ports():
1680 if ofport in ofports:
1681 verify_packet(test, pkt, ofport)
1682 else:
1683 verify_no_packet(test, pkt, ofport)
1684 verify_no_other_packets(test)
1685
Rich Lane12d04592013-10-10 17:21:07 -07001686def verify_no_errors(ctrl):
1687 error, _ = ctrl.poll(ofp.OFPT_ERROR, 0)
1688 if error:
1689 raise AssertionError("unexpected error type=%d code=%d" % (error.err_type, error.code))
Rich Lanee4b384d2013-09-13 14:33:40 -07001690
Jonathan Stoutfcee3142014-01-28 15:46:22 -05001691def verify_capability(test, capability):
1692 """
Jonathan Stout073642d2014-02-04 13:41:48 -05001693 Return True if DUT supports the specified capability.
Jonathan Stoutfcee3142014-01-28 15:46:22 -05001694
1695 @param test Instance of base_tests.SimpleProtocol
1696 @param capability One of ofp_capabilities.
1697 """
1698 logging.info("Verifing that capability code is valid.")
1699 test.assertIn(capability, ofp.const.ofp_capabilities_map,
1700 "Capability code %d does not exist." % capability)
1701 capability_str = ofp.const.ofp_capabilities_map[capability]
1702
1703 logging.info(("Sending features_request to test if capability "
Jonathan Stout97e458a2014-01-28 16:08:04 -05001704 "%s is supported."), capability_str)
Jonathan Stoutfcee3142014-01-28 15:46:22 -05001705 req = ofp.message.features_request()
1706 res, raw = test.controller.transact(req)
1707 test.assertIsNotNone(res, "Did not receive a response from the DUT.")
1708 test.assertEqual(res.type, ofp.OFPT_FEATURES_REPLY,
1709 ("Unexpected packet type %d received in response to "
1710 "OFPT_FEATURES_REQUEST") % res.type)
Jonathan Stout641167f2014-02-04 12:07:10 -05001711 logging.info("Received features_reply.")
Jonathan Stoutfcee3142014-01-28 15:46:22 -05001712
Jonathan Stout641167f2014-02-04 12:07:10 -05001713 if (res.capabilities & capability) > 0:
1714 logging.info("Switch capabilities bitmask claims to support %s",
1715 capability_str)
1716 return True, res.capabilities
1717 else:
1718 logging.info("Capabilities bitmask does not support %s.",
1719 capability_str)
1720 return False, res.capabilities
Jonathan Stoutfcee3142014-01-28 15:46:22 -05001721
Rich Lane7744e112013-01-11 17:23:57 -08001722__all__ = list(set(locals()) - _import_blacklist)