blob: 26c25d38748a1099b9b36604080cc15e6fafdec3 [file] [log] [blame]
Dan Talaycod2ca1032010-03-10 14:40:26 -08001import sys
Dan Talayco92c99122010-06-03 13:53:18 -07002import copy
Rich Lane6242d9f2013-01-06 17:35:39 -08003import logging
4import types
5import time
Rich Lane5a9a1922013-01-11 14:29:30 -08006import re
Rich Lanea68176f2013-08-09 17:41:05 -07007import packet as scapy
Dan Talayco41eae8b2010-03-10 13:57:06 -08008
Rich Lanecd97d3d2013-01-07 18:50:06 -08009import oftest
10import oftest.controller
11import oftest.dataplane
Rich Lanef6883512013-03-11 17:00:09 -070012import oftest.parse
Rich Lane4c504f32013-06-07 17:24:14 -070013import oftest.ofutils
Rich Lanee717c6e2013-03-12 10:25:50 -070014import ofp
Dan Talaycoc901f4d2010-03-07 21:55:45 -080015
Dan Talaycoba3745c2010-07-21 21:51:08 -070016global skipped_test_count
17skipped_test_count = 0
18
Rich Lane7744e112013-01-11 17:23:57 -080019_import_blacklist = set(locals().keys())
20
Dan Talayco551befa2010-07-15 17:05:32 -070021# Some useful defines
22IP_ETHERTYPE = 0x800
23TCP_PROTOCOL = 0x6
24UDP_PROTOCOL = 0x11
25
Jeffrey Townsend5cb7ed32012-08-17 18:11:01 +000026MINSIZE = 0
27
Rich Lane9a003812012-10-04 17:17:59 -070028def delete_all_flows(ctrl):
Dan Talayco41eae8b2010-03-10 13:57:06 -080029 """
30 Delete all flows on the switch
31 @param ctrl The controller object for the test
Dan Talayco41eae8b2010-03-10 13:57:06 -080032 """
33
Rich Lane9a003812012-10-04 17:17:59 -070034 logging.info("Deleting all flows")
Rich Lanee717c6e2013-03-12 10:25:50 -070035 msg = ofp.message.flow_delete()
Rich Lanec717f442013-06-13 15:49:09 -070036 if ofp.OFP_VERSION in [1, 2]:
37 msg.match.wildcards = ofp.OFPFW_ALL
38 msg.out_port = ofp.OFPP_NONE
39 msg.buffer_id = 0xffffffff
40 elif ofp.OFP_VERSION >= 3:
41 msg.table_id = ofp.OFPTT_ALL
42 msg.buffer_id = ofp.OFP_NO_BUFFER
43 msg.out_port = ofp.OFPP_ANY
44 msg.out_group = ofp.OFPG_ANY
Rich Lane5c3151c2013-01-03 17:15:41 -080045 ctrl.message_send(msg)
Rich Lane44c4e3f2013-07-08 10:17:49 -070046 do_barrier(ctrl)
Rich Lane32bf9482013-01-03 17:26:30 -080047 return 0 # for backwards compatibility
Dan Talayco41eae8b2010-03-10 13:57:06 -080048
Ed Swierk99a74de2012-08-22 06:40:54 -070049def required_wildcards(parent):
Rich Lane2014f9b2012-10-05 15:29:40 -070050 w = test_param_get('required_wildcards', default='default')
Ed Swierk99a74de2012-08-22 06:40:54 -070051 if w == 'l3-l4':
Rich Lanee717c6e2013-03-12 10:25:50 -070052 return (ofp.OFPFW_NW_SRC_ALL | ofp.OFPFW_NW_DST_ALL | ofp.OFPFW_NW_TOS
53 | ofp.OFPFW_NW_PROTO | ofp.OFPFW_TP_SRC | ofp.OFPFW_TP_DST)
Ed Swierk99a74de2012-08-22 06:40:54 -070054 else:
55 return 0
56
Dan Talayco41eae8b2010-03-10 13:57:06 -080057def simple_tcp_packet(pktlen=100,
Rich Laned0478ff2013-03-11 12:46:58 -070058 eth_dst='00:01:02:03:04:05',
59 eth_src='00:06:07:08:09:0a',
Tatsuya Yabe460321e2010-05-25 17:50:49 -070060 dl_vlan_enable=False,
Rich Laned0478ff2013-03-11 12:46:58 -070061 vlan_vid=0,
62 vlan_pcp=0,
Dan Talayco551befa2010-07-15 17:05:32 -070063 dl_vlan_cfi=0,
Dan Talayco41eae8b2010-03-10 13:57:06 -080064 ip_src='192.168.0.1',
65 ip_dst='192.168.0.2',
Tatsuya Yabe460321e2010-05-25 17:50:49 -070066 ip_tos=0,
Gregor Maier9cc93342013-01-29 16:55:28 -080067 ip_ttl=64,
Dan Talayco41eae8b2010-03-10 13:57:06 -080068 tcp_sport=1234,
Christian Dickmann8b59b4b2012-09-23 16:48:30 -070069 tcp_dport=80,
70 ip_ihl=None,
71 ip_options=False
Dan Talayco41eae8b2010-03-10 13:57:06 -080072 ):
73 """
74 Return a simple dataplane TCP packet
75
76 Supports a few parameters:
77 @param len Length of packet in bytes w/o CRC
Rich Laned0478ff2013-03-11 12:46:58 -070078 @param eth_dst Destinatino MAC
79 @param eth_src Source MAC
Tatsuya Yabe460321e2010-05-25 17:50:49 -070080 @param dl_vlan_enable True if the packet is with vlan, False otherwise
Rich Laned0478ff2013-03-11 12:46:58 -070081 @param vlan_vid VLAN ID
82 @param vlan_pcp VLAN priority
Dan Talayco41eae8b2010-03-10 13:57:06 -080083 @param ip_src IP source
84 @param ip_dst IP destination
Tatsuya Yabe460321e2010-05-25 17:50:49 -070085 @param ip_tos IP ToS
Gregor Maier9cc93342013-01-29 16:55:28 -080086 @param ip_ttl IP TTL
Dan Talayco41eae8b2010-03-10 13:57:06 -080087 @param tcp_dport TCP destination port
88 @param ip_sport TCP source port
89
90 Generates a simple TCP request. Users
91 shouldn't assume anything about this packet other than that
92 it is a valid ethernet/IP/TCP frame.
93 """
Jeffrey Townsend5cb7ed32012-08-17 18:11:01 +000094
95 if MINSIZE > pktlen:
96 pktlen = MINSIZE
97
Dan Talayco551befa2010-07-15 17:05:32 -070098 # Note Dot1Q.id is really CFI
Shudong Zhou43ee54c2012-12-13 15:52:37 -080099 if (dl_vlan_enable):
Rich Laned0478ff2013-03-11 12:46:58 -0700100 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
101 scapy.Dot1Q(prio=vlan_pcp, id=dl_vlan_cfi, vlan=vlan_vid)/ \
Gregor Maier9cc93342013-01-29 16:55:28 -0800102 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ttl=ip_ttl, ihl=ip_ihl)/ \
Tatsuya Yabe460321e2010-05-25 17:50:49 -0700103 scapy.TCP(sport=tcp_sport, dport=tcp_dport)
104 else:
Christian Dickmann8b59b4b2012-09-23 16:48:30 -0700105 if not ip_options:
Rich Laned0478ff2013-03-11 12:46:58 -0700106 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
Gregor Maier9cc93342013-01-29 16:55:28 -0800107 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ttl=ip_ttl, ihl=ip_ihl)/ \
Christian Dickmann8b59b4b2012-09-23 16:48:30 -0700108 scapy.TCP(sport=tcp_sport, dport=tcp_dport)
109 else:
Rich Laned0478ff2013-03-11 12:46:58 -0700110 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
Gregor Maier9cc93342013-01-29 16:55:28 -0800111 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ttl=ip_ttl, ihl=ip_ihl, options=ip_options)/ \
Christian Dickmann8b59b4b2012-09-23 16:48:30 -0700112 scapy.TCP(sport=tcp_sport, dport=tcp_dport)
Tatsuya Yabe460321e2010-05-25 17:50:49 -0700113
Dan Talayco41eae8b2010-03-10 13:57:06 -0800114 pkt = pkt/("D" * (pktlen - len(pkt)))
115
116 return pkt
117
Rich Lane86aceb02013-07-17 18:45:38 -0700118def simple_tcpv6_packet(pktlen=100,
119 eth_dst='00:01:02:03:04:05',
120 eth_src='00:06:07:08:09:0a',
121 dl_vlan_enable=False,
122 vlan_vid=0,
123 vlan_pcp=0,
124 ipv6_src='2001:db8:85a3::8a2e:370:7334',
125 ipv6_dst='2001:db8:85a3::8a2e:370:7335',
126 ipv6_tc=0,
127 ipv6_hlim=64,
128 ipv6_fl=0,
129 tcp_sport=1234,
130 tcp_dport=80):
131 """
132 Return a simple IPv6/TCP packet
133
134 Supports a few parameters:
135 @param len Length of packet in bytes w/o CRC
136 @param eth_dst Destination MAC
137 @param eth_src Source MAC
138 @param dl_vlan_enable True if the packet is with vlan, False otherwise
139 @param vlan_vid VLAN ID
140 @param vlan_pcp VLAN priority
141 @param ipv6_src IPv6 source
142 @param ipv6_dst IPv6 destination
143 @param ipv6_tc IPv6 traffic class
144 @param ipv6_ttl IPv6 hop limit
145 @param ipv6_fl IPv6 flow label
146 @param tcp_dport TCP destination port
147 @param tcp_sport TCP source port
148
149 Generates a simple TCP request. Users shouldn't assume anything about this
150 packet other than that it is a valid ethernet/IPv6/TCP frame.
151 """
152
153 if MINSIZE > pktlen:
154 pktlen = MINSIZE
155
156 pkt = scapy.Ether(dst=eth_dst, src=eth_src)
157 if dl_vlan_enable or vlan_vid or vlan_pcp:
158 pkt /= scapy.Dot1Q(vlan=vlan_vid, prio=vlan_pcp)
159 pkt /= scapy.IPv6(src=ipv6_src, dst=ipv6_dst, fl=ipv6_fl, tc=ipv6_tc, hlim=ipv6_hlim)
160 pkt /= scapy.TCP(sport=tcp_sport, dport=tcp_dport)
161 pkt /= ("D" * (pktlen - len(pkt)))
162
163 return pkt
164
Rich Lane6ee7bea2012-10-26 16:19:29 -0700165def simple_udp_packet(pktlen=100,
Rich Laned0478ff2013-03-11 12:46:58 -0700166 eth_dst='00:01:02:03:04:05',
167 eth_src='00:06:07:08:09:0a',
Rich Lane6ee7bea2012-10-26 16:19:29 -0700168 dl_vlan_enable=False,
Rich Laned0478ff2013-03-11 12:46:58 -0700169 vlan_vid=0,
170 vlan_pcp=0,
Rich Lane6ee7bea2012-10-26 16:19:29 -0700171 dl_vlan_cfi=0,
172 ip_src='192.168.0.1',
173 ip_dst='192.168.0.2',
174 ip_tos=0,
Gregor Maier9cc93342013-01-29 16:55:28 -0800175 ip_ttl=64,
Rich Lane6ee7bea2012-10-26 16:19:29 -0700176 udp_sport=1234,
177 udp_dport=80,
178 ip_ihl=None,
179 ip_options=False
180 ):
181 """
182 Return a simple dataplane UDP packet
183
184 Supports a few parameters:
185 @param len Length of packet in bytes w/o CRC
Rich Laned0478ff2013-03-11 12:46:58 -0700186 @param eth_dst Destination MAC
187 @param eth_src Source MAC
Rich Lane6ee7bea2012-10-26 16:19:29 -0700188 @param dl_vlan_enable True if the packet is with vlan, False otherwise
Rich Laned0478ff2013-03-11 12:46:58 -0700189 @param vlan_vid VLAN ID
190 @param vlan_pcp VLAN priority
Rich Lane6ee7bea2012-10-26 16:19:29 -0700191 @param ip_src IP source
192 @param ip_dst IP destination
193 @param ip_tos IP ToS
Gregor Maier9cc93342013-01-29 16:55:28 -0800194 @param ip_ttl IP TTL
Rich Lane6ee7bea2012-10-26 16:19:29 -0700195 @param udp_dport UDP destination port
196 @param udp_sport UDP source port
197
198 Generates a simple UDP packet. Users shouldn't assume anything about
199 this packet other than that it is a valid ethernet/IP/UDP frame.
200 """
201
202 if MINSIZE > pktlen:
203 pktlen = MINSIZE
204
205 # Note Dot1Q.id is really CFI
206 if (dl_vlan_enable):
Rich Laned0478ff2013-03-11 12:46:58 -0700207 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
208 scapy.Dot1Q(prio=vlan_pcp, id=dl_vlan_cfi, vlan=vlan_vid)/ \
Gregor Maier9cc93342013-01-29 16:55:28 -0800209 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ttl=ip_ttl, ihl=ip_ihl)/ \
Rich Lane6ee7bea2012-10-26 16:19:29 -0700210 scapy.UDP(sport=udp_sport, dport=udp_dport)
211 else:
212 if not ip_options:
Rich Laned0478ff2013-03-11 12:46:58 -0700213 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
Gregor Maier9cc93342013-01-29 16:55:28 -0800214 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ttl=ip_ttl, ihl=ip_ihl)/ \
Rich Lane6ee7bea2012-10-26 16:19:29 -0700215 scapy.UDP(sport=udp_sport, dport=udp_dport)
216 else:
Rich Laned0478ff2013-03-11 12:46:58 -0700217 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
Gregor Maier9cc93342013-01-29 16:55:28 -0800218 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ttl=ip_ttl, ihl=ip_ihl, options=ip_options)/ \
Rich Lane6ee7bea2012-10-26 16:19:29 -0700219 scapy.UDP(sport=udp_sport, dport=udp_dport)
220
221 pkt = pkt/("D" * (pktlen - len(pkt)))
222
223 return pkt
224
Rich Lane86aceb02013-07-17 18:45:38 -0700225def simple_udpv6_packet(pktlen=100,
226 eth_dst='00:01:02:03:04:05',
227 eth_src='00:06:07:08:09:0a',
228 dl_vlan_enable=False,
229 vlan_vid=0,
230 vlan_pcp=0,
231 ipv6_src='2001:db8:85a3::8a2e:370:7334',
232 ipv6_dst='2001:db8:85a3::8a2e:370:7335',
233 ipv6_tc=0,
234 ipv6_hlim=64,
235 ipv6_fl=0,
236 udp_sport=1234,
237 udp_dport=80):
238 """
239 Return a simple IPv6/UDP packet
240
241 Supports a few parameters:
242 @param len Length of packet in bytes w/o CRC
243 @param eth_dst Destination MAC
244 @param eth_src Source MAC
245 @param dl_vlan_enable True if the packet is with vlan, False otherwise
246 @param vlan_vid VLAN ID
247 @param vlan_pcp VLAN priority
248 @param ipv6_src IPv6 source
249 @param ipv6_dst IPv6 destination
250 @param ipv6_tc IPv6 traffic class
251 @param ipv6_ttl IPv6 hop limit
252 @param ipv6_fl IPv6 flow label
253 @param udp_dport UDP destination port
254 @param udp_sport UDP source port
255
256 Generates a simple UDP request. Users shouldn't assume anything about this
257 packet other than that it is a valid ethernet/IPv6/UDP frame.
258 """
259
260 if MINSIZE > pktlen:
261 pktlen = MINSIZE
262
263 pkt = scapy.Ether(dst=eth_dst, src=eth_src)
264 if dl_vlan_enable or vlan_vid or vlan_pcp:
265 pkt /= scapy.Dot1Q(vlan=vlan_vid, prio=vlan_pcp)
266 pkt /= scapy.IPv6(src=ipv6_src, dst=ipv6_dst, fl=ipv6_fl, tc=ipv6_tc, hlim=ipv6_hlim)
267 pkt /= scapy.UDP(sport=udp_sport, dport=udp_dport)
268 pkt /= ("D" * (pktlen - len(pkt)))
269
270 return pkt
271
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700272def simple_icmp_packet(pktlen=60,
Rich Laned0478ff2013-03-11 12:46:58 -0700273 eth_dst='00:01:02:03:04:05',
274 eth_src='00:06:07:08:09:0a',
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700275 dl_vlan_enable=False,
Rich Laned0478ff2013-03-11 12:46:58 -0700276 vlan_vid=0,
277 vlan_pcp=0,
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700278 ip_src='192.168.0.1',
279 ip_dst='192.168.0.2',
280 ip_tos=0,
Gregor Maier9cc93342013-01-29 16:55:28 -0800281 ip_ttl=64,
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700282 icmp_type=8,
283 icmp_code=0
284 ):
285 """
286 Return a simple ICMP packet
287
288 Supports a few parameters:
289 @param len Length of packet in bytes w/o CRC
Rich Laned0478ff2013-03-11 12:46:58 -0700290 @param eth_dst Destinatino MAC
291 @param eth_src Source MAC
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700292 @param dl_vlan_enable True if the packet is with vlan, False otherwise
Rich Laned0478ff2013-03-11 12:46:58 -0700293 @param vlan_vid VLAN ID
294 @param vlan_pcp VLAN priority
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700295 @param ip_src IP source
296 @param ip_dst IP destination
297 @param ip_tos IP ToS
Gregor Maier9cc93342013-01-29 16:55:28 -0800298 @param ip_ttl IP TTL
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700299 @param icmp_type ICMP type
300 @param icmp_code ICMP code
301
302 Generates a simple ICMP ECHO REQUEST. Users
303 shouldn't assume anything about this packet other than that
304 it is a valid ethernet/ICMP frame.
305 """
Jeffrey Townsend5cb7ed32012-08-17 18:11:01 +0000306
307 if MINSIZE > pktlen:
308 pktlen = MINSIZE
309
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700310 if (dl_vlan_enable):
Rich Laned0478ff2013-03-11 12:46:58 -0700311 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
312 scapy.Dot1Q(prio=vlan_pcp, id=0, vlan=vlan_vid)/ \
Gregor Maier9cc93342013-01-29 16:55:28 -0800313 scapy.IP(src=ip_src, dst=ip_dst, ttl=ip_ttl, tos=ip_tos)/ \
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700314 scapy.ICMP(type=icmp_type, code=icmp_code)
315 else:
Rich Laned0478ff2013-03-11 12:46:58 -0700316 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
Gregor Maier9cc93342013-01-29 16:55:28 -0800317 scapy.IP(src=ip_src, dst=ip_dst, ttl=ip_ttl, tos=ip_tos)/ \
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700318 scapy.ICMP(type=icmp_type, code=icmp_code)
319
320 pkt = pkt/("0" * (pktlen - len(pkt)))
321
322 return pkt
323
Rich Lane86aceb02013-07-17 18:45:38 -0700324def simple_icmpv6_packet(pktlen=100,
325 eth_dst='00:01:02:03:04:05',
326 eth_src='00:06:07:08:09:0a',
327 dl_vlan_enable=False,
328 vlan_vid=0,
329 vlan_pcp=0,
330 ipv6_src='2001:db8:85a3::8a2e:370:7334',
331 ipv6_dst='2001:db8:85a3::8a2e:370:7335',
332 ipv6_tc=0,
333 ipv6_hlim=64,
334 ipv6_fl=0,
335 icmp_type=8,
336 icmp_code=0):
337 """
338 Return a simple ICMPv6 packet
339
340 Supports a few parameters:
341 @param len Length of packet in bytes w/o CRC
342 @param eth_dst Destination MAC
343 @param eth_src Source MAC
344 @param dl_vlan_enable True if the packet is with vlan, False otherwise
345 @param vlan_vid VLAN ID
346 @param vlan_pcp VLAN priority
347 @param ipv6_src IPv6 source
348 @param ipv6_dst IPv6 destination
349 @param ipv6_tc IPv6 traffic class
350 @param ipv6_ttl IPv6 hop limit
351 @param ipv6_fl IPv6 flow label
352 @param icmp_type ICMP type
353 @param icmp_code ICMP code
354
355 Generates a simple ICMP ECHO REQUEST. Users shouldn't assume anything
356 about this packet other than that it is a valid ethernet/IPv6/ICMP frame.
357 """
358
359 if MINSIZE > pktlen:
360 pktlen = MINSIZE
361
362 pkt = scapy.Ether(dst=eth_dst, src=eth_src)
363 if dl_vlan_enable or vlan_vid or vlan_pcp:
364 pkt /= scapy.Dot1Q(vlan=vlan_vid, prio=vlan_pcp)
365 pkt /= scapy.IPv6(src=ipv6_src, dst=ipv6_dst, fl=ipv6_fl, tc=ipv6_tc, hlim=ipv6_hlim)
366 pkt /= scapy.ICMPv6Unknown(type=icmp_type, code=icmp_code)
367 pkt /= ("D" * (pktlen - len(pkt)))
368
369 return pkt
370
Shudong Zhouc7562b12013-02-06 01:12:18 -0800371def simple_arp_packet(pktlen=60,
Rich Laned0478ff2013-03-11 12:46:58 -0700372 eth_dst='ff:ff:ff:ff:ff:ff',
373 eth_src='00:06:07:08:09:0a',
Shudong Zhouc7562b12013-02-06 01:12:18 -0800374 arp_op=1,
375 ip_snd='192.168.0.1',
376 ip_tgt='192.168.0.2',
377 hw_snd='00:06:07:08:09:0a',
378 hw_tgt='00:00:00:00:00:00',
379 ):
380 """
381 Return a simple ARP packet
382
383 Supports a few parameters:
384 @param len Length of packet in bytes w/o CRC
Rich Laned0478ff2013-03-11 12:46:58 -0700385 @param eth_dst Destinatino MAC
386 @param eth_src Source MAC
Shudong Zhouc7562b12013-02-06 01:12:18 -0800387 @param arp_op Operation (1=request, 2=reply)
388 @param ip_snd Sender IP
389 @param ip_tgt Target IP
390 @param hw_snd Sender hardware address
391 @param hw_tgt Target hardware address
392
393 Generates a simple ARP REQUEST. Users
394 shouldn't assume anything about this packet other than that
395 it is a valid ethernet/ARP frame.
396 """
397
398 if MINSIZE > pktlen:
399 pktlen = MINSIZE
400
Rich Laned0478ff2013-03-11 12:46:58 -0700401 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
Shudong Zhouc7562b12013-02-06 01:12:18 -0800402 scapy.ARP(hwsrc=hw_snd, hwdst=hw_tgt, pdst=ip_tgt, psrc=ip_snd, op=arp_op)
403
404 pkt = pkt/("0" * (pktlen - len(pkt)))
405
406 return pkt
407
Ed Swierk0aeff8c2012-03-23 20:27:18 -0700408def simple_eth_packet(pktlen=60,
Rich Laneb7dc3e22013-08-02 13:51:06 -0700409 eth_dst='01:80:c2:00:00:00',
410 eth_src='00:01:02:03:04:05',
Rich Laned0478ff2013-03-11 12:46:58 -0700411 eth_type=0x88cc):
Jeffrey Townsend5cb7ed32012-08-17 18:11:01 +0000412
413 if MINSIZE > pktlen:
414 pktlen = MINSIZE
415
Rich Laned0478ff2013-03-11 12:46:58 -0700416 pkt = scapy.Ether(dst=eth_dst, src=eth_src, type=eth_type)
Ed Swierk0aeff8c2012-03-23 20:27:18 -0700417
418 pkt = pkt/("0" * (pktlen - len(pkt)))
419
420 return pkt
421
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800422def qinq_tcp_packet(pktlen=100,
Rich Laned0478ff2013-03-11 12:46:58 -0700423 eth_dst='00:01:02:03:04:05',
424 eth_src='00:06:07:08:09:0a',
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800425 dl_vlan_outer=20,
426 dl_vlan_pcp_outer=0,
427 dl_vlan_cfi_outer=0,
Rich Laned0478ff2013-03-11 12:46:58 -0700428 vlan_vid=10,
429 vlan_pcp=0,
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800430 dl_vlan_cfi=0,
431 ip_src='192.168.0.1',
432 ip_dst='192.168.0.2',
433 ip_tos=0,
Gregor Maier9cc93342013-01-29 16:55:28 -0800434 ip_ttl=64,
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800435 tcp_sport=1234,
436 tcp_dport=80,
437 ip_ihl=None,
438 ip_options=False
439 ):
440 """
441 Return a doubly tagged dataplane TCP packet
442
443 Supports a few parameters:
444 @param len Length of packet in bytes w/o CRC
Rich Laned0478ff2013-03-11 12:46:58 -0700445 @param eth_dst Destinatino MAC
446 @param eth_src Source MAC
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800447 @param dl_vlan_outer Outer VLAN ID
448 @param dl_vlan_pcp_outer Outer VLAN priority
449 @param dl_vlan_cfi_outer Outer VLAN cfi bit
Rich Laned0478ff2013-03-11 12:46:58 -0700450 @param vlan_vid Inner VLAN ID
451 @param vlan_pcp VLAN priority
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800452 @param dl_vlan_cfi VLAN cfi bit
453 @param ip_src IP source
454 @param ip_dst IP destination
455 @param ip_tos IP ToS
456 @param tcp_dport TCP destination port
457 @param ip_sport TCP source port
458
459 Generates a TCP request. Users
460 shouldn't assume anything about this packet other than that
461 it is a valid ethernet/IP/TCP frame.
462 """
463
464 if MINSIZE > pktlen:
465 pktlen = MINSIZE
466
467 # Note Dot1Q.id is really CFI
Rich Laned0478ff2013-03-11 12:46:58 -0700468 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800469 scapy.Dot1Q(prio=dl_vlan_pcp_outer, id=dl_vlan_cfi_outer, vlan=dl_vlan_outer)/ \
Rich Laned0478ff2013-03-11 12:46:58 -0700470 scapy.Dot1Q(prio=vlan_pcp, id=dl_vlan_cfi, vlan=vlan_vid)/ \
Gregor Maier9cc93342013-01-29 16:55:28 -0800471 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ttl=ip_ttl, ihl=ip_ihl)/ \
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800472 scapy.TCP(sport=tcp_sport, dport=tcp_dport)
473
474 pkt = pkt/("D" * (pktlen - len(pkt)))
475
476 return pkt
477
Shudong Zhoub7f12462012-11-20 13:01:12 -0800478def do_barrier(ctrl, timeout=-1):
Dan Talayco0fc08bd2012-04-09 16:56:18 -0700479 """
480 Do a barrier command
481 Return 0 on success, -1 on error
482 """
Rich Lanee717c6e2013-03-12 10:25:50 -0700483 b = ofp.message.barrier_request()
Shudong Zhoub7f12462012-11-20 13:01:12 -0800484 (resp, pkt) = ctrl.transact(b, timeout=timeout)
Rich Lane3a261d52013-01-03 17:45:08 -0800485 if resp is None:
486 raise AssertionError("barrier failed")
Dan Talaycof6b94832012-04-12 21:50:57 -0700487 # We'll trust the transaction processing in the controller that xid matched
Rich Lane3a261d52013-01-03 17:45:08 -0800488 return 0 # for backwards compatibility
Dan Talayco92c99122010-06-03 13:53:18 -0700489
Rich Lane9a003812012-10-04 17:17:59 -0700490def port_config_get(controller, port_no):
Dan Talayco92c99122010-06-03 13:53:18 -0700491 """
492 Get a port's configuration
493
494 Gets the switch feature configuration and grabs one port's
495 configuration
496
497 @returns (hwaddr, config, advert) The hwaddress, configuration and
498 advertised values
499 """
Rich Lane6dc865c2013-07-10 10:12:13 -0700500
501 if ofp.OFP_VERSION <= 3:
502 request = ofp.message.features_request()
503 reply, _ = controller.transact(request)
504 if reply is None:
505 logging.warn("Get feature request failed")
506 return None, None, None
507 logging.debug(reply.show())
508 ports = reply.ports
509 else:
510 request = ofp.message.port_desc_stats_request()
511 # TODO do multipart correctly
512 reply, _ = controller.transact(request)
513 if reply is None:
514 logging.warn("Port desc stats request failed")
515 return None, None, None
516 logging.debug(reply.show())
517 ports = reply.entries
518
519 for port in ports:
520 if port.port_no == port_no:
521 return (port.hw_addr, port.config, port.advertised)
Dan Talayco92c99122010-06-03 13:53:18 -0700522
Rich Lane9a003812012-10-04 17:17:59 -0700523 logging.warn("Did not find port number for port config")
Dan Talayco92c99122010-06-03 13:53:18 -0700524 return None, None, None
525
Rich Lane9a003812012-10-04 17:17:59 -0700526def port_config_set(controller, port_no, config, mask):
Dan Talayco92c99122010-06-03 13:53:18 -0700527 """
528 Set the port configuration according the given parameters
529
530 Gets the switch feature configuration and updates one port's
531 configuration value according to config and mask
532 """
Rich Lane9a003812012-10-04 17:17:59 -0700533 logging.info("Setting port " + str(port_no) + " to config " + str(config))
Rich Lane6dc865c2013-07-10 10:12:13 -0700534
535 hw_addr, _, _ = port_config_get(controller, port_no)
536
Rich Lanee717c6e2013-03-12 10:25:50 -0700537 mod = ofp.message.port_mod()
Dan Talayco92c99122010-06-03 13:53:18 -0700538 mod.port_no = port_no
Rich Lane6dc865c2013-07-10 10:12:13 -0700539 if hw_addr != None:
540 mod.hw_addr = hw_addr
Dan Talayco92c99122010-06-03 13:53:18 -0700541 mod.config = config
542 mod.mask = mask
Rich Lane6dc865c2013-07-10 10:12:13 -0700543 mod.advertise = 0 # No change
Rich Lane5c3151c2013-01-03 17:15:41 -0800544 controller.message_send(mod)
545 return 0
Dan Talayco92c99122010-06-03 13:53:18 -0700546
Rich Lane2014f9b2012-10-05 15:29:40 -0700547def receive_pkt_check(dp, pkt, yes_ports, no_ports, assert_if):
Dan Talayco92c99122010-06-03 13:53:18 -0700548 """
549 Check for proper receive packets across all ports
Ken Chiang1bf01602012-04-04 10:48:23 -0700550 @param dp The dataplane object
Dan Talayco92c99122010-06-03 13:53:18 -0700551 @param pkt Expected packet; may be None if yes_ports is empty
552 @param yes_ports Set or list of ports that should recieve packet
553 @param no_ports Set or list of ports that should not receive packet
554 @param assert_if Object that implements assertXXX
555 """
Rich Lane91765672012-12-06 16:33:04 -0800556
557 # Wait this long for packets that we don't expect to receive.
558 # 100ms is (rarely) too short for positive tests on slow
559 # switches but is definitely not too short for a negative test.
560 negative_timeout = 0.1
561
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700562 exp_pkt_arg = None
Rich Lanecd97d3d2013-01-07 18:50:06 -0800563 if oftest.config["relax"]:
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700564 exp_pkt_arg = pkt
565
Dan Talayco92c99122010-06-03 13:53:18 -0700566 for ofport in yes_ports:
Rich Lane9a003812012-10-04 17:17:59 -0700567 logging.debug("Checking for pkt on port " + str(ofport))
Ken Chiang1bf01602012-04-04 10:48:23 -0700568 (rcv_port, rcv_pkt, pkt_time) = dp.poll(
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700569 port_number=ofport, exp_pkt=exp_pkt_arg)
Dan Talayco92c99122010-06-03 13:53:18 -0700570 assert_if.assertTrue(rcv_pkt is not None,
571 "Did not receive pkt on " + str(ofport))
Rich Lanecd97d3d2013-01-07 18:50:06 -0800572 if not oftest.dataplane.match_exp_pkt(pkt, rcv_pkt):
Rich Lane3c266832013-01-29 18:29:15 -0800573 logging.debug("Expected %s" % format_packet(pkt))
574 logging.debug("Received %s" % format_packet(rcv_pkt))
Rich Lanecd97d3d2013-01-07 18:50:06 -0800575 assert_if.assertTrue(oftest.dataplane.match_exp_pkt(pkt, rcv_pkt),
Rich Lane3c266832013-01-29 18:29:15 -0800576 "Received packet does not match expected packet " +
Ken Chiang1bf01602012-04-04 10:48:23 -0700577 "on port " + str(ofport))
Dan Talayco73f84012012-10-02 09:23:18 -0700578 if len(no_ports) > 0:
Rich Lane91765672012-12-06 16:33:04 -0800579 time.sleep(negative_timeout)
Dan Talayco92c99122010-06-03 13:53:18 -0700580 for ofport in no_ports:
Rich Lane9a003812012-10-04 17:17:59 -0700581 logging.debug("Negative check for pkt on port " + str(ofport))
Ken Chiang1bf01602012-04-04 10:48:23 -0700582 (rcv_port, rcv_pkt, pkt_time) = dp.poll(
Rich Lane91765672012-12-06 16:33:04 -0800583 port_number=ofport, timeout=0, exp_pkt=exp_pkt_arg)
Dan Talayco92c99122010-06-03 13:53:18 -0700584 assert_if.assertTrue(rcv_pkt is None,
585 "Unexpected pkt on port " + str(ofport))
Dan Talayco551befa2010-07-15 17:05:32 -0700586
587
Dan Talaycoc948d0b2012-03-23 12:17:54 -0700588def receive_pkt_verify(parent, egr_ports, exp_pkt, ing_port):
Dan Talayco551befa2010-07-15 17:05:32 -0700589 """
590 Receive a packet and verify it matches an expected value
Dan Talaycof6e76c02012-03-23 10:56:12 -0700591 @param egr_port A single port or list of ports
Dan Talayco551befa2010-07-15 17:05:32 -0700592
593 parent must implement dataplane, assertTrue and assertEqual
594 """
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700595 exp_pkt_arg = None
Rich Lanecd97d3d2013-01-07 18:50:06 -0800596 if oftest.config["relax"]:
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700597 exp_pkt_arg = exp_pkt
598
Dan Talaycof6e76c02012-03-23 10:56:12 -0700599 if type(egr_ports) == type([]):
600 egr_port_list = egr_ports
601 else:
602 egr_port_list = [egr_ports]
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700603
Dan Talaycof6e76c02012-03-23 10:56:12 -0700604 # Expect a packet from each port on egr port list
605 for egr_port in egr_port_list:
Dan Talaycod8ae7582012-03-23 12:24:56 -0700606 check_port = egr_port
Rich Lanee717c6e2013-03-12 10:25:50 -0700607 if egr_port == ofp.OFPP_IN_PORT:
Dan Talaycod8ae7582012-03-23 12:24:56 -0700608 check_port = ing_port
Dan Talaycof6e76c02012-03-23 10:56:12 -0700609 (rcv_port, rcv_pkt, pkt_time) = parent.dataplane.poll(
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700610 port_number=check_port, exp_pkt=exp_pkt_arg)
Dan Talayco551befa2010-07-15 17:05:32 -0700611
Dan Talaycof6e76c02012-03-23 10:56:12 -0700612 if rcv_pkt is None:
Rich Lane9a003812012-10-04 17:17:59 -0700613 logging.error("ERROR: No packet received from " +
Dan Talaycod8ae7582012-03-23 12:24:56 -0700614 str(check_port))
Dan Talayco551befa2010-07-15 17:05:32 -0700615
Dan Talaycof6e76c02012-03-23 10:56:12 -0700616 parent.assertTrue(rcv_pkt is not None,
Dan Talaycod8ae7582012-03-23 12:24:56 -0700617 "Did not receive packet port " + str(check_port))
Rich Lane9a003812012-10-04 17:17:59 -0700618 logging.debug("Packet len " + str(len(rcv_pkt)) + " in on " +
Dan Talaycof6e76c02012-03-23 10:56:12 -0700619 str(rcv_port))
620
621 if str(exp_pkt) != str(rcv_pkt):
Rich Lane9a003812012-10-04 17:17:59 -0700622 logging.error("ERROR: Packet match failed.")
623 logging.debug("Expected len " + str(len(exp_pkt)) + ": "
Dan Talaycof6e76c02012-03-23 10:56:12 -0700624 + str(exp_pkt).encode('hex'))
Rich Lane9a003812012-10-04 17:17:59 -0700625 logging.debug("Received len " + str(len(rcv_pkt)) + ": "
Dan Talaycof6e76c02012-03-23 10:56:12 -0700626 + str(rcv_pkt).encode('hex'))
Rich Lane5d7e89a2012-10-26 16:43:13 -0700627 logging.debug("Expected packet: " + inspect_packet(scapy.Ether(str(exp_pkt))))
628 logging.debug("Received packet: " + inspect_packet(scapy.Ether(str(rcv_pkt))))
Dan Talaycof6e76c02012-03-23 10:56:12 -0700629 parent.assertEqual(str(exp_pkt), str(rcv_pkt),
Dan Talaycod8ae7582012-03-23 12:24:56 -0700630 "Packet match error on port " + str(check_port))
Dan Talaycof6e76c02012-03-23 10:56:12 -0700631
Dan Talayco551befa2010-07-15 17:05:32 -0700632def match_verify(parent, req_match, res_match):
633 """
634 Verify flow matches agree; if they disagree, report where
635
636 parent must implement assertEqual
637 Use str() to ensure content is compared and not pointers
638 """
639
640 parent.assertEqual(req_match.wildcards, res_match.wildcards,
641 'Match failed: wildcards: ' + hex(req_match.wildcards) +
642 " != " + hex(res_match.wildcards))
643 parent.assertEqual(req_match.in_port, res_match.in_port,
644 'Match failed: in_port: ' + str(req_match.in_port) +
645 " != " + str(res_match.in_port))
Rich Laned0478ff2013-03-11 12:46:58 -0700646 parent.assertEqual(str(req_match.eth_src), str(res_match.eth_src),
647 'Match failed: eth_src: ' + str(req_match.eth_src) +
648 " != " + str(res_match.eth_src))
649 parent.assertEqual(str(req_match.eth_dst), str(res_match.eth_dst),
650 'Match failed: eth_dst: ' + str(req_match.eth_dst) +
651 " != " + str(res_match.eth_dst))
652 parent.assertEqual(req_match.vlan_vid, res_match.vlan_vid,
653 'Match failed: vlan_vid: ' + str(req_match.vlan_vid) +
654 " != " + str(res_match.vlan_vid))
655 parent.assertEqual(req_match.vlan_pcp, res_match.vlan_pcp,
656 'Match failed: vlan_pcp: ' +
657 str(req_match.vlan_pcp) + " != " +
658 str(res_match.vlan_pcp))
659 parent.assertEqual(req_match.eth_type, res_match.eth_type,
660 'Match failed: eth_type: ' + str(req_match.eth_type) +
661 " != " + str(res_match.eth_type))
Dan Talayco551befa2010-07-15 17:05:32 -0700662
Rich Lanee717c6e2013-03-12 10:25:50 -0700663 if (not(req_match.wildcards & ofp.OFPFW_DL_TYPE)
Rich Laned0478ff2013-03-11 12:46:58 -0700664 and (req_match.eth_type == IP_ETHERTYPE)):
665 parent.assertEqual(req_match.ip_dscp, res_match.ip_dscp,
666 'Match failed: ip_dscp: ' + str(req_match.ip_dscp) +
667 " != " + str(res_match.ip_dscp))
668 parent.assertEqual(req_match.ip_proto, res_match.ip_proto,
669 'Match failed: ip_proto: ' + str(req_match.ip_proto) +
670 " != " + str(res_match.ip_proto))
671 parent.assertEqual(req_match.ipv4_src, res_match.ipv4_src,
672 'Match failed: ipv4_src: ' + str(req_match.ipv4_src) +
673 " != " + str(res_match.ipv4_src))
674 parent.assertEqual(req_match.ipv4_dst, res_match.ipv4_dst,
675 'Match failed: ipv4_dst: ' + str(req_match.ipv4_dst) +
676 " != " + str(res_match.ipv4_dst))
Dan Talayco551befa2010-07-15 17:05:32 -0700677
Rich Lanee717c6e2013-03-12 10:25:50 -0700678 if (not(req_match.wildcards & ofp.OFPFW_NW_PROTO)
Rich Laned0478ff2013-03-11 12:46:58 -0700679 and ((req_match.ip_proto == TCP_PROTOCOL)
680 or (req_match.ip_proto == UDP_PROTOCOL))):
681 parent.assertEqual(req_match.tcp_src, res_match.tcp_src,
682 'Match failed: tcp_src: ' +
683 str(req_match.tcp_src) +
684 " != " + str(res_match.tcp_src))
685 parent.assertEqual(req_match.tcp_dst, res_match.tcp_dst,
686 'Match failed: tcp_dst: ' +
687 str(req_match.tcp_dst) +
688 " != " + str(res_match.tcp_dst))
Dan Talayco551befa2010-07-15 17:05:32 -0700689
Ed Swierk99a74de2012-08-22 06:40:54 -0700690def packet_to_flow_match(parent, packet):
Rich Lanef6883512013-03-11 17:00:09 -0700691 match = oftest.parse.packet_to_flow_match(packet)
Rich Laneab7476f2013-06-13 15:53:52 -0700692 if ofp.OFP_VERSION in [1, 2]:
693 match.wildcards |= required_wildcards(parent)
694 else:
695 # TODO remove incompatible OXM entries
696 pass
Ed Swierk99a74de2012-08-22 06:40:54 -0700697 return match
698
699def flow_msg_create(parent, pkt, ing_port=None, action_list=None, wildcards=None,
Dan Talaycof6e76c02012-03-23 10:56:12 -0700700 egr_ports=None, egr_queue=None, check_expire=False, in_band=False):
Dan Talayco551befa2010-07-15 17:05:32 -0700701 """
702 Create a flow message
703
704 Match on packet with given wildcards.
705 See flow_match_test for other parameter descriptoins
706 @param egr_queue if not None, make the output an enqueue action
Dan Talayco677c0b72011-08-23 22:53:38 -0700707 @param in_band if True, do not wildcard ingress port
Dan Talaycof6e76c02012-03-23 10:56:12 -0700708 @param egr_ports None (drop), single port or list of ports
Dan Talayco551befa2010-07-15 17:05:32 -0700709 """
Rich Lanef6883512013-03-11 17:00:09 -0700710 match = oftest.parse.packet_to_flow_match(pkt)
Dan Talayco551befa2010-07-15 17:05:32 -0700711 parent.assertTrue(match is not None, "Flow match from pkt failed")
Ed Swierk99a74de2012-08-22 06:40:54 -0700712 if wildcards is None:
713 wildcards = required_wildcards(parent)
Dan Talayco677c0b72011-08-23 22:53:38 -0700714 if in_band:
Rich Lanee717c6e2013-03-12 10:25:50 -0700715 wildcards &= ~ofp.OFPFW_IN_PORT
Dan Talayco551befa2010-07-15 17:05:32 -0700716 match.wildcards = wildcards
717 match.in_port = ing_port
718
Dan Talaycof6e76c02012-03-23 10:56:12 -0700719 if type(egr_ports) == type([]):
720 egr_port_list = egr_ports
721 else:
722 egr_port_list = [egr_ports]
723
Rich Lanee717c6e2013-03-12 10:25:50 -0700724 request = ofp.message.flow_add()
Dan Talayco551befa2010-07-15 17:05:32 -0700725 request.match = match
726 request.buffer_id = 0xffffffff
727 if check_expire:
Rich Lanee717c6e2013-03-12 10:25:50 -0700728 request.flags |= ofp.OFPFF_SEND_FLOW_REM
Dan Talayco551befa2010-07-15 17:05:32 -0700729 request.hard_timeout = 1
730
731 if action_list is not None:
732 for act in action_list:
Rich Lane9a003812012-10-04 17:17:59 -0700733 logging.debug("Adding action " + act.show())
Rich Lanec495d9e2013-03-08 17:43:36 -0800734 request.actions.append(act)
Dan Talayco551befa2010-07-15 17:05:32 -0700735
736 # Set up output/enqueue action if directed
737 if egr_queue is not None:
Dan Talaycof6e76c02012-03-23 10:56:12 -0700738 parent.assertTrue(egr_ports is not None, "Egress port not set")
Rich Lanee717c6e2013-03-12 10:25:50 -0700739 act = ofp.action.enqueue()
Dan Talaycof6e76c02012-03-23 10:56:12 -0700740 for egr_port in egr_port_list:
741 act.port = egr_port
742 act.queue_id = egr_queue
Rich Lanec495d9e2013-03-08 17:43:36 -0800743 request.actions.append(act)
Dan Talaycof6e76c02012-03-23 10:56:12 -0700744 elif egr_ports is not None:
745 for egr_port in egr_port_list:
Rich Lanee717c6e2013-03-12 10:25:50 -0700746 act = ofp.action.output()
Dan Talaycof6e76c02012-03-23 10:56:12 -0700747 act.port = egr_port
Rich Lanec495d9e2013-03-08 17:43:36 -0800748 request.actions.append(act)
Dan Talayco551befa2010-07-15 17:05:32 -0700749
Rich Lane9a003812012-10-04 17:17:59 -0700750 logging.debug(request.show())
Dan Talayco551befa2010-07-15 17:05:32 -0700751
752 return request
753
Jeffrey Townsendf3eae9c2012-03-28 18:23:21 -0700754def flow_msg_install(parent, request, clear_table_override=None):
Dan Talayco551befa2010-07-15 17:05:32 -0700755 """
756 Install a flow mod message in the switch
757
758 @param parent Must implement controller, assertEqual, assertTrue
759 @param request The request, all set to go
760 @param clear_table If true, clear the flow table before installing
761 """
Dan Talayco8a64e332012-03-28 14:53:20 -0700762
Rich Lane2014f9b2012-10-05 15:29:40 -0700763 clear_table = test_param_get('clear_table', default=True)
Jeffrey Townsendf3eae9c2012-03-28 18:23:21 -0700764 if(clear_table_override != None):
765 clear_table = clear_table_override
766
767 if clear_table:
Rich Lane9a003812012-10-04 17:17:59 -0700768 logging.debug("Clear flow table")
Rich Lane32bf9482013-01-03 17:26:30 -0800769 delete_all_flows(parent.controller)
Dan Talayco551befa2010-07-15 17:05:32 -0700770
Rich Lane9a003812012-10-04 17:17:59 -0700771 logging.debug("Insert flow")
Rich Lane5c3151c2013-01-03 17:15:41 -0800772 parent.controller.message_send(request)
Rich Lanee912d032012-12-22 14:28:33 -0800773
Rich Lane3a261d52013-01-03 17:45:08 -0800774 do_barrier(parent.controller)
Dan Talayco551befa2010-07-15 17:05:32 -0700775
Ed Swierk99a74de2012-08-22 06:40:54 -0700776def flow_match_test_port_pair(parent, ing_port, egr_ports, wildcards=None,
Rich Laned0478ff2013-03-11 12:46:58 -0700777 vlan_vid=-1, pkt=None, exp_pkt=None,
Rich Lanee5779d32012-10-05 17:56:04 -0700778 action_list=None):
Dan Talayco551befa2010-07-15 17:05:32 -0700779 """
780 Flow match test on single TCP packet
Dan Talaycof6e76c02012-03-23 10:56:12 -0700781 @param egr_ports A single port or list of ports
Dan Talayco551befa2010-07-15 17:05:32 -0700782
783 Run test with packet through switch from ing_port to egr_port
784 See flow_match_test for parameter descriptions
785 """
786
Ed Swierk99a74de2012-08-22 06:40:54 -0700787 if wildcards is None:
788 wildcards = required_wildcards(parent)
Rich Lane9a003812012-10-04 17:17:59 -0700789 logging.info("Pkt match test: " + str(ing_port) + " to " +
Dan Talaycof6e76c02012-03-23 10:56:12 -0700790 str(egr_ports))
Rich Laned0478ff2013-03-11 12:46:58 -0700791 logging.debug(" WC: " + hex(wildcards) + " vlan: " + str(vlan_vid))
Dan Talayco551befa2010-07-15 17:05:32 -0700792 if pkt is None:
Rich Laned0478ff2013-03-11 12:46:58 -0700793 pkt = simple_tcp_packet(dl_vlan_enable=(vlan_vid >= 0), vlan_vid=vlan_vid)
Dan Talayco551befa2010-07-15 17:05:32 -0700794
795 request = flow_msg_create(parent, pkt, ing_port=ing_port,
Dan Talaycof6e76c02012-03-23 10:56:12 -0700796 wildcards=wildcards, egr_ports=egr_ports,
Dan Talayco551befa2010-07-15 17:05:32 -0700797 action_list=action_list)
798
799 flow_msg_install(parent, request)
800
Rich Lane9a003812012-10-04 17:17:59 -0700801 logging.debug("Send packet: " + str(ing_port) + " to " +
Dan Talaycof6e76c02012-03-23 10:56:12 -0700802 str(egr_ports))
Dan Talayco551befa2010-07-15 17:05:32 -0700803 parent.dataplane.send(ing_port, str(pkt))
804
805 if exp_pkt is None:
806 exp_pkt = pkt
Dan Talaycoc948d0b2012-03-23 12:17:54 -0700807 receive_pkt_verify(parent, egr_ports, exp_pkt, ing_port)
Dan Talayco551befa2010-07-15 17:05:32 -0700808
Rich Lane89725bb2012-12-03 16:23:27 -0800809def flow_match_test_pktout(parent, ing_port, egr_ports,
Rich Laned0478ff2013-03-11 12:46:58 -0700810 vlan_vid=-1, pkt=None, exp_pkt=None,
Rich Lane89725bb2012-12-03 16:23:27 -0800811 action_list=None):
812 """
813 Packet-out test on single TCP packet
814 @param egr_ports A single port or list of ports
815
816 Run test sending packet-out to egr_ports. The goal is to test the actions
817 taken on the packet, not the matching which is of course irrelevant.
818 See flow_match_test for parameter descriptions
819 """
820
821 if pkt is None:
Rich Laned0478ff2013-03-11 12:46:58 -0700822 pkt = simple_tcp_packet(dl_vlan_enable=(vlan_vid >= 0), vlan_vid=vlan_vid)
Rich Lane89725bb2012-12-03 16:23:27 -0800823
Rich Lanee717c6e2013-03-12 10:25:50 -0700824 msg = ofp.message.packet_out()
Rich Lane89725bb2012-12-03 16:23:27 -0800825 msg.in_port = ing_port
Rich Laneea8c4722013-04-04 15:30:20 -0700826 msg.buffer_id = 0xffffffff
Rich Lane89725bb2012-12-03 16:23:27 -0800827 msg.data = str(pkt)
828 if action_list is not None:
829 for act in action_list:
Rich Lanec495d9e2013-03-08 17:43:36 -0800830 msg.actions.append(act)
Rich Lane89725bb2012-12-03 16:23:27 -0800831
832 # Set up output action
833 if egr_ports is not None:
834 for egr_port in egr_ports:
Rich Lanee717c6e2013-03-12 10:25:50 -0700835 act = ofp.action.output()
Rich Lane89725bb2012-12-03 16:23:27 -0800836 act.port = egr_port
Rich Lanec495d9e2013-03-08 17:43:36 -0800837 msg.actions.append(act)
Rich Lane89725bb2012-12-03 16:23:27 -0800838
839 logging.debug(msg.show())
Rich Lane5c3151c2013-01-03 17:15:41 -0800840 parent.controller.message_send(msg)
Rich Lane89725bb2012-12-03 16:23:27 -0800841
842 if exp_pkt is None:
843 exp_pkt = pkt
844 receive_pkt_verify(parent, egr_ports, exp_pkt, ing_port)
845
Dan Talaycof6e76c02012-03-23 10:56:12 -0700846def get_egr_list(parent, of_ports, how_many, exclude_list=[]):
847 """
848 Generate a list of ports avoiding those in the exclude list
Rich Lane9a003812012-10-04 17:17:59 -0700849 @param parent Supplies logging
Dan Talaycof6e76c02012-03-23 10:56:12 -0700850 @param of_ports List of OF port numbers
851 @param how_many Number of ports to be added to the list
852 @param exclude_list List of ports not to be used
853 @returns An empty list if unable to find enough ports
854 """
855
Dan Talaycoc948d0b2012-03-23 12:17:54 -0700856 if how_many == 0:
857 return []
858
Dan Talaycof6e76c02012-03-23 10:56:12 -0700859 count = 0
860 egr_ports = []
861 for egr_idx in range(len(of_ports)):
862 if of_ports[egr_idx] not in exclude_list:
863 egr_ports.append(of_ports[egr_idx])
864 count += 1
865 if count >= how_many:
866 return egr_ports
Rich Lane9a003812012-10-04 17:17:59 -0700867 logging.debug("Could not generate enough egress ports for test")
Dan Talaycof6e76c02012-03-23 10:56:12 -0700868 return []
869
Rich Laned0478ff2013-03-11 12:46:58 -0700870def flow_match_test(parent, port_map, wildcards=None, vlan_vid=-1, pkt=None,
Rich Lanee5779d32012-10-05 17:56:04 -0700871 exp_pkt=None, action_list=None,
Dan Talaycoc948d0b2012-03-23 12:17:54 -0700872 max_test=0, egr_count=1, ing_port=False):
Dan Talayco551befa2010-07-15 17:05:32 -0700873 """
Rich Lane89725bb2012-12-03 16:23:27 -0800874 Run flow_match_test_port_pair on all port pairs and packet-out
Dan Talayco551befa2010-07-15 17:05:32 -0700875
876 @param max_test If > 0 no more than this number of tests are executed.
877 @param parent Must implement controller, dataplane, assertTrue, assertEqual
Rich Lane9a003812012-10-04 17:17:59 -0700878 and logging
Dan Talayco551befa2010-07-15 17:05:32 -0700879 @param pkt If not None, use this packet for ingress
880 @param wildcards For flow match entry
Rich Laned0478ff2013-03-11 12:46:58 -0700881 @param vlan_vid If not -1, and pkt is None, create a pkt w/ VLAN tag
Dan Talayco551befa2010-07-15 17:05:32 -0700882 @param exp_pkt If not None, use this as the expected output pkt; els use pkt
883 @param action_list Additional actions to add to flow mod
Dan Talaycocfa172f2012-03-23 12:03:00 -0700884 @param egr_count Number of egress ports; -1 means get from config w/ dflt 2
Dan Talayco551befa2010-07-15 17:05:32 -0700885 """
Ed Swierk99a74de2012-08-22 06:40:54 -0700886 if wildcards is None:
887 wildcards = required_wildcards(parent)
Dan Talayco551befa2010-07-15 17:05:32 -0700888 of_ports = port_map.keys()
889 of_ports.sort()
890 parent.assertTrue(len(of_ports) > 1, "Not enough ports for test")
891 test_count = 0
892
Dan Talaycocfa172f2012-03-23 12:03:00 -0700893 if egr_count == -1:
Rich Lane2014f9b2012-10-05 15:29:40 -0700894 egr_count = test_param_get('egr_count', default=2)
Dan Talaycocfa172f2012-03-23 12:03:00 -0700895
Dan Talayco551befa2010-07-15 17:05:32 -0700896 for ing_idx in range(len(of_ports)):
897 ingress_port = of_ports[ing_idx]
Dan Talaycof6e76c02012-03-23 10:56:12 -0700898 egr_ports = get_egr_list(parent, of_ports, egr_count,
899 exclude_list=[ingress_port])
Dan Talaycoc948d0b2012-03-23 12:17:54 -0700900 if ing_port:
Rich Lanee717c6e2013-03-12 10:25:50 -0700901 egr_ports.append(ofp.OFPP_IN_PORT)
Dan Talaycof6e76c02012-03-23 10:56:12 -0700902 if len(egr_ports) == 0:
903 parent.assertTrue(0, "Failed to generate egress port list")
904
905 flow_match_test_port_pair(parent, ingress_port, egr_ports,
Rich Laned0478ff2013-03-11 12:46:58 -0700906 wildcards=wildcards, vlan_vid=vlan_vid,
Dan Talaycof6e76c02012-03-23 10:56:12 -0700907 pkt=pkt, exp_pkt=exp_pkt,
Rich Lanee5779d32012-10-05 17:56:04 -0700908 action_list=action_list)
Dan Talaycof6e76c02012-03-23 10:56:12 -0700909 test_count += 1
910 if (max_test > 0) and (test_count > max_test):
Rich Lane9a003812012-10-04 17:17:59 -0700911 logging.info("Ran " + str(test_count) + " tests; exiting")
Rich Lane89725bb2012-12-03 16:23:27 -0800912 break
913
Ed Swierk38eea082013-01-02 19:46:20 -0800914 if not test_param_get('pktout_actions', default=True):
915 return
Rich Lane89725bb2012-12-03 16:23:27 -0800916
917 ingress_port = of_ports[0]
918 egr_ports = get_egr_list(parent, of_ports, egr_count,
919 exclude_list=[ingress_port])
920 if ing_port:
Rich Lanee717c6e2013-03-12 10:25:50 -0700921 egr_ports.append(ofp.OFPP_IN_PORT)
Rich Lane89725bb2012-12-03 16:23:27 -0800922 flow_match_test_pktout(parent, ingress_port, egr_ports,
Rich Laned0478ff2013-03-11 12:46:58 -0700923 vlan_vid=vlan_vid,
Rich Lane89725bb2012-12-03 16:23:27 -0800924 pkt=pkt, exp_pkt=exp_pkt,
925 action_list=action_list)
Dan Talayco551befa2010-07-15 17:05:32 -0700926
Rich Lane2014f9b2012-10-05 15:29:40 -0700927def test_param_get(key, default=None):
Dan Talayco4b2bee62010-07-20 14:10:05 -0700928 """
929 Return value passed via test-params if present
930
Dan Talayco4b2bee62010-07-20 14:10:05 -0700931 @param key The lookup key
932 @param default Default value to use if not found
933
934 If the pair 'key=val' appeared in the string passed to --test-params
935 on the command line, return val (as interpreted by exec). Otherwise
936 return default value.
Dan Talaycof6e76c02012-03-23 10:56:12 -0700937
938 WARNING: TEST PARAMETERS MUST BE PYTHON IDENTIFIERS;
939 eg egr_count, not egr-count.
Dan Talayco4b2bee62010-07-20 14:10:05 -0700940 """
941 try:
Rich Lanecd97d3d2013-01-07 18:50:06 -0800942 exec oftest.config["test_params"]
Dan Talayco4b2bee62010-07-20 14:10:05 -0700943 except:
944 return default
945
946 s = "val = " + str(key)
947 try:
948 exec s
949 return val
950 except:
951 return default
952
953def action_generate(parent, field_to_mod, mod_field_vals):
954 """
955 Create an action to modify the field indicated in field_to_mod
956
957 @param parent Must implement, assertTrue
958 @param field_to_mod The field to modify as a string name
959 @param mod_field_vals Hash of values to use for modified values
960 """
961
962 act = None
963
964 if field_to_mod in ['pktlen']:
965 return None
966
Rich Laned0478ff2013-03-11 12:46:58 -0700967 if field_to_mod == 'eth_dst':
Rich Lanee717c6e2013-03-12 10:25:50 -0700968 act = ofp.action.set_dl_dst()
Rich Lanef6883512013-03-11 17:00:09 -0700969 act.dl_addr = oftest.parse.parse_mac(mod_field_vals['eth_dst'])
Rich Laned0478ff2013-03-11 12:46:58 -0700970 elif field_to_mod == 'eth_src':
Rich Lanee717c6e2013-03-12 10:25:50 -0700971 act = ofp.action.set_dl_src()
Rich Lanef6883512013-03-11 17:00:09 -0700972 act.dl_addr = oftest.parse.parse_mac(mod_field_vals['eth_src'])
Dan Talayco4b2bee62010-07-20 14:10:05 -0700973 elif field_to_mod == 'dl_vlan_enable':
974 if not mod_field_vals['dl_vlan_enable']: # Strip VLAN tag
Rich Lanee717c6e2013-03-12 10:25:50 -0700975 act = ofp.action.strip_vlan()
Rich Laned0478ff2013-03-11 12:46:58 -0700976 # Add VLAN tag is handled by vlan_vid field
Dan Talayco4b2bee62010-07-20 14:10:05 -0700977 # Will return None in this case
Rich Laned0478ff2013-03-11 12:46:58 -0700978 elif field_to_mod == 'vlan_vid':
Rich Lanee717c6e2013-03-12 10:25:50 -0700979 act = ofp.action.set_vlan_vid()
Rich Laned0478ff2013-03-11 12:46:58 -0700980 act.vlan_vid = mod_field_vals['vlan_vid']
981 elif field_to_mod == 'vlan_pcp':
Rich Lanee717c6e2013-03-12 10:25:50 -0700982 act = ofp.action.set_vlan_pcp()
Rich Laned0478ff2013-03-11 12:46:58 -0700983 act.vlan_pcp = mod_field_vals['vlan_pcp']
Dan Talayco4b2bee62010-07-20 14:10:05 -0700984 elif field_to_mod == 'ip_src':
Rich Lanee717c6e2013-03-12 10:25:50 -0700985 act = ofp.action.set_nw_src()
Rich Lanef6883512013-03-11 17:00:09 -0700986 act.nw_addr = oftest.parse.parse_ip(mod_field_vals['ip_src'])
Dan Talayco4b2bee62010-07-20 14:10:05 -0700987 elif field_to_mod == 'ip_dst':
Rich Lanee717c6e2013-03-12 10:25:50 -0700988 act = ofp.action.set_nw_dst()
Rich Lanef6883512013-03-11 17:00:09 -0700989 act.nw_addr = oftest.parse.parse_ip(mod_field_vals['ip_dst'])
Dan Talayco4b2bee62010-07-20 14:10:05 -0700990 elif field_to_mod == 'ip_tos':
Rich Lanee717c6e2013-03-12 10:25:50 -0700991 act = ofp.action.set_nw_tos()
Dan Talayco4b2bee62010-07-20 14:10:05 -0700992 act.nw_tos = mod_field_vals['ip_tos']
993 elif field_to_mod == 'tcp_sport':
Rich Lanee717c6e2013-03-12 10:25:50 -0700994 act = ofp.action.set_tp_src()
Dan Talayco4b2bee62010-07-20 14:10:05 -0700995 act.tp_port = mod_field_vals['tcp_sport']
996 elif field_to_mod == 'tcp_dport':
Rich Lanee717c6e2013-03-12 10:25:50 -0700997 act = ofp.action.set_tp_dst()
Dan Talayco4b2bee62010-07-20 14:10:05 -0700998 act.tp_port = mod_field_vals['tcp_dport']
Rich Lane110e0e32012-10-26 16:21:46 -0700999 elif field_to_mod == 'udp_sport':
Rich Lanee717c6e2013-03-12 10:25:50 -07001000 act = ofp.action.set_tp_src()
Rich Lane110e0e32012-10-26 16:21:46 -07001001 act.tp_port = mod_field_vals['udp_sport']
1002 elif field_to_mod == 'udp_dport':
Rich Lanee717c6e2013-03-12 10:25:50 -07001003 act = ofp.action.set_tp_dst()
Rich Lane110e0e32012-10-26 16:21:46 -07001004 act.tp_port = mod_field_vals['udp_dport']
Dan Talayco4b2bee62010-07-20 14:10:05 -07001005 else:
1006 parent.assertTrue(0, "Unknown field to modify: " + str(field_to_mod))
1007
1008 return act
1009
1010def pkt_action_setup(parent, start_field_vals={}, mod_field_vals={},
Rich Lane110e0e32012-10-26 16:21:46 -07001011 mod_fields=[], tp="tcp", check_test_params=False):
Dan Talayco4b2bee62010-07-20 14:10:05 -07001012 """
1013 Set up the ingress and expected packet and action list for a test
1014
Rich Lane2014f9b2012-10-05 15:29:40 -07001015 @param parent Must implement assertTrue
Dan Talayco4b2bee62010-07-20 14:10:05 -07001016 @param start_field_values Field values to use for ingress packet (optional)
1017 @param mod_field_values Field values to use for modified packet (optional)
1018 @param mod_fields The list of fields to be modified by the switch in the test.
1019 @params check_test_params If True, will check the parameters vid, add_vlan
1020 and strip_vlan from the command line.
1021
1022 Returns a triple: pkt-to-send, expected-pkt, action-list
1023 """
1024
1025 new_actions = []
1026
Dan Talayco4b2bee62010-07-20 14:10:05 -07001027 base_pkt_params = {}
1028 base_pkt_params['pktlen'] = 100
Rich Laned0478ff2013-03-11 12:46:58 -07001029 base_pkt_params['eth_dst'] = '00:DE:F0:12:34:56'
1030 base_pkt_params['eth_src'] = '00:23:45:67:89:AB'
Dan Talayco4b2bee62010-07-20 14:10:05 -07001031 base_pkt_params['dl_vlan_enable'] = False
Rich Laned0478ff2013-03-11 12:46:58 -07001032 base_pkt_params['vlan_vid'] = 2
1033 base_pkt_params['vlan_pcp'] = 0
Dan Talayco4b2bee62010-07-20 14:10:05 -07001034 base_pkt_params['ip_src'] = '192.168.0.1'
1035 base_pkt_params['ip_dst'] = '192.168.0.2'
1036 base_pkt_params['ip_tos'] = 0
Rich Lane110e0e32012-10-26 16:21:46 -07001037 if tp == "tcp":
1038 base_pkt_params['tcp_sport'] = 1234
1039 base_pkt_params['tcp_dport'] = 80
1040 elif tp == "udp":
1041 base_pkt_params['udp_sport'] = 1234
1042 base_pkt_params['udp_dport'] = 80
Dan Talayco4b2bee62010-07-20 14:10:05 -07001043 for keyname in start_field_vals.keys():
1044 base_pkt_params[keyname] = start_field_vals[keyname]
1045
1046 mod_pkt_params = {}
1047 mod_pkt_params['pktlen'] = 100
Rich Laned0478ff2013-03-11 12:46:58 -07001048 mod_pkt_params['eth_dst'] = '00:21:0F:ED:CB:A9'
1049 mod_pkt_params['eth_src'] = '00:ED:CB:A9:87:65'
Dan Talayco4b2bee62010-07-20 14:10:05 -07001050 mod_pkt_params['dl_vlan_enable'] = False
Rich Laned0478ff2013-03-11 12:46:58 -07001051 mod_pkt_params['vlan_vid'] = 3
1052 mod_pkt_params['vlan_pcp'] = 7
Dan Talayco4b2bee62010-07-20 14:10:05 -07001053 mod_pkt_params['ip_src'] = '10.20.30.40'
1054 mod_pkt_params['ip_dst'] = '50.60.70.80'
1055 mod_pkt_params['ip_tos'] = 0xf0
Rich Lane110e0e32012-10-26 16:21:46 -07001056 if tp == "tcp":
1057 mod_pkt_params['tcp_sport'] = 4321
1058 mod_pkt_params['tcp_dport'] = 8765
1059 elif tp == "udp":
1060 mod_pkt_params['udp_sport'] = 4321
1061 mod_pkt_params['udp_dport'] = 8765
Dan Talayco4b2bee62010-07-20 14:10:05 -07001062 for keyname in mod_field_vals.keys():
1063 mod_pkt_params[keyname] = mod_field_vals[keyname]
1064
1065 # Check for test param modifications
1066 strip = False
1067 if check_test_params:
Rich Lane2014f9b2012-10-05 15:29:40 -07001068 add_vlan = test_param_get('add_vlan')
1069 strip_vlan = test_param_get('strip_vlan')
1070 vid = test_param_get('vid')
Dan Talayco4b2bee62010-07-20 14:10:05 -07001071
1072 if add_vlan and strip_vlan:
1073 parent.assertTrue(0, "Add and strip VLAN both specified")
1074
1075 if vid:
1076 base_pkt_params['dl_vlan_enable'] = True
Rich Laned0478ff2013-03-11 12:46:58 -07001077 base_pkt_params['vlan_vid'] = vid
1078 if 'vlan_vid' in mod_fields:
1079 mod_pkt_params['vlan_vid'] = vid + 1
Dan Talayco4b2bee62010-07-20 14:10:05 -07001080
1081 if add_vlan:
1082 base_pkt_params['dl_vlan_enable'] = False
1083 mod_pkt_params['dl_vlan_enable'] = True
1084 mod_pkt_params['pktlen'] = base_pkt_params['pktlen'] + 4
1085 mod_fields.append('pktlen')
1086 mod_fields.append('dl_vlan_enable')
Rich Laned0478ff2013-03-11 12:46:58 -07001087 if 'vlan_vid' not in mod_fields:
1088 mod_fields.append('vlan_vid')
Dan Talayco4b2bee62010-07-20 14:10:05 -07001089 elif strip_vlan:
1090 base_pkt_params['dl_vlan_enable'] = True
1091 mod_pkt_params['dl_vlan_enable'] = False
1092 mod_pkt_params['pktlen'] = base_pkt_params['pktlen'] - 4
1093 mod_fields.append('dl_vlan_enable')
1094 mod_fields.append('pktlen')
1095
Rich Lane110e0e32012-10-26 16:21:46 -07001096 if tp == "tcp":
1097 packet_builder = simple_tcp_packet
1098 elif tp == "udp":
1099 packet_builder = simple_udp_packet
1100 else:
1101 raise NotImplementedError("unknown transport protocol %s" % tp)
1102
Dan Talayco4b2bee62010-07-20 14:10:05 -07001103 # Build the ingress packet
Rich Lane110e0e32012-10-26 16:21:46 -07001104 ingress_pkt = packet_builder(**base_pkt_params)
Dan Talayco4b2bee62010-07-20 14:10:05 -07001105
1106 # Build the expected packet, modifying the indicated fields
1107 for item in mod_fields:
1108 base_pkt_params[item] = mod_pkt_params[item]
1109 act = action_generate(parent, item, mod_pkt_params)
1110 if act:
1111 new_actions.append(act)
1112
Rich Lane110e0e32012-10-26 16:21:46 -07001113 expected_pkt = packet_builder(**base_pkt_params)
Dan Talayco4b2bee62010-07-20 14:10:05 -07001114
1115 return (ingress_pkt, expected_pkt, new_actions)
Dan Talayco677c0b72011-08-23 22:53:38 -07001116
1117# Generate a simple "drop" flow mod
1118# If in_band is true, then only drop from first test port
1119def flow_mod_gen(port_map, in_band):
Rich Lanee717c6e2013-03-12 10:25:50 -07001120 request = ofp.message.flow_add()
1121 request.match.wildcards = ofp.OFPFW_ALL
Dan Talayco677c0b72011-08-23 22:53:38 -07001122 if in_band:
Rich Lanee717c6e2013-03-12 10:25:50 -07001123 request.match.wildcards = ofp.OFPFW_ALL - ofp.OFPFW_IN_PORT
Dan Talayco677c0b72011-08-23 22:53:38 -07001124 for of_port, ifname in port_map.items(): # Grab first port
1125 break
1126 request.match.in_port = of_port
1127 request.buffer_id = 0xffffffff
1128 return request
Dan Talaycoba3745c2010-07-21 21:51:08 -07001129
1130def skip_message_emit(parent, s):
1131 """
1132 Print out a 'skipped' message to stderr
1133
1134 @param s The string to print out to the log file
Dan Talaycoba3745c2010-07-21 21:51:08 -07001135 """
1136 global skipped_test_count
1137
1138 skipped_test_count += 1
Rich Lane9a003812012-10-04 17:17:59 -07001139 logging.info("Skipping: " + s)
Dan Talayco2940fdd2013-02-06 15:01:35 -08001140 if oftest.config["debug"] < logging.WARNING:
Dan Talaycoba3745c2010-07-21 21:51:08 -07001141 sys.stderr.write("(skipped) ")
1142 else:
1143 sys.stderr.write("(S)")
Dan Talayco677c0b72011-08-23 22:53:38 -07001144
Dan Talayco8a64e332012-03-28 14:53:20 -07001145
1146def all_stats_get(parent):
1147 """
1148 Get the aggregate stats for all flows in the table
1149 @param parent Test instance with controller connection and assert
1150 @returns dict with keys flows, packets, bytes, active (flows),
1151 lookups, matched
1152 """
Rich Lanee717c6e2013-03-12 10:25:50 -07001153 stat_req = ofp.message.aggregate_stats_request()
1154 stat_req.match = ofp.match()
1155 stat_req.match.wildcards = ofp.OFPFW_ALL
Dan Talayco8a64e332012-03-28 14:53:20 -07001156 stat_req.table_id = 0xff
Rich Lanee717c6e2013-03-12 10:25:50 -07001157 stat_req.out_port = ofp.OFPP_NONE
Dan Talayco8a64e332012-03-28 14:53:20 -07001158
1159 rv = {}
1160
Rich Lanec8aaa3e2012-07-26 19:28:02 -07001161 (reply, pkt) = parent.controller.transact(stat_req)
Rich Lane5fd6faf2013-03-11 13:30:20 -07001162 parent.assertTrue(len(reply.entries) == 1, "Did not receive flow stats reply")
Dan Talayco8a64e332012-03-28 14:53:20 -07001163
Rich Lane5fd6faf2013-03-11 13:30:20 -07001164 for obj in reply.entries:
Dan Talayco8a64e332012-03-28 14:53:20 -07001165 (rv["flows"], rv["packets"], rv["bytes"]) = (obj.flow_count,
1166 obj.packet_count, obj.byte_count)
1167 break
1168
Rich Lanee717c6e2013-03-12 10:25:50 -07001169 request = ofp.message.table_stats_request()
Rich Lanec8aaa3e2012-07-26 19:28:02 -07001170 (reply , pkt) = parent.controller.transact(request)
Dan Talayco8a64e332012-03-28 14:53:20 -07001171
1172
1173 (rv["active"], rv["lookups"], rv["matched"]) = (0,0,0)
Rich Lane5fd6faf2013-03-11 13:30:20 -07001174 for obj in reply.entries:
Dan Talayco8a64e332012-03-28 14:53:20 -07001175 rv["active"] += obj.active_count
1176 rv["lookups"] += obj.lookup_count
1177 rv["matched"] += obj.matched_count
1178
1179 return rv
Dan Talayco2baf8b52012-03-30 09:55:42 -07001180
Rich Lane7744e112013-01-11 17:23:57 -08001181_import_blacklist.add('FILTER')
Dan Talayco2baf8b52012-03-30 09:55:42 -07001182FILTER=''.join([(len(repr(chr(x)))==3) and chr(x) or '.'
1183 for x in range(256)])
1184
1185def hex_dump_buffer(src, length=16):
1186 """
1187 Convert src to a hex dump string and return the string
1188 @param src The source buffer
1189 @param length The number of bytes shown in each line
1190 @returns A string showing the hex dump
1191 """
Dan Talaycoc516fa02012-04-12 22:28:43 -07001192 result = ["\n"]
Dan Talayco2baf8b52012-03-30 09:55:42 -07001193 for i in xrange(0, len(src), length):
1194 chars = src[i:i+length]
1195 hex = ' '.join(["%02x" % ord(x) for x in chars])
1196 printable = ''.join(["%s" % ((ord(x) <= 127 and
1197 FILTER[ord(x)]) or '.') for x in chars])
1198 result.append("%04x %-*s %s\n" % (i, length*3, hex, printable))
1199 return ''.join(result)
1200
1201def format_packet(pkt):
1202 return "Packet length %d \n%s" % (len(str(pkt)),
1203 hex_dump_buffer(str(pkt)))
Rich Lane5d7e89a2012-10-26 16:43:13 -07001204
1205def inspect_packet(pkt):
1206 """
1207 Wrapper around scapy's show() method.
1208 @returns A string showing the dissected packet.
1209 """
1210 from cStringIO import StringIO
1211 out = None
1212 backup = sys.stdout
1213 try:
1214 sys.stdout = StringIO()
1215 pkt.show2()
1216 out = sys.stdout.getvalue()
1217 sys.stdout.close()
1218 finally:
1219 sys.stdout = backup
1220 return out
Rich Lane0a4f6372013-01-02 14:40:22 -08001221
1222def nonstandard(cls):
1223 """
Rich Lanecc45b8e2013-01-02 15:55:02 -08001224 Testcase decorator that marks the test as being non-standard.
1225 These tests are not automatically added to the "standard" group.
Rich Lane0a4f6372013-01-02 14:40:22 -08001226 """
Rich Lanecc45b8e2013-01-02 15:55:02 -08001227 cls._nonstandard = True
Rich Lane0a4f6372013-01-02 14:40:22 -08001228 return cls
1229
1230def disabled(cls):
1231 """
Rich Lanecc45b8e2013-01-02 15:55:02 -08001232 Testcase decorator that marks the test as being disabled.
1233 These tests are not automatically added to the "standard" group or
1234 their module's group.
Rich Lane0a4f6372013-01-02 14:40:22 -08001235 """
Rich Lanecc45b8e2013-01-02 15:55:02 -08001236 cls._disabled = True
Rich Lane0a4f6372013-01-02 14:40:22 -08001237 return cls
Rich Lane97e99652013-01-02 17:23:20 -08001238
1239def group(name):
1240 """
1241 Testcase decorator that adds the test to a group.
1242 """
1243 def fn(cls):
1244 if not hasattr(cls, "_groups"):
1245 cls._groups = []
1246 cls._groups.append(name)
1247 return cls
1248 return fn
Rich Lane5a9a1922013-01-11 14:29:30 -08001249
1250def version(ver):
1251 """
1252 Testcase decorator that specifies which versions of OpenFlow the test
1253 supports. The default is 1.0+. This decorator may only be used once.
1254
1255 Supported syntax:
1256 1.0 -> 1.0
1257 1.0,1.2,1.3 -> 1.0, 1.2, 1.3
1258 1.0+ -> 1.0, 1.1, 1.2, 1.3
1259 """
1260 versions = parse_version(ver)
1261 def fn(cls):
1262 cls._versions = versions
1263 return cls
1264 return fn
1265
1266def parse_version(ver):
1267 allowed_versions = ["1.0", "1.1", "1.2", "1.3"]
1268 if re.match("^1\.\d+$", ver):
1269 versions = set([ver])
1270 elif re.match("^(1\.\d+)\+$", ver):
1271 if not ver[:-1] in allowed_versions:
1272 raise ValueError("invalid OpenFlow version %s" % ver[:-1])
1273 versions = set()
1274 if ver != "1.1+": versions.add("1.0")
1275 if ver != "1.2+": versions.add("1.1")
1276 if ver != "1.3+": versions.add("1.2")
1277 versions.add("1.3")
1278 else:
1279 versions = set(ver.split(','))
1280
1281 for version in versions:
1282 if not version in allowed_versions:
1283 raise ValueError("invalid OpenFlow version %s" % version)
1284
1285 return versions
1286
1287assert(parse_version("1.0") == set(["1.0"]))
1288assert(parse_version("1.0,1.2,1.3") == set(["1.0", "1.2", "1.3"]))
1289assert(parse_version("1.0+") == set(["1.0", "1.1", "1.2", "1.3"]))
Rich Lane7744e112013-01-11 17:23:57 -08001290
Rich Laneae3428c2013-03-07 14:37:42 -08001291def get_stats(test, req):
1292 """
1293 Retrieve a list of stats entries. Handles OFPSF_REPLY_MORE.
1294 """
Rich Lanebd56ed62013-07-10 15:49:44 -07001295 if ofp.OFP_VERSION <= 3:
1296 more_flag = ofp.OFPSF_REPLY_MORE
1297 else:
1298 more_flag = ofp.OFPMPF_REPLY_MORE
Rich Laneae3428c2013-03-07 14:37:42 -08001299 stats = []
1300 reply, _ = test.controller.transact(req)
1301 test.assertTrue(reply is not None, "No response to stats request")
Rich Lane5fd6faf2013-03-11 13:30:20 -07001302 stats.extend(reply.entries)
Rich Lanebd56ed62013-07-10 15:49:44 -07001303 while reply.flags & more_flag != 0:
Rich Lanee717c6e2013-03-12 10:25:50 -07001304 reply, pkt = self.controller.poll(exp_msg=ofp.OFPT_STATS_REPLY)
Rich Laneae3428c2013-03-07 14:37:42 -08001305 test.assertTrue(reply is not None, "No response to stats request")
Rich Lane5fd6faf2013-03-11 13:30:20 -07001306 stats.extend(reply.entries)
Rich Laneae3428c2013-03-07 14:37:42 -08001307 return stats
1308
Rich Lanebd56ed62013-07-10 15:49:44 -07001309def get_flow_stats(test, match, table_id=None,
1310 out_port=None, out_group=None,
1311 cookie=0, cookie_mask=0):
Rich Laneae3428c2013-03-07 14:37:42 -08001312 """
1313 Retrieve a list of flow stats entries.
1314 """
Rich Lanebd56ed62013-07-10 15:49:44 -07001315
1316 if table_id == None:
1317 if ofp.OFP_VERSION <= 2:
1318 table_id = 0xff
1319 else:
1320 table_id = ofp.OFPTT_ALL
1321
Rich Lanef3bc48c2013-05-03 17:39:35 -07001322 if out_port == None:
Rich Lanebd56ed62013-07-10 15:49:44 -07001323 if ofp.OFP_VERSION == 1:
1324 out_port = ofp.OFPP_NONE
1325 else:
1326 out_port = ofp.OFPP_ANY
1327
1328 if out_group == None:
1329 if ofp.OFP_VERSION > 1:
1330 out_group = ofp.OFPP_ANY
1331
Rich Lanee717c6e2013-03-12 10:25:50 -07001332 req = ofp.message.flow_stats_request(match=match,
Rich Lanebd56ed62013-07-10 15:49:44 -07001333 table_id=table_id,
1334 out_port=out_port)
1335 if ofp.OFP_VERSION > 1:
1336 req.out_group = out_group
1337 req.cookie = cookie
1338 req.cookie_mask = cookie_mask
1339
Rich Laneae3428c2013-03-07 14:37:42 -08001340 return get_stats(test, req)
1341
Rich Lane968b6192013-03-07 15:34:43 -08001342def get_port_stats(test, port_no):
1343 """
1344 Retrieve a list of port stats entries.
1345 """
Rich Lanee717c6e2013-03-12 10:25:50 -07001346 req = ofp.message.port_stats_request(port_no=port_no)
Rich Lane968b6192013-03-07 15:34:43 -08001347 return get_stats(test, req)
1348
Rich Lane6a334922013-03-07 16:14:52 -08001349def get_queue_stats(test, port_no, queue_id):
1350 """
1351 Retrieve a list of queue stats entries.
1352 """
Rich Lanee717c6e2013-03-12 10:25:50 -07001353 req = ofp.message.queue_stats_request(port_no=port_no, queue_id=queue_id)
Rich Lane6a334922013-03-07 16:14:52 -08001354 return get_stats(test, req)
1355
Rich Laneae3428c2013-03-07 14:37:42 -08001356def verify_flow_stats(test, match, table_id=0xff,
Rich Lanef3bc48c2013-05-03 17:39:35 -07001357 out_port=None,
Rich Laneae3428c2013-03-07 14:37:42 -08001358 initial=[],
1359 pkts=None, bytes=None):
1360 """
1361 Verify that flow stats changed as expected.
1362
1363 Optionally takes an 'initial' list of stats entries, as returned by
1364 get_flow_stats(). If 'initial' is not given the counters are assumed to
1365 begin at 0.
1366 """
Rich Lanef3bc48c2013-05-03 17:39:35 -07001367 if out_port == None:
1368 out_port = ofp.OFPP_NONE
1369
Rich Laneae3428c2013-03-07 14:37:42 -08001370 def accumulate(stats):
1371 pkts_acc = bytes_acc = 0
1372 for stat in stats:
1373 pkts_acc += stat.packet_count
1374 bytes_acc += stat.byte_count
1375 return (pkts_acc, bytes_acc)
1376
1377 pkts_before, bytes_before = accumulate(initial)
1378
1379 # Wait 10s for counters to update
1380 pkt_diff = byte_diff = None
1381 for i in range(0, 100):
1382 stats = get_flow_stats(test, match, table_id=table_id, out_port=out_port)
1383 pkts_after, bytes_after = accumulate(stats)
1384 pkt_diff = pkts_after - pkts_before
1385 byte_diff = bytes_after - bytes_before
1386 if (pkts == None or pkt_diff >= pkts) and \
1387 (bytes == None or byte_diff >= bytes):
1388 break
Dan Talayco53724732013-03-08 23:54:02 -08001389 time.sleep(0.1)
Rich Laneae3428c2013-03-07 14:37:42 -08001390
1391 if pkts != None:
1392 test.assertEquals(pkt_diff, pkts, "Flow packet counter not updated properly (expected increase of %d, got increase of %d)" % (pkts, pkt_diff))
1393
1394 if bytes != None:
Rich Lane53b96812013-03-07 16:54:50 -08001395 test.assertTrue(byte_diff >= bytes and byte_diff <= bytes*1.1,
1396 "Flow byte counter not updated properly (expected increase of %d, got increase of %d)" % (bytes, byte_diff))
Rich Laneae3428c2013-03-07 14:37:42 -08001397
Rich Lane968b6192013-03-07 15:34:43 -08001398def verify_port_stats(test, port,
1399 initial=[],
1400 tx_pkts=None, rx_pkts=None,
1401 tx_bytes=None, rx_bytes=None):
1402 """
1403 Verify that port stats changed as expected.
1404
1405 Optionally takes an 'initial' list of stats entries, as returned by
1406 get_port_stats(). If 'initial' is not given the counters are assumed to
1407 begin at 0.
1408 """
1409 def accumulate(stats):
1410 tx_pkts_acc = rx_pkts_acc = tx_bytes_acc = rx_bytes_acc = 0
1411 for stat in stats:
1412 tx_pkts_acc += stat.tx_packets
1413 rx_pkts_acc += stat.rx_packets
1414 tx_bytes_acc += stat.tx_bytes
1415 rx_bytes_acc += stat.rx_bytes
1416 return (tx_pkts_acc, rx_pkts_acc, tx_bytes_acc, rx_bytes_acc)
1417
1418 tx_pkts_before, rx_pkts_before, \
1419 tx_bytes_before, rx_bytes_before = accumulate(initial)
1420
1421 # Wait 10s for counters to update
1422 for i in range(0, 100):
1423 stats = get_port_stats(test, port)
1424 tx_pkts_after, rx_pkts_after, \
1425 tx_bytes_after, rx_bytes_after = accumulate(stats)
1426 tx_pkts_diff = tx_pkts_after - tx_pkts_before
1427 rx_pkts_diff = rx_pkts_after - rx_pkts_before
1428 tx_bytes_diff = tx_bytes_after - tx_bytes_before
1429 rx_bytes_diff = rx_bytes_after - rx_bytes_before
1430 if (tx_pkts == None or tx_pkts == tx_pkts_diff) and \
1431 (rx_pkts == None or rx_pkts == rx_pkts_diff) and \
Rich Lane53b96812013-03-07 16:54:50 -08001432 (tx_bytes == None or tx_bytes <= tx_bytes_diff) and \
1433 (rx_bytes == None or rx_bytes <= rx_bytes_diff):
Rich Lane968b6192013-03-07 15:34:43 -08001434 break
1435 time.sleep(0.1)
1436
1437 if (tx_pkts != None):
1438 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))
1439 if (rx_pkts != None):
1440 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))
1441 if (tx_bytes != None):
Rich Lane53b96812013-03-07 16:54:50 -08001442 test.assertTrue(tx_bytes_diff >= tx_bytes and tx_bytes_diff <= tx_bytes*1.1,
1443 "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 -08001444 if (rx_bytes != None):
Rich Lane53b96812013-03-07 16:54:50 -08001445 test.assertTrue(rx_bytes_diff >= rx_bytes and rx_bytes_diff <= rx_bytes*1.1,
1446 "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 -08001447
Rich Lane6a334922013-03-07 16:14:52 -08001448def verify_queue_stats(test, port_no, queue_id,
1449 initial=[],
1450 pkts=None, bytes=None):
1451 """
1452 Verify that queue stats changed as expected.
1453
1454 Optionally takes an 'initial' list of stats entries, as returned by
1455 get_queue_stats(). If 'initial' is not given the counters are assumed to
1456 begin at 0.
1457 """
1458 def accumulate(stats):
1459 pkts_acc = bytes_acc = 0
1460 for stat in stats:
1461 pkts_acc += stat.tx_packets
1462 bytes_acc += stat.tx_bytes
1463 return (pkts_acc, bytes_acc)
1464
1465 pkts_before, bytes_before = accumulate(initial)
1466
1467 # Wait 10s for counters to update
1468 pkt_diff = byte_diff = None
1469 for i in range(0, 100):
1470 stats = get_queue_stats(test, port_no, queue_id)
1471 pkts_after, bytes_after = accumulate(stats)
1472 pkt_diff = pkts_after - pkts_before
1473 byte_diff = bytes_after - bytes_before
1474 if (pkts == None or pkt_diff >= pkts) and \
1475 (bytes == None or byte_diff >= bytes):
1476 break
Dan Talayco53724732013-03-08 23:54:02 -08001477 time.sleep(0.1)
Rich Lane6a334922013-03-07 16:14:52 -08001478
1479 if pkts != None:
1480 test.assertEquals(pkt_diff, pkts, "Queue packet counter not updated properly (expected increase of %d, got increase of %d)" % (pkts, pkt_diff))
1481
1482 if bytes != None:
Rich Lane53b96812013-03-07 16:54:50 -08001483 test.assertTrue(byte_diff >= bytes and byte_diff <= bytes*1.1,
1484 "Queue byte counter not updated properly (expected increase of %d, got increase of %d)" % (bytes, byte_diff))
Rich Laneae3428c2013-03-07 14:37:42 -08001485
Rich Lane4c504f32013-06-07 17:24:14 -07001486def packet_in_match(msg, data, in_port=None, reason=None):
1487 """
1488 Check whether the packet_in message 'msg' has fields matching 'data',
1489 'in_port', and 'reason'.
1490
1491 This function handles truncated packet_in data. The 'in_port' and 'reason'
1492 parameters are optional.
1493
1494 @param msg packet_in message
1495 @param data Expected packet_in data
1496 @param in_port Expected packet_in in_port, or None
1497 @param reason Expected packet_in reason, or None
1498 """
1499
Rich Lanec0d26dd2013-07-10 12:46:03 -07001500 if ofp.OFP_VERSION <= 2:
1501 pkt_in_port = msg.in_port
1502 else:
1503 oxms = { type(oxm): oxm for oxm in msg.match.oxm_list }
1504 if ofp.oxm.in_port in oxms:
1505 pkt_in_port = oxms[ofp.oxm.in_port].value
1506 else:
1507 logging.warn("Missing in_port in packet-in message")
1508 pkt_in_port = None
1509
1510 if in_port != None and in_port != pkt_in_port:
Rich Lane4c504f32013-06-07 17:24:14 -07001511 logging.debug("Incorrect packet_in in_port (expected %d, received %d)", in_port, msg.in_port)
1512 return False
1513
Rich Lanec0d26dd2013-07-10 12:46:03 -07001514 if reason != None and reason != msg.reason:
Rich Lane4c504f32013-06-07 17:24:14 -07001515 logging.debug("Incorrect packet_in reason (expected %d, received %d)", reason, msg.reason)
1516 return False
1517
1518 # Check that one of the packets is a prefix of the other.
1519 # The received packet may be either truncated or padded, but not both.
1520 # (Some of the padding may be truncated but that's irrelevant). We
1521 # need to check that the smaller packet is a prefix of the larger one.
1522 # Note that this check succeeds if the switch sends a zero-length
1523 # packet-in.
1524 compare_len = min(len(msg.data), len(data))
1525 if data[:compare_len] != msg.data[:compare_len]:
1526 logging.debug("Incorrect packet_in data")
1527 logging.debug("Expected %s" % format_packet(data[:compare_len]))
1528 logging.debug("Received %s" % format_packet(msg.data[:compare_len]))
1529 return False
1530
1531 return True
1532
1533def verify_packet_in(test, data, in_port, reason, controller=None):
1534 """
1535 Assert that the controller receives a packet_in message matching data 'data'
1536 from port 'in_port' with reason 'reason'. Does not trigger the packet_in
1537 itself, that's up to the test case.
1538
1539 @param test Instance of base_tests.SimpleProtocol
1540 @param pkt String to expect as the packet_in data
1541 @param in_port OpenFlow port number to expect as the packet_in in_port
1542 @param reason One of OFPR_* to expect as the packet_in reason
1543 @param controller Controller instance, defaults to test.controller
1544 @returns The received packet-in message
1545 """
1546
1547 if controller == None:
1548 controller = test.controller
1549
1550 end_time = time.time() + oftest.ofutils.default_timeout
1551
1552 while True:
1553 msg, _ = controller.poll(ofp.OFPT_PACKET_IN, end_time - time.time())
1554 if not msg:
1555 # Timeout
1556 break
1557 elif packet_in_match(msg, data, in_port, reason):
1558 # Found a matching message
1559 break
1560
1561 test.assertTrue(msg is not None, 'Packet in message not received on port %d' % in_port)
1562 return msg
1563
1564def verify_no_packet_in(test, data, in_port, controller=None):
1565 """
1566 Assert that the controller does not receive a packet_in message matching
1567 data 'data' from port 'in_port'.
1568
1569 @param test Instance of base_tests.SimpleProtocol
1570 @param pkt String to expect as the packet_in data
1571 @param in_port OpenFlow port number to expect as the packet_in in_port
1572 @param controller Controller instance, defaults to test.controller
1573 """
1574
1575 if controller == None:
1576 controller = test.controller
1577
1578 # Negative test, need to wait a short amount of time before checking we
1579 # didn't receive the message.
1580 time.sleep(0.5)
1581
1582 # Check every packet_in queued in the controller
1583 while True:
1584 msg, _ = controller.poll(ofp.OFPT_PACKET_IN, timeout=0)
1585 if msg == None:
1586 # No more queued packet_in messages
1587 break
1588 elif packet_in_match(msg, data, in_port, None):
1589 # Found a matching message
1590 break
1591
1592 test.assertTrue(msg == None, "Did not expect a packet-in message on port %d" % in_port)
1593
Rich Lane045db072013-08-06 13:16:30 -07001594def openflow_ports(num=None):
1595 """
1596 Return a list of 'num' OpenFlow port numbers
1597
1598 If 'num' is None, return all available ports. Otherwise, limit the length
1599 of the result to 'num' and raise an exception if not enough ports are
1600 available.
1601 """
1602 ports = sorted(oftest.config["port_map"].keys())
1603 if num != None and len(ports) < num:
1604 raise Exception("test requires %d ports but only %d are available" % (num, len(ports)))
1605 return ports[:num]
1606
Rich Lane7744e112013-01-11 17:23:57 -08001607__all__ = list(set(locals()) - _import_blacklist)