blob: cc02d2eea45cadd7b6bbfe123b7bf4c4122fff19 [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
296
macauley17cd60d2015-07-27 17:41:18 +0800297 #add vxlan header
298 pkt = pkt/scapy.VXLAN(vni=vnid)
299 #add innder payload
macauley1b23af82015-07-30 14:06:33 +0800300 if inner_payload!=None:
301 pkt=pkt/inner_payload
macauley17cd60d2015-07-27 17:41:18 +0800302
303 return pkt
304
Rich Lane86aceb02013-07-17 18:45:38 -0700305def simple_udpv6_packet(pktlen=100,
306 eth_dst='00:01:02:03:04:05',
307 eth_src='00:06:07:08:09:0a',
308 dl_vlan_enable=False,
309 vlan_vid=0,
310 vlan_pcp=0,
311 ipv6_src='2001:db8:85a3::8a2e:370:7334',
312 ipv6_dst='2001:db8:85a3::8a2e:370:7335',
313 ipv6_tc=0,
314 ipv6_hlim=64,
315 ipv6_fl=0,
316 udp_sport=1234,
317 udp_dport=80):
318 """
319 Return a simple IPv6/UDP packet
320
321 Supports a few parameters:
322 @param len Length of packet in bytes w/o CRC
323 @param eth_dst Destination MAC
324 @param eth_src Source MAC
325 @param dl_vlan_enable True if the packet is with vlan, False otherwise
326 @param vlan_vid VLAN ID
327 @param vlan_pcp VLAN priority
328 @param ipv6_src IPv6 source
329 @param ipv6_dst IPv6 destination
330 @param ipv6_tc IPv6 traffic class
331 @param ipv6_ttl IPv6 hop limit
332 @param ipv6_fl IPv6 flow label
333 @param udp_dport UDP destination port
334 @param udp_sport UDP source port
335
336 Generates a simple UDP request. Users shouldn't assume anything about this
337 packet other than that it is a valid ethernet/IPv6/UDP frame.
338 """
339
340 if MINSIZE > pktlen:
341 pktlen = MINSIZE
342
343 pkt = scapy.Ether(dst=eth_dst, src=eth_src)
344 if dl_vlan_enable or vlan_vid or vlan_pcp:
345 pkt /= scapy.Dot1Q(vlan=vlan_vid, prio=vlan_pcp)
346 pkt /= scapy.IPv6(src=ipv6_src, dst=ipv6_dst, fl=ipv6_fl, tc=ipv6_tc, hlim=ipv6_hlim)
347 pkt /= scapy.UDP(sport=udp_sport, dport=udp_dport)
348 pkt /= ("D" * (pktlen - len(pkt)))
349
350 return pkt
351
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700352def simple_icmp_packet(pktlen=60,
Rich Laned0478ff2013-03-11 12:46:58 -0700353 eth_dst='00:01:02:03:04:05',
354 eth_src='00:06:07:08:09:0a',
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700355 dl_vlan_enable=False,
Rich Laned0478ff2013-03-11 12:46:58 -0700356 vlan_vid=0,
357 vlan_pcp=0,
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700358 ip_src='192.168.0.1',
359 ip_dst='192.168.0.2',
360 ip_tos=0,
Gregor Maier9cc93342013-01-29 16:55:28 -0800361 ip_ttl=64,
Harshmeet Singhd209c0b2014-01-28 09:48:58 -0600362 ip_id=1,
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700363 icmp_type=8,
Harshmeet Singhd209c0b2014-01-28 09:48:58 -0600364 icmp_code=0,
Harshmeet Singh45b2a9d2014-01-28 13:02:04 -0600365 icmp_data=''):
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700366 """
367 Return a simple ICMP packet
368
369 Supports a few parameters:
370 @param len Length of packet in bytes w/o CRC
Rich Laned0478ff2013-03-11 12:46:58 -0700371 @param eth_dst Destinatino MAC
372 @param eth_src Source MAC
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700373 @param dl_vlan_enable True if the packet is with vlan, False otherwise
Rich Laned0478ff2013-03-11 12:46:58 -0700374 @param vlan_vid VLAN ID
375 @param vlan_pcp VLAN priority
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700376 @param ip_src IP source
377 @param ip_dst IP destination
378 @param ip_tos IP ToS
Gregor Maier9cc93342013-01-29 16:55:28 -0800379 @param ip_ttl IP TTL
Harshmeet Singhd209c0b2014-01-28 09:48:58 -0600380 @param ip_id IP Identification
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700381 @param icmp_type ICMP type
382 @param icmp_code ICMP code
Harshmeet Singhd209c0b2014-01-28 09:48:58 -0600383 @param icmp_data ICMP data
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700384
385 Generates a simple ICMP ECHO REQUEST. Users
386 shouldn't assume anything about this packet other than that
387 it is a valid ethernet/ICMP frame.
388 """
Jeffrey Townsend5cb7ed32012-08-17 18:11:01 +0000389
390 if MINSIZE > pktlen:
391 pktlen = MINSIZE
392
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700393 if (dl_vlan_enable):
Rich Laned0478ff2013-03-11 12:46:58 -0700394 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
395 scapy.Dot1Q(prio=vlan_pcp, id=0, vlan=vlan_vid)/ \
Harshmeet Singhd209c0b2014-01-28 09:48:58 -0600396 scapy.IP(src=ip_src, dst=ip_dst, ttl=ip_ttl, tos=ip_tos, id=ip_id)/ \
Harshmeet Singh45b2a9d2014-01-28 13:02:04 -0600397 scapy.ICMP(type=icmp_type, code=icmp_code)/ icmp_data
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700398 else:
Rich Laned0478ff2013-03-11 12:46:58 -0700399 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
Harshmeet Singhd209c0b2014-01-28 09:48:58 -0600400 scapy.IP(src=ip_src, dst=ip_dst, ttl=ip_ttl, tos=ip_tos, id=ip_id)/ \
Harshmeet Singh45b2a9d2014-01-28 13:02:04 -0600401 scapy.ICMP(type=icmp_type, code=icmp_code)/ icmp_data
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700402
403 pkt = pkt/("0" * (pktlen - len(pkt)))
404
405 return pkt
406
Rich Lane86aceb02013-07-17 18:45:38 -0700407def simple_icmpv6_packet(pktlen=100,
408 eth_dst='00:01:02:03:04:05',
409 eth_src='00:06:07:08:09:0a',
410 dl_vlan_enable=False,
411 vlan_vid=0,
412 vlan_pcp=0,
413 ipv6_src='2001:db8:85a3::8a2e:370:7334',
414 ipv6_dst='2001:db8:85a3::8a2e:370:7335',
415 ipv6_tc=0,
416 ipv6_hlim=64,
417 ipv6_fl=0,
418 icmp_type=8,
419 icmp_code=0):
420 """
421 Return a simple ICMPv6 packet
422
423 Supports a few parameters:
424 @param len Length of packet in bytes w/o CRC
425 @param eth_dst Destination MAC
426 @param eth_src Source MAC
427 @param dl_vlan_enable True if the packet is with vlan, False otherwise
428 @param vlan_vid VLAN ID
429 @param vlan_pcp VLAN priority
430 @param ipv6_src IPv6 source
431 @param ipv6_dst IPv6 destination
432 @param ipv6_tc IPv6 traffic class
433 @param ipv6_ttl IPv6 hop limit
434 @param ipv6_fl IPv6 flow label
435 @param icmp_type ICMP type
436 @param icmp_code ICMP code
437
438 Generates a simple ICMP ECHO REQUEST. Users shouldn't assume anything
439 about this packet other than that it is a valid ethernet/IPv6/ICMP frame.
440 """
441
442 if MINSIZE > pktlen:
443 pktlen = MINSIZE
444
445 pkt = scapy.Ether(dst=eth_dst, src=eth_src)
446 if dl_vlan_enable or vlan_vid or vlan_pcp:
447 pkt /= scapy.Dot1Q(vlan=vlan_vid, prio=vlan_pcp)
448 pkt /= scapy.IPv6(src=ipv6_src, dst=ipv6_dst, fl=ipv6_fl, tc=ipv6_tc, hlim=ipv6_hlim)
449 pkt /= scapy.ICMPv6Unknown(type=icmp_type, code=icmp_code)
450 pkt /= ("D" * (pktlen - len(pkt)))
451
452 return pkt
453
Shudong Zhouc7562b12013-02-06 01:12:18 -0800454def simple_arp_packet(pktlen=60,
Rich Laned0478ff2013-03-11 12:46:58 -0700455 eth_dst='ff:ff:ff:ff:ff:ff',
456 eth_src='00:06:07:08:09:0a',
Rich Lanee01611f2014-01-15 14:55:11 -0800457 vlan_vid=0,
458 vlan_pcp=0,
Shudong Zhouc7562b12013-02-06 01:12:18 -0800459 arp_op=1,
460 ip_snd='192.168.0.1',
461 ip_tgt='192.168.0.2',
462 hw_snd='00:06:07:08:09:0a',
463 hw_tgt='00:00:00:00:00:00',
464 ):
465 """
466 Return a simple ARP packet
467
468 Supports a few parameters:
469 @param len Length of packet in bytes w/o CRC
Rich Laned0478ff2013-03-11 12:46:58 -0700470 @param eth_dst Destinatino MAC
471 @param eth_src Source MAC
Shudong Zhouc7562b12013-02-06 01:12:18 -0800472 @param arp_op Operation (1=request, 2=reply)
473 @param ip_snd Sender IP
474 @param ip_tgt Target IP
475 @param hw_snd Sender hardware address
476 @param hw_tgt Target hardware address
477
478 Generates a simple ARP REQUEST. Users
479 shouldn't assume anything about this packet other than that
480 it is a valid ethernet/ARP frame.
481 """
482
483 if MINSIZE > pktlen:
484 pktlen = MINSIZE
485
Rich Lanee01611f2014-01-15 14:55:11 -0800486 pkt = scapy.Ether(dst=eth_dst, src=eth_src)
487 if vlan_vid or vlan_pcp:
488 pkt /= scapy.Dot1Q(vlan=vlan_vid, prio=vlan_pcp)
489 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 -0800490
Rich Laned459ce52014-01-24 12:09:54 -0800491 pkt = pkt/("\0" * (pktlen - len(pkt)))
Shudong Zhouc7562b12013-02-06 01:12:18 -0800492
493 return pkt
494
Ed Swierk0aeff8c2012-03-23 20:27:18 -0700495def simple_eth_packet(pktlen=60,
Rich Lane53275082013-11-18 23:26:22 -0800496 eth_dst='00:01:02:03:04:05',
497 eth_src='00:06:07:08:09:0a',
Rich Laned0478ff2013-03-11 12:46:58 -0700498 eth_type=0x88cc):
Jeffrey Townsend5cb7ed32012-08-17 18:11:01 +0000499
500 if MINSIZE > pktlen:
501 pktlen = MINSIZE
502
Rich Laned0478ff2013-03-11 12:46:58 -0700503 pkt = scapy.Ether(dst=eth_dst, src=eth_src, type=eth_type)
Ed Swierk0aeff8c2012-03-23 20:27:18 -0700504
505 pkt = pkt/("0" * (pktlen - len(pkt)))
506
507 return pkt
508
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800509def qinq_tcp_packet(pktlen=100,
Rich Laned0478ff2013-03-11 12:46:58 -0700510 eth_dst='00:01:02:03:04:05',
511 eth_src='00:06:07:08:09:0a',
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800512 dl_vlan_outer=20,
513 dl_vlan_pcp_outer=0,
514 dl_vlan_cfi_outer=0,
Rich Laned0478ff2013-03-11 12:46:58 -0700515 vlan_vid=10,
516 vlan_pcp=0,
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800517 dl_vlan_cfi=0,
518 ip_src='192.168.0.1',
519 ip_dst='192.168.0.2',
520 ip_tos=0,
Gregor Maier9cc93342013-01-29 16:55:28 -0800521 ip_ttl=64,
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800522 tcp_sport=1234,
523 tcp_dport=80,
524 ip_ihl=None,
525 ip_options=False
526 ):
527 """
528 Return a doubly tagged dataplane TCP packet
529
530 Supports a few parameters:
531 @param len Length of packet in bytes w/o CRC
Rich Laned0478ff2013-03-11 12:46:58 -0700532 @param eth_dst Destinatino MAC
533 @param eth_src Source MAC
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800534 @param dl_vlan_outer Outer VLAN ID
535 @param dl_vlan_pcp_outer Outer VLAN priority
536 @param dl_vlan_cfi_outer Outer VLAN cfi bit
Rich Laned0478ff2013-03-11 12:46:58 -0700537 @param vlan_vid Inner VLAN ID
538 @param vlan_pcp VLAN priority
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800539 @param dl_vlan_cfi VLAN cfi bit
540 @param ip_src IP source
541 @param ip_dst IP destination
542 @param ip_tos IP ToS
543 @param tcp_dport TCP destination port
544 @param ip_sport TCP source port
545
546 Generates a TCP request. Users
547 shouldn't assume anything about this packet other than that
548 it is a valid ethernet/IP/TCP frame.
549 """
550
551 if MINSIZE > pktlen:
552 pktlen = MINSIZE
553
554 # Note Dot1Q.id is really CFI
Rich Laned0478ff2013-03-11 12:46:58 -0700555 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800556 scapy.Dot1Q(prio=dl_vlan_pcp_outer, id=dl_vlan_cfi_outer, vlan=dl_vlan_outer)/ \
Rich Laned0478ff2013-03-11 12:46:58 -0700557 scapy.Dot1Q(prio=vlan_pcp, id=dl_vlan_cfi, vlan=vlan_vid)/ \
Gregor Maier9cc93342013-01-29 16:55:28 -0800558 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ttl=ip_ttl, ihl=ip_ihl)/ \
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800559 scapy.TCP(sport=tcp_sport, dport=tcp_dport)
560
561 pkt = pkt/("D" * (pktlen - len(pkt)))
562
563 return pkt
564
Shudong Zhoub7f12462012-11-20 13:01:12 -0800565def do_barrier(ctrl, timeout=-1):
Dan Talayco0fc08bd2012-04-09 16:56:18 -0700566 """
567 Do a barrier command
568 Return 0 on success, -1 on error
569 """
Rich Lanee717c6e2013-03-12 10:25:50 -0700570 b = ofp.message.barrier_request()
Shudong Zhoub7f12462012-11-20 13:01:12 -0800571 (resp, pkt) = ctrl.transact(b, timeout=timeout)
Rich Lane3a261d52013-01-03 17:45:08 -0800572 if resp is None:
573 raise AssertionError("barrier failed")
Dan Talaycof6b94832012-04-12 21:50:57 -0700574 # We'll trust the transaction processing in the controller that xid matched
Rich Lane3a261d52013-01-03 17:45:08 -0800575 return 0 # for backwards compatibility
Dan Talayco92c99122010-06-03 13:53:18 -0700576
Rich Lane9a003812012-10-04 17:17:59 -0700577def port_config_get(controller, port_no):
Dan Talayco92c99122010-06-03 13:53:18 -0700578 """
579 Get a port's configuration
580
581 Gets the switch feature configuration and grabs one port's
582 configuration
583
584 @returns (hwaddr, config, advert) The hwaddress, configuration and
585 advertised values
586 """
Rich Lane6dc865c2013-07-10 10:12:13 -0700587
588 if ofp.OFP_VERSION <= 3:
589 request = ofp.message.features_request()
590 reply, _ = controller.transact(request)
591 if reply is None:
592 logging.warn("Get feature request failed")
593 return None, None, None
594 logging.debug(reply.show())
595 ports = reply.ports
596 else:
597 request = ofp.message.port_desc_stats_request()
598 # TODO do multipart correctly
599 reply, _ = controller.transact(request)
600 if reply is None:
601 logging.warn("Port desc stats request failed")
602 return None, None, None
603 logging.debug(reply.show())
604 ports = reply.entries
605
606 for port in ports:
607 if port.port_no == port_no:
608 return (port.hw_addr, port.config, port.advertised)
Dan Talayco92c99122010-06-03 13:53:18 -0700609
Rich Lane9a003812012-10-04 17:17:59 -0700610 logging.warn("Did not find port number for port config")
Dan Talayco92c99122010-06-03 13:53:18 -0700611 return None, None, None
612
Rich Lane9a003812012-10-04 17:17:59 -0700613def port_config_set(controller, port_no, config, mask):
Dan Talayco92c99122010-06-03 13:53:18 -0700614 """
615 Set the port configuration according the given parameters
616
617 Gets the switch feature configuration and updates one port's
618 configuration value according to config and mask
619 """
Rich Lane9a003812012-10-04 17:17:59 -0700620 logging.info("Setting port " + str(port_no) + " to config " + str(config))
Rich Lane6dc865c2013-07-10 10:12:13 -0700621
622 hw_addr, _, _ = port_config_get(controller, port_no)
623
Rich Lanee717c6e2013-03-12 10:25:50 -0700624 mod = ofp.message.port_mod()
Dan Talayco92c99122010-06-03 13:53:18 -0700625 mod.port_no = port_no
Rich Lane6dc865c2013-07-10 10:12:13 -0700626 if hw_addr != None:
627 mod.hw_addr = hw_addr
Dan Talayco92c99122010-06-03 13:53:18 -0700628 mod.config = config
629 mod.mask = mask
Rich Lane6dc865c2013-07-10 10:12:13 -0700630 mod.advertise = 0 # No change
Rich Lane5c3151c2013-01-03 17:15:41 -0800631 controller.message_send(mod)
632 return 0
Dan Talayco92c99122010-06-03 13:53:18 -0700633
Rich Lane2014f9b2012-10-05 15:29:40 -0700634def receive_pkt_check(dp, pkt, yes_ports, no_ports, assert_if):
Dan Talayco92c99122010-06-03 13:53:18 -0700635 """
636 Check for proper receive packets across all ports
Ken Chiang1bf01602012-04-04 10:48:23 -0700637 @param dp The dataplane object
Dan Talayco92c99122010-06-03 13:53:18 -0700638 @param pkt Expected packet; may be None if yes_ports is empty
639 @param yes_ports Set or list of ports that should recieve packet
640 @param no_ports Set or list of ports that should not receive packet
641 @param assert_if Object that implements assertXXX
Rich Lanee4b384d2013-09-13 14:33:40 -0700642
643 DEPRECATED in favor in verify_packets
Dan Talayco92c99122010-06-03 13:53:18 -0700644 """
Rich Lane91765672012-12-06 16:33:04 -0800645
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700646 exp_pkt_arg = None
Rich Lanecd97d3d2013-01-07 18:50:06 -0800647 if oftest.config["relax"]:
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700648 exp_pkt_arg = pkt
649
Dan Talayco92c99122010-06-03 13:53:18 -0700650 for ofport in yes_ports:
Rich Lane9a003812012-10-04 17:17:59 -0700651 logging.debug("Checking for pkt on port " + str(ofport))
Ken Chiang1bf01602012-04-04 10:48:23 -0700652 (rcv_port, rcv_pkt, pkt_time) = dp.poll(
Wilson Ngc2c6b4e2015-03-04 17:30:20 -0800653 port_number=ofport, exp_pkt=exp_pkt_arg)
Dan Talayco92c99122010-06-03 13:53:18 -0700654 assert_if.assertTrue(rcv_pkt is not None,
655 "Did not receive pkt on " + str(ofport))
Rich Lanecd97d3d2013-01-07 18:50:06 -0800656 if not oftest.dataplane.match_exp_pkt(pkt, rcv_pkt):
Rich Lane3c266832013-01-29 18:29:15 -0800657 logging.debug("Expected %s" % format_packet(pkt))
658 logging.debug("Received %s" % format_packet(rcv_pkt))
Rich Lanecd97d3d2013-01-07 18:50:06 -0800659 assert_if.assertTrue(oftest.dataplane.match_exp_pkt(pkt, rcv_pkt),
Rich Lane3c266832013-01-29 18:29:15 -0800660 "Received packet does not match expected packet " +
Ken Chiang1bf01602012-04-04 10:48:23 -0700661 "on port " + str(ofport))
Dan Talayco73f84012012-10-02 09:23:18 -0700662 if len(no_ports) > 0:
Rich Lane57dfee72014-03-24 16:59:47 -0700663 time.sleep(oftest.ofutils.default_negative_timeout)
Dan Talayco92c99122010-06-03 13:53:18 -0700664 for ofport in no_ports:
Rich Lane9a003812012-10-04 17:17:59 -0700665 logging.debug("Negative check for pkt on port " + str(ofport))
Ken Chiang1bf01602012-04-04 10:48:23 -0700666 (rcv_port, rcv_pkt, pkt_time) = dp.poll(
Rich Lane91765672012-12-06 16:33:04 -0800667 port_number=ofport, timeout=0, exp_pkt=exp_pkt_arg)
Dan Talayco92c99122010-06-03 13:53:18 -0700668 assert_if.assertTrue(rcv_pkt is None,
669 "Unexpected pkt on port " + str(ofport))
Dan Talayco551befa2010-07-15 17:05:32 -0700670
671
Dan Talaycoc948d0b2012-03-23 12:17:54 -0700672def receive_pkt_verify(parent, egr_ports, exp_pkt, ing_port):
Dan Talayco551befa2010-07-15 17:05:32 -0700673 """
674 Receive a packet and verify it matches an expected value
Dan Talaycof6e76c02012-03-23 10:56:12 -0700675 @param egr_port A single port or list of ports
Dan Talayco551befa2010-07-15 17:05:32 -0700676
677 parent must implement dataplane, assertTrue and assertEqual
Rich Lanee4b384d2013-09-13 14:33:40 -0700678
679 DEPRECATED in favor in verify_packets
Dan Talayco551befa2010-07-15 17:05:32 -0700680 """
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700681 exp_pkt_arg = None
Rich Lanecd97d3d2013-01-07 18:50:06 -0800682 if oftest.config["relax"]:
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700683 exp_pkt_arg = exp_pkt
684
Dan Talaycof6e76c02012-03-23 10:56:12 -0700685 if type(egr_ports) == type([]):
686 egr_port_list = egr_ports
687 else:
688 egr_port_list = [egr_ports]
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700689
Dan Talaycof6e76c02012-03-23 10:56:12 -0700690 # Expect a packet from each port on egr port list
691 for egr_port in egr_port_list:
Dan Talaycod8ae7582012-03-23 12:24:56 -0700692 check_port = egr_port
Rich Lanee717c6e2013-03-12 10:25:50 -0700693 if egr_port == ofp.OFPP_IN_PORT:
Dan Talaycod8ae7582012-03-23 12:24:56 -0700694 check_port = ing_port
Dan Talaycof6e76c02012-03-23 10:56:12 -0700695 (rcv_port, rcv_pkt, pkt_time) = parent.dataplane.poll(
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700696 port_number=check_port, exp_pkt=exp_pkt_arg)
Dan Talayco551befa2010-07-15 17:05:32 -0700697
Dan Talaycof6e76c02012-03-23 10:56:12 -0700698 if rcv_pkt is None:
Rich Lane9a003812012-10-04 17:17:59 -0700699 logging.error("ERROR: No packet received from " +
Dan Talaycod8ae7582012-03-23 12:24:56 -0700700 str(check_port))
Dan Talayco551befa2010-07-15 17:05:32 -0700701
Dan Talaycof6e76c02012-03-23 10:56:12 -0700702 parent.assertTrue(rcv_pkt is not None,
Dan Talaycod8ae7582012-03-23 12:24:56 -0700703 "Did not receive packet port " + str(check_port))
Rich Lane9a003812012-10-04 17:17:59 -0700704 logging.debug("Packet len " + str(len(rcv_pkt)) + " in on " +
Dan Talaycof6e76c02012-03-23 10:56:12 -0700705 str(rcv_port))
706
707 if str(exp_pkt) != str(rcv_pkt):
Rich Lane9a003812012-10-04 17:17:59 -0700708 logging.error("ERROR: Packet match failed.")
709 logging.debug("Expected len " + str(len(exp_pkt)) + ": "
Dan Talaycof6e76c02012-03-23 10:56:12 -0700710 + str(exp_pkt).encode('hex'))
Rich Lane9a003812012-10-04 17:17:59 -0700711 logging.debug("Received len " + str(len(rcv_pkt)) + ": "
Dan Talaycof6e76c02012-03-23 10:56:12 -0700712 + str(rcv_pkt).encode('hex'))
Rich Lane5d7e89a2012-10-26 16:43:13 -0700713 logging.debug("Expected packet: " + inspect_packet(scapy.Ether(str(exp_pkt))))
714 logging.debug("Received packet: " + inspect_packet(scapy.Ether(str(rcv_pkt))))
Dan Talaycof6e76c02012-03-23 10:56:12 -0700715 parent.assertEqual(str(exp_pkt), str(rcv_pkt),
Dan Talaycod8ae7582012-03-23 12:24:56 -0700716 "Packet match error on port " + str(check_port))
Dan Talaycof6e76c02012-03-23 10:56:12 -0700717
Dan Talayco551befa2010-07-15 17:05:32 -0700718def match_verify(parent, req_match, res_match):
719 """
720 Verify flow matches agree; if they disagree, report where
721
722 parent must implement assertEqual
723 Use str() to ensure content is compared and not pointers
724 """
725
726 parent.assertEqual(req_match.wildcards, res_match.wildcards,
727 'Match failed: wildcards: ' + hex(req_match.wildcards) +
728 " != " + hex(res_match.wildcards))
729 parent.assertEqual(req_match.in_port, res_match.in_port,
730 'Match failed: in_port: ' + str(req_match.in_port) +
731 " != " + str(res_match.in_port))
Rich Laned0478ff2013-03-11 12:46:58 -0700732 parent.assertEqual(str(req_match.eth_src), str(res_match.eth_src),
733 'Match failed: eth_src: ' + str(req_match.eth_src) +
734 " != " + str(res_match.eth_src))
735 parent.assertEqual(str(req_match.eth_dst), str(res_match.eth_dst),
736 'Match failed: eth_dst: ' + str(req_match.eth_dst) +
737 " != " + str(res_match.eth_dst))
738 parent.assertEqual(req_match.vlan_vid, res_match.vlan_vid,
739 'Match failed: vlan_vid: ' + str(req_match.vlan_vid) +
740 " != " + str(res_match.vlan_vid))
741 parent.assertEqual(req_match.vlan_pcp, res_match.vlan_pcp,
742 'Match failed: vlan_pcp: ' +
743 str(req_match.vlan_pcp) + " != " +
744 str(res_match.vlan_pcp))
745 parent.assertEqual(req_match.eth_type, res_match.eth_type,
746 'Match failed: eth_type: ' + str(req_match.eth_type) +
747 " != " + str(res_match.eth_type))
Dan Talayco551befa2010-07-15 17:05:32 -0700748
Rich Lanee717c6e2013-03-12 10:25:50 -0700749 if (not(req_match.wildcards & ofp.OFPFW_DL_TYPE)
Rich Laned0478ff2013-03-11 12:46:58 -0700750 and (req_match.eth_type == IP_ETHERTYPE)):
751 parent.assertEqual(req_match.ip_dscp, res_match.ip_dscp,
752 'Match failed: ip_dscp: ' + str(req_match.ip_dscp) +
753 " != " + str(res_match.ip_dscp))
754 parent.assertEqual(req_match.ip_proto, res_match.ip_proto,
755 'Match failed: ip_proto: ' + str(req_match.ip_proto) +
756 " != " + str(res_match.ip_proto))
757 parent.assertEqual(req_match.ipv4_src, res_match.ipv4_src,
758 'Match failed: ipv4_src: ' + str(req_match.ipv4_src) +
759 " != " + str(res_match.ipv4_src))
760 parent.assertEqual(req_match.ipv4_dst, res_match.ipv4_dst,
761 'Match failed: ipv4_dst: ' + str(req_match.ipv4_dst) +
762 " != " + str(res_match.ipv4_dst))
Dan Talayco551befa2010-07-15 17:05:32 -0700763
Rich Lanee717c6e2013-03-12 10:25:50 -0700764 if (not(req_match.wildcards & ofp.OFPFW_NW_PROTO)
Rich Laned0478ff2013-03-11 12:46:58 -0700765 and ((req_match.ip_proto == TCP_PROTOCOL)
766 or (req_match.ip_proto == UDP_PROTOCOL))):
767 parent.assertEqual(req_match.tcp_src, res_match.tcp_src,
768 'Match failed: tcp_src: ' +
769 str(req_match.tcp_src) +
770 " != " + str(res_match.tcp_src))
771 parent.assertEqual(req_match.tcp_dst, res_match.tcp_dst,
772 'Match failed: tcp_dst: ' +
773 str(req_match.tcp_dst) +
774 " != " + str(res_match.tcp_dst))
Dan Talayco551befa2010-07-15 17:05:32 -0700775
Ed Swierk99a74de2012-08-22 06:40:54 -0700776def packet_to_flow_match(parent, packet):
Rich Lanef6883512013-03-11 17:00:09 -0700777 match = oftest.parse.packet_to_flow_match(packet)
Rich Laneab7476f2013-06-13 15:53:52 -0700778 if ofp.OFP_VERSION in [1, 2]:
779 match.wildcards |= required_wildcards(parent)
780 else:
781 # TODO remove incompatible OXM entries
782 pass
Ed Swierk99a74de2012-08-22 06:40:54 -0700783 return match
784
785def flow_msg_create(parent, pkt, ing_port=None, action_list=None, wildcards=None,
Dan Talaycof6e76c02012-03-23 10:56:12 -0700786 egr_ports=None, egr_queue=None, check_expire=False, in_band=False):
Dan Talayco551befa2010-07-15 17:05:32 -0700787 """
788 Create a flow message
789
790 Match on packet with given wildcards.
791 See flow_match_test for other parameter descriptoins
792 @param egr_queue if not None, make the output an enqueue action
Dan Talayco677c0b72011-08-23 22:53:38 -0700793 @param in_band if True, do not wildcard ingress port
Dan Talaycof6e76c02012-03-23 10:56:12 -0700794 @param egr_ports None (drop), single port or list of ports
Dan Talayco551befa2010-07-15 17:05:32 -0700795 """
Rich Lanef6883512013-03-11 17:00:09 -0700796 match = oftest.parse.packet_to_flow_match(pkt)
Dan Talayco551befa2010-07-15 17:05:32 -0700797 parent.assertTrue(match is not None, "Flow match from pkt failed")
Ed Swierk99a74de2012-08-22 06:40:54 -0700798 if wildcards is None:
799 wildcards = required_wildcards(parent)
Dan Talayco677c0b72011-08-23 22:53:38 -0700800 if in_band:
Rich Lanee717c6e2013-03-12 10:25:50 -0700801 wildcards &= ~ofp.OFPFW_IN_PORT
Dan Talayco551befa2010-07-15 17:05:32 -0700802 match.wildcards = wildcards
803 match.in_port = ing_port
804
Dan Talaycof6e76c02012-03-23 10:56:12 -0700805 if type(egr_ports) == type([]):
806 egr_port_list = egr_ports
807 else:
808 egr_port_list = [egr_ports]
809
Rich Lanee717c6e2013-03-12 10:25:50 -0700810 request = ofp.message.flow_add()
Dan Talayco551befa2010-07-15 17:05:32 -0700811 request.match = match
812 request.buffer_id = 0xffffffff
813 if check_expire:
Rich Lanee717c6e2013-03-12 10:25:50 -0700814 request.flags |= ofp.OFPFF_SEND_FLOW_REM
Dan Talayco551befa2010-07-15 17:05:32 -0700815 request.hard_timeout = 1
816
Rich Lane400fb9b2013-10-10 17:20:54 -0700817 if ofp.OFP_VERSION == 1:
818 actions = request.actions
819 else:
820 actions = []
821 request.instructions.append(ofp.instruction.apply_actions(actions))
822
Dan Talayco551befa2010-07-15 17:05:32 -0700823 if action_list is not None:
Rich Lane400fb9b2013-10-10 17:20:54 -0700824 actions.extend(action_list)
Dan Talayco551befa2010-07-15 17:05:32 -0700825
826 # Set up output/enqueue action if directed
827 if egr_queue is not None:
Dan Talaycof6e76c02012-03-23 10:56:12 -0700828 parent.assertTrue(egr_ports is not None, "Egress port not set")
Rich Lanee717c6e2013-03-12 10:25:50 -0700829 act = ofp.action.enqueue()
Dan Talaycof6e76c02012-03-23 10:56:12 -0700830 for egr_port in egr_port_list:
831 act.port = egr_port
832 act.queue_id = egr_queue
Rich Lane400fb9b2013-10-10 17:20:54 -0700833 actions.append(act)
Dan Talaycof6e76c02012-03-23 10:56:12 -0700834 elif egr_ports is not None:
835 for egr_port in egr_port_list:
Rich Lanee717c6e2013-03-12 10:25:50 -0700836 act = ofp.action.output()
Dan Talaycof6e76c02012-03-23 10:56:12 -0700837 act.port = egr_port
Rich Lane400fb9b2013-10-10 17:20:54 -0700838 actions.append(act)
Dan Talayco551befa2010-07-15 17:05:32 -0700839
Rich Lane9a003812012-10-04 17:17:59 -0700840 logging.debug(request.show())
Dan Talayco551befa2010-07-15 17:05:32 -0700841
842 return request
843
Jeffrey Townsendf3eae9c2012-03-28 18:23:21 -0700844def flow_msg_install(parent, request, clear_table_override=None):
Dan Talayco551befa2010-07-15 17:05:32 -0700845 """
846 Install a flow mod message in the switch
847
848 @param parent Must implement controller, assertEqual, assertTrue
849 @param request The request, all set to go
850 @param clear_table If true, clear the flow table before installing
851 """
Dan Talayco8a64e332012-03-28 14:53:20 -0700852
Rich Lane2014f9b2012-10-05 15:29:40 -0700853 clear_table = test_param_get('clear_table', default=True)
Jeffrey Townsendf3eae9c2012-03-28 18:23:21 -0700854 if(clear_table_override != None):
855 clear_table = clear_table_override
856
857 if clear_table:
Rich Lane9a003812012-10-04 17:17:59 -0700858 logging.debug("Clear flow table")
Rich Lane32bf9482013-01-03 17:26:30 -0800859 delete_all_flows(parent.controller)
Dan Talayco551befa2010-07-15 17:05:32 -0700860
Rich Lane9a003812012-10-04 17:17:59 -0700861 logging.debug("Insert flow")
Rich Lane5c3151c2013-01-03 17:15:41 -0800862 parent.controller.message_send(request)
Rich Lanee912d032012-12-22 14:28:33 -0800863
Rich Lane3a261d52013-01-03 17:45:08 -0800864 do_barrier(parent.controller)
Dan Talayco551befa2010-07-15 17:05:32 -0700865
Ed Swierk99a74de2012-08-22 06:40:54 -0700866def flow_match_test_port_pair(parent, ing_port, egr_ports, wildcards=None,
Rich Laned0478ff2013-03-11 12:46:58 -0700867 vlan_vid=-1, pkt=None, exp_pkt=None,
Rich Lanee5779d32012-10-05 17:56:04 -0700868 action_list=None):
Dan Talayco551befa2010-07-15 17:05:32 -0700869 """
870 Flow match test on single TCP packet
Dan Talaycof6e76c02012-03-23 10:56:12 -0700871 @param egr_ports A single port or list of ports
Dan Talayco551befa2010-07-15 17:05:32 -0700872
873 Run test with packet through switch from ing_port to egr_port
874 See flow_match_test for parameter descriptions
875 """
876
Ed Swierk99a74de2012-08-22 06:40:54 -0700877 if wildcards is None:
878 wildcards = required_wildcards(parent)
Rich Lane9a003812012-10-04 17:17:59 -0700879 logging.info("Pkt match test: " + str(ing_port) + " to " +
Dan Talaycof6e76c02012-03-23 10:56:12 -0700880 str(egr_ports))
Rich Laned0478ff2013-03-11 12:46:58 -0700881 logging.debug(" WC: " + hex(wildcards) + " vlan: " + str(vlan_vid))
Dan Talayco551befa2010-07-15 17:05:32 -0700882 if pkt is None:
Rich Laned0478ff2013-03-11 12:46:58 -0700883 pkt = simple_tcp_packet(dl_vlan_enable=(vlan_vid >= 0), vlan_vid=vlan_vid)
Rich Lanec41fbec2013-10-02 00:27:59 -0700884 if exp_pkt is None:
885 exp_pkt = pkt
Dan Talayco551befa2010-07-15 17:05:32 -0700886
887 request = flow_msg_create(parent, pkt, ing_port=ing_port,
Dan Talaycof6e76c02012-03-23 10:56:12 -0700888 wildcards=wildcards, egr_ports=egr_ports,
Dan Talayco551befa2010-07-15 17:05:32 -0700889 action_list=action_list)
890
891 flow_msg_install(parent, request)
892
Rich Lane9a003812012-10-04 17:17:59 -0700893 logging.debug("Send packet: " + str(ing_port) + " to " +
Dan Talaycof6e76c02012-03-23 10:56:12 -0700894 str(egr_ports))
Dan Talayco551befa2010-07-15 17:05:32 -0700895 parent.dataplane.send(ing_port, str(pkt))
896
Rich Lane8f45e2d2013-10-01 16:06:54 -0700897 exp_ports = [ing_port if port == ofp.OFPP_IN_PORT else port for port in egr_ports]
Rich Lanee4b384d2013-09-13 14:33:40 -0700898 verify_packets(parent, exp_pkt, exp_ports)
Dan Talayco551befa2010-07-15 17:05:32 -0700899
Rich Lane89725bb2012-12-03 16:23:27 -0800900def flow_match_test_pktout(parent, ing_port, egr_ports,
Rich Laned0478ff2013-03-11 12:46:58 -0700901 vlan_vid=-1, pkt=None, exp_pkt=None,
Rich Lane89725bb2012-12-03 16:23:27 -0800902 action_list=None):
903 """
904 Packet-out test on single TCP packet
905 @param egr_ports A single port or list of ports
906
907 Run test sending packet-out to egr_ports. The goal is to test the actions
908 taken on the packet, not the matching which is of course irrelevant.
909 See flow_match_test for parameter descriptions
910 """
911
912 if pkt is None:
Rich Laned0478ff2013-03-11 12:46:58 -0700913 pkt = simple_tcp_packet(dl_vlan_enable=(vlan_vid >= 0), vlan_vid=vlan_vid)
Rich Lanec41fbec2013-10-02 00:27:59 -0700914 if exp_pkt is None:
915 exp_pkt = pkt
Rich Lane89725bb2012-12-03 16:23:27 -0800916
Rich Lanee717c6e2013-03-12 10:25:50 -0700917 msg = ofp.message.packet_out()
Rich Lane89725bb2012-12-03 16:23:27 -0800918 msg.in_port = ing_port
Rich Laneea8c4722013-04-04 15:30:20 -0700919 msg.buffer_id = 0xffffffff
Rich Lane89725bb2012-12-03 16:23:27 -0800920 msg.data = str(pkt)
921 if action_list is not None:
922 for act in action_list:
Rich Lanec495d9e2013-03-08 17:43:36 -0800923 msg.actions.append(act)
Rich Lane89725bb2012-12-03 16:23:27 -0800924
925 # Set up output action
926 if egr_ports is not None:
927 for egr_port in egr_ports:
Rich Lanee717c6e2013-03-12 10:25:50 -0700928 act = ofp.action.output()
Rich Lane89725bb2012-12-03 16:23:27 -0800929 act.port = egr_port
Rich Lanec495d9e2013-03-08 17:43:36 -0800930 msg.actions.append(act)
Rich Lane89725bb2012-12-03 16:23:27 -0800931
932 logging.debug(msg.show())
Rich Lane5c3151c2013-01-03 17:15:41 -0800933 parent.controller.message_send(msg)
Rich Lane89725bb2012-12-03 16:23:27 -0800934
Rich Lane8f45e2d2013-10-01 16:06:54 -0700935 exp_ports = [ing_port if port == ofp.OFPP_IN_PORT else port for port in egr_ports]
Rich Lanee4b384d2013-09-13 14:33:40 -0700936 verify_packets(parent, exp_pkt, exp_ports)
Rich Lane89725bb2012-12-03 16:23:27 -0800937
Dan Talaycof6e76c02012-03-23 10:56:12 -0700938def get_egr_list(parent, of_ports, how_many, exclude_list=[]):
939 """
940 Generate a list of ports avoiding those in the exclude list
Rich Lane9a003812012-10-04 17:17:59 -0700941 @param parent Supplies logging
Dan Talaycof6e76c02012-03-23 10:56:12 -0700942 @param of_ports List of OF port numbers
943 @param how_many Number of ports to be added to the list
944 @param exclude_list List of ports not to be used
945 @returns An empty list if unable to find enough ports
946 """
947
Dan Talaycoc948d0b2012-03-23 12:17:54 -0700948 if how_many == 0:
949 return []
950
Dan Talaycof6e76c02012-03-23 10:56:12 -0700951 count = 0
952 egr_ports = []
953 for egr_idx in range(len(of_ports)):
954 if of_ports[egr_idx] not in exclude_list:
955 egr_ports.append(of_ports[egr_idx])
956 count += 1
957 if count >= how_many:
958 return egr_ports
Rich Lane9a003812012-10-04 17:17:59 -0700959 logging.debug("Could not generate enough egress ports for test")
Dan Talaycof6e76c02012-03-23 10:56:12 -0700960 return []
961
Rich Laned0478ff2013-03-11 12:46:58 -0700962def flow_match_test(parent, port_map, wildcards=None, vlan_vid=-1, pkt=None,
Rich Lanee5779d32012-10-05 17:56:04 -0700963 exp_pkt=None, action_list=None,
Dan Talaycoc948d0b2012-03-23 12:17:54 -0700964 max_test=0, egr_count=1, ing_port=False):
Dan Talayco551befa2010-07-15 17:05:32 -0700965 """
Rich Lane89725bb2012-12-03 16:23:27 -0800966 Run flow_match_test_port_pair on all port pairs and packet-out
Dan Talayco551befa2010-07-15 17:05:32 -0700967
968 @param max_test If > 0 no more than this number of tests are executed.
969 @param parent Must implement controller, dataplane, assertTrue, assertEqual
Rich Lane9a003812012-10-04 17:17:59 -0700970 and logging
Dan Talayco551befa2010-07-15 17:05:32 -0700971 @param pkt If not None, use this packet for ingress
972 @param wildcards For flow match entry
Rich Laned0478ff2013-03-11 12:46:58 -0700973 @param vlan_vid If not -1, and pkt is None, create a pkt w/ VLAN tag
Dan Talayco551befa2010-07-15 17:05:32 -0700974 @param exp_pkt If not None, use this as the expected output pkt; els use pkt
975 @param action_list Additional actions to add to flow mod
Dan Talaycocfa172f2012-03-23 12:03:00 -0700976 @param egr_count Number of egress ports; -1 means get from config w/ dflt 2
Dan Talayco551befa2010-07-15 17:05:32 -0700977 """
Ed Swierk99a74de2012-08-22 06:40:54 -0700978 if wildcards is None:
979 wildcards = required_wildcards(parent)
Dan Talayco551befa2010-07-15 17:05:32 -0700980 of_ports = port_map.keys()
981 of_ports.sort()
982 parent.assertTrue(len(of_ports) > 1, "Not enough ports for test")
983 test_count = 0
984
Dan Talaycocfa172f2012-03-23 12:03:00 -0700985 if egr_count == -1:
Rich Lane2014f9b2012-10-05 15:29:40 -0700986 egr_count = test_param_get('egr_count', default=2)
Dan Talaycocfa172f2012-03-23 12:03:00 -0700987
Dan Talayco551befa2010-07-15 17:05:32 -0700988 for ing_idx in range(len(of_ports)):
989 ingress_port = of_ports[ing_idx]
Dan Talaycof6e76c02012-03-23 10:56:12 -0700990 egr_ports = get_egr_list(parent, of_ports, egr_count,
991 exclude_list=[ingress_port])
Dan Talaycoc948d0b2012-03-23 12:17:54 -0700992 if ing_port:
Rich Lanee717c6e2013-03-12 10:25:50 -0700993 egr_ports.append(ofp.OFPP_IN_PORT)
Dan Talaycof6e76c02012-03-23 10:56:12 -0700994 if len(egr_ports) == 0:
995 parent.assertTrue(0, "Failed to generate egress port list")
996
997 flow_match_test_port_pair(parent, ingress_port, egr_ports,
Rich Laned0478ff2013-03-11 12:46:58 -0700998 wildcards=wildcards, vlan_vid=vlan_vid,
Dan Talaycof6e76c02012-03-23 10:56:12 -0700999 pkt=pkt, exp_pkt=exp_pkt,
Rich Lanee5779d32012-10-05 17:56:04 -07001000 action_list=action_list)
Dan Talaycof6e76c02012-03-23 10:56:12 -07001001 test_count += 1
1002 if (max_test > 0) and (test_count > max_test):
Rich Lane9a003812012-10-04 17:17:59 -07001003 logging.info("Ran " + str(test_count) + " tests; exiting")
Rich Lane89725bb2012-12-03 16:23:27 -08001004 break
1005
Ed Swierk38eea082013-01-02 19:46:20 -08001006 if not test_param_get('pktout_actions', default=True):
1007 return
Rich Lane89725bb2012-12-03 16:23:27 -08001008
1009 ingress_port = of_ports[0]
1010 egr_ports = get_egr_list(parent, of_ports, egr_count,
1011 exclude_list=[ingress_port])
1012 if ing_port:
Rich Lanee717c6e2013-03-12 10:25:50 -07001013 egr_ports.append(ofp.OFPP_IN_PORT)
Rich Lane89725bb2012-12-03 16:23:27 -08001014 flow_match_test_pktout(parent, ingress_port, egr_ports,
Rich Laned0478ff2013-03-11 12:46:58 -07001015 vlan_vid=vlan_vid,
Rich Lane89725bb2012-12-03 16:23:27 -08001016 pkt=pkt, exp_pkt=exp_pkt,
1017 action_list=action_list)
Dan Talayco551befa2010-07-15 17:05:32 -07001018
Rich Lane2014f9b2012-10-05 15:29:40 -07001019def test_param_get(key, default=None):
Dan Talayco4b2bee62010-07-20 14:10:05 -07001020 """
1021 Return value passed via test-params if present
1022
Dan Talayco4b2bee62010-07-20 14:10:05 -07001023 @param key The lookup key
1024 @param default Default value to use if not found
1025
1026 If the pair 'key=val' appeared in the string passed to --test-params
1027 on the command line, return val (as interpreted by exec). Otherwise
1028 return default value.
Dan Talaycof6e76c02012-03-23 10:56:12 -07001029
1030 WARNING: TEST PARAMETERS MUST BE PYTHON IDENTIFIERS;
1031 eg egr_count, not egr-count.
Dan Talayco4b2bee62010-07-20 14:10:05 -07001032 """
1033 try:
Rich Lanecd97d3d2013-01-07 18:50:06 -08001034 exec oftest.config["test_params"]
Dan Talayco4b2bee62010-07-20 14:10:05 -07001035 except:
1036 return default
1037
Dan Talayco4b2bee62010-07-20 14:10:05 -07001038 try:
Rich Lanefdec0fb2013-08-09 18:01:05 -07001039 return eval(str(key))
Dan Talayco4b2bee62010-07-20 14:10:05 -07001040 except:
1041 return default
1042
1043def action_generate(parent, field_to_mod, mod_field_vals):
1044 """
1045 Create an action to modify the field indicated in field_to_mod
1046
1047 @param parent Must implement, assertTrue
1048 @param field_to_mod The field to modify as a string name
1049 @param mod_field_vals Hash of values to use for modified values
1050 """
1051
1052 act = None
1053
1054 if field_to_mod in ['pktlen']:
1055 return None
1056
Rich Laned0478ff2013-03-11 12:46:58 -07001057 if field_to_mod == 'eth_dst':
Rich Lanee717c6e2013-03-12 10:25:50 -07001058 act = ofp.action.set_dl_dst()
Rich Lanef6883512013-03-11 17:00:09 -07001059 act.dl_addr = oftest.parse.parse_mac(mod_field_vals['eth_dst'])
Rich Laned0478ff2013-03-11 12:46:58 -07001060 elif field_to_mod == 'eth_src':
Rich Lanee717c6e2013-03-12 10:25:50 -07001061 act = ofp.action.set_dl_src()
Rich Lanef6883512013-03-11 17:00:09 -07001062 act.dl_addr = oftest.parse.parse_mac(mod_field_vals['eth_src'])
Dan Talayco4b2bee62010-07-20 14:10:05 -07001063 elif field_to_mod == 'dl_vlan_enable':
1064 if not mod_field_vals['dl_vlan_enable']: # Strip VLAN tag
Rich Lanee717c6e2013-03-12 10:25:50 -07001065 act = ofp.action.strip_vlan()
Rich Laned0478ff2013-03-11 12:46:58 -07001066 # Add VLAN tag is handled by vlan_vid field
Dan Talayco4b2bee62010-07-20 14:10:05 -07001067 # Will return None in this case
Rich Laned0478ff2013-03-11 12:46:58 -07001068 elif field_to_mod == 'vlan_vid':
Rich Lanee717c6e2013-03-12 10:25:50 -07001069 act = ofp.action.set_vlan_vid()
Rich Laned0478ff2013-03-11 12:46:58 -07001070 act.vlan_vid = mod_field_vals['vlan_vid']
1071 elif field_to_mod == 'vlan_pcp':
Rich Lanee717c6e2013-03-12 10:25:50 -07001072 act = ofp.action.set_vlan_pcp()
Rich Laned0478ff2013-03-11 12:46:58 -07001073 act.vlan_pcp = mod_field_vals['vlan_pcp']
Dan Talayco4b2bee62010-07-20 14:10:05 -07001074 elif field_to_mod == 'ip_src':
Rich Lanee717c6e2013-03-12 10:25:50 -07001075 act = ofp.action.set_nw_src()
Rich Lanef6883512013-03-11 17:00:09 -07001076 act.nw_addr = oftest.parse.parse_ip(mod_field_vals['ip_src'])
Dan Talayco4b2bee62010-07-20 14:10:05 -07001077 elif field_to_mod == 'ip_dst':
Rich Lanee717c6e2013-03-12 10:25:50 -07001078 act = ofp.action.set_nw_dst()
Rich Lanef6883512013-03-11 17:00:09 -07001079 act.nw_addr = oftest.parse.parse_ip(mod_field_vals['ip_dst'])
Dan Talayco4b2bee62010-07-20 14:10:05 -07001080 elif field_to_mod == 'ip_tos':
Rich Lanee717c6e2013-03-12 10:25:50 -07001081 act = ofp.action.set_nw_tos()
Dan Talayco4b2bee62010-07-20 14:10:05 -07001082 act.nw_tos = mod_field_vals['ip_tos']
1083 elif field_to_mod == 'tcp_sport':
Rich Lanee717c6e2013-03-12 10:25:50 -07001084 act = ofp.action.set_tp_src()
Dan Talayco4b2bee62010-07-20 14:10:05 -07001085 act.tp_port = mod_field_vals['tcp_sport']
1086 elif field_to_mod == 'tcp_dport':
Rich Lanee717c6e2013-03-12 10:25:50 -07001087 act = ofp.action.set_tp_dst()
Dan Talayco4b2bee62010-07-20 14:10:05 -07001088 act.tp_port = mod_field_vals['tcp_dport']
Rich Lane110e0e32012-10-26 16:21:46 -07001089 elif field_to_mod == 'udp_sport':
Rich Lanee717c6e2013-03-12 10:25:50 -07001090 act = ofp.action.set_tp_src()
Rich Lane110e0e32012-10-26 16:21:46 -07001091 act.tp_port = mod_field_vals['udp_sport']
1092 elif field_to_mod == 'udp_dport':
Rich Lanee717c6e2013-03-12 10:25:50 -07001093 act = ofp.action.set_tp_dst()
Rich Lane110e0e32012-10-26 16:21:46 -07001094 act.tp_port = mod_field_vals['udp_dport']
Dan Talayco4b2bee62010-07-20 14:10:05 -07001095 else:
1096 parent.assertTrue(0, "Unknown field to modify: " + str(field_to_mod))
1097
1098 return act
1099
1100def pkt_action_setup(parent, start_field_vals={}, mod_field_vals={},
Rich Lane110e0e32012-10-26 16:21:46 -07001101 mod_fields=[], tp="tcp", check_test_params=False):
Dan Talayco4b2bee62010-07-20 14:10:05 -07001102 """
1103 Set up the ingress and expected packet and action list for a test
1104
Rich Lane2014f9b2012-10-05 15:29:40 -07001105 @param parent Must implement assertTrue
Dan Talayco4b2bee62010-07-20 14:10:05 -07001106 @param start_field_values Field values to use for ingress packet (optional)
1107 @param mod_field_values Field values to use for modified packet (optional)
1108 @param mod_fields The list of fields to be modified by the switch in the test.
1109 @params check_test_params If True, will check the parameters vid, add_vlan
1110 and strip_vlan from the command line.
1111
1112 Returns a triple: pkt-to-send, expected-pkt, action-list
1113 """
1114
1115 new_actions = []
1116
Dan Talayco4b2bee62010-07-20 14:10:05 -07001117 base_pkt_params = {}
1118 base_pkt_params['pktlen'] = 100
Rich Laned0478ff2013-03-11 12:46:58 -07001119 base_pkt_params['eth_dst'] = '00:DE:F0:12:34:56'
1120 base_pkt_params['eth_src'] = '00:23:45:67:89:AB'
Dan Talayco4b2bee62010-07-20 14:10:05 -07001121 base_pkt_params['dl_vlan_enable'] = False
Rich Laned0478ff2013-03-11 12:46:58 -07001122 base_pkt_params['vlan_vid'] = 2
1123 base_pkt_params['vlan_pcp'] = 0
Dan Talayco4b2bee62010-07-20 14:10:05 -07001124 base_pkt_params['ip_src'] = '192.168.0.1'
1125 base_pkt_params['ip_dst'] = '192.168.0.2'
1126 base_pkt_params['ip_tos'] = 0
Rich Lane110e0e32012-10-26 16:21:46 -07001127 if tp == "tcp":
1128 base_pkt_params['tcp_sport'] = 1234
1129 base_pkt_params['tcp_dport'] = 80
1130 elif tp == "udp":
1131 base_pkt_params['udp_sport'] = 1234
1132 base_pkt_params['udp_dport'] = 80
Dan Talayco4b2bee62010-07-20 14:10:05 -07001133 for keyname in start_field_vals.keys():
1134 base_pkt_params[keyname] = start_field_vals[keyname]
1135
1136 mod_pkt_params = {}
1137 mod_pkt_params['pktlen'] = 100
Rich Laned0478ff2013-03-11 12:46:58 -07001138 mod_pkt_params['eth_dst'] = '00:21:0F:ED:CB:A9'
1139 mod_pkt_params['eth_src'] = '00:ED:CB:A9:87:65'
Dan Talayco4b2bee62010-07-20 14:10:05 -07001140 mod_pkt_params['dl_vlan_enable'] = False
Rich Laned0478ff2013-03-11 12:46:58 -07001141 mod_pkt_params['vlan_vid'] = 3
1142 mod_pkt_params['vlan_pcp'] = 7
Dan Talayco4b2bee62010-07-20 14:10:05 -07001143 mod_pkt_params['ip_src'] = '10.20.30.40'
1144 mod_pkt_params['ip_dst'] = '50.60.70.80'
1145 mod_pkt_params['ip_tos'] = 0xf0
Rich Lane110e0e32012-10-26 16:21:46 -07001146 if tp == "tcp":
1147 mod_pkt_params['tcp_sport'] = 4321
1148 mod_pkt_params['tcp_dport'] = 8765
1149 elif tp == "udp":
1150 mod_pkt_params['udp_sport'] = 4321
1151 mod_pkt_params['udp_dport'] = 8765
Dan Talayco4b2bee62010-07-20 14:10:05 -07001152 for keyname in mod_field_vals.keys():
1153 mod_pkt_params[keyname] = mod_field_vals[keyname]
1154
1155 # Check for test param modifications
1156 strip = False
1157 if check_test_params:
Rich Lane2014f9b2012-10-05 15:29:40 -07001158 add_vlan = test_param_get('add_vlan')
1159 strip_vlan = test_param_get('strip_vlan')
1160 vid = test_param_get('vid')
Dan Talayco4b2bee62010-07-20 14:10:05 -07001161
1162 if add_vlan and strip_vlan:
1163 parent.assertTrue(0, "Add and strip VLAN both specified")
1164
1165 if vid:
1166 base_pkt_params['dl_vlan_enable'] = True
Rich Laned0478ff2013-03-11 12:46:58 -07001167 base_pkt_params['vlan_vid'] = vid
1168 if 'vlan_vid' in mod_fields:
1169 mod_pkt_params['vlan_vid'] = vid + 1
Dan Talayco4b2bee62010-07-20 14:10:05 -07001170
1171 if add_vlan:
1172 base_pkt_params['dl_vlan_enable'] = False
1173 mod_pkt_params['dl_vlan_enable'] = True
1174 mod_pkt_params['pktlen'] = base_pkt_params['pktlen'] + 4
1175 mod_fields.append('pktlen')
1176 mod_fields.append('dl_vlan_enable')
Rich Laned0478ff2013-03-11 12:46:58 -07001177 if 'vlan_vid' not in mod_fields:
1178 mod_fields.append('vlan_vid')
Dan Talayco4b2bee62010-07-20 14:10:05 -07001179 elif strip_vlan:
1180 base_pkt_params['dl_vlan_enable'] = True
1181 mod_pkt_params['dl_vlan_enable'] = False
1182 mod_pkt_params['pktlen'] = base_pkt_params['pktlen'] - 4
1183 mod_fields.append('dl_vlan_enable')
1184 mod_fields.append('pktlen')
1185
Rich Lane110e0e32012-10-26 16:21:46 -07001186 if tp == "tcp":
1187 packet_builder = simple_tcp_packet
1188 elif tp == "udp":
1189 packet_builder = simple_udp_packet
1190 else:
1191 raise NotImplementedError("unknown transport protocol %s" % tp)
1192
Dan Talayco4b2bee62010-07-20 14:10:05 -07001193 # Build the ingress packet
Rich Lane110e0e32012-10-26 16:21:46 -07001194 ingress_pkt = packet_builder(**base_pkt_params)
Dan Talayco4b2bee62010-07-20 14:10:05 -07001195
1196 # Build the expected packet, modifying the indicated fields
1197 for item in mod_fields:
1198 base_pkt_params[item] = mod_pkt_params[item]
1199 act = action_generate(parent, item, mod_pkt_params)
1200 if act:
1201 new_actions.append(act)
1202
Rich Lane110e0e32012-10-26 16:21:46 -07001203 expected_pkt = packet_builder(**base_pkt_params)
Dan Talayco4b2bee62010-07-20 14:10:05 -07001204
1205 return (ingress_pkt, expected_pkt, new_actions)
Dan Talayco677c0b72011-08-23 22:53:38 -07001206
1207# Generate a simple "drop" flow mod
1208# If in_band is true, then only drop from first test port
1209def flow_mod_gen(port_map, in_band):
Rich Lanee717c6e2013-03-12 10:25:50 -07001210 request = ofp.message.flow_add()
1211 request.match.wildcards = ofp.OFPFW_ALL
Dan Talayco677c0b72011-08-23 22:53:38 -07001212 if in_band:
Rich Lanee717c6e2013-03-12 10:25:50 -07001213 request.match.wildcards = ofp.OFPFW_ALL - ofp.OFPFW_IN_PORT
Dan Talayco677c0b72011-08-23 22:53:38 -07001214 for of_port, ifname in port_map.items(): # Grab first port
1215 break
1216 request.match.in_port = of_port
1217 request.buffer_id = 0xffffffff
1218 return request
Dan Talaycoba3745c2010-07-21 21:51:08 -07001219
1220def skip_message_emit(parent, s):
1221 """
1222 Print out a 'skipped' message to stderr
1223
1224 @param s The string to print out to the log file
Dan Talaycoba3745c2010-07-21 21:51:08 -07001225 """
1226 global skipped_test_count
1227
1228 skipped_test_count += 1
Rich Lane9a003812012-10-04 17:17:59 -07001229 logging.info("Skipping: " + s)
Dan Talayco2940fdd2013-02-06 15:01:35 -08001230 if oftest.config["debug"] < logging.WARNING:
Dan Talaycoba3745c2010-07-21 21:51:08 -07001231 sys.stderr.write("(skipped) ")
1232 else:
1233 sys.stderr.write("(S)")
Dan Talayco677c0b72011-08-23 22:53:38 -07001234
Dan Talayco8a64e332012-03-28 14:53:20 -07001235
1236def all_stats_get(parent):
1237 """
1238 Get the aggregate stats for all flows in the table
1239 @param parent Test instance with controller connection and assert
1240 @returns dict with keys flows, packets, bytes, active (flows),
1241 lookups, matched
1242 """
Rich Lanee717c6e2013-03-12 10:25:50 -07001243 stat_req = ofp.message.aggregate_stats_request()
1244 stat_req.match = ofp.match()
1245 stat_req.match.wildcards = ofp.OFPFW_ALL
Dan Talayco8a64e332012-03-28 14:53:20 -07001246 stat_req.table_id = 0xff
Rich Lanee717c6e2013-03-12 10:25:50 -07001247 stat_req.out_port = ofp.OFPP_NONE
Dan Talayco8a64e332012-03-28 14:53:20 -07001248
1249 rv = {}
1250
Rich Lanec8aaa3e2012-07-26 19:28:02 -07001251 (reply, pkt) = parent.controller.transact(stat_req)
Rich Lane5fd6faf2013-03-11 13:30:20 -07001252 parent.assertTrue(len(reply.entries) == 1, "Did not receive flow stats reply")
Dan Talayco8a64e332012-03-28 14:53:20 -07001253
Rich Lane5fd6faf2013-03-11 13:30:20 -07001254 for obj in reply.entries:
Dan Talayco8a64e332012-03-28 14:53:20 -07001255 (rv["flows"], rv["packets"], rv["bytes"]) = (obj.flow_count,
1256 obj.packet_count, obj.byte_count)
1257 break
1258
Rich Lanee717c6e2013-03-12 10:25:50 -07001259 request = ofp.message.table_stats_request()
Rich Lanec8aaa3e2012-07-26 19:28:02 -07001260 (reply , pkt) = parent.controller.transact(request)
Dan Talayco8a64e332012-03-28 14:53:20 -07001261
1262
1263 (rv["active"], rv["lookups"], rv["matched"]) = (0,0,0)
Rich Lane5fd6faf2013-03-11 13:30:20 -07001264 for obj in reply.entries:
Dan Talayco8a64e332012-03-28 14:53:20 -07001265 rv["active"] += obj.active_count
1266 rv["lookups"] += obj.lookup_count
1267 rv["matched"] += obj.matched_count
1268
1269 return rv
Dan Talayco2baf8b52012-03-30 09:55:42 -07001270
Rich Lane7744e112013-01-11 17:23:57 -08001271_import_blacklist.add('FILTER')
Dan Talayco2baf8b52012-03-30 09:55:42 -07001272FILTER=''.join([(len(repr(chr(x)))==3) and chr(x) or '.'
1273 for x in range(256)])
1274
1275def hex_dump_buffer(src, length=16):
1276 """
1277 Convert src to a hex dump string and return the string
1278 @param src The source buffer
1279 @param length The number of bytes shown in each line
1280 @returns A string showing the hex dump
1281 """
Dan Talaycoc516fa02012-04-12 22:28:43 -07001282 result = ["\n"]
Dan Talayco2baf8b52012-03-30 09:55:42 -07001283 for i in xrange(0, len(src), length):
1284 chars = src[i:i+length]
1285 hex = ' '.join(["%02x" % ord(x) for x in chars])
1286 printable = ''.join(["%s" % ((ord(x) <= 127 and
1287 FILTER[ord(x)]) or '.') for x in chars])
1288 result.append("%04x %-*s %s\n" % (i, length*3, hex, printable))
1289 return ''.join(result)
1290
1291def format_packet(pkt):
1292 return "Packet length %d \n%s" % (len(str(pkt)),
1293 hex_dump_buffer(str(pkt)))
Rich Lane5d7e89a2012-10-26 16:43:13 -07001294
1295def inspect_packet(pkt):
1296 """
1297 Wrapper around scapy's show() method.
1298 @returns A string showing the dissected packet.
1299 """
1300 from cStringIO import StringIO
1301 out = None
1302 backup = sys.stdout
1303 try:
Rich Lanefdec0fb2013-08-09 18:01:05 -07001304 tmp = StringIO()
1305 sys.stdout = tmp
Rich Lane5d7e89a2012-10-26 16:43:13 -07001306 pkt.show2()
Rich Lanefdec0fb2013-08-09 18:01:05 -07001307 out = tmp.getvalue()
1308 tmp.close()
Rich Lane5d7e89a2012-10-26 16:43:13 -07001309 finally:
1310 sys.stdout = backup
1311 return out
Rich Lane0a4f6372013-01-02 14:40:22 -08001312
1313def nonstandard(cls):
1314 """
Rich Lanecc45b8e2013-01-02 15:55:02 -08001315 Testcase decorator that marks the test as being non-standard.
1316 These tests are not automatically added to the "standard" group.
Rich Lane0a4f6372013-01-02 14:40:22 -08001317 """
Rich Lanecc45b8e2013-01-02 15:55:02 -08001318 cls._nonstandard = True
Rich Lane0a4f6372013-01-02 14:40:22 -08001319 return cls
1320
1321def disabled(cls):
1322 """
Rich Lanecc45b8e2013-01-02 15:55:02 -08001323 Testcase decorator that marks the test as being disabled.
1324 These tests are not automatically added to the "standard" group or
1325 their module's group.
Rich Lane0a4f6372013-01-02 14:40:22 -08001326 """
Rich Lanecc45b8e2013-01-02 15:55:02 -08001327 cls._disabled = True
Rich Lane0a4f6372013-01-02 14:40:22 -08001328 return cls
Rich Lane97e99652013-01-02 17:23:20 -08001329
1330def group(name):
1331 """
1332 Testcase decorator that adds the test to a group.
1333 """
1334 def fn(cls):
1335 if not hasattr(cls, "_groups"):
1336 cls._groups = []
1337 cls._groups.append(name)
1338 return cls
1339 return fn
Rich Lane5a9a1922013-01-11 14:29:30 -08001340
1341def version(ver):
1342 """
1343 Testcase decorator that specifies which versions of OpenFlow the test
1344 supports. The default is 1.0+. This decorator may only be used once.
1345
1346 Supported syntax:
1347 1.0 -> 1.0
1348 1.0,1.2,1.3 -> 1.0, 1.2, 1.3
1349 1.0+ -> 1.0, 1.1, 1.2, 1.3
1350 """
1351 versions = parse_version(ver)
1352 def fn(cls):
1353 cls._versions = versions
1354 return cls
1355 return fn
1356
1357def parse_version(ver):
1358 allowed_versions = ["1.0", "1.1", "1.2", "1.3"]
1359 if re.match("^1\.\d+$", ver):
1360 versions = set([ver])
1361 elif re.match("^(1\.\d+)\+$", ver):
1362 if not ver[:-1] in allowed_versions:
1363 raise ValueError("invalid OpenFlow version %s" % ver[:-1])
1364 versions = set()
1365 if ver != "1.1+": versions.add("1.0")
1366 if ver != "1.2+": versions.add("1.1")
1367 if ver != "1.3+": versions.add("1.2")
1368 versions.add("1.3")
1369 else:
1370 versions = set(ver.split(','))
1371
1372 for version in versions:
1373 if not version in allowed_versions:
1374 raise ValueError("invalid OpenFlow version %s" % version)
1375
1376 return versions
1377
1378assert(parse_version("1.0") == set(["1.0"]))
1379assert(parse_version("1.0,1.2,1.3") == set(["1.0", "1.2", "1.3"]))
1380assert(parse_version("1.0+") == set(["1.0", "1.1", "1.2", "1.3"]))
Rich Lane7744e112013-01-11 17:23:57 -08001381
Rich Laneae3428c2013-03-07 14:37:42 -08001382def get_stats(test, req):
1383 """
1384 Retrieve a list of stats entries. Handles OFPSF_REPLY_MORE.
1385 """
Rich Lane609194f2013-10-21 06:17:37 -07001386 msgtype = ofp.OFPT_STATS_REPLY
1387 more_flag = ofp.OFPSF_REPLY_MORE
Rich Laneae3428c2013-03-07 14:37:42 -08001388 stats = []
1389 reply, _ = test.controller.transact(req)
1390 test.assertTrue(reply is not None, "No response to stats request")
Rich Lane34c68d52013-10-11 10:38:21 -07001391 test.assertEquals(reply.type, msgtype, "Response had unexpected message type")
Rich Lane5fd6faf2013-03-11 13:30:20 -07001392 stats.extend(reply.entries)
Rich Lanebd56ed62013-07-10 15:49:44 -07001393 while reply.flags & more_flag != 0:
Rich Lane34c68d52013-10-11 10:38:21 -07001394 reply, pkt = test.controller.poll(exp_msg=msgtype)
Rich Laneae3428c2013-03-07 14:37:42 -08001395 test.assertTrue(reply is not None, "No response to stats request")
Rich Lane5fd6faf2013-03-11 13:30:20 -07001396 stats.extend(reply.entries)
Rich Laneae3428c2013-03-07 14:37:42 -08001397 return stats
1398
Rich Lanebd56ed62013-07-10 15:49:44 -07001399def get_flow_stats(test, match, table_id=None,
1400 out_port=None, out_group=None,
1401 cookie=0, cookie_mask=0):
Rich Laneae3428c2013-03-07 14:37:42 -08001402 """
1403 Retrieve a list of flow stats entries.
1404 """
Rich Lanebd56ed62013-07-10 15:49:44 -07001405
1406 if table_id == None:
1407 if ofp.OFP_VERSION <= 2:
1408 table_id = 0xff
1409 else:
1410 table_id = ofp.OFPTT_ALL
1411
Rich Lanef3bc48c2013-05-03 17:39:35 -07001412 if out_port == None:
Rich Lanebd56ed62013-07-10 15:49:44 -07001413 if ofp.OFP_VERSION == 1:
1414 out_port = ofp.OFPP_NONE
1415 else:
1416 out_port = ofp.OFPP_ANY
1417
1418 if out_group == None:
1419 if ofp.OFP_VERSION > 1:
1420 out_group = ofp.OFPP_ANY
1421
Rich Lanee717c6e2013-03-12 10:25:50 -07001422 req = ofp.message.flow_stats_request(match=match,
Rich Lanebd56ed62013-07-10 15:49:44 -07001423 table_id=table_id,
1424 out_port=out_port)
1425 if ofp.OFP_VERSION > 1:
1426 req.out_group = out_group
1427 req.cookie = cookie
1428 req.cookie_mask = cookie_mask
1429
Rich Laneae3428c2013-03-07 14:37:42 -08001430 return get_stats(test, req)
1431
Rich Lane968b6192013-03-07 15:34:43 -08001432def get_port_stats(test, port_no):
1433 """
1434 Retrieve a list of port stats entries.
1435 """
Rich Lanee717c6e2013-03-12 10:25:50 -07001436 req = ofp.message.port_stats_request(port_no=port_no)
Rich Lane968b6192013-03-07 15:34:43 -08001437 return get_stats(test, req)
1438
Rich Lane6a334922013-03-07 16:14:52 -08001439def get_queue_stats(test, port_no, queue_id):
1440 """
1441 Retrieve a list of queue stats entries.
1442 """
Rich Lanee717c6e2013-03-12 10:25:50 -07001443 req = ofp.message.queue_stats_request(port_no=port_no, queue_id=queue_id)
Rich Lane6a334922013-03-07 16:14:52 -08001444 return get_stats(test, req)
1445
Rich Laneae3428c2013-03-07 14:37:42 -08001446def verify_flow_stats(test, match, table_id=0xff,
Rich Laneae3428c2013-03-07 14:37:42 -08001447 initial=[],
1448 pkts=None, bytes=None):
1449 """
1450 Verify that flow stats changed as expected.
1451
1452 Optionally takes an 'initial' list of stats entries, as returned by
1453 get_flow_stats(). If 'initial' is not given the counters are assumed to
1454 begin at 0.
1455 """
Rich Lanef3bc48c2013-05-03 17:39:35 -07001456
Rich Laneae3428c2013-03-07 14:37:42 -08001457 def accumulate(stats):
1458 pkts_acc = bytes_acc = 0
1459 for stat in stats:
1460 pkts_acc += stat.packet_count
1461 bytes_acc += stat.byte_count
1462 return (pkts_acc, bytes_acc)
1463
1464 pkts_before, bytes_before = accumulate(initial)
1465
1466 # Wait 10s for counters to update
1467 pkt_diff = byte_diff = None
1468 for i in range(0, 100):
Rich Lane61edad52014-03-28 16:25:08 -07001469 stats = get_flow_stats(test, match, table_id=table_id)
Rich Laneae3428c2013-03-07 14:37:42 -08001470 pkts_after, bytes_after = accumulate(stats)
1471 pkt_diff = pkts_after - pkts_before
1472 byte_diff = bytes_after - bytes_before
1473 if (pkts == None or pkt_diff >= pkts) and \
1474 (bytes == None or byte_diff >= bytes):
1475 break
Dan Talayco53724732013-03-08 23:54:02 -08001476 time.sleep(0.1)
Rich Laneae3428c2013-03-07 14:37:42 -08001477
1478 if pkts != None:
1479 test.assertEquals(pkt_diff, pkts, "Flow packet counter not updated properly (expected increase of %d, got increase of %d)" % (pkts, pkt_diff))
1480
1481 if bytes != None:
Rich Lane53b96812013-03-07 16:54:50 -08001482 test.assertTrue(byte_diff >= bytes and byte_diff <= bytes*1.1,
1483 "Flow byte counter not updated properly (expected increase of %d, got increase of %d)" % (bytes, byte_diff))
Rich Laneae3428c2013-03-07 14:37:42 -08001484
Rich Lane968b6192013-03-07 15:34:43 -08001485def verify_port_stats(test, port,
1486 initial=[],
1487 tx_pkts=None, rx_pkts=None,
1488 tx_bytes=None, rx_bytes=None):
1489 """
1490 Verify that port stats changed as expected.
1491
1492 Optionally takes an 'initial' list of stats entries, as returned by
1493 get_port_stats(). If 'initial' is not given the counters are assumed to
1494 begin at 0.
1495 """
1496 def accumulate(stats):
1497 tx_pkts_acc = rx_pkts_acc = tx_bytes_acc = rx_bytes_acc = 0
1498 for stat in stats:
1499 tx_pkts_acc += stat.tx_packets
1500 rx_pkts_acc += stat.rx_packets
1501 tx_bytes_acc += stat.tx_bytes
1502 rx_bytes_acc += stat.rx_bytes
1503 return (tx_pkts_acc, rx_pkts_acc, tx_bytes_acc, rx_bytes_acc)
1504
1505 tx_pkts_before, rx_pkts_before, \
1506 tx_bytes_before, rx_bytes_before = accumulate(initial)
1507
1508 # Wait 10s for counters to update
1509 for i in range(0, 100):
1510 stats = get_port_stats(test, port)
1511 tx_pkts_after, rx_pkts_after, \
1512 tx_bytes_after, rx_bytes_after = accumulate(stats)
1513 tx_pkts_diff = tx_pkts_after - tx_pkts_before
1514 rx_pkts_diff = rx_pkts_after - rx_pkts_before
1515 tx_bytes_diff = tx_bytes_after - tx_bytes_before
1516 rx_bytes_diff = rx_bytes_after - rx_bytes_before
Rich Lane3a208f82015-04-10 12:37:57 -07001517 if (tx_pkts == None or tx_pkts <= tx_pkts_diff) and \
1518 (rx_pkts == None or rx_pkts <= rx_pkts_diff) and \
Rich Lane53b96812013-03-07 16:54:50 -08001519 (tx_bytes == None or tx_bytes <= tx_bytes_diff) and \
1520 (rx_bytes == None or rx_bytes <= rx_bytes_diff):
Rich Lane968b6192013-03-07 15:34:43 -08001521 break
1522 time.sleep(0.1)
1523
1524 if (tx_pkts != None):
Rich Lane3a208f82015-04-10 12:37:57 -07001525 test.assertGreaterEqual(tx_pkts_diff, tx_pkts,
1526 "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 -08001527 if (rx_pkts != None):
Rich Lane3a208f82015-04-10 12:37:57 -07001528 test.assertGreaterEqual(rx_pkts_diff, rx_pkts,
1529 "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 -08001530 if (tx_bytes != None):
Rich Lane3a208f82015-04-10 12:37:57 -07001531 test.assertGreaterEqual(tx_bytes_diff, tx_bytes,
1532 "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 -08001533 if (rx_bytes != None):
Rich Lane3a208f82015-04-10 12:37:57 -07001534 test.assertGreaterEqual(rx_bytes_diff, rx_bytes,
1535 "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 -08001536
Rich Lane6a334922013-03-07 16:14:52 -08001537def verify_queue_stats(test, port_no, queue_id,
1538 initial=[],
1539 pkts=None, bytes=None):
1540 """
1541 Verify that queue stats changed as expected.
1542
1543 Optionally takes an 'initial' list of stats entries, as returned by
1544 get_queue_stats(). If 'initial' is not given the counters are assumed to
1545 begin at 0.
1546 """
1547 def accumulate(stats):
1548 pkts_acc = bytes_acc = 0
1549 for stat in stats:
1550 pkts_acc += stat.tx_packets
1551 bytes_acc += stat.tx_bytes
1552 return (pkts_acc, bytes_acc)
1553
1554 pkts_before, bytes_before = accumulate(initial)
1555
1556 # Wait 10s for counters to update
1557 pkt_diff = byte_diff = None
1558 for i in range(0, 100):
1559 stats = get_queue_stats(test, port_no, queue_id)
1560 pkts_after, bytes_after = accumulate(stats)
1561 pkt_diff = pkts_after - pkts_before
1562 byte_diff = bytes_after - bytes_before
1563 if (pkts == None or pkt_diff >= pkts) and \
1564 (bytes == None or byte_diff >= bytes):
1565 break
Dan Talayco53724732013-03-08 23:54:02 -08001566 time.sleep(0.1)
Rich Lane6a334922013-03-07 16:14:52 -08001567
1568 if pkts != None:
1569 test.assertEquals(pkt_diff, pkts, "Queue packet counter not updated properly (expected increase of %d, got increase of %d)" % (pkts, pkt_diff))
1570
1571 if bytes != None:
Rich Lane53b96812013-03-07 16:54:50 -08001572 test.assertTrue(byte_diff >= bytes and byte_diff <= bytes*1.1,
1573 "Queue byte counter not updated properly (expected increase of %d, got increase of %d)" % (bytes, byte_diff))
Rich Laneae3428c2013-03-07 14:37:42 -08001574
Rich Lane4c504f32013-06-07 17:24:14 -07001575def packet_in_match(msg, data, in_port=None, reason=None):
1576 """
1577 Check whether the packet_in message 'msg' has fields matching 'data',
1578 'in_port', and 'reason'.
1579
1580 This function handles truncated packet_in data. The 'in_port' and 'reason'
1581 parameters are optional.
1582
1583 @param msg packet_in message
1584 @param data Expected packet_in data
1585 @param in_port Expected packet_in in_port, or None
1586 @param reason Expected packet_in reason, or None
1587 """
1588
Rich Lanec0d26dd2013-07-10 12:46:03 -07001589 if ofp.OFP_VERSION <= 2:
1590 pkt_in_port = msg.in_port
1591 else:
1592 oxms = { type(oxm): oxm for oxm in msg.match.oxm_list }
1593 if ofp.oxm.in_port in oxms:
1594 pkt_in_port = oxms[ofp.oxm.in_port].value
1595 else:
1596 logging.warn("Missing in_port in packet-in message")
1597 pkt_in_port = None
1598
1599 if in_port != None and in_port != pkt_in_port:
Rich Lane9f2f17e2013-09-13 13:19:37 -07001600 logging.debug("Incorrect packet_in in_port (expected %d, received %d)", in_port, pkt_in_port)
Rich Lane4c504f32013-06-07 17:24:14 -07001601 return False
1602
Rich Lanec0d26dd2013-07-10 12:46:03 -07001603 if reason != None and reason != msg.reason:
Rich Lane4c504f32013-06-07 17:24:14 -07001604 logging.debug("Incorrect packet_in reason (expected %d, received %d)", reason, msg.reason)
1605 return False
1606
1607 # Check that one of the packets is a prefix of the other.
1608 # The received packet may be either truncated or padded, but not both.
1609 # (Some of the padding may be truncated but that's irrelevant). We
1610 # need to check that the smaller packet is a prefix of the larger one.
1611 # Note that this check succeeds if the switch sends a zero-length
1612 # packet-in.
1613 compare_len = min(len(msg.data), len(data))
1614 if data[:compare_len] != msg.data[:compare_len]:
1615 logging.debug("Incorrect packet_in data")
1616 logging.debug("Expected %s" % format_packet(data[:compare_len]))
1617 logging.debug("Received %s" % format_packet(msg.data[:compare_len]))
1618 return False
1619
1620 return True
1621
1622def verify_packet_in(test, data, in_port, reason, controller=None):
1623 """
1624 Assert that the controller receives a packet_in message matching data 'data'
1625 from port 'in_port' with reason 'reason'. Does not trigger the packet_in
1626 itself, that's up to the test case.
1627
1628 @param test Instance of base_tests.SimpleProtocol
1629 @param pkt String to expect as the packet_in data
1630 @param in_port OpenFlow port number to expect as the packet_in in_port
1631 @param reason One of OFPR_* to expect as the packet_in reason
1632 @param controller Controller instance, defaults to test.controller
1633 @returns The received packet-in message
1634 """
1635
1636 if controller == None:
1637 controller = test.controller
1638
1639 end_time = time.time() + oftest.ofutils.default_timeout
1640
1641 while True:
1642 msg, _ = controller.poll(ofp.OFPT_PACKET_IN, end_time - time.time())
1643 if not msg:
1644 # Timeout
1645 break
1646 elif packet_in_match(msg, data, in_port, reason):
1647 # Found a matching message
1648 break
1649
Kiran Poola58c5c042014-05-15 15:11:06 -07001650 test.assertTrue(msg is not None, 'Packet in message not received on port %r' % in_port)
Rich Lane4c504f32013-06-07 17:24:14 -07001651 return msg
1652
1653def verify_no_packet_in(test, data, in_port, controller=None):
1654 """
1655 Assert that the controller does not receive a packet_in message matching
1656 data 'data' from port 'in_port'.
1657
1658 @param test Instance of base_tests.SimpleProtocol
1659 @param pkt String to expect as the packet_in data
1660 @param in_port OpenFlow port number to expect as the packet_in in_port
1661 @param controller Controller instance, defaults to test.controller
1662 """
1663
1664 if controller == None:
1665 controller = test.controller
1666
1667 # Negative test, need to wait a short amount of time before checking we
1668 # didn't receive the message.
Rich Lane48f6aed2014-03-23 15:51:02 -07001669 time.sleep(oftest.ofutils.default_negative_timeout)
Rich Lane4c504f32013-06-07 17:24:14 -07001670
1671 # Check every packet_in queued in the controller
1672 while True:
1673 msg, _ = controller.poll(ofp.OFPT_PACKET_IN, timeout=0)
1674 if msg == None:
1675 # No more queued packet_in messages
1676 break
1677 elif packet_in_match(msg, data, in_port, None):
1678 # Found a matching message
1679 break
1680
Rich Lane82c882d2013-08-09 17:13:52 -07001681 if in_port == None:
1682 test.assertTrue(msg == None, "Did not expect a packet-in message on any port")
1683 else:
1684 test.assertTrue(msg == None, "Did not expect a packet-in message on port %d" % in_port)
Rich Lane4c504f32013-06-07 17:24:14 -07001685
Rich Lane045db072013-08-06 13:16:30 -07001686def openflow_ports(num=None):
1687 """
1688 Return a list of 'num' OpenFlow port numbers
1689
1690 If 'num' is None, return all available ports. Otherwise, limit the length
1691 of the result to 'num' and raise an exception if not enough ports are
1692 available.
1693 """
1694 ports = sorted(oftest.config["port_map"].keys())
1695 if num != None and len(ports) < num:
1696 raise Exception("test requires %d ports but only %d are available" % (num, len(ports)))
1697 return ports[:num]
1698
Rich Lanee4b384d2013-09-13 14:33:40 -07001699def verify_packet(test, pkt, ofport):
1700 """
1701 Check that an expected packet is received
1702 """
1703 logging.debug("Checking for pkt on port %r", ofport)
1704 (rcv_port, rcv_pkt, pkt_time) = test.dataplane.poll(port_number=ofport, exp_pkt=str(pkt))
1705 test.assertTrue(rcv_pkt != None, "Did not receive pkt on %r" % ofport)
macauley17cd60d2015-07-27 17:41:18 +08001706 return (rcv_port, rcv_pkt, pkt_time)
1707
Rich Lanee4b384d2013-09-13 14:33:40 -07001708def verify_no_packet(test, pkt, ofport):
1709 """
1710 Check that a particular packet is not received
1711 """
1712 logging.debug("Negative check for pkt on port %r", ofport)
Rich Lane48f6aed2014-03-23 15:51:02 -07001713 (rcv_port, rcv_pkt, pkt_time) = \
1714 test.dataplane.poll(
1715 port_number=ofport, exp_pkt=str(pkt),
1716 timeout=oftest.ofutils.default_negative_timeout)
Rich Lanee4b384d2013-09-13 14:33:40 -07001717 test.assertTrue(rcv_pkt == None, "Received packet on %r" % ofport)
1718
1719def verify_no_other_packets(test):
1720 """
1721 Check that no unexpected packets are received
1722
1723 This is a no-op if the --relax option is in effect.
1724 """
1725 if oftest.config["relax"]:
1726 return
1727 logging.debug("Checking for unexpected packets on all ports")
Rich Lane48f6aed2014-03-23 15:51:02 -07001728 (rcv_port, rcv_pkt, pkt_time) = test.dataplane.poll(timeout=oftest.ofutils.default_negative_timeout)
Rich Lanee4b384d2013-09-13 14:33:40 -07001729 if rcv_pkt != None:
1730 logging.debug("Received unexpected packet on port %r: %s", rcv_port, format_packet(rcv_pkt))
1731 test.assertTrue(rcv_pkt == None, "Unexpected packet on port %r" % rcv_port)
1732
1733def verify_packets(test, pkt, ofports):
1734 """
1735 Check that a packet is received on certain ports
1736
1737 Also verifies that the packet is not received on any other ports, and that no
1738 other packets are received (unless --relax is in effect).
1739
1740 This covers the common and simplest cases for checking dataplane outputs.
1741 For more complex usage, like multiple different packets being output, or
1742 multiple packets on the same port, use the primitive verify_packet,
1743 verify_no_packet, and verify_no_other_packets functions directly.
1744 """
1745 pkt = str(pkt)
1746 for ofport in openflow_ports():
1747 if ofport in ofports:
1748 verify_packet(test, pkt, ofport)
1749 else:
1750 verify_no_packet(test, pkt, ofport)
1751 verify_no_other_packets(test)
1752
Rich Lane12d04592013-10-10 17:21:07 -07001753def verify_no_errors(ctrl):
1754 error, _ = ctrl.poll(ofp.OFPT_ERROR, 0)
1755 if error:
1756 raise AssertionError("unexpected error type=%d code=%d" % (error.err_type, error.code))
Rich Lanee4b384d2013-09-13 14:33:40 -07001757
Jonathan Stoutfcee3142014-01-28 15:46:22 -05001758def verify_capability(test, capability):
1759 """
Jonathan Stout073642d2014-02-04 13:41:48 -05001760 Return True if DUT supports the specified capability.
Jonathan Stoutfcee3142014-01-28 15:46:22 -05001761
1762 @param test Instance of base_tests.SimpleProtocol
1763 @param capability One of ofp_capabilities.
1764 """
1765 logging.info("Verifing that capability code is valid.")
1766 test.assertIn(capability, ofp.const.ofp_capabilities_map,
1767 "Capability code %d does not exist." % capability)
1768 capability_str = ofp.const.ofp_capabilities_map[capability]
1769
1770 logging.info(("Sending features_request to test if capability "
Jonathan Stout97e458a2014-01-28 16:08:04 -05001771 "%s is supported."), capability_str)
Jonathan Stoutfcee3142014-01-28 15:46:22 -05001772 req = ofp.message.features_request()
1773 res, raw = test.controller.transact(req)
1774 test.assertIsNotNone(res, "Did not receive a response from the DUT.")
1775 test.assertEqual(res.type, ofp.OFPT_FEATURES_REPLY,
1776 ("Unexpected packet type %d received in response to "
1777 "OFPT_FEATURES_REQUEST") % res.type)
Jonathan Stout641167f2014-02-04 12:07:10 -05001778 logging.info("Received features_reply.")
Jonathan Stoutfcee3142014-01-28 15:46:22 -05001779
Jonathan Stout641167f2014-02-04 12:07:10 -05001780 if (res.capabilities & capability) > 0:
1781 logging.info("Switch capabilities bitmask claims to support %s",
1782 capability_str)
1783 return True, res.capabilities
1784 else:
1785 logging.info("Capabilities bitmask does not support %s.",
1786 capability_str)
1787 return False, res.capabilities
Jonathan Stoutfcee3142014-01-28 15:46:22 -05001788
Jonathan Stouteb3721d2014-02-04 13:59:12 -05001789def verify_configuration_flag(test, flag):
1790 """
1791 Return True if DUT supports specified configuration flag.
1792
1793 @param test Instance of base_tests.SimpleProtocol
1794 @param flag One of ofp_config_flags.
Jonathan Stout1ec8c0f2014-02-04 15:25:38 -05001795 @returns (supported, flags) Bool if flag is set and flag values.
Jonathan Stouteb3721d2014-02-04 13:59:12 -05001796 """
1797 logging.info("Verifing that flag is valid.")
1798 test.assertIn(flag, ofp.const.ofp_config_flags_map,
1799 "flag %s does not exist." % flag)
1800 flag_str = ofp.const.ofp_config_flags_map[flag]
1801
1802 logging.info("Sending OFPT_GET_CONFIG_REQUEST.")
1803 req = ofp.message.get_config_request()
1804 rv = test.controller.message_send(req)
1805 test.assertNotEqual(rv, -1, "Not able to send get_config_request.")
1806
1807 logging.info("Expecting OFPT_GET_CONFIG_REPLY ")
1808 (res, pkt) = test.controller.poll(exp_msg=ofp.OFPT_GET_CONFIG_REPLY,
1809 timeout=2)
1810 test.assertIsNotNone(res, "Did not receive OFPT_GET_CONFIG_REPLY")
1811 logging.info("Received OFPT_GET_CONFIG_REPLY ")
1812
1813 if res.flags == flag:
1814 logging.info("%s flag is set.", flag_str)
1815 return True, res.flags
1816 else:
1817 logging.info("%s flag is not set.", flag_str)
1818 return False, res.flags
1819
Rich Lane7744e112013-01-11 17:23:57 -08001820__all__ = list(set(locals()) - _import_blacklist)