blob: e8498d5a1b30ec06277dea7c3a169d0c35da4772 [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',
Shudong Zhouc7562b12013-02-06 01:12:18 -0800387 arp_op=1,
388 ip_snd='192.168.0.1',
389 ip_tgt='192.168.0.2',
390 hw_snd='00:06:07:08:09:0a',
391 hw_tgt='00:00:00:00:00:00',
392 ):
393 """
394 Return a simple ARP packet
395
396 Supports a few parameters:
397 @param len Length of packet in bytes w/o CRC
Rich Laned0478ff2013-03-11 12:46:58 -0700398 @param eth_dst Destinatino MAC
399 @param eth_src Source MAC
Shudong Zhouc7562b12013-02-06 01:12:18 -0800400 @param arp_op Operation (1=request, 2=reply)
401 @param ip_snd Sender IP
402 @param ip_tgt Target IP
403 @param hw_snd Sender hardware address
404 @param hw_tgt Target hardware address
405
406 Generates a simple ARP REQUEST. Users
407 shouldn't assume anything about this packet other than that
408 it is a valid ethernet/ARP frame.
409 """
410
411 if MINSIZE > pktlen:
412 pktlen = MINSIZE
413
Rich Laned0478ff2013-03-11 12:46:58 -0700414 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
Shudong Zhouc7562b12013-02-06 01:12:18 -0800415 scapy.ARP(hwsrc=hw_snd, hwdst=hw_tgt, pdst=ip_tgt, psrc=ip_snd, op=arp_op)
416
417 pkt = pkt/("0" * (pktlen - len(pkt)))
418
419 return pkt
420
Ed Swierk0aeff8c2012-03-23 20:27:18 -0700421def simple_eth_packet(pktlen=60,
Rich Lane53275082013-11-18 23:26:22 -0800422 eth_dst='00:01:02:03:04:05',
423 eth_src='00:06:07:08:09:0a',
Rich Laned0478ff2013-03-11 12:46:58 -0700424 eth_type=0x88cc):
Jeffrey Townsend5cb7ed32012-08-17 18:11:01 +0000425
426 if MINSIZE > pktlen:
427 pktlen = MINSIZE
428
Rich Laned0478ff2013-03-11 12:46:58 -0700429 pkt = scapy.Ether(dst=eth_dst, src=eth_src, type=eth_type)
Ed Swierk0aeff8c2012-03-23 20:27:18 -0700430
431 pkt = pkt/("0" * (pktlen - len(pkt)))
432
433 return pkt
434
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800435def qinq_tcp_packet(pktlen=100,
Rich Laned0478ff2013-03-11 12:46:58 -0700436 eth_dst='00:01:02:03:04:05',
437 eth_src='00:06:07:08:09:0a',
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800438 dl_vlan_outer=20,
439 dl_vlan_pcp_outer=0,
440 dl_vlan_cfi_outer=0,
Rich Laned0478ff2013-03-11 12:46:58 -0700441 vlan_vid=10,
442 vlan_pcp=0,
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800443 dl_vlan_cfi=0,
444 ip_src='192.168.0.1',
445 ip_dst='192.168.0.2',
446 ip_tos=0,
Gregor Maier9cc93342013-01-29 16:55:28 -0800447 ip_ttl=64,
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800448 tcp_sport=1234,
449 tcp_dport=80,
450 ip_ihl=None,
451 ip_options=False
452 ):
453 """
454 Return a doubly tagged dataplane TCP packet
455
456 Supports a few parameters:
457 @param len Length of packet in bytes w/o CRC
Rich Laned0478ff2013-03-11 12:46:58 -0700458 @param eth_dst Destinatino MAC
459 @param eth_src Source MAC
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800460 @param dl_vlan_outer Outer VLAN ID
461 @param dl_vlan_pcp_outer Outer VLAN priority
462 @param dl_vlan_cfi_outer Outer VLAN cfi bit
Rich Laned0478ff2013-03-11 12:46:58 -0700463 @param vlan_vid Inner VLAN ID
464 @param vlan_pcp VLAN priority
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800465 @param dl_vlan_cfi VLAN cfi bit
466 @param ip_src IP source
467 @param ip_dst IP destination
468 @param ip_tos IP ToS
469 @param tcp_dport TCP destination port
470 @param ip_sport TCP source port
471
472 Generates a TCP request. Users
473 shouldn't assume anything about this packet other than that
474 it is a valid ethernet/IP/TCP frame.
475 """
476
477 if MINSIZE > pktlen:
478 pktlen = MINSIZE
479
480 # Note Dot1Q.id is really CFI
Rich Laned0478ff2013-03-11 12:46:58 -0700481 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800482 scapy.Dot1Q(prio=dl_vlan_pcp_outer, id=dl_vlan_cfi_outer, vlan=dl_vlan_outer)/ \
Rich Laned0478ff2013-03-11 12:46:58 -0700483 scapy.Dot1Q(prio=vlan_pcp, id=dl_vlan_cfi, vlan=vlan_vid)/ \
Gregor Maier9cc93342013-01-29 16:55:28 -0800484 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ttl=ip_ttl, ihl=ip_ihl)/ \
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800485 scapy.TCP(sport=tcp_sport, dport=tcp_dport)
486
487 pkt = pkt/("D" * (pktlen - len(pkt)))
488
489 return pkt
490
Shudong Zhoub7f12462012-11-20 13:01:12 -0800491def do_barrier(ctrl, timeout=-1):
Dan Talayco0fc08bd2012-04-09 16:56:18 -0700492 """
493 Do a barrier command
494 Return 0 on success, -1 on error
495 """
Rich Lanee717c6e2013-03-12 10:25:50 -0700496 b = ofp.message.barrier_request()
Shudong Zhoub7f12462012-11-20 13:01:12 -0800497 (resp, pkt) = ctrl.transact(b, timeout=timeout)
Rich Lane3a261d52013-01-03 17:45:08 -0800498 if resp is None:
499 raise AssertionError("barrier failed")
Dan Talaycof6b94832012-04-12 21:50:57 -0700500 # We'll trust the transaction processing in the controller that xid matched
Rich Lane3a261d52013-01-03 17:45:08 -0800501 return 0 # for backwards compatibility
Dan Talayco92c99122010-06-03 13:53:18 -0700502
Rich Lane9a003812012-10-04 17:17:59 -0700503def port_config_get(controller, port_no):
Dan Talayco92c99122010-06-03 13:53:18 -0700504 """
505 Get a port's configuration
506
507 Gets the switch feature configuration and grabs one port's
508 configuration
509
510 @returns (hwaddr, config, advert) The hwaddress, configuration and
511 advertised values
512 """
Rich Lane6dc865c2013-07-10 10:12:13 -0700513
514 if ofp.OFP_VERSION <= 3:
515 request = ofp.message.features_request()
516 reply, _ = controller.transact(request)
517 if reply is None:
518 logging.warn("Get feature request failed")
519 return None, None, None
520 logging.debug(reply.show())
521 ports = reply.ports
522 else:
523 request = ofp.message.port_desc_stats_request()
524 # TODO do multipart correctly
525 reply, _ = controller.transact(request)
526 if reply is None:
527 logging.warn("Port desc stats request failed")
528 return None, None, None
529 logging.debug(reply.show())
530 ports = reply.entries
531
532 for port in ports:
533 if port.port_no == port_no:
534 return (port.hw_addr, port.config, port.advertised)
Dan Talayco92c99122010-06-03 13:53:18 -0700535
Rich Lane9a003812012-10-04 17:17:59 -0700536 logging.warn("Did not find port number for port config")
Dan Talayco92c99122010-06-03 13:53:18 -0700537 return None, None, None
538
Rich Lane9a003812012-10-04 17:17:59 -0700539def port_config_set(controller, port_no, config, mask):
Dan Talayco92c99122010-06-03 13:53:18 -0700540 """
541 Set the port configuration according the given parameters
542
543 Gets the switch feature configuration and updates one port's
544 configuration value according to config and mask
545 """
Rich Lane9a003812012-10-04 17:17:59 -0700546 logging.info("Setting port " + str(port_no) + " to config " + str(config))
Rich Lane6dc865c2013-07-10 10:12:13 -0700547
548 hw_addr, _, _ = port_config_get(controller, port_no)
549
Rich Lanee717c6e2013-03-12 10:25:50 -0700550 mod = ofp.message.port_mod()
Dan Talayco92c99122010-06-03 13:53:18 -0700551 mod.port_no = port_no
Rich Lane6dc865c2013-07-10 10:12:13 -0700552 if hw_addr != None:
553 mod.hw_addr = hw_addr
Dan Talayco92c99122010-06-03 13:53:18 -0700554 mod.config = config
555 mod.mask = mask
Rich Lane6dc865c2013-07-10 10:12:13 -0700556 mod.advertise = 0 # No change
Rich Lane5c3151c2013-01-03 17:15:41 -0800557 controller.message_send(mod)
558 return 0
Dan Talayco92c99122010-06-03 13:53:18 -0700559
Rich Lane2014f9b2012-10-05 15:29:40 -0700560def receive_pkt_check(dp, pkt, yes_ports, no_ports, assert_if):
Dan Talayco92c99122010-06-03 13:53:18 -0700561 """
562 Check for proper receive packets across all ports
Ken Chiang1bf01602012-04-04 10:48:23 -0700563 @param dp The dataplane object
Dan Talayco92c99122010-06-03 13:53:18 -0700564 @param pkt Expected packet; may be None if yes_ports is empty
565 @param yes_ports Set or list of ports that should recieve packet
566 @param no_ports Set or list of ports that should not receive packet
567 @param assert_if Object that implements assertXXX
Rich Lanee4b384d2013-09-13 14:33:40 -0700568
569 DEPRECATED in favor in verify_packets
Dan Talayco92c99122010-06-03 13:53:18 -0700570 """
Rich Lane91765672012-12-06 16:33:04 -0800571
572 # Wait this long for packets that we don't expect to receive.
573 # 100ms is (rarely) too short for positive tests on slow
574 # switches but is definitely not too short for a negative test.
575 negative_timeout = 0.1
576
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700577 exp_pkt_arg = None
Rich Lanecd97d3d2013-01-07 18:50:06 -0800578 if oftest.config["relax"]:
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700579 exp_pkt_arg = pkt
580
Dan Talayco92c99122010-06-03 13:53:18 -0700581 for ofport in yes_ports:
Rich Lane9a003812012-10-04 17:17:59 -0700582 logging.debug("Checking for pkt on port " + str(ofport))
Ken Chiang1bf01602012-04-04 10:48:23 -0700583 (rcv_port, rcv_pkt, pkt_time) = dp.poll(
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700584 port_number=ofport, exp_pkt=exp_pkt_arg)
Dan Talayco92c99122010-06-03 13:53:18 -0700585 assert_if.assertTrue(rcv_pkt is not None,
586 "Did not receive pkt on " + str(ofport))
Rich Lanecd97d3d2013-01-07 18:50:06 -0800587 if not oftest.dataplane.match_exp_pkt(pkt, rcv_pkt):
Rich Lane3c266832013-01-29 18:29:15 -0800588 logging.debug("Expected %s" % format_packet(pkt))
589 logging.debug("Received %s" % format_packet(rcv_pkt))
Rich Lanecd97d3d2013-01-07 18:50:06 -0800590 assert_if.assertTrue(oftest.dataplane.match_exp_pkt(pkt, rcv_pkt),
Rich Lane3c266832013-01-29 18:29:15 -0800591 "Received packet does not match expected packet " +
Ken Chiang1bf01602012-04-04 10:48:23 -0700592 "on port " + str(ofport))
Dan Talayco73f84012012-10-02 09:23:18 -0700593 if len(no_ports) > 0:
Rich Lane91765672012-12-06 16:33:04 -0800594 time.sleep(negative_timeout)
Dan Talayco92c99122010-06-03 13:53:18 -0700595 for ofport in no_ports:
Rich Lane9a003812012-10-04 17:17:59 -0700596 logging.debug("Negative check for pkt on port " + str(ofport))
Ken Chiang1bf01602012-04-04 10:48:23 -0700597 (rcv_port, rcv_pkt, pkt_time) = dp.poll(
Rich Lane91765672012-12-06 16:33:04 -0800598 port_number=ofport, timeout=0, exp_pkt=exp_pkt_arg)
Dan Talayco92c99122010-06-03 13:53:18 -0700599 assert_if.assertTrue(rcv_pkt is None,
600 "Unexpected pkt on port " + str(ofport))
Dan Talayco551befa2010-07-15 17:05:32 -0700601
602
Dan Talaycoc948d0b2012-03-23 12:17:54 -0700603def receive_pkt_verify(parent, egr_ports, exp_pkt, ing_port):
Dan Talayco551befa2010-07-15 17:05:32 -0700604 """
605 Receive a packet and verify it matches an expected value
Dan Talaycof6e76c02012-03-23 10:56:12 -0700606 @param egr_port A single port or list of ports
Dan Talayco551befa2010-07-15 17:05:32 -0700607
608 parent must implement dataplane, assertTrue and assertEqual
Rich Lanee4b384d2013-09-13 14:33:40 -0700609
610 DEPRECATED in favor in verify_packets
Dan Talayco551befa2010-07-15 17:05:32 -0700611 """
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700612 exp_pkt_arg = None
Rich Lanecd97d3d2013-01-07 18:50:06 -0800613 if oftest.config["relax"]:
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700614 exp_pkt_arg = exp_pkt
615
Dan Talaycof6e76c02012-03-23 10:56:12 -0700616 if type(egr_ports) == type([]):
617 egr_port_list = egr_ports
618 else:
619 egr_port_list = [egr_ports]
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700620
Dan Talaycof6e76c02012-03-23 10:56:12 -0700621 # Expect a packet from each port on egr port list
622 for egr_port in egr_port_list:
Dan Talaycod8ae7582012-03-23 12:24:56 -0700623 check_port = egr_port
Rich Lanee717c6e2013-03-12 10:25:50 -0700624 if egr_port == ofp.OFPP_IN_PORT:
Dan Talaycod8ae7582012-03-23 12:24:56 -0700625 check_port = ing_port
Dan Talaycof6e76c02012-03-23 10:56:12 -0700626 (rcv_port, rcv_pkt, pkt_time) = parent.dataplane.poll(
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700627 port_number=check_port, exp_pkt=exp_pkt_arg)
Dan Talayco551befa2010-07-15 17:05:32 -0700628
Dan Talaycof6e76c02012-03-23 10:56:12 -0700629 if rcv_pkt is None:
Rich Lane9a003812012-10-04 17:17:59 -0700630 logging.error("ERROR: No packet received from " +
Dan Talaycod8ae7582012-03-23 12:24:56 -0700631 str(check_port))
Dan Talayco551befa2010-07-15 17:05:32 -0700632
Dan Talaycof6e76c02012-03-23 10:56:12 -0700633 parent.assertTrue(rcv_pkt is not None,
Dan Talaycod8ae7582012-03-23 12:24:56 -0700634 "Did not receive packet port " + str(check_port))
Rich Lane9a003812012-10-04 17:17:59 -0700635 logging.debug("Packet len " + str(len(rcv_pkt)) + " in on " +
Dan Talaycof6e76c02012-03-23 10:56:12 -0700636 str(rcv_port))
637
638 if str(exp_pkt) != str(rcv_pkt):
Rich Lane9a003812012-10-04 17:17:59 -0700639 logging.error("ERROR: Packet match failed.")
640 logging.debug("Expected len " + str(len(exp_pkt)) + ": "
Dan Talaycof6e76c02012-03-23 10:56:12 -0700641 + str(exp_pkt).encode('hex'))
Rich Lane9a003812012-10-04 17:17:59 -0700642 logging.debug("Received len " + str(len(rcv_pkt)) + ": "
Dan Talaycof6e76c02012-03-23 10:56:12 -0700643 + str(rcv_pkt).encode('hex'))
Rich Lane5d7e89a2012-10-26 16:43:13 -0700644 logging.debug("Expected packet: " + inspect_packet(scapy.Ether(str(exp_pkt))))
645 logging.debug("Received packet: " + inspect_packet(scapy.Ether(str(rcv_pkt))))
Dan Talaycof6e76c02012-03-23 10:56:12 -0700646 parent.assertEqual(str(exp_pkt), str(rcv_pkt),
Dan Talaycod8ae7582012-03-23 12:24:56 -0700647 "Packet match error on port " + str(check_port))
Dan Talaycof6e76c02012-03-23 10:56:12 -0700648
Dan Talayco551befa2010-07-15 17:05:32 -0700649def match_verify(parent, req_match, res_match):
650 """
651 Verify flow matches agree; if they disagree, report where
652
653 parent must implement assertEqual
654 Use str() to ensure content is compared and not pointers
655 """
656
657 parent.assertEqual(req_match.wildcards, res_match.wildcards,
658 'Match failed: wildcards: ' + hex(req_match.wildcards) +
659 " != " + hex(res_match.wildcards))
660 parent.assertEqual(req_match.in_port, res_match.in_port,
661 'Match failed: in_port: ' + str(req_match.in_port) +
662 " != " + str(res_match.in_port))
Rich Laned0478ff2013-03-11 12:46:58 -0700663 parent.assertEqual(str(req_match.eth_src), str(res_match.eth_src),
664 'Match failed: eth_src: ' + str(req_match.eth_src) +
665 " != " + str(res_match.eth_src))
666 parent.assertEqual(str(req_match.eth_dst), str(res_match.eth_dst),
667 'Match failed: eth_dst: ' + str(req_match.eth_dst) +
668 " != " + str(res_match.eth_dst))
669 parent.assertEqual(req_match.vlan_vid, res_match.vlan_vid,
670 'Match failed: vlan_vid: ' + str(req_match.vlan_vid) +
671 " != " + str(res_match.vlan_vid))
672 parent.assertEqual(req_match.vlan_pcp, res_match.vlan_pcp,
673 'Match failed: vlan_pcp: ' +
674 str(req_match.vlan_pcp) + " != " +
675 str(res_match.vlan_pcp))
676 parent.assertEqual(req_match.eth_type, res_match.eth_type,
677 'Match failed: eth_type: ' + str(req_match.eth_type) +
678 " != " + str(res_match.eth_type))
Dan Talayco551befa2010-07-15 17:05:32 -0700679
Rich Lanee717c6e2013-03-12 10:25:50 -0700680 if (not(req_match.wildcards & ofp.OFPFW_DL_TYPE)
Rich Laned0478ff2013-03-11 12:46:58 -0700681 and (req_match.eth_type == IP_ETHERTYPE)):
682 parent.assertEqual(req_match.ip_dscp, res_match.ip_dscp,
683 'Match failed: ip_dscp: ' + str(req_match.ip_dscp) +
684 " != " + str(res_match.ip_dscp))
685 parent.assertEqual(req_match.ip_proto, res_match.ip_proto,
686 'Match failed: ip_proto: ' + str(req_match.ip_proto) +
687 " != " + str(res_match.ip_proto))
688 parent.assertEqual(req_match.ipv4_src, res_match.ipv4_src,
689 'Match failed: ipv4_src: ' + str(req_match.ipv4_src) +
690 " != " + str(res_match.ipv4_src))
691 parent.assertEqual(req_match.ipv4_dst, res_match.ipv4_dst,
692 'Match failed: ipv4_dst: ' + str(req_match.ipv4_dst) +
693 " != " + str(res_match.ipv4_dst))
Dan Talayco551befa2010-07-15 17:05:32 -0700694
Rich Lanee717c6e2013-03-12 10:25:50 -0700695 if (not(req_match.wildcards & ofp.OFPFW_NW_PROTO)
Rich Laned0478ff2013-03-11 12:46:58 -0700696 and ((req_match.ip_proto == TCP_PROTOCOL)
697 or (req_match.ip_proto == UDP_PROTOCOL))):
698 parent.assertEqual(req_match.tcp_src, res_match.tcp_src,
699 'Match failed: tcp_src: ' +
700 str(req_match.tcp_src) +
701 " != " + str(res_match.tcp_src))
702 parent.assertEqual(req_match.tcp_dst, res_match.tcp_dst,
703 'Match failed: tcp_dst: ' +
704 str(req_match.tcp_dst) +
705 " != " + str(res_match.tcp_dst))
Dan Talayco551befa2010-07-15 17:05:32 -0700706
Ed Swierk99a74de2012-08-22 06:40:54 -0700707def packet_to_flow_match(parent, packet):
Rich Lanef6883512013-03-11 17:00:09 -0700708 match = oftest.parse.packet_to_flow_match(packet)
Rich Laneab7476f2013-06-13 15:53:52 -0700709 if ofp.OFP_VERSION in [1, 2]:
710 match.wildcards |= required_wildcards(parent)
711 else:
712 # TODO remove incompatible OXM entries
713 pass
Ed Swierk99a74de2012-08-22 06:40:54 -0700714 return match
715
716def flow_msg_create(parent, pkt, ing_port=None, action_list=None, wildcards=None,
Dan Talaycof6e76c02012-03-23 10:56:12 -0700717 egr_ports=None, egr_queue=None, check_expire=False, in_band=False):
Dan Talayco551befa2010-07-15 17:05:32 -0700718 """
719 Create a flow message
720
721 Match on packet with given wildcards.
722 See flow_match_test for other parameter descriptoins
723 @param egr_queue if not None, make the output an enqueue action
Dan Talayco677c0b72011-08-23 22:53:38 -0700724 @param in_band if True, do not wildcard ingress port
Dan Talaycof6e76c02012-03-23 10:56:12 -0700725 @param egr_ports None (drop), single port or list of ports
Dan Talayco551befa2010-07-15 17:05:32 -0700726 """
Rich Lanef6883512013-03-11 17:00:09 -0700727 match = oftest.parse.packet_to_flow_match(pkt)
Dan Talayco551befa2010-07-15 17:05:32 -0700728 parent.assertTrue(match is not None, "Flow match from pkt failed")
Ed Swierk99a74de2012-08-22 06:40:54 -0700729 if wildcards is None:
730 wildcards = required_wildcards(parent)
Dan Talayco677c0b72011-08-23 22:53:38 -0700731 if in_band:
Rich Lanee717c6e2013-03-12 10:25:50 -0700732 wildcards &= ~ofp.OFPFW_IN_PORT
Dan Talayco551befa2010-07-15 17:05:32 -0700733 match.wildcards = wildcards
734 match.in_port = ing_port
735
Dan Talaycof6e76c02012-03-23 10:56:12 -0700736 if type(egr_ports) == type([]):
737 egr_port_list = egr_ports
738 else:
739 egr_port_list = [egr_ports]
740
Rich Lanee717c6e2013-03-12 10:25:50 -0700741 request = ofp.message.flow_add()
Dan Talayco551befa2010-07-15 17:05:32 -0700742 request.match = match
743 request.buffer_id = 0xffffffff
744 if check_expire:
Rich Lanee717c6e2013-03-12 10:25:50 -0700745 request.flags |= ofp.OFPFF_SEND_FLOW_REM
Dan Talayco551befa2010-07-15 17:05:32 -0700746 request.hard_timeout = 1
747
Rich Lane400fb9b2013-10-10 17:20:54 -0700748 if ofp.OFP_VERSION == 1:
749 actions = request.actions
750 else:
751 actions = []
752 request.instructions.append(ofp.instruction.apply_actions(actions))
753
Dan Talayco551befa2010-07-15 17:05:32 -0700754 if action_list is not None:
Rich Lane400fb9b2013-10-10 17:20:54 -0700755 actions.extend(action_list)
Dan Talayco551befa2010-07-15 17:05:32 -0700756
757 # Set up output/enqueue action if directed
758 if egr_queue is not None:
Dan Talaycof6e76c02012-03-23 10:56:12 -0700759 parent.assertTrue(egr_ports is not None, "Egress port not set")
Rich Lanee717c6e2013-03-12 10:25:50 -0700760 act = ofp.action.enqueue()
Dan Talaycof6e76c02012-03-23 10:56:12 -0700761 for egr_port in egr_port_list:
762 act.port = egr_port
763 act.queue_id = egr_queue
Rich Lane400fb9b2013-10-10 17:20:54 -0700764 actions.append(act)
Dan Talaycof6e76c02012-03-23 10:56:12 -0700765 elif egr_ports is not None:
766 for egr_port in egr_port_list:
Rich Lanee717c6e2013-03-12 10:25:50 -0700767 act = ofp.action.output()
Dan Talaycof6e76c02012-03-23 10:56:12 -0700768 act.port = egr_port
Rich Lane400fb9b2013-10-10 17:20:54 -0700769 actions.append(act)
Dan Talayco551befa2010-07-15 17:05:32 -0700770
Rich Lane9a003812012-10-04 17:17:59 -0700771 logging.debug(request.show())
Dan Talayco551befa2010-07-15 17:05:32 -0700772
773 return request
774
Jeffrey Townsendf3eae9c2012-03-28 18:23:21 -0700775def flow_msg_install(parent, request, clear_table_override=None):
Dan Talayco551befa2010-07-15 17:05:32 -0700776 """
777 Install a flow mod message in the switch
778
779 @param parent Must implement controller, assertEqual, assertTrue
780 @param request The request, all set to go
781 @param clear_table If true, clear the flow table before installing
782 """
Dan Talayco8a64e332012-03-28 14:53:20 -0700783
Rich Lane2014f9b2012-10-05 15:29:40 -0700784 clear_table = test_param_get('clear_table', default=True)
Jeffrey Townsendf3eae9c2012-03-28 18:23:21 -0700785 if(clear_table_override != None):
786 clear_table = clear_table_override
787
788 if clear_table:
Rich Lane9a003812012-10-04 17:17:59 -0700789 logging.debug("Clear flow table")
Rich Lane32bf9482013-01-03 17:26:30 -0800790 delete_all_flows(parent.controller)
Dan Talayco551befa2010-07-15 17:05:32 -0700791
Rich Lane9a003812012-10-04 17:17:59 -0700792 logging.debug("Insert flow")
Rich Lane5c3151c2013-01-03 17:15:41 -0800793 parent.controller.message_send(request)
Rich Lanee912d032012-12-22 14:28:33 -0800794
Rich Lane3a261d52013-01-03 17:45:08 -0800795 do_barrier(parent.controller)
Dan Talayco551befa2010-07-15 17:05:32 -0700796
Ed Swierk99a74de2012-08-22 06:40:54 -0700797def flow_match_test_port_pair(parent, ing_port, egr_ports, wildcards=None,
Rich Laned0478ff2013-03-11 12:46:58 -0700798 vlan_vid=-1, pkt=None, exp_pkt=None,
Rich Lanee5779d32012-10-05 17:56:04 -0700799 action_list=None):
Dan Talayco551befa2010-07-15 17:05:32 -0700800 """
801 Flow match test on single TCP packet
Dan Talaycof6e76c02012-03-23 10:56:12 -0700802 @param egr_ports A single port or list of ports
Dan Talayco551befa2010-07-15 17:05:32 -0700803
804 Run test with packet through switch from ing_port to egr_port
805 See flow_match_test for parameter descriptions
806 """
807
Ed Swierk99a74de2012-08-22 06:40:54 -0700808 if wildcards is None:
809 wildcards = required_wildcards(parent)
Rich Lane9a003812012-10-04 17:17:59 -0700810 logging.info("Pkt match test: " + str(ing_port) + " to " +
Dan Talaycof6e76c02012-03-23 10:56:12 -0700811 str(egr_ports))
Rich Laned0478ff2013-03-11 12:46:58 -0700812 logging.debug(" WC: " + hex(wildcards) + " vlan: " + str(vlan_vid))
Dan Talayco551befa2010-07-15 17:05:32 -0700813 if pkt is None:
Rich Laned0478ff2013-03-11 12:46:58 -0700814 pkt = simple_tcp_packet(dl_vlan_enable=(vlan_vid >= 0), vlan_vid=vlan_vid)
Rich Lanec41fbec2013-10-02 00:27:59 -0700815 if exp_pkt is None:
816 exp_pkt = pkt
Dan Talayco551befa2010-07-15 17:05:32 -0700817
818 request = flow_msg_create(parent, pkt, ing_port=ing_port,
Dan Talaycof6e76c02012-03-23 10:56:12 -0700819 wildcards=wildcards, egr_ports=egr_ports,
Dan Talayco551befa2010-07-15 17:05:32 -0700820 action_list=action_list)
821
822 flow_msg_install(parent, request)
823
Rich Lane9a003812012-10-04 17:17:59 -0700824 logging.debug("Send packet: " + str(ing_port) + " to " +
Dan Talaycof6e76c02012-03-23 10:56:12 -0700825 str(egr_ports))
Dan Talayco551befa2010-07-15 17:05:32 -0700826 parent.dataplane.send(ing_port, str(pkt))
827
Rich Lane8f45e2d2013-10-01 16:06:54 -0700828 exp_ports = [ing_port if port == ofp.OFPP_IN_PORT else port for port in egr_ports]
Rich Lanee4b384d2013-09-13 14:33:40 -0700829 verify_packets(parent, exp_pkt, exp_ports)
Dan Talayco551befa2010-07-15 17:05:32 -0700830
Rich Lane89725bb2012-12-03 16:23:27 -0800831def flow_match_test_pktout(parent, ing_port, egr_ports,
Rich Laned0478ff2013-03-11 12:46:58 -0700832 vlan_vid=-1, pkt=None, exp_pkt=None,
Rich Lane89725bb2012-12-03 16:23:27 -0800833 action_list=None):
834 """
835 Packet-out test on single TCP packet
836 @param egr_ports A single port or list of ports
837
838 Run test sending packet-out to egr_ports. The goal is to test the actions
839 taken on the packet, not the matching which is of course irrelevant.
840 See flow_match_test for parameter descriptions
841 """
842
843 if pkt is None:
Rich Laned0478ff2013-03-11 12:46:58 -0700844 pkt = simple_tcp_packet(dl_vlan_enable=(vlan_vid >= 0), vlan_vid=vlan_vid)
Rich Lanec41fbec2013-10-02 00:27:59 -0700845 if exp_pkt is None:
846 exp_pkt = pkt
Rich Lane89725bb2012-12-03 16:23:27 -0800847
Rich Lanee717c6e2013-03-12 10:25:50 -0700848 msg = ofp.message.packet_out()
Rich Lane89725bb2012-12-03 16:23:27 -0800849 msg.in_port = ing_port
Rich Laneea8c4722013-04-04 15:30:20 -0700850 msg.buffer_id = 0xffffffff
Rich Lane89725bb2012-12-03 16:23:27 -0800851 msg.data = str(pkt)
852 if action_list is not None:
853 for act in action_list:
Rich Lanec495d9e2013-03-08 17:43:36 -0800854 msg.actions.append(act)
Rich Lane89725bb2012-12-03 16:23:27 -0800855
856 # Set up output action
857 if egr_ports is not None:
858 for egr_port in egr_ports:
Rich Lanee717c6e2013-03-12 10:25:50 -0700859 act = ofp.action.output()
Rich Lane89725bb2012-12-03 16:23:27 -0800860 act.port = egr_port
Rich Lanec495d9e2013-03-08 17:43:36 -0800861 msg.actions.append(act)
Rich Lane89725bb2012-12-03 16:23:27 -0800862
863 logging.debug(msg.show())
Rich Lane5c3151c2013-01-03 17:15:41 -0800864 parent.controller.message_send(msg)
Rich Lane89725bb2012-12-03 16:23:27 -0800865
Rich Lane8f45e2d2013-10-01 16:06:54 -0700866 exp_ports = [ing_port if port == ofp.OFPP_IN_PORT else port for port in egr_ports]
Rich Lanee4b384d2013-09-13 14:33:40 -0700867 verify_packets(parent, exp_pkt, exp_ports)
Rich Lane89725bb2012-12-03 16:23:27 -0800868
Dan Talaycof6e76c02012-03-23 10:56:12 -0700869def get_egr_list(parent, of_ports, how_many, exclude_list=[]):
870 """
871 Generate a list of ports avoiding those in the exclude list
Rich Lane9a003812012-10-04 17:17:59 -0700872 @param parent Supplies logging
Dan Talaycof6e76c02012-03-23 10:56:12 -0700873 @param of_ports List of OF port numbers
874 @param how_many Number of ports to be added to the list
875 @param exclude_list List of ports not to be used
876 @returns An empty list if unable to find enough ports
877 """
878
Dan Talaycoc948d0b2012-03-23 12:17:54 -0700879 if how_many == 0:
880 return []
881
Dan Talaycof6e76c02012-03-23 10:56:12 -0700882 count = 0
883 egr_ports = []
884 for egr_idx in range(len(of_ports)):
885 if of_ports[egr_idx] not in exclude_list:
886 egr_ports.append(of_ports[egr_idx])
887 count += 1
888 if count >= how_many:
889 return egr_ports
Rich Lane9a003812012-10-04 17:17:59 -0700890 logging.debug("Could not generate enough egress ports for test")
Dan Talaycof6e76c02012-03-23 10:56:12 -0700891 return []
892
Rich Laned0478ff2013-03-11 12:46:58 -0700893def flow_match_test(parent, port_map, wildcards=None, vlan_vid=-1, pkt=None,
Rich Lanee5779d32012-10-05 17:56:04 -0700894 exp_pkt=None, action_list=None,
Dan Talaycoc948d0b2012-03-23 12:17:54 -0700895 max_test=0, egr_count=1, ing_port=False):
Dan Talayco551befa2010-07-15 17:05:32 -0700896 """
Rich Lane89725bb2012-12-03 16:23:27 -0800897 Run flow_match_test_port_pair on all port pairs and packet-out
Dan Talayco551befa2010-07-15 17:05:32 -0700898
899 @param max_test If > 0 no more than this number of tests are executed.
900 @param parent Must implement controller, dataplane, assertTrue, assertEqual
Rich Lane9a003812012-10-04 17:17:59 -0700901 and logging
Dan Talayco551befa2010-07-15 17:05:32 -0700902 @param pkt If not None, use this packet for ingress
903 @param wildcards For flow match entry
Rich Laned0478ff2013-03-11 12:46:58 -0700904 @param vlan_vid If not -1, and pkt is None, create a pkt w/ VLAN tag
Dan Talayco551befa2010-07-15 17:05:32 -0700905 @param exp_pkt If not None, use this as the expected output pkt; els use pkt
906 @param action_list Additional actions to add to flow mod
Dan Talaycocfa172f2012-03-23 12:03:00 -0700907 @param egr_count Number of egress ports; -1 means get from config w/ dflt 2
Dan Talayco551befa2010-07-15 17:05:32 -0700908 """
Ed Swierk99a74de2012-08-22 06:40:54 -0700909 if wildcards is None:
910 wildcards = required_wildcards(parent)
Dan Talayco551befa2010-07-15 17:05:32 -0700911 of_ports = port_map.keys()
912 of_ports.sort()
913 parent.assertTrue(len(of_ports) > 1, "Not enough ports for test")
914 test_count = 0
915
Dan Talaycocfa172f2012-03-23 12:03:00 -0700916 if egr_count == -1:
Rich Lane2014f9b2012-10-05 15:29:40 -0700917 egr_count = test_param_get('egr_count', default=2)
Dan Talaycocfa172f2012-03-23 12:03:00 -0700918
Dan Talayco551befa2010-07-15 17:05:32 -0700919 for ing_idx in range(len(of_ports)):
920 ingress_port = of_ports[ing_idx]
Dan Talaycof6e76c02012-03-23 10:56:12 -0700921 egr_ports = get_egr_list(parent, of_ports, egr_count,
922 exclude_list=[ingress_port])
Dan Talaycoc948d0b2012-03-23 12:17:54 -0700923 if ing_port:
Rich Lanee717c6e2013-03-12 10:25:50 -0700924 egr_ports.append(ofp.OFPP_IN_PORT)
Dan Talaycof6e76c02012-03-23 10:56:12 -0700925 if len(egr_ports) == 0:
926 parent.assertTrue(0, "Failed to generate egress port list")
927
928 flow_match_test_port_pair(parent, ingress_port, egr_ports,
Rich Laned0478ff2013-03-11 12:46:58 -0700929 wildcards=wildcards, vlan_vid=vlan_vid,
Dan Talaycof6e76c02012-03-23 10:56:12 -0700930 pkt=pkt, exp_pkt=exp_pkt,
Rich Lanee5779d32012-10-05 17:56:04 -0700931 action_list=action_list)
Dan Talaycof6e76c02012-03-23 10:56:12 -0700932 test_count += 1
933 if (max_test > 0) and (test_count > max_test):
Rich Lane9a003812012-10-04 17:17:59 -0700934 logging.info("Ran " + str(test_count) + " tests; exiting")
Rich Lane89725bb2012-12-03 16:23:27 -0800935 break
936
Ed Swierk38eea082013-01-02 19:46:20 -0800937 if not test_param_get('pktout_actions', default=True):
938 return
Rich Lane89725bb2012-12-03 16:23:27 -0800939
940 ingress_port = of_ports[0]
941 egr_ports = get_egr_list(parent, of_ports, egr_count,
942 exclude_list=[ingress_port])
943 if ing_port:
Rich Lanee717c6e2013-03-12 10:25:50 -0700944 egr_ports.append(ofp.OFPP_IN_PORT)
Rich Lane89725bb2012-12-03 16:23:27 -0800945 flow_match_test_pktout(parent, ingress_port, egr_ports,
Rich Laned0478ff2013-03-11 12:46:58 -0700946 vlan_vid=vlan_vid,
Rich Lane89725bb2012-12-03 16:23:27 -0800947 pkt=pkt, exp_pkt=exp_pkt,
948 action_list=action_list)
Dan Talayco551befa2010-07-15 17:05:32 -0700949
Rich Lane2014f9b2012-10-05 15:29:40 -0700950def test_param_get(key, default=None):
Dan Talayco4b2bee62010-07-20 14:10:05 -0700951 """
952 Return value passed via test-params if present
953
Dan Talayco4b2bee62010-07-20 14:10:05 -0700954 @param key The lookup key
955 @param default Default value to use if not found
956
957 If the pair 'key=val' appeared in the string passed to --test-params
958 on the command line, return val (as interpreted by exec). Otherwise
959 return default value.
Dan Talaycof6e76c02012-03-23 10:56:12 -0700960
961 WARNING: TEST PARAMETERS MUST BE PYTHON IDENTIFIERS;
962 eg egr_count, not egr-count.
Dan Talayco4b2bee62010-07-20 14:10:05 -0700963 """
964 try:
Rich Lanecd97d3d2013-01-07 18:50:06 -0800965 exec oftest.config["test_params"]
Dan Talayco4b2bee62010-07-20 14:10:05 -0700966 except:
967 return default
968
Dan Talayco4b2bee62010-07-20 14:10:05 -0700969 try:
Rich Lanefdec0fb2013-08-09 18:01:05 -0700970 return eval(str(key))
Dan Talayco4b2bee62010-07-20 14:10:05 -0700971 except:
972 return default
973
974def action_generate(parent, field_to_mod, mod_field_vals):
975 """
976 Create an action to modify the field indicated in field_to_mod
977
978 @param parent Must implement, assertTrue
979 @param field_to_mod The field to modify as a string name
980 @param mod_field_vals Hash of values to use for modified values
981 """
982
983 act = None
984
985 if field_to_mod in ['pktlen']:
986 return None
987
Rich Laned0478ff2013-03-11 12:46:58 -0700988 if field_to_mod == 'eth_dst':
Rich Lanee717c6e2013-03-12 10:25:50 -0700989 act = ofp.action.set_dl_dst()
Rich Lanef6883512013-03-11 17:00:09 -0700990 act.dl_addr = oftest.parse.parse_mac(mod_field_vals['eth_dst'])
Rich Laned0478ff2013-03-11 12:46:58 -0700991 elif field_to_mod == 'eth_src':
Rich Lanee717c6e2013-03-12 10:25:50 -0700992 act = ofp.action.set_dl_src()
Rich Lanef6883512013-03-11 17:00:09 -0700993 act.dl_addr = oftest.parse.parse_mac(mod_field_vals['eth_src'])
Dan Talayco4b2bee62010-07-20 14:10:05 -0700994 elif field_to_mod == 'dl_vlan_enable':
995 if not mod_field_vals['dl_vlan_enable']: # Strip VLAN tag
Rich Lanee717c6e2013-03-12 10:25:50 -0700996 act = ofp.action.strip_vlan()
Rich Laned0478ff2013-03-11 12:46:58 -0700997 # Add VLAN tag is handled by vlan_vid field
Dan Talayco4b2bee62010-07-20 14:10:05 -0700998 # Will return None in this case
Rich Laned0478ff2013-03-11 12:46:58 -0700999 elif field_to_mod == 'vlan_vid':
Rich Lanee717c6e2013-03-12 10:25:50 -07001000 act = ofp.action.set_vlan_vid()
Rich Laned0478ff2013-03-11 12:46:58 -07001001 act.vlan_vid = mod_field_vals['vlan_vid']
1002 elif field_to_mod == 'vlan_pcp':
Rich Lanee717c6e2013-03-12 10:25:50 -07001003 act = ofp.action.set_vlan_pcp()
Rich Laned0478ff2013-03-11 12:46:58 -07001004 act.vlan_pcp = mod_field_vals['vlan_pcp']
Dan Talayco4b2bee62010-07-20 14:10:05 -07001005 elif field_to_mod == 'ip_src':
Rich Lanee717c6e2013-03-12 10:25:50 -07001006 act = ofp.action.set_nw_src()
Rich Lanef6883512013-03-11 17:00:09 -07001007 act.nw_addr = oftest.parse.parse_ip(mod_field_vals['ip_src'])
Dan Talayco4b2bee62010-07-20 14:10:05 -07001008 elif field_to_mod == 'ip_dst':
Rich Lanee717c6e2013-03-12 10:25:50 -07001009 act = ofp.action.set_nw_dst()
Rich Lanef6883512013-03-11 17:00:09 -07001010 act.nw_addr = oftest.parse.parse_ip(mod_field_vals['ip_dst'])
Dan Talayco4b2bee62010-07-20 14:10:05 -07001011 elif field_to_mod == 'ip_tos':
Rich Lanee717c6e2013-03-12 10:25:50 -07001012 act = ofp.action.set_nw_tos()
Dan Talayco4b2bee62010-07-20 14:10:05 -07001013 act.nw_tos = mod_field_vals['ip_tos']
1014 elif field_to_mod == 'tcp_sport':
Rich Lanee717c6e2013-03-12 10:25:50 -07001015 act = ofp.action.set_tp_src()
Dan Talayco4b2bee62010-07-20 14:10:05 -07001016 act.tp_port = mod_field_vals['tcp_sport']
1017 elif field_to_mod == 'tcp_dport':
Rich Lanee717c6e2013-03-12 10:25:50 -07001018 act = ofp.action.set_tp_dst()
Dan Talayco4b2bee62010-07-20 14:10:05 -07001019 act.tp_port = mod_field_vals['tcp_dport']
Rich Lane110e0e32012-10-26 16:21:46 -07001020 elif field_to_mod == 'udp_sport':
Rich Lanee717c6e2013-03-12 10:25:50 -07001021 act = ofp.action.set_tp_src()
Rich Lane110e0e32012-10-26 16:21:46 -07001022 act.tp_port = mod_field_vals['udp_sport']
1023 elif field_to_mod == 'udp_dport':
Rich Lanee717c6e2013-03-12 10:25:50 -07001024 act = ofp.action.set_tp_dst()
Rich Lane110e0e32012-10-26 16:21:46 -07001025 act.tp_port = mod_field_vals['udp_dport']
Dan Talayco4b2bee62010-07-20 14:10:05 -07001026 else:
1027 parent.assertTrue(0, "Unknown field to modify: " + str(field_to_mod))
1028
1029 return act
1030
1031def pkt_action_setup(parent, start_field_vals={}, mod_field_vals={},
Rich Lane110e0e32012-10-26 16:21:46 -07001032 mod_fields=[], tp="tcp", check_test_params=False):
Dan Talayco4b2bee62010-07-20 14:10:05 -07001033 """
1034 Set up the ingress and expected packet and action list for a test
1035
Rich Lane2014f9b2012-10-05 15:29:40 -07001036 @param parent Must implement assertTrue
Dan Talayco4b2bee62010-07-20 14:10:05 -07001037 @param start_field_values Field values to use for ingress packet (optional)
1038 @param mod_field_values Field values to use for modified packet (optional)
1039 @param mod_fields The list of fields to be modified by the switch in the test.
1040 @params check_test_params If True, will check the parameters vid, add_vlan
1041 and strip_vlan from the command line.
1042
1043 Returns a triple: pkt-to-send, expected-pkt, action-list
1044 """
1045
1046 new_actions = []
1047
Dan Talayco4b2bee62010-07-20 14:10:05 -07001048 base_pkt_params = {}
1049 base_pkt_params['pktlen'] = 100
Rich Laned0478ff2013-03-11 12:46:58 -07001050 base_pkt_params['eth_dst'] = '00:DE:F0:12:34:56'
1051 base_pkt_params['eth_src'] = '00:23:45:67:89:AB'
Dan Talayco4b2bee62010-07-20 14:10:05 -07001052 base_pkt_params['dl_vlan_enable'] = False
Rich Laned0478ff2013-03-11 12:46:58 -07001053 base_pkt_params['vlan_vid'] = 2
1054 base_pkt_params['vlan_pcp'] = 0
Dan Talayco4b2bee62010-07-20 14:10:05 -07001055 base_pkt_params['ip_src'] = '192.168.0.1'
1056 base_pkt_params['ip_dst'] = '192.168.0.2'
1057 base_pkt_params['ip_tos'] = 0
Rich Lane110e0e32012-10-26 16:21:46 -07001058 if tp == "tcp":
1059 base_pkt_params['tcp_sport'] = 1234
1060 base_pkt_params['tcp_dport'] = 80
1061 elif tp == "udp":
1062 base_pkt_params['udp_sport'] = 1234
1063 base_pkt_params['udp_dport'] = 80
Dan Talayco4b2bee62010-07-20 14:10:05 -07001064 for keyname in start_field_vals.keys():
1065 base_pkt_params[keyname] = start_field_vals[keyname]
1066
1067 mod_pkt_params = {}
1068 mod_pkt_params['pktlen'] = 100
Rich Laned0478ff2013-03-11 12:46:58 -07001069 mod_pkt_params['eth_dst'] = '00:21:0F:ED:CB:A9'
1070 mod_pkt_params['eth_src'] = '00:ED:CB:A9:87:65'
Dan Talayco4b2bee62010-07-20 14:10:05 -07001071 mod_pkt_params['dl_vlan_enable'] = False
Rich Laned0478ff2013-03-11 12:46:58 -07001072 mod_pkt_params['vlan_vid'] = 3
1073 mod_pkt_params['vlan_pcp'] = 7
Dan Talayco4b2bee62010-07-20 14:10:05 -07001074 mod_pkt_params['ip_src'] = '10.20.30.40'
1075 mod_pkt_params['ip_dst'] = '50.60.70.80'
1076 mod_pkt_params['ip_tos'] = 0xf0
Rich Lane110e0e32012-10-26 16:21:46 -07001077 if tp == "tcp":
1078 mod_pkt_params['tcp_sport'] = 4321
1079 mod_pkt_params['tcp_dport'] = 8765
1080 elif tp == "udp":
1081 mod_pkt_params['udp_sport'] = 4321
1082 mod_pkt_params['udp_dport'] = 8765
Dan Talayco4b2bee62010-07-20 14:10:05 -07001083 for keyname in mod_field_vals.keys():
1084 mod_pkt_params[keyname] = mod_field_vals[keyname]
1085
1086 # Check for test param modifications
1087 strip = False
1088 if check_test_params:
Rich Lane2014f9b2012-10-05 15:29:40 -07001089 add_vlan = test_param_get('add_vlan')
1090 strip_vlan = test_param_get('strip_vlan')
1091 vid = test_param_get('vid')
Dan Talayco4b2bee62010-07-20 14:10:05 -07001092
1093 if add_vlan and strip_vlan:
1094 parent.assertTrue(0, "Add and strip VLAN both specified")
1095
1096 if vid:
1097 base_pkt_params['dl_vlan_enable'] = True
Rich Laned0478ff2013-03-11 12:46:58 -07001098 base_pkt_params['vlan_vid'] = vid
1099 if 'vlan_vid' in mod_fields:
1100 mod_pkt_params['vlan_vid'] = vid + 1
Dan Talayco4b2bee62010-07-20 14:10:05 -07001101
1102 if add_vlan:
1103 base_pkt_params['dl_vlan_enable'] = False
1104 mod_pkt_params['dl_vlan_enable'] = True
1105 mod_pkt_params['pktlen'] = base_pkt_params['pktlen'] + 4
1106 mod_fields.append('pktlen')
1107 mod_fields.append('dl_vlan_enable')
Rich Laned0478ff2013-03-11 12:46:58 -07001108 if 'vlan_vid' not in mod_fields:
1109 mod_fields.append('vlan_vid')
Dan Talayco4b2bee62010-07-20 14:10:05 -07001110 elif strip_vlan:
1111 base_pkt_params['dl_vlan_enable'] = True
1112 mod_pkt_params['dl_vlan_enable'] = False
1113 mod_pkt_params['pktlen'] = base_pkt_params['pktlen'] - 4
1114 mod_fields.append('dl_vlan_enable')
1115 mod_fields.append('pktlen')
1116
Rich Lane110e0e32012-10-26 16:21:46 -07001117 if tp == "tcp":
1118 packet_builder = simple_tcp_packet
1119 elif tp == "udp":
1120 packet_builder = simple_udp_packet
1121 else:
1122 raise NotImplementedError("unknown transport protocol %s" % tp)
1123
Dan Talayco4b2bee62010-07-20 14:10:05 -07001124 # Build the ingress packet
Rich Lane110e0e32012-10-26 16:21:46 -07001125 ingress_pkt = packet_builder(**base_pkt_params)
Dan Talayco4b2bee62010-07-20 14:10:05 -07001126
1127 # Build the expected packet, modifying the indicated fields
1128 for item in mod_fields:
1129 base_pkt_params[item] = mod_pkt_params[item]
1130 act = action_generate(parent, item, mod_pkt_params)
1131 if act:
1132 new_actions.append(act)
1133
Rich Lane110e0e32012-10-26 16:21:46 -07001134 expected_pkt = packet_builder(**base_pkt_params)
Dan Talayco4b2bee62010-07-20 14:10:05 -07001135
1136 return (ingress_pkt, expected_pkt, new_actions)
Dan Talayco677c0b72011-08-23 22:53:38 -07001137
1138# Generate a simple "drop" flow mod
1139# If in_band is true, then only drop from first test port
1140def flow_mod_gen(port_map, in_band):
Rich Lanee717c6e2013-03-12 10:25:50 -07001141 request = ofp.message.flow_add()
1142 request.match.wildcards = ofp.OFPFW_ALL
Dan Talayco677c0b72011-08-23 22:53:38 -07001143 if in_band:
Rich Lanee717c6e2013-03-12 10:25:50 -07001144 request.match.wildcards = ofp.OFPFW_ALL - ofp.OFPFW_IN_PORT
Dan Talayco677c0b72011-08-23 22:53:38 -07001145 for of_port, ifname in port_map.items(): # Grab first port
1146 break
1147 request.match.in_port = of_port
1148 request.buffer_id = 0xffffffff
1149 return request
Dan Talaycoba3745c2010-07-21 21:51:08 -07001150
1151def skip_message_emit(parent, s):
1152 """
1153 Print out a 'skipped' message to stderr
1154
1155 @param s The string to print out to the log file
Dan Talaycoba3745c2010-07-21 21:51:08 -07001156 """
1157 global skipped_test_count
1158
1159 skipped_test_count += 1
Rich Lane9a003812012-10-04 17:17:59 -07001160 logging.info("Skipping: " + s)
Dan Talayco2940fdd2013-02-06 15:01:35 -08001161 if oftest.config["debug"] < logging.WARNING:
Dan Talaycoba3745c2010-07-21 21:51:08 -07001162 sys.stderr.write("(skipped) ")
1163 else:
1164 sys.stderr.write("(S)")
Dan Talayco677c0b72011-08-23 22:53:38 -07001165
Dan Talayco8a64e332012-03-28 14:53:20 -07001166
1167def all_stats_get(parent):
1168 """
1169 Get the aggregate stats for all flows in the table
1170 @param parent Test instance with controller connection and assert
1171 @returns dict with keys flows, packets, bytes, active (flows),
1172 lookups, matched
1173 """
Rich Lanee717c6e2013-03-12 10:25:50 -07001174 stat_req = ofp.message.aggregate_stats_request()
1175 stat_req.match = ofp.match()
1176 stat_req.match.wildcards = ofp.OFPFW_ALL
Dan Talayco8a64e332012-03-28 14:53:20 -07001177 stat_req.table_id = 0xff
Rich Lanee717c6e2013-03-12 10:25:50 -07001178 stat_req.out_port = ofp.OFPP_NONE
Dan Talayco8a64e332012-03-28 14:53:20 -07001179
1180 rv = {}
1181
Rich Lanec8aaa3e2012-07-26 19:28:02 -07001182 (reply, pkt) = parent.controller.transact(stat_req)
Rich Lane5fd6faf2013-03-11 13:30:20 -07001183 parent.assertTrue(len(reply.entries) == 1, "Did not receive flow stats reply")
Dan Talayco8a64e332012-03-28 14:53:20 -07001184
Rich Lane5fd6faf2013-03-11 13:30:20 -07001185 for obj in reply.entries:
Dan Talayco8a64e332012-03-28 14:53:20 -07001186 (rv["flows"], rv["packets"], rv["bytes"]) = (obj.flow_count,
1187 obj.packet_count, obj.byte_count)
1188 break
1189
Rich Lanee717c6e2013-03-12 10:25:50 -07001190 request = ofp.message.table_stats_request()
Rich Lanec8aaa3e2012-07-26 19:28:02 -07001191 (reply , pkt) = parent.controller.transact(request)
Dan Talayco8a64e332012-03-28 14:53:20 -07001192
1193
1194 (rv["active"], rv["lookups"], rv["matched"]) = (0,0,0)
Rich Lane5fd6faf2013-03-11 13:30:20 -07001195 for obj in reply.entries:
Dan Talayco8a64e332012-03-28 14:53:20 -07001196 rv["active"] += obj.active_count
1197 rv["lookups"] += obj.lookup_count
1198 rv["matched"] += obj.matched_count
1199
1200 return rv
Dan Talayco2baf8b52012-03-30 09:55:42 -07001201
Rich Lane7744e112013-01-11 17:23:57 -08001202_import_blacklist.add('FILTER')
Dan Talayco2baf8b52012-03-30 09:55:42 -07001203FILTER=''.join([(len(repr(chr(x)))==3) and chr(x) or '.'
1204 for x in range(256)])
1205
1206def hex_dump_buffer(src, length=16):
1207 """
1208 Convert src to a hex dump string and return the string
1209 @param src The source buffer
1210 @param length The number of bytes shown in each line
1211 @returns A string showing the hex dump
1212 """
Dan Talaycoc516fa02012-04-12 22:28:43 -07001213 result = ["\n"]
Dan Talayco2baf8b52012-03-30 09:55:42 -07001214 for i in xrange(0, len(src), length):
1215 chars = src[i:i+length]
1216 hex = ' '.join(["%02x" % ord(x) for x in chars])
1217 printable = ''.join(["%s" % ((ord(x) <= 127 and
1218 FILTER[ord(x)]) or '.') for x in chars])
1219 result.append("%04x %-*s %s\n" % (i, length*3, hex, printable))
1220 return ''.join(result)
1221
1222def format_packet(pkt):
1223 return "Packet length %d \n%s" % (len(str(pkt)),
1224 hex_dump_buffer(str(pkt)))
Rich Lane5d7e89a2012-10-26 16:43:13 -07001225
1226def inspect_packet(pkt):
1227 """
1228 Wrapper around scapy's show() method.
1229 @returns A string showing the dissected packet.
1230 """
1231 from cStringIO import StringIO
1232 out = None
1233 backup = sys.stdout
1234 try:
Rich Lanefdec0fb2013-08-09 18:01:05 -07001235 tmp = StringIO()
1236 sys.stdout = tmp
Rich Lane5d7e89a2012-10-26 16:43:13 -07001237 pkt.show2()
Rich Lanefdec0fb2013-08-09 18:01:05 -07001238 out = tmp.getvalue()
1239 tmp.close()
Rich Lane5d7e89a2012-10-26 16:43:13 -07001240 finally:
1241 sys.stdout = backup
1242 return out
Rich Lane0a4f6372013-01-02 14:40:22 -08001243
1244def nonstandard(cls):
1245 """
Rich Lanecc45b8e2013-01-02 15:55:02 -08001246 Testcase decorator that marks the test as being non-standard.
1247 These tests are not automatically added to the "standard" group.
Rich Lane0a4f6372013-01-02 14:40:22 -08001248 """
Rich Lanecc45b8e2013-01-02 15:55:02 -08001249 cls._nonstandard = True
Rich Lane0a4f6372013-01-02 14:40:22 -08001250 return cls
1251
1252def disabled(cls):
1253 """
Rich Lanecc45b8e2013-01-02 15:55:02 -08001254 Testcase decorator that marks the test as being disabled.
1255 These tests are not automatically added to the "standard" group or
1256 their module's group.
Rich Lane0a4f6372013-01-02 14:40:22 -08001257 """
Rich Lanecc45b8e2013-01-02 15:55:02 -08001258 cls._disabled = True
Rich Lane0a4f6372013-01-02 14:40:22 -08001259 return cls
Rich Lane97e99652013-01-02 17:23:20 -08001260
1261def group(name):
1262 """
1263 Testcase decorator that adds the test to a group.
1264 """
1265 def fn(cls):
1266 if not hasattr(cls, "_groups"):
1267 cls._groups = []
1268 cls._groups.append(name)
1269 return cls
1270 return fn
Rich Lane5a9a1922013-01-11 14:29:30 -08001271
1272def version(ver):
1273 """
1274 Testcase decorator that specifies which versions of OpenFlow the test
1275 supports. The default is 1.0+. This decorator may only be used once.
1276
1277 Supported syntax:
1278 1.0 -> 1.0
1279 1.0,1.2,1.3 -> 1.0, 1.2, 1.3
1280 1.0+ -> 1.0, 1.1, 1.2, 1.3
1281 """
1282 versions = parse_version(ver)
1283 def fn(cls):
1284 cls._versions = versions
1285 return cls
1286 return fn
1287
1288def parse_version(ver):
1289 allowed_versions = ["1.0", "1.1", "1.2", "1.3"]
1290 if re.match("^1\.\d+$", ver):
1291 versions = set([ver])
1292 elif re.match("^(1\.\d+)\+$", ver):
1293 if not ver[:-1] in allowed_versions:
1294 raise ValueError("invalid OpenFlow version %s" % ver[:-1])
1295 versions = set()
1296 if ver != "1.1+": versions.add("1.0")
1297 if ver != "1.2+": versions.add("1.1")
1298 if ver != "1.3+": versions.add("1.2")
1299 versions.add("1.3")
1300 else:
1301 versions = set(ver.split(','))
1302
1303 for version in versions:
1304 if not version in allowed_versions:
1305 raise ValueError("invalid OpenFlow version %s" % version)
1306
1307 return versions
1308
1309assert(parse_version("1.0") == set(["1.0"]))
1310assert(parse_version("1.0,1.2,1.3") == set(["1.0", "1.2", "1.3"]))
1311assert(parse_version("1.0+") == set(["1.0", "1.1", "1.2", "1.3"]))
Rich Lane7744e112013-01-11 17:23:57 -08001312
Rich Laneae3428c2013-03-07 14:37:42 -08001313def get_stats(test, req):
1314 """
1315 Retrieve a list of stats entries. Handles OFPSF_REPLY_MORE.
1316 """
Rich Lane609194f2013-10-21 06:17:37 -07001317 msgtype = ofp.OFPT_STATS_REPLY
1318 more_flag = ofp.OFPSF_REPLY_MORE
Rich Laneae3428c2013-03-07 14:37:42 -08001319 stats = []
1320 reply, _ = test.controller.transact(req)
1321 test.assertTrue(reply is not None, "No response to stats request")
Rich Lane34c68d52013-10-11 10:38:21 -07001322 test.assertEquals(reply.type, msgtype, "Response had unexpected message type")
Rich Lane5fd6faf2013-03-11 13:30:20 -07001323 stats.extend(reply.entries)
Rich Lanebd56ed62013-07-10 15:49:44 -07001324 while reply.flags & more_flag != 0:
Rich Lane34c68d52013-10-11 10:38:21 -07001325 reply, pkt = test.controller.poll(exp_msg=msgtype)
Rich Laneae3428c2013-03-07 14:37:42 -08001326 test.assertTrue(reply is not None, "No response to stats request")
Rich Lane5fd6faf2013-03-11 13:30:20 -07001327 stats.extend(reply.entries)
Rich Laneae3428c2013-03-07 14:37:42 -08001328 return stats
1329
Rich Lanebd56ed62013-07-10 15:49:44 -07001330def get_flow_stats(test, match, table_id=None,
1331 out_port=None, out_group=None,
1332 cookie=0, cookie_mask=0):
Rich Laneae3428c2013-03-07 14:37:42 -08001333 """
1334 Retrieve a list of flow stats entries.
1335 """
Rich Lanebd56ed62013-07-10 15:49:44 -07001336
1337 if table_id == None:
1338 if ofp.OFP_VERSION <= 2:
1339 table_id = 0xff
1340 else:
1341 table_id = ofp.OFPTT_ALL
1342
Rich Lanef3bc48c2013-05-03 17:39:35 -07001343 if out_port == None:
Rich Lanebd56ed62013-07-10 15:49:44 -07001344 if ofp.OFP_VERSION == 1:
1345 out_port = ofp.OFPP_NONE
1346 else:
1347 out_port = ofp.OFPP_ANY
1348
1349 if out_group == None:
1350 if ofp.OFP_VERSION > 1:
1351 out_group = ofp.OFPP_ANY
1352
Rich Lanee717c6e2013-03-12 10:25:50 -07001353 req = ofp.message.flow_stats_request(match=match,
Rich Lanebd56ed62013-07-10 15:49:44 -07001354 table_id=table_id,
1355 out_port=out_port)
1356 if ofp.OFP_VERSION > 1:
1357 req.out_group = out_group
1358 req.cookie = cookie
1359 req.cookie_mask = cookie_mask
1360
Rich Laneae3428c2013-03-07 14:37:42 -08001361 return get_stats(test, req)
1362
Rich Lane968b6192013-03-07 15:34:43 -08001363def get_port_stats(test, port_no):
1364 """
1365 Retrieve a list of port stats entries.
1366 """
Rich Lanee717c6e2013-03-12 10:25:50 -07001367 req = ofp.message.port_stats_request(port_no=port_no)
Rich Lane968b6192013-03-07 15:34:43 -08001368 return get_stats(test, req)
1369
Rich Lane6a334922013-03-07 16:14:52 -08001370def get_queue_stats(test, port_no, queue_id):
1371 """
1372 Retrieve a list of queue stats entries.
1373 """
Rich Lanee717c6e2013-03-12 10:25:50 -07001374 req = ofp.message.queue_stats_request(port_no=port_no, queue_id=queue_id)
Rich Lane6a334922013-03-07 16:14:52 -08001375 return get_stats(test, req)
1376
Rich Laneae3428c2013-03-07 14:37:42 -08001377def verify_flow_stats(test, match, table_id=0xff,
Rich Lanef3bc48c2013-05-03 17:39:35 -07001378 out_port=None,
Rich Laneae3428c2013-03-07 14:37:42 -08001379 initial=[],
1380 pkts=None, bytes=None):
1381 """
1382 Verify that flow stats changed as expected.
1383
1384 Optionally takes an 'initial' list of stats entries, as returned by
1385 get_flow_stats(). If 'initial' is not given the counters are assumed to
1386 begin at 0.
1387 """
Rich Lanef3bc48c2013-05-03 17:39:35 -07001388 if out_port == None:
1389 out_port = ofp.OFPP_NONE
1390
Rich Laneae3428c2013-03-07 14:37:42 -08001391 def accumulate(stats):
1392 pkts_acc = bytes_acc = 0
1393 for stat in stats:
1394 pkts_acc += stat.packet_count
1395 bytes_acc += stat.byte_count
1396 return (pkts_acc, bytes_acc)
1397
1398 pkts_before, bytes_before = accumulate(initial)
1399
1400 # Wait 10s for counters to update
1401 pkt_diff = byte_diff = None
1402 for i in range(0, 100):
1403 stats = get_flow_stats(test, match, table_id=table_id, out_port=out_port)
1404 pkts_after, bytes_after = accumulate(stats)
1405 pkt_diff = pkts_after - pkts_before
1406 byte_diff = bytes_after - bytes_before
1407 if (pkts == None or pkt_diff >= pkts) and \
1408 (bytes == None or byte_diff >= bytes):
1409 break
Dan Talayco53724732013-03-08 23:54:02 -08001410 time.sleep(0.1)
Rich Laneae3428c2013-03-07 14:37:42 -08001411
1412 if pkts != None:
1413 test.assertEquals(pkt_diff, pkts, "Flow packet counter not updated properly (expected increase of %d, got increase of %d)" % (pkts, pkt_diff))
1414
1415 if bytes != None:
Rich Lane53b96812013-03-07 16:54:50 -08001416 test.assertTrue(byte_diff >= bytes and byte_diff <= bytes*1.1,
1417 "Flow byte counter not updated properly (expected increase of %d, got increase of %d)" % (bytes, byte_diff))
Rich Laneae3428c2013-03-07 14:37:42 -08001418
Rich Lane968b6192013-03-07 15:34:43 -08001419def verify_port_stats(test, port,
1420 initial=[],
1421 tx_pkts=None, rx_pkts=None,
1422 tx_bytes=None, rx_bytes=None):
1423 """
1424 Verify that port stats changed as expected.
1425
1426 Optionally takes an 'initial' list of stats entries, as returned by
1427 get_port_stats(). If 'initial' is not given the counters are assumed to
1428 begin at 0.
1429 """
1430 def accumulate(stats):
1431 tx_pkts_acc = rx_pkts_acc = tx_bytes_acc = rx_bytes_acc = 0
1432 for stat in stats:
1433 tx_pkts_acc += stat.tx_packets
1434 rx_pkts_acc += stat.rx_packets
1435 tx_bytes_acc += stat.tx_bytes
1436 rx_bytes_acc += stat.rx_bytes
1437 return (tx_pkts_acc, rx_pkts_acc, tx_bytes_acc, rx_bytes_acc)
1438
1439 tx_pkts_before, rx_pkts_before, \
1440 tx_bytes_before, rx_bytes_before = accumulate(initial)
1441
1442 # Wait 10s for counters to update
1443 for i in range(0, 100):
1444 stats = get_port_stats(test, port)
1445 tx_pkts_after, rx_pkts_after, \
1446 tx_bytes_after, rx_bytes_after = accumulate(stats)
1447 tx_pkts_diff = tx_pkts_after - tx_pkts_before
1448 rx_pkts_diff = rx_pkts_after - rx_pkts_before
1449 tx_bytes_diff = tx_bytes_after - tx_bytes_before
1450 rx_bytes_diff = rx_bytes_after - rx_bytes_before
1451 if (tx_pkts == None or tx_pkts == tx_pkts_diff) and \
1452 (rx_pkts == None or rx_pkts == rx_pkts_diff) and \
Rich Lane53b96812013-03-07 16:54:50 -08001453 (tx_bytes == None or tx_bytes <= tx_bytes_diff) and \
1454 (rx_bytes == None or rx_bytes <= rx_bytes_diff):
Rich Lane968b6192013-03-07 15:34:43 -08001455 break
1456 time.sleep(0.1)
1457
1458 if (tx_pkts != None):
1459 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))
1460 if (rx_pkts != None):
1461 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))
1462 if (tx_bytes != None):
Rich Lane53b96812013-03-07 16:54:50 -08001463 test.assertTrue(tx_bytes_diff >= tx_bytes and tx_bytes_diff <= tx_bytes*1.1,
1464 "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 -08001465 if (rx_bytes != None):
Rich Lane53b96812013-03-07 16:54:50 -08001466 test.assertTrue(rx_bytes_diff >= rx_bytes and rx_bytes_diff <= rx_bytes*1.1,
1467 "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 -08001468
Rich Lane6a334922013-03-07 16:14:52 -08001469def verify_queue_stats(test, port_no, queue_id,
1470 initial=[],
1471 pkts=None, bytes=None):
1472 """
1473 Verify that queue stats changed as expected.
1474
1475 Optionally takes an 'initial' list of stats entries, as returned by
1476 get_queue_stats(). If 'initial' is not given the counters are assumed to
1477 begin at 0.
1478 """
1479 def accumulate(stats):
1480 pkts_acc = bytes_acc = 0
1481 for stat in stats:
1482 pkts_acc += stat.tx_packets
1483 bytes_acc += stat.tx_bytes
1484 return (pkts_acc, bytes_acc)
1485
1486 pkts_before, bytes_before = accumulate(initial)
1487
1488 # Wait 10s for counters to update
1489 pkt_diff = byte_diff = None
1490 for i in range(0, 100):
1491 stats = get_queue_stats(test, port_no, queue_id)
1492 pkts_after, bytes_after = accumulate(stats)
1493 pkt_diff = pkts_after - pkts_before
1494 byte_diff = bytes_after - bytes_before
1495 if (pkts == None or pkt_diff >= pkts) and \
1496 (bytes == None or byte_diff >= bytes):
1497 break
Dan Talayco53724732013-03-08 23:54:02 -08001498 time.sleep(0.1)
Rich Lane6a334922013-03-07 16:14:52 -08001499
1500 if pkts != None:
1501 test.assertEquals(pkt_diff, pkts, "Queue packet counter not updated properly (expected increase of %d, got increase of %d)" % (pkts, pkt_diff))
1502
1503 if bytes != None:
Rich Lane53b96812013-03-07 16:54:50 -08001504 test.assertTrue(byte_diff >= bytes and byte_diff <= bytes*1.1,
1505 "Queue byte counter not updated properly (expected increase of %d, got increase of %d)" % (bytes, byte_diff))
Rich Laneae3428c2013-03-07 14:37:42 -08001506
Rich Lane4c504f32013-06-07 17:24:14 -07001507def packet_in_match(msg, data, in_port=None, reason=None):
1508 """
1509 Check whether the packet_in message 'msg' has fields matching 'data',
1510 'in_port', and 'reason'.
1511
1512 This function handles truncated packet_in data. The 'in_port' and 'reason'
1513 parameters are optional.
1514
1515 @param msg packet_in message
1516 @param data Expected packet_in data
1517 @param in_port Expected packet_in in_port, or None
1518 @param reason Expected packet_in reason, or None
1519 """
1520
Rich Lanec0d26dd2013-07-10 12:46:03 -07001521 if ofp.OFP_VERSION <= 2:
1522 pkt_in_port = msg.in_port
1523 else:
1524 oxms = { type(oxm): oxm for oxm in msg.match.oxm_list }
1525 if ofp.oxm.in_port in oxms:
1526 pkt_in_port = oxms[ofp.oxm.in_port].value
1527 else:
1528 logging.warn("Missing in_port in packet-in message")
1529 pkt_in_port = None
1530
1531 if in_port != None and in_port != pkt_in_port:
Rich Lane9f2f17e2013-09-13 13:19:37 -07001532 logging.debug("Incorrect packet_in in_port (expected %d, received %d)", in_port, pkt_in_port)
Rich Lane4c504f32013-06-07 17:24:14 -07001533 return False
1534
Rich Lanec0d26dd2013-07-10 12:46:03 -07001535 if reason != None and reason != msg.reason:
Rich Lane4c504f32013-06-07 17:24:14 -07001536 logging.debug("Incorrect packet_in reason (expected %d, received %d)", reason, msg.reason)
1537 return False
1538
1539 # Check that one of the packets is a prefix of the other.
1540 # The received packet may be either truncated or padded, but not both.
1541 # (Some of the padding may be truncated but that's irrelevant). We
1542 # need to check that the smaller packet is a prefix of the larger one.
1543 # Note that this check succeeds if the switch sends a zero-length
1544 # packet-in.
1545 compare_len = min(len(msg.data), len(data))
1546 if data[:compare_len] != msg.data[:compare_len]:
1547 logging.debug("Incorrect packet_in data")
1548 logging.debug("Expected %s" % format_packet(data[:compare_len]))
1549 logging.debug("Received %s" % format_packet(msg.data[:compare_len]))
1550 return False
1551
1552 return True
1553
1554def verify_packet_in(test, data, in_port, reason, controller=None):
1555 """
1556 Assert that the controller receives a packet_in message matching data 'data'
1557 from port 'in_port' with reason 'reason'. Does not trigger the packet_in
1558 itself, that's up to the test case.
1559
1560 @param test Instance of base_tests.SimpleProtocol
1561 @param pkt String to expect as the packet_in data
1562 @param in_port OpenFlow port number to expect as the packet_in in_port
1563 @param reason One of OFPR_* to expect as the packet_in reason
1564 @param controller Controller instance, defaults to test.controller
1565 @returns The received packet-in message
1566 """
1567
1568 if controller == None:
1569 controller = test.controller
1570
1571 end_time = time.time() + oftest.ofutils.default_timeout
1572
1573 while True:
1574 msg, _ = controller.poll(ofp.OFPT_PACKET_IN, end_time - time.time())
1575 if not msg:
1576 # Timeout
1577 break
1578 elif packet_in_match(msg, data, in_port, reason):
1579 # Found a matching message
1580 break
1581
1582 test.assertTrue(msg is not None, 'Packet in message not received on port %d' % in_port)
1583 return msg
1584
1585def verify_no_packet_in(test, data, in_port, controller=None):
1586 """
1587 Assert that the controller does not receive a packet_in message matching
1588 data 'data' from port 'in_port'.
1589
1590 @param test Instance of base_tests.SimpleProtocol
1591 @param pkt String to expect as the packet_in data
1592 @param in_port OpenFlow port number to expect as the packet_in in_port
1593 @param controller Controller instance, defaults to test.controller
1594 """
1595
1596 if controller == None:
1597 controller = test.controller
1598
1599 # Negative test, need to wait a short amount of time before checking we
1600 # didn't receive the message.
1601 time.sleep(0.5)
1602
1603 # Check every packet_in queued in the controller
1604 while True:
1605 msg, _ = controller.poll(ofp.OFPT_PACKET_IN, timeout=0)
1606 if msg == None:
1607 # No more queued packet_in messages
1608 break
1609 elif packet_in_match(msg, data, in_port, None):
1610 # Found a matching message
1611 break
1612
Rich Lane82c882d2013-08-09 17:13:52 -07001613 if in_port == None:
1614 test.assertTrue(msg == None, "Did not expect a packet-in message on any port")
1615 else:
1616 test.assertTrue(msg == None, "Did not expect a packet-in message on port %d" % in_port)
Rich Lane4c504f32013-06-07 17:24:14 -07001617
Rich Lane045db072013-08-06 13:16:30 -07001618def openflow_ports(num=None):
1619 """
1620 Return a list of 'num' OpenFlow port numbers
1621
1622 If 'num' is None, return all available ports. Otherwise, limit the length
1623 of the result to 'num' and raise an exception if not enough ports are
1624 available.
1625 """
1626 ports = sorted(oftest.config["port_map"].keys())
1627 if num != None and len(ports) < num:
1628 raise Exception("test requires %d ports but only %d are available" % (num, len(ports)))
1629 return ports[:num]
1630
Rich Lanee4b384d2013-09-13 14:33:40 -07001631def verify_packet(test, pkt, ofport):
1632 """
1633 Check that an expected packet is received
1634 """
1635 logging.debug("Checking for pkt on port %r", ofport)
1636 (rcv_port, rcv_pkt, pkt_time) = test.dataplane.poll(port_number=ofport, exp_pkt=str(pkt))
1637 test.assertTrue(rcv_pkt != None, "Did not receive pkt on %r" % ofport)
1638
1639def verify_no_packet(test, pkt, ofport):
1640 """
1641 Check that a particular packet is not received
1642 """
1643 logging.debug("Negative check for pkt on port %r", ofport)
1644 (rcv_port, rcv_pkt, pkt_time) = test.dataplane.poll(port_number=ofport, exp_pkt=str(pkt), timeout=0.01)
1645 test.assertTrue(rcv_pkt == None, "Received packet on %r" % ofport)
1646
1647def verify_no_other_packets(test):
1648 """
1649 Check that no unexpected packets are received
1650
1651 This is a no-op if the --relax option is in effect.
1652 """
1653 if oftest.config["relax"]:
1654 return
1655 logging.debug("Checking for unexpected packets on all ports")
1656 (rcv_port, rcv_pkt, pkt_time) = test.dataplane.poll(timeout=0.01)
1657 if rcv_pkt != None:
1658 logging.debug("Received unexpected packet on port %r: %s", rcv_port, format_packet(rcv_pkt))
1659 test.assertTrue(rcv_pkt == None, "Unexpected packet on port %r" % rcv_port)
1660
1661def verify_packets(test, pkt, ofports):
1662 """
1663 Check that a packet is received on certain ports
1664
1665 Also verifies that the packet is not received on any other ports, and that no
1666 other packets are received (unless --relax is in effect).
1667
1668 This covers the common and simplest cases for checking dataplane outputs.
1669 For more complex usage, like multiple different packets being output, or
1670 multiple packets on the same port, use the primitive verify_packet,
1671 verify_no_packet, and verify_no_other_packets functions directly.
1672 """
1673 pkt = str(pkt)
1674 for ofport in openflow_ports():
1675 if ofport in ofports:
1676 verify_packet(test, pkt, ofport)
1677 else:
1678 verify_no_packet(test, pkt, ofport)
1679 verify_no_other_packets(test)
1680
Rich Lane12d04592013-10-10 17:21:07 -07001681def verify_no_errors(ctrl):
1682 error, _ = ctrl.poll(ofp.OFPT_ERROR, 0)
1683 if error:
1684 raise AssertionError("unexpected error type=%d code=%d" % (error.err_type, error.code))
Rich Lanee4b384d2013-09-13 14:33:40 -07001685
Rich Lane7744e112013-01-11 17:23:57 -08001686__all__ = list(set(locals()) - _import_blacklist)