blob: 2903a5e5ba4a38252cca73d8e66e4fb3500e1284 [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,
Harshmeet Singhc51f4042014-05-21 13:32:52 -070083 tcp_flags="S",
Christian Dickmann8b59b4b2012-09-23 16:48:30 -070084 ip_ihl=None,
85 ip_options=False
Dan Talayco41eae8b2010-03-10 13:57:06 -080086 ):
87 """
88 Return a simple dataplane TCP packet
89
90 Supports a few parameters:
91 @param len Length of packet in bytes w/o CRC
Rich Laned0478ff2013-03-11 12:46:58 -070092 @param eth_dst Destinatino MAC
93 @param eth_src Source MAC
Tatsuya Yabe460321e2010-05-25 17:50:49 -070094 @param dl_vlan_enable True if the packet is with vlan, False otherwise
Rich Laned0478ff2013-03-11 12:46:58 -070095 @param vlan_vid VLAN ID
96 @param vlan_pcp VLAN priority
Dan Talayco41eae8b2010-03-10 13:57:06 -080097 @param ip_src IP source
98 @param ip_dst IP destination
Tatsuya Yabe460321e2010-05-25 17:50:49 -070099 @param ip_tos IP ToS
Gregor Maier9cc93342013-01-29 16:55:28 -0800100 @param ip_ttl IP TTL
Dan Talayco41eae8b2010-03-10 13:57:06 -0800101 @param tcp_dport TCP destination port
Harshmeet Singhc51f4042014-05-21 13:32:52 -0700102 @param tcp_sport TCP source port
103 @param tcp_flags TCP Control flags
Dan Talayco41eae8b2010-03-10 13:57:06 -0800104
105 Generates a simple TCP request. Users
106 shouldn't assume anything about this packet other than that
107 it is a valid ethernet/IP/TCP frame.
108 """
Jeffrey Townsend5cb7ed32012-08-17 18:11:01 +0000109
110 if MINSIZE > pktlen:
111 pktlen = MINSIZE
112
Dan Talayco551befa2010-07-15 17:05:32 -0700113 # Note Dot1Q.id is really CFI
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800114 if (dl_vlan_enable):
Rich Laned0478ff2013-03-11 12:46:58 -0700115 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
116 scapy.Dot1Q(prio=vlan_pcp, id=dl_vlan_cfi, vlan=vlan_vid)/ \
Gregor Maier9cc93342013-01-29 16:55:28 -0800117 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ttl=ip_ttl, ihl=ip_ihl)/ \
Harshmeet Singhc51f4042014-05-21 13:32:52 -0700118 scapy.TCP(sport=tcp_sport, dport=tcp_dport, flags=tcp_flags)
Tatsuya Yabe460321e2010-05-25 17:50:49 -0700119 else:
Christian Dickmann8b59b4b2012-09-23 16:48:30 -0700120 if not ip_options:
Rich Laned0478ff2013-03-11 12:46:58 -0700121 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
Gregor Maier9cc93342013-01-29 16:55:28 -0800122 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ttl=ip_ttl, ihl=ip_ihl)/ \
Harshmeet Singhc51f4042014-05-21 13:32:52 -0700123 scapy.TCP(sport=tcp_sport, dport=tcp_dport, flags=tcp_flags)
Christian Dickmann8b59b4b2012-09-23 16:48:30 -0700124 else:
Rich Laned0478ff2013-03-11 12:46:58 -0700125 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
Gregor Maier9cc93342013-01-29 16:55:28 -0800126 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ttl=ip_ttl, ihl=ip_ihl, options=ip_options)/ \
Harshmeet Singhc51f4042014-05-21 13:32:52 -0700127 scapy.TCP(sport=tcp_sport, dport=tcp_dport, flags=tcp_flags)
Tatsuya Yabe460321e2010-05-25 17:50:49 -0700128
Dan Talayco41eae8b2010-03-10 13:57:06 -0800129 pkt = pkt/("D" * (pktlen - len(pkt)))
130
131 return pkt
132
Rich Lane86aceb02013-07-17 18:45:38 -0700133def simple_tcpv6_packet(pktlen=100,
134 eth_dst='00:01:02:03:04:05',
135 eth_src='00:06:07:08:09:0a',
136 dl_vlan_enable=False,
137 vlan_vid=0,
138 vlan_pcp=0,
139 ipv6_src='2001:db8:85a3::8a2e:370:7334',
140 ipv6_dst='2001:db8:85a3::8a2e:370:7335',
141 ipv6_tc=0,
142 ipv6_hlim=64,
143 ipv6_fl=0,
144 tcp_sport=1234,
Harshmeet Singhc51f4042014-05-21 13:32:52 -0700145 tcp_dport=80,
Harshmeet Singh31ba3312014-05-21 13:48:35 -0700146 tcp_flags="S"):
Rich Lane86aceb02013-07-17 18:45:38 -0700147 """
148 Return a simple IPv6/TCP packet
149
150 Supports a few parameters:
151 @param len Length of packet in bytes w/o CRC
152 @param eth_dst Destination MAC
153 @param eth_src Source MAC
154 @param dl_vlan_enable True if the packet is with vlan, False otherwise
155 @param vlan_vid VLAN ID
156 @param vlan_pcp VLAN priority
157 @param ipv6_src IPv6 source
158 @param ipv6_dst IPv6 destination
159 @param ipv6_tc IPv6 traffic class
160 @param ipv6_ttl IPv6 hop limit
161 @param ipv6_fl IPv6 flow label
162 @param tcp_dport TCP destination port
163 @param tcp_sport TCP source port
Harshmeet Singhc51f4042014-05-21 13:32:52 -0700164 @param tcp_flags TCP Control flags
Rich Lane86aceb02013-07-17 18:45:38 -0700165
166 Generates a simple TCP request. Users shouldn't assume anything about this
167 packet other than that it is a valid ethernet/IPv6/TCP frame.
168 """
169
170 if MINSIZE > pktlen:
171 pktlen = MINSIZE
172
173 pkt = scapy.Ether(dst=eth_dst, src=eth_src)
174 if dl_vlan_enable or vlan_vid or vlan_pcp:
175 pkt /= scapy.Dot1Q(vlan=vlan_vid, prio=vlan_pcp)
176 pkt /= scapy.IPv6(src=ipv6_src, dst=ipv6_dst, fl=ipv6_fl, tc=ipv6_tc, hlim=ipv6_hlim)
Harshmeet Singhc51f4042014-05-21 13:32:52 -0700177 pkt /= scapy.TCP(sport=tcp_sport, dport=tcp_dport, flags=tcp_flags)
Rich Lane86aceb02013-07-17 18:45:38 -0700178 pkt /= ("D" * (pktlen - len(pkt)))
179
180 return pkt
181
Rich Lane6ee7bea2012-10-26 16:19:29 -0700182def simple_udp_packet(pktlen=100,
Rich Laned0478ff2013-03-11 12:46:58 -0700183 eth_dst='00:01:02:03:04:05',
184 eth_src='00:06:07:08:09:0a',
Rich Lane6ee7bea2012-10-26 16:19:29 -0700185 dl_vlan_enable=False,
Rich Laned0478ff2013-03-11 12:46:58 -0700186 vlan_vid=0,
187 vlan_pcp=0,
Rich Lane6ee7bea2012-10-26 16:19:29 -0700188 dl_vlan_cfi=0,
189 ip_src='192.168.0.1',
190 ip_dst='192.168.0.2',
191 ip_tos=0,
Gregor Maier9cc93342013-01-29 16:55:28 -0800192 ip_ttl=64,
Rich Lane6ee7bea2012-10-26 16:19:29 -0700193 udp_sport=1234,
194 udp_dport=80,
195 ip_ihl=None,
196 ip_options=False
197 ):
198 """
199 Return a simple dataplane UDP packet
200
201 Supports a few parameters:
202 @param len Length of packet in bytes w/o CRC
Rich Laned0478ff2013-03-11 12:46:58 -0700203 @param eth_dst Destination MAC
204 @param eth_src Source MAC
Rich Lane6ee7bea2012-10-26 16:19:29 -0700205 @param dl_vlan_enable True if the packet is with vlan, False otherwise
Rich Laned0478ff2013-03-11 12:46:58 -0700206 @param vlan_vid VLAN ID
207 @param vlan_pcp VLAN priority
Rich Lane6ee7bea2012-10-26 16:19:29 -0700208 @param ip_src IP source
209 @param ip_dst IP destination
210 @param ip_tos IP ToS
Gregor Maier9cc93342013-01-29 16:55:28 -0800211 @param ip_ttl IP TTL
Rich Lane6ee7bea2012-10-26 16:19:29 -0700212 @param udp_dport UDP destination port
213 @param udp_sport UDP source port
214
215 Generates a simple UDP packet. Users shouldn't assume anything about
216 this packet other than that it is a valid ethernet/IP/UDP frame.
217 """
218
219 if MINSIZE > pktlen:
220 pktlen = MINSIZE
221
222 # Note Dot1Q.id is really CFI
223 if (dl_vlan_enable):
Rich Laned0478ff2013-03-11 12:46:58 -0700224 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
225 scapy.Dot1Q(prio=vlan_pcp, id=dl_vlan_cfi, vlan=vlan_vid)/ \
Gregor Maier9cc93342013-01-29 16:55:28 -0800226 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ttl=ip_ttl, ihl=ip_ihl)/ \
Rich Lane6ee7bea2012-10-26 16:19:29 -0700227 scapy.UDP(sport=udp_sport, dport=udp_dport)
228 else:
229 if not ip_options:
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)/ \
Rich Lane6ee7bea2012-10-26 16:19:29 -0700232 scapy.UDP(sport=udp_sport, dport=udp_dport)
233 else:
Rich Laned0478ff2013-03-11 12:46:58 -0700234 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
Gregor Maier9cc93342013-01-29 16:55:28 -0800235 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 -0700236 scapy.UDP(sport=udp_sport, dport=udp_dport)
237
238 pkt = pkt/("D" * (pktlen - len(pkt)))
239
240 return pkt
241
macauley17cd60d2015-07-27 17:41:18 +0800242def simple_vxlan_packet(eth_dst='00:01:02:03:04:05',
243 eth_src='00:06:07:08:09:0a',
244 dl_vlan_enable=False,
245 vlan_vid=0,
246 vlan_pcp=0,
247 dl_vlan_cfi=0,
248 ip_src='192.168.0.1',
249 ip_dst='192.168.0.2',
250 ip_tos=0,
251 ip_ttl=64,
252 udp_sport=1234,
253 udp_dport=4789,
254 vnid=1,
255 inner_pyload=None,
256 ip_ihl=None,
257 ip_options=False
258 ):
259 """
260 Return a simple dataplane UDP packet
261
262 Supports a few parameters:
263 @param len Length of packet in bytes w/o CRC
264 @param eth_dst Destination MAC
265 @param eth_src Source MAC
266 @param dl_vlan_enable True if the packet is with vlan, False otherwise
267 @param vlan_vid VLAN ID
268 @param vlan_pcp VLAN priority
269 @param ip_src IP source
270 @param ip_dst IP destination
271 @param ip_tos IP ToS
272 @param ip_ttl IP TTL
273 @param udp_dport UDP destination port
274 @param udp_sport UDP source port
275 @param inner_pyload inner pacekt content
276 Generates a simple UDP packet. Users shouldn't assume anything about
277 this packet other than that it is a valid ethernet/IP/UDP frame.
278 """
279
280 # Note Dot1Q.id is really CFI
281 if (dl_vlan_enable):
282 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
283 scapy.Dot1Q(prio=vlan_pcp, id=dl_vlan_cfi, vlan=vlan_vid)/ \
284 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ttl=ip_ttl, ihl=ip_ihl)/ \
285 scapy.UDP(sport=udp_sport, dport=udp_dport)
286 else:
287 if not ip_options:
288 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
289 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ttl=ip_ttl, ihl=ip_ihl)/ \
290 scapy.UDP(sport=udp_sport, dport=udp_dport)
291 else:
292 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
293 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ttl=ip_ttl, ihl=ip_ihl, options=ip_options)/ \
294 scapy.UDP(sport=udp_sport, dport=udp_dport)
295 #add vxlan header
296 pkt = pkt/scapy.VXLAN(vni=vnid)
297 #add innder payload
298 pkt=pkt/inner_pyload
299
300 return pkt
301
Rich Lane86aceb02013-07-17 18:45:38 -0700302def simple_udpv6_packet(pktlen=100,
303 eth_dst='00:01:02:03:04:05',
304 eth_src='00:06:07:08:09:0a',
305 dl_vlan_enable=False,
306 vlan_vid=0,
307 vlan_pcp=0,
308 ipv6_src='2001:db8:85a3::8a2e:370:7334',
309 ipv6_dst='2001:db8:85a3::8a2e:370:7335',
310 ipv6_tc=0,
311 ipv6_hlim=64,
312 ipv6_fl=0,
313 udp_sport=1234,
314 udp_dport=80):
315 """
316 Return a simple IPv6/UDP packet
317
318 Supports a few parameters:
319 @param len Length of packet in bytes w/o CRC
320 @param eth_dst Destination MAC
321 @param eth_src Source MAC
322 @param dl_vlan_enable True if the packet is with vlan, False otherwise
323 @param vlan_vid VLAN ID
324 @param vlan_pcp VLAN priority
325 @param ipv6_src IPv6 source
326 @param ipv6_dst IPv6 destination
327 @param ipv6_tc IPv6 traffic class
328 @param ipv6_ttl IPv6 hop limit
329 @param ipv6_fl IPv6 flow label
330 @param udp_dport UDP destination port
331 @param udp_sport UDP source port
332
333 Generates a simple UDP request. Users shouldn't assume anything about this
334 packet other than that it is a valid ethernet/IPv6/UDP frame.
335 """
336
337 if MINSIZE > pktlen:
338 pktlen = MINSIZE
339
340 pkt = scapy.Ether(dst=eth_dst, src=eth_src)
341 if dl_vlan_enable or vlan_vid or vlan_pcp:
342 pkt /= scapy.Dot1Q(vlan=vlan_vid, prio=vlan_pcp)
343 pkt /= scapy.IPv6(src=ipv6_src, dst=ipv6_dst, fl=ipv6_fl, tc=ipv6_tc, hlim=ipv6_hlim)
344 pkt /= scapy.UDP(sport=udp_sport, dport=udp_dport)
345 pkt /= ("D" * (pktlen - len(pkt)))
346
347 return pkt
348
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700349def simple_icmp_packet(pktlen=60,
Rich Laned0478ff2013-03-11 12:46:58 -0700350 eth_dst='00:01:02:03:04:05',
351 eth_src='00:06:07:08:09:0a',
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700352 dl_vlan_enable=False,
Rich Laned0478ff2013-03-11 12:46:58 -0700353 vlan_vid=0,
354 vlan_pcp=0,
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700355 ip_src='192.168.0.1',
356 ip_dst='192.168.0.2',
357 ip_tos=0,
Gregor Maier9cc93342013-01-29 16:55:28 -0800358 ip_ttl=64,
Harshmeet Singhd209c0b2014-01-28 09:48:58 -0600359 ip_id=1,
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700360 icmp_type=8,
Harshmeet Singhd209c0b2014-01-28 09:48:58 -0600361 icmp_code=0,
Harshmeet Singh45b2a9d2014-01-28 13:02:04 -0600362 icmp_data=''):
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700363 """
364 Return a simple ICMP packet
365
366 Supports a few parameters:
367 @param len Length of packet in bytes w/o CRC
Rich Laned0478ff2013-03-11 12:46:58 -0700368 @param eth_dst Destinatino MAC
369 @param eth_src Source MAC
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700370 @param dl_vlan_enable True if the packet is with vlan, False otherwise
Rich Laned0478ff2013-03-11 12:46:58 -0700371 @param vlan_vid VLAN ID
372 @param vlan_pcp VLAN priority
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700373 @param ip_src IP source
374 @param ip_dst IP destination
375 @param ip_tos IP ToS
Gregor Maier9cc93342013-01-29 16:55:28 -0800376 @param ip_ttl IP TTL
Harshmeet Singhd209c0b2014-01-28 09:48:58 -0600377 @param ip_id IP Identification
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700378 @param icmp_type ICMP type
379 @param icmp_code ICMP code
Harshmeet Singhd209c0b2014-01-28 09:48:58 -0600380 @param icmp_data ICMP data
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700381
382 Generates a simple ICMP ECHO REQUEST. Users
383 shouldn't assume anything about this packet other than that
384 it is a valid ethernet/ICMP frame.
385 """
Jeffrey Townsend5cb7ed32012-08-17 18:11:01 +0000386
387 if MINSIZE > pktlen:
388 pktlen = MINSIZE
389
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700390 if (dl_vlan_enable):
Rich Laned0478ff2013-03-11 12:46:58 -0700391 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
392 scapy.Dot1Q(prio=vlan_pcp, id=0, vlan=vlan_vid)/ \
Harshmeet Singhd209c0b2014-01-28 09:48:58 -0600393 scapy.IP(src=ip_src, dst=ip_dst, ttl=ip_ttl, tos=ip_tos, id=ip_id)/ \
Harshmeet Singh45b2a9d2014-01-28 13:02:04 -0600394 scapy.ICMP(type=icmp_type, code=icmp_code)/ icmp_data
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700395 else:
Rich Laned0478ff2013-03-11 12:46:58 -0700396 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
Harshmeet Singhd209c0b2014-01-28 09:48:58 -0600397 scapy.IP(src=ip_src, dst=ip_dst, ttl=ip_ttl, tos=ip_tos, id=ip_id)/ \
Harshmeet Singh45b2a9d2014-01-28 13:02:04 -0600398 scapy.ICMP(type=icmp_type, code=icmp_code)/ icmp_data
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700399
400 pkt = pkt/("0" * (pktlen - len(pkt)))
401
402 return pkt
403
Rich Lane86aceb02013-07-17 18:45:38 -0700404def simple_icmpv6_packet(pktlen=100,
405 eth_dst='00:01:02:03:04:05',
406 eth_src='00:06:07:08:09:0a',
407 dl_vlan_enable=False,
408 vlan_vid=0,
409 vlan_pcp=0,
410 ipv6_src='2001:db8:85a3::8a2e:370:7334',
411 ipv6_dst='2001:db8:85a3::8a2e:370:7335',
412 ipv6_tc=0,
413 ipv6_hlim=64,
414 ipv6_fl=0,
415 icmp_type=8,
416 icmp_code=0):
417 """
418 Return a simple ICMPv6 packet
419
420 Supports a few parameters:
421 @param len Length of packet in bytes w/o CRC
422 @param eth_dst Destination MAC
423 @param eth_src Source MAC
424 @param dl_vlan_enable True if the packet is with vlan, False otherwise
425 @param vlan_vid VLAN ID
426 @param vlan_pcp VLAN priority
427 @param ipv6_src IPv6 source
428 @param ipv6_dst IPv6 destination
429 @param ipv6_tc IPv6 traffic class
430 @param ipv6_ttl IPv6 hop limit
431 @param ipv6_fl IPv6 flow label
432 @param icmp_type ICMP type
433 @param icmp_code ICMP code
434
435 Generates a simple ICMP ECHO REQUEST. Users shouldn't assume anything
436 about this packet other than that it is a valid ethernet/IPv6/ICMP frame.
437 """
438
439 if MINSIZE > pktlen:
440 pktlen = MINSIZE
441
442 pkt = scapy.Ether(dst=eth_dst, src=eth_src)
443 if dl_vlan_enable or vlan_vid or vlan_pcp:
444 pkt /= scapy.Dot1Q(vlan=vlan_vid, prio=vlan_pcp)
445 pkt /= scapy.IPv6(src=ipv6_src, dst=ipv6_dst, fl=ipv6_fl, tc=ipv6_tc, hlim=ipv6_hlim)
446 pkt /= scapy.ICMPv6Unknown(type=icmp_type, code=icmp_code)
447 pkt /= ("D" * (pktlen - len(pkt)))
448
449 return pkt
450
Shudong Zhouc7562b12013-02-06 01:12:18 -0800451def simple_arp_packet(pktlen=60,
Rich Laned0478ff2013-03-11 12:46:58 -0700452 eth_dst='ff:ff:ff:ff:ff:ff',
453 eth_src='00:06:07:08:09:0a',
Rich Lanee01611f2014-01-15 14:55:11 -0800454 vlan_vid=0,
455 vlan_pcp=0,
Shudong Zhouc7562b12013-02-06 01:12:18 -0800456 arp_op=1,
457 ip_snd='192.168.0.1',
458 ip_tgt='192.168.0.2',
459 hw_snd='00:06:07:08:09:0a',
460 hw_tgt='00:00:00:00:00:00',
461 ):
462 """
463 Return a simple ARP packet
464
465 Supports a few parameters:
466 @param len Length of packet in bytes w/o CRC
Rich Laned0478ff2013-03-11 12:46:58 -0700467 @param eth_dst Destinatino MAC
468 @param eth_src Source MAC
Shudong Zhouc7562b12013-02-06 01:12:18 -0800469 @param arp_op Operation (1=request, 2=reply)
470 @param ip_snd Sender IP
471 @param ip_tgt Target IP
472 @param hw_snd Sender hardware address
473 @param hw_tgt Target hardware address
474
475 Generates a simple ARP REQUEST. Users
476 shouldn't assume anything about this packet other than that
477 it is a valid ethernet/ARP frame.
478 """
479
480 if MINSIZE > pktlen:
481 pktlen = MINSIZE
482
Rich Lanee01611f2014-01-15 14:55:11 -0800483 pkt = scapy.Ether(dst=eth_dst, src=eth_src)
484 if vlan_vid or vlan_pcp:
485 pkt /= scapy.Dot1Q(vlan=vlan_vid, prio=vlan_pcp)
486 pkt /= scapy.ARP(hwsrc=hw_snd, hwdst=hw_tgt, pdst=ip_tgt, psrc=ip_snd, op=arp_op)
Shudong Zhouc7562b12013-02-06 01:12:18 -0800487
Rich Laned459ce52014-01-24 12:09:54 -0800488 pkt = pkt/("\0" * (pktlen - len(pkt)))
Shudong Zhouc7562b12013-02-06 01:12:18 -0800489
490 return pkt
491
Ed Swierk0aeff8c2012-03-23 20:27:18 -0700492def simple_eth_packet(pktlen=60,
Rich Lane53275082013-11-18 23:26:22 -0800493 eth_dst='00:01:02:03:04:05',
494 eth_src='00:06:07:08:09:0a',
Rich Laned0478ff2013-03-11 12:46:58 -0700495 eth_type=0x88cc):
Jeffrey Townsend5cb7ed32012-08-17 18:11:01 +0000496
497 if MINSIZE > pktlen:
498 pktlen = MINSIZE
499
Rich Laned0478ff2013-03-11 12:46:58 -0700500 pkt = scapy.Ether(dst=eth_dst, src=eth_src, type=eth_type)
Ed Swierk0aeff8c2012-03-23 20:27:18 -0700501
502 pkt = pkt/("0" * (pktlen - len(pkt)))
503
504 return pkt
505
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800506def qinq_tcp_packet(pktlen=100,
Rich Laned0478ff2013-03-11 12:46:58 -0700507 eth_dst='00:01:02:03:04:05',
508 eth_src='00:06:07:08:09:0a',
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800509 dl_vlan_outer=20,
510 dl_vlan_pcp_outer=0,
511 dl_vlan_cfi_outer=0,
Rich Laned0478ff2013-03-11 12:46:58 -0700512 vlan_vid=10,
513 vlan_pcp=0,
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800514 dl_vlan_cfi=0,
515 ip_src='192.168.0.1',
516 ip_dst='192.168.0.2',
517 ip_tos=0,
Gregor Maier9cc93342013-01-29 16:55:28 -0800518 ip_ttl=64,
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800519 tcp_sport=1234,
520 tcp_dport=80,
521 ip_ihl=None,
522 ip_options=False
523 ):
524 """
525 Return a doubly tagged dataplane TCP packet
526
527 Supports a few parameters:
528 @param len Length of packet in bytes w/o CRC
Rich Laned0478ff2013-03-11 12:46:58 -0700529 @param eth_dst Destinatino MAC
530 @param eth_src Source MAC
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800531 @param dl_vlan_outer Outer VLAN ID
532 @param dl_vlan_pcp_outer Outer VLAN priority
533 @param dl_vlan_cfi_outer Outer VLAN cfi bit
Rich Laned0478ff2013-03-11 12:46:58 -0700534 @param vlan_vid Inner VLAN ID
535 @param vlan_pcp VLAN priority
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800536 @param dl_vlan_cfi VLAN cfi bit
537 @param ip_src IP source
538 @param ip_dst IP destination
539 @param ip_tos IP ToS
540 @param tcp_dport TCP destination port
541 @param ip_sport TCP source port
542
543 Generates a TCP request. Users
544 shouldn't assume anything about this packet other than that
545 it is a valid ethernet/IP/TCP frame.
546 """
547
548 if MINSIZE > pktlen:
549 pktlen = MINSIZE
550
551 # Note Dot1Q.id is really CFI
Rich Laned0478ff2013-03-11 12:46:58 -0700552 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800553 scapy.Dot1Q(prio=dl_vlan_pcp_outer, id=dl_vlan_cfi_outer, vlan=dl_vlan_outer)/ \
Rich Laned0478ff2013-03-11 12:46:58 -0700554 scapy.Dot1Q(prio=vlan_pcp, id=dl_vlan_cfi, vlan=vlan_vid)/ \
Gregor Maier9cc93342013-01-29 16:55:28 -0800555 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ttl=ip_ttl, ihl=ip_ihl)/ \
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800556 scapy.TCP(sport=tcp_sport, dport=tcp_dport)
557
558 pkt = pkt/("D" * (pktlen - len(pkt)))
559
560 return pkt
561
Shudong Zhoub7f12462012-11-20 13:01:12 -0800562def do_barrier(ctrl, timeout=-1):
Dan Talayco0fc08bd2012-04-09 16:56:18 -0700563 """
564 Do a barrier command
565 Return 0 on success, -1 on error
566 """
Rich Lanee717c6e2013-03-12 10:25:50 -0700567 b = ofp.message.barrier_request()
Shudong Zhoub7f12462012-11-20 13:01:12 -0800568 (resp, pkt) = ctrl.transact(b, timeout=timeout)
Rich Lane3a261d52013-01-03 17:45:08 -0800569 if resp is None:
570 raise AssertionError("barrier failed")
Dan Talaycof6b94832012-04-12 21:50:57 -0700571 # We'll trust the transaction processing in the controller that xid matched
Rich Lane3a261d52013-01-03 17:45:08 -0800572 return 0 # for backwards compatibility
Dan Talayco92c99122010-06-03 13:53:18 -0700573
Rich Lane9a003812012-10-04 17:17:59 -0700574def port_config_get(controller, port_no):
Dan Talayco92c99122010-06-03 13:53:18 -0700575 """
576 Get a port's configuration
577
578 Gets the switch feature configuration and grabs one port's
579 configuration
580
581 @returns (hwaddr, config, advert) The hwaddress, configuration and
582 advertised values
583 """
Rich Lane6dc865c2013-07-10 10:12:13 -0700584
585 if ofp.OFP_VERSION <= 3:
586 request = ofp.message.features_request()
587 reply, _ = controller.transact(request)
588 if reply is None:
589 logging.warn("Get feature request failed")
590 return None, None, None
591 logging.debug(reply.show())
592 ports = reply.ports
593 else:
594 request = ofp.message.port_desc_stats_request()
595 # TODO do multipart correctly
596 reply, _ = controller.transact(request)
597 if reply is None:
598 logging.warn("Port desc stats request failed")
599 return None, None, None
600 logging.debug(reply.show())
601 ports = reply.entries
602
603 for port in ports:
604 if port.port_no == port_no:
605 return (port.hw_addr, port.config, port.advertised)
Dan Talayco92c99122010-06-03 13:53:18 -0700606
Rich Lane9a003812012-10-04 17:17:59 -0700607 logging.warn("Did not find port number for port config")
Dan Talayco92c99122010-06-03 13:53:18 -0700608 return None, None, None
609
Rich Lane9a003812012-10-04 17:17:59 -0700610def port_config_set(controller, port_no, config, mask):
Dan Talayco92c99122010-06-03 13:53:18 -0700611 """
612 Set the port configuration according the given parameters
613
614 Gets the switch feature configuration and updates one port's
615 configuration value according to config and mask
616 """
Rich Lane9a003812012-10-04 17:17:59 -0700617 logging.info("Setting port " + str(port_no) + " to config " + str(config))
Rich Lane6dc865c2013-07-10 10:12:13 -0700618
619 hw_addr, _, _ = port_config_get(controller, port_no)
620
Rich Lanee717c6e2013-03-12 10:25:50 -0700621 mod = ofp.message.port_mod()
Dan Talayco92c99122010-06-03 13:53:18 -0700622 mod.port_no = port_no
Rich Lane6dc865c2013-07-10 10:12:13 -0700623 if hw_addr != None:
624 mod.hw_addr = hw_addr
Dan Talayco92c99122010-06-03 13:53:18 -0700625 mod.config = config
626 mod.mask = mask
Rich Lane6dc865c2013-07-10 10:12:13 -0700627 mod.advertise = 0 # No change
Rich Lane5c3151c2013-01-03 17:15:41 -0800628 controller.message_send(mod)
629 return 0
Dan Talayco92c99122010-06-03 13:53:18 -0700630
Rich Lane2014f9b2012-10-05 15:29:40 -0700631def receive_pkt_check(dp, pkt, yes_ports, no_ports, assert_if):
Dan Talayco92c99122010-06-03 13:53:18 -0700632 """
633 Check for proper receive packets across all ports
Ken Chiang1bf01602012-04-04 10:48:23 -0700634 @param dp The dataplane object
Dan Talayco92c99122010-06-03 13:53:18 -0700635 @param pkt Expected packet; may be None if yes_ports is empty
636 @param yes_ports Set or list of ports that should recieve packet
637 @param no_ports Set or list of ports that should not receive packet
638 @param assert_if Object that implements assertXXX
Rich Lanee4b384d2013-09-13 14:33:40 -0700639
640 DEPRECATED in favor in verify_packets
Dan Talayco92c99122010-06-03 13:53:18 -0700641 """
Rich Lane91765672012-12-06 16:33:04 -0800642
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700643 exp_pkt_arg = None
Rich Lanecd97d3d2013-01-07 18:50:06 -0800644 if oftest.config["relax"]:
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700645 exp_pkt_arg = pkt
646
Dan Talayco92c99122010-06-03 13:53:18 -0700647 for ofport in yes_ports:
Rich Lane9a003812012-10-04 17:17:59 -0700648 logging.debug("Checking for pkt on port " + str(ofport))
Ken Chiang1bf01602012-04-04 10:48:23 -0700649 (rcv_port, rcv_pkt, pkt_time) = dp.poll(
Wilson Ngc2c6b4e2015-03-04 17:30:20 -0800650 port_number=ofport, exp_pkt=exp_pkt_arg)
Dan Talayco92c99122010-06-03 13:53:18 -0700651 assert_if.assertTrue(rcv_pkt is not None,
652 "Did not receive pkt on " + str(ofport))
Rich Lanecd97d3d2013-01-07 18:50:06 -0800653 if not oftest.dataplane.match_exp_pkt(pkt, rcv_pkt):
Rich Lane3c266832013-01-29 18:29:15 -0800654 logging.debug("Expected %s" % format_packet(pkt))
655 logging.debug("Received %s" % format_packet(rcv_pkt))
Rich Lanecd97d3d2013-01-07 18:50:06 -0800656 assert_if.assertTrue(oftest.dataplane.match_exp_pkt(pkt, rcv_pkt),
Rich Lane3c266832013-01-29 18:29:15 -0800657 "Received packet does not match expected packet " +
Ken Chiang1bf01602012-04-04 10:48:23 -0700658 "on port " + str(ofport))
Dan Talayco73f84012012-10-02 09:23:18 -0700659 if len(no_ports) > 0:
Rich Lane57dfee72014-03-24 16:59:47 -0700660 time.sleep(oftest.ofutils.default_negative_timeout)
Dan Talayco92c99122010-06-03 13:53:18 -0700661 for ofport in no_ports:
Rich Lane9a003812012-10-04 17:17:59 -0700662 logging.debug("Negative check for pkt on port " + str(ofport))
Ken Chiang1bf01602012-04-04 10:48:23 -0700663 (rcv_port, rcv_pkt, pkt_time) = dp.poll(
Rich Lane91765672012-12-06 16:33:04 -0800664 port_number=ofport, timeout=0, exp_pkt=exp_pkt_arg)
Dan Talayco92c99122010-06-03 13:53:18 -0700665 assert_if.assertTrue(rcv_pkt is None,
666 "Unexpected pkt on port " + str(ofport))
Dan Talayco551befa2010-07-15 17:05:32 -0700667
668
Dan Talaycoc948d0b2012-03-23 12:17:54 -0700669def receive_pkt_verify(parent, egr_ports, exp_pkt, ing_port):
Dan Talayco551befa2010-07-15 17:05:32 -0700670 """
671 Receive a packet and verify it matches an expected value
Dan Talaycof6e76c02012-03-23 10:56:12 -0700672 @param egr_port A single port or list of ports
Dan Talayco551befa2010-07-15 17:05:32 -0700673
674 parent must implement dataplane, assertTrue and assertEqual
Rich Lanee4b384d2013-09-13 14:33:40 -0700675
676 DEPRECATED in favor in verify_packets
Dan Talayco551befa2010-07-15 17:05:32 -0700677 """
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700678 exp_pkt_arg = None
Rich Lanecd97d3d2013-01-07 18:50:06 -0800679 if oftest.config["relax"]:
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700680 exp_pkt_arg = exp_pkt
681
Dan Talaycof6e76c02012-03-23 10:56:12 -0700682 if type(egr_ports) == type([]):
683 egr_port_list = egr_ports
684 else:
685 egr_port_list = [egr_ports]
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700686
Dan Talaycof6e76c02012-03-23 10:56:12 -0700687 # Expect a packet from each port on egr port list
688 for egr_port in egr_port_list:
Dan Talaycod8ae7582012-03-23 12:24:56 -0700689 check_port = egr_port
Rich Lanee717c6e2013-03-12 10:25:50 -0700690 if egr_port == ofp.OFPP_IN_PORT:
Dan Talaycod8ae7582012-03-23 12:24:56 -0700691 check_port = ing_port
Dan Talaycof6e76c02012-03-23 10:56:12 -0700692 (rcv_port, rcv_pkt, pkt_time) = parent.dataplane.poll(
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700693 port_number=check_port, exp_pkt=exp_pkt_arg)
Dan Talayco551befa2010-07-15 17:05:32 -0700694
Dan Talaycof6e76c02012-03-23 10:56:12 -0700695 if rcv_pkt is None:
Rich Lane9a003812012-10-04 17:17:59 -0700696 logging.error("ERROR: No packet received from " +
Dan Talaycod8ae7582012-03-23 12:24:56 -0700697 str(check_port))
Dan Talayco551befa2010-07-15 17:05:32 -0700698
Dan Talaycof6e76c02012-03-23 10:56:12 -0700699 parent.assertTrue(rcv_pkt is not None,
Dan Talaycod8ae7582012-03-23 12:24:56 -0700700 "Did not receive packet port " + str(check_port))
Rich Lane9a003812012-10-04 17:17:59 -0700701 logging.debug("Packet len " + str(len(rcv_pkt)) + " in on " +
Dan Talaycof6e76c02012-03-23 10:56:12 -0700702 str(rcv_port))
703
704 if str(exp_pkt) != str(rcv_pkt):
Rich Lane9a003812012-10-04 17:17:59 -0700705 logging.error("ERROR: Packet match failed.")
706 logging.debug("Expected len " + str(len(exp_pkt)) + ": "
Dan Talaycof6e76c02012-03-23 10:56:12 -0700707 + str(exp_pkt).encode('hex'))
Rich Lane9a003812012-10-04 17:17:59 -0700708 logging.debug("Received len " + str(len(rcv_pkt)) + ": "
Dan Talaycof6e76c02012-03-23 10:56:12 -0700709 + str(rcv_pkt).encode('hex'))
Rich Lane5d7e89a2012-10-26 16:43:13 -0700710 logging.debug("Expected packet: " + inspect_packet(scapy.Ether(str(exp_pkt))))
711 logging.debug("Received packet: " + inspect_packet(scapy.Ether(str(rcv_pkt))))
Dan Talaycof6e76c02012-03-23 10:56:12 -0700712 parent.assertEqual(str(exp_pkt), str(rcv_pkt),
Dan Talaycod8ae7582012-03-23 12:24:56 -0700713 "Packet match error on port " + str(check_port))
Dan Talaycof6e76c02012-03-23 10:56:12 -0700714
Dan Talayco551befa2010-07-15 17:05:32 -0700715def match_verify(parent, req_match, res_match):
716 """
717 Verify flow matches agree; if they disagree, report where
718
719 parent must implement assertEqual
720 Use str() to ensure content is compared and not pointers
721 """
722
723 parent.assertEqual(req_match.wildcards, res_match.wildcards,
724 'Match failed: wildcards: ' + hex(req_match.wildcards) +
725 " != " + hex(res_match.wildcards))
726 parent.assertEqual(req_match.in_port, res_match.in_port,
727 'Match failed: in_port: ' + str(req_match.in_port) +
728 " != " + str(res_match.in_port))
Rich Laned0478ff2013-03-11 12:46:58 -0700729 parent.assertEqual(str(req_match.eth_src), str(res_match.eth_src),
730 'Match failed: eth_src: ' + str(req_match.eth_src) +
731 " != " + str(res_match.eth_src))
732 parent.assertEqual(str(req_match.eth_dst), str(res_match.eth_dst),
733 'Match failed: eth_dst: ' + str(req_match.eth_dst) +
734 " != " + str(res_match.eth_dst))
735 parent.assertEqual(req_match.vlan_vid, res_match.vlan_vid,
736 'Match failed: vlan_vid: ' + str(req_match.vlan_vid) +
737 " != " + str(res_match.vlan_vid))
738 parent.assertEqual(req_match.vlan_pcp, res_match.vlan_pcp,
739 'Match failed: vlan_pcp: ' +
740 str(req_match.vlan_pcp) + " != " +
741 str(res_match.vlan_pcp))
742 parent.assertEqual(req_match.eth_type, res_match.eth_type,
743 'Match failed: eth_type: ' + str(req_match.eth_type) +
744 " != " + str(res_match.eth_type))
Dan Talayco551befa2010-07-15 17:05:32 -0700745
Rich Lanee717c6e2013-03-12 10:25:50 -0700746 if (not(req_match.wildcards & ofp.OFPFW_DL_TYPE)
Rich Laned0478ff2013-03-11 12:46:58 -0700747 and (req_match.eth_type == IP_ETHERTYPE)):
748 parent.assertEqual(req_match.ip_dscp, res_match.ip_dscp,
749 'Match failed: ip_dscp: ' + str(req_match.ip_dscp) +
750 " != " + str(res_match.ip_dscp))
751 parent.assertEqual(req_match.ip_proto, res_match.ip_proto,
752 'Match failed: ip_proto: ' + str(req_match.ip_proto) +
753 " != " + str(res_match.ip_proto))
754 parent.assertEqual(req_match.ipv4_src, res_match.ipv4_src,
755 'Match failed: ipv4_src: ' + str(req_match.ipv4_src) +
756 " != " + str(res_match.ipv4_src))
757 parent.assertEqual(req_match.ipv4_dst, res_match.ipv4_dst,
758 'Match failed: ipv4_dst: ' + str(req_match.ipv4_dst) +
759 " != " + str(res_match.ipv4_dst))
Dan Talayco551befa2010-07-15 17:05:32 -0700760
Rich Lanee717c6e2013-03-12 10:25:50 -0700761 if (not(req_match.wildcards & ofp.OFPFW_NW_PROTO)
Rich Laned0478ff2013-03-11 12:46:58 -0700762 and ((req_match.ip_proto == TCP_PROTOCOL)
763 or (req_match.ip_proto == UDP_PROTOCOL))):
764 parent.assertEqual(req_match.tcp_src, res_match.tcp_src,
765 'Match failed: tcp_src: ' +
766 str(req_match.tcp_src) +
767 " != " + str(res_match.tcp_src))
768 parent.assertEqual(req_match.tcp_dst, res_match.tcp_dst,
769 'Match failed: tcp_dst: ' +
770 str(req_match.tcp_dst) +
771 " != " + str(res_match.tcp_dst))
Dan Talayco551befa2010-07-15 17:05:32 -0700772
Ed Swierk99a74de2012-08-22 06:40:54 -0700773def packet_to_flow_match(parent, packet):
Rich Lanef6883512013-03-11 17:00:09 -0700774 match = oftest.parse.packet_to_flow_match(packet)
Rich Laneab7476f2013-06-13 15:53:52 -0700775 if ofp.OFP_VERSION in [1, 2]:
776 match.wildcards |= required_wildcards(parent)
777 else:
778 # TODO remove incompatible OXM entries
779 pass
Ed Swierk99a74de2012-08-22 06:40:54 -0700780 return match
781
782def flow_msg_create(parent, pkt, ing_port=None, action_list=None, wildcards=None,
Dan Talaycof6e76c02012-03-23 10:56:12 -0700783 egr_ports=None, egr_queue=None, check_expire=False, in_band=False):
Dan Talayco551befa2010-07-15 17:05:32 -0700784 """
785 Create a flow message
786
787 Match on packet with given wildcards.
788 See flow_match_test for other parameter descriptoins
789 @param egr_queue if not None, make the output an enqueue action
Dan Talayco677c0b72011-08-23 22:53:38 -0700790 @param in_band if True, do not wildcard ingress port
Dan Talaycof6e76c02012-03-23 10:56:12 -0700791 @param egr_ports None (drop), single port or list of ports
Dan Talayco551befa2010-07-15 17:05:32 -0700792 """
Rich Lanef6883512013-03-11 17:00:09 -0700793 match = oftest.parse.packet_to_flow_match(pkt)
Dan Talayco551befa2010-07-15 17:05:32 -0700794 parent.assertTrue(match is not None, "Flow match from pkt failed")
Ed Swierk99a74de2012-08-22 06:40:54 -0700795 if wildcards is None:
796 wildcards = required_wildcards(parent)
Dan Talayco677c0b72011-08-23 22:53:38 -0700797 if in_band:
Rich Lanee717c6e2013-03-12 10:25:50 -0700798 wildcards &= ~ofp.OFPFW_IN_PORT
Dan Talayco551befa2010-07-15 17:05:32 -0700799 match.wildcards = wildcards
800 match.in_port = ing_port
801
Dan Talaycof6e76c02012-03-23 10:56:12 -0700802 if type(egr_ports) == type([]):
803 egr_port_list = egr_ports
804 else:
805 egr_port_list = [egr_ports]
806
Rich Lanee717c6e2013-03-12 10:25:50 -0700807 request = ofp.message.flow_add()
Dan Talayco551befa2010-07-15 17:05:32 -0700808 request.match = match
809 request.buffer_id = 0xffffffff
810 if check_expire:
Rich Lanee717c6e2013-03-12 10:25:50 -0700811 request.flags |= ofp.OFPFF_SEND_FLOW_REM
Dan Talayco551befa2010-07-15 17:05:32 -0700812 request.hard_timeout = 1
813
Rich Lane400fb9b2013-10-10 17:20:54 -0700814 if ofp.OFP_VERSION == 1:
815 actions = request.actions
816 else:
817 actions = []
818 request.instructions.append(ofp.instruction.apply_actions(actions))
819
Dan Talayco551befa2010-07-15 17:05:32 -0700820 if action_list is not None:
Rich Lane400fb9b2013-10-10 17:20:54 -0700821 actions.extend(action_list)
Dan Talayco551befa2010-07-15 17:05:32 -0700822
823 # Set up output/enqueue action if directed
824 if egr_queue is not None:
Dan Talaycof6e76c02012-03-23 10:56:12 -0700825 parent.assertTrue(egr_ports is not None, "Egress port not set")
Rich Lanee717c6e2013-03-12 10:25:50 -0700826 act = ofp.action.enqueue()
Dan Talaycof6e76c02012-03-23 10:56:12 -0700827 for egr_port in egr_port_list:
828 act.port = egr_port
829 act.queue_id = egr_queue
Rich Lane400fb9b2013-10-10 17:20:54 -0700830 actions.append(act)
Dan Talaycof6e76c02012-03-23 10:56:12 -0700831 elif egr_ports is not None:
832 for egr_port in egr_port_list:
Rich Lanee717c6e2013-03-12 10:25:50 -0700833 act = ofp.action.output()
Dan Talaycof6e76c02012-03-23 10:56:12 -0700834 act.port = egr_port
Rich Lane400fb9b2013-10-10 17:20:54 -0700835 actions.append(act)
Dan Talayco551befa2010-07-15 17:05:32 -0700836
Rich Lane9a003812012-10-04 17:17:59 -0700837 logging.debug(request.show())
Dan Talayco551befa2010-07-15 17:05:32 -0700838
839 return request
840
Jeffrey Townsendf3eae9c2012-03-28 18:23:21 -0700841def flow_msg_install(parent, request, clear_table_override=None):
Dan Talayco551befa2010-07-15 17:05:32 -0700842 """
843 Install a flow mod message in the switch
844
845 @param parent Must implement controller, assertEqual, assertTrue
846 @param request The request, all set to go
847 @param clear_table If true, clear the flow table before installing
848 """
Dan Talayco8a64e332012-03-28 14:53:20 -0700849
Rich Lane2014f9b2012-10-05 15:29:40 -0700850 clear_table = test_param_get('clear_table', default=True)
Jeffrey Townsendf3eae9c2012-03-28 18:23:21 -0700851 if(clear_table_override != None):
852 clear_table = clear_table_override
853
854 if clear_table:
Rich Lane9a003812012-10-04 17:17:59 -0700855 logging.debug("Clear flow table")
Rich Lane32bf9482013-01-03 17:26:30 -0800856 delete_all_flows(parent.controller)
Dan Talayco551befa2010-07-15 17:05:32 -0700857
Rich Lane9a003812012-10-04 17:17:59 -0700858 logging.debug("Insert flow")
Rich Lane5c3151c2013-01-03 17:15:41 -0800859 parent.controller.message_send(request)
Rich Lanee912d032012-12-22 14:28:33 -0800860
Rich Lane3a261d52013-01-03 17:45:08 -0800861 do_barrier(parent.controller)
Dan Talayco551befa2010-07-15 17:05:32 -0700862
Ed Swierk99a74de2012-08-22 06:40:54 -0700863def flow_match_test_port_pair(parent, ing_port, egr_ports, wildcards=None,
Rich Laned0478ff2013-03-11 12:46:58 -0700864 vlan_vid=-1, pkt=None, exp_pkt=None,
Rich Lanee5779d32012-10-05 17:56:04 -0700865 action_list=None):
Dan Talayco551befa2010-07-15 17:05:32 -0700866 """
867 Flow match test on single TCP packet
Dan Talaycof6e76c02012-03-23 10:56:12 -0700868 @param egr_ports A single port or list of ports
Dan Talayco551befa2010-07-15 17:05:32 -0700869
870 Run test with packet through switch from ing_port to egr_port
871 See flow_match_test for parameter descriptions
872 """
873
Ed Swierk99a74de2012-08-22 06:40:54 -0700874 if wildcards is None:
875 wildcards = required_wildcards(parent)
Rich Lane9a003812012-10-04 17:17:59 -0700876 logging.info("Pkt match test: " + str(ing_port) + " to " +
Dan Talaycof6e76c02012-03-23 10:56:12 -0700877 str(egr_ports))
Rich Laned0478ff2013-03-11 12:46:58 -0700878 logging.debug(" WC: " + hex(wildcards) + " vlan: " + str(vlan_vid))
Dan Talayco551befa2010-07-15 17:05:32 -0700879 if pkt is None:
Rich Laned0478ff2013-03-11 12:46:58 -0700880 pkt = simple_tcp_packet(dl_vlan_enable=(vlan_vid >= 0), vlan_vid=vlan_vid)
Rich Lanec41fbec2013-10-02 00:27:59 -0700881 if exp_pkt is None:
882 exp_pkt = pkt
Dan Talayco551befa2010-07-15 17:05:32 -0700883
884 request = flow_msg_create(parent, pkt, ing_port=ing_port,
Dan Talaycof6e76c02012-03-23 10:56:12 -0700885 wildcards=wildcards, egr_ports=egr_ports,
Dan Talayco551befa2010-07-15 17:05:32 -0700886 action_list=action_list)
887
888 flow_msg_install(parent, request)
889
Rich Lane9a003812012-10-04 17:17:59 -0700890 logging.debug("Send packet: " + str(ing_port) + " to " +
Dan Talaycof6e76c02012-03-23 10:56:12 -0700891 str(egr_ports))
Dan Talayco551befa2010-07-15 17:05:32 -0700892 parent.dataplane.send(ing_port, str(pkt))
893
Rich Lane8f45e2d2013-10-01 16:06:54 -0700894 exp_ports = [ing_port if port == ofp.OFPP_IN_PORT else port for port in egr_ports]
Rich Lanee4b384d2013-09-13 14:33:40 -0700895 verify_packets(parent, exp_pkt, exp_ports)
Dan Talayco551befa2010-07-15 17:05:32 -0700896
Rich Lane89725bb2012-12-03 16:23:27 -0800897def flow_match_test_pktout(parent, ing_port, egr_ports,
Rich Laned0478ff2013-03-11 12:46:58 -0700898 vlan_vid=-1, pkt=None, exp_pkt=None,
Rich Lane89725bb2012-12-03 16:23:27 -0800899 action_list=None):
900 """
901 Packet-out test on single TCP packet
902 @param egr_ports A single port or list of ports
903
904 Run test sending packet-out to egr_ports. The goal is to test the actions
905 taken on the packet, not the matching which is of course irrelevant.
906 See flow_match_test for parameter descriptions
907 """
908
909 if pkt is None:
Rich Laned0478ff2013-03-11 12:46:58 -0700910 pkt = simple_tcp_packet(dl_vlan_enable=(vlan_vid >= 0), vlan_vid=vlan_vid)
Rich Lanec41fbec2013-10-02 00:27:59 -0700911 if exp_pkt is None:
912 exp_pkt = pkt
Rich Lane89725bb2012-12-03 16:23:27 -0800913
Rich Lanee717c6e2013-03-12 10:25:50 -0700914 msg = ofp.message.packet_out()
Rich Lane89725bb2012-12-03 16:23:27 -0800915 msg.in_port = ing_port
Rich Laneea8c4722013-04-04 15:30:20 -0700916 msg.buffer_id = 0xffffffff
Rich Lane89725bb2012-12-03 16:23:27 -0800917 msg.data = str(pkt)
918 if action_list is not None:
919 for act in action_list:
Rich Lanec495d9e2013-03-08 17:43:36 -0800920 msg.actions.append(act)
Rich Lane89725bb2012-12-03 16:23:27 -0800921
922 # Set up output action
923 if egr_ports is not None:
924 for egr_port in egr_ports:
Rich Lanee717c6e2013-03-12 10:25:50 -0700925 act = ofp.action.output()
Rich Lane89725bb2012-12-03 16:23:27 -0800926 act.port = egr_port
Rich Lanec495d9e2013-03-08 17:43:36 -0800927 msg.actions.append(act)
Rich Lane89725bb2012-12-03 16:23:27 -0800928
929 logging.debug(msg.show())
Rich Lane5c3151c2013-01-03 17:15:41 -0800930 parent.controller.message_send(msg)
Rich Lane89725bb2012-12-03 16:23:27 -0800931
Rich Lane8f45e2d2013-10-01 16:06:54 -0700932 exp_ports = [ing_port if port == ofp.OFPP_IN_PORT else port for port in egr_ports]
Rich Lanee4b384d2013-09-13 14:33:40 -0700933 verify_packets(parent, exp_pkt, exp_ports)
Rich Lane89725bb2012-12-03 16:23:27 -0800934
Dan Talaycof6e76c02012-03-23 10:56:12 -0700935def get_egr_list(parent, of_ports, how_many, exclude_list=[]):
936 """
937 Generate a list of ports avoiding those in the exclude list
Rich Lane9a003812012-10-04 17:17:59 -0700938 @param parent Supplies logging
Dan Talaycof6e76c02012-03-23 10:56:12 -0700939 @param of_ports List of OF port numbers
940 @param how_many Number of ports to be added to the list
941 @param exclude_list List of ports not to be used
942 @returns An empty list if unable to find enough ports
943 """
944
Dan Talaycoc948d0b2012-03-23 12:17:54 -0700945 if how_many == 0:
946 return []
947
Dan Talaycof6e76c02012-03-23 10:56:12 -0700948 count = 0
949 egr_ports = []
950 for egr_idx in range(len(of_ports)):
951 if of_ports[egr_idx] not in exclude_list:
952 egr_ports.append(of_ports[egr_idx])
953 count += 1
954 if count >= how_many:
955 return egr_ports
Rich Lane9a003812012-10-04 17:17:59 -0700956 logging.debug("Could not generate enough egress ports for test")
Dan Talaycof6e76c02012-03-23 10:56:12 -0700957 return []
958
Rich Laned0478ff2013-03-11 12:46:58 -0700959def flow_match_test(parent, port_map, wildcards=None, vlan_vid=-1, pkt=None,
Rich Lanee5779d32012-10-05 17:56:04 -0700960 exp_pkt=None, action_list=None,
Dan Talaycoc948d0b2012-03-23 12:17:54 -0700961 max_test=0, egr_count=1, ing_port=False):
Dan Talayco551befa2010-07-15 17:05:32 -0700962 """
Rich Lane89725bb2012-12-03 16:23:27 -0800963 Run flow_match_test_port_pair on all port pairs and packet-out
Dan Talayco551befa2010-07-15 17:05:32 -0700964
965 @param max_test If > 0 no more than this number of tests are executed.
966 @param parent Must implement controller, dataplane, assertTrue, assertEqual
Rich Lane9a003812012-10-04 17:17:59 -0700967 and logging
Dan Talayco551befa2010-07-15 17:05:32 -0700968 @param pkt If not None, use this packet for ingress
969 @param wildcards For flow match entry
Rich Laned0478ff2013-03-11 12:46:58 -0700970 @param vlan_vid If not -1, and pkt is None, create a pkt w/ VLAN tag
Dan Talayco551befa2010-07-15 17:05:32 -0700971 @param exp_pkt If not None, use this as the expected output pkt; els use pkt
972 @param action_list Additional actions to add to flow mod
Dan Talaycocfa172f2012-03-23 12:03:00 -0700973 @param egr_count Number of egress ports; -1 means get from config w/ dflt 2
Dan Talayco551befa2010-07-15 17:05:32 -0700974 """
Ed Swierk99a74de2012-08-22 06:40:54 -0700975 if wildcards is None:
976 wildcards = required_wildcards(parent)
Dan Talayco551befa2010-07-15 17:05:32 -0700977 of_ports = port_map.keys()
978 of_ports.sort()
979 parent.assertTrue(len(of_ports) > 1, "Not enough ports for test")
980 test_count = 0
981
Dan Talaycocfa172f2012-03-23 12:03:00 -0700982 if egr_count == -1:
Rich Lane2014f9b2012-10-05 15:29:40 -0700983 egr_count = test_param_get('egr_count', default=2)
Dan Talaycocfa172f2012-03-23 12:03:00 -0700984
Dan Talayco551befa2010-07-15 17:05:32 -0700985 for ing_idx in range(len(of_ports)):
986 ingress_port = of_ports[ing_idx]
Dan Talaycof6e76c02012-03-23 10:56:12 -0700987 egr_ports = get_egr_list(parent, of_ports, egr_count,
988 exclude_list=[ingress_port])
Dan Talaycoc948d0b2012-03-23 12:17:54 -0700989 if ing_port:
Rich Lanee717c6e2013-03-12 10:25:50 -0700990 egr_ports.append(ofp.OFPP_IN_PORT)
Dan Talaycof6e76c02012-03-23 10:56:12 -0700991 if len(egr_ports) == 0:
992 parent.assertTrue(0, "Failed to generate egress port list")
993
994 flow_match_test_port_pair(parent, ingress_port, egr_ports,
Rich Laned0478ff2013-03-11 12:46:58 -0700995 wildcards=wildcards, vlan_vid=vlan_vid,
Dan Talaycof6e76c02012-03-23 10:56:12 -0700996 pkt=pkt, exp_pkt=exp_pkt,
Rich Lanee5779d32012-10-05 17:56:04 -0700997 action_list=action_list)
Dan Talaycof6e76c02012-03-23 10:56:12 -0700998 test_count += 1
999 if (max_test > 0) and (test_count > max_test):
Rich Lane9a003812012-10-04 17:17:59 -07001000 logging.info("Ran " + str(test_count) + " tests; exiting")
Rich Lane89725bb2012-12-03 16:23:27 -08001001 break
1002
Ed Swierk38eea082013-01-02 19:46:20 -08001003 if not test_param_get('pktout_actions', default=True):
1004 return
Rich Lane89725bb2012-12-03 16:23:27 -08001005
1006 ingress_port = of_ports[0]
1007 egr_ports = get_egr_list(parent, of_ports, egr_count,
1008 exclude_list=[ingress_port])
1009 if ing_port:
Rich Lanee717c6e2013-03-12 10:25:50 -07001010 egr_ports.append(ofp.OFPP_IN_PORT)
Rich Lane89725bb2012-12-03 16:23:27 -08001011 flow_match_test_pktout(parent, ingress_port, egr_ports,
Rich Laned0478ff2013-03-11 12:46:58 -07001012 vlan_vid=vlan_vid,
Rich Lane89725bb2012-12-03 16:23:27 -08001013 pkt=pkt, exp_pkt=exp_pkt,
1014 action_list=action_list)
Dan Talayco551befa2010-07-15 17:05:32 -07001015
Rich Lane2014f9b2012-10-05 15:29:40 -07001016def test_param_get(key, default=None):
Dan Talayco4b2bee62010-07-20 14:10:05 -07001017 """
1018 Return value passed via test-params if present
1019
Dan Talayco4b2bee62010-07-20 14:10:05 -07001020 @param key The lookup key
1021 @param default Default value to use if not found
1022
1023 If the pair 'key=val' appeared in the string passed to --test-params
1024 on the command line, return val (as interpreted by exec). Otherwise
1025 return default value.
Dan Talaycof6e76c02012-03-23 10:56:12 -07001026
1027 WARNING: TEST PARAMETERS MUST BE PYTHON IDENTIFIERS;
1028 eg egr_count, not egr-count.
Dan Talayco4b2bee62010-07-20 14:10:05 -07001029 """
1030 try:
Rich Lanecd97d3d2013-01-07 18:50:06 -08001031 exec oftest.config["test_params"]
Dan Talayco4b2bee62010-07-20 14:10:05 -07001032 except:
1033 return default
1034
Dan Talayco4b2bee62010-07-20 14:10:05 -07001035 try:
Rich Lanefdec0fb2013-08-09 18:01:05 -07001036 return eval(str(key))
Dan Talayco4b2bee62010-07-20 14:10:05 -07001037 except:
1038 return default
1039
1040def action_generate(parent, field_to_mod, mod_field_vals):
1041 """
1042 Create an action to modify the field indicated in field_to_mod
1043
1044 @param parent Must implement, assertTrue
1045 @param field_to_mod The field to modify as a string name
1046 @param mod_field_vals Hash of values to use for modified values
1047 """
1048
1049 act = None
1050
1051 if field_to_mod in ['pktlen']:
1052 return None
1053
Rich Laned0478ff2013-03-11 12:46:58 -07001054 if field_to_mod == 'eth_dst':
Rich Lanee717c6e2013-03-12 10:25:50 -07001055 act = ofp.action.set_dl_dst()
Rich Lanef6883512013-03-11 17:00:09 -07001056 act.dl_addr = oftest.parse.parse_mac(mod_field_vals['eth_dst'])
Rich Laned0478ff2013-03-11 12:46:58 -07001057 elif field_to_mod == 'eth_src':
Rich Lanee717c6e2013-03-12 10:25:50 -07001058 act = ofp.action.set_dl_src()
Rich Lanef6883512013-03-11 17:00:09 -07001059 act.dl_addr = oftest.parse.parse_mac(mod_field_vals['eth_src'])
Dan Talayco4b2bee62010-07-20 14:10:05 -07001060 elif field_to_mod == 'dl_vlan_enable':
1061 if not mod_field_vals['dl_vlan_enable']: # Strip VLAN tag
Rich Lanee717c6e2013-03-12 10:25:50 -07001062 act = ofp.action.strip_vlan()
Rich Laned0478ff2013-03-11 12:46:58 -07001063 # Add VLAN tag is handled by vlan_vid field
Dan Talayco4b2bee62010-07-20 14:10:05 -07001064 # Will return None in this case
Rich Laned0478ff2013-03-11 12:46:58 -07001065 elif field_to_mod == 'vlan_vid':
Rich Lanee717c6e2013-03-12 10:25:50 -07001066 act = ofp.action.set_vlan_vid()
Rich Laned0478ff2013-03-11 12:46:58 -07001067 act.vlan_vid = mod_field_vals['vlan_vid']
1068 elif field_to_mod == 'vlan_pcp':
Rich Lanee717c6e2013-03-12 10:25:50 -07001069 act = ofp.action.set_vlan_pcp()
Rich Laned0478ff2013-03-11 12:46:58 -07001070 act.vlan_pcp = mod_field_vals['vlan_pcp']
Dan Talayco4b2bee62010-07-20 14:10:05 -07001071 elif field_to_mod == 'ip_src':
Rich Lanee717c6e2013-03-12 10:25:50 -07001072 act = ofp.action.set_nw_src()
Rich Lanef6883512013-03-11 17:00:09 -07001073 act.nw_addr = oftest.parse.parse_ip(mod_field_vals['ip_src'])
Dan Talayco4b2bee62010-07-20 14:10:05 -07001074 elif field_to_mod == 'ip_dst':
Rich Lanee717c6e2013-03-12 10:25:50 -07001075 act = ofp.action.set_nw_dst()
Rich Lanef6883512013-03-11 17:00:09 -07001076 act.nw_addr = oftest.parse.parse_ip(mod_field_vals['ip_dst'])
Dan Talayco4b2bee62010-07-20 14:10:05 -07001077 elif field_to_mod == 'ip_tos':
Rich Lanee717c6e2013-03-12 10:25:50 -07001078 act = ofp.action.set_nw_tos()
Dan Talayco4b2bee62010-07-20 14:10:05 -07001079 act.nw_tos = mod_field_vals['ip_tos']
1080 elif field_to_mod == 'tcp_sport':
Rich Lanee717c6e2013-03-12 10:25:50 -07001081 act = ofp.action.set_tp_src()
Dan Talayco4b2bee62010-07-20 14:10:05 -07001082 act.tp_port = mod_field_vals['tcp_sport']
1083 elif field_to_mod == 'tcp_dport':
Rich Lanee717c6e2013-03-12 10:25:50 -07001084 act = ofp.action.set_tp_dst()
Dan Talayco4b2bee62010-07-20 14:10:05 -07001085 act.tp_port = mod_field_vals['tcp_dport']
Rich Lane110e0e32012-10-26 16:21:46 -07001086 elif field_to_mod == 'udp_sport':
Rich Lanee717c6e2013-03-12 10:25:50 -07001087 act = ofp.action.set_tp_src()
Rich Lane110e0e32012-10-26 16:21:46 -07001088 act.tp_port = mod_field_vals['udp_sport']
1089 elif field_to_mod == 'udp_dport':
Rich Lanee717c6e2013-03-12 10:25:50 -07001090 act = ofp.action.set_tp_dst()
Rich Lane110e0e32012-10-26 16:21:46 -07001091 act.tp_port = mod_field_vals['udp_dport']
Dan Talayco4b2bee62010-07-20 14:10:05 -07001092 else:
1093 parent.assertTrue(0, "Unknown field to modify: " + str(field_to_mod))
1094
1095 return act
1096
1097def pkt_action_setup(parent, start_field_vals={}, mod_field_vals={},
Rich Lane110e0e32012-10-26 16:21:46 -07001098 mod_fields=[], tp="tcp", check_test_params=False):
Dan Talayco4b2bee62010-07-20 14:10:05 -07001099 """
1100 Set up the ingress and expected packet and action list for a test
1101
Rich Lane2014f9b2012-10-05 15:29:40 -07001102 @param parent Must implement assertTrue
Dan Talayco4b2bee62010-07-20 14:10:05 -07001103 @param start_field_values Field values to use for ingress packet (optional)
1104 @param mod_field_values Field values to use for modified packet (optional)
1105 @param mod_fields The list of fields to be modified by the switch in the test.
1106 @params check_test_params If True, will check the parameters vid, add_vlan
1107 and strip_vlan from the command line.
1108
1109 Returns a triple: pkt-to-send, expected-pkt, action-list
1110 """
1111
1112 new_actions = []
1113
Dan Talayco4b2bee62010-07-20 14:10:05 -07001114 base_pkt_params = {}
1115 base_pkt_params['pktlen'] = 100
Rich Laned0478ff2013-03-11 12:46:58 -07001116 base_pkt_params['eth_dst'] = '00:DE:F0:12:34:56'
1117 base_pkt_params['eth_src'] = '00:23:45:67:89:AB'
Dan Talayco4b2bee62010-07-20 14:10:05 -07001118 base_pkt_params['dl_vlan_enable'] = False
Rich Laned0478ff2013-03-11 12:46:58 -07001119 base_pkt_params['vlan_vid'] = 2
1120 base_pkt_params['vlan_pcp'] = 0
Dan Talayco4b2bee62010-07-20 14:10:05 -07001121 base_pkt_params['ip_src'] = '192.168.0.1'
1122 base_pkt_params['ip_dst'] = '192.168.0.2'
1123 base_pkt_params['ip_tos'] = 0
Rich Lane110e0e32012-10-26 16:21:46 -07001124 if tp == "tcp":
1125 base_pkt_params['tcp_sport'] = 1234
1126 base_pkt_params['tcp_dport'] = 80
1127 elif tp == "udp":
1128 base_pkt_params['udp_sport'] = 1234
1129 base_pkt_params['udp_dport'] = 80
Dan Talayco4b2bee62010-07-20 14:10:05 -07001130 for keyname in start_field_vals.keys():
1131 base_pkt_params[keyname] = start_field_vals[keyname]
1132
1133 mod_pkt_params = {}
1134 mod_pkt_params['pktlen'] = 100
Rich Laned0478ff2013-03-11 12:46:58 -07001135 mod_pkt_params['eth_dst'] = '00:21:0F:ED:CB:A9'
1136 mod_pkt_params['eth_src'] = '00:ED:CB:A9:87:65'
Dan Talayco4b2bee62010-07-20 14:10:05 -07001137 mod_pkt_params['dl_vlan_enable'] = False
Rich Laned0478ff2013-03-11 12:46:58 -07001138 mod_pkt_params['vlan_vid'] = 3
1139 mod_pkt_params['vlan_pcp'] = 7
Dan Talayco4b2bee62010-07-20 14:10:05 -07001140 mod_pkt_params['ip_src'] = '10.20.30.40'
1141 mod_pkt_params['ip_dst'] = '50.60.70.80'
1142 mod_pkt_params['ip_tos'] = 0xf0
Rich Lane110e0e32012-10-26 16:21:46 -07001143 if tp == "tcp":
1144 mod_pkt_params['tcp_sport'] = 4321
1145 mod_pkt_params['tcp_dport'] = 8765
1146 elif tp == "udp":
1147 mod_pkt_params['udp_sport'] = 4321
1148 mod_pkt_params['udp_dport'] = 8765
Dan Talayco4b2bee62010-07-20 14:10:05 -07001149 for keyname in mod_field_vals.keys():
1150 mod_pkt_params[keyname] = mod_field_vals[keyname]
1151
1152 # Check for test param modifications
1153 strip = False
1154 if check_test_params:
Rich Lane2014f9b2012-10-05 15:29:40 -07001155 add_vlan = test_param_get('add_vlan')
1156 strip_vlan = test_param_get('strip_vlan')
1157 vid = test_param_get('vid')
Dan Talayco4b2bee62010-07-20 14:10:05 -07001158
1159 if add_vlan and strip_vlan:
1160 parent.assertTrue(0, "Add and strip VLAN both specified")
1161
1162 if vid:
1163 base_pkt_params['dl_vlan_enable'] = True
Rich Laned0478ff2013-03-11 12:46:58 -07001164 base_pkt_params['vlan_vid'] = vid
1165 if 'vlan_vid' in mod_fields:
1166 mod_pkt_params['vlan_vid'] = vid + 1
Dan Talayco4b2bee62010-07-20 14:10:05 -07001167
1168 if add_vlan:
1169 base_pkt_params['dl_vlan_enable'] = False
1170 mod_pkt_params['dl_vlan_enable'] = True
1171 mod_pkt_params['pktlen'] = base_pkt_params['pktlen'] + 4
1172 mod_fields.append('pktlen')
1173 mod_fields.append('dl_vlan_enable')
Rich Laned0478ff2013-03-11 12:46:58 -07001174 if 'vlan_vid' not in mod_fields:
1175 mod_fields.append('vlan_vid')
Dan Talayco4b2bee62010-07-20 14:10:05 -07001176 elif strip_vlan:
1177 base_pkt_params['dl_vlan_enable'] = True
1178 mod_pkt_params['dl_vlan_enable'] = False
1179 mod_pkt_params['pktlen'] = base_pkt_params['pktlen'] - 4
1180 mod_fields.append('dl_vlan_enable')
1181 mod_fields.append('pktlen')
1182
Rich Lane110e0e32012-10-26 16:21:46 -07001183 if tp == "tcp":
1184 packet_builder = simple_tcp_packet
1185 elif tp == "udp":
1186 packet_builder = simple_udp_packet
1187 else:
1188 raise NotImplementedError("unknown transport protocol %s" % tp)
1189
Dan Talayco4b2bee62010-07-20 14:10:05 -07001190 # Build the ingress packet
Rich Lane110e0e32012-10-26 16:21:46 -07001191 ingress_pkt = packet_builder(**base_pkt_params)
Dan Talayco4b2bee62010-07-20 14:10:05 -07001192
1193 # Build the expected packet, modifying the indicated fields
1194 for item in mod_fields:
1195 base_pkt_params[item] = mod_pkt_params[item]
1196 act = action_generate(parent, item, mod_pkt_params)
1197 if act:
1198 new_actions.append(act)
1199
Rich Lane110e0e32012-10-26 16:21:46 -07001200 expected_pkt = packet_builder(**base_pkt_params)
Dan Talayco4b2bee62010-07-20 14:10:05 -07001201
1202 return (ingress_pkt, expected_pkt, new_actions)
Dan Talayco677c0b72011-08-23 22:53:38 -07001203
1204# Generate a simple "drop" flow mod
1205# If in_band is true, then only drop from first test port
1206def flow_mod_gen(port_map, in_band):
Rich Lanee717c6e2013-03-12 10:25:50 -07001207 request = ofp.message.flow_add()
1208 request.match.wildcards = ofp.OFPFW_ALL
Dan Talayco677c0b72011-08-23 22:53:38 -07001209 if in_band:
Rich Lanee717c6e2013-03-12 10:25:50 -07001210 request.match.wildcards = ofp.OFPFW_ALL - ofp.OFPFW_IN_PORT
Dan Talayco677c0b72011-08-23 22:53:38 -07001211 for of_port, ifname in port_map.items(): # Grab first port
1212 break
1213 request.match.in_port = of_port
1214 request.buffer_id = 0xffffffff
1215 return request
Dan Talaycoba3745c2010-07-21 21:51:08 -07001216
1217def skip_message_emit(parent, s):
1218 """
1219 Print out a 'skipped' message to stderr
1220
1221 @param s The string to print out to the log file
Dan Talaycoba3745c2010-07-21 21:51:08 -07001222 """
1223 global skipped_test_count
1224
1225 skipped_test_count += 1
Rich Lane9a003812012-10-04 17:17:59 -07001226 logging.info("Skipping: " + s)
Dan Talayco2940fdd2013-02-06 15:01:35 -08001227 if oftest.config["debug"] < logging.WARNING:
Dan Talaycoba3745c2010-07-21 21:51:08 -07001228 sys.stderr.write("(skipped) ")
1229 else:
1230 sys.stderr.write("(S)")
Dan Talayco677c0b72011-08-23 22:53:38 -07001231
Dan Talayco8a64e332012-03-28 14:53:20 -07001232
1233def all_stats_get(parent):
1234 """
1235 Get the aggregate stats for all flows in the table
1236 @param parent Test instance with controller connection and assert
1237 @returns dict with keys flows, packets, bytes, active (flows),
1238 lookups, matched
1239 """
Rich Lanee717c6e2013-03-12 10:25:50 -07001240 stat_req = ofp.message.aggregate_stats_request()
1241 stat_req.match = ofp.match()
1242 stat_req.match.wildcards = ofp.OFPFW_ALL
Dan Talayco8a64e332012-03-28 14:53:20 -07001243 stat_req.table_id = 0xff
Rich Lanee717c6e2013-03-12 10:25:50 -07001244 stat_req.out_port = ofp.OFPP_NONE
Dan Talayco8a64e332012-03-28 14:53:20 -07001245
1246 rv = {}
1247
Rich Lanec8aaa3e2012-07-26 19:28:02 -07001248 (reply, pkt) = parent.controller.transact(stat_req)
Rich Lane5fd6faf2013-03-11 13:30:20 -07001249 parent.assertTrue(len(reply.entries) == 1, "Did not receive flow stats reply")
Dan Talayco8a64e332012-03-28 14:53:20 -07001250
Rich Lane5fd6faf2013-03-11 13:30:20 -07001251 for obj in reply.entries:
Dan Talayco8a64e332012-03-28 14:53:20 -07001252 (rv["flows"], rv["packets"], rv["bytes"]) = (obj.flow_count,
1253 obj.packet_count, obj.byte_count)
1254 break
1255
Rich Lanee717c6e2013-03-12 10:25:50 -07001256 request = ofp.message.table_stats_request()
Rich Lanec8aaa3e2012-07-26 19:28:02 -07001257 (reply , pkt) = parent.controller.transact(request)
Dan Talayco8a64e332012-03-28 14:53:20 -07001258
1259
1260 (rv["active"], rv["lookups"], rv["matched"]) = (0,0,0)
Rich Lane5fd6faf2013-03-11 13:30:20 -07001261 for obj in reply.entries:
Dan Talayco8a64e332012-03-28 14:53:20 -07001262 rv["active"] += obj.active_count
1263 rv["lookups"] += obj.lookup_count
1264 rv["matched"] += obj.matched_count
1265
1266 return rv
Dan Talayco2baf8b52012-03-30 09:55:42 -07001267
Rich Lane7744e112013-01-11 17:23:57 -08001268_import_blacklist.add('FILTER')
Dan Talayco2baf8b52012-03-30 09:55:42 -07001269FILTER=''.join([(len(repr(chr(x)))==3) and chr(x) or '.'
1270 for x in range(256)])
1271
1272def hex_dump_buffer(src, length=16):
1273 """
1274 Convert src to a hex dump string and return the string
1275 @param src The source buffer
1276 @param length The number of bytes shown in each line
1277 @returns A string showing the hex dump
1278 """
Dan Talaycoc516fa02012-04-12 22:28:43 -07001279 result = ["\n"]
Dan Talayco2baf8b52012-03-30 09:55:42 -07001280 for i in xrange(0, len(src), length):
1281 chars = src[i:i+length]
1282 hex = ' '.join(["%02x" % ord(x) for x in chars])
1283 printable = ''.join(["%s" % ((ord(x) <= 127 and
1284 FILTER[ord(x)]) or '.') for x in chars])
1285 result.append("%04x %-*s %s\n" % (i, length*3, hex, printable))
1286 return ''.join(result)
1287
1288def format_packet(pkt):
1289 return "Packet length %d \n%s" % (len(str(pkt)),
1290 hex_dump_buffer(str(pkt)))
Rich Lane5d7e89a2012-10-26 16:43:13 -07001291
1292def inspect_packet(pkt):
1293 """
1294 Wrapper around scapy's show() method.
1295 @returns A string showing the dissected packet.
1296 """
1297 from cStringIO import StringIO
1298 out = None
1299 backup = sys.stdout
1300 try:
Rich Lanefdec0fb2013-08-09 18:01:05 -07001301 tmp = StringIO()
1302 sys.stdout = tmp
Rich Lane5d7e89a2012-10-26 16:43:13 -07001303 pkt.show2()
Rich Lanefdec0fb2013-08-09 18:01:05 -07001304 out = tmp.getvalue()
1305 tmp.close()
Rich Lane5d7e89a2012-10-26 16:43:13 -07001306 finally:
1307 sys.stdout = backup
1308 return out
Rich Lane0a4f6372013-01-02 14:40:22 -08001309
1310def nonstandard(cls):
1311 """
Rich Lanecc45b8e2013-01-02 15:55:02 -08001312 Testcase decorator that marks the test as being non-standard.
1313 These tests are not automatically added to the "standard" group.
Rich Lane0a4f6372013-01-02 14:40:22 -08001314 """
Rich Lanecc45b8e2013-01-02 15:55:02 -08001315 cls._nonstandard = True
Rich Lane0a4f6372013-01-02 14:40:22 -08001316 return cls
1317
1318def disabled(cls):
1319 """
Rich Lanecc45b8e2013-01-02 15:55:02 -08001320 Testcase decorator that marks the test as being disabled.
1321 These tests are not automatically added to the "standard" group or
1322 their module's group.
Rich Lane0a4f6372013-01-02 14:40:22 -08001323 """
Rich Lanecc45b8e2013-01-02 15:55:02 -08001324 cls._disabled = True
Rich Lane0a4f6372013-01-02 14:40:22 -08001325 return cls
Rich Lane97e99652013-01-02 17:23:20 -08001326
1327def group(name):
1328 """
1329 Testcase decorator that adds the test to a group.
1330 """
1331 def fn(cls):
1332 if not hasattr(cls, "_groups"):
1333 cls._groups = []
1334 cls._groups.append(name)
1335 return cls
1336 return fn
Rich Lane5a9a1922013-01-11 14:29:30 -08001337
1338def version(ver):
1339 """
1340 Testcase decorator that specifies which versions of OpenFlow the test
1341 supports. The default is 1.0+. This decorator may only be used once.
1342
1343 Supported syntax:
1344 1.0 -> 1.0
1345 1.0,1.2,1.3 -> 1.0, 1.2, 1.3
1346 1.0+ -> 1.0, 1.1, 1.2, 1.3
1347 """
1348 versions = parse_version(ver)
1349 def fn(cls):
1350 cls._versions = versions
1351 return cls
1352 return fn
1353
1354def parse_version(ver):
1355 allowed_versions = ["1.0", "1.1", "1.2", "1.3"]
1356 if re.match("^1\.\d+$", ver):
1357 versions = set([ver])
1358 elif re.match("^(1\.\d+)\+$", ver):
1359 if not ver[:-1] in allowed_versions:
1360 raise ValueError("invalid OpenFlow version %s" % ver[:-1])
1361 versions = set()
1362 if ver != "1.1+": versions.add("1.0")
1363 if ver != "1.2+": versions.add("1.1")
1364 if ver != "1.3+": versions.add("1.2")
1365 versions.add("1.3")
1366 else:
1367 versions = set(ver.split(','))
1368
1369 for version in versions:
1370 if not version in allowed_versions:
1371 raise ValueError("invalid OpenFlow version %s" % version)
1372
1373 return versions
1374
1375assert(parse_version("1.0") == set(["1.0"]))
1376assert(parse_version("1.0,1.2,1.3") == set(["1.0", "1.2", "1.3"]))
1377assert(parse_version("1.0+") == set(["1.0", "1.1", "1.2", "1.3"]))
Rich Lane7744e112013-01-11 17:23:57 -08001378
Rich Laneae3428c2013-03-07 14:37:42 -08001379def get_stats(test, req):
1380 """
1381 Retrieve a list of stats entries. Handles OFPSF_REPLY_MORE.
1382 """
Rich Lane609194f2013-10-21 06:17:37 -07001383 msgtype = ofp.OFPT_STATS_REPLY
1384 more_flag = ofp.OFPSF_REPLY_MORE
Rich Laneae3428c2013-03-07 14:37:42 -08001385 stats = []
1386 reply, _ = test.controller.transact(req)
1387 test.assertTrue(reply is not None, "No response to stats request")
Rich Lane34c68d52013-10-11 10:38:21 -07001388 test.assertEquals(reply.type, msgtype, "Response had unexpected message type")
Rich Lane5fd6faf2013-03-11 13:30:20 -07001389 stats.extend(reply.entries)
Rich Lanebd56ed62013-07-10 15:49:44 -07001390 while reply.flags & more_flag != 0:
Rich Lane34c68d52013-10-11 10:38:21 -07001391 reply, pkt = test.controller.poll(exp_msg=msgtype)
Rich Laneae3428c2013-03-07 14:37:42 -08001392 test.assertTrue(reply is not None, "No response to stats request")
Rich Lane5fd6faf2013-03-11 13:30:20 -07001393 stats.extend(reply.entries)
Rich Laneae3428c2013-03-07 14:37:42 -08001394 return stats
1395
Rich Lanebd56ed62013-07-10 15:49:44 -07001396def get_flow_stats(test, match, table_id=None,
1397 out_port=None, out_group=None,
1398 cookie=0, cookie_mask=0):
Rich Laneae3428c2013-03-07 14:37:42 -08001399 """
1400 Retrieve a list of flow stats entries.
1401 """
Rich Lanebd56ed62013-07-10 15:49:44 -07001402
1403 if table_id == None:
1404 if ofp.OFP_VERSION <= 2:
1405 table_id = 0xff
1406 else:
1407 table_id = ofp.OFPTT_ALL
1408
Rich Lanef3bc48c2013-05-03 17:39:35 -07001409 if out_port == None:
Rich Lanebd56ed62013-07-10 15:49:44 -07001410 if ofp.OFP_VERSION == 1:
1411 out_port = ofp.OFPP_NONE
1412 else:
1413 out_port = ofp.OFPP_ANY
1414
1415 if out_group == None:
1416 if ofp.OFP_VERSION > 1:
1417 out_group = ofp.OFPP_ANY
1418
Rich Lanee717c6e2013-03-12 10:25:50 -07001419 req = ofp.message.flow_stats_request(match=match,
Rich Lanebd56ed62013-07-10 15:49:44 -07001420 table_id=table_id,
1421 out_port=out_port)
1422 if ofp.OFP_VERSION > 1:
1423 req.out_group = out_group
1424 req.cookie = cookie
1425 req.cookie_mask = cookie_mask
1426
Rich Laneae3428c2013-03-07 14:37:42 -08001427 return get_stats(test, req)
1428
Rich Lane968b6192013-03-07 15:34:43 -08001429def get_port_stats(test, port_no):
1430 """
1431 Retrieve a list of port stats entries.
1432 """
Rich Lanee717c6e2013-03-12 10:25:50 -07001433 req = ofp.message.port_stats_request(port_no=port_no)
Rich Lane968b6192013-03-07 15:34:43 -08001434 return get_stats(test, req)
1435
Rich Lane6a334922013-03-07 16:14:52 -08001436def get_queue_stats(test, port_no, queue_id):
1437 """
1438 Retrieve a list of queue stats entries.
1439 """
Rich Lanee717c6e2013-03-12 10:25:50 -07001440 req = ofp.message.queue_stats_request(port_no=port_no, queue_id=queue_id)
Rich Lane6a334922013-03-07 16:14:52 -08001441 return get_stats(test, req)
1442
Rich Laneae3428c2013-03-07 14:37:42 -08001443def verify_flow_stats(test, match, table_id=0xff,
Rich Laneae3428c2013-03-07 14:37:42 -08001444 initial=[],
1445 pkts=None, bytes=None):
1446 """
1447 Verify that flow stats changed as expected.
1448
1449 Optionally takes an 'initial' list of stats entries, as returned by
1450 get_flow_stats(). If 'initial' is not given the counters are assumed to
1451 begin at 0.
1452 """
Rich Lanef3bc48c2013-05-03 17:39:35 -07001453
Rich Laneae3428c2013-03-07 14:37:42 -08001454 def accumulate(stats):
1455 pkts_acc = bytes_acc = 0
1456 for stat in stats:
1457 pkts_acc += stat.packet_count
1458 bytes_acc += stat.byte_count
1459 return (pkts_acc, bytes_acc)
1460
1461 pkts_before, bytes_before = accumulate(initial)
1462
1463 # Wait 10s for counters to update
1464 pkt_diff = byte_diff = None
1465 for i in range(0, 100):
Rich Lane61edad52014-03-28 16:25:08 -07001466 stats = get_flow_stats(test, match, table_id=table_id)
Rich Laneae3428c2013-03-07 14:37:42 -08001467 pkts_after, bytes_after = accumulate(stats)
1468 pkt_diff = pkts_after - pkts_before
1469 byte_diff = bytes_after - bytes_before
1470 if (pkts == None or pkt_diff >= pkts) and \
1471 (bytes == None or byte_diff >= bytes):
1472 break
Dan Talayco53724732013-03-08 23:54:02 -08001473 time.sleep(0.1)
Rich Laneae3428c2013-03-07 14:37:42 -08001474
1475 if pkts != None:
1476 test.assertEquals(pkt_diff, pkts, "Flow packet counter not updated properly (expected increase of %d, got increase of %d)" % (pkts, pkt_diff))
1477
1478 if bytes != None:
Rich Lane53b96812013-03-07 16:54:50 -08001479 test.assertTrue(byte_diff >= bytes and byte_diff <= bytes*1.1,
1480 "Flow byte counter not updated properly (expected increase of %d, got increase of %d)" % (bytes, byte_diff))
Rich Laneae3428c2013-03-07 14:37:42 -08001481
Rich Lane968b6192013-03-07 15:34:43 -08001482def verify_port_stats(test, port,
1483 initial=[],
1484 tx_pkts=None, rx_pkts=None,
1485 tx_bytes=None, rx_bytes=None):
1486 """
1487 Verify that port stats changed as expected.
1488
1489 Optionally takes an 'initial' list of stats entries, as returned by
1490 get_port_stats(). If 'initial' is not given the counters are assumed to
1491 begin at 0.
1492 """
1493 def accumulate(stats):
1494 tx_pkts_acc = rx_pkts_acc = tx_bytes_acc = rx_bytes_acc = 0
1495 for stat in stats:
1496 tx_pkts_acc += stat.tx_packets
1497 rx_pkts_acc += stat.rx_packets
1498 tx_bytes_acc += stat.tx_bytes
1499 rx_bytes_acc += stat.rx_bytes
1500 return (tx_pkts_acc, rx_pkts_acc, tx_bytes_acc, rx_bytes_acc)
1501
1502 tx_pkts_before, rx_pkts_before, \
1503 tx_bytes_before, rx_bytes_before = accumulate(initial)
1504
1505 # Wait 10s for counters to update
1506 for i in range(0, 100):
1507 stats = get_port_stats(test, port)
1508 tx_pkts_after, rx_pkts_after, \
1509 tx_bytes_after, rx_bytes_after = accumulate(stats)
1510 tx_pkts_diff = tx_pkts_after - tx_pkts_before
1511 rx_pkts_diff = rx_pkts_after - rx_pkts_before
1512 tx_bytes_diff = tx_bytes_after - tx_bytes_before
1513 rx_bytes_diff = rx_bytes_after - rx_bytes_before
Rich Lane3a208f82015-04-10 12:37:57 -07001514 if (tx_pkts == None or tx_pkts <= tx_pkts_diff) and \
1515 (rx_pkts == None or rx_pkts <= rx_pkts_diff) and \
Rich Lane53b96812013-03-07 16:54:50 -08001516 (tx_bytes == None or tx_bytes <= tx_bytes_diff) and \
1517 (rx_bytes == None or rx_bytes <= rx_bytes_diff):
Rich Lane968b6192013-03-07 15:34:43 -08001518 break
1519 time.sleep(0.1)
1520
1521 if (tx_pkts != None):
Rich Lane3a208f82015-04-10 12:37:57 -07001522 test.assertGreaterEqual(tx_pkts_diff, tx_pkts,
1523 "Port TX packet counter is not updated correctly (expected increase of %d, got increase of %d)" % (tx_pkts, tx_pkts_diff))
Rich Lane968b6192013-03-07 15:34:43 -08001524 if (rx_pkts != None):
Rich Lane3a208f82015-04-10 12:37:57 -07001525 test.assertGreaterEqual(rx_pkts_diff, rx_pkts,
1526 "Port RX packet counter is not updated correctly (expected increase of %d, got increase of %d)" % (rx_pkts, rx_pkts_diff))
Rich Lane968b6192013-03-07 15:34:43 -08001527 if (tx_bytes != None):
Rich Lane3a208f82015-04-10 12:37:57 -07001528 test.assertGreaterEqual(tx_bytes_diff, tx_bytes,
1529 "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 -08001530 if (rx_bytes != None):
Rich Lane3a208f82015-04-10 12:37:57 -07001531 test.assertGreaterEqual(rx_bytes_diff, rx_bytes,
1532 "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 -08001533
Rich Lane6a334922013-03-07 16:14:52 -08001534def verify_queue_stats(test, port_no, queue_id,
1535 initial=[],
1536 pkts=None, bytes=None):
1537 """
1538 Verify that queue stats changed as expected.
1539
1540 Optionally takes an 'initial' list of stats entries, as returned by
1541 get_queue_stats(). If 'initial' is not given the counters are assumed to
1542 begin at 0.
1543 """
1544 def accumulate(stats):
1545 pkts_acc = bytes_acc = 0
1546 for stat in stats:
1547 pkts_acc += stat.tx_packets
1548 bytes_acc += stat.tx_bytes
1549 return (pkts_acc, bytes_acc)
1550
1551 pkts_before, bytes_before = accumulate(initial)
1552
1553 # Wait 10s for counters to update
1554 pkt_diff = byte_diff = None
1555 for i in range(0, 100):
1556 stats = get_queue_stats(test, port_no, queue_id)
1557 pkts_after, bytes_after = accumulate(stats)
1558 pkt_diff = pkts_after - pkts_before
1559 byte_diff = bytes_after - bytes_before
1560 if (pkts == None or pkt_diff >= pkts) and \
1561 (bytes == None or byte_diff >= bytes):
1562 break
Dan Talayco53724732013-03-08 23:54:02 -08001563 time.sleep(0.1)
Rich Lane6a334922013-03-07 16:14:52 -08001564
1565 if pkts != None:
1566 test.assertEquals(pkt_diff, pkts, "Queue packet counter not updated properly (expected increase of %d, got increase of %d)" % (pkts, pkt_diff))
1567
1568 if bytes != None:
Rich Lane53b96812013-03-07 16:54:50 -08001569 test.assertTrue(byte_diff >= bytes and byte_diff <= bytes*1.1,
1570 "Queue byte counter not updated properly (expected increase of %d, got increase of %d)" % (bytes, byte_diff))
Rich Laneae3428c2013-03-07 14:37:42 -08001571
Rich Lane4c504f32013-06-07 17:24:14 -07001572def packet_in_match(msg, data, in_port=None, reason=None):
1573 """
1574 Check whether the packet_in message 'msg' has fields matching 'data',
1575 'in_port', and 'reason'.
1576
1577 This function handles truncated packet_in data. The 'in_port' and 'reason'
1578 parameters are optional.
1579
1580 @param msg packet_in message
1581 @param data Expected packet_in data
1582 @param in_port Expected packet_in in_port, or None
1583 @param reason Expected packet_in reason, or None
1584 """
1585
Rich Lanec0d26dd2013-07-10 12:46:03 -07001586 if ofp.OFP_VERSION <= 2:
1587 pkt_in_port = msg.in_port
1588 else:
1589 oxms = { type(oxm): oxm for oxm in msg.match.oxm_list }
1590 if ofp.oxm.in_port in oxms:
1591 pkt_in_port = oxms[ofp.oxm.in_port].value
1592 else:
1593 logging.warn("Missing in_port in packet-in message")
1594 pkt_in_port = None
1595
1596 if in_port != None and in_port != pkt_in_port:
Rich Lane9f2f17e2013-09-13 13:19:37 -07001597 logging.debug("Incorrect packet_in in_port (expected %d, received %d)", in_port, pkt_in_port)
Rich Lane4c504f32013-06-07 17:24:14 -07001598 return False
1599
Rich Lanec0d26dd2013-07-10 12:46:03 -07001600 if reason != None and reason != msg.reason:
Rich Lane4c504f32013-06-07 17:24:14 -07001601 logging.debug("Incorrect packet_in reason (expected %d, received %d)", reason, msg.reason)
1602 return False
1603
1604 # Check that one of the packets is a prefix of the other.
1605 # The received packet may be either truncated or padded, but not both.
1606 # (Some of the padding may be truncated but that's irrelevant). We
1607 # need to check that the smaller packet is a prefix of the larger one.
1608 # Note that this check succeeds if the switch sends a zero-length
1609 # packet-in.
1610 compare_len = min(len(msg.data), len(data))
1611 if data[:compare_len] != msg.data[:compare_len]:
1612 logging.debug("Incorrect packet_in data")
1613 logging.debug("Expected %s" % format_packet(data[:compare_len]))
1614 logging.debug("Received %s" % format_packet(msg.data[:compare_len]))
1615 return False
1616
1617 return True
1618
1619def verify_packet_in(test, data, in_port, reason, controller=None):
1620 """
1621 Assert that the controller receives a packet_in message matching data 'data'
1622 from port 'in_port' with reason 'reason'. Does not trigger the packet_in
1623 itself, that's up to the test case.
1624
1625 @param test Instance of base_tests.SimpleProtocol
1626 @param pkt String to expect as the packet_in data
1627 @param in_port OpenFlow port number to expect as the packet_in in_port
1628 @param reason One of OFPR_* to expect as the packet_in reason
1629 @param controller Controller instance, defaults to test.controller
1630 @returns The received packet-in message
1631 """
1632
1633 if controller == None:
1634 controller = test.controller
1635
1636 end_time = time.time() + oftest.ofutils.default_timeout
1637
1638 while True:
1639 msg, _ = controller.poll(ofp.OFPT_PACKET_IN, end_time - time.time())
1640 if not msg:
1641 # Timeout
1642 break
1643 elif packet_in_match(msg, data, in_port, reason):
1644 # Found a matching message
1645 break
1646
Kiran Poola58c5c042014-05-15 15:11:06 -07001647 test.assertTrue(msg is not None, 'Packet in message not received on port %r' % in_port)
Rich Lane4c504f32013-06-07 17:24:14 -07001648 return msg
1649
1650def verify_no_packet_in(test, data, in_port, controller=None):
1651 """
1652 Assert that the controller does not receive a packet_in message matching
1653 data 'data' from port 'in_port'.
1654
1655 @param test Instance of base_tests.SimpleProtocol
1656 @param pkt String to expect as the packet_in data
1657 @param in_port OpenFlow port number to expect as the packet_in in_port
1658 @param controller Controller instance, defaults to test.controller
1659 """
1660
1661 if controller == None:
1662 controller = test.controller
1663
1664 # Negative test, need to wait a short amount of time before checking we
1665 # didn't receive the message.
Rich Lane48f6aed2014-03-23 15:51:02 -07001666 time.sleep(oftest.ofutils.default_negative_timeout)
Rich Lane4c504f32013-06-07 17:24:14 -07001667
1668 # Check every packet_in queued in the controller
1669 while True:
1670 msg, _ = controller.poll(ofp.OFPT_PACKET_IN, timeout=0)
1671 if msg == None:
1672 # No more queued packet_in messages
1673 break
1674 elif packet_in_match(msg, data, in_port, None):
1675 # Found a matching message
1676 break
1677
Rich Lane82c882d2013-08-09 17:13:52 -07001678 if in_port == None:
1679 test.assertTrue(msg == None, "Did not expect a packet-in message on any port")
1680 else:
1681 test.assertTrue(msg == None, "Did not expect a packet-in message on port %d" % in_port)
Rich Lane4c504f32013-06-07 17:24:14 -07001682
Rich Lane045db072013-08-06 13:16:30 -07001683def openflow_ports(num=None):
1684 """
1685 Return a list of 'num' OpenFlow port numbers
1686
1687 If 'num' is None, return all available ports. Otherwise, limit the length
1688 of the result to 'num' and raise an exception if not enough ports are
1689 available.
1690 """
1691 ports = sorted(oftest.config["port_map"].keys())
1692 if num != None and len(ports) < num:
1693 raise Exception("test requires %d ports but only %d are available" % (num, len(ports)))
1694 return ports[:num]
1695
Rich Lanee4b384d2013-09-13 14:33:40 -07001696def verify_packet(test, pkt, ofport):
1697 """
1698 Check that an expected packet is received
1699 """
1700 logging.debug("Checking for pkt on port %r", ofport)
1701 (rcv_port, rcv_pkt, pkt_time) = test.dataplane.poll(port_number=ofport, exp_pkt=str(pkt))
1702 test.assertTrue(rcv_pkt != None, "Did not receive pkt on %r" % ofport)
macauley17cd60d2015-07-27 17:41:18 +08001703 return (rcv_port, rcv_pkt, pkt_time)
1704
Rich Lanee4b384d2013-09-13 14:33:40 -07001705def verify_no_packet(test, pkt, ofport):
1706 """
1707 Check that a particular packet is not received
1708 """
1709 logging.debug("Negative check for pkt on port %r", ofport)
Rich Lane48f6aed2014-03-23 15:51:02 -07001710 (rcv_port, rcv_pkt, pkt_time) = \
1711 test.dataplane.poll(
1712 port_number=ofport, exp_pkt=str(pkt),
1713 timeout=oftest.ofutils.default_negative_timeout)
Rich Lanee4b384d2013-09-13 14:33:40 -07001714 test.assertTrue(rcv_pkt == None, "Received packet on %r" % ofport)
1715
1716def verify_no_other_packets(test):
1717 """
1718 Check that no unexpected packets are received
1719
1720 This is a no-op if the --relax option is in effect.
1721 """
1722 if oftest.config["relax"]:
1723 return
1724 logging.debug("Checking for unexpected packets on all ports")
Rich Lane48f6aed2014-03-23 15:51:02 -07001725 (rcv_port, rcv_pkt, pkt_time) = test.dataplane.poll(timeout=oftest.ofutils.default_negative_timeout)
Rich Lanee4b384d2013-09-13 14:33:40 -07001726 if rcv_pkt != None:
1727 logging.debug("Received unexpected packet on port %r: %s", rcv_port, format_packet(rcv_pkt))
1728 test.assertTrue(rcv_pkt == None, "Unexpected packet on port %r" % rcv_port)
1729
1730def verify_packets(test, pkt, ofports):
1731 """
1732 Check that a packet is received on certain ports
1733
1734 Also verifies that the packet is not received on any other ports, and that no
1735 other packets are received (unless --relax is in effect).
1736
1737 This covers the common and simplest cases for checking dataplane outputs.
1738 For more complex usage, like multiple different packets being output, or
1739 multiple packets on the same port, use the primitive verify_packet,
1740 verify_no_packet, and verify_no_other_packets functions directly.
1741 """
1742 pkt = str(pkt)
1743 for ofport in openflow_ports():
1744 if ofport in ofports:
1745 verify_packet(test, pkt, ofport)
1746 else:
1747 verify_no_packet(test, pkt, ofport)
1748 verify_no_other_packets(test)
1749
Rich Lane12d04592013-10-10 17:21:07 -07001750def verify_no_errors(ctrl):
1751 error, _ = ctrl.poll(ofp.OFPT_ERROR, 0)
1752 if error:
1753 raise AssertionError("unexpected error type=%d code=%d" % (error.err_type, error.code))
Rich Lanee4b384d2013-09-13 14:33:40 -07001754
Jonathan Stoutfcee3142014-01-28 15:46:22 -05001755def verify_capability(test, capability):
1756 """
Jonathan Stout073642d2014-02-04 13:41:48 -05001757 Return True if DUT supports the specified capability.
Jonathan Stoutfcee3142014-01-28 15:46:22 -05001758
1759 @param test Instance of base_tests.SimpleProtocol
1760 @param capability One of ofp_capabilities.
1761 """
1762 logging.info("Verifing that capability code is valid.")
1763 test.assertIn(capability, ofp.const.ofp_capabilities_map,
1764 "Capability code %d does not exist." % capability)
1765 capability_str = ofp.const.ofp_capabilities_map[capability]
1766
1767 logging.info(("Sending features_request to test if capability "
Jonathan Stout97e458a2014-01-28 16:08:04 -05001768 "%s is supported."), capability_str)
Jonathan Stoutfcee3142014-01-28 15:46:22 -05001769 req = ofp.message.features_request()
1770 res, raw = test.controller.transact(req)
1771 test.assertIsNotNone(res, "Did not receive a response from the DUT.")
1772 test.assertEqual(res.type, ofp.OFPT_FEATURES_REPLY,
1773 ("Unexpected packet type %d received in response to "
1774 "OFPT_FEATURES_REQUEST") % res.type)
Jonathan Stout641167f2014-02-04 12:07:10 -05001775 logging.info("Received features_reply.")
Jonathan Stoutfcee3142014-01-28 15:46:22 -05001776
Jonathan Stout641167f2014-02-04 12:07:10 -05001777 if (res.capabilities & capability) > 0:
1778 logging.info("Switch capabilities bitmask claims to support %s",
1779 capability_str)
1780 return True, res.capabilities
1781 else:
1782 logging.info("Capabilities bitmask does not support %s.",
1783 capability_str)
1784 return False, res.capabilities
Jonathan Stoutfcee3142014-01-28 15:46:22 -05001785
Jonathan Stouteb3721d2014-02-04 13:59:12 -05001786def verify_configuration_flag(test, flag):
1787 """
1788 Return True if DUT supports specified configuration flag.
1789
1790 @param test Instance of base_tests.SimpleProtocol
1791 @param flag One of ofp_config_flags.
Jonathan Stout1ec8c0f2014-02-04 15:25:38 -05001792 @returns (supported, flags) Bool if flag is set and flag values.
Jonathan Stouteb3721d2014-02-04 13:59:12 -05001793 """
1794 logging.info("Verifing that flag is valid.")
1795 test.assertIn(flag, ofp.const.ofp_config_flags_map,
1796 "flag %s does not exist." % flag)
1797 flag_str = ofp.const.ofp_config_flags_map[flag]
1798
1799 logging.info("Sending OFPT_GET_CONFIG_REQUEST.")
1800 req = ofp.message.get_config_request()
1801 rv = test.controller.message_send(req)
1802 test.assertNotEqual(rv, -1, "Not able to send get_config_request.")
1803
1804 logging.info("Expecting OFPT_GET_CONFIG_REPLY ")
1805 (res, pkt) = test.controller.poll(exp_msg=ofp.OFPT_GET_CONFIG_REPLY,
1806 timeout=2)
1807 test.assertIsNotNone(res, "Did not receive OFPT_GET_CONFIG_REPLY")
1808 logging.info("Received OFPT_GET_CONFIG_REPLY ")
1809
1810 if res.flags == flag:
1811 logging.info("%s flag is set.", flag_str)
1812 return True, res.flags
1813 else:
1814 logging.info("%s flag is not set.", flag_str)
1815 return False, res.flags
1816
Rich Lane7744e112013-01-11 17:23:57 -08001817__all__ = list(set(locals()) - _import_blacklist)