blob: 734af376498b612eeb70cff6ec30e01d8e4ba1e8 [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,
macauley1b23af82015-07-30 14:06:33 +0800255 inner_payload=None,
macauley17cd60d2015-07-27 17:41:18 +0800256 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)
macauley1b23af82015-07-30 14:06:33 +0800295
macauley17cd60d2015-07-27 17:41:18 +0800296 #add vxlan header
297 pkt = pkt/scapy.VXLAN(vni=vnid)
298 #add innder payload
macauley1b23af82015-07-30 14:06:33 +0800299 if inner_payload!=None:
300 pkt=pkt/inner_payload
macauley17cd60d2015-07-27 17:41:18 +0800301
302 return pkt
303
macauley_cheng45833df2015-08-31 15:19:07 +0800304
305def simple_mpls_packet(eth_dst='00:01:02:03:04:05',
306 eth_src='00:06:07:08:09:0a',
307 dl_vlan_enable=False,
308 vlan_vid=0,
309 vlan_pcp=0,
310 dl_vlan_cfi=0,
311 label=None,
312 inner_payload=None
313 ):
314 """
315 Return a simple dataplane MPLS packet
316
317 Supports a few parameters:
318 @param len Length of packet in bytes w/o CRC
319 @param eth_dst Destination MAC
320 @param eth_src Source MAC
321 @param dl_vlan_enable True if the packet is with vlan, False otherwise
322 @param vlan_vid VLAN ID
323 @param vlan_pcp VLAN priority
324 @param inner_pyload inner pacekt content
325 Generates a simple MPLS packet. Users shouldn't assume anything about
326 this packet other than that it is a valid ethernet/IP/UDP frame.
327 """
328
329 # Note Dot1Q.id is really CFI
330 if (dl_vlan_enable):
331 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
332 scapy.Dot1Q(prio=vlan_pcp, id=dl_vlan_cfi, vlan=vlan_vid)
333 else:
334 pkt = scapy.Ether(dst=eth_dst, src=eth_src)
335
336 #add MPLS header
337 for i in range(len(label)):
338 l,c,s,t=label[i]
339 pkt = pkt/scapy.MPLS(label=l, cos=c, s=s, ttl=t)
340
341 #add innder payload
342 if inner_payload!=None:
343 pkt=pkt/inner_payload
344
345 return pkt
346
Rich Lane86aceb02013-07-17 18:45:38 -0700347def simple_udpv6_packet(pktlen=100,
348 eth_dst='00:01:02:03:04:05',
349 eth_src='00:06:07:08:09:0a',
350 dl_vlan_enable=False,
351 vlan_vid=0,
352 vlan_pcp=0,
353 ipv6_src='2001:db8:85a3::8a2e:370:7334',
354 ipv6_dst='2001:db8:85a3::8a2e:370:7335',
355 ipv6_tc=0,
356 ipv6_hlim=64,
357 ipv6_fl=0,
358 udp_sport=1234,
359 udp_dport=80):
360 """
361 Return a simple IPv6/UDP packet
362
363 Supports a few parameters:
364 @param len Length of packet in bytes w/o CRC
365 @param eth_dst Destination MAC
366 @param eth_src Source MAC
367 @param dl_vlan_enable True if the packet is with vlan, False otherwise
368 @param vlan_vid VLAN ID
369 @param vlan_pcp VLAN priority
370 @param ipv6_src IPv6 source
371 @param ipv6_dst IPv6 destination
372 @param ipv6_tc IPv6 traffic class
373 @param ipv6_ttl IPv6 hop limit
374 @param ipv6_fl IPv6 flow label
375 @param udp_dport UDP destination port
376 @param udp_sport UDP source port
377
378 Generates a simple UDP request. Users shouldn't assume anything about this
379 packet other than that it is a valid ethernet/IPv6/UDP frame.
380 """
381
382 if MINSIZE > pktlen:
383 pktlen = MINSIZE
384
385 pkt = scapy.Ether(dst=eth_dst, src=eth_src)
386 if dl_vlan_enable or vlan_vid or vlan_pcp:
387 pkt /= scapy.Dot1Q(vlan=vlan_vid, prio=vlan_pcp)
388 pkt /= scapy.IPv6(src=ipv6_src, dst=ipv6_dst, fl=ipv6_fl, tc=ipv6_tc, hlim=ipv6_hlim)
389 pkt /= scapy.UDP(sport=udp_sport, dport=udp_dport)
390 pkt /= ("D" * (pktlen - len(pkt)))
391
392 return pkt
393
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700394def simple_icmp_packet(pktlen=60,
Rich Laned0478ff2013-03-11 12:46:58 -0700395 eth_dst='00:01:02:03:04:05',
396 eth_src='00:06:07:08:09:0a',
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700397 dl_vlan_enable=False,
Rich Laned0478ff2013-03-11 12:46:58 -0700398 vlan_vid=0,
399 vlan_pcp=0,
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700400 ip_src='192.168.0.1',
401 ip_dst='192.168.0.2',
402 ip_tos=0,
Gregor Maier9cc93342013-01-29 16:55:28 -0800403 ip_ttl=64,
Harshmeet Singhd209c0b2014-01-28 09:48:58 -0600404 ip_id=1,
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700405 icmp_type=8,
Harshmeet Singhd209c0b2014-01-28 09:48:58 -0600406 icmp_code=0,
Harshmeet Singh45b2a9d2014-01-28 13:02:04 -0600407 icmp_data=''):
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700408 """
409 Return a simple ICMP packet
410
411 Supports a few parameters:
412 @param len Length of packet in bytes w/o CRC
Rich Laned0478ff2013-03-11 12:46:58 -0700413 @param eth_dst Destinatino MAC
414 @param eth_src Source MAC
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700415 @param dl_vlan_enable True if the packet is with vlan, False otherwise
Rich Laned0478ff2013-03-11 12:46:58 -0700416 @param vlan_vid VLAN ID
417 @param vlan_pcp VLAN priority
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700418 @param ip_src IP source
419 @param ip_dst IP destination
420 @param ip_tos IP ToS
Gregor Maier9cc93342013-01-29 16:55:28 -0800421 @param ip_ttl IP TTL
Harshmeet Singhd209c0b2014-01-28 09:48:58 -0600422 @param ip_id IP Identification
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700423 @param icmp_type ICMP type
424 @param icmp_code ICMP code
Harshmeet Singhd209c0b2014-01-28 09:48:58 -0600425 @param icmp_data ICMP data
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700426
427 Generates a simple ICMP ECHO REQUEST. Users
428 shouldn't assume anything about this packet other than that
429 it is a valid ethernet/ICMP frame.
430 """
Jeffrey Townsend5cb7ed32012-08-17 18:11:01 +0000431
432 if MINSIZE > pktlen:
433 pktlen = MINSIZE
434
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700435 if (dl_vlan_enable):
Rich Laned0478ff2013-03-11 12:46:58 -0700436 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
437 scapy.Dot1Q(prio=vlan_pcp, id=0, vlan=vlan_vid)/ \
Harshmeet Singhd209c0b2014-01-28 09:48:58 -0600438 scapy.IP(src=ip_src, dst=ip_dst, ttl=ip_ttl, tos=ip_tos, id=ip_id)/ \
Harshmeet Singh45b2a9d2014-01-28 13:02:04 -0600439 scapy.ICMP(type=icmp_type, code=icmp_code)/ icmp_data
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700440 else:
Rich Laned0478ff2013-03-11 12:46:58 -0700441 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
Harshmeet Singhd209c0b2014-01-28 09:48:58 -0600442 scapy.IP(src=ip_src, dst=ip_dst, ttl=ip_ttl, tos=ip_tos, id=ip_id)/ \
Harshmeet Singh45b2a9d2014-01-28 13:02:04 -0600443 scapy.ICMP(type=icmp_type, code=icmp_code)/ icmp_data
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700444
445 pkt = pkt/("0" * (pktlen - len(pkt)))
446
447 return pkt
448
Rich Lane86aceb02013-07-17 18:45:38 -0700449def simple_icmpv6_packet(pktlen=100,
450 eth_dst='00:01:02:03:04:05',
451 eth_src='00:06:07:08:09:0a',
452 dl_vlan_enable=False,
453 vlan_vid=0,
454 vlan_pcp=0,
455 ipv6_src='2001:db8:85a3::8a2e:370:7334',
456 ipv6_dst='2001:db8:85a3::8a2e:370:7335',
457 ipv6_tc=0,
458 ipv6_hlim=64,
459 ipv6_fl=0,
460 icmp_type=8,
461 icmp_code=0):
462 """
463 Return a simple ICMPv6 packet
464
465 Supports a few parameters:
466 @param len Length of packet in bytes w/o CRC
467 @param eth_dst Destination MAC
468 @param eth_src Source MAC
469 @param dl_vlan_enable True if the packet is with vlan, False otherwise
470 @param vlan_vid VLAN ID
471 @param vlan_pcp VLAN priority
472 @param ipv6_src IPv6 source
473 @param ipv6_dst IPv6 destination
474 @param ipv6_tc IPv6 traffic class
475 @param ipv6_ttl IPv6 hop limit
476 @param ipv6_fl IPv6 flow label
477 @param icmp_type ICMP type
478 @param icmp_code ICMP code
479
480 Generates a simple ICMP ECHO REQUEST. Users shouldn't assume anything
481 about this packet other than that it is a valid ethernet/IPv6/ICMP frame.
482 """
483
484 if MINSIZE > pktlen:
485 pktlen = MINSIZE
486
487 pkt = scapy.Ether(dst=eth_dst, src=eth_src)
488 if dl_vlan_enable or vlan_vid or vlan_pcp:
489 pkt /= scapy.Dot1Q(vlan=vlan_vid, prio=vlan_pcp)
490 pkt /= scapy.IPv6(src=ipv6_src, dst=ipv6_dst, fl=ipv6_fl, tc=ipv6_tc, hlim=ipv6_hlim)
491 pkt /= scapy.ICMPv6Unknown(type=icmp_type, code=icmp_code)
492 pkt /= ("D" * (pktlen - len(pkt)))
493
494 return pkt
495
Shudong Zhouc7562b12013-02-06 01:12:18 -0800496def simple_arp_packet(pktlen=60,
Rich Laned0478ff2013-03-11 12:46:58 -0700497 eth_dst='ff:ff:ff:ff:ff:ff',
498 eth_src='00:06:07:08:09:0a',
Rich Lanee01611f2014-01-15 14:55:11 -0800499 vlan_vid=0,
500 vlan_pcp=0,
Shudong Zhouc7562b12013-02-06 01:12:18 -0800501 arp_op=1,
502 ip_snd='192.168.0.1',
503 ip_tgt='192.168.0.2',
504 hw_snd='00:06:07:08:09:0a',
505 hw_tgt='00:00:00:00:00:00',
506 ):
507 """
508 Return a simple ARP packet
509
510 Supports a few parameters:
511 @param len Length of packet in bytes w/o CRC
Rich Laned0478ff2013-03-11 12:46:58 -0700512 @param eth_dst Destinatino MAC
513 @param eth_src Source MAC
Shudong Zhouc7562b12013-02-06 01:12:18 -0800514 @param arp_op Operation (1=request, 2=reply)
515 @param ip_snd Sender IP
516 @param ip_tgt Target IP
517 @param hw_snd Sender hardware address
518 @param hw_tgt Target hardware address
519
520 Generates a simple ARP REQUEST. Users
521 shouldn't assume anything about this packet other than that
522 it is a valid ethernet/ARP frame.
523 """
524
525 if MINSIZE > pktlen:
526 pktlen = MINSIZE
527
Rich Lanee01611f2014-01-15 14:55:11 -0800528 pkt = scapy.Ether(dst=eth_dst, src=eth_src)
529 if vlan_vid or vlan_pcp:
530 pkt /= scapy.Dot1Q(vlan=vlan_vid, prio=vlan_pcp)
531 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 -0800532
Rich Laned459ce52014-01-24 12:09:54 -0800533 pkt = pkt/("\0" * (pktlen - len(pkt)))
Shudong Zhouc7562b12013-02-06 01:12:18 -0800534
535 return pkt
536
Ed Swierk0aeff8c2012-03-23 20:27:18 -0700537def simple_eth_packet(pktlen=60,
Rich Lane53275082013-11-18 23:26:22 -0800538 eth_dst='00:01:02:03:04:05',
539 eth_src='00:06:07:08:09:0a',
Rich Laned0478ff2013-03-11 12:46:58 -0700540 eth_type=0x88cc):
Jeffrey Townsend5cb7ed32012-08-17 18:11:01 +0000541
542 if MINSIZE > pktlen:
543 pktlen = MINSIZE
544
Rich Laned0478ff2013-03-11 12:46:58 -0700545 pkt = scapy.Ether(dst=eth_dst, src=eth_src, type=eth_type)
Ed Swierk0aeff8c2012-03-23 20:27:18 -0700546
547 pkt = pkt/("0" * (pktlen - len(pkt)))
548
549 return pkt
550
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800551def qinq_tcp_packet(pktlen=100,
Rich Laned0478ff2013-03-11 12:46:58 -0700552 eth_dst='00:01:02:03:04:05',
553 eth_src='00:06:07:08:09:0a',
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800554 dl_vlan_outer=20,
555 dl_vlan_pcp_outer=0,
556 dl_vlan_cfi_outer=0,
Rich Laned0478ff2013-03-11 12:46:58 -0700557 vlan_vid=10,
558 vlan_pcp=0,
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800559 dl_vlan_cfi=0,
560 ip_src='192.168.0.1',
561 ip_dst='192.168.0.2',
562 ip_tos=0,
Gregor Maier9cc93342013-01-29 16:55:28 -0800563 ip_ttl=64,
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800564 tcp_sport=1234,
565 tcp_dport=80,
566 ip_ihl=None,
567 ip_options=False
568 ):
569 """
570 Return a doubly tagged dataplane TCP packet
571
572 Supports a few parameters:
573 @param len Length of packet in bytes w/o CRC
Rich Laned0478ff2013-03-11 12:46:58 -0700574 @param eth_dst Destinatino MAC
575 @param eth_src Source MAC
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800576 @param dl_vlan_outer Outer VLAN ID
577 @param dl_vlan_pcp_outer Outer VLAN priority
578 @param dl_vlan_cfi_outer Outer VLAN cfi bit
Rich Laned0478ff2013-03-11 12:46:58 -0700579 @param vlan_vid Inner VLAN ID
580 @param vlan_pcp VLAN priority
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800581 @param dl_vlan_cfi VLAN cfi bit
582 @param ip_src IP source
583 @param ip_dst IP destination
584 @param ip_tos IP ToS
585 @param tcp_dport TCP destination port
586 @param ip_sport TCP source port
587
588 Generates a TCP request. Users
589 shouldn't assume anything about this packet other than that
590 it is a valid ethernet/IP/TCP frame.
591 """
592
593 if MINSIZE > pktlen:
594 pktlen = MINSIZE
595
596 # Note Dot1Q.id is really CFI
Rich Laned0478ff2013-03-11 12:46:58 -0700597 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800598 scapy.Dot1Q(prio=dl_vlan_pcp_outer, id=dl_vlan_cfi_outer, vlan=dl_vlan_outer)/ \
Rich Laned0478ff2013-03-11 12:46:58 -0700599 scapy.Dot1Q(prio=vlan_pcp, id=dl_vlan_cfi, vlan=vlan_vid)/ \
Gregor Maier9cc93342013-01-29 16:55:28 -0800600 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ttl=ip_ttl, ihl=ip_ihl)/ \
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800601 scapy.TCP(sport=tcp_sport, dport=tcp_dport)
602
603 pkt = pkt/("D" * (pktlen - len(pkt)))
604
605 return pkt
606
Shudong Zhoub7f12462012-11-20 13:01:12 -0800607def do_barrier(ctrl, timeout=-1):
Dan Talayco0fc08bd2012-04-09 16:56:18 -0700608 """
609 Do a barrier command
610 Return 0 on success, -1 on error
611 """
Rich Lanee717c6e2013-03-12 10:25:50 -0700612 b = ofp.message.barrier_request()
Shudong Zhoub7f12462012-11-20 13:01:12 -0800613 (resp, pkt) = ctrl.transact(b, timeout=timeout)
Rich Lane3a261d52013-01-03 17:45:08 -0800614 if resp is None:
615 raise AssertionError("barrier failed")
Dan Talaycof6b94832012-04-12 21:50:57 -0700616 # We'll trust the transaction processing in the controller that xid matched
Rich Lane3a261d52013-01-03 17:45:08 -0800617 return 0 # for backwards compatibility
Dan Talayco92c99122010-06-03 13:53:18 -0700618
Rich Lane9a003812012-10-04 17:17:59 -0700619def port_config_get(controller, port_no):
Dan Talayco92c99122010-06-03 13:53:18 -0700620 """
621 Get a port's configuration
622
623 Gets the switch feature configuration and grabs one port's
624 configuration
625
626 @returns (hwaddr, config, advert) The hwaddress, configuration and
627 advertised values
628 """
Rich Lane6dc865c2013-07-10 10:12:13 -0700629
630 if ofp.OFP_VERSION <= 3:
631 request = ofp.message.features_request()
632 reply, _ = controller.transact(request)
633 if reply is None:
634 logging.warn("Get feature request failed")
635 return None, None, None
636 logging.debug(reply.show())
637 ports = reply.ports
638 else:
639 request = ofp.message.port_desc_stats_request()
640 # TODO do multipart correctly
641 reply, _ = controller.transact(request)
642 if reply is None:
643 logging.warn("Port desc stats request failed")
644 return None, None, None
645 logging.debug(reply.show())
646 ports = reply.entries
647
648 for port in ports:
649 if port.port_no == port_no:
650 return (port.hw_addr, port.config, port.advertised)
Dan Talayco92c99122010-06-03 13:53:18 -0700651
Rich Lane9a003812012-10-04 17:17:59 -0700652 logging.warn("Did not find port number for port config")
Dan Talayco92c99122010-06-03 13:53:18 -0700653 return None, None, None
654
Rich Lane9a003812012-10-04 17:17:59 -0700655def port_config_set(controller, port_no, config, mask):
Dan Talayco92c99122010-06-03 13:53:18 -0700656 """
657 Set the port configuration according the given parameters
658
659 Gets the switch feature configuration and updates one port's
660 configuration value according to config and mask
661 """
Rich Lane9a003812012-10-04 17:17:59 -0700662 logging.info("Setting port " + str(port_no) + " to config " + str(config))
Rich Lane6dc865c2013-07-10 10:12:13 -0700663
664 hw_addr, _, _ = port_config_get(controller, port_no)
665
Rich Lanee717c6e2013-03-12 10:25:50 -0700666 mod = ofp.message.port_mod()
Dan Talayco92c99122010-06-03 13:53:18 -0700667 mod.port_no = port_no
Rich Lane6dc865c2013-07-10 10:12:13 -0700668 if hw_addr != None:
669 mod.hw_addr = hw_addr
Dan Talayco92c99122010-06-03 13:53:18 -0700670 mod.config = config
671 mod.mask = mask
Rich Lane6dc865c2013-07-10 10:12:13 -0700672 mod.advertise = 0 # No change
Rich Lane5c3151c2013-01-03 17:15:41 -0800673 controller.message_send(mod)
674 return 0
Dan Talayco92c99122010-06-03 13:53:18 -0700675
Rich Lane2014f9b2012-10-05 15:29:40 -0700676def receive_pkt_check(dp, pkt, yes_ports, no_ports, assert_if):
Dan Talayco92c99122010-06-03 13:53:18 -0700677 """
678 Check for proper receive packets across all ports
Ken Chiang1bf01602012-04-04 10:48:23 -0700679 @param dp The dataplane object
Dan Talayco92c99122010-06-03 13:53:18 -0700680 @param pkt Expected packet; may be None if yes_ports is empty
681 @param yes_ports Set or list of ports that should recieve packet
682 @param no_ports Set or list of ports that should not receive packet
683 @param assert_if Object that implements assertXXX
Rich Lanee4b384d2013-09-13 14:33:40 -0700684
685 DEPRECATED in favor in verify_packets
Dan Talayco92c99122010-06-03 13:53:18 -0700686 """
Rich Lane91765672012-12-06 16:33:04 -0800687
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700688 exp_pkt_arg = None
Rich Lanecd97d3d2013-01-07 18:50:06 -0800689 if oftest.config["relax"]:
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700690 exp_pkt_arg = pkt
691
Dan Talayco92c99122010-06-03 13:53:18 -0700692 for ofport in yes_ports:
Rich Lane9a003812012-10-04 17:17:59 -0700693 logging.debug("Checking for pkt on port " + str(ofport))
Ken Chiang1bf01602012-04-04 10:48:23 -0700694 (rcv_port, rcv_pkt, pkt_time) = dp.poll(
Wilson Ngc2c6b4e2015-03-04 17:30:20 -0800695 port_number=ofport, exp_pkt=exp_pkt_arg)
Dan Talayco92c99122010-06-03 13:53:18 -0700696 assert_if.assertTrue(rcv_pkt is not None,
697 "Did not receive pkt on " + str(ofport))
Rich Lanecd97d3d2013-01-07 18:50:06 -0800698 if not oftest.dataplane.match_exp_pkt(pkt, rcv_pkt):
Rich Lane3c266832013-01-29 18:29:15 -0800699 logging.debug("Expected %s" % format_packet(pkt))
700 logging.debug("Received %s" % format_packet(rcv_pkt))
Rich Lanecd97d3d2013-01-07 18:50:06 -0800701 assert_if.assertTrue(oftest.dataplane.match_exp_pkt(pkt, rcv_pkt),
Rich Lane3c266832013-01-29 18:29:15 -0800702 "Received packet does not match expected packet " +
Ken Chiang1bf01602012-04-04 10:48:23 -0700703 "on port " + str(ofport))
Dan Talayco73f84012012-10-02 09:23:18 -0700704 if len(no_ports) > 0:
Rich Lane57dfee72014-03-24 16:59:47 -0700705 time.sleep(oftest.ofutils.default_negative_timeout)
Dan Talayco92c99122010-06-03 13:53:18 -0700706 for ofport in no_ports:
Rich Lane9a003812012-10-04 17:17:59 -0700707 logging.debug("Negative check for pkt on port " + str(ofport))
Ken Chiang1bf01602012-04-04 10:48:23 -0700708 (rcv_port, rcv_pkt, pkt_time) = dp.poll(
Rich Lane91765672012-12-06 16:33:04 -0800709 port_number=ofport, timeout=0, exp_pkt=exp_pkt_arg)
Dan Talayco92c99122010-06-03 13:53:18 -0700710 assert_if.assertTrue(rcv_pkt is None,
711 "Unexpected pkt on port " + str(ofport))
Dan Talayco551befa2010-07-15 17:05:32 -0700712
713
Dan Talaycoc948d0b2012-03-23 12:17:54 -0700714def receive_pkt_verify(parent, egr_ports, exp_pkt, ing_port):
Dan Talayco551befa2010-07-15 17:05:32 -0700715 """
716 Receive a packet and verify it matches an expected value
Dan Talaycof6e76c02012-03-23 10:56:12 -0700717 @param egr_port A single port or list of ports
Dan Talayco551befa2010-07-15 17:05:32 -0700718
719 parent must implement dataplane, assertTrue and assertEqual
Rich Lanee4b384d2013-09-13 14:33:40 -0700720
721 DEPRECATED in favor in verify_packets
Dan Talayco551befa2010-07-15 17:05:32 -0700722 """
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700723 exp_pkt_arg = None
Rich Lanecd97d3d2013-01-07 18:50:06 -0800724 if oftest.config["relax"]:
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700725 exp_pkt_arg = exp_pkt
726
Dan Talaycof6e76c02012-03-23 10:56:12 -0700727 if type(egr_ports) == type([]):
728 egr_port_list = egr_ports
729 else:
730 egr_port_list = [egr_ports]
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700731
Dan Talaycof6e76c02012-03-23 10:56:12 -0700732 # Expect a packet from each port on egr port list
733 for egr_port in egr_port_list:
Dan Talaycod8ae7582012-03-23 12:24:56 -0700734 check_port = egr_port
Rich Lanee717c6e2013-03-12 10:25:50 -0700735 if egr_port == ofp.OFPP_IN_PORT:
Dan Talaycod8ae7582012-03-23 12:24:56 -0700736 check_port = ing_port
Dan Talaycof6e76c02012-03-23 10:56:12 -0700737 (rcv_port, rcv_pkt, pkt_time) = parent.dataplane.poll(
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700738 port_number=check_port, exp_pkt=exp_pkt_arg)
Dan Talayco551befa2010-07-15 17:05:32 -0700739
Dan Talaycof6e76c02012-03-23 10:56:12 -0700740 if rcv_pkt is None:
Rich Lane9a003812012-10-04 17:17:59 -0700741 logging.error("ERROR: No packet received from " +
Dan Talaycod8ae7582012-03-23 12:24:56 -0700742 str(check_port))
Dan Talayco551befa2010-07-15 17:05:32 -0700743
Dan Talaycof6e76c02012-03-23 10:56:12 -0700744 parent.assertTrue(rcv_pkt is not None,
Dan Talaycod8ae7582012-03-23 12:24:56 -0700745 "Did not receive packet port " + str(check_port))
Rich Lane9a003812012-10-04 17:17:59 -0700746 logging.debug("Packet len " + str(len(rcv_pkt)) + " in on " +
Dan Talaycof6e76c02012-03-23 10:56:12 -0700747 str(rcv_port))
748
749 if str(exp_pkt) != str(rcv_pkt):
Rich Lane9a003812012-10-04 17:17:59 -0700750 logging.error("ERROR: Packet match failed.")
751 logging.debug("Expected len " + str(len(exp_pkt)) + ": "
Dan Talaycof6e76c02012-03-23 10:56:12 -0700752 + str(exp_pkt).encode('hex'))
Rich Lane9a003812012-10-04 17:17:59 -0700753 logging.debug("Received len " + str(len(rcv_pkt)) + ": "
Dan Talaycof6e76c02012-03-23 10:56:12 -0700754 + str(rcv_pkt).encode('hex'))
Rich Lane5d7e89a2012-10-26 16:43:13 -0700755 logging.debug("Expected packet: " + inspect_packet(scapy.Ether(str(exp_pkt))))
756 logging.debug("Received packet: " + inspect_packet(scapy.Ether(str(rcv_pkt))))
Dan Talaycof6e76c02012-03-23 10:56:12 -0700757 parent.assertEqual(str(exp_pkt), str(rcv_pkt),
Dan Talaycod8ae7582012-03-23 12:24:56 -0700758 "Packet match error on port " + str(check_port))
Dan Talaycof6e76c02012-03-23 10:56:12 -0700759
Dan Talayco551befa2010-07-15 17:05:32 -0700760def match_verify(parent, req_match, res_match):
761 """
762 Verify flow matches agree; if they disagree, report where
763
764 parent must implement assertEqual
765 Use str() to ensure content is compared and not pointers
766 """
767
768 parent.assertEqual(req_match.wildcards, res_match.wildcards,
769 'Match failed: wildcards: ' + hex(req_match.wildcards) +
770 " != " + hex(res_match.wildcards))
771 parent.assertEqual(req_match.in_port, res_match.in_port,
772 'Match failed: in_port: ' + str(req_match.in_port) +
773 " != " + str(res_match.in_port))
Rich Laned0478ff2013-03-11 12:46:58 -0700774 parent.assertEqual(str(req_match.eth_src), str(res_match.eth_src),
775 'Match failed: eth_src: ' + str(req_match.eth_src) +
776 " != " + str(res_match.eth_src))
777 parent.assertEqual(str(req_match.eth_dst), str(res_match.eth_dst),
778 'Match failed: eth_dst: ' + str(req_match.eth_dst) +
779 " != " + str(res_match.eth_dst))
780 parent.assertEqual(req_match.vlan_vid, res_match.vlan_vid,
781 'Match failed: vlan_vid: ' + str(req_match.vlan_vid) +
782 " != " + str(res_match.vlan_vid))
783 parent.assertEqual(req_match.vlan_pcp, res_match.vlan_pcp,
784 'Match failed: vlan_pcp: ' +
785 str(req_match.vlan_pcp) + " != " +
786 str(res_match.vlan_pcp))
787 parent.assertEqual(req_match.eth_type, res_match.eth_type,
788 'Match failed: eth_type: ' + str(req_match.eth_type) +
789 " != " + str(res_match.eth_type))
Dan Talayco551befa2010-07-15 17:05:32 -0700790
Rich Lanee717c6e2013-03-12 10:25:50 -0700791 if (not(req_match.wildcards & ofp.OFPFW_DL_TYPE)
Rich Laned0478ff2013-03-11 12:46:58 -0700792 and (req_match.eth_type == IP_ETHERTYPE)):
793 parent.assertEqual(req_match.ip_dscp, res_match.ip_dscp,
794 'Match failed: ip_dscp: ' + str(req_match.ip_dscp) +
795 " != " + str(res_match.ip_dscp))
796 parent.assertEqual(req_match.ip_proto, res_match.ip_proto,
797 'Match failed: ip_proto: ' + str(req_match.ip_proto) +
798 " != " + str(res_match.ip_proto))
799 parent.assertEqual(req_match.ipv4_src, res_match.ipv4_src,
800 'Match failed: ipv4_src: ' + str(req_match.ipv4_src) +
801 " != " + str(res_match.ipv4_src))
802 parent.assertEqual(req_match.ipv4_dst, res_match.ipv4_dst,
803 'Match failed: ipv4_dst: ' + str(req_match.ipv4_dst) +
804 " != " + str(res_match.ipv4_dst))
Dan Talayco551befa2010-07-15 17:05:32 -0700805
Rich Lanee717c6e2013-03-12 10:25:50 -0700806 if (not(req_match.wildcards & ofp.OFPFW_NW_PROTO)
Rich Laned0478ff2013-03-11 12:46:58 -0700807 and ((req_match.ip_proto == TCP_PROTOCOL)
808 or (req_match.ip_proto == UDP_PROTOCOL))):
809 parent.assertEqual(req_match.tcp_src, res_match.tcp_src,
810 'Match failed: tcp_src: ' +
811 str(req_match.tcp_src) +
812 " != " + str(res_match.tcp_src))
813 parent.assertEqual(req_match.tcp_dst, res_match.tcp_dst,
814 'Match failed: tcp_dst: ' +
815 str(req_match.tcp_dst) +
816 " != " + str(res_match.tcp_dst))
Dan Talayco551befa2010-07-15 17:05:32 -0700817
Ed Swierk99a74de2012-08-22 06:40:54 -0700818def packet_to_flow_match(parent, packet):
Rich Lanef6883512013-03-11 17:00:09 -0700819 match = oftest.parse.packet_to_flow_match(packet)
Rich Laneab7476f2013-06-13 15:53:52 -0700820 if ofp.OFP_VERSION in [1, 2]:
821 match.wildcards |= required_wildcards(parent)
822 else:
823 # TODO remove incompatible OXM entries
824 pass
Ed Swierk99a74de2012-08-22 06:40:54 -0700825 return match
826
827def flow_msg_create(parent, pkt, ing_port=None, action_list=None, wildcards=None,
Dan Talaycof6e76c02012-03-23 10:56:12 -0700828 egr_ports=None, egr_queue=None, check_expire=False, in_band=False):
Dan Talayco551befa2010-07-15 17:05:32 -0700829 """
830 Create a flow message
831
832 Match on packet with given wildcards.
833 See flow_match_test for other parameter descriptoins
834 @param egr_queue if not None, make the output an enqueue action
Dan Talayco677c0b72011-08-23 22:53:38 -0700835 @param in_band if True, do not wildcard ingress port
Dan Talaycof6e76c02012-03-23 10:56:12 -0700836 @param egr_ports None (drop), single port or list of ports
Dan Talayco551befa2010-07-15 17:05:32 -0700837 """
Rich Lanef6883512013-03-11 17:00:09 -0700838 match = oftest.parse.packet_to_flow_match(pkt)
Dan Talayco551befa2010-07-15 17:05:32 -0700839 parent.assertTrue(match is not None, "Flow match from pkt failed")
Ed Swierk99a74de2012-08-22 06:40:54 -0700840 if wildcards is None:
841 wildcards = required_wildcards(parent)
Dan Talayco677c0b72011-08-23 22:53:38 -0700842 if in_band:
Rich Lanee717c6e2013-03-12 10:25:50 -0700843 wildcards &= ~ofp.OFPFW_IN_PORT
Dan Talayco551befa2010-07-15 17:05:32 -0700844 match.wildcards = wildcards
845 match.in_port = ing_port
846
Dan Talaycof6e76c02012-03-23 10:56:12 -0700847 if type(egr_ports) == type([]):
848 egr_port_list = egr_ports
849 else:
850 egr_port_list = [egr_ports]
851
Rich Lanee717c6e2013-03-12 10:25:50 -0700852 request = ofp.message.flow_add()
Dan Talayco551befa2010-07-15 17:05:32 -0700853 request.match = match
854 request.buffer_id = 0xffffffff
855 if check_expire:
Rich Lanee717c6e2013-03-12 10:25:50 -0700856 request.flags |= ofp.OFPFF_SEND_FLOW_REM
Dan Talayco551befa2010-07-15 17:05:32 -0700857 request.hard_timeout = 1
858
Rich Lane400fb9b2013-10-10 17:20:54 -0700859 if ofp.OFP_VERSION == 1:
860 actions = request.actions
861 else:
862 actions = []
863 request.instructions.append(ofp.instruction.apply_actions(actions))
864
Dan Talayco551befa2010-07-15 17:05:32 -0700865 if action_list is not None:
Rich Lane400fb9b2013-10-10 17:20:54 -0700866 actions.extend(action_list)
Dan Talayco551befa2010-07-15 17:05:32 -0700867
868 # Set up output/enqueue action if directed
869 if egr_queue is not None:
Dan Talaycof6e76c02012-03-23 10:56:12 -0700870 parent.assertTrue(egr_ports is not None, "Egress port not set")
Rich Lanee717c6e2013-03-12 10:25:50 -0700871 act = ofp.action.enqueue()
Dan Talaycof6e76c02012-03-23 10:56:12 -0700872 for egr_port in egr_port_list:
873 act.port = egr_port
874 act.queue_id = egr_queue
Rich Lane400fb9b2013-10-10 17:20:54 -0700875 actions.append(act)
Dan Talaycof6e76c02012-03-23 10:56:12 -0700876 elif egr_ports is not None:
877 for egr_port in egr_port_list:
Rich Lanee717c6e2013-03-12 10:25:50 -0700878 act = ofp.action.output()
Dan Talaycof6e76c02012-03-23 10:56:12 -0700879 act.port = egr_port
Rich Lane400fb9b2013-10-10 17:20:54 -0700880 actions.append(act)
Dan Talayco551befa2010-07-15 17:05:32 -0700881
Rich Lane9a003812012-10-04 17:17:59 -0700882 logging.debug(request.show())
Dan Talayco551befa2010-07-15 17:05:32 -0700883
884 return request
885
Jeffrey Townsendf3eae9c2012-03-28 18:23:21 -0700886def flow_msg_install(parent, request, clear_table_override=None):
Dan Talayco551befa2010-07-15 17:05:32 -0700887 """
888 Install a flow mod message in the switch
889
890 @param parent Must implement controller, assertEqual, assertTrue
891 @param request The request, all set to go
892 @param clear_table If true, clear the flow table before installing
893 """
Dan Talayco8a64e332012-03-28 14:53:20 -0700894
Rich Lane2014f9b2012-10-05 15:29:40 -0700895 clear_table = test_param_get('clear_table', default=True)
Jeffrey Townsendf3eae9c2012-03-28 18:23:21 -0700896 if(clear_table_override != None):
897 clear_table = clear_table_override
898
899 if clear_table:
Rich Lane9a003812012-10-04 17:17:59 -0700900 logging.debug("Clear flow table")
Rich Lane32bf9482013-01-03 17:26:30 -0800901 delete_all_flows(parent.controller)
Dan Talayco551befa2010-07-15 17:05:32 -0700902
Rich Lane9a003812012-10-04 17:17:59 -0700903 logging.debug("Insert flow")
Rich Lane5c3151c2013-01-03 17:15:41 -0800904 parent.controller.message_send(request)
Rich Lanee912d032012-12-22 14:28:33 -0800905
Rich Lane3a261d52013-01-03 17:45:08 -0800906 do_barrier(parent.controller)
Dan Talayco551befa2010-07-15 17:05:32 -0700907
Ed Swierk99a74de2012-08-22 06:40:54 -0700908def flow_match_test_port_pair(parent, ing_port, egr_ports, wildcards=None,
Rich Laned0478ff2013-03-11 12:46:58 -0700909 vlan_vid=-1, pkt=None, exp_pkt=None,
Rich Lanee5779d32012-10-05 17:56:04 -0700910 action_list=None):
Dan Talayco551befa2010-07-15 17:05:32 -0700911 """
912 Flow match test on single TCP packet
Dan Talaycof6e76c02012-03-23 10:56:12 -0700913 @param egr_ports A single port or list of ports
Dan Talayco551befa2010-07-15 17:05:32 -0700914
915 Run test with packet through switch from ing_port to egr_port
916 See flow_match_test for parameter descriptions
917 """
918
Ed Swierk99a74de2012-08-22 06:40:54 -0700919 if wildcards is None:
920 wildcards = required_wildcards(parent)
Rich Lane9a003812012-10-04 17:17:59 -0700921 logging.info("Pkt match test: " + str(ing_port) + " to " +
Dan Talaycof6e76c02012-03-23 10:56:12 -0700922 str(egr_ports))
Rich Laned0478ff2013-03-11 12:46:58 -0700923 logging.debug(" WC: " + hex(wildcards) + " vlan: " + str(vlan_vid))
Dan Talayco551befa2010-07-15 17:05:32 -0700924 if pkt is None:
Rich Laned0478ff2013-03-11 12:46:58 -0700925 pkt = simple_tcp_packet(dl_vlan_enable=(vlan_vid >= 0), vlan_vid=vlan_vid)
Rich Lanec41fbec2013-10-02 00:27:59 -0700926 if exp_pkt is None:
927 exp_pkt = pkt
Dan Talayco551befa2010-07-15 17:05:32 -0700928
929 request = flow_msg_create(parent, pkt, ing_port=ing_port,
Dan Talaycof6e76c02012-03-23 10:56:12 -0700930 wildcards=wildcards, egr_ports=egr_ports,
Dan Talayco551befa2010-07-15 17:05:32 -0700931 action_list=action_list)
932
933 flow_msg_install(parent, request)
934
Rich Lane9a003812012-10-04 17:17:59 -0700935 logging.debug("Send packet: " + str(ing_port) + " to " +
Dan Talaycof6e76c02012-03-23 10:56:12 -0700936 str(egr_ports))
Dan Talayco551befa2010-07-15 17:05:32 -0700937 parent.dataplane.send(ing_port, str(pkt))
938
Rich Lane8f45e2d2013-10-01 16:06:54 -0700939 exp_ports = [ing_port if port == ofp.OFPP_IN_PORT else port for port in egr_ports]
Rich Lanee4b384d2013-09-13 14:33:40 -0700940 verify_packets(parent, exp_pkt, exp_ports)
Dan Talayco551befa2010-07-15 17:05:32 -0700941
Rich Lane89725bb2012-12-03 16:23:27 -0800942def flow_match_test_pktout(parent, ing_port, egr_ports,
Rich Laned0478ff2013-03-11 12:46:58 -0700943 vlan_vid=-1, pkt=None, exp_pkt=None,
Rich Lane89725bb2012-12-03 16:23:27 -0800944 action_list=None):
945 """
946 Packet-out test on single TCP packet
947 @param egr_ports A single port or list of ports
948
949 Run test sending packet-out to egr_ports. The goal is to test the actions
950 taken on the packet, not the matching which is of course irrelevant.
951 See flow_match_test for parameter descriptions
952 """
953
954 if pkt is None:
Rich Laned0478ff2013-03-11 12:46:58 -0700955 pkt = simple_tcp_packet(dl_vlan_enable=(vlan_vid >= 0), vlan_vid=vlan_vid)
Rich Lanec41fbec2013-10-02 00:27:59 -0700956 if exp_pkt is None:
957 exp_pkt = pkt
Rich Lane89725bb2012-12-03 16:23:27 -0800958
Rich Lanee717c6e2013-03-12 10:25:50 -0700959 msg = ofp.message.packet_out()
Rich Lane89725bb2012-12-03 16:23:27 -0800960 msg.in_port = ing_port
Rich Laneea8c4722013-04-04 15:30:20 -0700961 msg.buffer_id = 0xffffffff
Rich Lane89725bb2012-12-03 16:23:27 -0800962 msg.data = str(pkt)
963 if action_list is not None:
964 for act in action_list:
Rich Lanec495d9e2013-03-08 17:43:36 -0800965 msg.actions.append(act)
Rich Lane89725bb2012-12-03 16:23:27 -0800966
967 # Set up output action
968 if egr_ports is not None:
969 for egr_port in egr_ports:
Rich Lanee717c6e2013-03-12 10:25:50 -0700970 act = ofp.action.output()
Rich Lane89725bb2012-12-03 16:23:27 -0800971 act.port = egr_port
Rich Lanec495d9e2013-03-08 17:43:36 -0800972 msg.actions.append(act)
Rich Lane89725bb2012-12-03 16:23:27 -0800973
974 logging.debug(msg.show())
Rich Lane5c3151c2013-01-03 17:15:41 -0800975 parent.controller.message_send(msg)
Rich Lane89725bb2012-12-03 16:23:27 -0800976
Rich Lane8f45e2d2013-10-01 16:06:54 -0700977 exp_ports = [ing_port if port == ofp.OFPP_IN_PORT else port for port in egr_ports]
Rich Lanee4b384d2013-09-13 14:33:40 -0700978 verify_packets(parent, exp_pkt, exp_ports)
Rich Lane89725bb2012-12-03 16:23:27 -0800979
Dan Talaycof6e76c02012-03-23 10:56:12 -0700980def get_egr_list(parent, of_ports, how_many, exclude_list=[]):
981 """
982 Generate a list of ports avoiding those in the exclude list
Rich Lane9a003812012-10-04 17:17:59 -0700983 @param parent Supplies logging
Dan Talaycof6e76c02012-03-23 10:56:12 -0700984 @param of_ports List of OF port numbers
985 @param how_many Number of ports to be added to the list
986 @param exclude_list List of ports not to be used
987 @returns An empty list if unable to find enough ports
988 """
989
Dan Talaycoc948d0b2012-03-23 12:17:54 -0700990 if how_many == 0:
991 return []
992
Dan Talaycof6e76c02012-03-23 10:56:12 -0700993 count = 0
994 egr_ports = []
995 for egr_idx in range(len(of_ports)):
996 if of_ports[egr_idx] not in exclude_list:
997 egr_ports.append(of_ports[egr_idx])
998 count += 1
999 if count >= how_many:
1000 return egr_ports
Rich Lane9a003812012-10-04 17:17:59 -07001001 logging.debug("Could not generate enough egress ports for test")
Dan Talaycof6e76c02012-03-23 10:56:12 -07001002 return []
1003
Rich Laned0478ff2013-03-11 12:46:58 -07001004def flow_match_test(parent, port_map, wildcards=None, vlan_vid=-1, pkt=None,
Rich Lanee5779d32012-10-05 17:56:04 -07001005 exp_pkt=None, action_list=None,
Dan Talaycoc948d0b2012-03-23 12:17:54 -07001006 max_test=0, egr_count=1, ing_port=False):
Dan Talayco551befa2010-07-15 17:05:32 -07001007 """
Rich Lane89725bb2012-12-03 16:23:27 -08001008 Run flow_match_test_port_pair on all port pairs and packet-out
Dan Talayco551befa2010-07-15 17:05:32 -07001009
1010 @param max_test If > 0 no more than this number of tests are executed.
1011 @param parent Must implement controller, dataplane, assertTrue, assertEqual
Rich Lane9a003812012-10-04 17:17:59 -07001012 and logging
Dan Talayco551befa2010-07-15 17:05:32 -07001013 @param pkt If not None, use this packet for ingress
1014 @param wildcards For flow match entry
Rich Laned0478ff2013-03-11 12:46:58 -07001015 @param vlan_vid If not -1, and pkt is None, create a pkt w/ VLAN tag
Dan Talayco551befa2010-07-15 17:05:32 -07001016 @param exp_pkt If not None, use this as the expected output pkt; els use pkt
1017 @param action_list Additional actions to add to flow mod
Dan Talaycocfa172f2012-03-23 12:03:00 -07001018 @param egr_count Number of egress ports; -1 means get from config w/ dflt 2
Dan Talayco551befa2010-07-15 17:05:32 -07001019 """
Ed Swierk99a74de2012-08-22 06:40:54 -07001020 if wildcards is None:
1021 wildcards = required_wildcards(parent)
Dan Talayco551befa2010-07-15 17:05:32 -07001022 of_ports = port_map.keys()
1023 of_ports.sort()
1024 parent.assertTrue(len(of_ports) > 1, "Not enough ports for test")
1025 test_count = 0
1026
Dan Talaycocfa172f2012-03-23 12:03:00 -07001027 if egr_count == -1:
Rich Lane2014f9b2012-10-05 15:29:40 -07001028 egr_count = test_param_get('egr_count', default=2)
Dan Talaycocfa172f2012-03-23 12:03:00 -07001029
Dan Talayco551befa2010-07-15 17:05:32 -07001030 for ing_idx in range(len(of_ports)):
1031 ingress_port = of_ports[ing_idx]
Dan Talaycof6e76c02012-03-23 10:56:12 -07001032 egr_ports = get_egr_list(parent, of_ports, egr_count,
1033 exclude_list=[ingress_port])
Dan Talaycoc948d0b2012-03-23 12:17:54 -07001034 if ing_port:
Rich Lanee717c6e2013-03-12 10:25:50 -07001035 egr_ports.append(ofp.OFPP_IN_PORT)
Dan Talaycof6e76c02012-03-23 10:56:12 -07001036 if len(egr_ports) == 0:
1037 parent.assertTrue(0, "Failed to generate egress port list")
1038
1039 flow_match_test_port_pair(parent, ingress_port, egr_ports,
Rich Laned0478ff2013-03-11 12:46:58 -07001040 wildcards=wildcards, vlan_vid=vlan_vid,
Dan Talaycof6e76c02012-03-23 10:56:12 -07001041 pkt=pkt, exp_pkt=exp_pkt,
Rich Lanee5779d32012-10-05 17:56:04 -07001042 action_list=action_list)
Dan Talaycof6e76c02012-03-23 10:56:12 -07001043 test_count += 1
1044 if (max_test > 0) and (test_count > max_test):
Rich Lane9a003812012-10-04 17:17:59 -07001045 logging.info("Ran " + str(test_count) + " tests; exiting")
Rich Lane89725bb2012-12-03 16:23:27 -08001046 break
1047
Ed Swierk38eea082013-01-02 19:46:20 -08001048 if not test_param_get('pktout_actions', default=True):
1049 return
Rich Lane89725bb2012-12-03 16:23:27 -08001050
1051 ingress_port = of_ports[0]
1052 egr_ports = get_egr_list(parent, of_ports, egr_count,
1053 exclude_list=[ingress_port])
1054 if ing_port:
Rich Lanee717c6e2013-03-12 10:25:50 -07001055 egr_ports.append(ofp.OFPP_IN_PORT)
Rich Lane89725bb2012-12-03 16:23:27 -08001056 flow_match_test_pktout(parent, ingress_port, egr_ports,
Rich Laned0478ff2013-03-11 12:46:58 -07001057 vlan_vid=vlan_vid,
Rich Lane89725bb2012-12-03 16:23:27 -08001058 pkt=pkt, exp_pkt=exp_pkt,
1059 action_list=action_list)
Dan Talayco551befa2010-07-15 17:05:32 -07001060
Rich Lane2014f9b2012-10-05 15:29:40 -07001061def test_param_get(key, default=None):
Dan Talayco4b2bee62010-07-20 14:10:05 -07001062 """
1063 Return value passed via test-params if present
1064
Dan Talayco4b2bee62010-07-20 14:10:05 -07001065 @param key The lookup key
1066 @param default Default value to use if not found
1067
1068 If the pair 'key=val' appeared in the string passed to --test-params
1069 on the command line, return val (as interpreted by exec). Otherwise
1070 return default value.
Dan Talaycof6e76c02012-03-23 10:56:12 -07001071
1072 WARNING: TEST PARAMETERS MUST BE PYTHON IDENTIFIERS;
1073 eg egr_count, not egr-count.
Dan Talayco4b2bee62010-07-20 14:10:05 -07001074 """
1075 try:
Rich Lanecd97d3d2013-01-07 18:50:06 -08001076 exec oftest.config["test_params"]
Dan Talayco4b2bee62010-07-20 14:10:05 -07001077 except:
1078 return default
1079
Dan Talayco4b2bee62010-07-20 14:10:05 -07001080 try:
Rich Lanefdec0fb2013-08-09 18:01:05 -07001081 return eval(str(key))
Dan Talayco4b2bee62010-07-20 14:10:05 -07001082 except:
1083 return default
1084
1085def action_generate(parent, field_to_mod, mod_field_vals):
1086 """
1087 Create an action to modify the field indicated in field_to_mod
1088
1089 @param parent Must implement, assertTrue
1090 @param field_to_mod The field to modify as a string name
1091 @param mod_field_vals Hash of values to use for modified values
1092 """
1093
1094 act = None
1095
1096 if field_to_mod in ['pktlen']:
1097 return None
1098
Rich Laned0478ff2013-03-11 12:46:58 -07001099 if field_to_mod == 'eth_dst':
Rich Lanee717c6e2013-03-12 10:25:50 -07001100 act = ofp.action.set_dl_dst()
Rich Lanef6883512013-03-11 17:00:09 -07001101 act.dl_addr = oftest.parse.parse_mac(mod_field_vals['eth_dst'])
Rich Laned0478ff2013-03-11 12:46:58 -07001102 elif field_to_mod == 'eth_src':
Rich Lanee717c6e2013-03-12 10:25:50 -07001103 act = ofp.action.set_dl_src()
Rich Lanef6883512013-03-11 17:00:09 -07001104 act.dl_addr = oftest.parse.parse_mac(mod_field_vals['eth_src'])
Dan Talayco4b2bee62010-07-20 14:10:05 -07001105 elif field_to_mod == 'dl_vlan_enable':
1106 if not mod_field_vals['dl_vlan_enable']: # Strip VLAN tag
Rich Lanee717c6e2013-03-12 10:25:50 -07001107 act = ofp.action.strip_vlan()
Rich Laned0478ff2013-03-11 12:46:58 -07001108 # Add VLAN tag is handled by vlan_vid field
Dan Talayco4b2bee62010-07-20 14:10:05 -07001109 # Will return None in this case
Rich Laned0478ff2013-03-11 12:46:58 -07001110 elif field_to_mod == 'vlan_vid':
Rich Lanee717c6e2013-03-12 10:25:50 -07001111 act = ofp.action.set_vlan_vid()
Rich Laned0478ff2013-03-11 12:46:58 -07001112 act.vlan_vid = mod_field_vals['vlan_vid']
1113 elif field_to_mod == 'vlan_pcp':
Rich Lanee717c6e2013-03-12 10:25:50 -07001114 act = ofp.action.set_vlan_pcp()
Rich Laned0478ff2013-03-11 12:46:58 -07001115 act.vlan_pcp = mod_field_vals['vlan_pcp']
Dan Talayco4b2bee62010-07-20 14:10:05 -07001116 elif field_to_mod == 'ip_src':
Rich Lanee717c6e2013-03-12 10:25:50 -07001117 act = ofp.action.set_nw_src()
Rich Lanef6883512013-03-11 17:00:09 -07001118 act.nw_addr = oftest.parse.parse_ip(mod_field_vals['ip_src'])
Dan Talayco4b2bee62010-07-20 14:10:05 -07001119 elif field_to_mod == 'ip_dst':
Rich Lanee717c6e2013-03-12 10:25:50 -07001120 act = ofp.action.set_nw_dst()
Rich Lanef6883512013-03-11 17:00:09 -07001121 act.nw_addr = oftest.parse.parse_ip(mod_field_vals['ip_dst'])
Dan Talayco4b2bee62010-07-20 14:10:05 -07001122 elif field_to_mod == 'ip_tos':
Rich Lanee717c6e2013-03-12 10:25:50 -07001123 act = ofp.action.set_nw_tos()
Dan Talayco4b2bee62010-07-20 14:10:05 -07001124 act.nw_tos = mod_field_vals['ip_tos']
1125 elif field_to_mod == 'tcp_sport':
Rich Lanee717c6e2013-03-12 10:25:50 -07001126 act = ofp.action.set_tp_src()
Dan Talayco4b2bee62010-07-20 14:10:05 -07001127 act.tp_port = mod_field_vals['tcp_sport']
1128 elif field_to_mod == 'tcp_dport':
Rich Lanee717c6e2013-03-12 10:25:50 -07001129 act = ofp.action.set_tp_dst()
Dan Talayco4b2bee62010-07-20 14:10:05 -07001130 act.tp_port = mod_field_vals['tcp_dport']
Rich Lane110e0e32012-10-26 16:21:46 -07001131 elif field_to_mod == 'udp_sport':
Rich Lanee717c6e2013-03-12 10:25:50 -07001132 act = ofp.action.set_tp_src()
Rich Lane110e0e32012-10-26 16:21:46 -07001133 act.tp_port = mod_field_vals['udp_sport']
1134 elif field_to_mod == 'udp_dport':
Rich Lanee717c6e2013-03-12 10:25:50 -07001135 act = ofp.action.set_tp_dst()
Rich Lane110e0e32012-10-26 16:21:46 -07001136 act.tp_port = mod_field_vals['udp_dport']
Dan Talayco4b2bee62010-07-20 14:10:05 -07001137 else:
1138 parent.assertTrue(0, "Unknown field to modify: " + str(field_to_mod))
1139
1140 return act
1141
1142def pkt_action_setup(parent, start_field_vals={}, mod_field_vals={},
Rich Lane110e0e32012-10-26 16:21:46 -07001143 mod_fields=[], tp="tcp", check_test_params=False):
Dan Talayco4b2bee62010-07-20 14:10:05 -07001144 """
1145 Set up the ingress and expected packet and action list for a test
1146
Rich Lane2014f9b2012-10-05 15:29:40 -07001147 @param parent Must implement assertTrue
Dan Talayco4b2bee62010-07-20 14:10:05 -07001148 @param start_field_values Field values to use for ingress packet (optional)
1149 @param mod_field_values Field values to use for modified packet (optional)
1150 @param mod_fields The list of fields to be modified by the switch in the test.
1151 @params check_test_params If True, will check the parameters vid, add_vlan
1152 and strip_vlan from the command line.
1153
1154 Returns a triple: pkt-to-send, expected-pkt, action-list
1155 """
1156
1157 new_actions = []
1158
Dan Talayco4b2bee62010-07-20 14:10:05 -07001159 base_pkt_params = {}
1160 base_pkt_params['pktlen'] = 100
Rich Laned0478ff2013-03-11 12:46:58 -07001161 base_pkt_params['eth_dst'] = '00:DE:F0:12:34:56'
1162 base_pkt_params['eth_src'] = '00:23:45:67:89:AB'
Dan Talayco4b2bee62010-07-20 14:10:05 -07001163 base_pkt_params['dl_vlan_enable'] = False
Rich Laned0478ff2013-03-11 12:46:58 -07001164 base_pkt_params['vlan_vid'] = 2
1165 base_pkt_params['vlan_pcp'] = 0
Dan Talayco4b2bee62010-07-20 14:10:05 -07001166 base_pkt_params['ip_src'] = '192.168.0.1'
1167 base_pkt_params['ip_dst'] = '192.168.0.2'
1168 base_pkt_params['ip_tos'] = 0
Rich Lane110e0e32012-10-26 16:21:46 -07001169 if tp == "tcp":
1170 base_pkt_params['tcp_sport'] = 1234
1171 base_pkt_params['tcp_dport'] = 80
1172 elif tp == "udp":
1173 base_pkt_params['udp_sport'] = 1234
1174 base_pkt_params['udp_dport'] = 80
Dan Talayco4b2bee62010-07-20 14:10:05 -07001175 for keyname in start_field_vals.keys():
1176 base_pkt_params[keyname] = start_field_vals[keyname]
1177
1178 mod_pkt_params = {}
1179 mod_pkt_params['pktlen'] = 100
Rich Laned0478ff2013-03-11 12:46:58 -07001180 mod_pkt_params['eth_dst'] = '00:21:0F:ED:CB:A9'
1181 mod_pkt_params['eth_src'] = '00:ED:CB:A9:87:65'
Dan Talayco4b2bee62010-07-20 14:10:05 -07001182 mod_pkt_params['dl_vlan_enable'] = False
Rich Laned0478ff2013-03-11 12:46:58 -07001183 mod_pkt_params['vlan_vid'] = 3
1184 mod_pkt_params['vlan_pcp'] = 7
Dan Talayco4b2bee62010-07-20 14:10:05 -07001185 mod_pkt_params['ip_src'] = '10.20.30.40'
1186 mod_pkt_params['ip_dst'] = '50.60.70.80'
1187 mod_pkt_params['ip_tos'] = 0xf0
Rich Lane110e0e32012-10-26 16:21:46 -07001188 if tp == "tcp":
1189 mod_pkt_params['tcp_sport'] = 4321
1190 mod_pkt_params['tcp_dport'] = 8765
1191 elif tp == "udp":
1192 mod_pkt_params['udp_sport'] = 4321
1193 mod_pkt_params['udp_dport'] = 8765
Dan Talayco4b2bee62010-07-20 14:10:05 -07001194 for keyname in mod_field_vals.keys():
1195 mod_pkt_params[keyname] = mod_field_vals[keyname]
1196
1197 # Check for test param modifications
1198 strip = False
1199 if check_test_params:
Rich Lane2014f9b2012-10-05 15:29:40 -07001200 add_vlan = test_param_get('add_vlan')
1201 strip_vlan = test_param_get('strip_vlan')
1202 vid = test_param_get('vid')
Dan Talayco4b2bee62010-07-20 14:10:05 -07001203
1204 if add_vlan and strip_vlan:
1205 parent.assertTrue(0, "Add and strip VLAN both specified")
1206
1207 if vid:
1208 base_pkt_params['dl_vlan_enable'] = True
Rich Laned0478ff2013-03-11 12:46:58 -07001209 base_pkt_params['vlan_vid'] = vid
1210 if 'vlan_vid' in mod_fields:
1211 mod_pkt_params['vlan_vid'] = vid + 1
Dan Talayco4b2bee62010-07-20 14:10:05 -07001212
1213 if add_vlan:
1214 base_pkt_params['dl_vlan_enable'] = False
1215 mod_pkt_params['dl_vlan_enable'] = True
1216 mod_pkt_params['pktlen'] = base_pkt_params['pktlen'] + 4
1217 mod_fields.append('pktlen')
1218 mod_fields.append('dl_vlan_enable')
Rich Laned0478ff2013-03-11 12:46:58 -07001219 if 'vlan_vid' not in mod_fields:
1220 mod_fields.append('vlan_vid')
Dan Talayco4b2bee62010-07-20 14:10:05 -07001221 elif strip_vlan:
1222 base_pkt_params['dl_vlan_enable'] = True
1223 mod_pkt_params['dl_vlan_enable'] = False
1224 mod_pkt_params['pktlen'] = base_pkt_params['pktlen'] - 4
1225 mod_fields.append('dl_vlan_enable')
1226 mod_fields.append('pktlen')
1227
Rich Lane110e0e32012-10-26 16:21:46 -07001228 if tp == "tcp":
1229 packet_builder = simple_tcp_packet
1230 elif tp == "udp":
1231 packet_builder = simple_udp_packet
1232 else:
1233 raise NotImplementedError("unknown transport protocol %s" % tp)
1234
Dan Talayco4b2bee62010-07-20 14:10:05 -07001235 # Build the ingress packet
Rich Lane110e0e32012-10-26 16:21:46 -07001236 ingress_pkt = packet_builder(**base_pkt_params)
Dan Talayco4b2bee62010-07-20 14:10:05 -07001237
1238 # Build the expected packet, modifying the indicated fields
1239 for item in mod_fields:
1240 base_pkt_params[item] = mod_pkt_params[item]
1241 act = action_generate(parent, item, mod_pkt_params)
1242 if act:
1243 new_actions.append(act)
1244
Rich Lane110e0e32012-10-26 16:21:46 -07001245 expected_pkt = packet_builder(**base_pkt_params)
Dan Talayco4b2bee62010-07-20 14:10:05 -07001246
1247 return (ingress_pkt, expected_pkt, new_actions)
Dan Talayco677c0b72011-08-23 22:53:38 -07001248
1249# Generate a simple "drop" flow mod
1250# If in_band is true, then only drop from first test port
1251def flow_mod_gen(port_map, in_band):
Rich Lanee717c6e2013-03-12 10:25:50 -07001252 request = ofp.message.flow_add()
1253 request.match.wildcards = ofp.OFPFW_ALL
Dan Talayco677c0b72011-08-23 22:53:38 -07001254 if in_band:
Rich Lanee717c6e2013-03-12 10:25:50 -07001255 request.match.wildcards = ofp.OFPFW_ALL - ofp.OFPFW_IN_PORT
Dan Talayco677c0b72011-08-23 22:53:38 -07001256 for of_port, ifname in port_map.items(): # Grab first port
1257 break
1258 request.match.in_port = of_port
1259 request.buffer_id = 0xffffffff
1260 return request
Dan Talaycoba3745c2010-07-21 21:51:08 -07001261
1262def skip_message_emit(parent, s):
1263 """
1264 Print out a 'skipped' message to stderr
1265
1266 @param s The string to print out to the log file
Dan Talaycoba3745c2010-07-21 21:51:08 -07001267 """
1268 global skipped_test_count
1269
1270 skipped_test_count += 1
Rich Lane9a003812012-10-04 17:17:59 -07001271 logging.info("Skipping: " + s)
Dan Talayco2940fdd2013-02-06 15:01:35 -08001272 if oftest.config["debug"] < logging.WARNING:
Dan Talaycoba3745c2010-07-21 21:51:08 -07001273 sys.stderr.write("(skipped) ")
1274 else:
1275 sys.stderr.write("(S)")
Dan Talayco677c0b72011-08-23 22:53:38 -07001276
Dan Talayco8a64e332012-03-28 14:53:20 -07001277
1278def all_stats_get(parent):
1279 """
1280 Get the aggregate stats for all flows in the table
1281 @param parent Test instance with controller connection and assert
1282 @returns dict with keys flows, packets, bytes, active (flows),
1283 lookups, matched
1284 """
Rich Lanee717c6e2013-03-12 10:25:50 -07001285 stat_req = ofp.message.aggregate_stats_request()
1286 stat_req.match = ofp.match()
1287 stat_req.match.wildcards = ofp.OFPFW_ALL
Dan Talayco8a64e332012-03-28 14:53:20 -07001288 stat_req.table_id = 0xff
Rich Lanee717c6e2013-03-12 10:25:50 -07001289 stat_req.out_port = ofp.OFPP_NONE
Dan Talayco8a64e332012-03-28 14:53:20 -07001290
1291 rv = {}
1292
Rich Lanec8aaa3e2012-07-26 19:28:02 -07001293 (reply, pkt) = parent.controller.transact(stat_req)
Rich Lane5fd6faf2013-03-11 13:30:20 -07001294 parent.assertTrue(len(reply.entries) == 1, "Did not receive flow stats reply")
Dan Talayco8a64e332012-03-28 14:53:20 -07001295
Rich Lane5fd6faf2013-03-11 13:30:20 -07001296 for obj in reply.entries:
Dan Talayco8a64e332012-03-28 14:53:20 -07001297 (rv["flows"], rv["packets"], rv["bytes"]) = (obj.flow_count,
1298 obj.packet_count, obj.byte_count)
1299 break
1300
Rich Lanee717c6e2013-03-12 10:25:50 -07001301 request = ofp.message.table_stats_request()
Rich Lanec8aaa3e2012-07-26 19:28:02 -07001302 (reply , pkt) = parent.controller.transact(request)
Dan Talayco8a64e332012-03-28 14:53:20 -07001303
1304
1305 (rv["active"], rv["lookups"], rv["matched"]) = (0,0,0)
Rich Lane5fd6faf2013-03-11 13:30:20 -07001306 for obj in reply.entries:
Dan Talayco8a64e332012-03-28 14:53:20 -07001307 rv["active"] += obj.active_count
1308 rv["lookups"] += obj.lookup_count
1309 rv["matched"] += obj.matched_count
1310
1311 return rv
Dan Talayco2baf8b52012-03-30 09:55:42 -07001312
Rich Lane7744e112013-01-11 17:23:57 -08001313_import_blacklist.add('FILTER')
Dan Talayco2baf8b52012-03-30 09:55:42 -07001314FILTER=''.join([(len(repr(chr(x)))==3) and chr(x) or '.'
1315 for x in range(256)])
1316
1317def hex_dump_buffer(src, length=16):
1318 """
1319 Convert src to a hex dump string and return the string
1320 @param src The source buffer
1321 @param length The number of bytes shown in each line
1322 @returns A string showing the hex dump
1323 """
Dan Talaycoc516fa02012-04-12 22:28:43 -07001324 result = ["\n"]
Dan Talayco2baf8b52012-03-30 09:55:42 -07001325 for i in xrange(0, len(src), length):
1326 chars = src[i:i+length]
1327 hex = ' '.join(["%02x" % ord(x) for x in chars])
1328 printable = ''.join(["%s" % ((ord(x) <= 127 and
1329 FILTER[ord(x)]) or '.') for x in chars])
1330 result.append("%04x %-*s %s\n" % (i, length*3, hex, printable))
1331 return ''.join(result)
1332
1333def format_packet(pkt):
1334 return "Packet length %d \n%s" % (len(str(pkt)),
1335 hex_dump_buffer(str(pkt)))
Rich Lane5d7e89a2012-10-26 16:43:13 -07001336
1337def inspect_packet(pkt):
1338 """
1339 Wrapper around scapy's show() method.
1340 @returns A string showing the dissected packet.
1341 """
1342 from cStringIO import StringIO
1343 out = None
1344 backup = sys.stdout
1345 try:
Rich Lanefdec0fb2013-08-09 18:01:05 -07001346 tmp = StringIO()
1347 sys.stdout = tmp
Rich Lane5d7e89a2012-10-26 16:43:13 -07001348 pkt.show2()
Rich Lanefdec0fb2013-08-09 18:01:05 -07001349 out = tmp.getvalue()
1350 tmp.close()
Rich Lane5d7e89a2012-10-26 16:43:13 -07001351 finally:
1352 sys.stdout = backup
1353 return out
Rich Lane0a4f6372013-01-02 14:40:22 -08001354
1355def nonstandard(cls):
1356 """
Rich Lanecc45b8e2013-01-02 15:55:02 -08001357 Testcase decorator that marks the test as being non-standard.
1358 These tests are not automatically added to the "standard" group.
Rich Lane0a4f6372013-01-02 14:40:22 -08001359 """
Rich Lanecc45b8e2013-01-02 15:55:02 -08001360 cls._nonstandard = True
Rich Lane0a4f6372013-01-02 14:40:22 -08001361 return cls
1362
1363def disabled(cls):
1364 """
Rich Lanecc45b8e2013-01-02 15:55:02 -08001365 Testcase decorator that marks the test as being disabled.
1366 These tests are not automatically added to the "standard" group or
1367 their module's group.
Rich Lane0a4f6372013-01-02 14:40:22 -08001368 """
Rich Lanecc45b8e2013-01-02 15:55:02 -08001369 cls._disabled = True
Rich Lane0a4f6372013-01-02 14:40:22 -08001370 return cls
Rich Lane97e99652013-01-02 17:23:20 -08001371
1372def group(name):
1373 """
1374 Testcase decorator that adds the test to a group.
1375 """
1376 def fn(cls):
1377 if not hasattr(cls, "_groups"):
1378 cls._groups = []
1379 cls._groups.append(name)
1380 return cls
1381 return fn
Rich Lane5a9a1922013-01-11 14:29:30 -08001382
1383def version(ver):
1384 """
1385 Testcase decorator that specifies which versions of OpenFlow the test
1386 supports. The default is 1.0+. This decorator may only be used once.
1387
1388 Supported syntax:
1389 1.0 -> 1.0
1390 1.0,1.2,1.3 -> 1.0, 1.2, 1.3
1391 1.0+ -> 1.0, 1.1, 1.2, 1.3
1392 """
1393 versions = parse_version(ver)
1394 def fn(cls):
1395 cls._versions = versions
1396 return cls
1397 return fn
1398
1399def parse_version(ver):
1400 allowed_versions = ["1.0", "1.1", "1.2", "1.3"]
1401 if re.match("^1\.\d+$", ver):
1402 versions = set([ver])
1403 elif re.match("^(1\.\d+)\+$", ver):
1404 if not ver[:-1] in allowed_versions:
1405 raise ValueError("invalid OpenFlow version %s" % ver[:-1])
1406 versions = set()
1407 if ver != "1.1+": versions.add("1.0")
1408 if ver != "1.2+": versions.add("1.1")
1409 if ver != "1.3+": versions.add("1.2")
1410 versions.add("1.3")
1411 else:
1412 versions = set(ver.split(','))
1413
1414 for version in versions:
1415 if not version in allowed_versions:
1416 raise ValueError("invalid OpenFlow version %s" % version)
1417
1418 return versions
1419
1420assert(parse_version("1.0") == set(["1.0"]))
1421assert(parse_version("1.0,1.2,1.3") == set(["1.0", "1.2", "1.3"]))
1422assert(parse_version("1.0+") == set(["1.0", "1.1", "1.2", "1.3"]))
Rich Lane7744e112013-01-11 17:23:57 -08001423
Rich Laneae3428c2013-03-07 14:37:42 -08001424def get_stats(test, req):
1425 """
1426 Retrieve a list of stats entries. Handles OFPSF_REPLY_MORE.
1427 """
Rich Lane609194f2013-10-21 06:17:37 -07001428 msgtype = ofp.OFPT_STATS_REPLY
1429 more_flag = ofp.OFPSF_REPLY_MORE
Rich Laneae3428c2013-03-07 14:37:42 -08001430 stats = []
1431 reply, _ = test.controller.transact(req)
1432 test.assertTrue(reply is not None, "No response to stats request")
Rich Lane34c68d52013-10-11 10:38:21 -07001433 test.assertEquals(reply.type, msgtype, "Response had unexpected message type")
Rich Lane5fd6faf2013-03-11 13:30:20 -07001434 stats.extend(reply.entries)
Rich Lanebd56ed62013-07-10 15:49:44 -07001435 while reply.flags & more_flag != 0:
Rich Lane34c68d52013-10-11 10:38:21 -07001436 reply, pkt = test.controller.poll(exp_msg=msgtype)
Rich Laneae3428c2013-03-07 14:37:42 -08001437 test.assertTrue(reply is not None, "No response to stats request")
Rich Lane5fd6faf2013-03-11 13:30:20 -07001438 stats.extend(reply.entries)
Rich Laneae3428c2013-03-07 14:37:42 -08001439 return stats
1440
Rich Lanebd56ed62013-07-10 15:49:44 -07001441def get_flow_stats(test, match, table_id=None,
1442 out_port=None, out_group=None,
1443 cookie=0, cookie_mask=0):
Rich Laneae3428c2013-03-07 14:37:42 -08001444 """
1445 Retrieve a list of flow stats entries.
1446 """
Rich Lanebd56ed62013-07-10 15:49:44 -07001447
1448 if table_id == None:
1449 if ofp.OFP_VERSION <= 2:
1450 table_id = 0xff
1451 else:
1452 table_id = ofp.OFPTT_ALL
1453
Rich Lanef3bc48c2013-05-03 17:39:35 -07001454 if out_port == None:
Rich Lanebd56ed62013-07-10 15:49:44 -07001455 if ofp.OFP_VERSION == 1:
1456 out_port = ofp.OFPP_NONE
1457 else:
1458 out_port = ofp.OFPP_ANY
1459
1460 if out_group == None:
1461 if ofp.OFP_VERSION > 1:
1462 out_group = ofp.OFPP_ANY
1463
Rich Lanee717c6e2013-03-12 10:25:50 -07001464 req = ofp.message.flow_stats_request(match=match,
Rich Lanebd56ed62013-07-10 15:49:44 -07001465 table_id=table_id,
1466 out_port=out_port)
1467 if ofp.OFP_VERSION > 1:
1468 req.out_group = out_group
1469 req.cookie = cookie
1470 req.cookie_mask = cookie_mask
1471
Rich Laneae3428c2013-03-07 14:37:42 -08001472 return get_stats(test, req)
1473
Rich Lane968b6192013-03-07 15:34:43 -08001474def get_port_stats(test, port_no):
1475 """
1476 Retrieve a list of port stats entries.
1477 """
Rich Lanee717c6e2013-03-12 10:25:50 -07001478 req = ofp.message.port_stats_request(port_no=port_no)
Rich Lane968b6192013-03-07 15:34:43 -08001479 return get_stats(test, req)
1480
Rich Lane6a334922013-03-07 16:14:52 -08001481def get_queue_stats(test, port_no, queue_id):
1482 """
1483 Retrieve a list of queue stats entries.
1484 """
Rich Lanee717c6e2013-03-12 10:25:50 -07001485 req = ofp.message.queue_stats_request(port_no=port_no, queue_id=queue_id)
Rich Lane6a334922013-03-07 16:14:52 -08001486 return get_stats(test, req)
1487
Rich Laneae3428c2013-03-07 14:37:42 -08001488def verify_flow_stats(test, match, table_id=0xff,
Rich Laneae3428c2013-03-07 14:37:42 -08001489 initial=[],
1490 pkts=None, bytes=None):
1491 """
1492 Verify that flow stats changed as expected.
1493
1494 Optionally takes an 'initial' list of stats entries, as returned by
1495 get_flow_stats(). If 'initial' is not given the counters are assumed to
1496 begin at 0.
1497 """
Rich Lanef3bc48c2013-05-03 17:39:35 -07001498
Rich Laneae3428c2013-03-07 14:37:42 -08001499 def accumulate(stats):
1500 pkts_acc = bytes_acc = 0
1501 for stat in stats:
1502 pkts_acc += stat.packet_count
1503 bytes_acc += stat.byte_count
1504 return (pkts_acc, bytes_acc)
1505
1506 pkts_before, bytes_before = accumulate(initial)
1507
1508 # Wait 10s for counters to update
1509 pkt_diff = byte_diff = None
1510 for i in range(0, 100):
Rich Lane61edad52014-03-28 16:25:08 -07001511 stats = get_flow_stats(test, match, table_id=table_id)
Rich Laneae3428c2013-03-07 14:37:42 -08001512 pkts_after, bytes_after = accumulate(stats)
1513 pkt_diff = pkts_after - pkts_before
1514 byte_diff = bytes_after - bytes_before
1515 if (pkts == None or pkt_diff >= pkts) and \
1516 (bytes == None or byte_diff >= bytes):
1517 break
Dan Talayco53724732013-03-08 23:54:02 -08001518 time.sleep(0.1)
Rich Laneae3428c2013-03-07 14:37:42 -08001519
1520 if pkts != None:
1521 test.assertEquals(pkt_diff, pkts, "Flow packet counter not updated properly (expected increase of %d, got increase of %d)" % (pkts, pkt_diff))
1522
1523 if bytes != None:
Rich Lane53b96812013-03-07 16:54:50 -08001524 test.assertTrue(byte_diff >= bytes and byte_diff <= bytes*1.1,
1525 "Flow byte counter not updated properly (expected increase of %d, got increase of %d)" % (bytes, byte_diff))
Rich Laneae3428c2013-03-07 14:37:42 -08001526
Rich Lane968b6192013-03-07 15:34:43 -08001527def verify_port_stats(test, port,
1528 initial=[],
1529 tx_pkts=None, rx_pkts=None,
1530 tx_bytes=None, rx_bytes=None):
1531 """
1532 Verify that port stats changed as expected.
1533
1534 Optionally takes an 'initial' list of stats entries, as returned by
1535 get_port_stats(). If 'initial' is not given the counters are assumed to
1536 begin at 0.
1537 """
1538 def accumulate(stats):
1539 tx_pkts_acc = rx_pkts_acc = tx_bytes_acc = rx_bytes_acc = 0
1540 for stat in stats:
1541 tx_pkts_acc += stat.tx_packets
1542 rx_pkts_acc += stat.rx_packets
1543 tx_bytes_acc += stat.tx_bytes
1544 rx_bytes_acc += stat.rx_bytes
1545 return (tx_pkts_acc, rx_pkts_acc, tx_bytes_acc, rx_bytes_acc)
1546
1547 tx_pkts_before, rx_pkts_before, \
1548 tx_bytes_before, rx_bytes_before = accumulate(initial)
1549
1550 # Wait 10s for counters to update
1551 for i in range(0, 100):
1552 stats = get_port_stats(test, port)
1553 tx_pkts_after, rx_pkts_after, \
1554 tx_bytes_after, rx_bytes_after = accumulate(stats)
1555 tx_pkts_diff = tx_pkts_after - tx_pkts_before
1556 rx_pkts_diff = rx_pkts_after - rx_pkts_before
1557 tx_bytes_diff = tx_bytes_after - tx_bytes_before
1558 rx_bytes_diff = rx_bytes_after - rx_bytes_before
Rich Lane3a208f82015-04-10 12:37:57 -07001559 if (tx_pkts == None or tx_pkts <= tx_pkts_diff) and \
1560 (rx_pkts == None or rx_pkts <= rx_pkts_diff) and \
Rich Lane53b96812013-03-07 16:54:50 -08001561 (tx_bytes == None or tx_bytes <= tx_bytes_diff) and \
1562 (rx_bytes == None or rx_bytes <= rx_bytes_diff):
Rich Lane968b6192013-03-07 15:34:43 -08001563 break
1564 time.sleep(0.1)
1565
1566 if (tx_pkts != None):
Rich Lane3a208f82015-04-10 12:37:57 -07001567 test.assertGreaterEqual(tx_pkts_diff, tx_pkts,
1568 "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 -08001569 if (rx_pkts != None):
Rich Lane3a208f82015-04-10 12:37:57 -07001570 test.assertGreaterEqual(rx_pkts_diff, rx_pkts,
1571 "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 -08001572 if (tx_bytes != None):
Rich Lane3a208f82015-04-10 12:37:57 -07001573 test.assertGreaterEqual(tx_bytes_diff, tx_bytes,
1574 "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 -08001575 if (rx_bytes != None):
Rich Lane3a208f82015-04-10 12:37:57 -07001576 test.assertGreaterEqual(rx_bytes_diff, rx_bytes,
1577 "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 -08001578
Rich Lane6a334922013-03-07 16:14:52 -08001579def verify_queue_stats(test, port_no, queue_id,
1580 initial=[],
1581 pkts=None, bytes=None):
1582 """
1583 Verify that queue stats changed as expected.
1584
1585 Optionally takes an 'initial' list of stats entries, as returned by
1586 get_queue_stats(). If 'initial' is not given the counters are assumed to
1587 begin at 0.
1588 """
1589 def accumulate(stats):
1590 pkts_acc = bytes_acc = 0
1591 for stat in stats:
1592 pkts_acc += stat.tx_packets
1593 bytes_acc += stat.tx_bytes
1594 return (pkts_acc, bytes_acc)
1595
1596 pkts_before, bytes_before = accumulate(initial)
1597
1598 # Wait 10s for counters to update
1599 pkt_diff = byte_diff = None
1600 for i in range(0, 100):
1601 stats = get_queue_stats(test, port_no, queue_id)
1602 pkts_after, bytes_after = accumulate(stats)
1603 pkt_diff = pkts_after - pkts_before
1604 byte_diff = bytes_after - bytes_before
1605 if (pkts == None or pkt_diff >= pkts) and \
1606 (bytes == None or byte_diff >= bytes):
1607 break
Dan Talayco53724732013-03-08 23:54:02 -08001608 time.sleep(0.1)
Rich Lane6a334922013-03-07 16:14:52 -08001609
1610 if pkts != None:
1611 test.assertEquals(pkt_diff, pkts, "Queue packet counter not updated properly (expected increase of %d, got increase of %d)" % (pkts, pkt_diff))
1612
1613 if bytes != None:
Rich Lane53b96812013-03-07 16:54:50 -08001614 test.assertTrue(byte_diff >= bytes and byte_diff <= bytes*1.1,
1615 "Queue byte counter not updated properly (expected increase of %d, got increase of %d)" % (bytes, byte_diff))
Rich Laneae3428c2013-03-07 14:37:42 -08001616
Rich Lane4c504f32013-06-07 17:24:14 -07001617def packet_in_match(msg, data, in_port=None, reason=None):
1618 """
1619 Check whether the packet_in message 'msg' has fields matching 'data',
1620 'in_port', and 'reason'.
1621
1622 This function handles truncated packet_in data. The 'in_port' and 'reason'
1623 parameters are optional.
1624
1625 @param msg packet_in message
1626 @param data Expected packet_in data
1627 @param in_port Expected packet_in in_port, or None
1628 @param reason Expected packet_in reason, or None
1629 """
1630
Rich Lanec0d26dd2013-07-10 12:46:03 -07001631 if ofp.OFP_VERSION <= 2:
1632 pkt_in_port = msg.in_port
1633 else:
1634 oxms = { type(oxm): oxm for oxm in msg.match.oxm_list }
1635 if ofp.oxm.in_port in oxms:
1636 pkt_in_port = oxms[ofp.oxm.in_port].value
1637 else:
1638 logging.warn("Missing in_port in packet-in message")
1639 pkt_in_port = None
1640
1641 if in_port != None and in_port != pkt_in_port:
Rich Lane9f2f17e2013-09-13 13:19:37 -07001642 logging.debug("Incorrect packet_in in_port (expected %d, received %d)", in_port, pkt_in_port)
Rich Lane4c504f32013-06-07 17:24:14 -07001643 return False
1644
Rich Lanec0d26dd2013-07-10 12:46:03 -07001645 if reason != None and reason != msg.reason:
Rich Lane4c504f32013-06-07 17:24:14 -07001646 logging.debug("Incorrect packet_in reason (expected %d, received %d)", reason, msg.reason)
1647 return False
1648
1649 # Check that one of the packets is a prefix of the other.
1650 # The received packet may be either truncated or padded, but not both.
1651 # (Some of the padding may be truncated but that's irrelevant). We
1652 # need to check that the smaller packet is a prefix of the larger one.
1653 # Note that this check succeeds if the switch sends a zero-length
1654 # packet-in.
1655 compare_len = min(len(msg.data), len(data))
1656 if data[:compare_len] != msg.data[:compare_len]:
1657 logging.debug("Incorrect packet_in data")
1658 logging.debug("Expected %s" % format_packet(data[:compare_len]))
1659 logging.debug("Received %s" % format_packet(msg.data[:compare_len]))
1660 return False
1661
1662 return True
1663
1664def verify_packet_in(test, data, in_port, reason, controller=None):
1665 """
1666 Assert that the controller receives a packet_in message matching data 'data'
1667 from port 'in_port' with reason 'reason'. Does not trigger the packet_in
1668 itself, that's up to the test case.
1669
1670 @param test Instance of base_tests.SimpleProtocol
1671 @param pkt String to expect as the packet_in data
1672 @param in_port OpenFlow port number to expect as the packet_in in_port
1673 @param reason One of OFPR_* to expect as the packet_in reason
1674 @param controller Controller instance, defaults to test.controller
1675 @returns The received packet-in message
1676 """
1677
1678 if controller == None:
1679 controller = test.controller
1680
1681 end_time = time.time() + oftest.ofutils.default_timeout
1682
1683 while True:
1684 msg, _ = controller.poll(ofp.OFPT_PACKET_IN, end_time - time.time())
1685 if not msg:
1686 # Timeout
1687 break
1688 elif packet_in_match(msg, data, in_port, reason):
1689 # Found a matching message
1690 break
1691
Kiran Poola58c5c042014-05-15 15:11:06 -07001692 test.assertTrue(msg is not None, 'Packet in message not received on port %r' % in_port)
Rich Lane4c504f32013-06-07 17:24:14 -07001693 return msg
1694
1695def verify_no_packet_in(test, data, in_port, controller=None):
1696 """
1697 Assert that the controller does not receive a packet_in message matching
1698 data 'data' from port 'in_port'.
1699
1700 @param test Instance of base_tests.SimpleProtocol
1701 @param pkt String to expect as the packet_in data
1702 @param in_port OpenFlow port number to expect as the packet_in in_port
1703 @param controller Controller instance, defaults to test.controller
1704 """
1705
1706 if controller == None:
1707 controller = test.controller
1708
1709 # Negative test, need to wait a short amount of time before checking we
1710 # didn't receive the message.
Rich Lane48f6aed2014-03-23 15:51:02 -07001711 time.sleep(oftest.ofutils.default_negative_timeout)
Rich Lane4c504f32013-06-07 17:24:14 -07001712
1713 # Check every packet_in queued in the controller
1714 while True:
1715 msg, _ = controller.poll(ofp.OFPT_PACKET_IN, timeout=0)
1716 if msg == None:
1717 # No more queued packet_in messages
1718 break
1719 elif packet_in_match(msg, data, in_port, None):
1720 # Found a matching message
1721 break
1722
Rich Lane82c882d2013-08-09 17:13:52 -07001723 if in_port == None:
1724 test.assertTrue(msg == None, "Did not expect a packet-in message on any port")
1725 else:
1726 test.assertTrue(msg == None, "Did not expect a packet-in message on port %d" % in_port)
Rich Lane4c504f32013-06-07 17:24:14 -07001727
Rich Lane045db072013-08-06 13:16:30 -07001728def openflow_ports(num=None):
1729 """
1730 Return a list of 'num' OpenFlow port numbers
1731
1732 If 'num' is None, return all available ports. Otherwise, limit the length
1733 of the result to 'num' and raise an exception if not enough ports are
1734 available.
1735 """
1736 ports = sorted(oftest.config["port_map"].keys())
1737 if num != None and len(ports) < num:
1738 raise Exception("test requires %d ports but only %d are available" % (num, len(ports)))
1739 return ports[:num]
1740
Rich Lanee4b384d2013-09-13 14:33:40 -07001741def verify_packet(test, pkt, ofport):
1742 """
1743 Check that an expected packet is received
1744 """
1745 logging.debug("Checking for pkt on port %r", ofport)
1746 (rcv_port, rcv_pkt, pkt_time) = test.dataplane.poll(port_number=ofport, exp_pkt=str(pkt))
1747 test.assertTrue(rcv_pkt != None, "Did not receive pkt on %r" % ofport)
macauley17cd60d2015-07-27 17:41:18 +08001748 return (rcv_port, rcv_pkt, pkt_time)
1749
Rich Lanee4b384d2013-09-13 14:33:40 -07001750def verify_no_packet(test, pkt, ofport):
1751 """
1752 Check that a particular packet is not received
1753 """
1754 logging.debug("Negative check for pkt on port %r", ofport)
Rich Lane48f6aed2014-03-23 15:51:02 -07001755 (rcv_port, rcv_pkt, pkt_time) = \
1756 test.dataplane.poll(
1757 port_number=ofport, exp_pkt=str(pkt),
1758 timeout=oftest.ofutils.default_negative_timeout)
Rich Lanee4b384d2013-09-13 14:33:40 -07001759 test.assertTrue(rcv_pkt == None, "Received packet on %r" % ofport)
1760
1761def verify_no_other_packets(test):
1762 """
1763 Check that no unexpected packets are received
1764
1765 This is a no-op if the --relax option is in effect.
1766 """
1767 if oftest.config["relax"]:
1768 return
1769 logging.debug("Checking for unexpected packets on all ports")
Rich Lane48f6aed2014-03-23 15:51:02 -07001770 (rcv_port, rcv_pkt, pkt_time) = test.dataplane.poll(timeout=oftest.ofutils.default_negative_timeout)
Rich Lanee4b384d2013-09-13 14:33:40 -07001771 if rcv_pkt != None:
1772 logging.debug("Received unexpected packet on port %r: %s", rcv_port, format_packet(rcv_pkt))
1773 test.assertTrue(rcv_pkt == None, "Unexpected packet on port %r" % rcv_port)
1774
1775def verify_packets(test, pkt, ofports):
1776 """
1777 Check that a packet is received on certain ports
1778
1779 Also verifies that the packet is not received on any other ports, and that no
1780 other packets are received (unless --relax is in effect).
1781
1782 This covers the common and simplest cases for checking dataplane outputs.
1783 For more complex usage, like multiple different packets being output, or
1784 multiple packets on the same port, use the primitive verify_packet,
1785 verify_no_packet, and verify_no_other_packets functions directly.
1786 """
1787 pkt = str(pkt)
1788 for ofport in openflow_ports():
1789 if ofport in ofports:
1790 verify_packet(test, pkt, ofport)
1791 else:
1792 verify_no_packet(test, pkt, ofport)
1793 verify_no_other_packets(test)
1794
Rich Lane12d04592013-10-10 17:21:07 -07001795def verify_no_errors(ctrl):
1796 error, _ = ctrl.poll(ofp.OFPT_ERROR, 0)
1797 if error:
1798 raise AssertionError("unexpected error type=%d code=%d" % (error.err_type, error.code))
Rich Lanee4b384d2013-09-13 14:33:40 -07001799
Jonathan Stoutfcee3142014-01-28 15:46:22 -05001800def verify_capability(test, capability):
1801 """
Jonathan Stout073642d2014-02-04 13:41:48 -05001802 Return True if DUT supports the specified capability.
Jonathan Stoutfcee3142014-01-28 15:46:22 -05001803
1804 @param test Instance of base_tests.SimpleProtocol
1805 @param capability One of ofp_capabilities.
1806 """
1807 logging.info("Verifing that capability code is valid.")
1808 test.assertIn(capability, ofp.const.ofp_capabilities_map,
1809 "Capability code %d does not exist." % capability)
1810 capability_str = ofp.const.ofp_capabilities_map[capability]
1811
1812 logging.info(("Sending features_request to test if capability "
Jonathan Stout97e458a2014-01-28 16:08:04 -05001813 "%s is supported."), capability_str)
Jonathan Stoutfcee3142014-01-28 15:46:22 -05001814 req = ofp.message.features_request()
1815 res, raw = test.controller.transact(req)
1816 test.assertIsNotNone(res, "Did not receive a response from the DUT.")
1817 test.assertEqual(res.type, ofp.OFPT_FEATURES_REPLY,
1818 ("Unexpected packet type %d received in response to "
1819 "OFPT_FEATURES_REQUEST") % res.type)
Jonathan Stout641167f2014-02-04 12:07:10 -05001820 logging.info("Received features_reply.")
Jonathan Stoutfcee3142014-01-28 15:46:22 -05001821
Jonathan Stout641167f2014-02-04 12:07:10 -05001822 if (res.capabilities & capability) > 0:
1823 logging.info("Switch capabilities bitmask claims to support %s",
1824 capability_str)
1825 return True, res.capabilities
1826 else:
1827 logging.info("Capabilities bitmask does not support %s.",
1828 capability_str)
1829 return False, res.capabilities
Jonathan Stoutfcee3142014-01-28 15:46:22 -05001830
Jonathan Stouteb3721d2014-02-04 13:59:12 -05001831def verify_configuration_flag(test, flag):
1832 """
1833 Return True if DUT supports specified configuration flag.
1834
1835 @param test Instance of base_tests.SimpleProtocol
1836 @param flag One of ofp_config_flags.
Jonathan Stout1ec8c0f2014-02-04 15:25:38 -05001837 @returns (supported, flags) Bool if flag is set and flag values.
Jonathan Stouteb3721d2014-02-04 13:59:12 -05001838 """
1839 logging.info("Verifing that flag is valid.")
1840 test.assertIn(flag, ofp.const.ofp_config_flags_map,
1841 "flag %s does not exist." % flag)
1842 flag_str = ofp.const.ofp_config_flags_map[flag]
1843
1844 logging.info("Sending OFPT_GET_CONFIG_REQUEST.")
1845 req = ofp.message.get_config_request()
1846 rv = test.controller.message_send(req)
1847 test.assertNotEqual(rv, -1, "Not able to send get_config_request.")
1848
1849 logging.info("Expecting OFPT_GET_CONFIG_REPLY ")
1850 (res, pkt) = test.controller.poll(exp_msg=ofp.OFPT_GET_CONFIG_REPLY,
1851 timeout=2)
1852 test.assertIsNotNone(res, "Did not receive OFPT_GET_CONFIG_REPLY")
1853 logging.info("Received OFPT_GET_CONFIG_REPLY ")
1854
1855 if res.flags == flag:
1856 logging.info("%s flag is set.", flag_str)
1857 return True, res.flags
1858 else:
1859 logging.info("%s flag is not set.", flag_str)
1860 return False, res.flags
1861
Rich Lane7744e112013-01-11 17:23:57 -08001862__all__ = list(set(locals()) - _import_blacklist)