blob: 8b27f25e53a13cf09bf7c64123999c30133fe470 [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
Rich Lanee4b384d2013-09-13 14:33:40 -0700555
556 DEPRECATED in favor in verify_packets
Dan Talayco92c99122010-06-03 13:53:18 -0700557 """
Rich Lane91765672012-12-06 16:33:04 -0800558
559 # Wait this long for packets that we don't expect to receive.
560 # 100ms is (rarely) too short for positive tests on slow
561 # switches but is definitely not too short for a negative test.
562 negative_timeout = 0.1
563
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700564 exp_pkt_arg = None
Rich Lanecd97d3d2013-01-07 18:50:06 -0800565 if oftest.config["relax"]:
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700566 exp_pkt_arg = pkt
567
Dan Talayco92c99122010-06-03 13:53:18 -0700568 for ofport in yes_ports:
Rich Lane9a003812012-10-04 17:17:59 -0700569 logging.debug("Checking for pkt on port " + str(ofport))
Ken Chiang1bf01602012-04-04 10:48:23 -0700570 (rcv_port, rcv_pkt, pkt_time) = dp.poll(
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700571 port_number=ofport, exp_pkt=exp_pkt_arg)
Dan Talayco92c99122010-06-03 13:53:18 -0700572 assert_if.assertTrue(rcv_pkt is not None,
573 "Did not receive pkt on " + str(ofport))
Rich Lanecd97d3d2013-01-07 18:50:06 -0800574 if not oftest.dataplane.match_exp_pkt(pkt, rcv_pkt):
Rich Lane3c266832013-01-29 18:29:15 -0800575 logging.debug("Expected %s" % format_packet(pkt))
576 logging.debug("Received %s" % format_packet(rcv_pkt))
Rich Lanecd97d3d2013-01-07 18:50:06 -0800577 assert_if.assertTrue(oftest.dataplane.match_exp_pkt(pkt, rcv_pkt),
Rich Lane3c266832013-01-29 18:29:15 -0800578 "Received packet does not match expected packet " +
Ken Chiang1bf01602012-04-04 10:48:23 -0700579 "on port " + str(ofport))
Dan Talayco73f84012012-10-02 09:23:18 -0700580 if len(no_ports) > 0:
Rich Lane91765672012-12-06 16:33:04 -0800581 time.sleep(negative_timeout)
Dan Talayco92c99122010-06-03 13:53:18 -0700582 for ofport in no_ports:
Rich Lane9a003812012-10-04 17:17:59 -0700583 logging.debug("Negative check for pkt on port " + str(ofport))
Ken Chiang1bf01602012-04-04 10:48:23 -0700584 (rcv_port, rcv_pkt, pkt_time) = dp.poll(
Rich Lane91765672012-12-06 16:33:04 -0800585 port_number=ofport, timeout=0, exp_pkt=exp_pkt_arg)
Dan Talayco92c99122010-06-03 13:53:18 -0700586 assert_if.assertTrue(rcv_pkt is None,
587 "Unexpected pkt on port " + str(ofport))
Dan Talayco551befa2010-07-15 17:05:32 -0700588
589
Dan Talaycoc948d0b2012-03-23 12:17:54 -0700590def receive_pkt_verify(parent, egr_ports, exp_pkt, ing_port):
Dan Talayco551befa2010-07-15 17:05:32 -0700591 """
592 Receive a packet and verify it matches an expected value
Dan Talaycof6e76c02012-03-23 10:56:12 -0700593 @param egr_port A single port or list of ports
Dan Talayco551befa2010-07-15 17:05:32 -0700594
595 parent must implement dataplane, assertTrue and assertEqual
Rich Lanee4b384d2013-09-13 14:33:40 -0700596
597 DEPRECATED in favor in verify_packets
Dan Talayco551befa2010-07-15 17:05:32 -0700598 """
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700599 exp_pkt_arg = None
Rich Lanecd97d3d2013-01-07 18:50:06 -0800600 if oftest.config["relax"]:
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700601 exp_pkt_arg = exp_pkt
602
Dan Talaycof6e76c02012-03-23 10:56:12 -0700603 if type(egr_ports) == type([]):
604 egr_port_list = egr_ports
605 else:
606 egr_port_list = [egr_ports]
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700607
Dan Talaycof6e76c02012-03-23 10:56:12 -0700608 # Expect a packet from each port on egr port list
609 for egr_port in egr_port_list:
Dan Talaycod8ae7582012-03-23 12:24:56 -0700610 check_port = egr_port
Rich Lanee717c6e2013-03-12 10:25:50 -0700611 if egr_port == ofp.OFPP_IN_PORT:
Dan Talaycod8ae7582012-03-23 12:24:56 -0700612 check_port = ing_port
Dan Talaycof6e76c02012-03-23 10:56:12 -0700613 (rcv_port, rcv_pkt, pkt_time) = parent.dataplane.poll(
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700614 port_number=check_port, exp_pkt=exp_pkt_arg)
Dan Talayco551befa2010-07-15 17:05:32 -0700615
Dan Talaycof6e76c02012-03-23 10:56:12 -0700616 if rcv_pkt is None:
Rich Lane9a003812012-10-04 17:17:59 -0700617 logging.error("ERROR: No packet received from " +
Dan Talaycod8ae7582012-03-23 12:24:56 -0700618 str(check_port))
Dan Talayco551befa2010-07-15 17:05:32 -0700619
Dan Talaycof6e76c02012-03-23 10:56:12 -0700620 parent.assertTrue(rcv_pkt is not None,
Dan Talaycod8ae7582012-03-23 12:24:56 -0700621 "Did not receive packet port " + str(check_port))
Rich Lane9a003812012-10-04 17:17:59 -0700622 logging.debug("Packet len " + str(len(rcv_pkt)) + " in on " +
Dan Talaycof6e76c02012-03-23 10:56:12 -0700623 str(rcv_port))
624
625 if str(exp_pkt) != str(rcv_pkt):
Rich Lane9a003812012-10-04 17:17:59 -0700626 logging.error("ERROR: Packet match failed.")
627 logging.debug("Expected len " + str(len(exp_pkt)) + ": "
Dan Talaycof6e76c02012-03-23 10:56:12 -0700628 + str(exp_pkt).encode('hex'))
Rich Lane9a003812012-10-04 17:17:59 -0700629 logging.debug("Received len " + str(len(rcv_pkt)) + ": "
Dan Talaycof6e76c02012-03-23 10:56:12 -0700630 + str(rcv_pkt).encode('hex'))
Rich Lane5d7e89a2012-10-26 16:43:13 -0700631 logging.debug("Expected packet: " + inspect_packet(scapy.Ether(str(exp_pkt))))
632 logging.debug("Received packet: " + inspect_packet(scapy.Ether(str(rcv_pkt))))
Dan Talaycof6e76c02012-03-23 10:56:12 -0700633 parent.assertEqual(str(exp_pkt), str(rcv_pkt),
Dan Talaycod8ae7582012-03-23 12:24:56 -0700634 "Packet match error on port " + str(check_port))
Dan Talaycof6e76c02012-03-23 10:56:12 -0700635
Dan Talayco551befa2010-07-15 17:05:32 -0700636def match_verify(parent, req_match, res_match):
637 """
638 Verify flow matches agree; if they disagree, report where
639
640 parent must implement assertEqual
641 Use str() to ensure content is compared and not pointers
642 """
643
644 parent.assertEqual(req_match.wildcards, res_match.wildcards,
645 'Match failed: wildcards: ' + hex(req_match.wildcards) +
646 " != " + hex(res_match.wildcards))
647 parent.assertEqual(req_match.in_port, res_match.in_port,
648 'Match failed: in_port: ' + str(req_match.in_port) +
649 " != " + str(res_match.in_port))
Rich Laned0478ff2013-03-11 12:46:58 -0700650 parent.assertEqual(str(req_match.eth_src), str(res_match.eth_src),
651 'Match failed: eth_src: ' + str(req_match.eth_src) +
652 " != " + str(res_match.eth_src))
653 parent.assertEqual(str(req_match.eth_dst), str(res_match.eth_dst),
654 'Match failed: eth_dst: ' + str(req_match.eth_dst) +
655 " != " + str(res_match.eth_dst))
656 parent.assertEqual(req_match.vlan_vid, res_match.vlan_vid,
657 'Match failed: vlan_vid: ' + str(req_match.vlan_vid) +
658 " != " + str(res_match.vlan_vid))
659 parent.assertEqual(req_match.vlan_pcp, res_match.vlan_pcp,
660 'Match failed: vlan_pcp: ' +
661 str(req_match.vlan_pcp) + " != " +
662 str(res_match.vlan_pcp))
663 parent.assertEqual(req_match.eth_type, res_match.eth_type,
664 'Match failed: eth_type: ' + str(req_match.eth_type) +
665 " != " + str(res_match.eth_type))
Dan Talayco551befa2010-07-15 17:05:32 -0700666
Rich Lanee717c6e2013-03-12 10:25:50 -0700667 if (not(req_match.wildcards & ofp.OFPFW_DL_TYPE)
Rich Laned0478ff2013-03-11 12:46:58 -0700668 and (req_match.eth_type == IP_ETHERTYPE)):
669 parent.assertEqual(req_match.ip_dscp, res_match.ip_dscp,
670 'Match failed: ip_dscp: ' + str(req_match.ip_dscp) +
671 " != " + str(res_match.ip_dscp))
672 parent.assertEqual(req_match.ip_proto, res_match.ip_proto,
673 'Match failed: ip_proto: ' + str(req_match.ip_proto) +
674 " != " + str(res_match.ip_proto))
675 parent.assertEqual(req_match.ipv4_src, res_match.ipv4_src,
676 'Match failed: ipv4_src: ' + str(req_match.ipv4_src) +
677 " != " + str(res_match.ipv4_src))
678 parent.assertEqual(req_match.ipv4_dst, res_match.ipv4_dst,
679 'Match failed: ipv4_dst: ' + str(req_match.ipv4_dst) +
680 " != " + str(res_match.ipv4_dst))
Dan Talayco551befa2010-07-15 17:05:32 -0700681
Rich Lanee717c6e2013-03-12 10:25:50 -0700682 if (not(req_match.wildcards & ofp.OFPFW_NW_PROTO)
Rich Laned0478ff2013-03-11 12:46:58 -0700683 and ((req_match.ip_proto == TCP_PROTOCOL)
684 or (req_match.ip_proto == UDP_PROTOCOL))):
685 parent.assertEqual(req_match.tcp_src, res_match.tcp_src,
686 'Match failed: tcp_src: ' +
687 str(req_match.tcp_src) +
688 " != " + str(res_match.tcp_src))
689 parent.assertEqual(req_match.tcp_dst, res_match.tcp_dst,
690 'Match failed: tcp_dst: ' +
691 str(req_match.tcp_dst) +
692 " != " + str(res_match.tcp_dst))
Dan Talayco551befa2010-07-15 17:05:32 -0700693
Ed Swierk99a74de2012-08-22 06:40:54 -0700694def packet_to_flow_match(parent, packet):
Rich Lanef6883512013-03-11 17:00:09 -0700695 match = oftest.parse.packet_to_flow_match(packet)
Rich Laneab7476f2013-06-13 15:53:52 -0700696 if ofp.OFP_VERSION in [1, 2]:
697 match.wildcards |= required_wildcards(parent)
698 else:
699 # TODO remove incompatible OXM entries
700 pass
Ed Swierk99a74de2012-08-22 06:40:54 -0700701 return match
702
703def flow_msg_create(parent, pkt, ing_port=None, action_list=None, wildcards=None,
Dan Talaycof6e76c02012-03-23 10:56:12 -0700704 egr_ports=None, egr_queue=None, check_expire=False, in_band=False):
Dan Talayco551befa2010-07-15 17:05:32 -0700705 """
706 Create a flow message
707
708 Match on packet with given wildcards.
709 See flow_match_test for other parameter descriptoins
710 @param egr_queue if not None, make the output an enqueue action
Dan Talayco677c0b72011-08-23 22:53:38 -0700711 @param in_band if True, do not wildcard ingress port
Dan Talaycof6e76c02012-03-23 10:56:12 -0700712 @param egr_ports None (drop), single port or list of ports
Dan Talayco551befa2010-07-15 17:05:32 -0700713 """
Rich Lanef6883512013-03-11 17:00:09 -0700714 match = oftest.parse.packet_to_flow_match(pkt)
Dan Talayco551befa2010-07-15 17:05:32 -0700715 parent.assertTrue(match is not None, "Flow match from pkt failed")
Ed Swierk99a74de2012-08-22 06:40:54 -0700716 if wildcards is None:
717 wildcards = required_wildcards(parent)
Dan Talayco677c0b72011-08-23 22:53:38 -0700718 if in_band:
Rich Lanee717c6e2013-03-12 10:25:50 -0700719 wildcards &= ~ofp.OFPFW_IN_PORT
Dan Talayco551befa2010-07-15 17:05:32 -0700720 match.wildcards = wildcards
721 match.in_port = ing_port
722
Dan Talaycof6e76c02012-03-23 10:56:12 -0700723 if type(egr_ports) == type([]):
724 egr_port_list = egr_ports
725 else:
726 egr_port_list = [egr_ports]
727
Rich Lanee717c6e2013-03-12 10:25:50 -0700728 request = ofp.message.flow_add()
Dan Talayco551befa2010-07-15 17:05:32 -0700729 request.match = match
730 request.buffer_id = 0xffffffff
731 if check_expire:
Rich Lanee717c6e2013-03-12 10:25:50 -0700732 request.flags |= ofp.OFPFF_SEND_FLOW_REM
Dan Talayco551befa2010-07-15 17:05:32 -0700733 request.hard_timeout = 1
734
735 if action_list is not None:
736 for act in action_list:
Rich Lane9a003812012-10-04 17:17:59 -0700737 logging.debug("Adding action " + act.show())
Rich Lanec495d9e2013-03-08 17:43:36 -0800738 request.actions.append(act)
Dan Talayco551befa2010-07-15 17:05:32 -0700739
740 # Set up output/enqueue action if directed
741 if egr_queue is not None:
Dan Talaycof6e76c02012-03-23 10:56:12 -0700742 parent.assertTrue(egr_ports is not None, "Egress port not set")
Rich Lanee717c6e2013-03-12 10:25:50 -0700743 act = ofp.action.enqueue()
Dan Talaycof6e76c02012-03-23 10:56:12 -0700744 for egr_port in egr_port_list:
745 act.port = egr_port
746 act.queue_id = egr_queue
Rich Lanec495d9e2013-03-08 17:43:36 -0800747 request.actions.append(act)
Dan Talaycof6e76c02012-03-23 10:56:12 -0700748 elif egr_ports is not None:
749 for egr_port in egr_port_list:
Rich Lanee717c6e2013-03-12 10:25:50 -0700750 act = ofp.action.output()
Dan Talaycof6e76c02012-03-23 10:56:12 -0700751 act.port = egr_port
Rich Lanec495d9e2013-03-08 17:43:36 -0800752 request.actions.append(act)
Dan Talayco551befa2010-07-15 17:05:32 -0700753
Rich Lane9a003812012-10-04 17:17:59 -0700754 logging.debug(request.show())
Dan Talayco551befa2010-07-15 17:05:32 -0700755
756 return request
757
Jeffrey Townsendf3eae9c2012-03-28 18:23:21 -0700758def flow_msg_install(parent, request, clear_table_override=None):
Dan Talayco551befa2010-07-15 17:05:32 -0700759 """
760 Install a flow mod message in the switch
761
762 @param parent Must implement controller, assertEqual, assertTrue
763 @param request The request, all set to go
764 @param clear_table If true, clear the flow table before installing
765 """
Dan Talayco8a64e332012-03-28 14:53:20 -0700766
Rich Lane2014f9b2012-10-05 15:29:40 -0700767 clear_table = test_param_get('clear_table', default=True)
Jeffrey Townsendf3eae9c2012-03-28 18:23:21 -0700768 if(clear_table_override != None):
769 clear_table = clear_table_override
770
771 if clear_table:
Rich Lane9a003812012-10-04 17:17:59 -0700772 logging.debug("Clear flow table")
Rich Lane32bf9482013-01-03 17:26:30 -0800773 delete_all_flows(parent.controller)
Dan Talayco551befa2010-07-15 17:05:32 -0700774
Rich Lane9a003812012-10-04 17:17:59 -0700775 logging.debug("Insert flow")
Rich Lane5c3151c2013-01-03 17:15:41 -0800776 parent.controller.message_send(request)
Rich Lanee912d032012-12-22 14:28:33 -0800777
Rich Lane3a261d52013-01-03 17:45:08 -0800778 do_barrier(parent.controller)
Dan Talayco551befa2010-07-15 17:05:32 -0700779
Ed Swierk99a74de2012-08-22 06:40:54 -0700780def flow_match_test_port_pair(parent, ing_port, egr_ports, wildcards=None,
Rich Laned0478ff2013-03-11 12:46:58 -0700781 vlan_vid=-1, pkt=None, exp_pkt=None,
Rich Lanee5779d32012-10-05 17:56:04 -0700782 action_list=None):
Dan Talayco551befa2010-07-15 17:05:32 -0700783 """
784 Flow match test on single TCP packet
Dan Talaycof6e76c02012-03-23 10:56:12 -0700785 @param egr_ports A single port or list of ports
Dan Talayco551befa2010-07-15 17:05:32 -0700786
787 Run test with packet through switch from ing_port to egr_port
788 See flow_match_test for parameter descriptions
789 """
790
Ed Swierk99a74de2012-08-22 06:40:54 -0700791 if wildcards is None:
792 wildcards = required_wildcards(parent)
Rich Lane9a003812012-10-04 17:17:59 -0700793 logging.info("Pkt match test: " + str(ing_port) + " to " +
Dan Talaycof6e76c02012-03-23 10:56:12 -0700794 str(egr_ports))
Rich Laned0478ff2013-03-11 12:46:58 -0700795 logging.debug(" WC: " + hex(wildcards) + " vlan: " + str(vlan_vid))
Dan Talayco551befa2010-07-15 17:05:32 -0700796 if pkt is None:
Rich Laned0478ff2013-03-11 12:46:58 -0700797 pkt = simple_tcp_packet(dl_vlan_enable=(vlan_vid >= 0), vlan_vid=vlan_vid)
Rich Lanec41fbec2013-10-02 00:27:59 -0700798 if exp_pkt is None:
799 exp_pkt = pkt
Dan Talayco551befa2010-07-15 17:05:32 -0700800
801 request = flow_msg_create(parent, pkt, ing_port=ing_port,
Dan Talaycof6e76c02012-03-23 10:56:12 -0700802 wildcards=wildcards, egr_ports=egr_ports,
Dan Talayco551befa2010-07-15 17:05:32 -0700803 action_list=action_list)
804
805 flow_msg_install(parent, request)
806
Rich Lane9a003812012-10-04 17:17:59 -0700807 logging.debug("Send packet: " + str(ing_port) + " to " +
Dan Talaycof6e76c02012-03-23 10:56:12 -0700808 str(egr_ports))
Dan Talayco551befa2010-07-15 17:05:32 -0700809 parent.dataplane.send(ing_port, str(pkt))
810
Rich Lane8f45e2d2013-10-01 16:06:54 -0700811 exp_ports = [ing_port if port == ofp.OFPP_IN_PORT else port for port in egr_ports]
Rich Lanee4b384d2013-09-13 14:33:40 -0700812 verify_packets(parent, exp_pkt, exp_ports)
Dan Talayco551befa2010-07-15 17:05:32 -0700813
Rich Lane89725bb2012-12-03 16:23:27 -0800814def flow_match_test_pktout(parent, ing_port, egr_ports,
Rich Laned0478ff2013-03-11 12:46:58 -0700815 vlan_vid=-1, pkt=None, exp_pkt=None,
Rich Lane89725bb2012-12-03 16:23:27 -0800816 action_list=None):
817 """
818 Packet-out test on single TCP packet
819 @param egr_ports A single port or list of ports
820
821 Run test sending packet-out to egr_ports. The goal is to test the actions
822 taken on the packet, not the matching which is of course irrelevant.
823 See flow_match_test for parameter descriptions
824 """
825
826 if pkt is None:
Rich Laned0478ff2013-03-11 12:46:58 -0700827 pkt = simple_tcp_packet(dl_vlan_enable=(vlan_vid >= 0), vlan_vid=vlan_vid)
Rich Lanec41fbec2013-10-02 00:27:59 -0700828 if exp_pkt is None:
829 exp_pkt = pkt
Rich Lane89725bb2012-12-03 16:23:27 -0800830
Rich Lanee717c6e2013-03-12 10:25:50 -0700831 msg = ofp.message.packet_out()
Rich Lane89725bb2012-12-03 16:23:27 -0800832 msg.in_port = ing_port
Rich Laneea8c4722013-04-04 15:30:20 -0700833 msg.buffer_id = 0xffffffff
Rich Lane89725bb2012-12-03 16:23:27 -0800834 msg.data = str(pkt)
835 if action_list is not None:
836 for act in action_list:
Rich Lanec495d9e2013-03-08 17:43:36 -0800837 msg.actions.append(act)
Rich Lane89725bb2012-12-03 16:23:27 -0800838
839 # Set up output action
840 if egr_ports is not None:
841 for egr_port in egr_ports:
Rich Lanee717c6e2013-03-12 10:25:50 -0700842 act = ofp.action.output()
Rich Lane89725bb2012-12-03 16:23:27 -0800843 act.port = egr_port
Rich Lanec495d9e2013-03-08 17:43:36 -0800844 msg.actions.append(act)
Rich Lane89725bb2012-12-03 16:23:27 -0800845
846 logging.debug(msg.show())
Rich Lane5c3151c2013-01-03 17:15:41 -0800847 parent.controller.message_send(msg)
Rich Lane89725bb2012-12-03 16:23:27 -0800848
Rich Lane8f45e2d2013-10-01 16:06:54 -0700849 exp_ports = [ing_port if port == ofp.OFPP_IN_PORT else port for port in egr_ports]
Rich Lanee4b384d2013-09-13 14:33:40 -0700850 verify_packets(parent, exp_pkt, exp_ports)
Rich Lane89725bb2012-12-03 16:23:27 -0800851
Dan Talaycof6e76c02012-03-23 10:56:12 -0700852def get_egr_list(parent, of_ports, how_many, exclude_list=[]):
853 """
854 Generate a list of ports avoiding those in the exclude list
Rich Lane9a003812012-10-04 17:17:59 -0700855 @param parent Supplies logging
Dan Talaycof6e76c02012-03-23 10:56:12 -0700856 @param of_ports List of OF port numbers
857 @param how_many Number of ports to be added to the list
858 @param exclude_list List of ports not to be used
859 @returns An empty list if unable to find enough ports
860 """
861
Dan Talaycoc948d0b2012-03-23 12:17:54 -0700862 if how_many == 0:
863 return []
864
Dan Talaycof6e76c02012-03-23 10:56:12 -0700865 count = 0
866 egr_ports = []
867 for egr_idx in range(len(of_ports)):
868 if of_ports[egr_idx] not in exclude_list:
869 egr_ports.append(of_ports[egr_idx])
870 count += 1
871 if count >= how_many:
872 return egr_ports
Rich Lane9a003812012-10-04 17:17:59 -0700873 logging.debug("Could not generate enough egress ports for test")
Dan Talaycof6e76c02012-03-23 10:56:12 -0700874 return []
875
Rich Laned0478ff2013-03-11 12:46:58 -0700876def flow_match_test(parent, port_map, wildcards=None, vlan_vid=-1, pkt=None,
Rich Lanee5779d32012-10-05 17:56:04 -0700877 exp_pkt=None, action_list=None,
Dan Talaycoc948d0b2012-03-23 12:17:54 -0700878 max_test=0, egr_count=1, ing_port=False):
Dan Talayco551befa2010-07-15 17:05:32 -0700879 """
Rich Lane89725bb2012-12-03 16:23:27 -0800880 Run flow_match_test_port_pair on all port pairs and packet-out
Dan Talayco551befa2010-07-15 17:05:32 -0700881
882 @param max_test If > 0 no more than this number of tests are executed.
883 @param parent Must implement controller, dataplane, assertTrue, assertEqual
Rich Lane9a003812012-10-04 17:17:59 -0700884 and logging
Dan Talayco551befa2010-07-15 17:05:32 -0700885 @param pkt If not None, use this packet for ingress
886 @param wildcards For flow match entry
Rich Laned0478ff2013-03-11 12:46:58 -0700887 @param vlan_vid If not -1, and pkt is None, create a pkt w/ VLAN tag
Dan Talayco551befa2010-07-15 17:05:32 -0700888 @param exp_pkt If not None, use this as the expected output pkt; els use pkt
889 @param action_list Additional actions to add to flow mod
Dan Talaycocfa172f2012-03-23 12:03:00 -0700890 @param egr_count Number of egress ports; -1 means get from config w/ dflt 2
Dan Talayco551befa2010-07-15 17:05:32 -0700891 """
Ed Swierk99a74de2012-08-22 06:40:54 -0700892 if wildcards is None:
893 wildcards = required_wildcards(parent)
Dan Talayco551befa2010-07-15 17:05:32 -0700894 of_ports = port_map.keys()
895 of_ports.sort()
896 parent.assertTrue(len(of_ports) > 1, "Not enough ports for test")
897 test_count = 0
898
Dan Talaycocfa172f2012-03-23 12:03:00 -0700899 if egr_count == -1:
Rich Lane2014f9b2012-10-05 15:29:40 -0700900 egr_count = test_param_get('egr_count', default=2)
Dan Talaycocfa172f2012-03-23 12:03:00 -0700901
Dan Talayco551befa2010-07-15 17:05:32 -0700902 for ing_idx in range(len(of_ports)):
903 ingress_port = of_ports[ing_idx]
Dan Talaycof6e76c02012-03-23 10:56:12 -0700904 egr_ports = get_egr_list(parent, of_ports, egr_count,
905 exclude_list=[ingress_port])
Dan Talaycoc948d0b2012-03-23 12:17:54 -0700906 if ing_port:
Rich Lanee717c6e2013-03-12 10:25:50 -0700907 egr_ports.append(ofp.OFPP_IN_PORT)
Dan Talaycof6e76c02012-03-23 10:56:12 -0700908 if len(egr_ports) == 0:
909 parent.assertTrue(0, "Failed to generate egress port list")
910
911 flow_match_test_port_pair(parent, ingress_port, egr_ports,
Rich Laned0478ff2013-03-11 12:46:58 -0700912 wildcards=wildcards, vlan_vid=vlan_vid,
Dan Talaycof6e76c02012-03-23 10:56:12 -0700913 pkt=pkt, exp_pkt=exp_pkt,
Rich Lanee5779d32012-10-05 17:56:04 -0700914 action_list=action_list)
Dan Talaycof6e76c02012-03-23 10:56:12 -0700915 test_count += 1
916 if (max_test > 0) and (test_count > max_test):
Rich Lane9a003812012-10-04 17:17:59 -0700917 logging.info("Ran " + str(test_count) + " tests; exiting")
Rich Lane89725bb2012-12-03 16:23:27 -0800918 break
919
Ed Swierk38eea082013-01-02 19:46:20 -0800920 if not test_param_get('pktout_actions', default=True):
921 return
Rich Lane89725bb2012-12-03 16:23:27 -0800922
923 ingress_port = of_ports[0]
924 egr_ports = get_egr_list(parent, of_ports, egr_count,
925 exclude_list=[ingress_port])
926 if ing_port:
Rich Lanee717c6e2013-03-12 10:25:50 -0700927 egr_ports.append(ofp.OFPP_IN_PORT)
Rich Lane89725bb2012-12-03 16:23:27 -0800928 flow_match_test_pktout(parent, ingress_port, egr_ports,
Rich Laned0478ff2013-03-11 12:46:58 -0700929 vlan_vid=vlan_vid,
Rich Lane89725bb2012-12-03 16:23:27 -0800930 pkt=pkt, exp_pkt=exp_pkt,
931 action_list=action_list)
Dan Talayco551befa2010-07-15 17:05:32 -0700932
Rich Lane2014f9b2012-10-05 15:29:40 -0700933def test_param_get(key, default=None):
Dan Talayco4b2bee62010-07-20 14:10:05 -0700934 """
935 Return value passed via test-params if present
936
Dan Talayco4b2bee62010-07-20 14:10:05 -0700937 @param key The lookup key
938 @param default Default value to use if not found
939
940 If the pair 'key=val' appeared in the string passed to --test-params
941 on the command line, return val (as interpreted by exec). Otherwise
942 return default value.
Dan Talaycof6e76c02012-03-23 10:56:12 -0700943
944 WARNING: TEST PARAMETERS MUST BE PYTHON IDENTIFIERS;
945 eg egr_count, not egr-count.
Dan Talayco4b2bee62010-07-20 14:10:05 -0700946 """
947 try:
Rich Lanecd97d3d2013-01-07 18:50:06 -0800948 exec oftest.config["test_params"]
Dan Talayco4b2bee62010-07-20 14:10:05 -0700949 except:
950 return default
951
Dan Talayco4b2bee62010-07-20 14:10:05 -0700952 try:
Rich Lanefdec0fb2013-08-09 18:01:05 -0700953 return eval(str(key))
Dan Talayco4b2bee62010-07-20 14:10:05 -0700954 except:
955 return default
956
957def action_generate(parent, field_to_mod, mod_field_vals):
958 """
959 Create an action to modify the field indicated in field_to_mod
960
961 @param parent Must implement, assertTrue
962 @param field_to_mod The field to modify as a string name
963 @param mod_field_vals Hash of values to use for modified values
964 """
965
966 act = None
967
968 if field_to_mod in ['pktlen']:
969 return None
970
Rich Laned0478ff2013-03-11 12:46:58 -0700971 if field_to_mod == 'eth_dst':
Rich Lanee717c6e2013-03-12 10:25:50 -0700972 act = ofp.action.set_dl_dst()
Rich Lanef6883512013-03-11 17:00:09 -0700973 act.dl_addr = oftest.parse.parse_mac(mod_field_vals['eth_dst'])
Rich Laned0478ff2013-03-11 12:46:58 -0700974 elif field_to_mod == 'eth_src':
Rich Lanee717c6e2013-03-12 10:25:50 -0700975 act = ofp.action.set_dl_src()
Rich Lanef6883512013-03-11 17:00:09 -0700976 act.dl_addr = oftest.parse.parse_mac(mod_field_vals['eth_src'])
Dan Talayco4b2bee62010-07-20 14:10:05 -0700977 elif field_to_mod == 'dl_vlan_enable':
978 if not mod_field_vals['dl_vlan_enable']: # Strip VLAN tag
Rich Lanee717c6e2013-03-12 10:25:50 -0700979 act = ofp.action.strip_vlan()
Rich Laned0478ff2013-03-11 12:46:58 -0700980 # Add VLAN tag is handled by vlan_vid field
Dan Talayco4b2bee62010-07-20 14:10:05 -0700981 # Will return None in this case
Rich Laned0478ff2013-03-11 12:46:58 -0700982 elif field_to_mod == 'vlan_vid':
Rich Lanee717c6e2013-03-12 10:25:50 -0700983 act = ofp.action.set_vlan_vid()
Rich Laned0478ff2013-03-11 12:46:58 -0700984 act.vlan_vid = mod_field_vals['vlan_vid']
985 elif field_to_mod == 'vlan_pcp':
Rich Lanee717c6e2013-03-12 10:25:50 -0700986 act = ofp.action.set_vlan_pcp()
Rich Laned0478ff2013-03-11 12:46:58 -0700987 act.vlan_pcp = mod_field_vals['vlan_pcp']
Dan Talayco4b2bee62010-07-20 14:10:05 -0700988 elif field_to_mod == 'ip_src':
Rich Lanee717c6e2013-03-12 10:25:50 -0700989 act = ofp.action.set_nw_src()
Rich Lanef6883512013-03-11 17:00:09 -0700990 act.nw_addr = oftest.parse.parse_ip(mod_field_vals['ip_src'])
Dan Talayco4b2bee62010-07-20 14:10:05 -0700991 elif field_to_mod == 'ip_dst':
Rich Lanee717c6e2013-03-12 10:25:50 -0700992 act = ofp.action.set_nw_dst()
Rich Lanef6883512013-03-11 17:00:09 -0700993 act.nw_addr = oftest.parse.parse_ip(mod_field_vals['ip_dst'])
Dan Talayco4b2bee62010-07-20 14:10:05 -0700994 elif field_to_mod == 'ip_tos':
Rich Lanee717c6e2013-03-12 10:25:50 -0700995 act = ofp.action.set_nw_tos()
Dan Talayco4b2bee62010-07-20 14:10:05 -0700996 act.nw_tos = mod_field_vals['ip_tos']
997 elif field_to_mod == 'tcp_sport':
Rich Lanee717c6e2013-03-12 10:25:50 -0700998 act = ofp.action.set_tp_src()
Dan Talayco4b2bee62010-07-20 14:10:05 -0700999 act.tp_port = mod_field_vals['tcp_sport']
1000 elif field_to_mod == 'tcp_dport':
Rich Lanee717c6e2013-03-12 10:25:50 -07001001 act = ofp.action.set_tp_dst()
Dan Talayco4b2bee62010-07-20 14:10:05 -07001002 act.tp_port = mod_field_vals['tcp_dport']
Rich Lane110e0e32012-10-26 16:21:46 -07001003 elif field_to_mod == 'udp_sport':
Rich Lanee717c6e2013-03-12 10:25:50 -07001004 act = ofp.action.set_tp_src()
Rich Lane110e0e32012-10-26 16:21:46 -07001005 act.tp_port = mod_field_vals['udp_sport']
1006 elif field_to_mod == 'udp_dport':
Rich Lanee717c6e2013-03-12 10:25:50 -07001007 act = ofp.action.set_tp_dst()
Rich Lane110e0e32012-10-26 16:21:46 -07001008 act.tp_port = mod_field_vals['udp_dport']
Dan Talayco4b2bee62010-07-20 14:10:05 -07001009 else:
1010 parent.assertTrue(0, "Unknown field to modify: " + str(field_to_mod))
1011
1012 return act
1013
1014def pkt_action_setup(parent, start_field_vals={}, mod_field_vals={},
Rich Lane110e0e32012-10-26 16:21:46 -07001015 mod_fields=[], tp="tcp", check_test_params=False):
Dan Talayco4b2bee62010-07-20 14:10:05 -07001016 """
1017 Set up the ingress and expected packet and action list for a test
1018
Rich Lane2014f9b2012-10-05 15:29:40 -07001019 @param parent Must implement assertTrue
Dan Talayco4b2bee62010-07-20 14:10:05 -07001020 @param start_field_values Field values to use for ingress packet (optional)
1021 @param mod_field_values Field values to use for modified packet (optional)
1022 @param mod_fields The list of fields to be modified by the switch in the test.
1023 @params check_test_params If True, will check the parameters vid, add_vlan
1024 and strip_vlan from the command line.
1025
1026 Returns a triple: pkt-to-send, expected-pkt, action-list
1027 """
1028
1029 new_actions = []
1030
Dan Talayco4b2bee62010-07-20 14:10:05 -07001031 base_pkt_params = {}
1032 base_pkt_params['pktlen'] = 100
Rich Laned0478ff2013-03-11 12:46:58 -07001033 base_pkt_params['eth_dst'] = '00:DE:F0:12:34:56'
1034 base_pkt_params['eth_src'] = '00:23:45:67:89:AB'
Dan Talayco4b2bee62010-07-20 14:10:05 -07001035 base_pkt_params['dl_vlan_enable'] = False
Rich Laned0478ff2013-03-11 12:46:58 -07001036 base_pkt_params['vlan_vid'] = 2
1037 base_pkt_params['vlan_pcp'] = 0
Dan Talayco4b2bee62010-07-20 14:10:05 -07001038 base_pkt_params['ip_src'] = '192.168.0.1'
1039 base_pkt_params['ip_dst'] = '192.168.0.2'
1040 base_pkt_params['ip_tos'] = 0
Rich Lane110e0e32012-10-26 16:21:46 -07001041 if tp == "tcp":
1042 base_pkt_params['tcp_sport'] = 1234
1043 base_pkt_params['tcp_dport'] = 80
1044 elif tp == "udp":
1045 base_pkt_params['udp_sport'] = 1234
1046 base_pkt_params['udp_dport'] = 80
Dan Talayco4b2bee62010-07-20 14:10:05 -07001047 for keyname in start_field_vals.keys():
1048 base_pkt_params[keyname] = start_field_vals[keyname]
1049
1050 mod_pkt_params = {}
1051 mod_pkt_params['pktlen'] = 100
Rich Laned0478ff2013-03-11 12:46:58 -07001052 mod_pkt_params['eth_dst'] = '00:21:0F:ED:CB:A9'
1053 mod_pkt_params['eth_src'] = '00:ED:CB:A9:87:65'
Dan Talayco4b2bee62010-07-20 14:10:05 -07001054 mod_pkt_params['dl_vlan_enable'] = False
Rich Laned0478ff2013-03-11 12:46:58 -07001055 mod_pkt_params['vlan_vid'] = 3
1056 mod_pkt_params['vlan_pcp'] = 7
Dan Talayco4b2bee62010-07-20 14:10:05 -07001057 mod_pkt_params['ip_src'] = '10.20.30.40'
1058 mod_pkt_params['ip_dst'] = '50.60.70.80'
1059 mod_pkt_params['ip_tos'] = 0xf0
Rich Lane110e0e32012-10-26 16:21:46 -07001060 if tp == "tcp":
1061 mod_pkt_params['tcp_sport'] = 4321
1062 mod_pkt_params['tcp_dport'] = 8765
1063 elif tp == "udp":
1064 mod_pkt_params['udp_sport'] = 4321
1065 mod_pkt_params['udp_dport'] = 8765
Dan Talayco4b2bee62010-07-20 14:10:05 -07001066 for keyname in mod_field_vals.keys():
1067 mod_pkt_params[keyname] = mod_field_vals[keyname]
1068
1069 # Check for test param modifications
1070 strip = False
1071 if check_test_params:
Rich Lane2014f9b2012-10-05 15:29:40 -07001072 add_vlan = test_param_get('add_vlan')
1073 strip_vlan = test_param_get('strip_vlan')
1074 vid = test_param_get('vid')
Dan Talayco4b2bee62010-07-20 14:10:05 -07001075
1076 if add_vlan and strip_vlan:
1077 parent.assertTrue(0, "Add and strip VLAN both specified")
1078
1079 if vid:
1080 base_pkt_params['dl_vlan_enable'] = True
Rich Laned0478ff2013-03-11 12:46:58 -07001081 base_pkt_params['vlan_vid'] = vid
1082 if 'vlan_vid' in mod_fields:
1083 mod_pkt_params['vlan_vid'] = vid + 1
Dan Talayco4b2bee62010-07-20 14:10:05 -07001084
1085 if add_vlan:
1086 base_pkt_params['dl_vlan_enable'] = False
1087 mod_pkt_params['dl_vlan_enable'] = True
1088 mod_pkt_params['pktlen'] = base_pkt_params['pktlen'] + 4
1089 mod_fields.append('pktlen')
1090 mod_fields.append('dl_vlan_enable')
Rich Laned0478ff2013-03-11 12:46:58 -07001091 if 'vlan_vid' not in mod_fields:
1092 mod_fields.append('vlan_vid')
Dan Talayco4b2bee62010-07-20 14:10:05 -07001093 elif strip_vlan:
1094 base_pkt_params['dl_vlan_enable'] = True
1095 mod_pkt_params['dl_vlan_enable'] = False
1096 mod_pkt_params['pktlen'] = base_pkt_params['pktlen'] - 4
1097 mod_fields.append('dl_vlan_enable')
1098 mod_fields.append('pktlen')
1099
Rich Lane110e0e32012-10-26 16:21:46 -07001100 if tp == "tcp":
1101 packet_builder = simple_tcp_packet
1102 elif tp == "udp":
1103 packet_builder = simple_udp_packet
1104 else:
1105 raise NotImplementedError("unknown transport protocol %s" % tp)
1106
Dan Talayco4b2bee62010-07-20 14:10:05 -07001107 # Build the ingress packet
Rich Lane110e0e32012-10-26 16:21:46 -07001108 ingress_pkt = packet_builder(**base_pkt_params)
Dan Talayco4b2bee62010-07-20 14:10:05 -07001109
1110 # Build the expected packet, modifying the indicated fields
1111 for item in mod_fields:
1112 base_pkt_params[item] = mod_pkt_params[item]
1113 act = action_generate(parent, item, mod_pkt_params)
1114 if act:
1115 new_actions.append(act)
1116
Rich Lane110e0e32012-10-26 16:21:46 -07001117 expected_pkt = packet_builder(**base_pkt_params)
Dan Talayco4b2bee62010-07-20 14:10:05 -07001118
1119 return (ingress_pkt, expected_pkt, new_actions)
Dan Talayco677c0b72011-08-23 22:53:38 -07001120
1121# Generate a simple "drop" flow mod
1122# If in_band is true, then only drop from first test port
1123def flow_mod_gen(port_map, in_band):
Rich Lanee717c6e2013-03-12 10:25:50 -07001124 request = ofp.message.flow_add()
1125 request.match.wildcards = ofp.OFPFW_ALL
Dan Talayco677c0b72011-08-23 22:53:38 -07001126 if in_band:
Rich Lanee717c6e2013-03-12 10:25:50 -07001127 request.match.wildcards = ofp.OFPFW_ALL - ofp.OFPFW_IN_PORT
Dan Talayco677c0b72011-08-23 22:53:38 -07001128 for of_port, ifname in port_map.items(): # Grab first port
1129 break
1130 request.match.in_port = of_port
1131 request.buffer_id = 0xffffffff
1132 return request
Dan Talaycoba3745c2010-07-21 21:51:08 -07001133
1134def skip_message_emit(parent, s):
1135 """
1136 Print out a 'skipped' message to stderr
1137
1138 @param s The string to print out to the log file
Dan Talaycoba3745c2010-07-21 21:51:08 -07001139 """
1140 global skipped_test_count
1141
1142 skipped_test_count += 1
Rich Lane9a003812012-10-04 17:17:59 -07001143 logging.info("Skipping: " + s)
Dan Talayco2940fdd2013-02-06 15:01:35 -08001144 if oftest.config["debug"] < logging.WARNING:
Dan Talaycoba3745c2010-07-21 21:51:08 -07001145 sys.stderr.write("(skipped) ")
1146 else:
1147 sys.stderr.write("(S)")
Dan Talayco677c0b72011-08-23 22:53:38 -07001148
Dan Talayco8a64e332012-03-28 14:53:20 -07001149
1150def all_stats_get(parent):
1151 """
1152 Get the aggregate stats for all flows in the table
1153 @param parent Test instance with controller connection and assert
1154 @returns dict with keys flows, packets, bytes, active (flows),
1155 lookups, matched
1156 """
Rich Lanee717c6e2013-03-12 10:25:50 -07001157 stat_req = ofp.message.aggregate_stats_request()
1158 stat_req.match = ofp.match()
1159 stat_req.match.wildcards = ofp.OFPFW_ALL
Dan Talayco8a64e332012-03-28 14:53:20 -07001160 stat_req.table_id = 0xff
Rich Lanee717c6e2013-03-12 10:25:50 -07001161 stat_req.out_port = ofp.OFPP_NONE
Dan Talayco8a64e332012-03-28 14:53:20 -07001162
1163 rv = {}
1164
Rich Lanec8aaa3e2012-07-26 19:28:02 -07001165 (reply, pkt) = parent.controller.transact(stat_req)
Rich Lane5fd6faf2013-03-11 13:30:20 -07001166 parent.assertTrue(len(reply.entries) == 1, "Did not receive flow stats reply")
Dan Talayco8a64e332012-03-28 14:53:20 -07001167
Rich Lane5fd6faf2013-03-11 13:30:20 -07001168 for obj in reply.entries:
Dan Talayco8a64e332012-03-28 14:53:20 -07001169 (rv["flows"], rv["packets"], rv["bytes"]) = (obj.flow_count,
1170 obj.packet_count, obj.byte_count)
1171 break
1172
Rich Lanee717c6e2013-03-12 10:25:50 -07001173 request = ofp.message.table_stats_request()
Rich Lanec8aaa3e2012-07-26 19:28:02 -07001174 (reply , pkt) = parent.controller.transact(request)
Dan Talayco8a64e332012-03-28 14:53:20 -07001175
1176
1177 (rv["active"], rv["lookups"], rv["matched"]) = (0,0,0)
Rich Lane5fd6faf2013-03-11 13:30:20 -07001178 for obj in reply.entries:
Dan Talayco8a64e332012-03-28 14:53:20 -07001179 rv["active"] += obj.active_count
1180 rv["lookups"] += obj.lookup_count
1181 rv["matched"] += obj.matched_count
1182
1183 return rv
Dan Talayco2baf8b52012-03-30 09:55:42 -07001184
Rich Lane7744e112013-01-11 17:23:57 -08001185_import_blacklist.add('FILTER')
Dan Talayco2baf8b52012-03-30 09:55:42 -07001186FILTER=''.join([(len(repr(chr(x)))==3) and chr(x) or '.'
1187 for x in range(256)])
1188
1189def hex_dump_buffer(src, length=16):
1190 """
1191 Convert src to a hex dump string and return the string
1192 @param src The source buffer
1193 @param length The number of bytes shown in each line
1194 @returns A string showing the hex dump
1195 """
Dan Talaycoc516fa02012-04-12 22:28:43 -07001196 result = ["\n"]
Dan Talayco2baf8b52012-03-30 09:55:42 -07001197 for i in xrange(0, len(src), length):
1198 chars = src[i:i+length]
1199 hex = ' '.join(["%02x" % ord(x) for x in chars])
1200 printable = ''.join(["%s" % ((ord(x) <= 127 and
1201 FILTER[ord(x)]) or '.') for x in chars])
1202 result.append("%04x %-*s %s\n" % (i, length*3, hex, printable))
1203 return ''.join(result)
1204
1205def format_packet(pkt):
1206 return "Packet length %d \n%s" % (len(str(pkt)),
1207 hex_dump_buffer(str(pkt)))
Rich Lane5d7e89a2012-10-26 16:43:13 -07001208
1209def inspect_packet(pkt):
1210 """
1211 Wrapper around scapy's show() method.
1212 @returns A string showing the dissected packet.
1213 """
1214 from cStringIO import StringIO
1215 out = None
1216 backup = sys.stdout
1217 try:
Rich Lanefdec0fb2013-08-09 18:01:05 -07001218 tmp = StringIO()
1219 sys.stdout = tmp
Rich Lane5d7e89a2012-10-26 16:43:13 -07001220 pkt.show2()
Rich Lanefdec0fb2013-08-09 18:01:05 -07001221 out = tmp.getvalue()
1222 tmp.close()
Rich Lane5d7e89a2012-10-26 16:43:13 -07001223 finally:
1224 sys.stdout = backup
1225 return out
Rich Lane0a4f6372013-01-02 14:40:22 -08001226
1227def nonstandard(cls):
1228 """
Rich Lanecc45b8e2013-01-02 15:55:02 -08001229 Testcase decorator that marks the test as being non-standard.
1230 These tests are not automatically added to the "standard" group.
Rich Lane0a4f6372013-01-02 14:40:22 -08001231 """
Rich Lanecc45b8e2013-01-02 15:55:02 -08001232 cls._nonstandard = True
Rich Lane0a4f6372013-01-02 14:40:22 -08001233 return cls
1234
1235def disabled(cls):
1236 """
Rich Lanecc45b8e2013-01-02 15:55:02 -08001237 Testcase decorator that marks the test as being disabled.
1238 These tests are not automatically added to the "standard" group or
1239 their module's group.
Rich Lane0a4f6372013-01-02 14:40:22 -08001240 """
Rich Lanecc45b8e2013-01-02 15:55:02 -08001241 cls._disabled = True
Rich Lane0a4f6372013-01-02 14:40:22 -08001242 return cls
Rich Lane97e99652013-01-02 17:23:20 -08001243
1244def group(name):
1245 """
1246 Testcase decorator that adds the test to a group.
1247 """
1248 def fn(cls):
1249 if not hasattr(cls, "_groups"):
1250 cls._groups = []
1251 cls._groups.append(name)
1252 return cls
1253 return fn
Rich Lane5a9a1922013-01-11 14:29:30 -08001254
1255def version(ver):
1256 """
1257 Testcase decorator that specifies which versions of OpenFlow the test
1258 supports. The default is 1.0+. This decorator may only be used once.
1259
1260 Supported syntax:
1261 1.0 -> 1.0
1262 1.0,1.2,1.3 -> 1.0, 1.2, 1.3
1263 1.0+ -> 1.0, 1.1, 1.2, 1.3
1264 """
1265 versions = parse_version(ver)
1266 def fn(cls):
1267 cls._versions = versions
1268 return cls
1269 return fn
1270
1271def parse_version(ver):
1272 allowed_versions = ["1.0", "1.1", "1.2", "1.3"]
1273 if re.match("^1\.\d+$", ver):
1274 versions = set([ver])
1275 elif re.match("^(1\.\d+)\+$", ver):
1276 if not ver[:-1] in allowed_versions:
1277 raise ValueError("invalid OpenFlow version %s" % ver[:-1])
1278 versions = set()
1279 if ver != "1.1+": versions.add("1.0")
1280 if ver != "1.2+": versions.add("1.1")
1281 if ver != "1.3+": versions.add("1.2")
1282 versions.add("1.3")
1283 else:
1284 versions = set(ver.split(','))
1285
1286 for version in versions:
1287 if not version in allowed_versions:
1288 raise ValueError("invalid OpenFlow version %s" % version)
1289
1290 return versions
1291
1292assert(parse_version("1.0") == set(["1.0"]))
1293assert(parse_version("1.0,1.2,1.3") == set(["1.0", "1.2", "1.3"]))
1294assert(parse_version("1.0+") == set(["1.0", "1.1", "1.2", "1.3"]))
Rich Lane7744e112013-01-11 17:23:57 -08001295
Rich Laneae3428c2013-03-07 14:37:42 -08001296def get_stats(test, req):
1297 """
1298 Retrieve a list of stats entries. Handles OFPSF_REPLY_MORE.
1299 """
Rich Lanebd56ed62013-07-10 15:49:44 -07001300 if ofp.OFP_VERSION <= 3:
1301 more_flag = ofp.OFPSF_REPLY_MORE
1302 else:
1303 more_flag = ofp.OFPMPF_REPLY_MORE
Rich Laneae3428c2013-03-07 14:37:42 -08001304 stats = []
1305 reply, _ = test.controller.transact(req)
1306 test.assertTrue(reply is not None, "No response to stats request")
Rich Lane5fd6faf2013-03-11 13:30:20 -07001307 stats.extend(reply.entries)
Rich Lanebd56ed62013-07-10 15:49:44 -07001308 while reply.flags & more_flag != 0:
Rich Lane720eaf22013-08-09 18:00:45 -07001309 reply, pkt = test.controller.poll(exp_msg=ofp.OFPT_STATS_REPLY)
Rich Laneae3428c2013-03-07 14:37:42 -08001310 test.assertTrue(reply is not None, "No response to stats request")
Rich Lane5fd6faf2013-03-11 13:30:20 -07001311 stats.extend(reply.entries)
Rich Laneae3428c2013-03-07 14:37:42 -08001312 return stats
1313
Rich Lanebd56ed62013-07-10 15:49:44 -07001314def get_flow_stats(test, match, table_id=None,
1315 out_port=None, out_group=None,
1316 cookie=0, cookie_mask=0):
Rich Laneae3428c2013-03-07 14:37:42 -08001317 """
1318 Retrieve a list of flow stats entries.
1319 """
Rich Lanebd56ed62013-07-10 15:49:44 -07001320
1321 if table_id == None:
1322 if ofp.OFP_VERSION <= 2:
1323 table_id = 0xff
1324 else:
1325 table_id = ofp.OFPTT_ALL
1326
Rich Lanef3bc48c2013-05-03 17:39:35 -07001327 if out_port == None:
Rich Lanebd56ed62013-07-10 15:49:44 -07001328 if ofp.OFP_VERSION == 1:
1329 out_port = ofp.OFPP_NONE
1330 else:
1331 out_port = ofp.OFPP_ANY
1332
1333 if out_group == None:
1334 if ofp.OFP_VERSION > 1:
1335 out_group = ofp.OFPP_ANY
1336
Rich Lanee717c6e2013-03-12 10:25:50 -07001337 req = ofp.message.flow_stats_request(match=match,
Rich Lanebd56ed62013-07-10 15:49:44 -07001338 table_id=table_id,
1339 out_port=out_port)
1340 if ofp.OFP_VERSION > 1:
1341 req.out_group = out_group
1342 req.cookie = cookie
1343 req.cookie_mask = cookie_mask
1344
Rich Laneae3428c2013-03-07 14:37:42 -08001345 return get_stats(test, req)
1346
Rich Lane968b6192013-03-07 15:34:43 -08001347def get_port_stats(test, port_no):
1348 """
1349 Retrieve a list of port stats entries.
1350 """
Rich Lanee717c6e2013-03-12 10:25:50 -07001351 req = ofp.message.port_stats_request(port_no=port_no)
Rich Lane968b6192013-03-07 15:34:43 -08001352 return get_stats(test, req)
1353
Rich Lane6a334922013-03-07 16:14:52 -08001354def get_queue_stats(test, port_no, queue_id):
1355 """
1356 Retrieve a list of queue stats entries.
1357 """
Rich Lanee717c6e2013-03-12 10:25:50 -07001358 req = ofp.message.queue_stats_request(port_no=port_no, queue_id=queue_id)
Rich Lane6a334922013-03-07 16:14:52 -08001359 return get_stats(test, req)
1360
Rich Laneae3428c2013-03-07 14:37:42 -08001361def verify_flow_stats(test, match, table_id=0xff,
Rich Lanef3bc48c2013-05-03 17:39:35 -07001362 out_port=None,
Rich Laneae3428c2013-03-07 14:37:42 -08001363 initial=[],
1364 pkts=None, bytes=None):
1365 """
1366 Verify that flow stats changed as expected.
1367
1368 Optionally takes an 'initial' list of stats entries, as returned by
1369 get_flow_stats(). If 'initial' is not given the counters are assumed to
1370 begin at 0.
1371 """
Rich Lanef3bc48c2013-05-03 17:39:35 -07001372 if out_port == None:
1373 out_port = ofp.OFPP_NONE
1374
Rich Laneae3428c2013-03-07 14:37:42 -08001375 def accumulate(stats):
1376 pkts_acc = bytes_acc = 0
1377 for stat in stats:
1378 pkts_acc += stat.packet_count
1379 bytes_acc += stat.byte_count
1380 return (pkts_acc, bytes_acc)
1381
1382 pkts_before, bytes_before = accumulate(initial)
1383
1384 # Wait 10s for counters to update
1385 pkt_diff = byte_diff = None
1386 for i in range(0, 100):
1387 stats = get_flow_stats(test, match, table_id=table_id, out_port=out_port)
1388 pkts_after, bytes_after = accumulate(stats)
1389 pkt_diff = pkts_after - pkts_before
1390 byte_diff = bytes_after - bytes_before
1391 if (pkts == None or pkt_diff >= pkts) and \
1392 (bytes == None or byte_diff >= bytes):
1393 break
Dan Talayco53724732013-03-08 23:54:02 -08001394 time.sleep(0.1)
Rich Laneae3428c2013-03-07 14:37:42 -08001395
1396 if pkts != None:
1397 test.assertEquals(pkt_diff, pkts, "Flow packet counter not updated properly (expected increase of %d, got increase of %d)" % (pkts, pkt_diff))
1398
1399 if bytes != None:
Rich Lane53b96812013-03-07 16:54:50 -08001400 test.assertTrue(byte_diff >= bytes and byte_diff <= bytes*1.1,
1401 "Flow byte counter not updated properly (expected increase of %d, got increase of %d)" % (bytes, byte_diff))
Rich Laneae3428c2013-03-07 14:37:42 -08001402
Rich Lane968b6192013-03-07 15:34:43 -08001403def verify_port_stats(test, port,
1404 initial=[],
1405 tx_pkts=None, rx_pkts=None,
1406 tx_bytes=None, rx_bytes=None):
1407 """
1408 Verify that port stats changed as expected.
1409
1410 Optionally takes an 'initial' list of stats entries, as returned by
1411 get_port_stats(). If 'initial' is not given the counters are assumed to
1412 begin at 0.
1413 """
1414 def accumulate(stats):
1415 tx_pkts_acc = rx_pkts_acc = tx_bytes_acc = rx_bytes_acc = 0
1416 for stat in stats:
1417 tx_pkts_acc += stat.tx_packets
1418 rx_pkts_acc += stat.rx_packets
1419 tx_bytes_acc += stat.tx_bytes
1420 rx_bytes_acc += stat.rx_bytes
1421 return (tx_pkts_acc, rx_pkts_acc, tx_bytes_acc, rx_bytes_acc)
1422
1423 tx_pkts_before, rx_pkts_before, \
1424 tx_bytes_before, rx_bytes_before = accumulate(initial)
1425
1426 # Wait 10s for counters to update
1427 for i in range(0, 100):
1428 stats = get_port_stats(test, port)
1429 tx_pkts_after, rx_pkts_after, \
1430 tx_bytes_after, rx_bytes_after = accumulate(stats)
1431 tx_pkts_diff = tx_pkts_after - tx_pkts_before
1432 rx_pkts_diff = rx_pkts_after - rx_pkts_before
1433 tx_bytes_diff = tx_bytes_after - tx_bytes_before
1434 rx_bytes_diff = rx_bytes_after - rx_bytes_before
1435 if (tx_pkts == None or tx_pkts == tx_pkts_diff) and \
1436 (rx_pkts == None or rx_pkts == rx_pkts_diff) and \
Rich Lane53b96812013-03-07 16:54:50 -08001437 (tx_bytes == None or tx_bytes <= tx_bytes_diff) and \
1438 (rx_bytes == None or rx_bytes <= rx_bytes_diff):
Rich Lane968b6192013-03-07 15:34:43 -08001439 break
1440 time.sleep(0.1)
1441
1442 if (tx_pkts != None):
1443 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))
1444 if (rx_pkts != None):
1445 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))
1446 if (tx_bytes != None):
Rich Lane53b96812013-03-07 16:54:50 -08001447 test.assertTrue(tx_bytes_diff >= tx_bytes and tx_bytes_diff <= tx_bytes*1.1,
1448 "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 -08001449 if (rx_bytes != None):
Rich Lane53b96812013-03-07 16:54:50 -08001450 test.assertTrue(rx_bytes_diff >= rx_bytes and rx_bytes_diff <= rx_bytes*1.1,
1451 "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 -08001452
Rich Lane6a334922013-03-07 16:14:52 -08001453def verify_queue_stats(test, port_no, queue_id,
1454 initial=[],
1455 pkts=None, bytes=None):
1456 """
1457 Verify that queue stats changed as expected.
1458
1459 Optionally takes an 'initial' list of stats entries, as returned by
1460 get_queue_stats(). If 'initial' is not given the counters are assumed to
1461 begin at 0.
1462 """
1463 def accumulate(stats):
1464 pkts_acc = bytes_acc = 0
1465 for stat in stats:
1466 pkts_acc += stat.tx_packets
1467 bytes_acc += stat.tx_bytes
1468 return (pkts_acc, bytes_acc)
1469
1470 pkts_before, bytes_before = accumulate(initial)
1471
1472 # Wait 10s for counters to update
1473 pkt_diff = byte_diff = None
1474 for i in range(0, 100):
1475 stats = get_queue_stats(test, port_no, queue_id)
1476 pkts_after, bytes_after = accumulate(stats)
1477 pkt_diff = pkts_after - pkts_before
1478 byte_diff = bytes_after - bytes_before
1479 if (pkts == None or pkt_diff >= pkts) and \
1480 (bytes == None or byte_diff >= bytes):
1481 break
Dan Talayco53724732013-03-08 23:54:02 -08001482 time.sleep(0.1)
Rich Lane6a334922013-03-07 16:14:52 -08001483
1484 if pkts != None:
1485 test.assertEquals(pkt_diff, pkts, "Queue packet counter not updated properly (expected increase of %d, got increase of %d)" % (pkts, pkt_diff))
1486
1487 if bytes != None:
Rich Lane53b96812013-03-07 16:54:50 -08001488 test.assertTrue(byte_diff >= bytes and byte_diff <= bytes*1.1,
1489 "Queue byte counter not updated properly (expected increase of %d, got increase of %d)" % (bytes, byte_diff))
Rich Laneae3428c2013-03-07 14:37:42 -08001490
Rich Lane4c504f32013-06-07 17:24:14 -07001491def packet_in_match(msg, data, in_port=None, reason=None):
1492 """
1493 Check whether the packet_in message 'msg' has fields matching 'data',
1494 'in_port', and 'reason'.
1495
1496 This function handles truncated packet_in data. The 'in_port' and 'reason'
1497 parameters are optional.
1498
1499 @param msg packet_in message
1500 @param data Expected packet_in data
1501 @param in_port Expected packet_in in_port, or None
1502 @param reason Expected packet_in reason, or None
1503 """
1504
Rich Lanec0d26dd2013-07-10 12:46:03 -07001505 if ofp.OFP_VERSION <= 2:
1506 pkt_in_port = msg.in_port
1507 else:
1508 oxms = { type(oxm): oxm for oxm in msg.match.oxm_list }
1509 if ofp.oxm.in_port in oxms:
1510 pkt_in_port = oxms[ofp.oxm.in_port].value
1511 else:
1512 logging.warn("Missing in_port in packet-in message")
1513 pkt_in_port = None
1514
1515 if in_port != None and in_port != pkt_in_port:
Rich Lane9f2f17e2013-09-13 13:19:37 -07001516 logging.debug("Incorrect packet_in in_port (expected %d, received %d)", in_port, pkt_in_port)
Rich Lane4c504f32013-06-07 17:24:14 -07001517 return False
1518
Rich Lanec0d26dd2013-07-10 12:46:03 -07001519 if reason != None and reason != msg.reason:
Rich Lane4c504f32013-06-07 17:24:14 -07001520 logging.debug("Incorrect packet_in reason (expected %d, received %d)", reason, msg.reason)
1521 return False
1522
1523 # Check that one of the packets is a prefix of the other.
1524 # The received packet may be either truncated or padded, but not both.
1525 # (Some of the padding may be truncated but that's irrelevant). We
1526 # need to check that the smaller packet is a prefix of the larger one.
1527 # Note that this check succeeds if the switch sends a zero-length
1528 # packet-in.
1529 compare_len = min(len(msg.data), len(data))
1530 if data[:compare_len] != msg.data[:compare_len]:
1531 logging.debug("Incorrect packet_in data")
1532 logging.debug("Expected %s" % format_packet(data[:compare_len]))
1533 logging.debug("Received %s" % format_packet(msg.data[:compare_len]))
1534 return False
1535
1536 return True
1537
1538def verify_packet_in(test, data, in_port, reason, controller=None):
1539 """
1540 Assert that the controller receives a packet_in message matching data 'data'
1541 from port 'in_port' with reason 'reason'. Does not trigger the packet_in
1542 itself, that's up to the test case.
1543
1544 @param test Instance of base_tests.SimpleProtocol
1545 @param pkt String to expect as the packet_in data
1546 @param in_port OpenFlow port number to expect as the packet_in in_port
1547 @param reason One of OFPR_* to expect as the packet_in reason
1548 @param controller Controller instance, defaults to test.controller
1549 @returns The received packet-in message
1550 """
1551
1552 if controller == None:
1553 controller = test.controller
1554
1555 end_time = time.time() + oftest.ofutils.default_timeout
1556
1557 while True:
1558 msg, _ = controller.poll(ofp.OFPT_PACKET_IN, end_time - time.time())
1559 if not msg:
1560 # Timeout
1561 break
1562 elif packet_in_match(msg, data, in_port, reason):
1563 # Found a matching message
1564 break
1565
1566 test.assertTrue(msg is not None, 'Packet in message not received on port %d' % in_port)
1567 return msg
1568
1569def verify_no_packet_in(test, data, in_port, controller=None):
1570 """
1571 Assert that the controller does not receive a packet_in message matching
1572 data 'data' from port 'in_port'.
1573
1574 @param test Instance of base_tests.SimpleProtocol
1575 @param pkt String to expect as the packet_in data
1576 @param in_port OpenFlow port number to expect as the packet_in in_port
1577 @param controller Controller instance, defaults to test.controller
1578 """
1579
1580 if controller == None:
1581 controller = test.controller
1582
1583 # Negative test, need to wait a short amount of time before checking we
1584 # didn't receive the message.
1585 time.sleep(0.5)
1586
1587 # Check every packet_in queued in the controller
1588 while True:
1589 msg, _ = controller.poll(ofp.OFPT_PACKET_IN, timeout=0)
1590 if msg == None:
1591 # No more queued packet_in messages
1592 break
1593 elif packet_in_match(msg, data, in_port, None):
1594 # Found a matching message
1595 break
1596
Rich Lane82c882d2013-08-09 17:13:52 -07001597 if in_port == None:
1598 test.assertTrue(msg == None, "Did not expect a packet-in message on any port")
1599 else:
1600 test.assertTrue(msg == None, "Did not expect a packet-in message on port %d" % in_port)
Rich Lane4c504f32013-06-07 17:24:14 -07001601
Rich Lane045db072013-08-06 13:16:30 -07001602def openflow_ports(num=None):
1603 """
1604 Return a list of 'num' OpenFlow port numbers
1605
1606 If 'num' is None, return all available ports. Otherwise, limit the length
1607 of the result to 'num' and raise an exception if not enough ports are
1608 available.
1609 """
1610 ports = sorted(oftest.config["port_map"].keys())
1611 if num != None and len(ports) < num:
1612 raise Exception("test requires %d ports but only %d are available" % (num, len(ports)))
1613 return ports[:num]
1614
Rich Lanee4b384d2013-09-13 14:33:40 -07001615def verify_packet(test, pkt, ofport):
1616 """
1617 Check that an expected packet is received
1618 """
1619 logging.debug("Checking for pkt on port %r", ofport)
1620 (rcv_port, rcv_pkt, pkt_time) = test.dataplane.poll(port_number=ofport, exp_pkt=str(pkt))
1621 test.assertTrue(rcv_pkt != None, "Did not receive pkt on %r" % ofport)
1622
1623def verify_no_packet(test, pkt, ofport):
1624 """
1625 Check that a particular packet is not received
1626 """
1627 logging.debug("Negative check for pkt on port %r", ofport)
1628 (rcv_port, rcv_pkt, pkt_time) = test.dataplane.poll(port_number=ofport, exp_pkt=str(pkt), timeout=0.01)
1629 test.assertTrue(rcv_pkt == None, "Received packet on %r" % ofport)
1630
1631def verify_no_other_packets(test):
1632 """
1633 Check that no unexpected packets are received
1634
1635 This is a no-op if the --relax option is in effect.
1636 """
1637 if oftest.config["relax"]:
1638 return
1639 logging.debug("Checking for unexpected packets on all ports")
1640 (rcv_port, rcv_pkt, pkt_time) = test.dataplane.poll(timeout=0.01)
1641 if rcv_pkt != None:
1642 logging.debug("Received unexpected packet on port %r: %s", rcv_port, format_packet(rcv_pkt))
1643 test.assertTrue(rcv_pkt == None, "Unexpected packet on port %r" % rcv_port)
1644
1645def verify_packets(test, pkt, ofports):
1646 """
1647 Check that a packet is received on certain ports
1648
1649 Also verifies that the packet is not received on any other ports, and that no
1650 other packets are received (unless --relax is in effect).
1651
1652 This covers the common and simplest cases for checking dataplane outputs.
1653 For more complex usage, like multiple different packets being output, or
1654 multiple packets on the same port, use the primitive verify_packet,
1655 verify_no_packet, and verify_no_other_packets functions directly.
1656 """
1657 pkt = str(pkt)
1658 for ofport in openflow_ports():
1659 if ofport in ofports:
1660 verify_packet(test, pkt, ofport)
1661 else:
1662 verify_no_packet(test, pkt, ofport)
1663 verify_no_other_packets(test)
1664
1665
Rich Lane7744e112013-01-11 17:23:57 -08001666__all__ = list(set(locals()) - _import_blacklist)