blob: 256bfcdcf1571fc8599e130e216c03ebb956353c [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
macauley_chengb0ec33d2015-09-04 11:32:44 +0800242
243def simple_tcp_packet_two_vlan(pktlen=100,
244 eth_dst='00:01:02:03:04:05',
245 eth_src='00:06:07:08:09:0a',
246 out_dl_vlan_enable=False,
247 in_dl_vlan_enable=False,
248 out_vlan_vid=0,
249 out_vlan_pcp=0,
250 out_dl_vlan_cfi=0,
251 in_vlan_vid=0,
252 in_vlan_pcp=0,
253 in_dl_vlan_cfi=0,
254 ip_src='192.168.0.1',
255 ip_dst='192.168.0.2',
256 ip_tos=0,
257 ip_ttl=64,
258 tcp_sport=1234,
259 tcp_dport=80,
260 tcp_flags="S",
261 ip_ihl=None,
262 ip_options=False
263 ):
264 """
265 Return a simple dataplane TCP packet
266
267 Supports a few parameters:
268 @param len Length of packet in bytes w/o CRC
269 @param eth_dst Destinatino MAC
270 @param eth_src Source MAC
271 @param dl_vlan_enable True if the packet is with vlan, False otherwise
272 @param vlan_vid VLAN ID
273 @param vlan_pcp VLAN priority
274 @param ip_src IP source
275 @param ip_dst IP destination
276 @param ip_tos IP ToS
277 @param ip_ttl IP TTL
278 @param tcp_dport TCP destination port
279 @param tcp_sport TCP source port
280 @param tcp_flags TCP Control flags
281
282 Generates a simple TCP request. Users
283 shouldn't assume anything about this packet other than that
284 it is a valid ethernet/IP/TCP frame.
285 """
286
287 if MINSIZE > pktlen:
288 pktlen = MINSIZE
289
290 # Note Dot1Q.id is really CFI
291 if (out_dl_vlan_enable and in_dl_vlan_enable):
292 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
293 scapy.Dot1Q(prio=out_vlan_pcp, id=out_dl_vlan_cfi, vlan=out_vlan_vid)
294
295 if in_dl_vlan_enable:
296 pkt = pkt/scapy.Dot1Q(prio=in_vlan_pcp, id=in_dl_vlan_cfi, vlan=in_vlan_vid)
297
298 pkt = pkt/scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ttl=ip_ttl, ihl=ip_ihl)/ \
299 scapy.TCP(sport=tcp_sport, dport=tcp_dport, flags=tcp_flags)
300 elif (out_dl_vlan_enable and (not in_dl_vlan_enable)):
301 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
302 scapy.Dot1Q(prio=out_vlan_pcp, id=out_dl_vlan_cfi, vlan=out_vlan_vid)/ \
303 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ttl=ip_ttl, ihl=ip_ihl)/ \
304 scapy.TCP(sport=tcp_sport, dport=tcp_dport, flags=tcp_flags)
305 elif ((not out_dl_vlan_enable) and in_dl_vlan_enable):
306 assert(0) #shall not have this caes
307 else:
308 if not ip_options:
309 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
310 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ttl=ip_ttl, ihl=ip_ihl)/ \
311 scapy.TCP(sport=tcp_sport, dport=tcp_dport, flags=tcp_flags)
312 else:
313 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
314 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ttl=ip_ttl, ihl=ip_ihl, options=ip_options)/ \
315 scapy.TCP(sport=tcp_sport, dport=tcp_dport, flags=tcp_flags)
316
317 pkt = pkt/("D" * (pktlen - len(pkt)))
318
319 return pkt
320
macauley17cd60d2015-07-27 17:41:18 +0800321def simple_vxlan_packet(eth_dst='00:01:02:03:04:05',
322 eth_src='00:06:07:08:09:0a',
323 dl_vlan_enable=False,
324 vlan_vid=0,
325 vlan_pcp=0,
326 dl_vlan_cfi=0,
327 ip_src='192.168.0.1',
328 ip_dst='192.168.0.2',
329 ip_tos=0,
330 ip_ttl=64,
331 udp_sport=1234,
332 udp_dport=4789,
333 vnid=1,
macauley1b23af82015-07-30 14:06:33 +0800334 inner_payload=None,
macauley17cd60d2015-07-27 17:41:18 +0800335 ip_ihl=None,
336 ip_options=False
337 ):
338 """
339 Return a simple dataplane UDP packet
340
341 Supports a few parameters:
342 @param len Length of packet in bytes w/o CRC
343 @param eth_dst Destination MAC
344 @param eth_src Source MAC
345 @param dl_vlan_enable True if the packet is with vlan, False otherwise
346 @param vlan_vid VLAN ID
347 @param vlan_pcp VLAN priority
348 @param ip_src IP source
349 @param ip_dst IP destination
350 @param ip_tos IP ToS
351 @param ip_ttl IP TTL
352 @param udp_dport UDP destination port
353 @param udp_sport UDP source port
354 @param inner_pyload inner pacekt content
355 Generates a simple UDP packet. Users shouldn't assume anything about
356 this packet other than that it is a valid ethernet/IP/UDP frame.
357 """
358
359 # Note Dot1Q.id is really CFI
360 if (dl_vlan_enable):
361 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
362 scapy.Dot1Q(prio=vlan_pcp, id=dl_vlan_cfi, vlan=vlan_vid)/ \
363 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ttl=ip_ttl, ihl=ip_ihl)/ \
364 scapy.UDP(sport=udp_sport, dport=udp_dport)
365 else:
366 if not ip_options:
367 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
368 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ttl=ip_ttl, ihl=ip_ihl)/ \
369 scapy.UDP(sport=udp_sport, dport=udp_dport)
370 else:
371 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
372 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ttl=ip_ttl, ihl=ip_ihl, options=ip_options)/ \
373 scapy.UDP(sport=udp_sport, dport=udp_dport)
macauley1b23af82015-07-30 14:06:33 +0800374
macauley17cd60d2015-07-27 17:41:18 +0800375 #add vxlan header
376 pkt = pkt/scapy.VXLAN(vni=vnid)
377 #add innder payload
macauley1b23af82015-07-30 14:06:33 +0800378 if inner_payload!=None:
379 pkt=pkt/inner_payload
macauley17cd60d2015-07-27 17:41:18 +0800380
381 return pkt
382
macauley_chengb0ec33d2015-09-04 11:32:44 +0800383
macauley_cheng45833df2015-08-31 15:19:07 +0800384
385def simple_mpls_packet(eth_dst='00:01:02:03:04:05',
386 eth_src='00:06:07:08:09:0a',
387 dl_vlan_enable=False,
388 vlan_vid=0,
389 vlan_pcp=0,
390 dl_vlan_cfi=0,
391 label=None,
392 inner_payload=None
393 ):
394 """
395 Return a simple dataplane MPLS packet
396
397 Supports a few parameters:
398 @param len Length of packet in bytes w/o CRC
399 @param eth_dst Destination MAC
400 @param eth_src Source MAC
401 @param dl_vlan_enable True if the packet is with vlan, False otherwise
402 @param vlan_vid VLAN ID
403 @param vlan_pcp VLAN priority
404 @param inner_pyload inner pacekt content
405 Generates a simple MPLS packet. Users shouldn't assume anything about
406 this packet other than that it is a valid ethernet/IP/UDP frame.
407 """
408
409 # Note Dot1Q.id is really CFI
410 if (dl_vlan_enable):
411 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
412 scapy.Dot1Q(prio=vlan_pcp, id=dl_vlan_cfi, vlan=vlan_vid)
413 else:
414 pkt = scapy.Ether(dst=eth_dst, src=eth_src)
415
416 #add MPLS header
417 for i in range(len(label)):
418 l,c,s,t=label[i]
419 pkt = pkt/scapy.MPLS(label=l, cos=c, s=s, ttl=t)
420
421 #add innder payload
422 if inner_payload!=None:
423 pkt=pkt/inner_payload
424
425 return pkt
426
Rich Lane86aceb02013-07-17 18:45:38 -0700427def simple_udpv6_packet(pktlen=100,
428 eth_dst='00:01:02:03:04:05',
429 eth_src='00:06:07:08:09:0a',
430 dl_vlan_enable=False,
431 vlan_vid=0,
432 vlan_pcp=0,
433 ipv6_src='2001:db8:85a3::8a2e:370:7334',
434 ipv6_dst='2001:db8:85a3::8a2e:370:7335',
435 ipv6_tc=0,
436 ipv6_hlim=64,
437 ipv6_fl=0,
438 udp_sport=1234,
439 udp_dport=80):
440 """
441 Return a simple IPv6/UDP packet
442
443 Supports a few parameters:
444 @param len Length of packet in bytes w/o CRC
445 @param eth_dst Destination MAC
446 @param eth_src Source MAC
447 @param dl_vlan_enable True if the packet is with vlan, False otherwise
448 @param vlan_vid VLAN ID
449 @param vlan_pcp VLAN priority
450 @param ipv6_src IPv6 source
451 @param ipv6_dst IPv6 destination
452 @param ipv6_tc IPv6 traffic class
453 @param ipv6_ttl IPv6 hop limit
454 @param ipv6_fl IPv6 flow label
455 @param udp_dport UDP destination port
456 @param udp_sport UDP source port
457
458 Generates a simple UDP request. Users shouldn't assume anything about this
459 packet other than that it is a valid ethernet/IPv6/UDP frame.
460 """
461
462 if MINSIZE > pktlen:
463 pktlen = MINSIZE
464
465 pkt = scapy.Ether(dst=eth_dst, src=eth_src)
466 if dl_vlan_enable or vlan_vid or vlan_pcp:
467 pkt /= scapy.Dot1Q(vlan=vlan_vid, prio=vlan_pcp)
468 pkt /= scapy.IPv6(src=ipv6_src, dst=ipv6_dst, fl=ipv6_fl, tc=ipv6_tc, hlim=ipv6_hlim)
469 pkt /= scapy.UDP(sport=udp_sport, dport=udp_dport)
470 pkt /= ("D" * (pktlen - len(pkt)))
471
472 return pkt
473
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700474def simple_icmp_packet(pktlen=60,
Rich Laned0478ff2013-03-11 12:46:58 -0700475 eth_dst='00:01:02:03:04:05',
476 eth_src='00:06:07:08:09:0a',
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700477 dl_vlan_enable=False,
Rich Laned0478ff2013-03-11 12:46:58 -0700478 vlan_vid=0,
479 vlan_pcp=0,
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700480 ip_src='192.168.0.1',
481 ip_dst='192.168.0.2',
482 ip_tos=0,
Gregor Maier9cc93342013-01-29 16:55:28 -0800483 ip_ttl=64,
Harshmeet Singhd209c0b2014-01-28 09:48:58 -0600484 ip_id=1,
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700485 icmp_type=8,
Harshmeet Singhd209c0b2014-01-28 09:48:58 -0600486 icmp_code=0,
Harshmeet Singh45b2a9d2014-01-28 13:02:04 -0600487 icmp_data=''):
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700488 """
489 Return a simple ICMP packet
490
491 Supports a few parameters:
492 @param len Length of packet in bytes w/o CRC
Rich Laned0478ff2013-03-11 12:46:58 -0700493 @param eth_dst Destinatino MAC
494 @param eth_src Source MAC
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700495 @param dl_vlan_enable True if the packet is with vlan, False otherwise
Rich Laned0478ff2013-03-11 12:46:58 -0700496 @param vlan_vid VLAN ID
497 @param vlan_pcp VLAN priority
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700498 @param ip_src IP source
499 @param ip_dst IP destination
500 @param ip_tos IP ToS
Gregor Maier9cc93342013-01-29 16:55:28 -0800501 @param ip_ttl IP TTL
Harshmeet Singhd209c0b2014-01-28 09:48:58 -0600502 @param ip_id IP Identification
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700503 @param icmp_type ICMP type
504 @param icmp_code ICMP code
Harshmeet Singhd209c0b2014-01-28 09:48:58 -0600505 @param icmp_data ICMP data
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700506
507 Generates a simple ICMP ECHO REQUEST. Users
508 shouldn't assume anything about this packet other than that
509 it is a valid ethernet/ICMP frame.
510 """
Jeffrey Townsend5cb7ed32012-08-17 18:11:01 +0000511
512 if MINSIZE > pktlen:
513 pktlen = MINSIZE
514
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700515 if (dl_vlan_enable):
Rich Laned0478ff2013-03-11 12:46:58 -0700516 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
517 scapy.Dot1Q(prio=vlan_pcp, id=0, vlan=vlan_vid)/ \
Harshmeet Singhd209c0b2014-01-28 09:48:58 -0600518 scapy.IP(src=ip_src, dst=ip_dst, ttl=ip_ttl, tos=ip_tos, id=ip_id)/ \
Harshmeet Singh45b2a9d2014-01-28 13:02:04 -0600519 scapy.ICMP(type=icmp_type, code=icmp_code)/ icmp_data
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700520 else:
Rich Laned0478ff2013-03-11 12:46:58 -0700521 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
Harshmeet Singhd209c0b2014-01-28 09:48:58 -0600522 scapy.IP(src=ip_src, dst=ip_dst, ttl=ip_ttl, tos=ip_tos, id=ip_id)/ \
Harshmeet Singh45b2a9d2014-01-28 13:02:04 -0600523 scapy.ICMP(type=icmp_type, code=icmp_code)/ icmp_data
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700524
525 pkt = pkt/("0" * (pktlen - len(pkt)))
526
527 return pkt
528
Rich Lane86aceb02013-07-17 18:45:38 -0700529def simple_icmpv6_packet(pktlen=100,
530 eth_dst='00:01:02:03:04:05',
531 eth_src='00:06:07:08:09:0a',
532 dl_vlan_enable=False,
533 vlan_vid=0,
534 vlan_pcp=0,
535 ipv6_src='2001:db8:85a3::8a2e:370:7334',
536 ipv6_dst='2001:db8:85a3::8a2e:370:7335',
537 ipv6_tc=0,
538 ipv6_hlim=64,
539 ipv6_fl=0,
540 icmp_type=8,
541 icmp_code=0):
542 """
543 Return a simple ICMPv6 packet
544
545 Supports a few parameters:
546 @param len Length of packet in bytes w/o CRC
547 @param eth_dst Destination MAC
548 @param eth_src Source MAC
549 @param dl_vlan_enable True if the packet is with vlan, False otherwise
550 @param vlan_vid VLAN ID
551 @param vlan_pcp VLAN priority
552 @param ipv6_src IPv6 source
553 @param ipv6_dst IPv6 destination
554 @param ipv6_tc IPv6 traffic class
555 @param ipv6_ttl IPv6 hop limit
556 @param ipv6_fl IPv6 flow label
557 @param icmp_type ICMP type
558 @param icmp_code ICMP code
559
560 Generates a simple ICMP ECHO REQUEST. Users shouldn't assume anything
561 about this packet other than that it is a valid ethernet/IPv6/ICMP frame.
562 """
563
564 if MINSIZE > pktlen:
565 pktlen = MINSIZE
566
567 pkt = scapy.Ether(dst=eth_dst, src=eth_src)
568 if dl_vlan_enable or vlan_vid or vlan_pcp:
569 pkt /= scapy.Dot1Q(vlan=vlan_vid, prio=vlan_pcp)
570 pkt /= scapy.IPv6(src=ipv6_src, dst=ipv6_dst, fl=ipv6_fl, tc=ipv6_tc, hlim=ipv6_hlim)
571 pkt /= scapy.ICMPv6Unknown(type=icmp_type, code=icmp_code)
572 pkt /= ("D" * (pktlen - len(pkt)))
573
574 return pkt
575
Shudong Zhouc7562b12013-02-06 01:12:18 -0800576def simple_arp_packet(pktlen=60,
Rich Laned0478ff2013-03-11 12:46:58 -0700577 eth_dst='ff:ff:ff:ff:ff:ff',
578 eth_src='00:06:07:08:09:0a',
Rich Lanee01611f2014-01-15 14:55:11 -0800579 vlan_vid=0,
580 vlan_pcp=0,
Shudong Zhouc7562b12013-02-06 01:12:18 -0800581 arp_op=1,
582 ip_snd='192.168.0.1',
583 ip_tgt='192.168.0.2',
584 hw_snd='00:06:07:08:09:0a',
585 hw_tgt='00:00:00:00:00:00',
586 ):
587 """
588 Return a simple ARP packet
589
590 Supports a few parameters:
591 @param len Length of packet in bytes w/o CRC
Rich Laned0478ff2013-03-11 12:46:58 -0700592 @param eth_dst Destinatino MAC
593 @param eth_src Source MAC
Shudong Zhouc7562b12013-02-06 01:12:18 -0800594 @param arp_op Operation (1=request, 2=reply)
595 @param ip_snd Sender IP
596 @param ip_tgt Target IP
597 @param hw_snd Sender hardware address
598 @param hw_tgt Target hardware address
599
600 Generates a simple ARP REQUEST. Users
601 shouldn't assume anything about this packet other than that
602 it is a valid ethernet/ARP frame.
603 """
604
605 if MINSIZE > pktlen:
606 pktlen = MINSIZE
607
Rich Lanee01611f2014-01-15 14:55:11 -0800608 pkt = scapy.Ether(dst=eth_dst, src=eth_src)
609 if vlan_vid or vlan_pcp:
610 pkt /= scapy.Dot1Q(vlan=vlan_vid, prio=vlan_pcp)
611 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 -0800612
Rich Laned459ce52014-01-24 12:09:54 -0800613 pkt = pkt/("\0" * (pktlen - len(pkt)))
Shudong Zhouc7562b12013-02-06 01:12:18 -0800614
615 return pkt
616
Ed Swierk0aeff8c2012-03-23 20:27:18 -0700617def simple_eth_packet(pktlen=60,
Rich Lane53275082013-11-18 23:26:22 -0800618 eth_dst='00:01:02:03:04:05',
619 eth_src='00:06:07:08:09:0a',
Rich Laned0478ff2013-03-11 12:46:58 -0700620 eth_type=0x88cc):
Jeffrey Townsend5cb7ed32012-08-17 18:11:01 +0000621
622 if MINSIZE > pktlen:
623 pktlen = MINSIZE
624
Rich Laned0478ff2013-03-11 12:46:58 -0700625 pkt = scapy.Ether(dst=eth_dst, src=eth_src, type=eth_type)
Ed Swierk0aeff8c2012-03-23 20:27:18 -0700626
627 pkt = pkt/("0" * (pktlen - len(pkt)))
628
629 return pkt
630
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800631def qinq_tcp_packet(pktlen=100,
Rich Laned0478ff2013-03-11 12:46:58 -0700632 eth_dst='00:01:02:03:04:05',
633 eth_src='00:06:07:08:09:0a',
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800634 dl_vlan_outer=20,
635 dl_vlan_pcp_outer=0,
636 dl_vlan_cfi_outer=0,
Rich Laned0478ff2013-03-11 12:46:58 -0700637 vlan_vid=10,
638 vlan_pcp=0,
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800639 dl_vlan_cfi=0,
640 ip_src='192.168.0.1',
641 ip_dst='192.168.0.2',
642 ip_tos=0,
Gregor Maier9cc93342013-01-29 16:55:28 -0800643 ip_ttl=64,
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800644 tcp_sport=1234,
645 tcp_dport=80,
646 ip_ihl=None,
647 ip_options=False
648 ):
649 """
650 Return a doubly tagged dataplane TCP packet
651
652 Supports a few parameters:
653 @param len Length of packet in bytes w/o CRC
Rich Laned0478ff2013-03-11 12:46:58 -0700654 @param eth_dst Destinatino MAC
655 @param eth_src Source MAC
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800656 @param dl_vlan_outer Outer VLAN ID
657 @param dl_vlan_pcp_outer Outer VLAN priority
658 @param dl_vlan_cfi_outer Outer VLAN cfi bit
Rich Laned0478ff2013-03-11 12:46:58 -0700659 @param vlan_vid Inner VLAN ID
660 @param vlan_pcp VLAN priority
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800661 @param dl_vlan_cfi VLAN cfi bit
662 @param ip_src IP source
663 @param ip_dst IP destination
664 @param ip_tos IP ToS
665 @param tcp_dport TCP destination port
666 @param ip_sport TCP source port
667
668 Generates a TCP request. Users
669 shouldn't assume anything about this packet other than that
670 it is a valid ethernet/IP/TCP frame.
671 """
672
673 if MINSIZE > pktlen:
674 pktlen = MINSIZE
675
676 # Note Dot1Q.id is really CFI
Rich Laned0478ff2013-03-11 12:46:58 -0700677 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800678 scapy.Dot1Q(prio=dl_vlan_pcp_outer, id=dl_vlan_cfi_outer, vlan=dl_vlan_outer)/ \
Rich Laned0478ff2013-03-11 12:46:58 -0700679 scapy.Dot1Q(prio=vlan_pcp, id=dl_vlan_cfi, vlan=vlan_vid)/ \
Gregor Maier9cc93342013-01-29 16:55:28 -0800680 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ttl=ip_ttl, ihl=ip_ihl)/ \
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800681 scapy.TCP(sport=tcp_sport, dport=tcp_dport)
682
683 pkt = pkt/("D" * (pktlen - len(pkt)))
684
685 return pkt
686
Shudong Zhoub7f12462012-11-20 13:01:12 -0800687def do_barrier(ctrl, timeout=-1):
Dan Talayco0fc08bd2012-04-09 16:56:18 -0700688 """
689 Do a barrier command
690 Return 0 on success, -1 on error
691 """
Rich Lanee717c6e2013-03-12 10:25:50 -0700692 b = ofp.message.barrier_request()
Shudong Zhoub7f12462012-11-20 13:01:12 -0800693 (resp, pkt) = ctrl.transact(b, timeout=timeout)
Rich Lane3a261d52013-01-03 17:45:08 -0800694 if resp is None:
695 raise AssertionError("barrier failed")
Dan Talaycof6b94832012-04-12 21:50:57 -0700696 # We'll trust the transaction processing in the controller that xid matched
Rich Lane3a261d52013-01-03 17:45:08 -0800697 return 0 # for backwards compatibility
Dan Talayco92c99122010-06-03 13:53:18 -0700698
Rich Lane9a003812012-10-04 17:17:59 -0700699def port_config_get(controller, port_no):
Dan Talayco92c99122010-06-03 13:53:18 -0700700 """
701 Get a port's configuration
702
703 Gets the switch feature configuration and grabs one port's
704 configuration
705
706 @returns (hwaddr, config, advert) The hwaddress, configuration and
707 advertised values
708 """
Rich Lane6dc865c2013-07-10 10:12:13 -0700709
710 if ofp.OFP_VERSION <= 3:
711 request = ofp.message.features_request()
712 reply, _ = controller.transact(request)
713 if reply is None:
714 logging.warn("Get feature request failed")
715 return None, None, None
716 logging.debug(reply.show())
717 ports = reply.ports
718 else:
719 request = ofp.message.port_desc_stats_request()
720 # TODO do multipart correctly
721 reply, _ = controller.transact(request)
722 if reply is None:
723 logging.warn("Port desc stats request failed")
724 return None, None, None
725 logging.debug(reply.show())
726 ports = reply.entries
727
728 for port in ports:
729 if port.port_no == port_no:
730 return (port.hw_addr, port.config, port.advertised)
Dan Talayco92c99122010-06-03 13:53:18 -0700731
Rich Lane9a003812012-10-04 17:17:59 -0700732 logging.warn("Did not find port number for port config")
Dan Talayco92c99122010-06-03 13:53:18 -0700733 return None, None, None
734
Rich Lane9a003812012-10-04 17:17:59 -0700735def port_config_set(controller, port_no, config, mask):
Dan Talayco92c99122010-06-03 13:53:18 -0700736 """
737 Set the port configuration according the given parameters
738
739 Gets the switch feature configuration and updates one port's
740 configuration value according to config and mask
741 """
Rich Lane9a003812012-10-04 17:17:59 -0700742 logging.info("Setting port " + str(port_no) + " to config " + str(config))
Rich Lane6dc865c2013-07-10 10:12:13 -0700743
744 hw_addr, _, _ = port_config_get(controller, port_no)
745
Rich Lanee717c6e2013-03-12 10:25:50 -0700746 mod = ofp.message.port_mod()
Dan Talayco92c99122010-06-03 13:53:18 -0700747 mod.port_no = port_no
Rich Lane6dc865c2013-07-10 10:12:13 -0700748 if hw_addr != None:
749 mod.hw_addr = hw_addr
Dan Talayco92c99122010-06-03 13:53:18 -0700750 mod.config = config
751 mod.mask = mask
Rich Lane6dc865c2013-07-10 10:12:13 -0700752 mod.advertise = 0 # No change
Rich Lane5c3151c2013-01-03 17:15:41 -0800753 controller.message_send(mod)
754 return 0
Dan Talayco92c99122010-06-03 13:53:18 -0700755
Rich Lane2014f9b2012-10-05 15:29:40 -0700756def receive_pkt_check(dp, pkt, yes_ports, no_ports, assert_if):
Dan Talayco92c99122010-06-03 13:53:18 -0700757 """
758 Check for proper receive packets across all ports
Ken Chiang1bf01602012-04-04 10:48:23 -0700759 @param dp The dataplane object
Dan Talayco92c99122010-06-03 13:53:18 -0700760 @param pkt Expected packet; may be None if yes_ports is empty
761 @param yes_ports Set or list of ports that should recieve packet
762 @param no_ports Set or list of ports that should not receive packet
763 @param assert_if Object that implements assertXXX
Rich Lanee4b384d2013-09-13 14:33:40 -0700764
765 DEPRECATED in favor in verify_packets
Dan Talayco92c99122010-06-03 13:53:18 -0700766 """
Rich Lane91765672012-12-06 16:33:04 -0800767
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700768 exp_pkt_arg = None
Rich Lanecd97d3d2013-01-07 18:50:06 -0800769 if oftest.config["relax"]:
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700770 exp_pkt_arg = pkt
771
Dan Talayco92c99122010-06-03 13:53:18 -0700772 for ofport in yes_ports:
Rich Lane9a003812012-10-04 17:17:59 -0700773 logging.debug("Checking for pkt on port " + str(ofport))
Ken Chiang1bf01602012-04-04 10:48:23 -0700774 (rcv_port, rcv_pkt, pkt_time) = dp.poll(
Wilson Ngc2c6b4e2015-03-04 17:30:20 -0800775 port_number=ofport, exp_pkt=exp_pkt_arg)
Dan Talayco92c99122010-06-03 13:53:18 -0700776 assert_if.assertTrue(rcv_pkt is not None,
777 "Did not receive pkt on " + str(ofport))
Rich Lanecd97d3d2013-01-07 18:50:06 -0800778 if not oftest.dataplane.match_exp_pkt(pkt, rcv_pkt):
Rich Lane3c266832013-01-29 18:29:15 -0800779 logging.debug("Expected %s" % format_packet(pkt))
780 logging.debug("Received %s" % format_packet(rcv_pkt))
Rich Lanecd97d3d2013-01-07 18:50:06 -0800781 assert_if.assertTrue(oftest.dataplane.match_exp_pkt(pkt, rcv_pkt),
Rich Lane3c266832013-01-29 18:29:15 -0800782 "Received packet does not match expected packet " +
Ken Chiang1bf01602012-04-04 10:48:23 -0700783 "on port " + str(ofport))
Dan Talayco73f84012012-10-02 09:23:18 -0700784 if len(no_ports) > 0:
Rich Lane57dfee72014-03-24 16:59:47 -0700785 time.sleep(oftest.ofutils.default_negative_timeout)
Dan Talayco92c99122010-06-03 13:53:18 -0700786 for ofport in no_ports:
Rich Lane9a003812012-10-04 17:17:59 -0700787 logging.debug("Negative check for pkt on port " + str(ofport))
Ken Chiang1bf01602012-04-04 10:48:23 -0700788 (rcv_port, rcv_pkt, pkt_time) = dp.poll(
Rich Lane91765672012-12-06 16:33:04 -0800789 port_number=ofport, timeout=0, exp_pkt=exp_pkt_arg)
Dan Talayco92c99122010-06-03 13:53:18 -0700790 assert_if.assertTrue(rcv_pkt is None,
791 "Unexpected pkt on port " + str(ofport))
Dan Talayco551befa2010-07-15 17:05:32 -0700792
793
Dan Talaycoc948d0b2012-03-23 12:17:54 -0700794def receive_pkt_verify(parent, egr_ports, exp_pkt, ing_port):
Dan Talayco551befa2010-07-15 17:05:32 -0700795 """
796 Receive a packet and verify it matches an expected value
Dan Talaycof6e76c02012-03-23 10:56:12 -0700797 @param egr_port A single port or list of ports
Dan Talayco551befa2010-07-15 17:05:32 -0700798
799 parent must implement dataplane, assertTrue and assertEqual
Rich Lanee4b384d2013-09-13 14:33:40 -0700800
801 DEPRECATED in favor in verify_packets
Dan Talayco551befa2010-07-15 17:05:32 -0700802 """
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700803 exp_pkt_arg = None
Rich Lanecd97d3d2013-01-07 18:50:06 -0800804 if oftest.config["relax"]:
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700805 exp_pkt_arg = exp_pkt
806
Dan Talaycof6e76c02012-03-23 10:56:12 -0700807 if type(egr_ports) == type([]):
808 egr_port_list = egr_ports
809 else:
810 egr_port_list = [egr_ports]
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700811
Dan Talaycof6e76c02012-03-23 10:56:12 -0700812 # Expect a packet from each port on egr port list
813 for egr_port in egr_port_list:
Dan Talaycod8ae7582012-03-23 12:24:56 -0700814 check_port = egr_port
Rich Lanee717c6e2013-03-12 10:25:50 -0700815 if egr_port == ofp.OFPP_IN_PORT:
Dan Talaycod8ae7582012-03-23 12:24:56 -0700816 check_port = ing_port
Dan Talaycof6e76c02012-03-23 10:56:12 -0700817 (rcv_port, rcv_pkt, pkt_time) = parent.dataplane.poll(
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700818 port_number=check_port, exp_pkt=exp_pkt_arg)
Dan Talayco551befa2010-07-15 17:05:32 -0700819
Dan Talaycof6e76c02012-03-23 10:56:12 -0700820 if rcv_pkt is None:
Rich Lane9a003812012-10-04 17:17:59 -0700821 logging.error("ERROR: No packet received from " +
Dan Talaycod8ae7582012-03-23 12:24:56 -0700822 str(check_port))
Dan Talayco551befa2010-07-15 17:05:32 -0700823
Dan Talaycof6e76c02012-03-23 10:56:12 -0700824 parent.assertTrue(rcv_pkt is not None,
Dan Talaycod8ae7582012-03-23 12:24:56 -0700825 "Did not receive packet port " + str(check_port))
Rich Lane9a003812012-10-04 17:17:59 -0700826 logging.debug("Packet len " + str(len(rcv_pkt)) + " in on " +
Dan Talaycof6e76c02012-03-23 10:56:12 -0700827 str(rcv_port))
828
829 if str(exp_pkt) != str(rcv_pkt):
Rich Lane9a003812012-10-04 17:17:59 -0700830 logging.error("ERROR: Packet match failed.")
831 logging.debug("Expected len " + str(len(exp_pkt)) + ": "
Dan Talaycof6e76c02012-03-23 10:56:12 -0700832 + str(exp_pkt).encode('hex'))
Rich Lane9a003812012-10-04 17:17:59 -0700833 logging.debug("Received len " + str(len(rcv_pkt)) + ": "
Dan Talaycof6e76c02012-03-23 10:56:12 -0700834 + str(rcv_pkt).encode('hex'))
Rich Lane5d7e89a2012-10-26 16:43:13 -0700835 logging.debug("Expected packet: " + inspect_packet(scapy.Ether(str(exp_pkt))))
836 logging.debug("Received packet: " + inspect_packet(scapy.Ether(str(rcv_pkt))))
Dan Talaycof6e76c02012-03-23 10:56:12 -0700837 parent.assertEqual(str(exp_pkt), str(rcv_pkt),
Dan Talaycod8ae7582012-03-23 12:24:56 -0700838 "Packet match error on port " + str(check_port))
Dan Talaycof6e76c02012-03-23 10:56:12 -0700839
Dan Talayco551befa2010-07-15 17:05:32 -0700840def match_verify(parent, req_match, res_match):
841 """
842 Verify flow matches agree; if they disagree, report where
843
844 parent must implement assertEqual
845 Use str() to ensure content is compared and not pointers
846 """
847
848 parent.assertEqual(req_match.wildcards, res_match.wildcards,
849 'Match failed: wildcards: ' + hex(req_match.wildcards) +
850 " != " + hex(res_match.wildcards))
851 parent.assertEqual(req_match.in_port, res_match.in_port,
852 'Match failed: in_port: ' + str(req_match.in_port) +
853 " != " + str(res_match.in_port))
Rich Laned0478ff2013-03-11 12:46:58 -0700854 parent.assertEqual(str(req_match.eth_src), str(res_match.eth_src),
855 'Match failed: eth_src: ' + str(req_match.eth_src) +
856 " != " + str(res_match.eth_src))
857 parent.assertEqual(str(req_match.eth_dst), str(res_match.eth_dst),
858 'Match failed: eth_dst: ' + str(req_match.eth_dst) +
859 " != " + str(res_match.eth_dst))
860 parent.assertEqual(req_match.vlan_vid, res_match.vlan_vid,
861 'Match failed: vlan_vid: ' + str(req_match.vlan_vid) +
862 " != " + str(res_match.vlan_vid))
863 parent.assertEqual(req_match.vlan_pcp, res_match.vlan_pcp,
864 'Match failed: vlan_pcp: ' +
865 str(req_match.vlan_pcp) + " != " +
866 str(res_match.vlan_pcp))
867 parent.assertEqual(req_match.eth_type, res_match.eth_type,
868 'Match failed: eth_type: ' + str(req_match.eth_type) +
869 " != " + str(res_match.eth_type))
Dan Talayco551befa2010-07-15 17:05:32 -0700870
Rich Lanee717c6e2013-03-12 10:25:50 -0700871 if (not(req_match.wildcards & ofp.OFPFW_DL_TYPE)
Rich Laned0478ff2013-03-11 12:46:58 -0700872 and (req_match.eth_type == IP_ETHERTYPE)):
873 parent.assertEqual(req_match.ip_dscp, res_match.ip_dscp,
874 'Match failed: ip_dscp: ' + str(req_match.ip_dscp) +
875 " != " + str(res_match.ip_dscp))
876 parent.assertEqual(req_match.ip_proto, res_match.ip_proto,
877 'Match failed: ip_proto: ' + str(req_match.ip_proto) +
878 " != " + str(res_match.ip_proto))
879 parent.assertEqual(req_match.ipv4_src, res_match.ipv4_src,
880 'Match failed: ipv4_src: ' + str(req_match.ipv4_src) +
881 " != " + str(res_match.ipv4_src))
882 parent.assertEqual(req_match.ipv4_dst, res_match.ipv4_dst,
883 'Match failed: ipv4_dst: ' + str(req_match.ipv4_dst) +
884 " != " + str(res_match.ipv4_dst))
Dan Talayco551befa2010-07-15 17:05:32 -0700885
Rich Lanee717c6e2013-03-12 10:25:50 -0700886 if (not(req_match.wildcards & ofp.OFPFW_NW_PROTO)
Rich Laned0478ff2013-03-11 12:46:58 -0700887 and ((req_match.ip_proto == TCP_PROTOCOL)
888 or (req_match.ip_proto == UDP_PROTOCOL))):
889 parent.assertEqual(req_match.tcp_src, res_match.tcp_src,
890 'Match failed: tcp_src: ' +
891 str(req_match.tcp_src) +
892 " != " + str(res_match.tcp_src))
893 parent.assertEqual(req_match.tcp_dst, res_match.tcp_dst,
894 'Match failed: tcp_dst: ' +
895 str(req_match.tcp_dst) +
896 " != " + str(res_match.tcp_dst))
Dan Talayco551befa2010-07-15 17:05:32 -0700897
Ed Swierk99a74de2012-08-22 06:40:54 -0700898def packet_to_flow_match(parent, packet):
Rich Lanef6883512013-03-11 17:00:09 -0700899 match = oftest.parse.packet_to_flow_match(packet)
Rich Laneab7476f2013-06-13 15:53:52 -0700900 if ofp.OFP_VERSION in [1, 2]:
901 match.wildcards |= required_wildcards(parent)
902 else:
903 # TODO remove incompatible OXM entries
904 pass
Ed Swierk99a74de2012-08-22 06:40:54 -0700905 return match
906
907def flow_msg_create(parent, pkt, ing_port=None, action_list=None, wildcards=None,
Dan Talaycof6e76c02012-03-23 10:56:12 -0700908 egr_ports=None, egr_queue=None, check_expire=False, in_band=False):
Dan Talayco551befa2010-07-15 17:05:32 -0700909 """
910 Create a flow message
911
912 Match on packet with given wildcards.
913 See flow_match_test for other parameter descriptoins
914 @param egr_queue if not None, make the output an enqueue action
Dan Talayco677c0b72011-08-23 22:53:38 -0700915 @param in_band if True, do not wildcard ingress port
Dan Talaycof6e76c02012-03-23 10:56:12 -0700916 @param egr_ports None (drop), single port or list of ports
Dan Talayco551befa2010-07-15 17:05:32 -0700917 """
Rich Lanef6883512013-03-11 17:00:09 -0700918 match = oftest.parse.packet_to_flow_match(pkt)
Dan Talayco551befa2010-07-15 17:05:32 -0700919 parent.assertTrue(match is not None, "Flow match from pkt failed")
Ed Swierk99a74de2012-08-22 06:40:54 -0700920 if wildcards is None:
921 wildcards = required_wildcards(parent)
Dan Talayco677c0b72011-08-23 22:53:38 -0700922 if in_band:
Rich Lanee717c6e2013-03-12 10:25:50 -0700923 wildcards &= ~ofp.OFPFW_IN_PORT
Dan Talayco551befa2010-07-15 17:05:32 -0700924 match.wildcards = wildcards
925 match.in_port = ing_port
926
Dan Talaycof6e76c02012-03-23 10:56:12 -0700927 if type(egr_ports) == type([]):
928 egr_port_list = egr_ports
929 else:
930 egr_port_list = [egr_ports]
931
Rich Lanee717c6e2013-03-12 10:25:50 -0700932 request = ofp.message.flow_add()
Dan Talayco551befa2010-07-15 17:05:32 -0700933 request.match = match
934 request.buffer_id = 0xffffffff
935 if check_expire:
Rich Lanee717c6e2013-03-12 10:25:50 -0700936 request.flags |= ofp.OFPFF_SEND_FLOW_REM
Dan Talayco551befa2010-07-15 17:05:32 -0700937 request.hard_timeout = 1
938
Rich Lane400fb9b2013-10-10 17:20:54 -0700939 if ofp.OFP_VERSION == 1:
940 actions = request.actions
941 else:
942 actions = []
943 request.instructions.append(ofp.instruction.apply_actions(actions))
944
Dan Talayco551befa2010-07-15 17:05:32 -0700945 if action_list is not None:
Rich Lane400fb9b2013-10-10 17:20:54 -0700946 actions.extend(action_list)
Dan Talayco551befa2010-07-15 17:05:32 -0700947
948 # Set up output/enqueue action if directed
949 if egr_queue is not None:
Dan Talaycof6e76c02012-03-23 10:56:12 -0700950 parent.assertTrue(egr_ports is not None, "Egress port not set")
Rich Lanee717c6e2013-03-12 10:25:50 -0700951 act = ofp.action.enqueue()
Dan Talaycof6e76c02012-03-23 10:56:12 -0700952 for egr_port in egr_port_list:
953 act.port = egr_port
954 act.queue_id = egr_queue
Rich Lane400fb9b2013-10-10 17:20:54 -0700955 actions.append(act)
Dan Talaycof6e76c02012-03-23 10:56:12 -0700956 elif egr_ports is not None:
957 for egr_port in egr_port_list:
Rich Lanee717c6e2013-03-12 10:25:50 -0700958 act = ofp.action.output()
Dan Talaycof6e76c02012-03-23 10:56:12 -0700959 act.port = egr_port
Rich Lane400fb9b2013-10-10 17:20:54 -0700960 actions.append(act)
Dan Talayco551befa2010-07-15 17:05:32 -0700961
Rich Lane9a003812012-10-04 17:17:59 -0700962 logging.debug(request.show())
Dan Talayco551befa2010-07-15 17:05:32 -0700963
964 return request
965
Jeffrey Townsendf3eae9c2012-03-28 18:23:21 -0700966def flow_msg_install(parent, request, clear_table_override=None):
Dan Talayco551befa2010-07-15 17:05:32 -0700967 """
968 Install a flow mod message in the switch
969
970 @param parent Must implement controller, assertEqual, assertTrue
971 @param request The request, all set to go
972 @param clear_table If true, clear the flow table before installing
973 """
Dan Talayco8a64e332012-03-28 14:53:20 -0700974
Rich Lane2014f9b2012-10-05 15:29:40 -0700975 clear_table = test_param_get('clear_table', default=True)
Jeffrey Townsendf3eae9c2012-03-28 18:23:21 -0700976 if(clear_table_override != None):
977 clear_table = clear_table_override
978
979 if clear_table:
Rich Lane9a003812012-10-04 17:17:59 -0700980 logging.debug("Clear flow table")
Rich Lane32bf9482013-01-03 17:26:30 -0800981 delete_all_flows(parent.controller)
Dan Talayco551befa2010-07-15 17:05:32 -0700982
Rich Lane9a003812012-10-04 17:17:59 -0700983 logging.debug("Insert flow")
Rich Lane5c3151c2013-01-03 17:15:41 -0800984 parent.controller.message_send(request)
Rich Lanee912d032012-12-22 14:28:33 -0800985
Rich Lane3a261d52013-01-03 17:45:08 -0800986 do_barrier(parent.controller)
Dan Talayco551befa2010-07-15 17:05:32 -0700987
Ed Swierk99a74de2012-08-22 06:40:54 -0700988def flow_match_test_port_pair(parent, ing_port, egr_ports, wildcards=None,
Rich Laned0478ff2013-03-11 12:46:58 -0700989 vlan_vid=-1, pkt=None, exp_pkt=None,
Rich Lanee5779d32012-10-05 17:56:04 -0700990 action_list=None):
Dan Talayco551befa2010-07-15 17:05:32 -0700991 """
992 Flow match test on single TCP packet
Dan Talaycof6e76c02012-03-23 10:56:12 -0700993 @param egr_ports A single port or list of ports
Dan Talayco551befa2010-07-15 17:05:32 -0700994
995 Run test with packet through switch from ing_port to egr_port
996 See flow_match_test for parameter descriptions
997 """
998
Ed Swierk99a74de2012-08-22 06:40:54 -0700999 if wildcards is None:
1000 wildcards = required_wildcards(parent)
Rich Lane9a003812012-10-04 17:17:59 -07001001 logging.info("Pkt match test: " + str(ing_port) + " to " +
Dan Talaycof6e76c02012-03-23 10:56:12 -07001002 str(egr_ports))
Rich Laned0478ff2013-03-11 12:46:58 -07001003 logging.debug(" WC: " + hex(wildcards) + " vlan: " + str(vlan_vid))
Dan Talayco551befa2010-07-15 17:05:32 -07001004 if pkt is None:
Rich Laned0478ff2013-03-11 12:46:58 -07001005 pkt = simple_tcp_packet(dl_vlan_enable=(vlan_vid >= 0), vlan_vid=vlan_vid)
Rich Lanec41fbec2013-10-02 00:27:59 -07001006 if exp_pkt is None:
1007 exp_pkt = pkt
Dan Talayco551befa2010-07-15 17:05:32 -07001008
1009 request = flow_msg_create(parent, pkt, ing_port=ing_port,
Dan Talaycof6e76c02012-03-23 10:56:12 -07001010 wildcards=wildcards, egr_ports=egr_ports,
Dan Talayco551befa2010-07-15 17:05:32 -07001011 action_list=action_list)
1012
1013 flow_msg_install(parent, request)
1014
Rich Lane9a003812012-10-04 17:17:59 -07001015 logging.debug("Send packet: " + str(ing_port) + " to " +
Dan Talaycof6e76c02012-03-23 10:56:12 -07001016 str(egr_ports))
Dan Talayco551befa2010-07-15 17:05:32 -07001017 parent.dataplane.send(ing_port, str(pkt))
1018
Rich Lane8f45e2d2013-10-01 16:06:54 -07001019 exp_ports = [ing_port if port == ofp.OFPP_IN_PORT else port for port in egr_ports]
Rich Lanee4b384d2013-09-13 14:33:40 -07001020 verify_packets(parent, exp_pkt, exp_ports)
Dan Talayco551befa2010-07-15 17:05:32 -07001021
Rich Lane89725bb2012-12-03 16:23:27 -08001022def flow_match_test_pktout(parent, ing_port, egr_ports,
Rich Laned0478ff2013-03-11 12:46:58 -07001023 vlan_vid=-1, pkt=None, exp_pkt=None,
Rich Lane89725bb2012-12-03 16:23:27 -08001024 action_list=None):
1025 """
1026 Packet-out test on single TCP packet
1027 @param egr_ports A single port or list of ports
1028
1029 Run test sending packet-out to egr_ports. The goal is to test the actions
1030 taken on the packet, not the matching which is of course irrelevant.
1031 See flow_match_test for parameter descriptions
1032 """
1033
1034 if pkt is None:
Rich Laned0478ff2013-03-11 12:46:58 -07001035 pkt = simple_tcp_packet(dl_vlan_enable=(vlan_vid >= 0), vlan_vid=vlan_vid)
Rich Lanec41fbec2013-10-02 00:27:59 -07001036 if exp_pkt is None:
1037 exp_pkt = pkt
Rich Lane89725bb2012-12-03 16:23:27 -08001038
Rich Lanee717c6e2013-03-12 10:25:50 -07001039 msg = ofp.message.packet_out()
Rich Lane89725bb2012-12-03 16:23:27 -08001040 msg.in_port = ing_port
Rich Laneea8c4722013-04-04 15:30:20 -07001041 msg.buffer_id = 0xffffffff
Rich Lane89725bb2012-12-03 16:23:27 -08001042 msg.data = str(pkt)
1043 if action_list is not None:
1044 for act in action_list:
Rich Lanec495d9e2013-03-08 17:43:36 -08001045 msg.actions.append(act)
Rich Lane89725bb2012-12-03 16:23:27 -08001046
1047 # Set up output action
1048 if egr_ports is not None:
1049 for egr_port in egr_ports:
Rich Lanee717c6e2013-03-12 10:25:50 -07001050 act = ofp.action.output()
Rich Lane89725bb2012-12-03 16:23:27 -08001051 act.port = egr_port
Rich Lanec495d9e2013-03-08 17:43:36 -08001052 msg.actions.append(act)
Rich Lane89725bb2012-12-03 16:23:27 -08001053
1054 logging.debug(msg.show())
Rich Lane5c3151c2013-01-03 17:15:41 -08001055 parent.controller.message_send(msg)
Rich Lane89725bb2012-12-03 16:23:27 -08001056
Rich Lane8f45e2d2013-10-01 16:06:54 -07001057 exp_ports = [ing_port if port == ofp.OFPP_IN_PORT else port for port in egr_ports]
Rich Lanee4b384d2013-09-13 14:33:40 -07001058 verify_packets(parent, exp_pkt, exp_ports)
Rich Lane89725bb2012-12-03 16:23:27 -08001059
Dan Talaycof6e76c02012-03-23 10:56:12 -07001060def get_egr_list(parent, of_ports, how_many, exclude_list=[]):
1061 """
1062 Generate a list of ports avoiding those in the exclude list
Rich Lane9a003812012-10-04 17:17:59 -07001063 @param parent Supplies logging
Dan Talaycof6e76c02012-03-23 10:56:12 -07001064 @param of_ports List of OF port numbers
1065 @param how_many Number of ports to be added to the list
1066 @param exclude_list List of ports not to be used
1067 @returns An empty list if unable to find enough ports
1068 """
1069
Dan Talaycoc948d0b2012-03-23 12:17:54 -07001070 if how_many == 0:
1071 return []
1072
Dan Talaycof6e76c02012-03-23 10:56:12 -07001073 count = 0
1074 egr_ports = []
1075 for egr_idx in range(len(of_ports)):
1076 if of_ports[egr_idx] not in exclude_list:
1077 egr_ports.append(of_ports[egr_idx])
1078 count += 1
1079 if count >= how_many:
1080 return egr_ports
Rich Lane9a003812012-10-04 17:17:59 -07001081 logging.debug("Could not generate enough egress ports for test")
Dan Talaycof6e76c02012-03-23 10:56:12 -07001082 return []
1083
Rich Laned0478ff2013-03-11 12:46:58 -07001084def flow_match_test(parent, port_map, wildcards=None, vlan_vid=-1, pkt=None,
Rich Lanee5779d32012-10-05 17:56:04 -07001085 exp_pkt=None, action_list=None,
Dan Talaycoc948d0b2012-03-23 12:17:54 -07001086 max_test=0, egr_count=1, ing_port=False):
Dan Talayco551befa2010-07-15 17:05:32 -07001087 """
Rich Lane89725bb2012-12-03 16:23:27 -08001088 Run flow_match_test_port_pair on all port pairs and packet-out
Dan Talayco551befa2010-07-15 17:05:32 -07001089
1090 @param max_test If > 0 no more than this number of tests are executed.
1091 @param parent Must implement controller, dataplane, assertTrue, assertEqual
Rich Lane9a003812012-10-04 17:17:59 -07001092 and logging
Dan Talayco551befa2010-07-15 17:05:32 -07001093 @param pkt If not None, use this packet for ingress
1094 @param wildcards For flow match entry
Rich Laned0478ff2013-03-11 12:46:58 -07001095 @param vlan_vid If not -1, and pkt is None, create a pkt w/ VLAN tag
Dan Talayco551befa2010-07-15 17:05:32 -07001096 @param exp_pkt If not None, use this as the expected output pkt; els use pkt
1097 @param action_list Additional actions to add to flow mod
Dan Talaycocfa172f2012-03-23 12:03:00 -07001098 @param egr_count Number of egress ports; -1 means get from config w/ dflt 2
Dan Talayco551befa2010-07-15 17:05:32 -07001099 """
Ed Swierk99a74de2012-08-22 06:40:54 -07001100 if wildcards is None:
1101 wildcards = required_wildcards(parent)
Dan Talayco551befa2010-07-15 17:05:32 -07001102 of_ports = port_map.keys()
1103 of_ports.sort()
1104 parent.assertTrue(len(of_ports) > 1, "Not enough ports for test")
1105 test_count = 0
1106
Dan Talaycocfa172f2012-03-23 12:03:00 -07001107 if egr_count == -1:
Rich Lane2014f9b2012-10-05 15:29:40 -07001108 egr_count = test_param_get('egr_count', default=2)
Dan Talaycocfa172f2012-03-23 12:03:00 -07001109
Dan Talayco551befa2010-07-15 17:05:32 -07001110 for ing_idx in range(len(of_ports)):
1111 ingress_port = of_ports[ing_idx]
Dan Talaycof6e76c02012-03-23 10:56:12 -07001112 egr_ports = get_egr_list(parent, of_ports, egr_count,
1113 exclude_list=[ingress_port])
Dan Talaycoc948d0b2012-03-23 12:17:54 -07001114 if ing_port:
Rich Lanee717c6e2013-03-12 10:25:50 -07001115 egr_ports.append(ofp.OFPP_IN_PORT)
Dan Talaycof6e76c02012-03-23 10:56:12 -07001116 if len(egr_ports) == 0:
1117 parent.assertTrue(0, "Failed to generate egress port list")
1118
1119 flow_match_test_port_pair(parent, ingress_port, egr_ports,
Rich Laned0478ff2013-03-11 12:46:58 -07001120 wildcards=wildcards, vlan_vid=vlan_vid,
Dan Talaycof6e76c02012-03-23 10:56:12 -07001121 pkt=pkt, exp_pkt=exp_pkt,
Rich Lanee5779d32012-10-05 17:56:04 -07001122 action_list=action_list)
Dan Talaycof6e76c02012-03-23 10:56:12 -07001123 test_count += 1
1124 if (max_test > 0) and (test_count > max_test):
Rich Lane9a003812012-10-04 17:17:59 -07001125 logging.info("Ran " + str(test_count) + " tests; exiting")
Rich Lane89725bb2012-12-03 16:23:27 -08001126 break
1127
Ed Swierk38eea082013-01-02 19:46:20 -08001128 if not test_param_get('pktout_actions', default=True):
1129 return
Rich Lane89725bb2012-12-03 16:23:27 -08001130
1131 ingress_port = of_ports[0]
1132 egr_ports = get_egr_list(parent, of_ports, egr_count,
1133 exclude_list=[ingress_port])
1134 if ing_port:
Rich Lanee717c6e2013-03-12 10:25:50 -07001135 egr_ports.append(ofp.OFPP_IN_PORT)
Rich Lane89725bb2012-12-03 16:23:27 -08001136 flow_match_test_pktout(parent, ingress_port, egr_ports,
Rich Laned0478ff2013-03-11 12:46:58 -07001137 vlan_vid=vlan_vid,
Rich Lane89725bb2012-12-03 16:23:27 -08001138 pkt=pkt, exp_pkt=exp_pkt,
1139 action_list=action_list)
Dan Talayco551befa2010-07-15 17:05:32 -07001140
Rich Lane2014f9b2012-10-05 15:29:40 -07001141def test_param_get(key, default=None):
Dan Talayco4b2bee62010-07-20 14:10:05 -07001142 """
1143 Return value passed via test-params if present
1144
Dan Talayco4b2bee62010-07-20 14:10:05 -07001145 @param key The lookup key
1146 @param default Default value to use if not found
1147
1148 If the pair 'key=val' appeared in the string passed to --test-params
1149 on the command line, return val (as interpreted by exec). Otherwise
1150 return default value.
Dan Talaycof6e76c02012-03-23 10:56:12 -07001151
1152 WARNING: TEST PARAMETERS MUST BE PYTHON IDENTIFIERS;
1153 eg egr_count, not egr-count.
Dan Talayco4b2bee62010-07-20 14:10:05 -07001154 """
1155 try:
Rich Lanecd97d3d2013-01-07 18:50:06 -08001156 exec oftest.config["test_params"]
Dan Talayco4b2bee62010-07-20 14:10:05 -07001157 except:
1158 return default
1159
Dan Talayco4b2bee62010-07-20 14:10:05 -07001160 try:
Rich Lanefdec0fb2013-08-09 18:01:05 -07001161 return eval(str(key))
Dan Talayco4b2bee62010-07-20 14:10:05 -07001162 except:
1163 return default
1164
1165def action_generate(parent, field_to_mod, mod_field_vals):
1166 """
1167 Create an action to modify the field indicated in field_to_mod
1168
1169 @param parent Must implement, assertTrue
1170 @param field_to_mod The field to modify as a string name
1171 @param mod_field_vals Hash of values to use for modified values
1172 """
1173
1174 act = None
1175
1176 if field_to_mod in ['pktlen']:
1177 return None
1178
Rich Laned0478ff2013-03-11 12:46:58 -07001179 if field_to_mod == 'eth_dst':
Rich Lanee717c6e2013-03-12 10:25:50 -07001180 act = ofp.action.set_dl_dst()
Rich Lanef6883512013-03-11 17:00:09 -07001181 act.dl_addr = oftest.parse.parse_mac(mod_field_vals['eth_dst'])
Rich Laned0478ff2013-03-11 12:46:58 -07001182 elif field_to_mod == 'eth_src':
Rich Lanee717c6e2013-03-12 10:25:50 -07001183 act = ofp.action.set_dl_src()
Rich Lanef6883512013-03-11 17:00:09 -07001184 act.dl_addr = oftest.parse.parse_mac(mod_field_vals['eth_src'])
Dan Talayco4b2bee62010-07-20 14:10:05 -07001185 elif field_to_mod == 'dl_vlan_enable':
1186 if not mod_field_vals['dl_vlan_enable']: # Strip VLAN tag
Rich Lanee717c6e2013-03-12 10:25:50 -07001187 act = ofp.action.strip_vlan()
Rich Laned0478ff2013-03-11 12:46:58 -07001188 # Add VLAN tag is handled by vlan_vid field
Dan Talayco4b2bee62010-07-20 14:10:05 -07001189 # Will return None in this case
Rich Laned0478ff2013-03-11 12:46:58 -07001190 elif field_to_mod == 'vlan_vid':
Rich Lanee717c6e2013-03-12 10:25:50 -07001191 act = ofp.action.set_vlan_vid()
Rich Laned0478ff2013-03-11 12:46:58 -07001192 act.vlan_vid = mod_field_vals['vlan_vid']
1193 elif field_to_mod == 'vlan_pcp':
Rich Lanee717c6e2013-03-12 10:25:50 -07001194 act = ofp.action.set_vlan_pcp()
Rich Laned0478ff2013-03-11 12:46:58 -07001195 act.vlan_pcp = mod_field_vals['vlan_pcp']
Dan Talayco4b2bee62010-07-20 14:10:05 -07001196 elif field_to_mod == 'ip_src':
Rich Lanee717c6e2013-03-12 10:25:50 -07001197 act = ofp.action.set_nw_src()
Rich Lanef6883512013-03-11 17:00:09 -07001198 act.nw_addr = oftest.parse.parse_ip(mod_field_vals['ip_src'])
Dan Talayco4b2bee62010-07-20 14:10:05 -07001199 elif field_to_mod == 'ip_dst':
Rich Lanee717c6e2013-03-12 10:25:50 -07001200 act = ofp.action.set_nw_dst()
Rich Lanef6883512013-03-11 17:00:09 -07001201 act.nw_addr = oftest.parse.parse_ip(mod_field_vals['ip_dst'])
Dan Talayco4b2bee62010-07-20 14:10:05 -07001202 elif field_to_mod == 'ip_tos':
Rich Lanee717c6e2013-03-12 10:25:50 -07001203 act = ofp.action.set_nw_tos()
Dan Talayco4b2bee62010-07-20 14:10:05 -07001204 act.nw_tos = mod_field_vals['ip_tos']
1205 elif field_to_mod == 'tcp_sport':
Rich Lanee717c6e2013-03-12 10:25:50 -07001206 act = ofp.action.set_tp_src()
Dan Talayco4b2bee62010-07-20 14:10:05 -07001207 act.tp_port = mod_field_vals['tcp_sport']
1208 elif field_to_mod == 'tcp_dport':
Rich Lanee717c6e2013-03-12 10:25:50 -07001209 act = ofp.action.set_tp_dst()
Dan Talayco4b2bee62010-07-20 14:10:05 -07001210 act.tp_port = mod_field_vals['tcp_dport']
Rich Lane110e0e32012-10-26 16:21:46 -07001211 elif field_to_mod == 'udp_sport':
Rich Lanee717c6e2013-03-12 10:25:50 -07001212 act = ofp.action.set_tp_src()
Rich Lane110e0e32012-10-26 16:21:46 -07001213 act.tp_port = mod_field_vals['udp_sport']
1214 elif field_to_mod == 'udp_dport':
Rich Lanee717c6e2013-03-12 10:25:50 -07001215 act = ofp.action.set_tp_dst()
Rich Lane110e0e32012-10-26 16:21:46 -07001216 act.tp_port = mod_field_vals['udp_dport']
Dan Talayco4b2bee62010-07-20 14:10:05 -07001217 else:
1218 parent.assertTrue(0, "Unknown field to modify: " + str(field_to_mod))
1219
1220 return act
1221
1222def pkt_action_setup(parent, start_field_vals={}, mod_field_vals={},
Rich Lane110e0e32012-10-26 16:21:46 -07001223 mod_fields=[], tp="tcp", check_test_params=False):
Dan Talayco4b2bee62010-07-20 14:10:05 -07001224 """
1225 Set up the ingress and expected packet and action list for a test
1226
Rich Lane2014f9b2012-10-05 15:29:40 -07001227 @param parent Must implement assertTrue
Dan Talayco4b2bee62010-07-20 14:10:05 -07001228 @param start_field_values Field values to use for ingress packet (optional)
1229 @param mod_field_values Field values to use for modified packet (optional)
1230 @param mod_fields The list of fields to be modified by the switch in the test.
1231 @params check_test_params If True, will check the parameters vid, add_vlan
1232 and strip_vlan from the command line.
1233
1234 Returns a triple: pkt-to-send, expected-pkt, action-list
1235 """
1236
1237 new_actions = []
1238
Dan Talayco4b2bee62010-07-20 14:10:05 -07001239 base_pkt_params = {}
1240 base_pkt_params['pktlen'] = 100
Rich Laned0478ff2013-03-11 12:46:58 -07001241 base_pkt_params['eth_dst'] = '00:DE:F0:12:34:56'
1242 base_pkt_params['eth_src'] = '00:23:45:67:89:AB'
Dan Talayco4b2bee62010-07-20 14:10:05 -07001243 base_pkt_params['dl_vlan_enable'] = False
Rich Laned0478ff2013-03-11 12:46:58 -07001244 base_pkt_params['vlan_vid'] = 2
1245 base_pkt_params['vlan_pcp'] = 0
Dan Talayco4b2bee62010-07-20 14:10:05 -07001246 base_pkt_params['ip_src'] = '192.168.0.1'
1247 base_pkt_params['ip_dst'] = '192.168.0.2'
1248 base_pkt_params['ip_tos'] = 0
Rich Lane110e0e32012-10-26 16:21:46 -07001249 if tp == "tcp":
1250 base_pkt_params['tcp_sport'] = 1234
1251 base_pkt_params['tcp_dport'] = 80
1252 elif tp == "udp":
1253 base_pkt_params['udp_sport'] = 1234
1254 base_pkt_params['udp_dport'] = 80
Dan Talayco4b2bee62010-07-20 14:10:05 -07001255 for keyname in start_field_vals.keys():
1256 base_pkt_params[keyname] = start_field_vals[keyname]
1257
1258 mod_pkt_params = {}
1259 mod_pkt_params['pktlen'] = 100
Rich Laned0478ff2013-03-11 12:46:58 -07001260 mod_pkt_params['eth_dst'] = '00:21:0F:ED:CB:A9'
1261 mod_pkt_params['eth_src'] = '00:ED:CB:A9:87:65'
Dan Talayco4b2bee62010-07-20 14:10:05 -07001262 mod_pkt_params['dl_vlan_enable'] = False
Rich Laned0478ff2013-03-11 12:46:58 -07001263 mod_pkt_params['vlan_vid'] = 3
1264 mod_pkt_params['vlan_pcp'] = 7
Dan Talayco4b2bee62010-07-20 14:10:05 -07001265 mod_pkt_params['ip_src'] = '10.20.30.40'
1266 mod_pkt_params['ip_dst'] = '50.60.70.80'
1267 mod_pkt_params['ip_tos'] = 0xf0
Rich Lane110e0e32012-10-26 16:21:46 -07001268 if tp == "tcp":
1269 mod_pkt_params['tcp_sport'] = 4321
1270 mod_pkt_params['tcp_dport'] = 8765
1271 elif tp == "udp":
1272 mod_pkt_params['udp_sport'] = 4321
1273 mod_pkt_params['udp_dport'] = 8765
Dan Talayco4b2bee62010-07-20 14:10:05 -07001274 for keyname in mod_field_vals.keys():
1275 mod_pkt_params[keyname] = mod_field_vals[keyname]
1276
1277 # Check for test param modifications
1278 strip = False
1279 if check_test_params:
Rich Lane2014f9b2012-10-05 15:29:40 -07001280 add_vlan = test_param_get('add_vlan')
1281 strip_vlan = test_param_get('strip_vlan')
1282 vid = test_param_get('vid')
Dan Talayco4b2bee62010-07-20 14:10:05 -07001283
1284 if add_vlan and strip_vlan:
1285 parent.assertTrue(0, "Add and strip VLAN both specified")
1286
1287 if vid:
1288 base_pkt_params['dl_vlan_enable'] = True
Rich Laned0478ff2013-03-11 12:46:58 -07001289 base_pkt_params['vlan_vid'] = vid
1290 if 'vlan_vid' in mod_fields:
1291 mod_pkt_params['vlan_vid'] = vid + 1
Dan Talayco4b2bee62010-07-20 14:10:05 -07001292
1293 if add_vlan:
1294 base_pkt_params['dl_vlan_enable'] = False
1295 mod_pkt_params['dl_vlan_enable'] = True
1296 mod_pkt_params['pktlen'] = base_pkt_params['pktlen'] + 4
1297 mod_fields.append('pktlen')
1298 mod_fields.append('dl_vlan_enable')
Rich Laned0478ff2013-03-11 12:46:58 -07001299 if 'vlan_vid' not in mod_fields:
1300 mod_fields.append('vlan_vid')
Dan Talayco4b2bee62010-07-20 14:10:05 -07001301 elif strip_vlan:
1302 base_pkt_params['dl_vlan_enable'] = True
1303 mod_pkt_params['dl_vlan_enable'] = False
1304 mod_pkt_params['pktlen'] = base_pkt_params['pktlen'] - 4
1305 mod_fields.append('dl_vlan_enable')
1306 mod_fields.append('pktlen')
1307
Rich Lane110e0e32012-10-26 16:21:46 -07001308 if tp == "tcp":
1309 packet_builder = simple_tcp_packet
1310 elif tp == "udp":
1311 packet_builder = simple_udp_packet
1312 else:
1313 raise NotImplementedError("unknown transport protocol %s" % tp)
1314
Dan Talayco4b2bee62010-07-20 14:10:05 -07001315 # Build the ingress packet
Rich Lane110e0e32012-10-26 16:21:46 -07001316 ingress_pkt = packet_builder(**base_pkt_params)
Dan Talayco4b2bee62010-07-20 14:10:05 -07001317
1318 # Build the expected packet, modifying the indicated fields
1319 for item in mod_fields:
1320 base_pkt_params[item] = mod_pkt_params[item]
1321 act = action_generate(parent, item, mod_pkt_params)
1322 if act:
1323 new_actions.append(act)
1324
Rich Lane110e0e32012-10-26 16:21:46 -07001325 expected_pkt = packet_builder(**base_pkt_params)
Dan Talayco4b2bee62010-07-20 14:10:05 -07001326
1327 return (ingress_pkt, expected_pkt, new_actions)
Dan Talayco677c0b72011-08-23 22:53:38 -07001328
1329# Generate a simple "drop" flow mod
1330# If in_band is true, then only drop from first test port
1331def flow_mod_gen(port_map, in_band):
Rich Lanee717c6e2013-03-12 10:25:50 -07001332 request = ofp.message.flow_add()
1333 request.match.wildcards = ofp.OFPFW_ALL
Dan Talayco677c0b72011-08-23 22:53:38 -07001334 if in_band:
Rich Lanee717c6e2013-03-12 10:25:50 -07001335 request.match.wildcards = ofp.OFPFW_ALL - ofp.OFPFW_IN_PORT
Dan Talayco677c0b72011-08-23 22:53:38 -07001336 for of_port, ifname in port_map.items(): # Grab first port
1337 break
1338 request.match.in_port = of_port
1339 request.buffer_id = 0xffffffff
1340 return request
Dan Talaycoba3745c2010-07-21 21:51:08 -07001341
1342def skip_message_emit(parent, s):
1343 """
1344 Print out a 'skipped' message to stderr
1345
1346 @param s The string to print out to the log file
Dan Talaycoba3745c2010-07-21 21:51:08 -07001347 """
1348 global skipped_test_count
1349
1350 skipped_test_count += 1
Rich Lane9a003812012-10-04 17:17:59 -07001351 logging.info("Skipping: " + s)
Dan Talayco2940fdd2013-02-06 15:01:35 -08001352 if oftest.config["debug"] < logging.WARNING:
Dan Talaycoba3745c2010-07-21 21:51:08 -07001353 sys.stderr.write("(skipped) ")
1354 else:
1355 sys.stderr.write("(S)")
Dan Talayco677c0b72011-08-23 22:53:38 -07001356
Dan Talayco8a64e332012-03-28 14:53:20 -07001357
1358def all_stats_get(parent):
1359 """
1360 Get the aggregate stats for all flows in the table
1361 @param parent Test instance with controller connection and assert
1362 @returns dict with keys flows, packets, bytes, active (flows),
1363 lookups, matched
1364 """
Rich Lanee717c6e2013-03-12 10:25:50 -07001365 stat_req = ofp.message.aggregate_stats_request()
1366 stat_req.match = ofp.match()
1367 stat_req.match.wildcards = ofp.OFPFW_ALL
Dan Talayco8a64e332012-03-28 14:53:20 -07001368 stat_req.table_id = 0xff
Rich Lanee717c6e2013-03-12 10:25:50 -07001369 stat_req.out_port = ofp.OFPP_NONE
Dan Talayco8a64e332012-03-28 14:53:20 -07001370
1371 rv = {}
1372
Rich Lanec8aaa3e2012-07-26 19:28:02 -07001373 (reply, pkt) = parent.controller.transact(stat_req)
Rich Lane5fd6faf2013-03-11 13:30:20 -07001374 parent.assertTrue(len(reply.entries) == 1, "Did not receive flow stats reply")
Dan Talayco8a64e332012-03-28 14:53:20 -07001375
Rich Lane5fd6faf2013-03-11 13:30:20 -07001376 for obj in reply.entries:
Dan Talayco8a64e332012-03-28 14:53:20 -07001377 (rv["flows"], rv["packets"], rv["bytes"]) = (obj.flow_count,
1378 obj.packet_count, obj.byte_count)
1379 break
1380
Rich Lanee717c6e2013-03-12 10:25:50 -07001381 request = ofp.message.table_stats_request()
Rich Lanec8aaa3e2012-07-26 19:28:02 -07001382 (reply , pkt) = parent.controller.transact(request)
Dan Talayco8a64e332012-03-28 14:53:20 -07001383
1384
1385 (rv["active"], rv["lookups"], rv["matched"]) = (0,0,0)
Rich Lane5fd6faf2013-03-11 13:30:20 -07001386 for obj in reply.entries:
Dan Talayco8a64e332012-03-28 14:53:20 -07001387 rv["active"] += obj.active_count
1388 rv["lookups"] += obj.lookup_count
1389 rv["matched"] += obj.matched_count
1390
1391 return rv
Dan Talayco2baf8b52012-03-30 09:55:42 -07001392
Rich Lane7744e112013-01-11 17:23:57 -08001393_import_blacklist.add('FILTER')
Dan Talayco2baf8b52012-03-30 09:55:42 -07001394FILTER=''.join([(len(repr(chr(x)))==3) and chr(x) or '.'
1395 for x in range(256)])
1396
1397def hex_dump_buffer(src, length=16):
1398 """
1399 Convert src to a hex dump string and return the string
1400 @param src The source buffer
1401 @param length The number of bytes shown in each line
1402 @returns A string showing the hex dump
1403 """
Dan Talaycoc516fa02012-04-12 22:28:43 -07001404 result = ["\n"]
Dan Talayco2baf8b52012-03-30 09:55:42 -07001405 for i in xrange(0, len(src), length):
1406 chars = src[i:i+length]
1407 hex = ' '.join(["%02x" % ord(x) for x in chars])
1408 printable = ''.join(["%s" % ((ord(x) <= 127 and
1409 FILTER[ord(x)]) or '.') for x in chars])
1410 result.append("%04x %-*s %s\n" % (i, length*3, hex, printable))
1411 return ''.join(result)
1412
1413def format_packet(pkt):
1414 return "Packet length %d \n%s" % (len(str(pkt)),
1415 hex_dump_buffer(str(pkt)))
Rich Lane5d7e89a2012-10-26 16:43:13 -07001416
1417def inspect_packet(pkt):
1418 """
1419 Wrapper around scapy's show() method.
1420 @returns A string showing the dissected packet.
1421 """
1422 from cStringIO import StringIO
1423 out = None
1424 backup = sys.stdout
1425 try:
Rich Lanefdec0fb2013-08-09 18:01:05 -07001426 tmp = StringIO()
1427 sys.stdout = tmp
Rich Lane5d7e89a2012-10-26 16:43:13 -07001428 pkt.show2()
Rich Lanefdec0fb2013-08-09 18:01:05 -07001429 out = tmp.getvalue()
1430 tmp.close()
Rich Lane5d7e89a2012-10-26 16:43:13 -07001431 finally:
1432 sys.stdout = backup
1433 return out
Rich Lane0a4f6372013-01-02 14:40:22 -08001434
1435def nonstandard(cls):
1436 """
Rich Lanecc45b8e2013-01-02 15:55:02 -08001437 Testcase decorator that marks the test as being non-standard.
1438 These tests are not automatically added to the "standard" group.
Rich Lane0a4f6372013-01-02 14:40:22 -08001439 """
Rich Lanecc45b8e2013-01-02 15:55:02 -08001440 cls._nonstandard = True
Rich Lane0a4f6372013-01-02 14:40:22 -08001441 return cls
1442
1443def disabled(cls):
1444 """
Rich Lanecc45b8e2013-01-02 15:55:02 -08001445 Testcase decorator that marks the test as being disabled.
1446 These tests are not automatically added to the "standard" group or
1447 their module's group.
Rich Lane0a4f6372013-01-02 14:40:22 -08001448 """
Rich Lanecc45b8e2013-01-02 15:55:02 -08001449 cls._disabled = True
Rich Lane0a4f6372013-01-02 14:40:22 -08001450 return cls
Rich Lane97e99652013-01-02 17:23:20 -08001451
1452def group(name):
1453 """
1454 Testcase decorator that adds the test to a group.
1455 """
1456 def fn(cls):
1457 if not hasattr(cls, "_groups"):
1458 cls._groups = []
1459 cls._groups.append(name)
1460 return cls
1461 return fn
Rich Lane5a9a1922013-01-11 14:29:30 -08001462
1463def version(ver):
1464 """
1465 Testcase decorator that specifies which versions of OpenFlow the test
1466 supports. The default is 1.0+. This decorator may only be used once.
1467
1468 Supported syntax:
1469 1.0 -> 1.0
1470 1.0,1.2,1.3 -> 1.0, 1.2, 1.3
1471 1.0+ -> 1.0, 1.1, 1.2, 1.3
1472 """
1473 versions = parse_version(ver)
1474 def fn(cls):
1475 cls._versions = versions
1476 return cls
1477 return fn
1478
1479def parse_version(ver):
1480 allowed_versions = ["1.0", "1.1", "1.2", "1.3"]
1481 if re.match("^1\.\d+$", ver):
1482 versions = set([ver])
1483 elif re.match("^(1\.\d+)\+$", ver):
1484 if not ver[:-1] in allowed_versions:
1485 raise ValueError("invalid OpenFlow version %s" % ver[:-1])
1486 versions = set()
1487 if ver != "1.1+": versions.add("1.0")
1488 if ver != "1.2+": versions.add("1.1")
1489 if ver != "1.3+": versions.add("1.2")
1490 versions.add("1.3")
1491 else:
1492 versions = set(ver.split(','))
1493
1494 for version in versions:
1495 if not version in allowed_versions:
1496 raise ValueError("invalid OpenFlow version %s" % version)
1497
1498 return versions
1499
1500assert(parse_version("1.0") == set(["1.0"]))
1501assert(parse_version("1.0,1.2,1.3") == set(["1.0", "1.2", "1.3"]))
1502assert(parse_version("1.0+") == set(["1.0", "1.1", "1.2", "1.3"]))
Rich Lane7744e112013-01-11 17:23:57 -08001503
Rich Laneae3428c2013-03-07 14:37:42 -08001504def get_stats(test, req):
1505 """
1506 Retrieve a list of stats entries. Handles OFPSF_REPLY_MORE.
1507 """
Rich Lane609194f2013-10-21 06:17:37 -07001508 msgtype = ofp.OFPT_STATS_REPLY
1509 more_flag = ofp.OFPSF_REPLY_MORE
Rich Laneae3428c2013-03-07 14:37:42 -08001510 stats = []
1511 reply, _ = test.controller.transact(req)
1512 test.assertTrue(reply is not None, "No response to stats request")
Rich Lane34c68d52013-10-11 10:38:21 -07001513 test.assertEquals(reply.type, msgtype, "Response had unexpected message type")
Rich Lane5fd6faf2013-03-11 13:30:20 -07001514 stats.extend(reply.entries)
Rich Lanebd56ed62013-07-10 15:49:44 -07001515 while reply.flags & more_flag != 0:
Rich Lane34c68d52013-10-11 10:38:21 -07001516 reply, pkt = test.controller.poll(exp_msg=msgtype)
Rich Laneae3428c2013-03-07 14:37:42 -08001517 test.assertTrue(reply is not None, "No response to stats request")
Rich Lane5fd6faf2013-03-11 13:30:20 -07001518 stats.extend(reply.entries)
Rich Laneae3428c2013-03-07 14:37:42 -08001519 return stats
1520
Rich Lanebd56ed62013-07-10 15:49:44 -07001521def get_flow_stats(test, match, table_id=None,
1522 out_port=None, out_group=None,
1523 cookie=0, cookie_mask=0):
Rich Laneae3428c2013-03-07 14:37:42 -08001524 """
1525 Retrieve a list of flow stats entries.
1526 """
Rich Lanebd56ed62013-07-10 15:49:44 -07001527
1528 if table_id == None:
1529 if ofp.OFP_VERSION <= 2:
1530 table_id = 0xff
1531 else:
1532 table_id = ofp.OFPTT_ALL
1533
Rich Lanef3bc48c2013-05-03 17:39:35 -07001534 if out_port == None:
Rich Lanebd56ed62013-07-10 15:49:44 -07001535 if ofp.OFP_VERSION == 1:
1536 out_port = ofp.OFPP_NONE
1537 else:
1538 out_port = ofp.OFPP_ANY
1539
1540 if out_group == None:
1541 if ofp.OFP_VERSION > 1:
1542 out_group = ofp.OFPP_ANY
1543
Rich Lanee717c6e2013-03-12 10:25:50 -07001544 req = ofp.message.flow_stats_request(match=match,
Rich Lanebd56ed62013-07-10 15:49:44 -07001545 table_id=table_id,
1546 out_port=out_port)
1547 if ofp.OFP_VERSION > 1:
1548 req.out_group = out_group
1549 req.cookie = cookie
1550 req.cookie_mask = cookie_mask
1551
Rich Laneae3428c2013-03-07 14:37:42 -08001552 return get_stats(test, req)
1553
Rich Lane968b6192013-03-07 15:34:43 -08001554def get_port_stats(test, port_no):
1555 """
1556 Retrieve a list of port stats entries.
1557 """
Rich Lanee717c6e2013-03-12 10:25:50 -07001558 req = ofp.message.port_stats_request(port_no=port_no)
Rich Lane968b6192013-03-07 15:34:43 -08001559 return get_stats(test, req)
1560
Rich Lane6a334922013-03-07 16:14:52 -08001561def get_queue_stats(test, port_no, queue_id):
1562 """
1563 Retrieve a list of queue stats entries.
1564 """
Rich Lanee717c6e2013-03-12 10:25:50 -07001565 req = ofp.message.queue_stats_request(port_no=port_no, queue_id=queue_id)
Rich Lane6a334922013-03-07 16:14:52 -08001566 return get_stats(test, req)
1567
Rich Laneae3428c2013-03-07 14:37:42 -08001568def verify_flow_stats(test, match, table_id=0xff,
Rich Laneae3428c2013-03-07 14:37:42 -08001569 initial=[],
1570 pkts=None, bytes=None):
1571 """
1572 Verify that flow stats changed as expected.
1573
1574 Optionally takes an 'initial' list of stats entries, as returned by
1575 get_flow_stats(). If 'initial' is not given the counters are assumed to
1576 begin at 0.
1577 """
Rich Lanef3bc48c2013-05-03 17:39:35 -07001578
Rich Laneae3428c2013-03-07 14:37:42 -08001579 def accumulate(stats):
1580 pkts_acc = bytes_acc = 0
1581 for stat in stats:
1582 pkts_acc += stat.packet_count
1583 bytes_acc += stat.byte_count
1584 return (pkts_acc, bytes_acc)
1585
1586 pkts_before, bytes_before = accumulate(initial)
1587
1588 # Wait 10s for counters to update
1589 pkt_diff = byte_diff = None
1590 for i in range(0, 100):
Rich Lane61edad52014-03-28 16:25:08 -07001591 stats = get_flow_stats(test, match, table_id=table_id)
Rich Laneae3428c2013-03-07 14:37:42 -08001592 pkts_after, bytes_after = accumulate(stats)
1593 pkt_diff = pkts_after - pkts_before
1594 byte_diff = bytes_after - bytes_before
1595 if (pkts == None or pkt_diff >= pkts) and \
1596 (bytes == None or byte_diff >= bytes):
1597 break
Dan Talayco53724732013-03-08 23:54:02 -08001598 time.sleep(0.1)
Rich Laneae3428c2013-03-07 14:37:42 -08001599
1600 if pkts != None:
1601 test.assertEquals(pkt_diff, pkts, "Flow packet counter not updated properly (expected increase of %d, got increase of %d)" % (pkts, pkt_diff))
1602
1603 if bytes != None:
Rich Lane53b96812013-03-07 16:54:50 -08001604 test.assertTrue(byte_diff >= bytes and byte_diff <= bytes*1.1,
1605 "Flow byte counter not updated properly (expected increase of %d, got increase of %d)" % (bytes, byte_diff))
Rich Laneae3428c2013-03-07 14:37:42 -08001606
Rich Lane968b6192013-03-07 15:34:43 -08001607def verify_port_stats(test, port,
1608 initial=[],
1609 tx_pkts=None, rx_pkts=None,
1610 tx_bytes=None, rx_bytes=None):
1611 """
1612 Verify that port stats changed as expected.
1613
1614 Optionally takes an 'initial' list of stats entries, as returned by
1615 get_port_stats(). If 'initial' is not given the counters are assumed to
1616 begin at 0.
1617 """
1618 def accumulate(stats):
1619 tx_pkts_acc = rx_pkts_acc = tx_bytes_acc = rx_bytes_acc = 0
1620 for stat in stats:
1621 tx_pkts_acc += stat.tx_packets
1622 rx_pkts_acc += stat.rx_packets
1623 tx_bytes_acc += stat.tx_bytes
1624 rx_bytes_acc += stat.rx_bytes
1625 return (tx_pkts_acc, rx_pkts_acc, tx_bytes_acc, rx_bytes_acc)
1626
1627 tx_pkts_before, rx_pkts_before, \
1628 tx_bytes_before, rx_bytes_before = accumulate(initial)
1629
1630 # Wait 10s for counters to update
1631 for i in range(0, 100):
1632 stats = get_port_stats(test, port)
1633 tx_pkts_after, rx_pkts_after, \
1634 tx_bytes_after, rx_bytes_after = accumulate(stats)
1635 tx_pkts_diff = tx_pkts_after - tx_pkts_before
1636 rx_pkts_diff = rx_pkts_after - rx_pkts_before
1637 tx_bytes_diff = tx_bytes_after - tx_bytes_before
1638 rx_bytes_diff = rx_bytes_after - rx_bytes_before
Rich Lane3a208f82015-04-10 12:37:57 -07001639 if (tx_pkts == None or tx_pkts <= tx_pkts_diff) and \
1640 (rx_pkts == None or rx_pkts <= rx_pkts_diff) and \
Rich Lane53b96812013-03-07 16:54:50 -08001641 (tx_bytes == None or tx_bytes <= tx_bytes_diff) and \
1642 (rx_bytes == None or rx_bytes <= rx_bytes_diff):
Rich Lane968b6192013-03-07 15:34:43 -08001643 break
1644 time.sleep(0.1)
1645
1646 if (tx_pkts != None):
Rich Lane3a208f82015-04-10 12:37:57 -07001647 test.assertGreaterEqual(tx_pkts_diff, tx_pkts,
1648 "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 -08001649 if (rx_pkts != None):
Rich Lane3a208f82015-04-10 12:37:57 -07001650 test.assertGreaterEqual(rx_pkts_diff, rx_pkts,
1651 "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 -08001652 if (tx_bytes != None):
Rich Lane3a208f82015-04-10 12:37:57 -07001653 test.assertGreaterEqual(tx_bytes_diff, tx_bytes,
1654 "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 -08001655 if (rx_bytes != None):
Rich Lane3a208f82015-04-10 12:37:57 -07001656 test.assertGreaterEqual(rx_bytes_diff, rx_bytes,
1657 "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 -08001658
Rich Lane6a334922013-03-07 16:14:52 -08001659def verify_queue_stats(test, port_no, queue_id,
1660 initial=[],
1661 pkts=None, bytes=None):
1662 """
1663 Verify that queue stats changed as expected.
1664
1665 Optionally takes an 'initial' list of stats entries, as returned by
1666 get_queue_stats(). If 'initial' is not given the counters are assumed to
1667 begin at 0.
1668 """
1669 def accumulate(stats):
1670 pkts_acc = bytes_acc = 0
1671 for stat in stats:
1672 pkts_acc += stat.tx_packets
1673 bytes_acc += stat.tx_bytes
1674 return (pkts_acc, bytes_acc)
1675
1676 pkts_before, bytes_before = accumulate(initial)
1677
1678 # Wait 10s for counters to update
1679 pkt_diff = byte_diff = None
1680 for i in range(0, 100):
1681 stats = get_queue_stats(test, port_no, queue_id)
1682 pkts_after, bytes_after = accumulate(stats)
1683 pkt_diff = pkts_after - pkts_before
1684 byte_diff = bytes_after - bytes_before
1685 if (pkts == None or pkt_diff >= pkts) and \
1686 (bytes == None or byte_diff >= bytes):
1687 break
Dan Talayco53724732013-03-08 23:54:02 -08001688 time.sleep(0.1)
Rich Lane6a334922013-03-07 16:14:52 -08001689
1690 if pkts != None:
1691 test.assertEquals(pkt_diff, pkts, "Queue packet counter not updated properly (expected increase of %d, got increase of %d)" % (pkts, pkt_diff))
1692
1693 if bytes != None:
Rich Lane53b96812013-03-07 16:54:50 -08001694 test.assertTrue(byte_diff >= bytes and byte_diff <= bytes*1.1,
1695 "Queue byte counter not updated properly (expected increase of %d, got increase of %d)" % (bytes, byte_diff))
Rich Laneae3428c2013-03-07 14:37:42 -08001696
Rich Lane4c504f32013-06-07 17:24:14 -07001697def packet_in_match(msg, data, in_port=None, reason=None):
1698 """
1699 Check whether the packet_in message 'msg' has fields matching 'data',
1700 'in_port', and 'reason'.
1701
1702 This function handles truncated packet_in data. The 'in_port' and 'reason'
1703 parameters are optional.
1704
1705 @param msg packet_in message
1706 @param data Expected packet_in data
1707 @param in_port Expected packet_in in_port, or None
1708 @param reason Expected packet_in reason, or None
1709 """
1710
Rich Lanec0d26dd2013-07-10 12:46:03 -07001711 if ofp.OFP_VERSION <= 2:
1712 pkt_in_port = msg.in_port
1713 else:
1714 oxms = { type(oxm): oxm for oxm in msg.match.oxm_list }
1715 if ofp.oxm.in_port in oxms:
1716 pkt_in_port = oxms[ofp.oxm.in_port].value
1717 else:
1718 logging.warn("Missing in_port in packet-in message")
1719 pkt_in_port = None
1720
1721 if in_port != None and in_port != pkt_in_port:
Rich Lane9f2f17e2013-09-13 13:19:37 -07001722 logging.debug("Incorrect packet_in in_port (expected %d, received %d)", in_port, pkt_in_port)
Rich Lane4c504f32013-06-07 17:24:14 -07001723 return False
1724
Rich Lanec0d26dd2013-07-10 12:46:03 -07001725 if reason != None and reason != msg.reason:
Rich Lane4c504f32013-06-07 17:24:14 -07001726 logging.debug("Incorrect packet_in reason (expected %d, received %d)", reason, msg.reason)
1727 return False
1728
1729 # Check that one of the packets is a prefix of the other.
1730 # The received packet may be either truncated or padded, but not both.
1731 # (Some of the padding may be truncated but that's irrelevant). We
1732 # need to check that the smaller packet is a prefix of the larger one.
1733 # Note that this check succeeds if the switch sends a zero-length
1734 # packet-in.
1735 compare_len = min(len(msg.data), len(data))
1736 if data[:compare_len] != msg.data[:compare_len]:
1737 logging.debug("Incorrect packet_in data")
1738 logging.debug("Expected %s" % format_packet(data[:compare_len]))
1739 logging.debug("Received %s" % format_packet(msg.data[:compare_len]))
1740 return False
1741
1742 return True
1743
1744def verify_packet_in(test, data, in_port, reason, controller=None):
1745 """
1746 Assert that the controller receives a packet_in message matching data 'data'
1747 from port 'in_port' with reason 'reason'. Does not trigger the packet_in
1748 itself, that's up to the test case.
1749
1750 @param test Instance of base_tests.SimpleProtocol
1751 @param pkt String to expect as the packet_in data
1752 @param in_port OpenFlow port number to expect as the packet_in in_port
1753 @param reason One of OFPR_* to expect as the packet_in reason
1754 @param controller Controller instance, defaults to test.controller
1755 @returns The received packet-in message
1756 """
1757
1758 if controller == None:
1759 controller = test.controller
1760
1761 end_time = time.time() + oftest.ofutils.default_timeout
1762
1763 while True:
1764 msg, _ = controller.poll(ofp.OFPT_PACKET_IN, end_time - time.time())
1765 if not msg:
1766 # Timeout
1767 break
1768 elif packet_in_match(msg, data, in_port, reason):
1769 # Found a matching message
1770 break
1771
Kiran Poola58c5c042014-05-15 15:11:06 -07001772 test.assertTrue(msg is not None, 'Packet in message not received on port %r' % in_port)
Rich Lane4c504f32013-06-07 17:24:14 -07001773 return msg
1774
1775def verify_no_packet_in(test, data, in_port, controller=None):
1776 """
1777 Assert that the controller does not receive a packet_in message matching
1778 data 'data' from port 'in_port'.
1779
1780 @param test Instance of base_tests.SimpleProtocol
1781 @param pkt String to expect as the packet_in data
1782 @param in_port OpenFlow port number to expect as the packet_in in_port
1783 @param controller Controller instance, defaults to test.controller
1784 """
1785
1786 if controller == None:
1787 controller = test.controller
1788
1789 # Negative test, need to wait a short amount of time before checking we
1790 # didn't receive the message.
Rich Lane48f6aed2014-03-23 15:51:02 -07001791 time.sleep(oftest.ofutils.default_negative_timeout)
Rich Lane4c504f32013-06-07 17:24:14 -07001792
1793 # Check every packet_in queued in the controller
1794 while True:
1795 msg, _ = controller.poll(ofp.OFPT_PACKET_IN, timeout=0)
1796 if msg == None:
1797 # No more queued packet_in messages
1798 break
1799 elif packet_in_match(msg, data, in_port, None):
1800 # Found a matching message
1801 break
1802
Rich Lane82c882d2013-08-09 17:13:52 -07001803 if in_port == None:
1804 test.assertTrue(msg == None, "Did not expect a packet-in message on any port")
1805 else:
1806 test.assertTrue(msg == None, "Did not expect a packet-in message on port %d" % in_port)
Rich Lane4c504f32013-06-07 17:24:14 -07001807
Rich Lane045db072013-08-06 13:16:30 -07001808def openflow_ports(num=None):
1809 """
1810 Return a list of 'num' OpenFlow port numbers
1811
1812 If 'num' is None, return all available ports. Otherwise, limit the length
1813 of the result to 'num' and raise an exception if not enough ports are
1814 available.
1815 """
1816 ports = sorted(oftest.config["port_map"].keys())
1817 if num != None and len(ports) < num:
1818 raise Exception("test requires %d ports but only %d are available" % (num, len(ports)))
1819 return ports[:num]
1820
Rich Lanee4b384d2013-09-13 14:33:40 -07001821def verify_packet(test, pkt, ofport):
1822 """
1823 Check that an expected packet is received
1824 """
1825 logging.debug("Checking for pkt on port %r", ofport)
1826 (rcv_port, rcv_pkt, pkt_time) = test.dataplane.poll(port_number=ofport, exp_pkt=str(pkt))
1827 test.assertTrue(rcv_pkt != None, "Did not receive pkt on %r" % ofport)
macauley17cd60d2015-07-27 17:41:18 +08001828 return (rcv_port, rcv_pkt, pkt_time)
1829
Rich Lanee4b384d2013-09-13 14:33:40 -07001830def verify_no_packet(test, pkt, ofport):
1831 """
1832 Check that a particular packet is not received
1833 """
1834 logging.debug("Negative check for pkt on port %r", ofport)
Rich Lane48f6aed2014-03-23 15:51:02 -07001835 (rcv_port, rcv_pkt, pkt_time) = \
1836 test.dataplane.poll(
1837 port_number=ofport, exp_pkt=str(pkt),
1838 timeout=oftest.ofutils.default_negative_timeout)
Rich Lanee4b384d2013-09-13 14:33:40 -07001839 test.assertTrue(rcv_pkt == None, "Received packet on %r" % ofport)
1840
1841def verify_no_other_packets(test):
1842 """
1843 Check that no unexpected packets are received
1844
1845 This is a no-op if the --relax option is in effect.
1846 """
1847 if oftest.config["relax"]:
1848 return
1849 logging.debug("Checking for unexpected packets on all ports")
Rich Lane48f6aed2014-03-23 15:51:02 -07001850 (rcv_port, rcv_pkt, pkt_time) = test.dataplane.poll(timeout=oftest.ofutils.default_negative_timeout)
Rich Lanee4b384d2013-09-13 14:33:40 -07001851 if rcv_pkt != None:
1852 logging.debug("Received unexpected packet on port %r: %s", rcv_port, format_packet(rcv_pkt))
1853 test.assertTrue(rcv_pkt == None, "Unexpected packet on port %r" % rcv_port)
1854
1855def verify_packets(test, pkt, ofports):
1856 """
1857 Check that a packet is received on certain ports
1858
1859 Also verifies that the packet is not received on any other ports, and that no
1860 other packets are received (unless --relax is in effect).
1861
1862 This covers the common and simplest cases for checking dataplane outputs.
1863 For more complex usage, like multiple different packets being output, or
1864 multiple packets on the same port, use the primitive verify_packet,
1865 verify_no_packet, and verify_no_other_packets functions directly.
1866 """
1867 pkt = str(pkt)
1868 for ofport in openflow_ports():
1869 if ofport in ofports:
1870 verify_packet(test, pkt, ofport)
1871 else:
1872 verify_no_packet(test, pkt, ofport)
1873 verify_no_other_packets(test)
1874
Rich Lane12d04592013-10-10 17:21:07 -07001875def verify_no_errors(ctrl):
1876 error, _ = ctrl.poll(ofp.OFPT_ERROR, 0)
1877 if error:
1878 raise AssertionError("unexpected error type=%d code=%d" % (error.err_type, error.code))
Rich Lanee4b384d2013-09-13 14:33:40 -07001879
Jonathan Stoutfcee3142014-01-28 15:46:22 -05001880def verify_capability(test, capability):
1881 """
Jonathan Stout073642d2014-02-04 13:41:48 -05001882 Return True if DUT supports the specified capability.
Jonathan Stoutfcee3142014-01-28 15:46:22 -05001883
1884 @param test Instance of base_tests.SimpleProtocol
1885 @param capability One of ofp_capabilities.
1886 """
1887 logging.info("Verifing that capability code is valid.")
1888 test.assertIn(capability, ofp.const.ofp_capabilities_map,
1889 "Capability code %d does not exist." % capability)
1890 capability_str = ofp.const.ofp_capabilities_map[capability]
1891
1892 logging.info(("Sending features_request to test if capability "
Jonathan Stout97e458a2014-01-28 16:08:04 -05001893 "%s is supported."), capability_str)
Jonathan Stoutfcee3142014-01-28 15:46:22 -05001894 req = ofp.message.features_request()
1895 res, raw = test.controller.transact(req)
1896 test.assertIsNotNone(res, "Did not receive a response from the DUT.")
1897 test.assertEqual(res.type, ofp.OFPT_FEATURES_REPLY,
1898 ("Unexpected packet type %d received in response to "
1899 "OFPT_FEATURES_REQUEST") % res.type)
Jonathan Stout641167f2014-02-04 12:07:10 -05001900 logging.info("Received features_reply.")
Jonathan Stoutfcee3142014-01-28 15:46:22 -05001901
Jonathan Stout641167f2014-02-04 12:07:10 -05001902 if (res.capabilities & capability) > 0:
1903 logging.info("Switch capabilities bitmask claims to support %s",
1904 capability_str)
1905 return True, res.capabilities
1906 else:
1907 logging.info("Capabilities bitmask does not support %s.",
1908 capability_str)
1909 return False, res.capabilities
Jonathan Stoutfcee3142014-01-28 15:46:22 -05001910
Jonathan Stouteb3721d2014-02-04 13:59:12 -05001911def verify_configuration_flag(test, flag):
1912 """
1913 Return True if DUT supports specified configuration flag.
1914
1915 @param test Instance of base_tests.SimpleProtocol
1916 @param flag One of ofp_config_flags.
Jonathan Stout1ec8c0f2014-02-04 15:25:38 -05001917 @returns (supported, flags) Bool if flag is set and flag values.
Jonathan Stouteb3721d2014-02-04 13:59:12 -05001918 """
1919 logging.info("Verifing that flag is valid.")
1920 test.assertIn(flag, ofp.const.ofp_config_flags_map,
1921 "flag %s does not exist." % flag)
1922 flag_str = ofp.const.ofp_config_flags_map[flag]
1923
1924 logging.info("Sending OFPT_GET_CONFIG_REQUEST.")
1925 req = ofp.message.get_config_request()
1926 rv = test.controller.message_send(req)
1927 test.assertNotEqual(rv, -1, "Not able to send get_config_request.")
1928
1929 logging.info("Expecting OFPT_GET_CONFIG_REPLY ")
1930 (res, pkt) = test.controller.poll(exp_msg=ofp.OFPT_GET_CONFIG_REPLY,
1931 timeout=2)
1932 test.assertIsNotNone(res, "Did not receive OFPT_GET_CONFIG_REPLY")
1933 logging.info("Received OFPT_GET_CONFIG_REPLY ")
1934
1935 if res.flags == flag:
1936 logging.info("%s flag is set.", flag_str)
1937 return True, res.flags
1938 else:
1939 logging.info("%s flag is not set.", flag_str)
1940 return False, res.flags
1941
Rich Lane7744e112013-01-11 17:23:57 -08001942__all__ = list(set(locals()) - _import_blacklist)