blob: 5b2e36518160da0479d471a1e57f9214f9027519 [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
579 # Wait this long for packets that we don't expect to receive.
580 # 100ms is (rarely) too short for positive tests on slow
581 # switches but is definitely not too short for a negative test.
582 negative_timeout = 0.1
583
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700584 exp_pkt_arg = None
Rich Lanecd97d3d2013-01-07 18:50:06 -0800585 if oftest.config["relax"]:
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700586 exp_pkt_arg = pkt
587
Dan Talayco92c99122010-06-03 13:53:18 -0700588 for ofport in yes_ports:
Rich Lane9a003812012-10-04 17:17:59 -0700589 logging.debug("Checking for pkt on port " + str(ofport))
Ken Chiang1bf01602012-04-04 10:48:23 -0700590 (rcv_port, rcv_pkt, pkt_time) = dp.poll(
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700591 port_number=ofport, exp_pkt=exp_pkt_arg)
Dan Talayco92c99122010-06-03 13:53:18 -0700592 assert_if.assertTrue(rcv_pkt is not None,
593 "Did not receive pkt on " + str(ofport))
Rich Lanecd97d3d2013-01-07 18:50:06 -0800594 if not oftest.dataplane.match_exp_pkt(pkt, rcv_pkt):
Rich Lane3c266832013-01-29 18:29:15 -0800595 logging.debug("Expected %s" % format_packet(pkt))
596 logging.debug("Received %s" % format_packet(rcv_pkt))
Rich Lanecd97d3d2013-01-07 18:50:06 -0800597 assert_if.assertTrue(oftest.dataplane.match_exp_pkt(pkt, rcv_pkt),
Rich Lane3c266832013-01-29 18:29:15 -0800598 "Received packet does not match expected packet " +
Ken Chiang1bf01602012-04-04 10:48:23 -0700599 "on port " + str(ofport))
Dan Talayco73f84012012-10-02 09:23:18 -0700600 if len(no_ports) > 0:
Rich Lane91765672012-12-06 16:33:04 -0800601 time.sleep(negative_timeout)
Dan Talayco92c99122010-06-03 13:53:18 -0700602 for ofport in no_ports:
Rich Lane9a003812012-10-04 17:17:59 -0700603 logging.debug("Negative check for pkt on port " + str(ofport))
Ken Chiang1bf01602012-04-04 10:48:23 -0700604 (rcv_port, rcv_pkt, pkt_time) = dp.poll(
Rich Lane91765672012-12-06 16:33:04 -0800605 port_number=ofport, timeout=0, exp_pkt=exp_pkt_arg)
Dan Talayco92c99122010-06-03 13:53:18 -0700606 assert_if.assertTrue(rcv_pkt is None,
607 "Unexpected pkt on port " + str(ofport))
Dan Talayco551befa2010-07-15 17:05:32 -0700608
609
Dan Talaycoc948d0b2012-03-23 12:17:54 -0700610def receive_pkt_verify(parent, egr_ports, exp_pkt, ing_port):
Dan Talayco551befa2010-07-15 17:05:32 -0700611 """
612 Receive a packet and verify it matches an expected value
Dan Talaycof6e76c02012-03-23 10:56:12 -0700613 @param egr_port A single port or list of ports
Dan Talayco551befa2010-07-15 17:05:32 -0700614
615 parent must implement dataplane, assertTrue and assertEqual
Rich Lanee4b384d2013-09-13 14:33:40 -0700616
617 DEPRECATED in favor in verify_packets
Dan Talayco551befa2010-07-15 17:05:32 -0700618 """
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700619 exp_pkt_arg = None
Rich Lanecd97d3d2013-01-07 18:50:06 -0800620 if oftest.config["relax"]:
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700621 exp_pkt_arg = exp_pkt
622
Dan Talaycof6e76c02012-03-23 10:56:12 -0700623 if type(egr_ports) == type([]):
624 egr_port_list = egr_ports
625 else:
626 egr_port_list = [egr_ports]
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700627
Dan Talaycof6e76c02012-03-23 10:56:12 -0700628 # Expect a packet from each port on egr port list
629 for egr_port in egr_port_list:
Dan Talaycod8ae7582012-03-23 12:24:56 -0700630 check_port = egr_port
Rich Lanee717c6e2013-03-12 10:25:50 -0700631 if egr_port == ofp.OFPP_IN_PORT:
Dan Talaycod8ae7582012-03-23 12:24:56 -0700632 check_port = ing_port
Dan Talaycof6e76c02012-03-23 10:56:12 -0700633 (rcv_port, rcv_pkt, pkt_time) = parent.dataplane.poll(
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700634 port_number=check_port, exp_pkt=exp_pkt_arg)
Dan Talayco551befa2010-07-15 17:05:32 -0700635
Dan Talaycof6e76c02012-03-23 10:56:12 -0700636 if rcv_pkt is None:
Rich Lane9a003812012-10-04 17:17:59 -0700637 logging.error("ERROR: No packet received from " +
Dan Talaycod8ae7582012-03-23 12:24:56 -0700638 str(check_port))
Dan Talayco551befa2010-07-15 17:05:32 -0700639
Dan Talaycof6e76c02012-03-23 10:56:12 -0700640 parent.assertTrue(rcv_pkt is not None,
Dan Talaycod8ae7582012-03-23 12:24:56 -0700641 "Did not receive packet port " + str(check_port))
Rich Lane9a003812012-10-04 17:17:59 -0700642 logging.debug("Packet len " + str(len(rcv_pkt)) + " in on " +
Dan Talaycof6e76c02012-03-23 10:56:12 -0700643 str(rcv_port))
644
645 if str(exp_pkt) != str(rcv_pkt):
Rich Lane9a003812012-10-04 17:17:59 -0700646 logging.error("ERROR: Packet match failed.")
647 logging.debug("Expected len " + str(len(exp_pkt)) + ": "
Dan Talaycof6e76c02012-03-23 10:56:12 -0700648 + str(exp_pkt).encode('hex'))
Rich Lane9a003812012-10-04 17:17:59 -0700649 logging.debug("Received len " + str(len(rcv_pkt)) + ": "
Dan Talaycof6e76c02012-03-23 10:56:12 -0700650 + str(rcv_pkt).encode('hex'))
Rich Lane5d7e89a2012-10-26 16:43:13 -0700651 logging.debug("Expected packet: " + inspect_packet(scapy.Ether(str(exp_pkt))))
652 logging.debug("Received packet: " + inspect_packet(scapy.Ether(str(rcv_pkt))))
Dan Talaycof6e76c02012-03-23 10:56:12 -0700653 parent.assertEqual(str(exp_pkt), str(rcv_pkt),
Dan Talaycod8ae7582012-03-23 12:24:56 -0700654 "Packet match error on port " + str(check_port))
Dan Talaycof6e76c02012-03-23 10:56:12 -0700655
Dan Talayco551befa2010-07-15 17:05:32 -0700656def match_verify(parent, req_match, res_match):
657 """
658 Verify flow matches agree; if they disagree, report where
659
660 parent must implement assertEqual
661 Use str() to ensure content is compared and not pointers
662 """
663
664 parent.assertEqual(req_match.wildcards, res_match.wildcards,
665 'Match failed: wildcards: ' + hex(req_match.wildcards) +
666 " != " + hex(res_match.wildcards))
667 parent.assertEqual(req_match.in_port, res_match.in_port,
668 'Match failed: in_port: ' + str(req_match.in_port) +
669 " != " + str(res_match.in_port))
Rich Laned0478ff2013-03-11 12:46:58 -0700670 parent.assertEqual(str(req_match.eth_src), str(res_match.eth_src),
671 'Match failed: eth_src: ' + str(req_match.eth_src) +
672 " != " + str(res_match.eth_src))
673 parent.assertEqual(str(req_match.eth_dst), str(res_match.eth_dst),
674 'Match failed: eth_dst: ' + str(req_match.eth_dst) +
675 " != " + str(res_match.eth_dst))
676 parent.assertEqual(req_match.vlan_vid, res_match.vlan_vid,
677 'Match failed: vlan_vid: ' + str(req_match.vlan_vid) +
678 " != " + str(res_match.vlan_vid))
679 parent.assertEqual(req_match.vlan_pcp, res_match.vlan_pcp,
680 'Match failed: vlan_pcp: ' +
681 str(req_match.vlan_pcp) + " != " +
682 str(res_match.vlan_pcp))
683 parent.assertEqual(req_match.eth_type, res_match.eth_type,
684 'Match failed: eth_type: ' + str(req_match.eth_type) +
685 " != " + str(res_match.eth_type))
Dan Talayco551befa2010-07-15 17:05:32 -0700686
Rich Lanee717c6e2013-03-12 10:25:50 -0700687 if (not(req_match.wildcards & ofp.OFPFW_DL_TYPE)
Rich Laned0478ff2013-03-11 12:46:58 -0700688 and (req_match.eth_type == IP_ETHERTYPE)):
689 parent.assertEqual(req_match.ip_dscp, res_match.ip_dscp,
690 'Match failed: ip_dscp: ' + str(req_match.ip_dscp) +
691 " != " + str(res_match.ip_dscp))
692 parent.assertEqual(req_match.ip_proto, res_match.ip_proto,
693 'Match failed: ip_proto: ' + str(req_match.ip_proto) +
694 " != " + str(res_match.ip_proto))
695 parent.assertEqual(req_match.ipv4_src, res_match.ipv4_src,
696 'Match failed: ipv4_src: ' + str(req_match.ipv4_src) +
697 " != " + str(res_match.ipv4_src))
698 parent.assertEqual(req_match.ipv4_dst, res_match.ipv4_dst,
699 'Match failed: ipv4_dst: ' + str(req_match.ipv4_dst) +
700 " != " + str(res_match.ipv4_dst))
Dan Talayco551befa2010-07-15 17:05:32 -0700701
Rich Lanee717c6e2013-03-12 10:25:50 -0700702 if (not(req_match.wildcards & ofp.OFPFW_NW_PROTO)
Rich Laned0478ff2013-03-11 12:46:58 -0700703 and ((req_match.ip_proto == TCP_PROTOCOL)
704 or (req_match.ip_proto == UDP_PROTOCOL))):
705 parent.assertEqual(req_match.tcp_src, res_match.tcp_src,
706 'Match failed: tcp_src: ' +
707 str(req_match.tcp_src) +
708 " != " + str(res_match.tcp_src))
709 parent.assertEqual(req_match.tcp_dst, res_match.tcp_dst,
710 'Match failed: tcp_dst: ' +
711 str(req_match.tcp_dst) +
712 " != " + str(res_match.tcp_dst))
Dan Talayco551befa2010-07-15 17:05:32 -0700713
Ed Swierk99a74de2012-08-22 06:40:54 -0700714def packet_to_flow_match(parent, packet):
Rich Lanef6883512013-03-11 17:00:09 -0700715 match = oftest.parse.packet_to_flow_match(packet)
Rich Laneab7476f2013-06-13 15:53:52 -0700716 if ofp.OFP_VERSION in [1, 2]:
717 match.wildcards |= required_wildcards(parent)
718 else:
719 # TODO remove incompatible OXM entries
720 pass
Ed Swierk99a74de2012-08-22 06:40:54 -0700721 return match
722
723def flow_msg_create(parent, pkt, ing_port=None, action_list=None, wildcards=None,
Dan Talaycof6e76c02012-03-23 10:56:12 -0700724 egr_ports=None, egr_queue=None, check_expire=False, in_band=False):
Dan Talayco551befa2010-07-15 17:05:32 -0700725 """
726 Create a flow message
727
728 Match on packet with given wildcards.
729 See flow_match_test for other parameter descriptoins
730 @param egr_queue if not None, make the output an enqueue action
Dan Talayco677c0b72011-08-23 22:53:38 -0700731 @param in_band if True, do not wildcard ingress port
Dan Talaycof6e76c02012-03-23 10:56:12 -0700732 @param egr_ports None (drop), single port or list of ports
Dan Talayco551befa2010-07-15 17:05:32 -0700733 """
Rich Lanef6883512013-03-11 17:00:09 -0700734 match = oftest.parse.packet_to_flow_match(pkt)
Dan Talayco551befa2010-07-15 17:05:32 -0700735 parent.assertTrue(match is not None, "Flow match from pkt failed")
Ed Swierk99a74de2012-08-22 06:40:54 -0700736 if wildcards is None:
737 wildcards = required_wildcards(parent)
Dan Talayco677c0b72011-08-23 22:53:38 -0700738 if in_band:
Rich Lanee717c6e2013-03-12 10:25:50 -0700739 wildcards &= ~ofp.OFPFW_IN_PORT
Dan Talayco551befa2010-07-15 17:05:32 -0700740 match.wildcards = wildcards
741 match.in_port = ing_port
742
Dan Talaycof6e76c02012-03-23 10:56:12 -0700743 if type(egr_ports) == type([]):
744 egr_port_list = egr_ports
745 else:
746 egr_port_list = [egr_ports]
747
Rich Lanee717c6e2013-03-12 10:25:50 -0700748 request = ofp.message.flow_add()
Dan Talayco551befa2010-07-15 17:05:32 -0700749 request.match = match
750 request.buffer_id = 0xffffffff
751 if check_expire:
Rich Lanee717c6e2013-03-12 10:25:50 -0700752 request.flags |= ofp.OFPFF_SEND_FLOW_REM
Dan Talayco551befa2010-07-15 17:05:32 -0700753 request.hard_timeout = 1
754
Rich Lane400fb9b2013-10-10 17:20:54 -0700755 if ofp.OFP_VERSION == 1:
756 actions = request.actions
757 else:
758 actions = []
759 request.instructions.append(ofp.instruction.apply_actions(actions))
760
Dan Talayco551befa2010-07-15 17:05:32 -0700761 if action_list is not None:
Rich Lane400fb9b2013-10-10 17:20:54 -0700762 actions.extend(action_list)
Dan Talayco551befa2010-07-15 17:05:32 -0700763
764 # Set up output/enqueue action if directed
765 if egr_queue is not None:
Dan Talaycof6e76c02012-03-23 10:56:12 -0700766 parent.assertTrue(egr_ports is not None, "Egress port not set")
Rich Lanee717c6e2013-03-12 10:25:50 -0700767 act = ofp.action.enqueue()
Dan Talaycof6e76c02012-03-23 10:56:12 -0700768 for egr_port in egr_port_list:
769 act.port = egr_port
770 act.queue_id = egr_queue
Rich Lane400fb9b2013-10-10 17:20:54 -0700771 actions.append(act)
Dan Talaycof6e76c02012-03-23 10:56:12 -0700772 elif egr_ports is not None:
773 for egr_port in egr_port_list:
Rich Lanee717c6e2013-03-12 10:25:50 -0700774 act = ofp.action.output()
Dan Talaycof6e76c02012-03-23 10:56:12 -0700775 act.port = egr_port
Rich Lane400fb9b2013-10-10 17:20:54 -0700776 actions.append(act)
Dan Talayco551befa2010-07-15 17:05:32 -0700777
Rich Lane9a003812012-10-04 17:17:59 -0700778 logging.debug(request.show())
Dan Talayco551befa2010-07-15 17:05:32 -0700779
780 return request
781
Jeffrey Townsendf3eae9c2012-03-28 18:23:21 -0700782def flow_msg_install(parent, request, clear_table_override=None):
Dan Talayco551befa2010-07-15 17:05:32 -0700783 """
784 Install a flow mod message in the switch
785
786 @param parent Must implement controller, assertEqual, assertTrue
787 @param request The request, all set to go
788 @param clear_table If true, clear the flow table before installing
789 """
Dan Talayco8a64e332012-03-28 14:53:20 -0700790
Rich Lane2014f9b2012-10-05 15:29:40 -0700791 clear_table = test_param_get('clear_table', default=True)
Jeffrey Townsendf3eae9c2012-03-28 18:23:21 -0700792 if(clear_table_override != None):
793 clear_table = clear_table_override
794
795 if clear_table:
Rich Lane9a003812012-10-04 17:17:59 -0700796 logging.debug("Clear flow table")
Rich Lane32bf9482013-01-03 17:26:30 -0800797 delete_all_flows(parent.controller)
Dan Talayco551befa2010-07-15 17:05:32 -0700798
Rich Lane9a003812012-10-04 17:17:59 -0700799 logging.debug("Insert flow")
Rich Lane5c3151c2013-01-03 17:15:41 -0800800 parent.controller.message_send(request)
Rich Lanee912d032012-12-22 14:28:33 -0800801
Rich Lane3a261d52013-01-03 17:45:08 -0800802 do_barrier(parent.controller)
Dan Talayco551befa2010-07-15 17:05:32 -0700803
Ed Swierk99a74de2012-08-22 06:40:54 -0700804def flow_match_test_port_pair(parent, ing_port, egr_ports, wildcards=None,
Rich Laned0478ff2013-03-11 12:46:58 -0700805 vlan_vid=-1, pkt=None, exp_pkt=None,
Rich Lanee5779d32012-10-05 17:56:04 -0700806 action_list=None):
Dan Talayco551befa2010-07-15 17:05:32 -0700807 """
808 Flow match test on single TCP packet
Dan Talaycof6e76c02012-03-23 10:56:12 -0700809 @param egr_ports A single port or list of ports
Dan Talayco551befa2010-07-15 17:05:32 -0700810
811 Run test with packet through switch from ing_port to egr_port
812 See flow_match_test for parameter descriptions
813 """
814
Ed Swierk99a74de2012-08-22 06:40:54 -0700815 if wildcards is None:
816 wildcards = required_wildcards(parent)
Rich Lane9a003812012-10-04 17:17:59 -0700817 logging.info("Pkt match test: " + str(ing_port) + " to " +
Dan Talaycof6e76c02012-03-23 10:56:12 -0700818 str(egr_ports))
Rich Laned0478ff2013-03-11 12:46:58 -0700819 logging.debug(" WC: " + hex(wildcards) + " vlan: " + str(vlan_vid))
Dan Talayco551befa2010-07-15 17:05:32 -0700820 if pkt is None:
Rich Laned0478ff2013-03-11 12:46:58 -0700821 pkt = simple_tcp_packet(dl_vlan_enable=(vlan_vid >= 0), vlan_vid=vlan_vid)
Rich Lanec41fbec2013-10-02 00:27:59 -0700822 if exp_pkt is None:
823 exp_pkt = pkt
Dan Talayco551befa2010-07-15 17:05:32 -0700824
825 request = flow_msg_create(parent, pkt, ing_port=ing_port,
Dan Talaycof6e76c02012-03-23 10:56:12 -0700826 wildcards=wildcards, egr_ports=egr_ports,
Dan Talayco551befa2010-07-15 17:05:32 -0700827 action_list=action_list)
828
829 flow_msg_install(parent, request)
830
Rich Lane9a003812012-10-04 17:17:59 -0700831 logging.debug("Send packet: " + str(ing_port) + " to " +
Dan Talaycof6e76c02012-03-23 10:56:12 -0700832 str(egr_ports))
Dan Talayco551befa2010-07-15 17:05:32 -0700833 parent.dataplane.send(ing_port, str(pkt))
834
Rich Lane8f45e2d2013-10-01 16:06:54 -0700835 exp_ports = [ing_port if port == ofp.OFPP_IN_PORT else port for port in egr_ports]
Rich Lanee4b384d2013-09-13 14:33:40 -0700836 verify_packets(parent, exp_pkt, exp_ports)
Dan Talayco551befa2010-07-15 17:05:32 -0700837
Rich Lane89725bb2012-12-03 16:23:27 -0800838def flow_match_test_pktout(parent, ing_port, egr_ports,
Rich Laned0478ff2013-03-11 12:46:58 -0700839 vlan_vid=-1, pkt=None, exp_pkt=None,
Rich Lane89725bb2012-12-03 16:23:27 -0800840 action_list=None):
841 """
842 Packet-out test on single TCP packet
843 @param egr_ports A single port or list of ports
844
845 Run test sending packet-out to egr_ports. The goal is to test the actions
846 taken on the packet, not the matching which is of course irrelevant.
847 See flow_match_test for parameter descriptions
848 """
849
850 if pkt is None:
Rich Laned0478ff2013-03-11 12:46:58 -0700851 pkt = simple_tcp_packet(dl_vlan_enable=(vlan_vid >= 0), vlan_vid=vlan_vid)
Rich Lanec41fbec2013-10-02 00:27:59 -0700852 if exp_pkt is None:
853 exp_pkt = pkt
Rich Lane89725bb2012-12-03 16:23:27 -0800854
Rich Lanee717c6e2013-03-12 10:25:50 -0700855 msg = ofp.message.packet_out()
Rich Lane89725bb2012-12-03 16:23:27 -0800856 msg.in_port = ing_port
Rich Laneea8c4722013-04-04 15:30:20 -0700857 msg.buffer_id = 0xffffffff
Rich Lane89725bb2012-12-03 16:23:27 -0800858 msg.data = str(pkt)
859 if action_list is not None:
860 for act in action_list:
Rich Lanec495d9e2013-03-08 17:43:36 -0800861 msg.actions.append(act)
Rich Lane89725bb2012-12-03 16:23:27 -0800862
863 # Set up output action
864 if egr_ports is not None:
865 for egr_port in egr_ports:
Rich Lanee717c6e2013-03-12 10:25:50 -0700866 act = ofp.action.output()
Rich Lane89725bb2012-12-03 16:23:27 -0800867 act.port = egr_port
Rich Lanec495d9e2013-03-08 17:43:36 -0800868 msg.actions.append(act)
Rich Lane89725bb2012-12-03 16:23:27 -0800869
870 logging.debug(msg.show())
Rich Lane5c3151c2013-01-03 17:15:41 -0800871 parent.controller.message_send(msg)
Rich Lane89725bb2012-12-03 16:23:27 -0800872
Rich Lane8f45e2d2013-10-01 16:06:54 -0700873 exp_ports = [ing_port if port == ofp.OFPP_IN_PORT else port for port in egr_ports]
Rich Lanee4b384d2013-09-13 14:33:40 -0700874 verify_packets(parent, exp_pkt, exp_ports)
Rich Lane89725bb2012-12-03 16:23:27 -0800875
Dan Talaycof6e76c02012-03-23 10:56:12 -0700876def get_egr_list(parent, of_ports, how_many, exclude_list=[]):
877 """
878 Generate a list of ports avoiding those in the exclude list
Rich Lane9a003812012-10-04 17:17:59 -0700879 @param parent Supplies logging
Dan Talaycof6e76c02012-03-23 10:56:12 -0700880 @param of_ports List of OF port numbers
881 @param how_many Number of ports to be added to the list
882 @param exclude_list List of ports not to be used
883 @returns An empty list if unable to find enough ports
884 """
885
Dan Talaycoc948d0b2012-03-23 12:17:54 -0700886 if how_many == 0:
887 return []
888
Dan Talaycof6e76c02012-03-23 10:56:12 -0700889 count = 0
890 egr_ports = []
891 for egr_idx in range(len(of_ports)):
892 if of_ports[egr_idx] not in exclude_list:
893 egr_ports.append(of_ports[egr_idx])
894 count += 1
895 if count >= how_many:
896 return egr_ports
Rich Lane9a003812012-10-04 17:17:59 -0700897 logging.debug("Could not generate enough egress ports for test")
Dan Talaycof6e76c02012-03-23 10:56:12 -0700898 return []
899
Rich Laned0478ff2013-03-11 12:46:58 -0700900def flow_match_test(parent, port_map, wildcards=None, vlan_vid=-1, pkt=None,
Rich Lanee5779d32012-10-05 17:56:04 -0700901 exp_pkt=None, action_list=None,
Dan Talaycoc948d0b2012-03-23 12:17:54 -0700902 max_test=0, egr_count=1, ing_port=False):
Dan Talayco551befa2010-07-15 17:05:32 -0700903 """
Rich Lane89725bb2012-12-03 16:23:27 -0800904 Run flow_match_test_port_pair on all port pairs and packet-out
Dan Talayco551befa2010-07-15 17:05:32 -0700905
906 @param max_test If > 0 no more than this number of tests are executed.
907 @param parent Must implement controller, dataplane, assertTrue, assertEqual
Rich Lane9a003812012-10-04 17:17:59 -0700908 and logging
Dan Talayco551befa2010-07-15 17:05:32 -0700909 @param pkt If not None, use this packet for ingress
910 @param wildcards For flow match entry
Rich Laned0478ff2013-03-11 12:46:58 -0700911 @param vlan_vid If not -1, and pkt is None, create a pkt w/ VLAN tag
Dan Talayco551befa2010-07-15 17:05:32 -0700912 @param exp_pkt If not None, use this as the expected output pkt; els use pkt
913 @param action_list Additional actions to add to flow mod
Dan Talaycocfa172f2012-03-23 12:03:00 -0700914 @param egr_count Number of egress ports; -1 means get from config w/ dflt 2
Dan Talayco551befa2010-07-15 17:05:32 -0700915 """
Ed Swierk99a74de2012-08-22 06:40:54 -0700916 if wildcards is None:
917 wildcards = required_wildcards(parent)
Dan Talayco551befa2010-07-15 17:05:32 -0700918 of_ports = port_map.keys()
919 of_ports.sort()
920 parent.assertTrue(len(of_ports) > 1, "Not enough ports for test")
921 test_count = 0
922
Dan Talaycocfa172f2012-03-23 12:03:00 -0700923 if egr_count == -1:
Rich Lane2014f9b2012-10-05 15:29:40 -0700924 egr_count = test_param_get('egr_count', default=2)
Dan Talaycocfa172f2012-03-23 12:03:00 -0700925
Dan Talayco551befa2010-07-15 17:05:32 -0700926 for ing_idx in range(len(of_ports)):
927 ingress_port = of_ports[ing_idx]
Dan Talaycof6e76c02012-03-23 10:56:12 -0700928 egr_ports = get_egr_list(parent, of_ports, egr_count,
929 exclude_list=[ingress_port])
Dan Talaycoc948d0b2012-03-23 12:17:54 -0700930 if ing_port:
Rich Lanee717c6e2013-03-12 10:25:50 -0700931 egr_ports.append(ofp.OFPP_IN_PORT)
Dan Talaycof6e76c02012-03-23 10:56:12 -0700932 if len(egr_ports) == 0:
933 parent.assertTrue(0, "Failed to generate egress port list")
934
935 flow_match_test_port_pair(parent, ingress_port, egr_ports,
Rich Laned0478ff2013-03-11 12:46:58 -0700936 wildcards=wildcards, vlan_vid=vlan_vid,
Dan Talaycof6e76c02012-03-23 10:56:12 -0700937 pkt=pkt, exp_pkt=exp_pkt,
Rich Lanee5779d32012-10-05 17:56:04 -0700938 action_list=action_list)
Dan Talaycof6e76c02012-03-23 10:56:12 -0700939 test_count += 1
940 if (max_test > 0) and (test_count > max_test):
Rich Lane9a003812012-10-04 17:17:59 -0700941 logging.info("Ran " + str(test_count) + " tests; exiting")
Rich Lane89725bb2012-12-03 16:23:27 -0800942 break
943
Ed Swierk38eea082013-01-02 19:46:20 -0800944 if not test_param_get('pktout_actions', default=True):
945 return
Rich Lane89725bb2012-12-03 16:23:27 -0800946
947 ingress_port = of_ports[0]
948 egr_ports = get_egr_list(parent, of_ports, egr_count,
949 exclude_list=[ingress_port])
950 if ing_port:
Rich Lanee717c6e2013-03-12 10:25:50 -0700951 egr_ports.append(ofp.OFPP_IN_PORT)
Rich Lane89725bb2012-12-03 16:23:27 -0800952 flow_match_test_pktout(parent, ingress_port, egr_ports,
Rich Laned0478ff2013-03-11 12:46:58 -0700953 vlan_vid=vlan_vid,
Rich Lane89725bb2012-12-03 16:23:27 -0800954 pkt=pkt, exp_pkt=exp_pkt,
955 action_list=action_list)
Dan Talayco551befa2010-07-15 17:05:32 -0700956
Rich Lane2014f9b2012-10-05 15:29:40 -0700957def test_param_get(key, default=None):
Dan Talayco4b2bee62010-07-20 14:10:05 -0700958 """
959 Return value passed via test-params if present
960
Dan Talayco4b2bee62010-07-20 14:10:05 -0700961 @param key The lookup key
962 @param default Default value to use if not found
963
964 If the pair 'key=val' appeared in the string passed to --test-params
965 on the command line, return val (as interpreted by exec). Otherwise
966 return default value.
Dan Talaycof6e76c02012-03-23 10:56:12 -0700967
968 WARNING: TEST PARAMETERS MUST BE PYTHON IDENTIFIERS;
969 eg egr_count, not egr-count.
Dan Talayco4b2bee62010-07-20 14:10:05 -0700970 """
971 try:
Rich Lanecd97d3d2013-01-07 18:50:06 -0800972 exec oftest.config["test_params"]
Dan Talayco4b2bee62010-07-20 14:10:05 -0700973 except:
974 return default
975
Dan Talayco4b2bee62010-07-20 14:10:05 -0700976 try:
Rich Lanefdec0fb2013-08-09 18:01:05 -0700977 return eval(str(key))
Dan Talayco4b2bee62010-07-20 14:10:05 -0700978 except:
979 return default
980
981def action_generate(parent, field_to_mod, mod_field_vals):
982 """
983 Create an action to modify the field indicated in field_to_mod
984
985 @param parent Must implement, assertTrue
986 @param field_to_mod The field to modify as a string name
987 @param mod_field_vals Hash of values to use for modified values
988 """
989
990 act = None
991
992 if field_to_mod in ['pktlen']:
993 return None
994
Rich Laned0478ff2013-03-11 12:46:58 -0700995 if field_to_mod == 'eth_dst':
Rich Lanee717c6e2013-03-12 10:25:50 -0700996 act = ofp.action.set_dl_dst()
Rich Lanef6883512013-03-11 17:00:09 -0700997 act.dl_addr = oftest.parse.parse_mac(mod_field_vals['eth_dst'])
Rich Laned0478ff2013-03-11 12:46:58 -0700998 elif field_to_mod == 'eth_src':
Rich Lanee717c6e2013-03-12 10:25:50 -0700999 act = ofp.action.set_dl_src()
Rich Lanef6883512013-03-11 17:00:09 -07001000 act.dl_addr = oftest.parse.parse_mac(mod_field_vals['eth_src'])
Dan Talayco4b2bee62010-07-20 14:10:05 -07001001 elif field_to_mod == 'dl_vlan_enable':
1002 if not mod_field_vals['dl_vlan_enable']: # Strip VLAN tag
Rich Lanee717c6e2013-03-12 10:25:50 -07001003 act = ofp.action.strip_vlan()
Rich Laned0478ff2013-03-11 12:46:58 -07001004 # Add VLAN tag is handled by vlan_vid field
Dan Talayco4b2bee62010-07-20 14:10:05 -07001005 # Will return None in this case
Rich Laned0478ff2013-03-11 12:46:58 -07001006 elif field_to_mod == 'vlan_vid':
Rich Lanee717c6e2013-03-12 10:25:50 -07001007 act = ofp.action.set_vlan_vid()
Rich Laned0478ff2013-03-11 12:46:58 -07001008 act.vlan_vid = mod_field_vals['vlan_vid']
1009 elif field_to_mod == 'vlan_pcp':
Rich Lanee717c6e2013-03-12 10:25:50 -07001010 act = ofp.action.set_vlan_pcp()
Rich Laned0478ff2013-03-11 12:46:58 -07001011 act.vlan_pcp = mod_field_vals['vlan_pcp']
Dan Talayco4b2bee62010-07-20 14:10:05 -07001012 elif field_to_mod == 'ip_src':
Rich Lanee717c6e2013-03-12 10:25:50 -07001013 act = ofp.action.set_nw_src()
Rich Lanef6883512013-03-11 17:00:09 -07001014 act.nw_addr = oftest.parse.parse_ip(mod_field_vals['ip_src'])
Dan Talayco4b2bee62010-07-20 14:10:05 -07001015 elif field_to_mod == 'ip_dst':
Rich Lanee717c6e2013-03-12 10:25:50 -07001016 act = ofp.action.set_nw_dst()
Rich Lanef6883512013-03-11 17:00:09 -07001017 act.nw_addr = oftest.parse.parse_ip(mod_field_vals['ip_dst'])
Dan Talayco4b2bee62010-07-20 14:10:05 -07001018 elif field_to_mod == 'ip_tos':
Rich Lanee717c6e2013-03-12 10:25:50 -07001019 act = ofp.action.set_nw_tos()
Dan Talayco4b2bee62010-07-20 14:10:05 -07001020 act.nw_tos = mod_field_vals['ip_tos']
1021 elif field_to_mod == 'tcp_sport':
Rich Lanee717c6e2013-03-12 10:25:50 -07001022 act = ofp.action.set_tp_src()
Dan Talayco4b2bee62010-07-20 14:10:05 -07001023 act.tp_port = mod_field_vals['tcp_sport']
1024 elif field_to_mod == 'tcp_dport':
Rich Lanee717c6e2013-03-12 10:25:50 -07001025 act = ofp.action.set_tp_dst()
Dan Talayco4b2bee62010-07-20 14:10:05 -07001026 act.tp_port = mod_field_vals['tcp_dport']
Rich Lane110e0e32012-10-26 16:21:46 -07001027 elif field_to_mod == 'udp_sport':
Rich Lanee717c6e2013-03-12 10:25:50 -07001028 act = ofp.action.set_tp_src()
Rich Lane110e0e32012-10-26 16:21:46 -07001029 act.tp_port = mod_field_vals['udp_sport']
1030 elif field_to_mod == 'udp_dport':
Rich Lanee717c6e2013-03-12 10:25:50 -07001031 act = ofp.action.set_tp_dst()
Rich Lane110e0e32012-10-26 16:21:46 -07001032 act.tp_port = mod_field_vals['udp_dport']
Dan Talayco4b2bee62010-07-20 14:10:05 -07001033 else:
1034 parent.assertTrue(0, "Unknown field to modify: " + str(field_to_mod))
1035
1036 return act
1037
1038def pkt_action_setup(parent, start_field_vals={}, mod_field_vals={},
Rich Lane110e0e32012-10-26 16:21:46 -07001039 mod_fields=[], tp="tcp", check_test_params=False):
Dan Talayco4b2bee62010-07-20 14:10:05 -07001040 """
1041 Set up the ingress and expected packet and action list for a test
1042
Rich Lane2014f9b2012-10-05 15:29:40 -07001043 @param parent Must implement assertTrue
Dan Talayco4b2bee62010-07-20 14:10:05 -07001044 @param start_field_values Field values to use for ingress packet (optional)
1045 @param mod_field_values Field values to use for modified packet (optional)
1046 @param mod_fields The list of fields to be modified by the switch in the test.
1047 @params check_test_params If True, will check the parameters vid, add_vlan
1048 and strip_vlan from the command line.
1049
1050 Returns a triple: pkt-to-send, expected-pkt, action-list
1051 """
1052
1053 new_actions = []
1054
Dan Talayco4b2bee62010-07-20 14:10:05 -07001055 base_pkt_params = {}
1056 base_pkt_params['pktlen'] = 100
Rich Laned0478ff2013-03-11 12:46:58 -07001057 base_pkt_params['eth_dst'] = '00:DE:F0:12:34:56'
1058 base_pkt_params['eth_src'] = '00:23:45:67:89:AB'
Dan Talayco4b2bee62010-07-20 14:10:05 -07001059 base_pkt_params['dl_vlan_enable'] = False
Rich Laned0478ff2013-03-11 12:46:58 -07001060 base_pkt_params['vlan_vid'] = 2
1061 base_pkt_params['vlan_pcp'] = 0
Dan Talayco4b2bee62010-07-20 14:10:05 -07001062 base_pkt_params['ip_src'] = '192.168.0.1'
1063 base_pkt_params['ip_dst'] = '192.168.0.2'
1064 base_pkt_params['ip_tos'] = 0
Rich Lane110e0e32012-10-26 16:21:46 -07001065 if tp == "tcp":
1066 base_pkt_params['tcp_sport'] = 1234
1067 base_pkt_params['tcp_dport'] = 80
1068 elif tp == "udp":
1069 base_pkt_params['udp_sport'] = 1234
1070 base_pkt_params['udp_dport'] = 80
Dan Talayco4b2bee62010-07-20 14:10:05 -07001071 for keyname in start_field_vals.keys():
1072 base_pkt_params[keyname] = start_field_vals[keyname]
1073
1074 mod_pkt_params = {}
1075 mod_pkt_params['pktlen'] = 100
Rich Laned0478ff2013-03-11 12:46:58 -07001076 mod_pkt_params['eth_dst'] = '00:21:0F:ED:CB:A9'
1077 mod_pkt_params['eth_src'] = '00:ED:CB:A9:87:65'
Dan Talayco4b2bee62010-07-20 14:10:05 -07001078 mod_pkt_params['dl_vlan_enable'] = False
Rich Laned0478ff2013-03-11 12:46:58 -07001079 mod_pkt_params['vlan_vid'] = 3
1080 mod_pkt_params['vlan_pcp'] = 7
Dan Talayco4b2bee62010-07-20 14:10:05 -07001081 mod_pkt_params['ip_src'] = '10.20.30.40'
1082 mod_pkt_params['ip_dst'] = '50.60.70.80'
1083 mod_pkt_params['ip_tos'] = 0xf0
Rich Lane110e0e32012-10-26 16:21:46 -07001084 if tp == "tcp":
1085 mod_pkt_params['tcp_sport'] = 4321
1086 mod_pkt_params['tcp_dport'] = 8765
1087 elif tp == "udp":
1088 mod_pkt_params['udp_sport'] = 4321
1089 mod_pkt_params['udp_dport'] = 8765
Dan Talayco4b2bee62010-07-20 14:10:05 -07001090 for keyname in mod_field_vals.keys():
1091 mod_pkt_params[keyname] = mod_field_vals[keyname]
1092
1093 # Check for test param modifications
1094 strip = False
1095 if check_test_params:
Rich Lane2014f9b2012-10-05 15:29:40 -07001096 add_vlan = test_param_get('add_vlan')
1097 strip_vlan = test_param_get('strip_vlan')
1098 vid = test_param_get('vid')
Dan Talayco4b2bee62010-07-20 14:10:05 -07001099
1100 if add_vlan and strip_vlan:
1101 parent.assertTrue(0, "Add and strip VLAN both specified")
1102
1103 if vid:
1104 base_pkt_params['dl_vlan_enable'] = True
Rich Laned0478ff2013-03-11 12:46:58 -07001105 base_pkt_params['vlan_vid'] = vid
1106 if 'vlan_vid' in mod_fields:
1107 mod_pkt_params['vlan_vid'] = vid + 1
Dan Talayco4b2bee62010-07-20 14:10:05 -07001108
1109 if add_vlan:
1110 base_pkt_params['dl_vlan_enable'] = False
1111 mod_pkt_params['dl_vlan_enable'] = True
1112 mod_pkt_params['pktlen'] = base_pkt_params['pktlen'] + 4
1113 mod_fields.append('pktlen')
1114 mod_fields.append('dl_vlan_enable')
Rich Laned0478ff2013-03-11 12:46:58 -07001115 if 'vlan_vid' not in mod_fields:
1116 mod_fields.append('vlan_vid')
Dan Talayco4b2bee62010-07-20 14:10:05 -07001117 elif strip_vlan:
1118 base_pkt_params['dl_vlan_enable'] = True
1119 mod_pkt_params['dl_vlan_enable'] = False
1120 mod_pkt_params['pktlen'] = base_pkt_params['pktlen'] - 4
1121 mod_fields.append('dl_vlan_enable')
1122 mod_fields.append('pktlen')
1123
Rich Lane110e0e32012-10-26 16:21:46 -07001124 if tp == "tcp":
1125 packet_builder = simple_tcp_packet
1126 elif tp == "udp":
1127 packet_builder = simple_udp_packet
1128 else:
1129 raise NotImplementedError("unknown transport protocol %s" % tp)
1130
Dan Talayco4b2bee62010-07-20 14:10:05 -07001131 # Build the ingress packet
Rich Lane110e0e32012-10-26 16:21:46 -07001132 ingress_pkt = packet_builder(**base_pkt_params)
Dan Talayco4b2bee62010-07-20 14:10:05 -07001133
1134 # Build the expected packet, modifying the indicated fields
1135 for item in mod_fields:
1136 base_pkt_params[item] = mod_pkt_params[item]
1137 act = action_generate(parent, item, mod_pkt_params)
1138 if act:
1139 new_actions.append(act)
1140
Rich Lane110e0e32012-10-26 16:21:46 -07001141 expected_pkt = packet_builder(**base_pkt_params)
Dan Talayco4b2bee62010-07-20 14:10:05 -07001142
1143 return (ingress_pkt, expected_pkt, new_actions)
Dan Talayco677c0b72011-08-23 22:53:38 -07001144
1145# Generate a simple "drop" flow mod
1146# If in_band is true, then only drop from first test port
1147def flow_mod_gen(port_map, in_band):
Rich Lanee717c6e2013-03-12 10:25:50 -07001148 request = ofp.message.flow_add()
1149 request.match.wildcards = ofp.OFPFW_ALL
Dan Talayco677c0b72011-08-23 22:53:38 -07001150 if in_band:
Rich Lanee717c6e2013-03-12 10:25:50 -07001151 request.match.wildcards = ofp.OFPFW_ALL - ofp.OFPFW_IN_PORT
Dan Talayco677c0b72011-08-23 22:53:38 -07001152 for of_port, ifname in port_map.items(): # Grab first port
1153 break
1154 request.match.in_port = of_port
1155 request.buffer_id = 0xffffffff
1156 return request
Dan Talaycoba3745c2010-07-21 21:51:08 -07001157
1158def skip_message_emit(parent, s):
1159 """
1160 Print out a 'skipped' message to stderr
1161
1162 @param s The string to print out to the log file
Dan Talaycoba3745c2010-07-21 21:51:08 -07001163 """
1164 global skipped_test_count
1165
1166 skipped_test_count += 1
Rich Lane9a003812012-10-04 17:17:59 -07001167 logging.info("Skipping: " + s)
Dan Talayco2940fdd2013-02-06 15:01:35 -08001168 if oftest.config["debug"] < logging.WARNING:
Dan Talaycoba3745c2010-07-21 21:51:08 -07001169 sys.stderr.write("(skipped) ")
1170 else:
1171 sys.stderr.write("(S)")
Dan Talayco677c0b72011-08-23 22:53:38 -07001172
Dan Talayco8a64e332012-03-28 14:53:20 -07001173
1174def all_stats_get(parent):
1175 """
1176 Get the aggregate stats for all flows in the table
1177 @param parent Test instance with controller connection and assert
1178 @returns dict with keys flows, packets, bytes, active (flows),
1179 lookups, matched
1180 """
Rich Lanee717c6e2013-03-12 10:25:50 -07001181 stat_req = ofp.message.aggregate_stats_request()
1182 stat_req.match = ofp.match()
1183 stat_req.match.wildcards = ofp.OFPFW_ALL
Dan Talayco8a64e332012-03-28 14:53:20 -07001184 stat_req.table_id = 0xff
Rich Lanee717c6e2013-03-12 10:25:50 -07001185 stat_req.out_port = ofp.OFPP_NONE
Dan Talayco8a64e332012-03-28 14:53:20 -07001186
1187 rv = {}
1188
Rich Lanec8aaa3e2012-07-26 19:28:02 -07001189 (reply, pkt) = parent.controller.transact(stat_req)
Rich Lane5fd6faf2013-03-11 13:30:20 -07001190 parent.assertTrue(len(reply.entries) == 1, "Did not receive flow stats reply")
Dan Talayco8a64e332012-03-28 14:53:20 -07001191
Rich Lane5fd6faf2013-03-11 13:30:20 -07001192 for obj in reply.entries:
Dan Talayco8a64e332012-03-28 14:53:20 -07001193 (rv["flows"], rv["packets"], rv["bytes"]) = (obj.flow_count,
1194 obj.packet_count, obj.byte_count)
1195 break
1196
Rich Lanee717c6e2013-03-12 10:25:50 -07001197 request = ofp.message.table_stats_request()
Rich Lanec8aaa3e2012-07-26 19:28:02 -07001198 (reply , pkt) = parent.controller.transact(request)
Dan Talayco8a64e332012-03-28 14:53:20 -07001199
1200
1201 (rv["active"], rv["lookups"], rv["matched"]) = (0,0,0)
Rich Lane5fd6faf2013-03-11 13:30:20 -07001202 for obj in reply.entries:
Dan Talayco8a64e332012-03-28 14:53:20 -07001203 rv["active"] += obj.active_count
1204 rv["lookups"] += obj.lookup_count
1205 rv["matched"] += obj.matched_count
1206
1207 return rv
Dan Talayco2baf8b52012-03-30 09:55:42 -07001208
Rich Lane7744e112013-01-11 17:23:57 -08001209_import_blacklist.add('FILTER')
Dan Talayco2baf8b52012-03-30 09:55:42 -07001210FILTER=''.join([(len(repr(chr(x)))==3) and chr(x) or '.'
1211 for x in range(256)])
1212
1213def hex_dump_buffer(src, length=16):
1214 """
1215 Convert src to a hex dump string and return the string
1216 @param src The source buffer
1217 @param length The number of bytes shown in each line
1218 @returns A string showing the hex dump
1219 """
Dan Talaycoc516fa02012-04-12 22:28:43 -07001220 result = ["\n"]
Dan Talayco2baf8b52012-03-30 09:55:42 -07001221 for i in xrange(0, len(src), length):
1222 chars = src[i:i+length]
1223 hex = ' '.join(["%02x" % ord(x) for x in chars])
1224 printable = ''.join(["%s" % ((ord(x) <= 127 and
1225 FILTER[ord(x)]) or '.') for x in chars])
1226 result.append("%04x %-*s %s\n" % (i, length*3, hex, printable))
1227 return ''.join(result)
1228
1229def format_packet(pkt):
1230 return "Packet length %d \n%s" % (len(str(pkt)),
1231 hex_dump_buffer(str(pkt)))
Rich Lane5d7e89a2012-10-26 16:43:13 -07001232
1233def inspect_packet(pkt):
1234 """
1235 Wrapper around scapy's show() method.
1236 @returns A string showing the dissected packet.
1237 """
1238 from cStringIO import StringIO
1239 out = None
1240 backup = sys.stdout
1241 try:
Rich Lanefdec0fb2013-08-09 18:01:05 -07001242 tmp = StringIO()
1243 sys.stdout = tmp
Rich Lane5d7e89a2012-10-26 16:43:13 -07001244 pkt.show2()
Rich Lanefdec0fb2013-08-09 18:01:05 -07001245 out = tmp.getvalue()
1246 tmp.close()
Rich Lane5d7e89a2012-10-26 16:43:13 -07001247 finally:
1248 sys.stdout = backup
1249 return out
Rich Lane0a4f6372013-01-02 14:40:22 -08001250
1251def nonstandard(cls):
1252 """
Rich Lanecc45b8e2013-01-02 15:55:02 -08001253 Testcase decorator that marks the test as being non-standard.
1254 These tests are not automatically added to the "standard" group.
Rich Lane0a4f6372013-01-02 14:40:22 -08001255 """
Rich Lanecc45b8e2013-01-02 15:55:02 -08001256 cls._nonstandard = True
Rich Lane0a4f6372013-01-02 14:40:22 -08001257 return cls
1258
1259def disabled(cls):
1260 """
Rich Lanecc45b8e2013-01-02 15:55:02 -08001261 Testcase decorator that marks the test as being disabled.
1262 These tests are not automatically added to the "standard" group or
1263 their module's group.
Rich Lane0a4f6372013-01-02 14:40:22 -08001264 """
Rich Lanecc45b8e2013-01-02 15:55:02 -08001265 cls._disabled = True
Rich Lane0a4f6372013-01-02 14:40:22 -08001266 return cls
Rich Lane97e99652013-01-02 17:23:20 -08001267
1268def group(name):
1269 """
1270 Testcase decorator that adds the test to a group.
1271 """
1272 def fn(cls):
1273 if not hasattr(cls, "_groups"):
1274 cls._groups = []
1275 cls._groups.append(name)
1276 return cls
1277 return fn
Rich Lane5a9a1922013-01-11 14:29:30 -08001278
1279def version(ver):
1280 """
1281 Testcase decorator that specifies which versions of OpenFlow the test
1282 supports. The default is 1.0+. This decorator may only be used once.
1283
1284 Supported syntax:
1285 1.0 -> 1.0
1286 1.0,1.2,1.3 -> 1.0, 1.2, 1.3
1287 1.0+ -> 1.0, 1.1, 1.2, 1.3
1288 """
1289 versions = parse_version(ver)
1290 def fn(cls):
1291 cls._versions = versions
1292 return cls
1293 return fn
1294
1295def parse_version(ver):
1296 allowed_versions = ["1.0", "1.1", "1.2", "1.3"]
1297 if re.match("^1\.\d+$", ver):
1298 versions = set([ver])
1299 elif re.match("^(1\.\d+)\+$", ver):
1300 if not ver[:-1] in allowed_versions:
1301 raise ValueError("invalid OpenFlow version %s" % ver[:-1])
1302 versions = set()
1303 if ver != "1.1+": versions.add("1.0")
1304 if ver != "1.2+": versions.add("1.1")
1305 if ver != "1.3+": versions.add("1.2")
1306 versions.add("1.3")
1307 else:
1308 versions = set(ver.split(','))
1309
1310 for version in versions:
1311 if not version in allowed_versions:
1312 raise ValueError("invalid OpenFlow version %s" % version)
1313
1314 return versions
1315
1316assert(parse_version("1.0") == set(["1.0"]))
1317assert(parse_version("1.0,1.2,1.3") == set(["1.0", "1.2", "1.3"]))
1318assert(parse_version("1.0+") == set(["1.0", "1.1", "1.2", "1.3"]))
Rich Lane7744e112013-01-11 17:23:57 -08001319
Rich Laneae3428c2013-03-07 14:37:42 -08001320def get_stats(test, req):
1321 """
1322 Retrieve a list of stats entries. Handles OFPSF_REPLY_MORE.
1323 """
Rich Lane609194f2013-10-21 06:17:37 -07001324 msgtype = ofp.OFPT_STATS_REPLY
1325 more_flag = ofp.OFPSF_REPLY_MORE
Rich Laneae3428c2013-03-07 14:37:42 -08001326 stats = []
1327 reply, _ = test.controller.transact(req)
1328 test.assertTrue(reply is not None, "No response to stats request")
Rich Lane34c68d52013-10-11 10:38:21 -07001329 test.assertEquals(reply.type, msgtype, "Response had unexpected message type")
Rich Lane5fd6faf2013-03-11 13:30:20 -07001330 stats.extend(reply.entries)
Rich Lanebd56ed62013-07-10 15:49:44 -07001331 while reply.flags & more_flag != 0:
Rich Lane34c68d52013-10-11 10:38:21 -07001332 reply, pkt = test.controller.poll(exp_msg=msgtype)
Rich Laneae3428c2013-03-07 14:37:42 -08001333 test.assertTrue(reply is not None, "No response to stats request")
Rich Lane5fd6faf2013-03-11 13:30:20 -07001334 stats.extend(reply.entries)
Rich Laneae3428c2013-03-07 14:37:42 -08001335 return stats
1336
Rich Lanebd56ed62013-07-10 15:49:44 -07001337def get_flow_stats(test, match, table_id=None,
1338 out_port=None, out_group=None,
1339 cookie=0, cookie_mask=0):
Rich Laneae3428c2013-03-07 14:37:42 -08001340 """
1341 Retrieve a list of flow stats entries.
1342 """
Rich Lanebd56ed62013-07-10 15:49:44 -07001343
1344 if table_id == None:
1345 if ofp.OFP_VERSION <= 2:
1346 table_id = 0xff
1347 else:
1348 table_id = ofp.OFPTT_ALL
1349
Rich Lanef3bc48c2013-05-03 17:39:35 -07001350 if out_port == None:
Rich Lanebd56ed62013-07-10 15:49:44 -07001351 if ofp.OFP_VERSION == 1:
1352 out_port = ofp.OFPP_NONE
1353 else:
1354 out_port = ofp.OFPP_ANY
1355
1356 if out_group == None:
1357 if ofp.OFP_VERSION > 1:
1358 out_group = ofp.OFPP_ANY
1359
Rich Lanee717c6e2013-03-12 10:25:50 -07001360 req = ofp.message.flow_stats_request(match=match,
Rich Lanebd56ed62013-07-10 15:49:44 -07001361 table_id=table_id,
1362 out_port=out_port)
1363 if ofp.OFP_VERSION > 1:
1364 req.out_group = out_group
1365 req.cookie = cookie
1366 req.cookie_mask = cookie_mask
1367
Rich Laneae3428c2013-03-07 14:37:42 -08001368 return get_stats(test, req)
1369
Rich Lane968b6192013-03-07 15:34:43 -08001370def get_port_stats(test, port_no):
1371 """
1372 Retrieve a list of port stats entries.
1373 """
Rich Lanee717c6e2013-03-12 10:25:50 -07001374 req = ofp.message.port_stats_request(port_no=port_no)
Rich Lane968b6192013-03-07 15:34:43 -08001375 return get_stats(test, req)
1376
Rich Lane6a334922013-03-07 16:14:52 -08001377def get_queue_stats(test, port_no, queue_id):
1378 """
1379 Retrieve a list of queue stats entries.
1380 """
Rich Lanee717c6e2013-03-12 10:25:50 -07001381 req = ofp.message.queue_stats_request(port_no=port_no, queue_id=queue_id)
Rich Lane6a334922013-03-07 16:14:52 -08001382 return get_stats(test, req)
1383
Rich Laneae3428c2013-03-07 14:37:42 -08001384def verify_flow_stats(test, match, table_id=0xff,
Rich Lanef3bc48c2013-05-03 17:39:35 -07001385 out_port=None,
Rich Laneae3428c2013-03-07 14:37:42 -08001386 initial=[],
1387 pkts=None, bytes=None):
1388 """
1389 Verify that flow stats changed as expected.
1390
1391 Optionally takes an 'initial' list of stats entries, as returned by
1392 get_flow_stats(). If 'initial' is not given the counters are assumed to
1393 begin at 0.
1394 """
Rich Lanef3bc48c2013-05-03 17:39:35 -07001395 if out_port == None:
1396 out_port = ofp.OFPP_NONE
1397
Rich Laneae3428c2013-03-07 14:37:42 -08001398 def accumulate(stats):
1399 pkts_acc = bytes_acc = 0
1400 for stat in stats:
1401 pkts_acc += stat.packet_count
1402 bytes_acc += stat.byte_count
1403 return (pkts_acc, bytes_acc)
1404
1405 pkts_before, bytes_before = accumulate(initial)
1406
1407 # Wait 10s for counters to update
1408 pkt_diff = byte_diff = None
1409 for i in range(0, 100):
1410 stats = get_flow_stats(test, match, table_id=table_id, out_port=out_port)
1411 pkts_after, bytes_after = accumulate(stats)
1412 pkt_diff = pkts_after - pkts_before
1413 byte_diff = bytes_after - bytes_before
1414 if (pkts == None or pkt_diff >= pkts) and \
1415 (bytes == None or byte_diff >= bytes):
1416 break
Dan Talayco53724732013-03-08 23:54:02 -08001417 time.sleep(0.1)
Rich Laneae3428c2013-03-07 14:37:42 -08001418
1419 if pkts != None:
1420 test.assertEquals(pkt_diff, pkts, "Flow packet counter not updated properly (expected increase of %d, got increase of %d)" % (pkts, pkt_diff))
1421
1422 if bytes != None:
Rich Lane53b96812013-03-07 16:54:50 -08001423 test.assertTrue(byte_diff >= bytes and byte_diff <= bytes*1.1,
1424 "Flow byte counter not updated properly (expected increase of %d, got increase of %d)" % (bytes, byte_diff))
Rich Laneae3428c2013-03-07 14:37:42 -08001425
Rich Lane968b6192013-03-07 15:34:43 -08001426def verify_port_stats(test, port,
1427 initial=[],
1428 tx_pkts=None, rx_pkts=None,
1429 tx_bytes=None, rx_bytes=None):
1430 """
1431 Verify that port stats changed as expected.
1432
1433 Optionally takes an 'initial' list of stats entries, as returned by
1434 get_port_stats(). If 'initial' is not given the counters are assumed to
1435 begin at 0.
1436 """
1437 def accumulate(stats):
1438 tx_pkts_acc = rx_pkts_acc = tx_bytes_acc = rx_bytes_acc = 0
1439 for stat in stats:
1440 tx_pkts_acc += stat.tx_packets
1441 rx_pkts_acc += stat.rx_packets
1442 tx_bytes_acc += stat.tx_bytes
1443 rx_bytes_acc += stat.rx_bytes
1444 return (tx_pkts_acc, rx_pkts_acc, tx_bytes_acc, rx_bytes_acc)
1445
1446 tx_pkts_before, rx_pkts_before, \
1447 tx_bytes_before, rx_bytes_before = accumulate(initial)
1448
1449 # Wait 10s for counters to update
1450 for i in range(0, 100):
1451 stats = get_port_stats(test, port)
1452 tx_pkts_after, rx_pkts_after, \
1453 tx_bytes_after, rx_bytes_after = accumulate(stats)
1454 tx_pkts_diff = tx_pkts_after - tx_pkts_before
1455 rx_pkts_diff = rx_pkts_after - rx_pkts_before
1456 tx_bytes_diff = tx_bytes_after - tx_bytes_before
1457 rx_bytes_diff = rx_bytes_after - rx_bytes_before
1458 if (tx_pkts == None or tx_pkts == tx_pkts_diff) and \
1459 (rx_pkts == None or rx_pkts == rx_pkts_diff) and \
Rich Lane53b96812013-03-07 16:54:50 -08001460 (tx_bytes == None or tx_bytes <= tx_bytes_diff) and \
1461 (rx_bytes == None or rx_bytes <= rx_bytes_diff):
Rich Lane968b6192013-03-07 15:34:43 -08001462 break
1463 time.sleep(0.1)
1464
1465 if (tx_pkts != None):
1466 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))
1467 if (rx_pkts != None):
1468 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))
1469 if (tx_bytes != None):
Rich Lane53b96812013-03-07 16:54:50 -08001470 test.assertTrue(tx_bytes_diff >= tx_bytes and tx_bytes_diff <= tx_bytes*1.1,
1471 "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 -08001472 if (rx_bytes != None):
Rich Lane53b96812013-03-07 16:54:50 -08001473 test.assertTrue(rx_bytes_diff >= rx_bytes and rx_bytes_diff <= rx_bytes*1.1,
1474 "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 -08001475
Rich Lane6a334922013-03-07 16:14:52 -08001476def verify_queue_stats(test, port_no, queue_id,
1477 initial=[],
1478 pkts=None, bytes=None):
1479 """
1480 Verify that queue stats changed as expected.
1481
1482 Optionally takes an 'initial' list of stats entries, as returned by
1483 get_queue_stats(). If 'initial' is not given the counters are assumed to
1484 begin at 0.
1485 """
1486 def accumulate(stats):
1487 pkts_acc = bytes_acc = 0
1488 for stat in stats:
1489 pkts_acc += stat.tx_packets
1490 bytes_acc += stat.tx_bytes
1491 return (pkts_acc, bytes_acc)
1492
1493 pkts_before, bytes_before = accumulate(initial)
1494
1495 # Wait 10s for counters to update
1496 pkt_diff = byte_diff = None
1497 for i in range(0, 100):
1498 stats = get_queue_stats(test, port_no, queue_id)
1499 pkts_after, bytes_after = accumulate(stats)
1500 pkt_diff = pkts_after - pkts_before
1501 byte_diff = bytes_after - bytes_before
1502 if (pkts == None or pkt_diff >= pkts) and \
1503 (bytes == None or byte_diff >= bytes):
1504 break
Dan Talayco53724732013-03-08 23:54:02 -08001505 time.sleep(0.1)
Rich Lane6a334922013-03-07 16:14:52 -08001506
1507 if pkts != None:
1508 test.assertEquals(pkt_diff, pkts, "Queue packet counter not updated properly (expected increase of %d, got increase of %d)" % (pkts, pkt_diff))
1509
1510 if bytes != None:
Rich Lane53b96812013-03-07 16:54:50 -08001511 test.assertTrue(byte_diff >= bytes and byte_diff <= bytes*1.1,
1512 "Queue byte counter not updated properly (expected increase of %d, got increase of %d)" % (bytes, byte_diff))
Rich Laneae3428c2013-03-07 14:37:42 -08001513
Rich Lane4c504f32013-06-07 17:24:14 -07001514def packet_in_match(msg, data, in_port=None, reason=None):
1515 """
1516 Check whether the packet_in message 'msg' has fields matching 'data',
1517 'in_port', and 'reason'.
1518
1519 This function handles truncated packet_in data. The 'in_port' and 'reason'
1520 parameters are optional.
1521
1522 @param msg packet_in message
1523 @param data Expected packet_in data
1524 @param in_port Expected packet_in in_port, or None
1525 @param reason Expected packet_in reason, or None
1526 """
1527
Rich Lanec0d26dd2013-07-10 12:46:03 -07001528 if ofp.OFP_VERSION <= 2:
1529 pkt_in_port = msg.in_port
1530 else:
1531 oxms = { type(oxm): oxm for oxm in msg.match.oxm_list }
1532 if ofp.oxm.in_port in oxms:
1533 pkt_in_port = oxms[ofp.oxm.in_port].value
1534 else:
1535 logging.warn("Missing in_port in packet-in message")
1536 pkt_in_port = None
1537
1538 if in_port != None and in_port != pkt_in_port:
Rich Lane9f2f17e2013-09-13 13:19:37 -07001539 logging.debug("Incorrect packet_in in_port (expected %d, received %d)", in_port, pkt_in_port)
Rich Lane4c504f32013-06-07 17:24:14 -07001540 return False
1541
Rich Lanec0d26dd2013-07-10 12:46:03 -07001542 if reason != None and reason != msg.reason:
Rich Lane4c504f32013-06-07 17:24:14 -07001543 logging.debug("Incorrect packet_in reason (expected %d, received %d)", reason, msg.reason)
1544 return False
1545
1546 # Check that one of the packets is a prefix of the other.
1547 # The received packet may be either truncated or padded, but not both.
1548 # (Some of the padding may be truncated but that's irrelevant). We
1549 # need to check that the smaller packet is a prefix of the larger one.
1550 # Note that this check succeeds if the switch sends a zero-length
1551 # packet-in.
1552 compare_len = min(len(msg.data), len(data))
1553 if data[:compare_len] != msg.data[:compare_len]:
1554 logging.debug("Incorrect packet_in data")
1555 logging.debug("Expected %s" % format_packet(data[:compare_len]))
1556 logging.debug("Received %s" % format_packet(msg.data[:compare_len]))
1557 return False
1558
1559 return True
1560
1561def verify_packet_in(test, data, in_port, reason, controller=None):
1562 """
1563 Assert that the controller receives a packet_in message matching data 'data'
1564 from port 'in_port' with reason 'reason'. Does not trigger the packet_in
1565 itself, that's up to the test case.
1566
1567 @param test Instance of base_tests.SimpleProtocol
1568 @param pkt String to expect as the packet_in data
1569 @param in_port OpenFlow port number to expect as the packet_in in_port
1570 @param reason One of OFPR_* to expect as the packet_in reason
1571 @param controller Controller instance, defaults to test.controller
1572 @returns The received packet-in message
1573 """
1574
1575 if controller == None:
1576 controller = test.controller
1577
1578 end_time = time.time() + oftest.ofutils.default_timeout
1579
1580 while True:
1581 msg, _ = controller.poll(ofp.OFPT_PACKET_IN, end_time - time.time())
1582 if not msg:
1583 # Timeout
1584 break
1585 elif packet_in_match(msg, data, in_port, reason):
1586 # Found a matching message
1587 break
1588
1589 test.assertTrue(msg is not None, 'Packet in message not received on port %d' % in_port)
1590 return msg
1591
1592def verify_no_packet_in(test, data, in_port, controller=None):
1593 """
1594 Assert that the controller does not receive a packet_in message matching
1595 data 'data' from port 'in_port'.
1596
1597 @param test Instance of base_tests.SimpleProtocol
1598 @param pkt String to expect as the packet_in data
1599 @param in_port OpenFlow port number to expect as the packet_in in_port
1600 @param controller Controller instance, defaults to test.controller
1601 """
1602
1603 if controller == None:
1604 controller = test.controller
1605
1606 # Negative test, need to wait a short amount of time before checking we
1607 # didn't receive the message.
1608 time.sleep(0.5)
1609
1610 # Check every packet_in queued in the controller
1611 while True:
1612 msg, _ = controller.poll(ofp.OFPT_PACKET_IN, timeout=0)
1613 if msg == None:
1614 # No more queued packet_in messages
1615 break
1616 elif packet_in_match(msg, data, in_port, None):
1617 # Found a matching message
1618 break
1619
Rich Lane82c882d2013-08-09 17:13:52 -07001620 if in_port == None:
1621 test.assertTrue(msg == None, "Did not expect a packet-in message on any port")
1622 else:
1623 test.assertTrue(msg == None, "Did not expect a packet-in message on port %d" % in_port)
Rich Lane4c504f32013-06-07 17:24:14 -07001624
Rich Lane045db072013-08-06 13:16:30 -07001625def openflow_ports(num=None):
1626 """
1627 Return a list of 'num' OpenFlow port numbers
1628
1629 If 'num' is None, return all available ports. Otherwise, limit the length
1630 of the result to 'num' and raise an exception if not enough ports are
1631 available.
1632 """
1633 ports = sorted(oftest.config["port_map"].keys())
1634 if num != None and len(ports) < num:
1635 raise Exception("test requires %d ports but only %d are available" % (num, len(ports)))
1636 return ports[:num]
1637
Rich Lanee4b384d2013-09-13 14:33:40 -07001638def verify_packet(test, pkt, ofport):
1639 """
1640 Check that an expected packet is received
1641 """
1642 logging.debug("Checking for pkt on port %r", ofport)
1643 (rcv_port, rcv_pkt, pkt_time) = test.dataplane.poll(port_number=ofport, exp_pkt=str(pkt))
1644 test.assertTrue(rcv_pkt != None, "Did not receive pkt on %r" % ofport)
1645
1646def verify_no_packet(test, pkt, ofport):
1647 """
1648 Check that a particular packet is not received
1649 """
1650 logging.debug("Negative check for pkt on port %r", ofport)
1651 (rcv_port, rcv_pkt, pkt_time) = test.dataplane.poll(port_number=ofport, exp_pkt=str(pkt), timeout=0.01)
1652 test.assertTrue(rcv_pkt == None, "Received packet on %r" % ofport)
1653
1654def verify_no_other_packets(test):
1655 """
1656 Check that no unexpected packets are received
1657
1658 This is a no-op if the --relax option is in effect.
1659 """
1660 if oftest.config["relax"]:
1661 return
1662 logging.debug("Checking for unexpected packets on all ports")
1663 (rcv_port, rcv_pkt, pkt_time) = test.dataplane.poll(timeout=0.01)
1664 if rcv_pkt != None:
1665 logging.debug("Received unexpected packet on port %r: %s", rcv_port, format_packet(rcv_pkt))
1666 test.assertTrue(rcv_pkt == None, "Unexpected packet on port %r" % rcv_port)
1667
1668def verify_packets(test, pkt, ofports):
1669 """
1670 Check that a packet is received on certain ports
1671
1672 Also verifies that the packet is not received on any other ports, and that no
1673 other packets are received (unless --relax is in effect).
1674
1675 This covers the common and simplest cases for checking dataplane outputs.
1676 For more complex usage, like multiple different packets being output, or
1677 multiple packets on the same port, use the primitive verify_packet,
1678 verify_no_packet, and verify_no_other_packets functions directly.
1679 """
1680 pkt = str(pkt)
1681 for ofport in openflow_ports():
1682 if ofport in ofports:
1683 verify_packet(test, pkt, ofport)
1684 else:
1685 verify_no_packet(test, pkt, ofport)
1686 verify_no_other_packets(test)
1687
Rich Lane12d04592013-10-10 17:21:07 -07001688def verify_no_errors(ctrl):
1689 error, _ = ctrl.poll(ofp.OFPT_ERROR, 0)
1690 if error:
1691 raise AssertionError("unexpected error type=%d code=%d" % (error.err_type, error.code))
Rich Lanee4b384d2013-09-13 14:33:40 -07001692
Jonathan Stoutfcee3142014-01-28 15:46:22 -05001693def verify_capability(test, capability):
1694 """
Jonathan Stout073642d2014-02-04 13:41:48 -05001695 Return True if DUT supports the specified capability.
Jonathan Stoutfcee3142014-01-28 15:46:22 -05001696
1697 @param test Instance of base_tests.SimpleProtocol
1698 @param capability One of ofp_capabilities.
1699 """
1700 logging.info("Verifing that capability code is valid.")
1701 test.assertIn(capability, ofp.const.ofp_capabilities_map,
1702 "Capability code %d does not exist." % capability)
1703 capability_str = ofp.const.ofp_capabilities_map[capability]
1704
1705 logging.info(("Sending features_request to test if capability "
Jonathan Stout97e458a2014-01-28 16:08:04 -05001706 "%s is supported."), capability_str)
Jonathan Stoutfcee3142014-01-28 15:46:22 -05001707 req = ofp.message.features_request()
1708 res, raw = test.controller.transact(req)
1709 test.assertIsNotNone(res, "Did not receive a response from the DUT.")
1710 test.assertEqual(res.type, ofp.OFPT_FEATURES_REPLY,
1711 ("Unexpected packet type %d received in response to "
1712 "OFPT_FEATURES_REQUEST") % res.type)
Jonathan Stout641167f2014-02-04 12:07:10 -05001713 logging.info("Received features_reply.")
Jonathan Stoutfcee3142014-01-28 15:46:22 -05001714
Jonathan Stout641167f2014-02-04 12:07:10 -05001715 if (res.capabilities & capability) > 0:
1716 logging.info("Switch capabilities bitmask claims to support %s",
1717 capability_str)
1718 return True, res.capabilities
1719 else:
1720 logging.info("Capabilities bitmask does not support %s.",
1721 capability_str)
1722 return False, res.capabilities
Jonathan Stoutfcee3142014-01-28 15:46:22 -05001723
Rich Lane7744e112013-01-11 17:23:57 -08001724__all__ = list(set(locals()) - _import_blacklist)