blob: dad521d0631db514d75a72d8978b6abe50735f17 [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,
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700295 icmp_type=8,
296 icmp_code=0
297 ):
298 """
299 Return a simple ICMP packet
300
301 Supports a few parameters:
302 @param len Length of packet in bytes w/o CRC
Rich Laned0478ff2013-03-11 12:46:58 -0700303 @param eth_dst Destinatino MAC
304 @param eth_src Source MAC
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700305 @param dl_vlan_enable True if the packet is with vlan, False otherwise
Rich Laned0478ff2013-03-11 12:46:58 -0700306 @param vlan_vid VLAN ID
307 @param vlan_pcp VLAN priority
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700308 @param ip_src IP source
309 @param ip_dst IP destination
310 @param ip_tos IP ToS
Gregor Maier9cc93342013-01-29 16:55:28 -0800311 @param ip_ttl IP TTL
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700312 @param icmp_type ICMP type
313 @param icmp_code ICMP code
314
315 Generates a simple ICMP ECHO REQUEST. Users
316 shouldn't assume anything about this packet other than that
317 it is a valid ethernet/ICMP frame.
318 """
Jeffrey Townsend5cb7ed32012-08-17 18:11:01 +0000319
320 if MINSIZE > pktlen:
321 pktlen = MINSIZE
322
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700323 if (dl_vlan_enable):
Rich Laned0478ff2013-03-11 12:46:58 -0700324 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
325 scapy.Dot1Q(prio=vlan_pcp, id=0, vlan=vlan_vid)/ \
Gregor Maier9cc93342013-01-29 16:55:28 -0800326 scapy.IP(src=ip_src, dst=ip_dst, ttl=ip_ttl, tos=ip_tos)/ \
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700327 scapy.ICMP(type=icmp_type, code=icmp_code)
328 else:
Rich Laned0478ff2013-03-11 12:46:58 -0700329 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
Gregor Maier9cc93342013-01-29 16:55:28 -0800330 scapy.IP(src=ip_src, dst=ip_dst, ttl=ip_ttl, tos=ip_tos)/ \
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700331 scapy.ICMP(type=icmp_type, code=icmp_code)
332
333 pkt = pkt/("0" * (pktlen - len(pkt)))
334
335 return pkt
336
Rich Lane86aceb02013-07-17 18:45:38 -0700337def simple_icmpv6_packet(pktlen=100,
338 eth_dst='00:01:02:03:04:05',
339 eth_src='00:06:07:08:09:0a',
340 dl_vlan_enable=False,
341 vlan_vid=0,
342 vlan_pcp=0,
343 ipv6_src='2001:db8:85a3::8a2e:370:7334',
344 ipv6_dst='2001:db8:85a3::8a2e:370:7335',
345 ipv6_tc=0,
346 ipv6_hlim=64,
347 ipv6_fl=0,
348 icmp_type=8,
349 icmp_code=0):
350 """
351 Return a simple ICMPv6 packet
352
353 Supports a few parameters:
354 @param len Length of packet in bytes w/o CRC
355 @param eth_dst Destination MAC
356 @param eth_src Source MAC
357 @param dl_vlan_enable True if the packet is with vlan, False otherwise
358 @param vlan_vid VLAN ID
359 @param vlan_pcp VLAN priority
360 @param ipv6_src IPv6 source
361 @param ipv6_dst IPv6 destination
362 @param ipv6_tc IPv6 traffic class
363 @param ipv6_ttl IPv6 hop limit
364 @param ipv6_fl IPv6 flow label
365 @param icmp_type ICMP type
366 @param icmp_code ICMP code
367
368 Generates a simple ICMP ECHO REQUEST. Users shouldn't assume anything
369 about this packet other than that it is a valid ethernet/IPv6/ICMP frame.
370 """
371
372 if MINSIZE > pktlen:
373 pktlen = MINSIZE
374
375 pkt = scapy.Ether(dst=eth_dst, src=eth_src)
376 if dl_vlan_enable or vlan_vid or vlan_pcp:
377 pkt /= scapy.Dot1Q(vlan=vlan_vid, prio=vlan_pcp)
378 pkt /= scapy.IPv6(src=ipv6_src, dst=ipv6_dst, fl=ipv6_fl, tc=ipv6_tc, hlim=ipv6_hlim)
379 pkt /= scapy.ICMPv6Unknown(type=icmp_type, code=icmp_code)
380 pkt /= ("D" * (pktlen - len(pkt)))
381
382 return pkt
383
Shudong Zhouc7562b12013-02-06 01:12:18 -0800384def simple_arp_packet(pktlen=60,
Rich Laned0478ff2013-03-11 12:46:58 -0700385 eth_dst='ff:ff:ff:ff:ff:ff',
386 eth_src='00:06:07:08:09:0a',
Rich Lanee01611f2014-01-15 14:55:11 -0800387 vlan_vid=0,
388 vlan_pcp=0,
Shudong Zhouc7562b12013-02-06 01:12:18 -0800389 arp_op=1,
390 ip_snd='192.168.0.1',
391 ip_tgt='192.168.0.2',
392 hw_snd='00:06:07:08:09:0a',
393 hw_tgt='00:00:00:00:00:00',
394 ):
395 """
396 Return a simple ARP packet
397
398 Supports a few parameters:
399 @param len Length of packet in bytes w/o CRC
Rich Laned0478ff2013-03-11 12:46:58 -0700400 @param eth_dst Destinatino MAC
401 @param eth_src Source MAC
Shudong Zhouc7562b12013-02-06 01:12:18 -0800402 @param arp_op Operation (1=request, 2=reply)
403 @param ip_snd Sender IP
404 @param ip_tgt Target IP
405 @param hw_snd Sender hardware address
406 @param hw_tgt Target hardware address
407
408 Generates a simple ARP REQUEST. Users
409 shouldn't assume anything about this packet other than that
410 it is a valid ethernet/ARP frame.
411 """
412
413 if MINSIZE > pktlen:
414 pktlen = MINSIZE
415
Rich Lanee01611f2014-01-15 14:55:11 -0800416 pkt = scapy.Ether(dst=eth_dst, src=eth_src)
417 if vlan_vid or vlan_pcp:
418 pkt /= scapy.Dot1Q(vlan=vlan_vid, prio=vlan_pcp)
419 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 -0800420
421 pkt = pkt/("0" * (pktlen - len(pkt)))
422
423 return pkt
424
Ed Swierk0aeff8c2012-03-23 20:27:18 -0700425def simple_eth_packet(pktlen=60,
Rich Lane53275082013-11-18 23:26:22 -0800426 eth_dst='00:01:02:03:04:05',
427 eth_src='00:06:07:08:09:0a',
Rich Laned0478ff2013-03-11 12:46:58 -0700428 eth_type=0x88cc):
Jeffrey Townsend5cb7ed32012-08-17 18:11:01 +0000429
430 if MINSIZE > pktlen:
431 pktlen = MINSIZE
432
Rich Laned0478ff2013-03-11 12:46:58 -0700433 pkt = scapy.Ether(dst=eth_dst, src=eth_src, type=eth_type)
Ed Swierk0aeff8c2012-03-23 20:27:18 -0700434
435 pkt = pkt/("0" * (pktlen - len(pkt)))
436
437 return pkt
438
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800439def qinq_tcp_packet(pktlen=100,
Rich Laned0478ff2013-03-11 12:46:58 -0700440 eth_dst='00:01:02:03:04:05',
441 eth_src='00:06:07:08:09:0a',
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800442 dl_vlan_outer=20,
443 dl_vlan_pcp_outer=0,
444 dl_vlan_cfi_outer=0,
Rich Laned0478ff2013-03-11 12:46:58 -0700445 vlan_vid=10,
446 vlan_pcp=0,
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800447 dl_vlan_cfi=0,
448 ip_src='192.168.0.1',
449 ip_dst='192.168.0.2',
450 ip_tos=0,
Gregor Maier9cc93342013-01-29 16:55:28 -0800451 ip_ttl=64,
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800452 tcp_sport=1234,
453 tcp_dport=80,
454 ip_ihl=None,
455 ip_options=False
456 ):
457 """
458 Return a doubly tagged dataplane TCP packet
459
460 Supports a few parameters:
461 @param len Length of packet in bytes w/o CRC
Rich Laned0478ff2013-03-11 12:46:58 -0700462 @param eth_dst Destinatino MAC
463 @param eth_src Source MAC
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800464 @param dl_vlan_outer Outer VLAN ID
465 @param dl_vlan_pcp_outer Outer VLAN priority
466 @param dl_vlan_cfi_outer Outer VLAN cfi bit
Rich Laned0478ff2013-03-11 12:46:58 -0700467 @param vlan_vid Inner VLAN ID
468 @param vlan_pcp VLAN priority
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800469 @param dl_vlan_cfi VLAN cfi bit
470 @param ip_src IP source
471 @param ip_dst IP destination
472 @param ip_tos IP ToS
473 @param tcp_dport TCP destination port
474 @param ip_sport TCP source port
475
476 Generates a TCP request. Users
477 shouldn't assume anything about this packet other than that
478 it is a valid ethernet/IP/TCP frame.
479 """
480
481 if MINSIZE > pktlen:
482 pktlen = MINSIZE
483
484 # Note Dot1Q.id is really CFI
Rich Laned0478ff2013-03-11 12:46:58 -0700485 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800486 scapy.Dot1Q(prio=dl_vlan_pcp_outer, id=dl_vlan_cfi_outer, vlan=dl_vlan_outer)/ \
Rich Laned0478ff2013-03-11 12:46:58 -0700487 scapy.Dot1Q(prio=vlan_pcp, id=dl_vlan_cfi, vlan=vlan_vid)/ \
Gregor Maier9cc93342013-01-29 16:55:28 -0800488 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ttl=ip_ttl, ihl=ip_ihl)/ \
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800489 scapy.TCP(sport=tcp_sport, dport=tcp_dport)
490
491 pkt = pkt/("D" * (pktlen - len(pkt)))
492
493 return pkt
494
Shudong Zhoub7f12462012-11-20 13:01:12 -0800495def do_barrier(ctrl, timeout=-1):
Dan Talayco0fc08bd2012-04-09 16:56:18 -0700496 """
497 Do a barrier command
498 Return 0 on success, -1 on error
499 """
Rich Lanee717c6e2013-03-12 10:25:50 -0700500 b = ofp.message.barrier_request()
Shudong Zhoub7f12462012-11-20 13:01:12 -0800501 (resp, pkt) = ctrl.transact(b, timeout=timeout)
Rich Lane3a261d52013-01-03 17:45:08 -0800502 if resp is None:
503 raise AssertionError("barrier failed")
Dan Talaycof6b94832012-04-12 21:50:57 -0700504 # We'll trust the transaction processing in the controller that xid matched
Rich Lane3a261d52013-01-03 17:45:08 -0800505 return 0 # for backwards compatibility
Dan Talayco92c99122010-06-03 13:53:18 -0700506
Rich Lane9a003812012-10-04 17:17:59 -0700507def port_config_get(controller, port_no):
Dan Talayco92c99122010-06-03 13:53:18 -0700508 """
509 Get a port's configuration
510
511 Gets the switch feature configuration and grabs one port's
512 configuration
513
514 @returns (hwaddr, config, advert) The hwaddress, configuration and
515 advertised values
516 """
Rich Lane6dc865c2013-07-10 10:12:13 -0700517
518 if ofp.OFP_VERSION <= 3:
519 request = ofp.message.features_request()
520 reply, _ = controller.transact(request)
521 if reply is None:
522 logging.warn("Get feature request failed")
523 return None, None, None
524 logging.debug(reply.show())
525 ports = reply.ports
526 else:
527 request = ofp.message.port_desc_stats_request()
528 # TODO do multipart correctly
529 reply, _ = controller.transact(request)
530 if reply is None:
531 logging.warn("Port desc stats request failed")
532 return None, None, None
533 logging.debug(reply.show())
534 ports = reply.entries
535
536 for port in ports:
537 if port.port_no == port_no:
538 return (port.hw_addr, port.config, port.advertised)
Dan Talayco92c99122010-06-03 13:53:18 -0700539
Rich Lane9a003812012-10-04 17:17:59 -0700540 logging.warn("Did not find port number for port config")
Dan Talayco92c99122010-06-03 13:53:18 -0700541 return None, None, None
542
Rich Lane9a003812012-10-04 17:17:59 -0700543def port_config_set(controller, port_no, config, mask):
Dan Talayco92c99122010-06-03 13:53:18 -0700544 """
545 Set the port configuration according the given parameters
546
547 Gets the switch feature configuration and updates one port's
548 configuration value according to config and mask
549 """
Rich Lane9a003812012-10-04 17:17:59 -0700550 logging.info("Setting port " + str(port_no) + " to config " + str(config))
Rich Lane6dc865c2013-07-10 10:12:13 -0700551
552 hw_addr, _, _ = port_config_get(controller, port_no)
553
Rich Lanee717c6e2013-03-12 10:25:50 -0700554 mod = ofp.message.port_mod()
Dan Talayco92c99122010-06-03 13:53:18 -0700555 mod.port_no = port_no
Rich Lane6dc865c2013-07-10 10:12:13 -0700556 if hw_addr != None:
557 mod.hw_addr = hw_addr
Dan Talayco92c99122010-06-03 13:53:18 -0700558 mod.config = config
559 mod.mask = mask
Rich Lane6dc865c2013-07-10 10:12:13 -0700560 mod.advertise = 0 # No change
Rich Lane5c3151c2013-01-03 17:15:41 -0800561 controller.message_send(mod)
562 return 0
Dan Talayco92c99122010-06-03 13:53:18 -0700563
Rich Lane2014f9b2012-10-05 15:29:40 -0700564def receive_pkt_check(dp, pkt, yes_ports, no_ports, assert_if):
Dan Talayco92c99122010-06-03 13:53:18 -0700565 """
566 Check for proper receive packets across all ports
Ken Chiang1bf01602012-04-04 10:48:23 -0700567 @param dp The dataplane object
Dan Talayco92c99122010-06-03 13:53:18 -0700568 @param pkt Expected packet; may be None if yes_ports is empty
569 @param yes_ports Set or list of ports that should recieve packet
570 @param no_ports Set or list of ports that should not receive packet
571 @param assert_if Object that implements assertXXX
Rich Lanee4b384d2013-09-13 14:33:40 -0700572
573 DEPRECATED in favor in verify_packets
Dan Talayco92c99122010-06-03 13:53:18 -0700574 """
Rich Lane91765672012-12-06 16:33:04 -0800575
576 # Wait this long for packets that we don't expect to receive.
577 # 100ms is (rarely) too short for positive tests on slow
578 # switches but is definitely not too short for a negative test.
579 negative_timeout = 0.1
580
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700581 exp_pkt_arg = None
Rich Lanecd97d3d2013-01-07 18:50:06 -0800582 if oftest.config["relax"]:
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700583 exp_pkt_arg = pkt
584
Dan Talayco92c99122010-06-03 13:53:18 -0700585 for ofport in yes_ports:
Rich Lane9a003812012-10-04 17:17:59 -0700586 logging.debug("Checking for pkt on port " + str(ofport))
Ken Chiang1bf01602012-04-04 10:48:23 -0700587 (rcv_port, rcv_pkt, pkt_time) = dp.poll(
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700588 port_number=ofport, exp_pkt=exp_pkt_arg)
Dan Talayco92c99122010-06-03 13:53:18 -0700589 assert_if.assertTrue(rcv_pkt is not None,
590 "Did not receive pkt on " + str(ofport))
Rich Lanecd97d3d2013-01-07 18:50:06 -0800591 if not oftest.dataplane.match_exp_pkt(pkt, rcv_pkt):
Rich Lane3c266832013-01-29 18:29:15 -0800592 logging.debug("Expected %s" % format_packet(pkt))
593 logging.debug("Received %s" % format_packet(rcv_pkt))
Rich Lanecd97d3d2013-01-07 18:50:06 -0800594 assert_if.assertTrue(oftest.dataplane.match_exp_pkt(pkt, rcv_pkt),
Rich Lane3c266832013-01-29 18:29:15 -0800595 "Received packet does not match expected packet " +
Ken Chiang1bf01602012-04-04 10:48:23 -0700596 "on port " + str(ofport))
Dan Talayco73f84012012-10-02 09:23:18 -0700597 if len(no_ports) > 0:
Rich Lane91765672012-12-06 16:33:04 -0800598 time.sleep(negative_timeout)
Dan Talayco92c99122010-06-03 13:53:18 -0700599 for ofport in no_ports:
Rich Lane9a003812012-10-04 17:17:59 -0700600 logging.debug("Negative check for pkt on port " + str(ofport))
Ken Chiang1bf01602012-04-04 10:48:23 -0700601 (rcv_port, rcv_pkt, pkt_time) = dp.poll(
Rich Lane91765672012-12-06 16:33:04 -0800602 port_number=ofport, timeout=0, exp_pkt=exp_pkt_arg)
Dan Talayco92c99122010-06-03 13:53:18 -0700603 assert_if.assertTrue(rcv_pkt is None,
604 "Unexpected pkt on port " + str(ofport))
Dan Talayco551befa2010-07-15 17:05:32 -0700605
606
Dan Talaycoc948d0b2012-03-23 12:17:54 -0700607def receive_pkt_verify(parent, egr_ports, exp_pkt, ing_port):
Dan Talayco551befa2010-07-15 17:05:32 -0700608 """
609 Receive a packet and verify it matches an expected value
Dan Talaycof6e76c02012-03-23 10:56:12 -0700610 @param egr_port A single port or list of ports
Dan Talayco551befa2010-07-15 17:05:32 -0700611
612 parent must implement dataplane, assertTrue and assertEqual
Rich Lanee4b384d2013-09-13 14:33:40 -0700613
614 DEPRECATED in favor in verify_packets
Dan Talayco551befa2010-07-15 17:05:32 -0700615 """
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700616 exp_pkt_arg = None
Rich Lanecd97d3d2013-01-07 18:50:06 -0800617 if oftest.config["relax"]:
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700618 exp_pkt_arg = exp_pkt
619
Dan Talaycof6e76c02012-03-23 10:56:12 -0700620 if type(egr_ports) == type([]):
621 egr_port_list = egr_ports
622 else:
623 egr_port_list = [egr_ports]
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700624
Dan Talaycof6e76c02012-03-23 10:56:12 -0700625 # Expect a packet from each port on egr port list
626 for egr_port in egr_port_list:
Dan Talaycod8ae7582012-03-23 12:24:56 -0700627 check_port = egr_port
Rich Lanee717c6e2013-03-12 10:25:50 -0700628 if egr_port == ofp.OFPP_IN_PORT:
Dan Talaycod8ae7582012-03-23 12:24:56 -0700629 check_port = ing_port
Dan Talaycof6e76c02012-03-23 10:56:12 -0700630 (rcv_port, rcv_pkt, pkt_time) = parent.dataplane.poll(
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700631 port_number=check_port, exp_pkt=exp_pkt_arg)
Dan Talayco551befa2010-07-15 17:05:32 -0700632
Dan Talaycof6e76c02012-03-23 10:56:12 -0700633 if rcv_pkt is None:
Rich Lane9a003812012-10-04 17:17:59 -0700634 logging.error("ERROR: No packet received from " +
Dan Talaycod8ae7582012-03-23 12:24:56 -0700635 str(check_port))
Dan Talayco551befa2010-07-15 17:05:32 -0700636
Dan Talaycof6e76c02012-03-23 10:56:12 -0700637 parent.assertTrue(rcv_pkt is not None,
Dan Talaycod8ae7582012-03-23 12:24:56 -0700638 "Did not receive packet port " + str(check_port))
Rich Lane9a003812012-10-04 17:17:59 -0700639 logging.debug("Packet len " + str(len(rcv_pkt)) + " in on " +
Dan Talaycof6e76c02012-03-23 10:56:12 -0700640 str(rcv_port))
641
642 if str(exp_pkt) != str(rcv_pkt):
Rich Lane9a003812012-10-04 17:17:59 -0700643 logging.error("ERROR: Packet match failed.")
644 logging.debug("Expected len " + str(len(exp_pkt)) + ": "
Dan Talaycof6e76c02012-03-23 10:56:12 -0700645 + str(exp_pkt).encode('hex'))
Rich Lane9a003812012-10-04 17:17:59 -0700646 logging.debug("Received len " + str(len(rcv_pkt)) + ": "
Dan Talaycof6e76c02012-03-23 10:56:12 -0700647 + str(rcv_pkt).encode('hex'))
Rich Lane5d7e89a2012-10-26 16:43:13 -0700648 logging.debug("Expected packet: " + inspect_packet(scapy.Ether(str(exp_pkt))))
649 logging.debug("Received packet: " + inspect_packet(scapy.Ether(str(rcv_pkt))))
Dan Talaycof6e76c02012-03-23 10:56:12 -0700650 parent.assertEqual(str(exp_pkt), str(rcv_pkt),
Dan Talaycod8ae7582012-03-23 12:24:56 -0700651 "Packet match error on port " + str(check_port))
Dan Talaycof6e76c02012-03-23 10:56:12 -0700652
Dan Talayco551befa2010-07-15 17:05:32 -0700653def match_verify(parent, req_match, res_match):
654 """
655 Verify flow matches agree; if they disagree, report where
656
657 parent must implement assertEqual
658 Use str() to ensure content is compared and not pointers
659 """
660
661 parent.assertEqual(req_match.wildcards, res_match.wildcards,
662 'Match failed: wildcards: ' + hex(req_match.wildcards) +
663 " != " + hex(res_match.wildcards))
664 parent.assertEqual(req_match.in_port, res_match.in_port,
665 'Match failed: in_port: ' + str(req_match.in_port) +
666 " != " + str(res_match.in_port))
Rich Laned0478ff2013-03-11 12:46:58 -0700667 parent.assertEqual(str(req_match.eth_src), str(res_match.eth_src),
668 'Match failed: eth_src: ' + str(req_match.eth_src) +
669 " != " + str(res_match.eth_src))
670 parent.assertEqual(str(req_match.eth_dst), str(res_match.eth_dst),
671 'Match failed: eth_dst: ' + str(req_match.eth_dst) +
672 " != " + str(res_match.eth_dst))
673 parent.assertEqual(req_match.vlan_vid, res_match.vlan_vid,
674 'Match failed: vlan_vid: ' + str(req_match.vlan_vid) +
675 " != " + str(res_match.vlan_vid))
676 parent.assertEqual(req_match.vlan_pcp, res_match.vlan_pcp,
677 'Match failed: vlan_pcp: ' +
678 str(req_match.vlan_pcp) + " != " +
679 str(res_match.vlan_pcp))
680 parent.assertEqual(req_match.eth_type, res_match.eth_type,
681 'Match failed: eth_type: ' + str(req_match.eth_type) +
682 " != " + str(res_match.eth_type))
Dan Talayco551befa2010-07-15 17:05:32 -0700683
Rich Lanee717c6e2013-03-12 10:25:50 -0700684 if (not(req_match.wildcards & ofp.OFPFW_DL_TYPE)
Rich Laned0478ff2013-03-11 12:46:58 -0700685 and (req_match.eth_type == IP_ETHERTYPE)):
686 parent.assertEqual(req_match.ip_dscp, res_match.ip_dscp,
687 'Match failed: ip_dscp: ' + str(req_match.ip_dscp) +
688 " != " + str(res_match.ip_dscp))
689 parent.assertEqual(req_match.ip_proto, res_match.ip_proto,
690 'Match failed: ip_proto: ' + str(req_match.ip_proto) +
691 " != " + str(res_match.ip_proto))
692 parent.assertEqual(req_match.ipv4_src, res_match.ipv4_src,
693 'Match failed: ipv4_src: ' + str(req_match.ipv4_src) +
694 " != " + str(res_match.ipv4_src))
695 parent.assertEqual(req_match.ipv4_dst, res_match.ipv4_dst,
696 'Match failed: ipv4_dst: ' + str(req_match.ipv4_dst) +
697 " != " + str(res_match.ipv4_dst))
Dan Talayco551befa2010-07-15 17:05:32 -0700698
Rich Lanee717c6e2013-03-12 10:25:50 -0700699 if (not(req_match.wildcards & ofp.OFPFW_NW_PROTO)
Rich Laned0478ff2013-03-11 12:46:58 -0700700 and ((req_match.ip_proto == TCP_PROTOCOL)
701 or (req_match.ip_proto == UDP_PROTOCOL))):
702 parent.assertEqual(req_match.tcp_src, res_match.tcp_src,
703 'Match failed: tcp_src: ' +
704 str(req_match.tcp_src) +
705 " != " + str(res_match.tcp_src))
706 parent.assertEqual(req_match.tcp_dst, res_match.tcp_dst,
707 'Match failed: tcp_dst: ' +
708 str(req_match.tcp_dst) +
709 " != " + str(res_match.tcp_dst))
Dan Talayco551befa2010-07-15 17:05:32 -0700710
Ed Swierk99a74de2012-08-22 06:40:54 -0700711def packet_to_flow_match(parent, packet):
Rich Lanef6883512013-03-11 17:00:09 -0700712 match = oftest.parse.packet_to_flow_match(packet)
Rich Laneab7476f2013-06-13 15:53:52 -0700713 if ofp.OFP_VERSION in [1, 2]:
714 match.wildcards |= required_wildcards(parent)
715 else:
716 # TODO remove incompatible OXM entries
717 pass
Ed Swierk99a74de2012-08-22 06:40:54 -0700718 return match
719
720def flow_msg_create(parent, pkt, ing_port=None, action_list=None, wildcards=None,
Dan Talaycof6e76c02012-03-23 10:56:12 -0700721 egr_ports=None, egr_queue=None, check_expire=False, in_band=False):
Dan Talayco551befa2010-07-15 17:05:32 -0700722 """
723 Create a flow message
724
725 Match on packet with given wildcards.
726 See flow_match_test for other parameter descriptoins
727 @param egr_queue if not None, make the output an enqueue action
Dan Talayco677c0b72011-08-23 22:53:38 -0700728 @param in_band if True, do not wildcard ingress port
Dan Talaycof6e76c02012-03-23 10:56:12 -0700729 @param egr_ports None (drop), single port or list of ports
Dan Talayco551befa2010-07-15 17:05:32 -0700730 """
Rich Lanef6883512013-03-11 17:00:09 -0700731 match = oftest.parse.packet_to_flow_match(pkt)
Dan Talayco551befa2010-07-15 17:05:32 -0700732 parent.assertTrue(match is not None, "Flow match from pkt failed")
Ed Swierk99a74de2012-08-22 06:40:54 -0700733 if wildcards is None:
734 wildcards = required_wildcards(parent)
Dan Talayco677c0b72011-08-23 22:53:38 -0700735 if in_band:
Rich Lanee717c6e2013-03-12 10:25:50 -0700736 wildcards &= ~ofp.OFPFW_IN_PORT
Dan Talayco551befa2010-07-15 17:05:32 -0700737 match.wildcards = wildcards
738 match.in_port = ing_port
739
Dan Talaycof6e76c02012-03-23 10:56:12 -0700740 if type(egr_ports) == type([]):
741 egr_port_list = egr_ports
742 else:
743 egr_port_list = [egr_ports]
744
Rich Lanee717c6e2013-03-12 10:25:50 -0700745 request = ofp.message.flow_add()
Dan Talayco551befa2010-07-15 17:05:32 -0700746 request.match = match
747 request.buffer_id = 0xffffffff
748 if check_expire:
Rich Lanee717c6e2013-03-12 10:25:50 -0700749 request.flags |= ofp.OFPFF_SEND_FLOW_REM
Dan Talayco551befa2010-07-15 17:05:32 -0700750 request.hard_timeout = 1
751
Rich Lane400fb9b2013-10-10 17:20:54 -0700752 if ofp.OFP_VERSION == 1:
753 actions = request.actions
754 else:
755 actions = []
756 request.instructions.append(ofp.instruction.apply_actions(actions))
757
Dan Talayco551befa2010-07-15 17:05:32 -0700758 if action_list is not None:
Rich Lane400fb9b2013-10-10 17:20:54 -0700759 actions.extend(action_list)
Dan Talayco551befa2010-07-15 17:05:32 -0700760
761 # Set up output/enqueue action if directed
762 if egr_queue is not None:
Dan Talaycof6e76c02012-03-23 10:56:12 -0700763 parent.assertTrue(egr_ports is not None, "Egress port not set")
Rich Lanee717c6e2013-03-12 10:25:50 -0700764 act = ofp.action.enqueue()
Dan Talaycof6e76c02012-03-23 10:56:12 -0700765 for egr_port in egr_port_list:
766 act.port = egr_port
767 act.queue_id = egr_queue
Rich Lane400fb9b2013-10-10 17:20:54 -0700768 actions.append(act)
Dan Talaycof6e76c02012-03-23 10:56:12 -0700769 elif egr_ports is not None:
770 for egr_port in egr_port_list:
Rich Lanee717c6e2013-03-12 10:25:50 -0700771 act = ofp.action.output()
Dan Talaycof6e76c02012-03-23 10:56:12 -0700772 act.port = egr_port
Rich Lane400fb9b2013-10-10 17:20:54 -0700773 actions.append(act)
Dan Talayco551befa2010-07-15 17:05:32 -0700774
Rich Lane9a003812012-10-04 17:17:59 -0700775 logging.debug(request.show())
Dan Talayco551befa2010-07-15 17:05:32 -0700776
777 return request
778
Jeffrey Townsendf3eae9c2012-03-28 18:23:21 -0700779def flow_msg_install(parent, request, clear_table_override=None):
Dan Talayco551befa2010-07-15 17:05:32 -0700780 """
781 Install a flow mod message in the switch
782
783 @param parent Must implement controller, assertEqual, assertTrue
784 @param request The request, all set to go
785 @param clear_table If true, clear the flow table before installing
786 """
Dan Talayco8a64e332012-03-28 14:53:20 -0700787
Rich Lane2014f9b2012-10-05 15:29:40 -0700788 clear_table = test_param_get('clear_table', default=True)
Jeffrey Townsendf3eae9c2012-03-28 18:23:21 -0700789 if(clear_table_override != None):
790 clear_table = clear_table_override
791
792 if clear_table:
Rich Lane9a003812012-10-04 17:17:59 -0700793 logging.debug("Clear flow table")
Rich Lane32bf9482013-01-03 17:26:30 -0800794 delete_all_flows(parent.controller)
Dan Talayco551befa2010-07-15 17:05:32 -0700795
Rich Lane9a003812012-10-04 17:17:59 -0700796 logging.debug("Insert flow")
Rich Lane5c3151c2013-01-03 17:15:41 -0800797 parent.controller.message_send(request)
Rich Lanee912d032012-12-22 14:28:33 -0800798
Rich Lane3a261d52013-01-03 17:45:08 -0800799 do_barrier(parent.controller)
Dan Talayco551befa2010-07-15 17:05:32 -0700800
Ed Swierk99a74de2012-08-22 06:40:54 -0700801def flow_match_test_port_pair(parent, ing_port, egr_ports, wildcards=None,
Rich Laned0478ff2013-03-11 12:46:58 -0700802 vlan_vid=-1, pkt=None, exp_pkt=None,
Rich Lanee5779d32012-10-05 17:56:04 -0700803 action_list=None):
Dan Talayco551befa2010-07-15 17:05:32 -0700804 """
805 Flow match test on single TCP packet
Dan Talaycof6e76c02012-03-23 10:56:12 -0700806 @param egr_ports A single port or list of ports
Dan Talayco551befa2010-07-15 17:05:32 -0700807
808 Run test with packet through switch from ing_port to egr_port
809 See flow_match_test for parameter descriptions
810 """
811
Ed Swierk99a74de2012-08-22 06:40:54 -0700812 if wildcards is None:
813 wildcards = required_wildcards(parent)
Rich Lane9a003812012-10-04 17:17:59 -0700814 logging.info("Pkt match test: " + str(ing_port) + " to " +
Dan Talaycof6e76c02012-03-23 10:56:12 -0700815 str(egr_ports))
Rich Laned0478ff2013-03-11 12:46:58 -0700816 logging.debug(" WC: " + hex(wildcards) + " vlan: " + str(vlan_vid))
Dan Talayco551befa2010-07-15 17:05:32 -0700817 if pkt is None:
Rich Laned0478ff2013-03-11 12:46:58 -0700818 pkt = simple_tcp_packet(dl_vlan_enable=(vlan_vid >= 0), vlan_vid=vlan_vid)
Rich Lanec41fbec2013-10-02 00:27:59 -0700819 if exp_pkt is None:
820 exp_pkt = pkt
Dan Talayco551befa2010-07-15 17:05:32 -0700821
822 request = flow_msg_create(parent, pkt, ing_port=ing_port,
Dan Talaycof6e76c02012-03-23 10:56:12 -0700823 wildcards=wildcards, egr_ports=egr_ports,
Dan Talayco551befa2010-07-15 17:05:32 -0700824 action_list=action_list)
825
826 flow_msg_install(parent, request)
827
Rich Lane9a003812012-10-04 17:17:59 -0700828 logging.debug("Send packet: " + str(ing_port) + " to " +
Dan Talaycof6e76c02012-03-23 10:56:12 -0700829 str(egr_ports))
Dan Talayco551befa2010-07-15 17:05:32 -0700830 parent.dataplane.send(ing_port, str(pkt))
831
Rich Lane8f45e2d2013-10-01 16:06:54 -0700832 exp_ports = [ing_port if port == ofp.OFPP_IN_PORT else port for port in egr_ports]
Rich Lanee4b384d2013-09-13 14:33:40 -0700833 verify_packets(parent, exp_pkt, exp_ports)
Dan Talayco551befa2010-07-15 17:05:32 -0700834
Rich Lane89725bb2012-12-03 16:23:27 -0800835def flow_match_test_pktout(parent, ing_port, egr_ports,
Rich Laned0478ff2013-03-11 12:46:58 -0700836 vlan_vid=-1, pkt=None, exp_pkt=None,
Rich Lane89725bb2012-12-03 16:23:27 -0800837 action_list=None):
838 """
839 Packet-out test on single TCP packet
840 @param egr_ports A single port or list of ports
841
842 Run test sending packet-out to egr_ports. The goal is to test the actions
843 taken on the packet, not the matching which is of course irrelevant.
844 See flow_match_test for parameter descriptions
845 """
846
847 if pkt is None:
Rich Laned0478ff2013-03-11 12:46:58 -0700848 pkt = simple_tcp_packet(dl_vlan_enable=(vlan_vid >= 0), vlan_vid=vlan_vid)
Rich Lanec41fbec2013-10-02 00:27:59 -0700849 if exp_pkt is None:
850 exp_pkt = pkt
Rich Lane89725bb2012-12-03 16:23:27 -0800851
Rich Lanee717c6e2013-03-12 10:25:50 -0700852 msg = ofp.message.packet_out()
Rich Lane89725bb2012-12-03 16:23:27 -0800853 msg.in_port = ing_port
Rich Laneea8c4722013-04-04 15:30:20 -0700854 msg.buffer_id = 0xffffffff
Rich Lane89725bb2012-12-03 16:23:27 -0800855 msg.data = str(pkt)
856 if action_list is not None:
857 for act in action_list:
Rich Lanec495d9e2013-03-08 17:43:36 -0800858 msg.actions.append(act)
Rich Lane89725bb2012-12-03 16:23:27 -0800859
860 # Set up output action
861 if egr_ports is not None:
862 for egr_port in egr_ports:
Rich Lanee717c6e2013-03-12 10:25:50 -0700863 act = ofp.action.output()
Rich Lane89725bb2012-12-03 16:23:27 -0800864 act.port = egr_port
Rich Lanec495d9e2013-03-08 17:43:36 -0800865 msg.actions.append(act)
Rich Lane89725bb2012-12-03 16:23:27 -0800866
867 logging.debug(msg.show())
Rich Lane5c3151c2013-01-03 17:15:41 -0800868 parent.controller.message_send(msg)
Rich Lane89725bb2012-12-03 16:23:27 -0800869
Rich Lane8f45e2d2013-10-01 16:06:54 -0700870 exp_ports = [ing_port if port == ofp.OFPP_IN_PORT else port for port in egr_ports]
Rich Lanee4b384d2013-09-13 14:33:40 -0700871 verify_packets(parent, exp_pkt, exp_ports)
Rich Lane89725bb2012-12-03 16:23:27 -0800872
Dan Talaycof6e76c02012-03-23 10:56:12 -0700873def get_egr_list(parent, of_ports, how_many, exclude_list=[]):
874 """
875 Generate a list of ports avoiding those in the exclude list
Rich Lane9a003812012-10-04 17:17:59 -0700876 @param parent Supplies logging
Dan Talaycof6e76c02012-03-23 10:56:12 -0700877 @param of_ports List of OF port numbers
878 @param how_many Number of ports to be added to the list
879 @param exclude_list List of ports not to be used
880 @returns An empty list if unable to find enough ports
881 """
882
Dan Talaycoc948d0b2012-03-23 12:17:54 -0700883 if how_many == 0:
884 return []
885
Dan Talaycof6e76c02012-03-23 10:56:12 -0700886 count = 0
887 egr_ports = []
888 for egr_idx in range(len(of_ports)):
889 if of_ports[egr_idx] not in exclude_list:
890 egr_ports.append(of_ports[egr_idx])
891 count += 1
892 if count >= how_many:
893 return egr_ports
Rich Lane9a003812012-10-04 17:17:59 -0700894 logging.debug("Could not generate enough egress ports for test")
Dan Talaycof6e76c02012-03-23 10:56:12 -0700895 return []
896
Rich Laned0478ff2013-03-11 12:46:58 -0700897def flow_match_test(parent, port_map, wildcards=None, vlan_vid=-1, pkt=None,
Rich Lanee5779d32012-10-05 17:56:04 -0700898 exp_pkt=None, action_list=None,
Dan Talaycoc948d0b2012-03-23 12:17:54 -0700899 max_test=0, egr_count=1, ing_port=False):
Dan Talayco551befa2010-07-15 17:05:32 -0700900 """
Rich Lane89725bb2012-12-03 16:23:27 -0800901 Run flow_match_test_port_pair on all port pairs and packet-out
Dan Talayco551befa2010-07-15 17:05:32 -0700902
903 @param max_test If > 0 no more than this number of tests are executed.
904 @param parent Must implement controller, dataplane, assertTrue, assertEqual
Rich Lane9a003812012-10-04 17:17:59 -0700905 and logging
Dan Talayco551befa2010-07-15 17:05:32 -0700906 @param pkt If not None, use this packet for ingress
907 @param wildcards For flow match entry
Rich Laned0478ff2013-03-11 12:46:58 -0700908 @param vlan_vid If not -1, and pkt is None, create a pkt w/ VLAN tag
Dan Talayco551befa2010-07-15 17:05:32 -0700909 @param exp_pkt If not None, use this as the expected output pkt; els use pkt
910 @param action_list Additional actions to add to flow mod
Dan Talaycocfa172f2012-03-23 12:03:00 -0700911 @param egr_count Number of egress ports; -1 means get from config w/ dflt 2
Dan Talayco551befa2010-07-15 17:05:32 -0700912 """
Ed Swierk99a74de2012-08-22 06:40:54 -0700913 if wildcards is None:
914 wildcards = required_wildcards(parent)
Dan Talayco551befa2010-07-15 17:05:32 -0700915 of_ports = port_map.keys()
916 of_ports.sort()
917 parent.assertTrue(len(of_ports) > 1, "Not enough ports for test")
918 test_count = 0
919
Dan Talaycocfa172f2012-03-23 12:03:00 -0700920 if egr_count == -1:
Rich Lane2014f9b2012-10-05 15:29:40 -0700921 egr_count = test_param_get('egr_count', default=2)
Dan Talaycocfa172f2012-03-23 12:03:00 -0700922
Dan Talayco551befa2010-07-15 17:05:32 -0700923 for ing_idx in range(len(of_ports)):
924 ingress_port = of_ports[ing_idx]
Dan Talaycof6e76c02012-03-23 10:56:12 -0700925 egr_ports = get_egr_list(parent, of_ports, egr_count,
926 exclude_list=[ingress_port])
Dan Talaycoc948d0b2012-03-23 12:17:54 -0700927 if ing_port:
Rich Lanee717c6e2013-03-12 10:25:50 -0700928 egr_ports.append(ofp.OFPP_IN_PORT)
Dan Talaycof6e76c02012-03-23 10:56:12 -0700929 if len(egr_ports) == 0:
930 parent.assertTrue(0, "Failed to generate egress port list")
931
932 flow_match_test_port_pair(parent, ingress_port, egr_ports,
Rich Laned0478ff2013-03-11 12:46:58 -0700933 wildcards=wildcards, vlan_vid=vlan_vid,
Dan Talaycof6e76c02012-03-23 10:56:12 -0700934 pkt=pkt, exp_pkt=exp_pkt,
Rich Lanee5779d32012-10-05 17:56:04 -0700935 action_list=action_list)
Dan Talaycof6e76c02012-03-23 10:56:12 -0700936 test_count += 1
937 if (max_test > 0) and (test_count > max_test):
Rich Lane9a003812012-10-04 17:17:59 -0700938 logging.info("Ran " + str(test_count) + " tests; exiting")
Rich Lane89725bb2012-12-03 16:23:27 -0800939 break
940
Ed Swierk38eea082013-01-02 19:46:20 -0800941 if not test_param_get('pktout_actions', default=True):
942 return
Rich Lane89725bb2012-12-03 16:23:27 -0800943
944 ingress_port = of_ports[0]
945 egr_ports = get_egr_list(parent, of_ports, egr_count,
946 exclude_list=[ingress_port])
947 if ing_port:
Rich Lanee717c6e2013-03-12 10:25:50 -0700948 egr_ports.append(ofp.OFPP_IN_PORT)
Rich Lane89725bb2012-12-03 16:23:27 -0800949 flow_match_test_pktout(parent, ingress_port, egr_ports,
Rich Laned0478ff2013-03-11 12:46:58 -0700950 vlan_vid=vlan_vid,
Rich Lane89725bb2012-12-03 16:23:27 -0800951 pkt=pkt, exp_pkt=exp_pkt,
952 action_list=action_list)
Dan Talayco551befa2010-07-15 17:05:32 -0700953
Rich Lane2014f9b2012-10-05 15:29:40 -0700954def test_param_get(key, default=None):
Dan Talayco4b2bee62010-07-20 14:10:05 -0700955 """
956 Return value passed via test-params if present
957
Dan Talayco4b2bee62010-07-20 14:10:05 -0700958 @param key The lookup key
959 @param default Default value to use if not found
960
961 If the pair 'key=val' appeared in the string passed to --test-params
962 on the command line, return val (as interpreted by exec). Otherwise
963 return default value.
Dan Talaycof6e76c02012-03-23 10:56:12 -0700964
965 WARNING: TEST PARAMETERS MUST BE PYTHON IDENTIFIERS;
966 eg egr_count, not egr-count.
Dan Talayco4b2bee62010-07-20 14:10:05 -0700967 """
968 try:
Rich Lanecd97d3d2013-01-07 18:50:06 -0800969 exec oftest.config["test_params"]
Dan Talayco4b2bee62010-07-20 14:10:05 -0700970 except:
971 return default
972
Dan Talayco4b2bee62010-07-20 14:10:05 -0700973 try:
Rich Lanefdec0fb2013-08-09 18:01:05 -0700974 return eval(str(key))
Dan Talayco4b2bee62010-07-20 14:10:05 -0700975 except:
976 return default
977
978def action_generate(parent, field_to_mod, mod_field_vals):
979 """
980 Create an action to modify the field indicated in field_to_mod
981
982 @param parent Must implement, assertTrue
983 @param field_to_mod The field to modify as a string name
984 @param mod_field_vals Hash of values to use for modified values
985 """
986
987 act = None
988
989 if field_to_mod in ['pktlen']:
990 return None
991
Rich Laned0478ff2013-03-11 12:46:58 -0700992 if field_to_mod == 'eth_dst':
Rich Lanee717c6e2013-03-12 10:25:50 -0700993 act = ofp.action.set_dl_dst()
Rich Lanef6883512013-03-11 17:00:09 -0700994 act.dl_addr = oftest.parse.parse_mac(mod_field_vals['eth_dst'])
Rich Laned0478ff2013-03-11 12:46:58 -0700995 elif field_to_mod == 'eth_src':
Rich Lanee717c6e2013-03-12 10:25:50 -0700996 act = ofp.action.set_dl_src()
Rich Lanef6883512013-03-11 17:00:09 -0700997 act.dl_addr = oftest.parse.parse_mac(mod_field_vals['eth_src'])
Dan Talayco4b2bee62010-07-20 14:10:05 -0700998 elif field_to_mod == 'dl_vlan_enable':
999 if not mod_field_vals['dl_vlan_enable']: # Strip VLAN tag
Rich Lanee717c6e2013-03-12 10:25:50 -07001000 act = ofp.action.strip_vlan()
Rich Laned0478ff2013-03-11 12:46:58 -07001001 # Add VLAN tag is handled by vlan_vid field
Dan Talayco4b2bee62010-07-20 14:10:05 -07001002 # Will return None in this case
Rich Laned0478ff2013-03-11 12:46:58 -07001003 elif field_to_mod == 'vlan_vid':
Rich Lanee717c6e2013-03-12 10:25:50 -07001004 act = ofp.action.set_vlan_vid()
Rich Laned0478ff2013-03-11 12:46:58 -07001005 act.vlan_vid = mod_field_vals['vlan_vid']
1006 elif field_to_mod == 'vlan_pcp':
Rich Lanee717c6e2013-03-12 10:25:50 -07001007 act = ofp.action.set_vlan_pcp()
Rich Laned0478ff2013-03-11 12:46:58 -07001008 act.vlan_pcp = mod_field_vals['vlan_pcp']
Dan Talayco4b2bee62010-07-20 14:10:05 -07001009 elif field_to_mod == 'ip_src':
Rich Lanee717c6e2013-03-12 10:25:50 -07001010 act = ofp.action.set_nw_src()
Rich Lanef6883512013-03-11 17:00:09 -07001011 act.nw_addr = oftest.parse.parse_ip(mod_field_vals['ip_src'])
Dan Talayco4b2bee62010-07-20 14:10:05 -07001012 elif field_to_mod == 'ip_dst':
Rich Lanee717c6e2013-03-12 10:25:50 -07001013 act = ofp.action.set_nw_dst()
Rich Lanef6883512013-03-11 17:00:09 -07001014 act.nw_addr = oftest.parse.parse_ip(mod_field_vals['ip_dst'])
Dan Talayco4b2bee62010-07-20 14:10:05 -07001015 elif field_to_mod == 'ip_tos':
Rich Lanee717c6e2013-03-12 10:25:50 -07001016 act = ofp.action.set_nw_tos()
Dan Talayco4b2bee62010-07-20 14:10:05 -07001017 act.nw_tos = mod_field_vals['ip_tos']
1018 elif field_to_mod == 'tcp_sport':
Rich Lanee717c6e2013-03-12 10:25:50 -07001019 act = ofp.action.set_tp_src()
Dan Talayco4b2bee62010-07-20 14:10:05 -07001020 act.tp_port = mod_field_vals['tcp_sport']
1021 elif field_to_mod == 'tcp_dport':
Rich Lanee717c6e2013-03-12 10:25:50 -07001022 act = ofp.action.set_tp_dst()
Dan Talayco4b2bee62010-07-20 14:10:05 -07001023 act.tp_port = mod_field_vals['tcp_dport']
Rich Lane110e0e32012-10-26 16:21:46 -07001024 elif field_to_mod == 'udp_sport':
Rich Lanee717c6e2013-03-12 10:25:50 -07001025 act = ofp.action.set_tp_src()
Rich Lane110e0e32012-10-26 16:21:46 -07001026 act.tp_port = mod_field_vals['udp_sport']
1027 elif field_to_mod == 'udp_dport':
Rich Lanee717c6e2013-03-12 10:25:50 -07001028 act = ofp.action.set_tp_dst()
Rich Lane110e0e32012-10-26 16:21:46 -07001029 act.tp_port = mod_field_vals['udp_dport']
Dan Talayco4b2bee62010-07-20 14:10:05 -07001030 else:
1031 parent.assertTrue(0, "Unknown field to modify: " + str(field_to_mod))
1032
1033 return act
1034
1035def pkt_action_setup(parent, start_field_vals={}, mod_field_vals={},
Rich Lane110e0e32012-10-26 16:21:46 -07001036 mod_fields=[], tp="tcp", check_test_params=False):
Dan Talayco4b2bee62010-07-20 14:10:05 -07001037 """
1038 Set up the ingress and expected packet and action list for a test
1039
Rich Lane2014f9b2012-10-05 15:29:40 -07001040 @param parent Must implement assertTrue
Dan Talayco4b2bee62010-07-20 14:10:05 -07001041 @param start_field_values Field values to use for ingress packet (optional)
1042 @param mod_field_values Field values to use for modified packet (optional)
1043 @param mod_fields The list of fields to be modified by the switch in the test.
1044 @params check_test_params If True, will check the parameters vid, add_vlan
1045 and strip_vlan from the command line.
1046
1047 Returns a triple: pkt-to-send, expected-pkt, action-list
1048 """
1049
1050 new_actions = []
1051
Dan Talayco4b2bee62010-07-20 14:10:05 -07001052 base_pkt_params = {}
1053 base_pkt_params['pktlen'] = 100
Rich Laned0478ff2013-03-11 12:46:58 -07001054 base_pkt_params['eth_dst'] = '00:DE:F0:12:34:56'
1055 base_pkt_params['eth_src'] = '00:23:45:67:89:AB'
Dan Talayco4b2bee62010-07-20 14:10:05 -07001056 base_pkt_params['dl_vlan_enable'] = False
Rich Laned0478ff2013-03-11 12:46:58 -07001057 base_pkt_params['vlan_vid'] = 2
1058 base_pkt_params['vlan_pcp'] = 0
Dan Talayco4b2bee62010-07-20 14:10:05 -07001059 base_pkt_params['ip_src'] = '192.168.0.1'
1060 base_pkt_params['ip_dst'] = '192.168.0.2'
1061 base_pkt_params['ip_tos'] = 0
Rich Lane110e0e32012-10-26 16:21:46 -07001062 if tp == "tcp":
1063 base_pkt_params['tcp_sport'] = 1234
1064 base_pkt_params['tcp_dport'] = 80
1065 elif tp == "udp":
1066 base_pkt_params['udp_sport'] = 1234
1067 base_pkt_params['udp_dport'] = 80
Dan Talayco4b2bee62010-07-20 14:10:05 -07001068 for keyname in start_field_vals.keys():
1069 base_pkt_params[keyname] = start_field_vals[keyname]
1070
1071 mod_pkt_params = {}
1072 mod_pkt_params['pktlen'] = 100
Rich Laned0478ff2013-03-11 12:46:58 -07001073 mod_pkt_params['eth_dst'] = '00:21:0F:ED:CB:A9'
1074 mod_pkt_params['eth_src'] = '00:ED:CB:A9:87:65'
Dan Talayco4b2bee62010-07-20 14:10:05 -07001075 mod_pkt_params['dl_vlan_enable'] = False
Rich Laned0478ff2013-03-11 12:46:58 -07001076 mod_pkt_params['vlan_vid'] = 3
1077 mod_pkt_params['vlan_pcp'] = 7
Dan Talayco4b2bee62010-07-20 14:10:05 -07001078 mod_pkt_params['ip_src'] = '10.20.30.40'
1079 mod_pkt_params['ip_dst'] = '50.60.70.80'
1080 mod_pkt_params['ip_tos'] = 0xf0
Rich Lane110e0e32012-10-26 16:21:46 -07001081 if tp == "tcp":
1082 mod_pkt_params['tcp_sport'] = 4321
1083 mod_pkt_params['tcp_dport'] = 8765
1084 elif tp == "udp":
1085 mod_pkt_params['udp_sport'] = 4321
1086 mod_pkt_params['udp_dport'] = 8765
Dan Talayco4b2bee62010-07-20 14:10:05 -07001087 for keyname in mod_field_vals.keys():
1088 mod_pkt_params[keyname] = mod_field_vals[keyname]
1089
1090 # Check for test param modifications
1091 strip = False
1092 if check_test_params:
Rich Lane2014f9b2012-10-05 15:29:40 -07001093 add_vlan = test_param_get('add_vlan')
1094 strip_vlan = test_param_get('strip_vlan')
1095 vid = test_param_get('vid')
Dan Talayco4b2bee62010-07-20 14:10:05 -07001096
1097 if add_vlan and strip_vlan:
1098 parent.assertTrue(0, "Add and strip VLAN both specified")
1099
1100 if vid:
1101 base_pkt_params['dl_vlan_enable'] = True
Rich Laned0478ff2013-03-11 12:46:58 -07001102 base_pkt_params['vlan_vid'] = vid
1103 if 'vlan_vid' in mod_fields:
1104 mod_pkt_params['vlan_vid'] = vid + 1
Dan Talayco4b2bee62010-07-20 14:10:05 -07001105
1106 if add_vlan:
1107 base_pkt_params['dl_vlan_enable'] = False
1108 mod_pkt_params['dl_vlan_enable'] = True
1109 mod_pkt_params['pktlen'] = base_pkt_params['pktlen'] + 4
1110 mod_fields.append('pktlen')
1111 mod_fields.append('dl_vlan_enable')
Rich Laned0478ff2013-03-11 12:46:58 -07001112 if 'vlan_vid' not in mod_fields:
1113 mod_fields.append('vlan_vid')
Dan Talayco4b2bee62010-07-20 14:10:05 -07001114 elif strip_vlan:
1115 base_pkt_params['dl_vlan_enable'] = True
1116 mod_pkt_params['dl_vlan_enable'] = False
1117 mod_pkt_params['pktlen'] = base_pkt_params['pktlen'] - 4
1118 mod_fields.append('dl_vlan_enable')
1119 mod_fields.append('pktlen')
1120
Rich Lane110e0e32012-10-26 16:21:46 -07001121 if tp == "tcp":
1122 packet_builder = simple_tcp_packet
1123 elif tp == "udp":
1124 packet_builder = simple_udp_packet
1125 else:
1126 raise NotImplementedError("unknown transport protocol %s" % tp)
1127
Dan Talayco4b2bee62010-07-20 14:10:05 -07001128 # Build the ingress packet
Rich Lane110e0e32012-10-26 16:21:46 -07001129 ingress_pkt = packet_builder(**base_pkt_params)
Dan Talayco4b2bee62010-07-20 14:10:05 -07001130
1131 # Build the expected packet, modifying the indicated fields
1132 for item in mod_fields:
1133 base_pkt_params[item] = mod_pkt_params[item]
1134 act = action_generate(parent, item, mod_pkt_params)
1135 if act:
1136 new_actions.append(act)
1137
Rich Lane110e0e32012-10-26 16:21:46 -07001138 expected_pkt = packet_builder(**base_pkt_params)
Dan Talayco4b2bee62010-07-20 14:10:05 -07001139
1140 return (ingress_pkt, expected_pkt, new_actions)
Dan Talayco677c0b72011-08-23 22:53:38 -07001141
1142# Generate a simple "drop" flow mod
1143# If in_band is true, then only drop from first test port
1144def flow_mod_gen(port_map, in_band):
Rich Lanee717c6e2013-03-12 10:25:50 -07001145 request = ofp.message.flow_add()
1146 request.match.wildcards = ofp.OFPFW_ALL
Dan Talayco677c0b72011-08-23 22:53:38 -07001147 if in_band:
Rich Lanee717c6e2013-03-12 10:25:50 -07001148 request.match.wildcards = ofp.OFPFW_ALL - ofp.OFPFW_IN_PORT
Dan Talayco677c0b72011-08-23 22:53:38 -07001149 for of_port, ifname in port_map.items(): # Grab first port
1150 break
1151 request.match.in_port = of_port
1152 request.buffer_id = 0xffffffff
1153 return request
Dan Talaycoba3745c2010-07-21 21:51:08 -07001154
1155def skip_message_emit(parent, s):
1156 """
1157 Print out a 'skipped' message to stderr
1158
1159 @param s The string to print out to the log file
Dan Talaycoba3745c2010-07-21 21:51:08 -07001160 """
1161 global skipped_test_count
1162
1163 skipped_test_count += 1
Rich Lane9a003812012-10-04 17:17:59 -07001164 logging.info("Skipping: " + s)
Dan Talayco2940fdd2013-02-06 15:01:35 -08001165 if oftest.config["debug"] < logging.WARNING:
Dan Talaycoba3745c2010-07-21 21:51:08 -07001166 sys.stderr.write("(skipped) ")
1167 else:
1168 sys.stderr.write("(S)")
Dan Talayco677c0b72011-08-23 22:53:38 -07001169
Dan Talayco8a64e332012-03-28 14:53:20 -07001170
1171def all_stats_get(parent):
1172 """
1173 Get the aggregate stats for all flows in the table
1174 @param parent Test instance with controller connection and assert
1175 @returns dict with keys flows, packets, bytes, active (flows),
1176 lookups, matched
1177 """
Rich Lanee717c6e2013-03-12 10:25:50 -07001178 stat_req = ofp.message.aggregate_stats_request()
1179 stat_req.match = ofp.match()
1180 stat_req.match.wildcards = ofp.OFPFW_ALL
Dan Talayco8a64e332012-03-28 14:53:20 -07001181 stat_req.table_id = 0xff
Rich Lanee717c6e2013-03-12 10:25:50 -07001182 stat_req.out_port = ofp.OFPP_NONE
Dan Talayco8a64e332012-03-28 14:53:20 -07001183
1184 rv = {}
1185
Rich Lanec8aaa3e2012-07-26 19:28:02 -07001186 (reply, pkt) = parent.controller.transact(stat_req)
Rich Lane5fd6faf2013-03-11 13:30:20 -07001187 parent.assertTrue(len(reply.entries) == 1, "Did not receive flow stats reply")
Dan Talayco8a64e332012-03-28 14:53:20 -07001188
Rich Lane5fd6faf2013-03-11 13:30:20 -07001189 for obj in reply.entries:
Dan Talayco8a64e332012-03-28 14:53:20 -07001190 (rv["flows"], rv["packets"], rv["bytes"]) = (obj.flow_count,
1191 obj.packet_count, obj.byte_count)
1192 break
1193
Rich Lanee717c6e2013-03-12 10:25:50 -07001194 request = ofp.message.table_stats_request()
Rich Lanec8aaa3e2012-07-26 19:28:02 -07001195 (reply , pkt) = parent.controller.transact(request)
Dan Talayco8a64e332012-03-28 14:53:20 -07001196
1197
1198 (rv["active"], rv["lookups"], rv["matched"]) = (0,0,0)
Rich Lane5fd6faf2013-03-11 13:30:20 -07001199 for obj in reply.entries:
Dan Talayco8a64e332012-03-28 14:53:20 -07001200 rv["active"] += obj.active_count
1201 rv["lookups"] += obj.lookup_count
1202 rv["matched"] += obj.matched_count
1203
1204 return rv
Dan Talayco2baf8b52012-03-30 09:55:42 -07001205
Rich Lane7744e112013-01-11 17:23:57 -08001206_import_blacklist.add('FILTER')
Dan Talayco2baf8b52012-03-30 09:55:42 -07001207FILTER=''.join([(len(repr(chr(x)))==3) and chr(x) or '.'
1208 for x in range(256)])
1209
1210def hex_dump_buffer(src, length=16):
1211 """
1212 Convert src to a hex dump string and return the string
1213 @param src The source buffer
1214 @param length The number of bytes shown in each line
1215 @returns A string showing the hex dump
1216 """
Dan Talaycoc516fa02012-04-12 22:28:43 -07001217 result = ["\n"]
Dan Talayco2baf8b52012-03-30 09:55:42 -07001218 for i in xrange(0, len(src), length):
1219 chars = src[i:i+length]
1220 hex = ' '.join(["%02x" % ord(x) for x in chars])
1221 printable = ''.join(["%s" % ((ord(x) <= 127 and
1222 FILTER[ord(x)]) or '.') for x in chars])
1223 result.append("%04x %-*s %s\n" % (i, length*3, hex, printable))
1224 return ''.join(result)
1225
1226def format_packet(pkt):
1227 return "Packet length %d \n%s" % (len(str(pkt)),
1228 hex_dump_buffer(str(pkt)))
Rich Lane5d7e89a2012-10-26 16:43:13 -07001229
1230def inspect_packet(pkt):
1231 """
1232 Wrapper around scapy's show() method.
1233 @returns A string showing the dissected packet.
1234 """
1235 from cStringIO import StringIO
1236 out = None
1237 backup = sys.stdout
1238 try:
Rich Lanefdec0fb2013-08-09 18:01:05 -07001239 tmp = StringIO()
1240 sys.stdout = tmp
Rich Lane5d7e89a2012-10-26 16:43:13 -07001241 pkt.show2()
Rich Lanefdec0fb2013-08-09 18:01:05 -07001242 out = tmp.getvalue()
1243 tmp.close()
Rich Lane5d7e89a2012-10-26 16:43:13 -07001244 finally:
1245 sys.stdout = backup
1246 return out
Rich Lane0a4f6372013-01-02 14:40:22 -08001247
1248def nonstandard(cls):
1249 """
Rich Lanecc45b8e2013-01-02 15:55:02 -08001250 Testcase decorator that marks the test as being non-standard.
1251 These tests are not automatically added to the "standard" group.
Rich Lane0a4f6372013-01-02 14:40:22 -08001252 """
Rich Lanecc45b8e2013-01-02 15:55:02 -08001253 cls._nonstandard = True
Rich Lane0a4f6372013-01-02 14:40:22 -08001254 return cls
1255
1256def disabled(cls):
1257 """
Rich Lanecc45b8e2013-01-02 15:55:02 -08001258 Testcase decorator that marks the test as being disabled.
1259 These tests are not automatically added to the "standard" group or
1260 their module's group.
Rich Lane0a4f6372013-01-02 14:40:22 -08001261 """
Rich Lanecc45b8e2013-01-02 15:55:02 -08001262 cls._disabled = True
Rich Lane0a4f6372013-01-02 14:40:22 -08001263 return cls
Rich Lane97e99652013-01-02 17:23:20 -08001264
1265def group(name):
1266 """
1267 Testcase decorator that adds the test to a group.
1268 """
1269 def fn(cls):
1270 if not hasattr(cls, "_groups"):
1271 cls._groups = []
1272 cls._groups.append(name)
1273 return cls
1274 return fn
Rich Lane5a9a1922013-01-11 14:29:30 -08001275
1276def version(ver):
1277 """
1278 Testcase decorator that specifies which versions of OpenFlow the test
1279 supports. The default is 1.0+. This decorator may only be used once.
1280
1281 Supported syntax:
1282 1.0 -> 1.0
1283 1.0,1.2,1.3 -> 1.0, 1.2, 1.3
1284 1.0+ -> 1.0, 1.1, 1.2, 1.3
1285 """
1286 versions = parse_version(ver)
1287 def fn(cls):
1288 cls._versions = versions
1289 return cls
1290 return fn
1291
1292def parse_version(ver):
1293 allowed_versions = ["1.0", "1.1", "1.2", "1.3"]
1294 if re.match("^1\.\d+$", ver):
1295 versions = set([ver])
1296 elif re.match("^(1\.\d+)\+$", ver):
1297 if not ver[:-1] in allowed_versions:
1298 raise ValueError("invalid OpenFlow version %s" % ver[:-1])
1299 versions = set()
1300 if ver != "1.1+": versions.add("1.0")
1301 if ver != "1.2+": versions.add("1.1")
1302 if ver != "1.3+": versions.add("1.2")
1303 versions.add("1.3")
1304 else:
1305 versions = set(ver.split(','))
1306
1307 for version in versions:
1308 if not version in allowed_versions:
1309 raise ValueError("invalid OpenFlow version %s" % version)
1310
1311 return versions
1312
1313assert(parse_version("1.0") == set(["1.0"]))
1314assert(parse_version("1.0,1.2,1.3") == set(["1.0", "1.2", "1.3"]))
1315assert(parse_version("1.0+") == set(["1.0", "1.1", "1.2", "1.3"]))
Rich Lane7744e112013-01-11 17:23:57 -08001316
Rich Laneae3428c2013-03-07 14:37:42 -08001317def get_stats(test, req):
1318 """
1319 Retrieve a list of stats entries. Handles OFPSF_REPLY_MORE.
1320 """
Rich Lane609194f2013-10-21 06:17:37 -07001321 msgtype = ofp.OFPT_STATS_REPLY
1322 more_flag = ofp.OFPSF_REPLY_MORE
Rich Laneae3428c2013-03-07 14:37:42 -08001323 stats = []
1324 reply, _ = test.controller.transact(req)
1325 test.assertTrue(reply is not None, "No response to stats request")
Rich Lane34c68d52013-10-11 10:38:21 -07001326 test.assertEquals(reply.type, msgtype, "Response had unexpected message type")
Rich Lane5fd6faf2013-03-11 13:30:20 -07001327 stats.extend(reply.entries)
Rich Lanebd56ed62013-07-10 15:49:44 -07001328 while reply.flags & more_flag != 0:
Rich Lane34c68d52013-10-11 10:38:21 -07001329 reply, pkt = test.controller.poll(exp_msg=msgtype)
Rich Laneae3428c2013-03-07 14:37:42 -08001330 test.assertTrue(reply is not None, "No response to stats request")
Rich Lane5fd6faf2013-03-11 13:30:20 -07001331 stats.extend(reply.entries)
Rich Laneae3428c2013-03-07 14:37:42 -08001332 return stats
1333
Rich Lanebd56ed62013-07-10 15:49:44 -07001334def get_flow_stats(test, match, table_id=None,
1335 out_port=None, out_group=None,
1336 cookie=0, cookie_mask=0):
Rich Laneae3428c2013-03-07 14:37:42 -08001337 """
1338 Retrieve a list of flow stats entries.
1339 """
Rich Lanebd56ed62013-07-10 15:49:44 -07001340
1341 if table_id == None:
1342 if ofp.OFP_VERSION <= 2:
1343 table_id = 0xff
1344 else:
1345 table_id = ofp.OFPTT_ALL
1346
Rich Lanef3bc48c2013-05-03 17:39:35 -07001347 if out_port == None:
Rich Lanebd56ed62013-07-10 15:49:44 -07001348 if ofp.OFP_VERSION == 1:
1349 out_port = ofp.OFPP_NONE
1350 else:
1351 out_port = ofp.OFPP_ANY
1352
1353 if out_group == None:
1354 if ofp.OFP_VERSION > 1:
1355 out_group = ofp.OFPP_ANY
1356
Rich Lanee717c6e2013-03-12 10:25:50 -07001357 req = ofp.message.flow_stats_request(match=match,
Rich Lanebd56ed62013-07-10 15:49:44 -07001358 table_id=table_id,
1359 out_port=out_port)
1360 if ofp.OFP_VERSION > 1:
1361 req.out_group = out_group
1362 req.cookie = cookie
1363 req.cookie_mask = cookie_mask
1364
Rich Laneae3428c2013-03-07 14:37:42 -08001365 return get_stats(test, req)
1366
Rich Lane968b6192013-03-07 15:34:43 -08001367def get_port_stats(test, port_no):
1368 """
1369 Retrieve a list of port stats entries.
1370 """
Rich Lanee717c6e2013-03-12 10:25:50 -07001371 req = ofp.message.port_stats_request(port_no=port_no)
Rich Lane968b6192013-03-07 15:34:43 -08001372 return get_stats(test, req)
1373
Rich Lane6a334922013-03-07 16:14:52 -08001374def get_queue_stats(test, port_no, queue_id):
1375 """
1376 Retrieve a list of queue stats entries.
1377 """
Rich Lanee717c6e2013-03-12 10:25:50 -07001378 req = ofp.message.queue_stats_request(port_no=port_no, queue_id=queue_id)
Rich Lane6a334922013-03-07 16:14:52 -08001379 return get_stats(test, req)
1380
Rich Laneae3428c2013-03-07 14:37:42 -08001381def verify_flow_stats(test, match, table_id=0xff,
Rich Lanef3bc48c2013-05-03 17:39:35 -07001382 out_port=None,
Rich Laneae3428c2013-03-07 14:37:42 -08001383 initial=[],
1384 pkts=None, bytes=None):
1385 """
1386 Verify that flow stats changed as expected.
1387
1388 Optionally takes an 'initial' list of stats entries, as returned by
1389 get_flow_stats(). If 'initial' is not given the counters are assumed to
1390 begin at 0.
1391 """
Rich Lanef3bc48c2013-05-03 17:39:35 -07001392 if out_port == None:
1393 out_port = ofp.OFPP_NONE
1394
Rich Laneae3428c2013-03-07 14:37:42 -08001395 def accumulate(stats):
1396 pkts_acc = bytes_acc = 0
1397 for stat in stats:
1398 pkts_acc += stat.packet_count
1399 bytes_acc += stat.byte_count
1400 return (pkts_acc, bytes_acc)
1401
1402 pkts_before, bytes_before = accumulate(initial)
1403
1404 # Wait 10s for counters to update
1405 pkt_diff = byte_diff = None
1406 for i in range(0, 100):
1407 stats = get_flow_stats(test, match, table_id=table_id, out_port=out_port)
1408 pkts_after, bytes_after = accumulate(stats)
1409 pkt_diff = pkts_after - pkts_before
1410 byte_diff = bytes_after - bytes_before
1411 if (pkts == None or pkt_diff >= pkts) and \
1412 (bytes == None or byte_diff >= bytes):
1413 break
Dan Talayco53724732013-03-08 23:54:02 -08001414 time.sleep(0.1)
Rich Laneae3428c2013-03-07 14:37:42 -08001415
1416 if pkts != None:
1417 test.assertEquals(pkt_diff, pkts, "Flow packet counter not updated properly (expected increase of %d, got increase of %d)" % (pkts, pkt_diff))
1418
1419 if bytes != None:
Rich Lane53b96812013-03-07 16:54:50 -08001420 test.assertTrue(byte_diff >= bytes and byte_diff <= bytes*1.1,
1421 "Flow byte counter not updated properly (expected increase of %d, got increase of %d)" % (bytes, byte_diff))
Rich Laneae3428c2013-03-07 14:37:42 -08001422
Rich Lane968b6192013-03-07 15:34:43 -08001423def verify_port_stats(test, port,
1424 initial=[],
1425 tx_pkts=None, rx_pkts=None,
1426 tx_bytes=None, rx_bytes=None):
1427 """
1428 Verify that port stats changed as expected.
1429
1430 Optionally takes an 'initial' list of stats entries, as returned by
1431 get_port_stats(). If 'initial' is not given the counters are assumed to
1432 begin at 0.
1433 """
1434 def accumulate(stats):
1435 tx_pkts_acc = rx_pkts_acc = tx_bytes_acc = rx_bytes_acc = 0
1436 for stat in stats:
1437 tx_pkts_acc += stat.tx_packets
1438 rx_pkts_acc += stat.rx_packets
1439 tx_bytes_acc += stat.tx_bytes
1440 rx_bytes_acc += stat.rx_bytes
1441 return (tx_pkts_acc, rx_pkts_acc, tx_bytes_acc, rx_bytes_acc)
1442
1443 tx_pkts_before, rx_pkts_before, \
1444 tx_bytes_before, rx_bytes_before = accumulate(initial)
1445
1446 # Wait 10s for counters to update
1447 for i in range(0, 100):
1448 stats = get_port_stats(test, port)
1449 tx_pkts_after, rx_pkts_after, \
1450 tx_bytes_after, rx_bytes_after = accumulate(stats)
1451 tx_pkts_diff = tx_pkts_after - tx_pkts_before
1452 rx_pkts_diff = rx_pkts_after - rx_pkts_before
1453 tx_bytes_diff = tx_bytes_after - tx_bytes_before
1454 rx_bytes_diff = rx_bytes_after - rx_bytes_before
1455 if (tx_pkts == None or tx_pkts == tx_pkts_diff) and \
1456 (rx_pkts == None or rx_pkts == rx_pkts_diff) and \
Rich Lane53b96812013-03-07 16:54:50 -08001457 (tx_bytes == None or tx_bytes <= tx_bytes_diff) and \
1458 (rx_bytes == None or rx_bytes <= rx_bytes_diff):
Rich Lane968b6192013-03-07 15:34:43 -08001459 break
1460 time.sleep(0.1)
1461
1462 if (tx_pkts != None):
1463 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))
1464 if (rx_pkts != None):
1465 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))
1466 if (tx_bytes != None):
Rich Lane53b96812013-03-07 16:54:50 -08001467 test.assertTrue(tx_bytes_diff >= tx_bytes and tx_bytes_diff <= tx_bytes*1.1,
1468 "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 -08001469 if (rx_bytes != None):
Rich Lane53b96812013-03-07 16:54:50 -08001470 test.assertTrue(rx_bytes_diff >= rx_bytes and rx_bytes_diff <= rx_bytes*1.1,
1471 "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 -08001472
Rich Lane6a334922013-03-07 16:14:52 -08001473def verify_queue_stats(test, port_no, queue_id,
1474 initial=[],
1475 pkts=None, bytes=None):
1476 """
1477 Verify that queue stats changed as expected.
1478
1479 Optionally takes an 'initial' list of stats entries, as returned by
1480 get_queue_stats(). If 'initial' is not given the counters are assumed to
1481 begin at 0.
1482 """
1483 def accumulate(stats):
1484 pkts_acc = bytes_acc = 0
1485 for stat in stats:
1486 pkts_acc += stat.tx_packets
1487 bytes_acc += stat.tx_bytes
1488 return (pkts_acc, bytes_acc)
1489
1490 pkts_before, bytes_before = accumulate(initial)
1491
1492 # Wait 10s for counters to update
1493 pkt_diff = byte_diff = None
1494 for i in range(0, 100):
1495 stats = get_queue_stats(test, port_no, queue_id)
1496 pkts_after, bytes_after = accumulate(stats)
1497 pkt_diff = pkts_after - pkts_before
1498 byte_diff = bytes_after - bytes_before
1499 if (pkts == None or pkt_diff >= pkts) and \
1500 (bytes == None or byte_diff >= bytes):
1501 break
Dan Talayco53724732013-03-08 23:54:02 -08001502 time.sleep(0.1)
Rich Lane6a334922013-03-07 16:14:52 -08001503
1504 if pkts != None:
1505 test.assertEquals(pkt_diff, pkts, "Queue packet counter not updated properly (expected increase of %d, got increase of %d)" % (pkts, pkt_diff))
1506
1507 if bytes != None:
Rich Lane53b96812013-03-07 16:54:50 -08001508 test.assertTrue(byte_diff >= bytes and byte_diff <= bytes*1.1,
1509 "Queue byte counter not updated properly (expected increase of %d, got increase of %d)" % (bytes, byte_diff))
Rich Laneae3428c2013-03-07 14:37:42 -08001510
Rich Lane4c504f32013-06-07 17:24:14 -07001511def packet_in_match(msg, data, in_port=None, reason=None):
1512 """
1513 Check whether the packet_in message 'msg' has fields matching 'data',
1514 'in_port', and 'reason'.
1515
1516 This function handles truncated packet_in data. The 'in_port' and 'reason'
1517 parameters are optional.
1518
1519 @param msg packet_in message
1520 @param data Expected packet_in data
1521 @param in_port Expected packet_in in_port, or None
1522 @param reason Expected packet_in reason, or None
1523 """
1524
Rich Lanec0d26dd2013-07-10 12:46:03 -07001525 if ofp.OFP_VERSION <= 2:
1526 pkt_in_port = msg.in_port
1527 else:
1528 oxms = { type(oxm): oxm for oxm in msg.match.oxm_list }
1529 if ofp.oxm.in_port in oxms:
1530 pkt_in_port = oxms[ofp.oxm.in_port].value
1531 else:
1532 logging.warn("Missing in_port in packet-in message")
1533 pkt_in_port = None
1534
1535 if in_port != None and in_port != pkt_in_port:
Rich Lane9f2f17e2013-09-13 13:19:37 -07001536 logging.debug("Incorrect packet_in in_port (expected %d, received %d)", in_port, pkt_in_port)
Rich Lane4c504f32013-06-07 17:24:14 -07001537 return False
1538
Rich Lanec0d26dd2013-07-10 12:46:03 -07001539 if reason != None and reason != msg.reason:
Rich Lane4c504f32013-06-07 17:24:14 -07001540 logging.debug("Incorrect packet_in reason (expected %d, received %d)", reason, msg.reason)
1541 return False
1542
1543 # Check that one of the packets is a prefix of the other.
1544 # The received packet may be either truncated or padded, but not both.
1545 # (Some of the padding may be truncated but that's irrelevant). We
1546 # need to check that the smaller packet is a prefix of the larger one.
1547 # Note that this check succeeds if the switch sends a zero-length
1548 # packet-in.
1549 compare_len = min(len(msg.data), len(data))
1550 if data[:compare_len] != msg.data[:compare_len]:
1551 logging.debug("Incorrect packet_in data")
1552 logging.debug("Expected %s" % format_packet(data[:compare_len]))
1553 logging.debug("Received %s" % format_packet(msg.data[:compare_len]))
1554 return False
1555
1556 return True
1557
1558def verify_packet_in(test, data, in_port, reason, controller=None):
1559 """
1560 Assert that the controller receives a packet_in message matching data 'data'
1561 from port 'in_port' with reason 'reason'. Does not trigger the packet_in
1562 itself, that's up to the test case.
1563
1564 @param test Instance of base_tests.SimpleProtocol
1565 @param pkt String to expect as the packet_in data
1566 @param in_port OpenFlow port number to expect as the packet_in in_port
1567 @param reason One of OFPR_* to expect as the packet_in reason
1568 @param controller Controller instance, defaults to test.controller
1569 @returns The received packet-in message
1570 """
1571
1572 if controller == None:
1573 controller = test.controller
1574
1575 end_time = time.time() + oftest.ofutils.default_timeout
1576
1577 while True:
1578 msg, _ = controller.poll(ofp.OFPT_PACKET_IN, end_time - time.time())
1579 if not msg:
1580 # Timeout
1581 break
1582 elif packet_in_match(msg, data, in_port, reason):
1583 # Found a matching message
1584 break
1585
1586 test.assertTrue(msg is not None, 'Packet in message not received on port %d' % in_port)
1587 return msg
1588
1589def verify_no_packet_in(test, data, in_port, controller=None):
1590 """
1591 Assert that the controller does not receive a packet_in message matching
1592 data 'data' from port 'in_port'.
1593
1594 @param test Instance of base_tests.SimpleProtocol
1595 @param pkt String to expect as the packet_in data
1596 @param in_port OpenFlow port number to expect as the packet_in in_port
1597 @param controller Controller instance, defaults to test.controller
1598 """
1599
1600 if controller == None:
1601 controller = test.controller
1602
1603 # Negative test, need to wait a short amount of time before checking we
1604 # didn't receive the message.
1605 time.sleep(0.5)
1606
1607 # Check every packet_in queued in the controller
1608 while True:
1609 msg, _ = controller.poll(ofp.OFPT_PACKET_IN, timeout=0)
1610 if msg == None:
1611 # No more queued packet_in messages
1612 break
1613 elif packet_in_match(msg, data, in_port, None):
1614 # Found a matching message
1615 break
1616
Rich Lane82c882d2013-08-09 17:13:52 -07001617 if in_port == None:
1618 test.assertTrue(msg == None, "Did not expect a packet-in message on any port")
1619 else:
1620 test.assertTrue(msg == None, "Did not expect a packet-in message on port %d" % in_port)
Rich Lane4c504f32013-06-07 17:24:14 -07001621
Rich Lane045db072013-08-06 13:16:30 -07001622def openflow_ports(num=None):
1623 """
1624 Return a list of 'num' OpenFlow port numbers
1625
1626 If 'num' is None, return all available ports. Otherwise, limit the length
1627 of the result to 'num' and raise an exception if not enough ports are
1628 available.
1629 """
1630 ports = sorted(oftest.config["port_map"].keys())
1631 if num != None and len(ports) < num:
1632 raise Exception("test requires %d ports but only %d are available" % (num, len(ports)))
1633 return ports[:num]
1634
Rich Lanee4b384d2013-09-13 14:33:40 -07001635def verify_packet(test, pkt, ofport):
1636 """
1637 Check that an expected packet is received
1638 """
1639 logging.debug("Checking for pkt on port %r", ofport)
1640 (rcv_port, rcv_pkt, pkt_time) = test.dataplane.poll(port_number=ofport, exp_pkt=str(pkt))
1641 test.assertTrue(rcv_pkt != None, "Did not receive pkt on %r" % ofport)
1642
1643def verify_no_packet(test, pkt, ofport):
1644 """
1645 Check that a particular packet is not received
1646 """
1647 logging.debug("Negative check for pkt on port %r", ofport)
1648 (rcv_port, rcv_pkt, pkt_time) = test.dataplane.poll(port_number=ofport, exp_pkt=str(pkt), timeout=0.01)
1649 test.assertTrue(rcv_pkt == None, "Received packet on %r" % ofport)
1650
1651def verify_no_other_packets(test):
1652 """
1653 Check that no unexpected packets are received
1654
1655 This is a no-op if the --relax option is in effect.
1656 """
1657 if oftest.config["relax"]:
1658 return
1659 logging.debug("Checking for unexpected packets on all ports")
1660 (rcv_port, rcv_pkt, pkt_time) = test.dataplane.poll(timeout=0.01)
1661 if rcv_pkt != None:
1662 logging.debug("Received unexpected packet on port %r: %s", rcv_port, format_packet(rcv_pkt))
1663 test.assertTrue(rcv_pkt == None, "Unexpected packet on port %r" % rcv_port)
1664
1665def verify_packets(test, pkt, ofports):
1666 """
1667 Check that a packet is received on certain ports
1668
1669 Also verifies that the packet is not received on any other ports, and that no
1670 other packets are received (unless --relax is in effect).
1671
1672 This covers the common and simplest cases for checking dataplane outputs.
1673 For more complex usage, like multiple different packets being output, or
1674 multiple packets on the same port, use the primitive verify_packet,
1675 verify_no_packet, and verify_no_other_packets functions directly.
1676 """
1677 pkt = str(pkt)
1678 for ofport in openflow_ports():
1679 if ofport in ofports:
1680 verify_packet(test, pkt, ofport)
1681 else:
1682 verify_no_packet(test, pkt, ofport)
1683 verify_no_other_packets(test)
1684
Rich Lane12d04592013-10-10 17:21:07 -07001685def verify_no_errors(ctrl):
1686 error, _ = ctrl.poll(ofp.OFPT_ERROR, 0)
1687 if error:
1688 raise AssertionError("unexpected error type=%d code=%d" % (error.err_type, error.code))
Rich Lanee4b384d2013-09-13 14:33:40 -07001689
Rich Lane7744e112013-01-11 17:23:57 -08001690__all__ = list(set(locals()) - _import_blacklist)