blob: 85ccfc37f668ba1e194b2160a00f841bfa69e0c6 [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
Rich Lane86aceb02013-07-17 18:45:38 -0700242def simple_udpv6_packet(pktlen=100,
243 eth_dst='00:01:02:03:04:05',
244 eth_src='00:06:07:08:09:0a',
245 dl_vlan_enable=False,
246 vlan_vid=0,
247 vlan_pcp=0,
248 ipv6_src='2001:db8:85a3::8a2e:370:7334',
249 ipv6_dst='2001:db8:85a3::8a2e:370:7335',
250 ipv6_tc=0,
251 ipv6_hlim=64,
252 ipv6_fl=0,
253 udp_sport=1234,
254 udp_dport=80):
255 """
256 Return a simple IPv6/UDP packet
257
258 Supports a few parameters:
259 @param len Length of packet in bytes w/o CRC
260 @param eth_dst Destination MAC
261 @param eth_src Source MAC
262 @param dl_vlan_enable True if the packet is with vlan, False otherwise
263 @param vlan_vid VLAN ID
264 @param vlan_pcp VLAN priority
265 @param ipv6_src IPv6 source
266 @param ipv6_dst IPv6 destination
267 @param ipv6_tc IPv6 traffic class
268 @param ipv6_ttl IPv6 hop limit
269 @param ipv6_fl IPv6 flow label
270 @param udp_dport UDP destination port
271 @param udp_sport UDP source port
272
273 Generates a simple UDP request. Users shouldn't assume anything about this
274 packet other than that it is a valid ethernet/IPv6/UDP frame.
275 """
276
277 if MINSIZE > pktlen:
278 pktlen = MINSIZE
279
280 pkt = scapy.Ether(dst=eth_dst, src=eth_src)
281 if dl_vlan_enable or vlan_vid or vlan_pcp:
282 pkt /= scapy.Dot1Q(vlan=vlan_vid, prio=vlan_pcp)
283 pkt /= scapy.IPv6(src=ipv6_src, dst=ipv6_dst, fl=ipv6_fl, tc=ipv6_tc, hlim=ipv6_hlim)
284 pkt /= scapy.UDP(sport=udp_sport, dport=udp_dport)
285 pkt /= ("D" * (pktlen - len(pkt)))
286
287 return pkt
288
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700289def simple_icmp_packet(pktlen=60,
Rich Laned0478ff2013-03-11 12:46:58 -0700290 eth_dst='00:01:02:03:04:05',
291 eth_src='00:06:07:08:09:0a',
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700292 dl_vlan_enable=False,
Rich Laned0478ff2013-03-11 12:46:58 -0700293 vlan_vid=0,
294 vlan_pcp=0,
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700295 ip_src='192.168.0.1',
296 ip_dst='192.168.0.2',
297 ip_tos=0,
Gregor Maier9cc93342013-01-29 16:55:28 -0800298 ip_ttl=64,
Harshmeet Singhd209c0b2014-01-28 09:48:58 -0600299 ip_id=1,
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700300 icmp_type=8,
Harshmeet Singhd209c0b2014-01-28 09:48:58 -0600301 icmp_code=0,
Harshmeet Singh45b2a9d2014-01-28 13:02:04 -0600302 icmp_data=''):
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700303 """
304 Return a simple ICMP packet
305
306 Supports a few parameters:
307 @param len Length of packet in bytes w/o CRC
Rich Laned0478ff2013-03-11 12:46:58 -0700308 @param eth_dst Destinatino MAC
309 @param eth_src Source MAC
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700310 @param dl_vlan_enable True if the packet is with vlan, False otherwise
Rich Laned0478ff2013-03-11 12:46:58 -0700311 @param vlan_vid VLAN ID
312 @param vlan_pcp VLAN priority
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700313 @param ip_src IP source
314 @param ip_dst IP destination
315 @param ip_tos IP ToS
Gregor Maier9cc93342013-01-29 16:55:28 -0800316 @param ip_ttl IP TTL
Harshmeet Singhd209c0b2014-01-28 09:48:58 -0600317 @param ip_id IP Identification
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700318 @param icmp_type ICMP type
319 @param icmp_code ICMP code
Harshmeet Singhd209c0b2014-01-28 09:48:58 -0600320 @param icmp_data ICMP data
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700321
322 Generates a simple ICMP ECHO REQUEST. Users
323 shouldn't assume anything about this packet other than that
324 it is a valid ethernet/ICMP frame.
325 """
Jeffrey Townsend5cb7ed32012-08-17 18:11:01 +0000326
327 if MINSIZE > pktlen:
328 pktlen = MINSIZE
329
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700330 if (dl_vlan_enable):
Rich Laned0478ff2013-03-11 12:46:58 -0700331 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
332 scapy.Dot1Q(prio=vlan_pcp, id=0, vlan=vlan_vid)/ \
Harshmeet Singhd209c0b2014-01-28 09:48:58 -0600333 scapy.IP(src=ip_src, dst=ip_dst, ttl=ip_ttl, tos=ip_tos, id=ip_id)/ \
Harshmeet Singh45b2a9d2014-01-28 13:02:04 -0600334 scapy.ICMP(type=icmp_type, code=icmp_code)/ icmp_data
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700335 else:
Rich Laned0478ff2013-03-11 12:46:58 -0700336 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
Harshmeet Singhd209c0b2014-01-28 09:48:58 -0600337 scapy.IP(src=ip_src, dst=ip_dst, ttl=ip_ttl, tos=ip_tos, id=ip_id)/ \
Harshmeet Singh45b2a9d2014-01-28 13:02:04 -0600338 scapy.ICMP(type=icmp_type, code=icmp_code)/ icmp_data
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700339
340 pkt = pkt/("0" * (pktlen - len(pkt)))
341
342 return pkt
343
Rich Lane86aceb02013-07-17 18:45:38 -0700344def simple_icmpv6_packet(pktlen=100,
345 eth_dst='00:01:02:03:04:05',
346 eth_src='00:06:07:08:09:0a',
347 dl_vlan_enable=False,
348 vlan_vid=0,
349 vlan_pcp=0,
350 ipv6_src='2001:db8:85a3::8a2e:370:7334',
351 ipv6_dst='2001:db8:85a3::8a2e:370:7335',
352 ipv6_tc=0,
353 ipv6_hlim=64,
354 ipv6_fl=0,
355 icmp_type=8,
356 icmp_code=0):
357 """
358 Return a simple ICMPv6 packet
359
360 Supports a few parameters:
361 @param len Length of packet in bytes w/o CRC
362 @param eth_dst Destination MAC
363 @param eth_src Source MAC
364 @param dl_vlan_enable True if the packet is with vlan, False otherwise
365 @param vlan_vid VLAN ID
366 @param vlan_pcp VLAN priority
367 @param ipv6_src IPv6 source
368 @param ipv6_dst IPv6 destination
369 @param ipv6_tc IPv6 traffic class
370 @param ipv6_ttl IPv6 hop limit
371 @param ipv6_fl IPv6 flow label
372 @param icmp_type ICMP type
373 @param icmp_code ICMP code
374
375 Generates a simple ICMP ECHO REQUEST. Users shouldn't assume anything
376 about this packet other than that it is a valid ethernet/IPv6/ICMP frame.
377 """
378
379 if MINSIZE > pktlen:
380 pktlen = MINSIZE
381
382 pkt = scapy.Ether(dst=eth_dst, src=eth_src)
383 if dl_vlan_enable or vlan_vid or vlan_pcp:
384 pkt /= scapy.Dot1Q(vlan=vlan_vid, prio=vlan_pcp)
385 pkt /= scapy.IPv6(src=ipv6_src, dst=ipv6_dst, fl=ipv6_fl, tc=ipv6_tc, hlim=ipv6_hlim)
386 pkt /= scapy.ICMPv6Unknown(type=icmp_type, code=icmp_code)
387 pkt /= ("D" * (pktlen - len(pkt)))
388
389 return pkt
390
Shudong Zhouc7562b12013-02-06 01:12:18 -0800391def simple_arp_packet(pktlen=60,
Rich Laned0478ff2013-03-11 12:46:58 -0700392 eth_dst='ff:ff:ff:ff:ff:ff',
393 eth_src='00:06:07:08:09:0a',
Rich Lanee01611f2014-01-15 14:55:11 -0800394 vlan_vid=0,
395 vlan_pcp=0,
Shudong Zhouc7562b12013-02-06 01:12:18 -0800396 arp_op=1,
397 ip_snd='192.168.0.1',
398 ip_tgt='192.168.0.2',
399 hw_snd='00:06:07:08:09:0a',
400 hw_tgt='00:00:00:00:00:00',
401 ):
402 """
403 Return a simple ARP packet
404
405 Supports a few parameters:
406 @param len Length of packet in bytes w/o CRC
Rich Laned0478ff2013-03-11 12:46:58 -0700407 @param eth_dst Destinatino MAC
408 @param eth_src Source MAC
Shudong Zhouc7562b12013-02-06 01:12:18 -0800409 @param arp_op Operation (1=request, 2=reply)
410 @param ip_snd Sender IP
411 @param ip_tgt Target IP
412 @param hw_snd Sender hardware address
413 @param hw_tgt Target hardware address
414
415 Generates a simple ARP REQUEST. Users
416 shouldn't assume anything about this packet other than that
417 it is a valid ethernet/ARP frame.
418 """
419
420 if MINSIZE > pktlen:
421 pktlen = MINSIZE
422
Rich Lanee01611f2014-01-15 14:55:11 -0800423 pkt = scapy.Ether(dst=eth_dst, src=eth_src)
424 if vlan_vid or vlan_pcp:
425 pkt /= scapy.Dot1Q(vlan=vlan_vid, prio=vlan_pcp)
426 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 -0800427
Rich Laned459ce52014-01-24 12:09:54 -0800428 pkt = pkt/("\0" * (pktlen - len(pkt)))
Shudong Zhouc7562b12013-02-06 01:12:18 -0800429
430 return pkt
431
Ed Swierk0aeff8c2012-03-23 20:27:18 -0700432def simple_eth_packet(pktlen=60,
Rich Lane53275082013-11-18 23:26:22 -0800433 eth_dst='00:01:02:03:04:05',
434 eth_src='00:06:07:08:09:0a',
Rich Laned0478ff2013-03-11 12:46:58 -0700435 eth_type=0x88cc):
Jeffrey Townsend5cb7ed32012-08-17 18:11:01 +0000436
437 if MINSIZE > pktlen:
438 pktlen = MINSIZE
439
Rich Laned0478ff2013-03-11 12:46:58 -0700440 pkt = scapy.Ether(dst=eth_dst, src=eth_src, type=eth_type)
Ed Swierk0aeff8c2012-03-23 20:27:18 -0700441
442 pkt = pkt/("0" * (pktlen - len(pkt)))
443
444 return pkt
445
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800446def qinq_tcp_packet(pktlen=100,
Rich Laned0478ff2013-03-11 12:46:58 -0700447 eth_dst='00:01:02:03:04:05',
448 eth_src='00:06:07:08:09:0a',
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800449 dl_vlan_outer=20,
450 dl_vlan_pcp_outer=0,
451 dl_vlan_cfi_outer=0,
Rich Laned0478ff2013-03-11 12:46:58 -0700452 vlan_vid=10,
453 vlan_pcp=0,
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800454 dl_vlan_cfi=0,
455 ip_src='192.168.0.1',
456 ip_dst='192.168.0.2',
457 ip_tos=0,
Gregor Maier9cc93342013-01-29 16:55:28 -0800458 ip_ttl=64,
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800459 tcp_sport=1234,
460 tcp_dport=80,
461 ip_ihl=None,
462 ip_options=False
463 ):
464 """
465 Return a doubly tagged dataplane TCP packet
466
467 Supports a few parameters:
468 @param len Length of packet in bytes w/o CRC
Rich Laned0478ff2013-03-11 12:46:58 -0700469 @param eth_dst Destinatino MAC
470 @param eth_src Source MAC
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800471 @param dl_vlan_outer Outer VLAN ID
472 @param dl_vlan_pcp_outer Outer VLAN priority
473 @param dl_vlan_cfi_outer Outer VLAN cfi bit
Rich Laned0478ff2013-03-11 12:46:58 -0700474 @param vlan_vid Inner VLAN ID
475 @param vlan_pcp VLAN priority
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800476 @param dl_vlan_cfi VLAN cfi bit
477 @param ip_src IP source
478 @param ip_dst IP destination
479 @param ip_tos IP ToS
480 @param tcp_dport TCP destination port
481 @param ip_sport TCP source port
482
483 Generates a TCP request. Users
484 shouldn't assume anything about this packet other than that
485 it is a valid ethernet/IP/TCP frame.
486 """
487
488 if MINSIZE > pktlen:
489 pktlen = MINSIZE
490
491 # Note Dot1Q.id is really CFI
Rich Laned0478ff2013-03-11 12:46:58 -0700492 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800493 scapy.Dot1Q(prio=dl_vlan_pcp_outer, id=dl_vlan_cfi_outer, vlan=dl_vlan_outer)/ \
Rich Laned0478ff2013-03-11 12:46:58 -0700494 scapy.Dot1Q(prio=vlan_pcp, id=dl_vlan_cfi, vlan=vlan_vid)/ \
Gregor Maier9cc93342013-01-29 16:55:28 -0800495 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ttl=ip_ttl, ihl=ip_ihl)/ \
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800496 scapy.TCP(sport=tcp_sport, dport=tcp_dport)
497
498 pkt = pkt/("D" * (pktlen - len(pkt)))
499
500 return pkt
501
Shudong Zhoub7f12462012-11-20 13:01:12 -0800502def do_barrier(ctrl, timeout=-1):
Dan Talayco0fc08bd2012-04-09 16:56:18 -0700503 """
504 Do a barrier command
505 Return 0 on success, -1 on error
506 """
Rich Lanee717c6e2013-03-12 10:25:50 -0700507 b = ofp.message.barrier_request()
Shudong Zhoub7f12462012-11-20 13:01:12 -0800508 (resp, pkt) = ctrl.transact(b, timeout=timeout)
Rich Lane3a261d52013-01-03 17:45:08 -0800509 if resp is None:
510 raise AssertionError("barrier failed")
Dan Talaycof6b94832012-04-12 21:50:57 -0700511 # We'll trust the transaction processing in the controller that xid matched
Rich Lane3a261d52013-01-03 17:45:08 -0800512 return 0 # for backwards compatibility
Dan Talayco92c99122010-06-03 13:53:18 -0700513
Rich Lane9a003812012-10-04 17:17:59 -0700514def port_config_get(controller, port_no):
Dan Talayco92c99122010-06-03 13:53:18 -0700515 """
516 Get a port's configuration
517
518 Gets the switch feature configuration and grabs one port's
519 configuration
520
521 @returns (hwaddr, config, advert) The hwaddress, configuration and
522 advertised values
523 """
Rich Lane6dc865c2013-07-10 10:12:13 -0700524
525 if ofp.OFP_VERSION <= 3:
526 request = ofp.message.features_request()
527 reply, _ = controller.transact(request)
528 if reply is None:
529 logging.warn("Get feature request failed")
530 return None, None, None
531 logging.debug(reply.show())
532 ports = reply.ports
533 else:
534 request = ofp.message.port_desc_stats_request()
535 # TODO do multipart correctly
536 reply, _ = controller.transact(request)
537 if reply is None:
538 logging.warn("Port desc stats request failed")
539 return None, None, None
540 logging.debug(reply.show())
541 ports = reply.entries
542
543 for port in ports:
544 if port.port_no == port_no:
545 return (port.hw_addr, port.config, port.advertised)
Dan Talayco92c99122010-06-03 13:53:18 -0700546
Rich Lane9a003812012-10-04 17:17:59 -0700547 logging.warn("Did not find port number for port config")
Dan Talayco92c99122010-06-03 13:53:18 -0700548 return None, None, None
549
Rich Lane9a003812012-10-04 17:17:59 -0700550def port_config_set(controller, port_no, config, mask):
Dan Talayco92c99122010-06-03 13:53:18 -0700551 """
552 Set the port configuration according the given parameters
553
554 Gets the switch feature configuration and updates one port's
555 configuration value according to config and mask
556 """
Rich Lane9a003812012-10-04 17:17:59 -0700557 logging.info("Setting port " + str(port_no) + " to config " + str(config))
Rich Lane6dc865c2013-07-10 10:12:13 -0700558
559 hw_addr, _, _ = port_config_get(controller, port_no)
560
Rich Lanee717c6e2013-03-12 10:25:50 -0700561 mod = ofp.message.port_mod()
Dan Talayco92c99122010-06-03 13:53:18 -0700562 mod.port_no = port_no
Rich Lane6dc865c2013-07-10 10:12:13 -0700563 if hw_addr != None:
564 mod.hw_addr = hw_addr
Dan Talayco92c99122010-06-03 13:53:18 -0700565 mod.config = config
566 mod.mask = mask
Rich Lane6dc865c2013-07-10 10:12:13 -0700567 mod.advertise = 0 # No change
Rich Lane5c3151c2013-01-03 17:15:41 -0800568 controller.message_send(mod)
569 return 0
Dan Talayco92c99122010-06-03 13:53:18 -0700570
Rich Lane2014f9b2012-10-05 15:29:40 -0700571def receive_pkt_check(dp, pkt, yes_ports, no_ports, assert_if):
Dan Talayco92c99122010-06-03 13:53:18 -0700572 """
573 Check for proper receive packets across all ports
Ken Chiang1bf01602012-04-04 10:48:23 -0700574 @param dp The dataplane object
Dan Talayco92c99122010-06-03 13:53:18 -0700575 @param pkt Expected packet; may be None if yes_ports is empty
576 @param yes_ports Set or list of ports that should recieve packet
577 @param no_ports Set or list of ports that should not receive packet
578 @param assert_if Object that implements assertXXX
Rich Lanee4b384d2013-09-13 14:33:40 -0700579
580 DEPRECATED in favor in verify_packets
Dan Talayco92c99122010-06-03 13:53:18 -0700581 """
Rich Lane91765672012-12-06 16:33:04 -0800582
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700583 exp_pkt_arg = None
Rich Lanecd97d3d2013-01-07 18:50:06 -0800584 if oftest.config["relax"]:
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700585 exp_pkt_arg = pkt
586
Dan Talayco92c99122010-06-03 13:53:18 -0700587 for ofport in yes_ports:
Rich Lane9a003812012-10-04 17:17:59 -0700588 logging.debug("Checking for pkt on port " + str(ofport))
Ken Chiang1bf01602012-04-04 10:48:23 -0700589 (rcv_port, rcv_pkt, pkt_time) = dp.poll(
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700590 port_number=ofport, exp_pkt=exp_pkt_arg)
Dan Talayco92c99122010-06-03 13:53:18 -0700591 assert_if.assertTrue(rcv_pkt is not None,
592 "Did not receive pkt on " + str(ofport))
Rich Lanecd97d3d2013-01-07 18:50:06 -0800593 if not oftest.dataplane.match_exp_pkt(pkt, rcv_pkt):
Rich Lane3c266832013-01-29 18:29:15 -0800594 logging.debug("Expected %s" % format_packet(pkt))
595 logging.debug("Received %s" % format_packet(rcv_pkt))
Rich Lanecd97d3d2013-01-07 18:50:06 -0800596 assert_if.assertTrue(oftest.dataplane.match_exp_pkt(pkt, rcv_pkt),
Rich Lane3c266832013-01-29 18:29:15 -0800597 "Received packet does not match expected packet " +
Ken Chiang1bf01602012-04-04 10:48:23 -0700598 "on port " + str(ofport))
Dan Talayco73f84012012-10-02 09:23:18 -0700599 if len(no_ports) > 0:
Rich Lane57dfee72014-03-24 16:59:47 -0700600 time.sleep(oftest.ofutils.default_negative_timeout)
Dan Talayco92c99122010-06-03 13:53:18 -0700601 for ofport in no_ports:
Rich Lane9a003812012-10-04 17:17:59 -0700602 logging.debug("Negative check for pkt on port " + str(ofport))
Ken Chiang1bf01602012-04-04 10:48:23 -0700603 (rcv_port, rcv_pkt, pkt_time) = dp.poll(
Rich Lane91765672012-12-06 16:33:04 -0800604 port_number=ofport, timeout=0, exp_pkt=exp_pkt_arg)
Dan Talayco92c99122010-06-03 13:53:18 -0700605 assert_if.assertTrue(rcv_pkt is None,
606 "Unexpected pkt on port " + str(ofport))
Dan Talayco551befa2010-07-15 17:05:32 -0700607
608
Dan Talaycoc948d0b2012-03-23 12:17:54 -0700609def receive_pkt_verify(parent, egr_ports, exp_pkt, ing_port):
Dan Talayco551befa2010-07-15 17:05:32 -0700610 """
611 Receive a packet and verify it matches an expected value
Dan Talaycof6e76c02012-03-23 10:56:12 -0700612 @param egr_port A single port or list of ports
Dan Talayco551befa2010-07-15 17:05:32 -0700613
614 parent must implement dataplane, assertTrue and assertEqual
Rich Lanee4b384d2013-09-13 14:33:40 -0700615
616 DEPRECATED in favor in verify_packets
Dan Talayco551befa2010-07-15 17:05:32 -0700617 """
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700618 exp_pkt_arg = None
Rich Lanecd97d3d2013-01-07 18:50:06 -0800619 if oftest.config["relax"]:
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700620 exp_pkt_arg = exp_pkt
621
Dan Talaycof6e76c02012-03-23 10:56:12 -0700622 if type(egr_ports) == type([]):
623 egr_port_list = egr_ports
624 else:
625 egr_port_list = [egr_ports]
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700626
Dan Talaycof6e76c02012-03-23 10:56:12 -0700627 # Expect a packet from each port on egr port list
628 for egr_port in egr_port_list:
Dan Talaycod8ae7582012-03-23 12:24:56 -0700629 check_port = egr_port
Rich Lanee717c6e2013-03-12 10:25:50 -0700630 if egr_port == ofp.OFPP_IN_PORT:
Dan Talaycod8ae7582012-03-23 12:24:56 -0700631 check_port = ing_port
Dan Talaycof6e76c02012-03-23 10:56:12 -0700632 (rcv_port, rcv_pkt, pkt_time) = parent.dataplane.poll(
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700633 port_number=check_port, exp_pkt=exp_pkt_arg)
Dan Talayco551befa2010-07-15 17:05:32 -0700634
Dan Talaycof6e76c02012-03-23 10:56:12 -0700635 if rcv_pkt is None:
Rich Lane9a003812012-10-04 17:17:59 -0700636 logging.error("ERROR: No packet received from " +
Dan Talaycod8ae7582012-03-23 12:24:56 -0700637 str(check_port))
Dan Talayco551befa2010-07-15 17:05:32 -0700638
Dan Talaycof6e76c02012-03-23 10:56:12 -0700639 parent.assertTrue(rcv_pkt is not None,
Dan Talaycod8ae7582012-03-23 12:24:56 -0700640 "Did not receive packet port " + str(check_port))
Rich Lane9a003812012-10-04 17:17:59 -0700641 logging.debug("Packet len " + str(len(rcv_pkt)) + " in on " +
Dan Talaycof6e76c02012-03-23 10:56:12 -0700642 str(rcv_port))
643
644 if str(exp_pkt) != str(rcv_pkt):
Rich Lane9a003812012-10-04 17:17:59 -0700645 logging.error("ERROR: Packet match failed.")
646 logging.debug("Expected len " + str(len(exp_pkt)) + ": "
Dan Talaycof6e76c02012-03-23 10:56:12 -0700647 + str(exp_pkt).encode('hex'))
Rich Lane9a003812012-10-04 17:17:59 -0700648 logging.debug("Received len " + str(len(rcv_pkt)) + ": "
Dan Talaycof6e76c02012-03-23 10:56:12 -0700649 + str(rcv_pkt).encode('hex'))
Rich Lane5d7e89a2012-10-26 16:43:13 -0700650 logging.debug("Expected packet: " + inspect_packet(scapy.Ether(str(exp_pkt))))
651 logging.debug("Received packet: " + inspect_packet(scapy.Ether(str(rcv_pkt))))
Dan Talaycof6e76c02012-03-23 10:56:12 -0700652 parent.assertEqual(str(exp_pkt), str(rcv_pkt),
Dan Talaycod8ae7582012-03-23 12:24:56 -0700653 "Packet match error on port " + str(check_port))
Dan Talaycof6e76c02012-03-23 10:56:12 -0700654
Dan Talayco551befa2010-07-15 17:05:32 -0700655def match_verify(parent, req_match, res_match):
656 """
657 Verify flow matches agree; if they disagree, report where
658
659 parent must implement assertEqual
660 Use str() to ensure content is compared and not pointers
661 """
662
663 parent.assertEqual(req_match.wildcards, res_match.wildcards,
664 'Match failed: wildcards: ' + hex(req_match.wildcards) +
665 " != " + hex(res_match.wildcards))
666 parent.assertEqual(req_match.in_port, res_match.in_port,
667 'Match failed: in_port: ' + str(req_match.in_port) +
668 " != " + str(res_match.in_port))
Rich Laned0478ff2013-03-11 12:46:58 -0700669 parent.assertEqual(str(req_match.eth_src), str(res_match.eth_src),
670 'Match failed: eth_src: ' + str(req_match.eth_src) +
671 " != " + str(res_match.eth_src))
672 parent.assertEqual(str(req_match.eth_dst), str(res_match.eth_dst),
673 'Match failed: eth_dst: ' + str(req_match.eth_dst) +
674 " != " + str(res_match.eth_dst))
675 parent.assertEqual(req_match.vlan_vid, res_match.vlan_vid,
676 'Match failed: vlan_vid: ' + str(req_match.vlan_vid) +
677 " != " + str(res_match.vlan_vid))
678 parent.assertEqual(req_match.vlan_pcp, res_match.vlan_pcp,
679 'Match failed: vlan_pcp: ' +
680 str(req_match.vlan_pcp) + " != " +
681 str(res_match.vlan_pcp))
682 parent.assertEqual(req_match.eth_type, res_match.eth_type,
683 'Match failed: eth_type: ' + str(req_match.eth_type) +
684 " != " + str(res_match.eth_type))
Dan Talayco551befa2010-07-15 17:05:32 -0700685
Rich Lanee717c6e2013-03-12 10:25:50 -0700686 if (not(req_match.wildcards & ofp.OFPFW_DL_TYPE)
Rich Laned0478ff2013-03-11 12:46:58 -0700687 and (req_match.eth_type == IP_ETHERTYPE)):
688 parent.assertEqual(req_match.ip_dscp, res_match.ip_dscp,
689 'Match failed: ip_dscp: ' + str(req_match.ip_dscp) +
690 " != " + str(res_match.ip_dscp))
691 parent.assertEqual(req_match.ip_proto, res_match.ip_proto,
692 'Match failed: ip_proto: ' + str(req_match.ip_proto) +
693 " != " + str(res_match.ip_proto))
694 parent.assertEqual(req_match.ipv4_src, res_match.ipv4_src,
695 'Match failed: ipv4_src: ' + str(req_match.ipv4_src) +
696 " != " + str(res_match.ipv4_src))
697 parent.assertEqual(req_match.ipv4_dst, res_match.ipv4_dst,
698 'Match failed: ipv4_dst: ' + str(req_match.ipv4_dst) +
699 " != " + str(res_match.ipv4_dst))
Dan Talayco551befa2010-07-15 17:05:32 -0700700
Rich Lanee717c6e2013-03-12 10:25:50 -0700701 if (not(req_match.wildcards & ofp.OFPFW_NW_PROTO)
Rich Laned0478ff2013-03-11 12:46:58 -0700702 and ((req_match.ip_proto == TCP_PROTOCOL)
703 or (req_match.ip_proto == UDP_PROTOCOL))):
704 parent.assertEqual(req_match.tcp_src, res_match.tcp_src,
705 'Match failed: tcp_src: ' +
706 str(req_match.tcp_src) +
707 " != " + str(res_match.tcp_src))
708 parent.assertEqual(req_match.tcp_dst, res_match.tcp_dst,
709 'Match failed: tcp_dst: ' +
710 str(req_match.tcp_dst) +
711 " != " + str(res_match.tcp_dst))
Dan Talayco551befa2010-07-15 17:05:32 -0700712
Ed Swierk99a74de2012-08-22 06:40:54 -0700713def packet_to_flow_match(parent, packet):
Rich Lanef6883512013-03-11 17:00:09 -0700714 match = oftest.parse.packet_to_flow_match(packet)
Rich Laneab7476f2013-06-13 15:53:52 -0700715 if ofp.OFP_VERSION in [1, 2]:
716 match.wildcards |= required_wildcards(parent)
717 else:
718 # TODO remove incompatible OXM entries
719 pass
Ed Swierk99a74de2012-08-22 06:40:54 -0700720 return match
721
722def flow_msg_create(parent, pkt, ing_port=None, action_list=None, wildcards=None,
Dan Talaycof6e76c02012-03-23 10:56:12 -0700723 egr_ports=None, egr_queue=None, check_expire=False, in_band=False):
Dan Talayco551befa2010-07-15 17:05:32 -0700724 """
725 Create a flow message
726
727 Match on packet with given wildcards.
728 See flow_match_test for other parameter descriptoins
729 @param egr_queue if not None, make the output an enqueue action
Dan Talayco677c0b72011-08-23 22:53:38 -0700730 @param in_band if True, do not wildcard ingress port
Dan Talaycof6e76c02012-03-23 10:56:12 -0700731 @param egr_ports None (drop), single port or list of ports
Dan Talayco551befa2010-07-15 17:05:32 -0700732 """
Rich Lanef6883512013-03-11 17:00:09 -0700733 match = oftest.parse.packet_to_flow_match(pkt)
Dan Talayco551befa2010-07-15 17:05:32 -0700734 parent.assertTrue(match is not None, "Flow match from pkt failed")
Ed Swierk99a74de2012-08-22 06:40:54 -0700735 if wildcards is None:
736 wildcards = required_wildcards(parent)
Dan Talayco677c0b72011-08-23 22:53:38 -0700737 if in_band:
Rich Lanee717c6e2013-03-12 10:25:50 -0700738 wildcards &= ~ofp.OFPFW_IN_PORT
Dan Talayco551befa2010-07-15 17:05:32 -0700739 match.wildcards = wildcards
740 match.in_port = ing_port
741
Dan Talaycof6e76c02012-03-23 10:56:12 -0700742 if type(egr_ports) == type([]):
743 egr_port_list = egr_ports
744 else:
745 egr_port_list = [egr_ports]
746
Rich Lanee717c6e2013-03-12 10:25:50 -0700747 request = ofp.message.flow_add()
Dan Talayco551befa2010-07-15 17:05:32 -0700748 request.match = match
749 request.buffer_id = 0xffffffff
750 if check_expire:
Rich Lanee717c6e2013-03-12 10:25:50 -0700751 request.flags |= ofp.OFPFF_SEND_FLOW_REM
Dan Talayco551befa2010-07-15 17:05:32 -0700752 request.hard_timeout = 1
753
Rich Lane400fb9b2013-10-10 17:20:54 -0700754 if ofp.OFP_VERSION == 1:
755 actions = request.actions
756 else:
757 actions = []
758 request.instructions.append(ofp.instruction.apply_actions(actions))
759
Dan Talayco551befa2010-07-15 17:05:32 -0700760 if action_list is not None:
Rich Lane400fb9b2013-10-10 17:20:54 -0700761 actions.extend(action_list)
Dan Talayco551befa2010-07-15 17:05:32 -0700762
763 # Set up output/enqueue action if directed
764 if egr_queue is not None:
Dan Talaycof6e76c02012-03-23 10:56:12 -0700765 parent.assertTrue(egr_ports is not None, "Egress port not set")
Rich Lanee717c6e2013-03-12 10:25:50 -0700766 act = ofp.action.enqueue()
Dan Talaycof6e76c02012-03-23 10:56:12 -0700767 for egr_port in egr_port_list:
768 act.port = egr_port
769 act.queue_id = egr_queue
Rich Lane400fb9b2013-10-10 17:20:54 -0700770 actions.append(act)
Dan Talaycof6e76c02012-03-23 10:56:12 -0700771 elif egr_ports is not None:
772 for egr_port in egr_port_list:
Rich Lanee717c6e2013-03-12 10:25:50 -0700773 act = ofp.action.output()
Dan Talaycof6e76c02012-03-23 10:56:12 -0700774 act.port = egr_port
Rich Lane400fb9b2013-10-10 17:20:54 -0700775 actions.append(act)
Dan Talayco551befa2010-07-15 17:05:32 -0700776
Rich Lane9a003812012-10-04 17:17:59 -0700777 logging.debug(request.show())
Dan Talayco551befa2010-07-15 17:05:32 -0700778
779 return request
780
Jeffrey Townsendf3eae9c2012-03-28 18:23:21 -0700781def flow_msg_install(parent, request, clear_table_override=None):
Dan Talayco551befa2010-07-15 17:05:32 -0700782 """
783 Install a flow mod message in the switch
784
785 @param parent Must implement controller, assertEqual, assertTrue
786 @param request The request, all set to go
787 @param clear_table If true, clear the flow table before installing
788 """
Dan Talayco8a64e332012-03-28 14:53:20 -0700789
Rich Lane2014f9b2012-10-05 15:29:40 -0700790 clear_table = test_param_get('clear_table', default=True)
Jeffrey Townsendf3eae9c2012-03-28 18:23:21 -0700791 if(clear_table_override != None):
792 clear_table = clear_table_override
793
794 if clear_table:
Rich Lane9a003812012-10-04 17:17:59 -0700795 logging.debug("Clear flow table")
Rich Lane32bf9482013-01-03 17:26:30 -0800796 delete_all_flows(parent.controller)
Dan Talayco551befa2010-07-15 17:05:32 -0700797
Rich Lane9a003812012-10-04 17:17:59 -0700798 logging.debug("Insert flow")
Rich Lane5c3151c2013-01-03 17:15:41 -0800799 parent.controller.message_send(request)
Rich Lanee912d032012-12-22 14:28:33 -0800800
Rich Lane3a261d52013-01-03 17:45:08 -0800801 do_barrier(parent.controller)
Dan Talayco551befa2010-07-15 17:05:32 -0700802
Ed Swierk99a74de2012-08-22 06:40:54 -0700803def flow_match_test_port_pair(parent, ing_port, egr_ports, wildcards=None,
Rich Laned0478ff2013-03-11 12:46:58 -0700804 vlan_vid=-1, pkt=None, exp_pkt=None,
Rich Lanee5779d32012-10-05 17:56:04 -0700805 action_list=None):
Dan Talayco551befa2010-07-15 17:05:32 -0700806 """
807 Flow match test on single TCP packet
Dan Talaycof6e76c02012-03-23 10:56:12 -0700808 @param egr_ports A single port or list of ports
Dan Talayco551befa2010-07-15 17:05:32 -0700809
810 Run test with packet through switch from ing_port to egr_port
811 See flow_match_test for parameter descriptions
812 """
813
Ed Swierk99a74de2012-08-22 06:40:54 -0700814 if wildcards is None:
815 wildcards = required_wildcards(parent)
Rich Lane9a003812012-10-04 17:17:59 -0700816 logging.info("Pkt match test: " + str(ing_port) + " to " +
Dan Talaycof6e76c02012-03-23 10:56:12 -0700817 str(egr_ports))
Rich Laned0478ff2013-03-11 12:46:58 -0700818 logging.debug(" WC: " + hex(wildcards) + " vlan: " + str(vlan_vid))
Dan Talayco551befa2010-07-15 17:05:32 -0700819 if pkt is None:
Rich Laned0478ff2013-03-11 12:46:58 -0700820 pkt = simple_tcp_packet(dl_vlan_enable=(vlan_vid >= 0), vlan_vid=vlan_vid)
Rich Lanec41fbec2013-10-02 00:27:59 -0700821 if exp_pkt is None:
822 exp_pkt = pkt
Dan Talayco551befa2010-07-15 17:05:32 -0700823
824 request = flow_msg_create(parent, pkt, ing_port=ing_port,
Dan Talaycof6e76c02012-03-23 10:56:12 -0700825 wildcards=wildcards, egr_ports=egr_ports,
Dan Talayco551befa2010-07-15 17:05:32 -0700826 action_list=action_list)
827
828 flow_msg_install(parent, request)
829
Rich Lane9a003812012-10-04 17:17:59 -0700830 logging.debug("Send packet: " + str(ing_port) + " to " +
Dan Talaycof6e76c02012-03-23 10:56:12 -0700831 str(egr_ports))
Dan Talayco551befa2010-07-15 17:05:32 -0700832 parent.dataplane.send(ing_port, str(pkt))
833
Rich Lane8f45e2d2013-10-01 16:06:54 -0700834 exp_ports = [ing_port if port == ofp.OFPP_IN_PORT else port for port in egr_ports]
Rich Lanee4b384d2013-09-13 14:33:40 -0700835 verify_packets(parent, exp_pkt, exp_ports)
Dan Talayco551befa2010-07-15 17:05:32 -0700836
Rich Lane89725bb2012-12-03 16:23:27 -0800837def flow_match_test_pktout(parent, ing_port, egr_ports,
Rich Laned0478ff2013-03-11 12:46:58 -0700838 vlan_vid=-1, pkt=None, exp_pkt=None,
Rich Lane89725bb2012-12-03 16:23:27 -0800839 action_list=None):
840 """
841 Packet-out test on single TCP packet
842 @param egr_ports A single port or list of ports
843
844 Run test sending packet-out to egr_ports. The goal is to test the actions
845 taken on the packet, not the matching which is of course irrelevant.
846 See flow_match_test for parameter descriptions
847 """
848
849 if pkt is None:
Rich Laned0478ff2013-03-11 12:46:58 -0700850 pkt = simple_tcp_packet(dl_vlan_enable=(vlan_vid >= 0), vlan_vid=vlan_vid)
Rich Lanec41fbec2013-10-02 00:27:59 -0700851 if exp_pkt is None:
852 exp_pkt = pkt
Rich Lane89725bb2012-12-03 16:23:27 -0800853
Rich Lanee717c6e2013-03-12 10:25:50 -0700854 msg = ofp.message.packet_out()
Rich Lane89725bb2012-12-03 16:23:27 -0800855 msg.in_port = ing_port
Rich Laneea8c4722013-04-04 15:30:20 -0700856 msg.buffer_id = 0xffffffff
Rich Lane89725bb2012-12-03 16:23:27 -0800857 msg.data = str(pkt)
858 if action_list is not None:
859 for act in action_list:
Rich Lanec495d9e2013-03-08 17:43:36 -0800860 msg.actions.append(act)
Rich Lane89725bb2012-12-03 16:23:27 -0800861
862 # Set up output action
863 if egr_ports is not None:
864 for egr_port in egr_ports:
Rich Lanee717c6e2013-03-12 10:25:50 -0700865 act = ofp.action.output()
Rich Lane89725bb2012-12-03 16:23:27 -0800866 act.port = egr_port
Rich Lanec495d9e2013-03-08 17:43:36 -0800867 msg.actions.append(act)
Rich Lane89725bb2012-12-03 16:23:27 -0800868
869 logging.debug(msg.show())
Rich Lane5c3151c2013-01-03 17:15:41 -0800870 parent.controller.message_send(msg)
Rich Lane89725bb2012-12-03 16:23:27 -0800871
Rich Lane8f45e2d2013-10-01 16:06:54 -0700872 exp_ports = [ing_port if port == ofp.OFPP_IN_PORT else port for port in egr_ports]
Rich Lanee4b384d2013-09-13 14:33:40 -0700873 verify_packets(parent, exp_pkt, exp_ports)
Rich Lane89725bb2012-12-03 16:23:27 -0800874
Dan Talaycof6e76c02012-03-23 10:56:12 -0700875def get_egr_list(parent, of_ports, how_many, exclude_list=[]):
876 """
877 Generate a list of ports avoiding those in the exclude list
Rich Lane9a003812012-10-04 17:17:59 -0700878 @param parent Supplies logging
Dan Talaycof6e76c02012-03-23 10:56:12 -0700879 @param of_ports List of OF port numbers
880 @param how_many Number of ports to be added to the list
881 @param exclude_list List of ports not to be used
882 @returns An empty list if unable to find enough ports
883 """
884
Dan Talaycoc948d0b2012-03-23 12:17:54 -0700885 if how_many == 0:
886 return []
887
Dan Talaycof6e76c02012-03-23 10:56:12 -0700888 count = 0
889 egr_ports = []
890 for egr_idx in range(len(of_ports)):
891 if of_ports[egr_idx] not in exclude_list:
892 egr_ports.append(of_ports[egr_idx])
893 count += 1
894 if count >= how_many:
895 return egr_ports
Rich Lane9a003812012-10-04 17:17:59 -0700896 logging.debug("Could not generate enough egress ports for test")
Dan Talaycof6e76c02012-03-23 10:56:12 -0700897 return []
898
Rich Laned0478ff2013-03-11 12:46:58 -0700899def flow_match_test(parent, port_map, wildcards=None, vlan_vid=-1, pkt=None,
Rich Lanee5779d32012-10-05 17:56:04 -0700900 exp_pkt=None, action_list=None,
Dan Talaycoc948d0b2012-03-23 12:17:54 -0700901 max_test=0, egr_count=1, ing_port=False):
Dan Talayco551befa2010-07-15 17:05:32 -0700902 """
Rich Lane89725bb2012-12-03 16:23:27 -0800903 Run flow_match_test_port_pair on all port pairs and packet-out
Dan Talayco551befa2010-07-15 17:05:32 -0700904
905 @param max_test If > 0 no more than this number of tests are executed.
906 @param parent Must implement controller, dataplane, assertTrue, assertEqual
Rich Lane9a003812012-10-04 17:17:59 -0700907 and logging
Dan Talayco551befa2010-07-15 17:05:32 -0700908 @param pkt If not None, use this packet for ingress
909 @param wildcards For flow match entry
Rich Laned0478ff2013-03-11 12:46:58 -0700910 @param vlan_vid If not -1, and pkt is None, create a pkt w/ VLAN tag
Dan Talayco551befa2010-07-15 17:05:32 -0700911 @param exp_pkt If not None, use this as the expected output pkt; els use pkt
912 @param action_list Additional actions to add to flow mod
Dan Talaycocfa172f2012-03-23 12:03:00 -0700913 @param egr_count Number of egress ports; -1 means get from config w/ dflt 2
Dan Talayco551befa2010-07-15 17:05:32 -0700914 """
Ed Swierk99a74de2012-08-22 06:40:54 -0700915 if wildcards is None:
916 wildcards = required_wildcards(parent)
Dan Talayco551befa2010-07-15 17:05:32 -0700917 of_ports = port_map.keys()
918 of_ports.sort()
919 parent.assertTrue(len(of_ports) > 1, "Not enough ports for test")
920 test_count = 0
921
Dan Talaycocfa172f2012-03-23 12:03:00 -0700922 if egr_count == -1:
Rich Lane2014f9b2012-10-05 15:29:40 -0700923 egr_count = test_param_get('egr_count', default=2)
Dan Talaycocfa172f2012-03-23 12:03:00 -0700924
Dan Talayco551befa2010-07-15 17:05:32 -0700925 for ing_idx in range(len(of_ports)):
926 ingress_port = of_ports[ing_idx]
Dan Talaycof6e76c02012-03-23 10:56:12 -0700927 egr_ports = get_egr_list(parent, of_ports, egr_count,
928 exclude_list=[ingress_port])
Dan Talaycoc948d0b2012-03-23 12:17:54 -0700929 if ing_port:
Rich Lanee717c6e2013-03-12 10:25:50 -0700930 egr_ports.append(ofp.OFPP_IN_PORT)
Dan Talaycof6e76c02012-03-23 10:56:12 -0700931 if len(egr_ports) == 0:
932 parent.assertTrue(0, "Failed to generate egress port list")
933
934 flow_match_test_port_pair(parent, ingress_port, egr_ports,
Rich Laned0478ff2013-03-11 12:46:58 -0700935 wildcards=wildcards, vlan_vid=vlan_vid,
Dan Talaycof6e76c02012-03-23 10:56:12 -0700936 pkt=pkt, exp_pkt=exp_pkt,
Rich Lanee5779d32012-10-05 17:56:04 -0700937 action_list=action_list)
Dan Talaycof6e76c02012-03-23 10:56:12 -0700938 test_count += 1
939 if (max_test > 0) and (test_count > max_test):
Rich Lane9a003812012-10-04 17:17:59 -0700940 logging.info("Ran " + str(test_count) + " tests; exiting")
Rich Lane89725bb2012-12-03 16:23:27 -0800941 break
942
Ed Swierk38eea082013-01-02 19:46:20 -0800943 if not test_param_get('pktout_actions', default=True):
944 return
Rich Lane89725bb2012-12-03 16:23:27 -0800945
946 ingress_port = of_ports[0]
947 egr_ports = get_egr_list(parent, of_ports, egr_count,
948 exclude_list=[ingress_port])
949 if ing_port:
Rich Lanee717c6e2013-03-12 10:25:50 -0700950 egr_ports.append(ofp.OFPP_IN_PORT)
Rich Lane89725bb2012-12-03 16:23:27 -0800951 flow_match_test_pktout(parent, ingress_port, egr_ports,
Rich Laned0478ff2013-03-11 12:46:58 -0700952 vlan_vid=vlan_vid,
Rich Lane89725bb2012-12-03 16:23:27 -0800953 pkt=pkt, exp_pkt=exp_pkt,
954 action_list=action_list)
Dan Talayco551befa2010-07-15 17:05:32 -0700955
Rich Lane2014f9b2012-10-05 15:29:40 -0700956def test_param_get(key, default=None):
Dan Talayco4b2bee62010-07-20 14:10:05 -0700957 """
958 Return value passed via test-params if present
959
Dan Talayco4b2bee62010-07-20 14:10:05 -0700960 @param key The lookup key
961 @param default Default value to use if not found
962
963 If the pair 'key=val' appeared in the string passed to --test-params
964 on the command line, return val (as interpreted by exec). Otherwise
965 return default value.
Dan Talaycof6e76c02012-03-23 10:56:12 -0700966
967 WARNING: TEST PARAMETERS MUST BE PYTHON IDENTIFIERS;
968 eg egr_count, not egr-count.
Dan Talayco4b2bee62010-07-20 14:10:05 -0700969 """
970 try:
Rich Lanecd97d3d2013-01-07 18:50:06 -0800971 exec oftest.config["test_params"]
Dan Talayco4b2bee62010-07-20 14:10:05 -0700972 except:
973 return default
974
Dan Talayco4b2bee62010-07-20 14:10:05 -0700975 try:
Rich Lanefdec0fb2013-08-09 18:01:05 -0700976 return eval(str(key))
Dan Talayco4b2bee62010-07-20 14:10:05 -0700977 except:
978 return default
979
980def action_generate(parent, field_to_mod, mod_field_vals):
981 """
982 Create an action to modify the field indicated in field_to_mod
983
984 @param parent Must implement, assertTrue
985 @param field_to_mod The field to modify as a string name
986 @param mod_field_vals Hash of values to use for modified values
987 """
988
989 act = None
990
991 if field_to_mod in ['pktlen']:
992 return None
993
Rich Laned0478ff2013-03-11 12:46:58 -0700994 if field_to_mod == 'eth_dst':
Rich Lanee717c6e2013-03-12 10:25:50 -0700995 act = ofp.action.set_dl_dst()
Rich Lanef6883512013-03-11 17:00:09 -0700996 act.dl_addr = oftest.parse.parse_mac(mod_field_vals['eth_dst'])
Rich Laned0478ff2013-03-11 12:46:58 -0700997 elif field_to_mod == 'eth_src':
Rich Lanee717c6e2013-03-12 10:25:50 -0700998 act = ofp.action.set_dl_src()
Rich Lanef6883512013-03-11 17:00:09 -0700999 act.dl_addr = oftest.parse.parse_mac(mod_field_vals['eth_src'])
Dan Talayco4b2bee62010-07-20 14:10:05 -07001000 elif field_to_mod == 'dl_vlan_enable':
1001 if not mod_field_vals['dl_vlan_enable']: # Strip VLAN tag
Rich Lanee717c6e2013-03-12 10:25:50 -07001002 act = ofp.action.strip_vlan()
Rich Laned0478ff2013-03-11 12:46:58 -07001003 # Add VLAN tag is handled by vlan_vid field
Dan Talayco4b2bee62010-07-20 14:10:05 -07001004 # Will return None in this case
Rich Laned0478ff2013-03-11 12:46:58 -07001005 elif field_to_mod == 'vlan_vid':
Rich Lanee717c6e2013-03-12 10:25:50 -07001006 act = ofp.action.set_vlan_vid()
Rich Laned0478ff2013-03-11 12:46:58 -07001007 act.vlan_vid = mod_field_vals['vlan_vid']
1008 elif field_to_mod == 'vlan_pcp':
Rich Lanee717c6e2013-03-12 10:25:50 -07001009 act = ofp.action.set_vlan_pcp()
Rich Laned0478ff2013-03-11 12:46:58 -07001010 act.vlan_pcp = mod_field_vals['vlan_pcp']
Dan Talayco4b2bee62010-07-20 14:10:05 -07001011 elif field_to_mod == 'ip_src':
Rich Lanee717c6e2013-03-12 10:25:50 -07001012 act = ofp.action.set_nw_src()
Rich Lanef6883512013-03-11 17:00:09 -07001013 act.nw_addr = oftest.parse.parse_ip(mod_field_vals['ip_src'])
Dan Talayco4b2bee62010-07-20 14:10:05 -07001014 elif field_to_mod == 'ip_dst':
Rich Lanee717c6e2013-03-12 10:25:50 -07001015 act = ofp.action.set_nw_dst()
Rich Lanef6883512013-03-11 17:00:09 -07001016 act.nw_addr = oftest.parse.parse_ip(mod_field_vals['ip_dst'])
Dan Talayco4b2bee62010-07-20 14:10:05 -07001017 elif field_to_mod == 'ip_tos':
Rich Lanee717c6e2013-03-12 10:25:50 -07001018 act = ofp.action.set_nw_tos()
Dan Talayco4b2bee62010-07-20 14:10:05 -07001019 act.nw_tos = mod_field_vals['ip_tos']
1020 elif field_to_mod == 'tcp_sport':
Rich Lanee717c6e2013-03-12 10:25:50 -07001021 act = ofp.action.set_tp_src()
Dan Talayco4b2bee62010-07-20 14:10:05 -07001022 act.tp_port = mod_field_vals['tcp_sport']
1023 elif field_to_mod == 'tcp_dport':
Rich Lanee717c6e2013-03-12 10:25:50 -07001024 act = ofp.action.set_tp_dst()
Dan Talayco4b2bee62010-07-20 14:10:05 -07001025 act.tp_port = mod_field_vals['tcp_dport']
Rich Lane110e0e32012-10-26 16:21:46 -07001026 elif field_to_mod == 'udp_sport':
Rich Lanee717c6e2013-03-12 10:25:50 -07001027 act = ofp.action.set_tp_src()
Rich Lane110e0e32012-10-26 16:21:46 -07001028 act.tp_port = mod_field_vals['udp_sport']
1029 elif field_to_mod == 'udp_dport':
Rich Lanee717c6e2013-03-12 10:25:50 -07001030 act = ofp.action.set_tp_dst()
Rich Lane110e0e32012-10-26 16:21:46 -07001031 act.tp_port = mod_field_vals['udp_dport']
Dan Talayco4b2bee62010-07-20 14:10:05 -07001032 else:
1033 parent.assertTrue(0, "Unknown field to modify: " + str(field_to_mod))
1034
1035 return act
1036
1037def pkt_action_setup(parent, start_field_vals={}, mod_field_vals={},
Rich Lane110e0e32012-10-26 16:21:46 -07001038 mod_fields=[], tp="tcp", check_test_params=False):
Dan Talayco4b2bee62010-07-20 14:10:05 -07001039 """
1040 Set up the ingress and expected packet and action list for a test
1041
Rich Lane2014f9b2012-10-05 15:29:40 -07001042 @param parent Must implement assertTrue
Dan Talayco4b2bee62010-07-20 14:10:05 -07001043 @param start_field_values Field values to use for ingress packet (optional)
1044 @param mod_field_values Field values to use for modified packet (optional)
1045 @param mod_fields The list of fields to be modified by the switch in the test.
1046 @params check_test_params If True, will check the parameters vid, add_vlan
1047 and strip_vlan from the command line.
1048
1049 Returns a triple: pkt-to-send, expected-pkt, action-list
1050 """
1051
1052 new_actions = []
1053
Dan Talayco4b2bee62010-07-20 14:10:05 -07001054 base_pkt_params = {}
1055 base_pkt_params['pktlen'] = 100
Rich Laned0478ff2013-03-11 12:46:58 -07001056 base_pkt_params['eth_dst'] = '00:DE:F0:12:34:56'
1057 base_pkt_params['eth_src'] = '00:23:45:67:89:AB'
Dan Talayco4b2bee62010-07-20 14:10:05 -07001058 base_pkt_params['dl_vlan_enable'] = False
Rich Laned0478ff2013-03-11 12:46:58 -07001059 base_pkt_params['vlan_vid'] = 2
1060 base_pkt_params['vlan_pcp'] = 0
Dan Talayco4b2bee62010-07-20 14:10:05 -07001061 base_pkt_params['ip_src'] = '192.168.0.1'
1062 base_pkt_params['ip_dst'] = '192.168.0.2'
1063 base_pkt_params['ip_tos'] = 0
Rich Lane110e0e32012-10-26 16:21:46 -07001064 if tp == "tcp":
1065 base_pkt_params['tcp_sport'] = 1234
1066 base_pkt_params['tcp_dport'] = 80
1067 elif tp == "udp":
1068 base_pkt_params['udp_sport'] = 1234
1069 base_pkt_params['udp_dport'] = 80
Dan Talayco4b2bee62010-07-20 14:10:05 -07001070 for keyname in start_field_vals.keys():
1071 base_pkt_params[keyname] = start_field_vals[keyname]
1072
1073 mod_pkt_params = {}
1074 mod_pkt_params['pktlen'] = 100
Rich Laned0478ff2013-03-11 12:46:58 -07001075 mod_pkt_params['eth_dst'] = '00:21:0F:ED:CB:A9'
1076 mod_pkt_params['eth_src'] = '00:ED:CB:A9:87:65'
Dan Talayco4b2bee62010-07-20 14:10:05 -07001077 mod_pkt_params['dl_vlan_enable'] = False
Rich Laned0478ff2013-03-11 12:46:58 -07001078 mod_pkt_params['vlan_vid'] = 3
1079 mod_pkt_params['vlan_pcp'] = 7
Dan Talayco4b2bee62010-07-20 14:10:05 -07001080 mod_pkt_params['ip_src'] = '10.20.30.40'
1081 mod_pkt_params['ip_dst'] = '50.60.70.80'
1082 mod_pkt_params['ip_tos'] = 0xf0
Rich Lane110e0e32012-10-26 16:21:46 -07001083 if tp == "tcp":
1084 mod_pkt_params['tcp_sport'] = 4321
1085 mod_pkt_params['tcp_dport'] = 8765
1086 elif tp == "udp":
1087 mod_pkt_params['udp_sport'] = 4321
1088 mod_pkt_params['udp_dport'] = 8765
Dan Talayco4b2bee62010-07-20 14:10:05 -07001089 for keyname in mod_field_vals.keys():
1090 mod_pkt_params[keyname] = mod_field_vals[keyname]
1091
1092 # Check for test param modifications
1093 strip = False
1094 if check_test_params:
Rich Lane2014f9b2012-10-05 15:29:40 -07001095 add_vlan = test_param_get('add_vlan')
1096 strip_vlan = test_param_get('strip_vlan')
1097 vid = test_param_get('vid')
Dan Talayco4b2bee62010-07-20 14:10:05 -07001098
1099 if add_vlan and strip_vlan:
1100 parent.assertTrue(0, "Add and strip VLAN both specified")
1101
1102 if vid:
1103 base_pkt_params['dl_vlan_enable'] = True
Rich Laned0478ff2013-03-11 12:46:58 -07001104 base_pkt_params['vlan_vid'] = vid
1105 if 'vlan_vid' in mod_fields:
1106 mod_pkt_params['vlan_vid'] = vid + 1
Dan Talayco4b2bee62010-07-20 14:10:05 -07001107
1108 if add_vlan:
1109 base_pkt_params['dl_vlan_enable'] = False
1110 mod_pkt_params['dl_vlan_enable'] = True
1111 mod_pkt_params['pktlen'] = base_pkt_params['pktlen'] + 4
1112 mod_fields.append('pktlen')
1113 mod_fields.append('dl_vlan_enable')
Rich Laned0478ff2013-03-11 12:46:58 -07001114 if 'vlan_vid' not in mod_fields:
1115 mod_fields.append('vlan_vid')
Dan Talayco4b2bee62010-07-20 14:10:05 -07001116 elif strip_vlan:
1117 base_pkt_params['dl_vlan_enable'] = True
1118 mod_pkt_params['dl_vlan_enable'] = False
1119 mod_pkt_params['pktlen'] = base_pkt_params['pktlen'] - 4
1120 mod_fields.append('dl_vlan_enable')
1121 mod_fields.append('pktlen')
1122
Rich Lane110e0e32012-10-26 16:21:46 -07001123 if tp == "tcp":
1124 packet_builder = simple_tcp_packet
1125 elif tp == "udp":
1126 packet_builder = simple_udp_packet
1127 else:
1128 raise NotImplementedError("unknown transport protocol %s" % tp)
1129
Dan Talayco4b2bee62010-07-20 14:10:05 -07001130 # Build the ingress packet
Rich Lane110e0e32012-10-26 16:21:46 -07001131 ingress_pkt = packet_builder(**base_pkt_params)
Dan Talayco4b2bee62010-07-20 14:10:05 -07001132
1133 # Build the expected packet, modifying the indicated fields
1134 for item in mod_fields:
1135 base_pkt_params[item] = mod_pkt_params[item]
1136 act = action_generate(parent, item, mod_pkt_params)
1137 if act:
1138 new_actions.append(act)
1139
Rich Lane110e0e32012-10-26 16:21:46 -07001140 expected_pkt = packet_builder(**base_pkt_params)
Dan Talayco4b2bee62010-07-20 14:10:05 -07001141
1142 return (ingress_pkt, expected_pkt, new_actions)
Dan Talayco677c0b72011-08-23 22:53:38 -07001143
1144# Generate a simple "drop" flow mod
1145# If in_band is true, then only drop from first test port
1146def flow_mod_gen(port_map, in_band):
Rich Lanee717c6e2013-03-12 10:25:50 -07001147 request = ofp.message.flow_add()
1148 request.match.wildcards = ofp.OFPFW_ALL
Dan Talayco677c0b72011-08-23 22:53:38 -07001149 if in_band:
Rich Lanee717c6e2013-03-12 10:25:50 -07001150 request.match.wildcards = ofp.OFPFW_ALL - ofp.OFPFW_IN_PORT
Dan Talayco677c0b72011-08-23 22:53:38 -07001151 for of_port, ifname in port_map.items(): # Grab first port
1152 break
1153 request.match.in_port = of_port
1154 request.buffer_id = 0xffffffff
1155 return request
Dan Talaycoba3745c2010-07-21 21:51:08 -07001156
1157def skip_message_emit(parent, s):
1158 """
1159 Print out a 'skipped' message to stderr
1160
1161 @param s The string to print out to the log file
Dan Talaycoba3745c2010-07-21 21:51:08 -07001162 """
1163 global skipped_test_count
1164
1165 skipped_test_count += 1
Rich Lane9a003812012-10-04 17:17:59 -07001166 logging.info("Skipping: " + s)
Dan Talayco2940fdd2013-02-06 15:01:35 -08001167 if oftest.config["debug"] < logging.WARNING:
Dan Talaycoba3745c2010-07-21 21:51:08 -07001168 sys.stderr.write("(skipped) ")
1169 else:
1170 sys.stderr.write("(S)")
Dan Talayco677c0b72011-08-23 22:53:38 -07001171
Dan Talayco8a64e332012-03-28 14:53:20 -07001172
1173def all_stats_get(parent):
1174 """
1175 Get the aggregate stats for all flows in the table
1176 @param parent Test instance with controller connection and assert
1177 @returns dict with keys flows, packets, bytes, active (flows),
1178 lookups, matched
1179 """
Rich Lanee717c6e2013-03-12 10:25:50 -07001180 stat_req = ofp.message.aggregate_stats_request()
1181 stat_req.match = ofp.match()
1182 stat_req.match.wildcards = ofp.OFPFW_ALL
Dan Talayco8a64e332012-03-28 14:53:20 -07001183 stat_req.table_id = 0xff
Rich Lanee717c6e2013-03-12 10:25:50 -07001184 stat_req.out_port = ofp.OFPP_NONE
Dan Talayco8a64e332012-03-28 14:53:20 -07001185
1186 rv = {}
1187
Rich Lanec8aaa3e2012-07-26 19:28:02 -07001188 (reply, pkt) = parent.controller.transact(stat_req)
Rich Lane5fd6faf2013-03-11 13:30:20 -07001189 parent.assertTrue(len(reply.entries) == 1, "Did not receive flow stats reply")
Dan Talayco8a64e332012-03-28 14:53:20 -07001190
Rich Lane5fd6faf2013-03-11 13:30:20 -07001191 for obj in reply.entries:
Dan Talayco8a64e332012-03-28 14:53:20 -07001192 (rv["flows"], rv["packets"], rv["bytes"]) = (obj.flow_count,
1193 obj.packet_count, obj.byte_count)
1194 break
1195
Rich Lanee717c6e2013-03-12 10:25:50 -07001196 request = ofp.message.table_stats_request()
Rich Lanec8aaa3e2012-07-26 19:28:02 -07001197 (reply , pkt) = parent.controller.transact(request)
Dan Talayco8a64e332012-03-28 14:53:20 -07001198
1199
1200 (rv["active"], rv["lookups"], rv["matched"]) = (0,0,0)
Rich Lane5fd6faf2013-03-11 13:30:20 -07001201 for obj in reply.entries:
Dan Talayco8a64e332012-03-28 14:53:20 -07001202 rv["active"] += obj.active_count
1203 rv["lookups"] += obj.lookup_count
1204 rv["matched"] += obj.matched_count
1205
1206 return rv
Dan Talayco2baf8b52012-03-30 09:55:42 -07001207
Rich Lane7744e112013-01-11 17:23:57 -08001208_import_blacklist.add('FILTER')
Dan Talayco2baf8b52012-03-30 09:55:42 -07001209FILTER=''.join([(len(repr(chr(x)))==3) and chr(x) or '.'
1210 for x in range(256)])
1211
1212def hex_dump_buffer(src, length=16):
1213 """
1214 Convert src to a hex dump string and return the string
1215 @param src The source buffer
1216 @param length The number of bytes shown in each line
1217 @returns A string showing the hex dump
1218 """
Dan Talaycoc516fa02012-04-12 22:28:43 -07001219 result = ["\n"]
Dan Talayco2baf8b52012-03-30 09:55:42 -07001220 for i in xrange(0, len(src), length):
1221 chars = src[i:i+length]
1222 hex = ' '.join(["%02x" % ord(x) for x in chars])
1223 printable = ''.join(["%s" % ((ord(x) <= 127 and
1224 FILTER[ord(x)]) or '.') for x in chars])
1225 result.append("%04x %-*s %s\n" % (i, length*3, hex, printable))
1226 return ''.join(result)
1227
1228def format_packet(pkt):
1229 return "Packet length %d \n%s" % (len(str(pkt)),
1230 hex_dump_buffer(str(pkt)))
Rich Lane5d7e89a2012-10-26 16:43:13 -07001231
1232def inspect_packet(pkt):
1233 """
1234 Wrapper around scapy's show() method.
1235 @returns A string showing the dissected packet.
1236 """
1237 from cStringIO import StringIO
1238 out = None
1239 backup = sys.stdout
1240 try:
Rich Lanefdec0fb2013-08-09 18:01:05 -07001241 tmp = StringIO()
1242 sys.stdout = tmp
Rich Lane5d7e89a2012-10-26 16:43:13 -07001243 pkt.show2()
Rich Lanefdec0fb2013-08-09 18:01:05 -07001244 out = tmp.getvalue()
1245 tmp.close()
Rich Lane5d7e89a2012-10-26 16:43:13 -07001246 finally:
1247 sys.stdout = backup
1248 return out
Rich Lane0a4f6372013-01-02 14:40:22 -08001249
1250def nonstandard(cls):
1251 """
Rich Lanecc45b8e2013-01-02 15:55:02 -08001252 Testcase decorator that marks the test as being non-standard.
1253 These tests are not automatically added to the "standard" group.
Rich Lane0a4f6372013-01-02 14:40:22 -08001254 """
Rich Lanecc45b8e2013-01-02 15:55:02 -08001255 cls._nonstandard = True
Rich Lane0a4f6372013-01-02 14:40:22 -08001256 return cls
1257
1258def disabled(cls):
1259 """
Rich Lanecc45b8e2013-01-02 15:55:02 -08001260 Testcase decorator that marks the test as being disabled.
1261 These tests are not automatically added to the "standard" group or
1262 their module's group.
Rich Lane0a4f6372013-01-02 14:40:22 -08001263 """
Rich Lanecc45b8e2013-01-02 15:55:02 -08001264 cls._disabled = True
Rich Lane0a4f6372013-01-02 14:40:22 -08001265 return cls
Rich Lane97e99652013-01-02 17:23:20 -08001266
1267def group(name):
1268 """
1269 Testcase decorator that adds the test to a group.
1270 """
1271 def fn(cls):
1272 if not hasattr(cls, "_groups"):
1273 cls._groups = []
1274 cls._groups.append(name)
1275 return cls
1276 return fn
Rich Lane5a9a1922013-01-11 14:29:30 -08001277
1278def version(ver):
1279 """
1280 Testcase decorator that specifies which versions of OpenFlow the test
1281 supports. The default is 1.0+. This decorator may only be used once.
1282
1283 Supported syntax:
1284 1.0 -> 1.0
1285 1.0,1.2,1.3 -> 1.0, 1.2, 1.3
1286 1.0+ -> 1.0, 1.1, 1.2, 1.3
1287 """
1288 versions = parse_version(ver)
1289 def fn(cls):
1290 cls._versions = versions
1291 return cls
1292 return fn
1293
1294def parse_version(ver):
1295 allowed_versions = ["1.0", "1.1", "1.2", "1.3"]
1296 if re.match("^1\.\d+$", ver):
1297 versions = set([ver])
1298 elif re.match("^(1\.\d+)\+$", ver):
1299 if not ver[:-1] in allowed_versions:
1300 raise ValueError("invalid OpenFlow version %s" % ver[:-1])
1301 versions = set()
1302 if ver != "1.1+": versions.add("1.0")
1303 if ver != "1.2+": versions.add("1.1")
1304 if ver != "1.3+": versions.add("1.2")
1305 versions.add("1.3")
1306 else:
1307 versions = set(ver.split(','))
1308
1309 for version in versions:
1310 if not version in allowed_versions:
1311 raise ValueError("invalid OpenFlow version %s" % version)
1312
1313 return versions
1314
1315assert(parse_version("1.0") == set(["1.0"]))
1316assert(parse_version("1.0,1.2,1.3") == set(["1.0", "1.2", "1.3"]))
1317assert(parse_version("1.0+") == set(["1.0", "1.1", "1.2", "1.3"]))
Rich Lane7744e112013-01-11 17:23:57 -08001318
Rich Laneae3428c2013-03-07 14:37:42 -08001319def get_stats(test, req):
1320 """
1321 Retrieve a list of stats entries. Handles OFPSF_REPLY_MORE.
1322 """
Rich Lane609194f2013-10-21 06:17:37 -07001323 msgtype = ofp.OFPT_STATS_REPLY
1324 more_flag = ofp.OFPSF_REPLY_MORE
Rich Laneae3428c2013-03-07 14:37:42 -08001325 stats = []
1326 reply, _ = test.controller.transact(req)
1327 test.assertTrue(reply is not None, "No response to stats request")
Rich Lane34c68d52013-10-11 10:38:21 -07001328 test.assertEquals(reply.type, msgtype, "Response had unexpected message type")
Rich Lane5fd6faf2013-03-11 13:30:20 -07001329 stats.extend(reply.entries)
Rich Lanebd56ed62013-07-10 15:49:44 -07001330 while reply.flags & more_flag != 0:
Rich Lane34c68d52013-10-11 10:38:21 -07001331 reply, pkt = test.controller.poll(exp_msg=msgtype)
Rich Laneae3428c2013-03-07 14:37:42 -08001332 test.assertTrue(reply is not None, "No response to stats request")
Rich Lane5fd6faf2013-03-11 13:30:20 -07001333 stats.extend(reply.entries)
Rich Laneae3428c2013-03-07 14:37:42 -08001334 return stats
1335
Rich Lanebd56ed62013-07-10 15:49:44 -07001336def get_flow_stats(test, match, table_id=None,
1337 out_port=None, out_group=None,
1338 cookie=0, cookie_mask=0):
Rich Laneae3428c2013-03-07 14:37:42 -08001339 """
1340 Retrieve a list of flow stats entries.
1341 """
Rich Lanebd56ed62013-07-10 15:49:44 -07001342
1343 if table_id == None:
1344 if ofp.OFP_VERSION <= 2:
1345 table_id = 0xff
1346 else:
1347 table_id = ofp.OFPTT_ALL
1348
Rich Lanef3bc48c2013-05-03 17:39:35 -07001349 if out_port == None:
Rich Lanebd56ed62013-07-10 15:49:44 -07001350 if ofp.OFP_VERSION == 1:
1351 out_port = ofp.OFPP_NONE
1352 else:
1353 out_port = ofp.OFPP_ANY
1354
1355 if out_group == None:
1356 if ofp.OFP_VERSION > 1:
1357 out_group = ofp.OFPP_ANY
1358
Rich Lanee717c6e2013-03-12 10:25:50 -07001359 req = ofp.message.flow_stats_request(match=match,
Rich Lanebd56ed62013-07-10 15:49:44 -07001360 table_id=table_id,
1361 out_port=out_port)
1362 if ofp.OFP_VERSION > 1:
1363 req.out_group = out_group
1364 req.cookie = cookie
1365 req.cookie_mask = cookie_mask
1366
Rich Laneae3428c2013-03-07 14:37:42 -08001367 return get_stats(test, req)
1368
Rich Lane968b6192013-03-07 15:34:43 -08001369def get_port_stats(test, port_no):
1370 """
1371 Retrieve a list of port stats entries.
1372 """
Rich Lanee717c6e2013-03-12 10:25:50 -07001373 req = ofp.message.port_stats_request(port_no=port_no)
Rich Lane968b6192013-03-07 15:34:43 -08001374 return get_stats(test, req)
1375
Rich Lane6a334922013-03-07 16:14:52 -08001376def get_queue_stats(test, port_no, queue_id):
1377 """
1378 Retrieve a list of queue stats entries.
1379 """
Rich Lanee717c6e2013-03-12 10:25:50 -07001380 req = ofp.message.queue_stats_request(port_no=port_no, queue_id=queue_id)
Rich Lane6a334922013-03-07 16:14:52 -08001381 return get_stats(test, req)
1382
Rich Laneae3428c2013-03-07 14:37:42 -08001383def verify_flow_stats(test, match, table_id=0xff,
Rich Laneae3428c2013-03-07 14:37:42 -08001384 initial=[],
1385 pkts=None, bytes=None):
1386 """
1387 Verify that flow stats changed as expected.
1388
1389 Optionally takes an 'initial' list of stats entries, as returned by
1390 get_flow_stats(). If 'initial' is not given the counters are assumed to
1391 begin at 0.
1392 """
Rich Lanef3bc48c2013-05-03 17:39:35 -07001393
Rich Laneae3428c2013-03-07 14:37:42 -08001394 def accumulate(stats):
1395 pkts_acc = bytes_acc = 0
1396 for stat in stats:
1397 pkts_acc += stat.packet_count
1398 bytes_acc += stat.byte_count
1399 return (pkts_acc, bytes_acc)
1400
1401 pkts_before, bytes_before = accumulate(initial)
1402
1403 # Wait 10s for counters to update
1404 pkt_diff = byte_diff = None
1405 for i in range(0, 100):
Rich Lane61edad52014-03-28 16:25:08 -07001406 stats = get_flow_stats(test, match, table_id=table_id)
Rich Laneae3428c2013-03-07 14:37:42 -08001407 pkts_after, bytes_after = accumulate(stats)
1408 pkt_diff = pkts_after - pkts_before
1409 byte_diff = bytes_after - bytes_before
1410 if (pkts == None or pkt_diff >= pkts) and \
1411 (bytes == None or byte_diff >= bytes):
1412 break
Dan Talayco53724732013-03-08 23:54:02 -08001413 time.sleep(0.1)
Rich Laneae3428c2013-03-07 14:37:42 -08001414
1415 if pkts != None:
1416 test.assertEquals(pkt_diff, pkts, "Flow packet counter not updated properly (expected increase of %d, got increase of %d)" % (pkts, pkt_diff))
1417
1418 if bytes != None:
Rich Lane53b96812013-03-07 16:54:50 -08001419 test.assertTrue(byte_diff >= bytes and byte_diff <= bytes*1.1,
1420 "Flow byte counter not updated properly (expected increase of %d, got increase of %d)" % (bytes, byte_diff))
Rich Laneae3428c2013-03-07 14:37:42 -08001421
Rich Lane968b6192013-03-07 15:34:43 -08001422def verify_port_stats(test, port,
1423 initial=[],
1424 tx_pkts=None, rx_pkts=None,
1425 tx_bytes=None, rx_bytes=None):
1426 """
1427 Verify that port stats changed as expected.
1428
1429 Optionally takes an 'initial' list of stats entries, as returned by
1430 get_port_stats(). If 'initial' is not given the counters are assumed to
1431 begin at 0.
1432 """
1433 def accumulate(stats):
1434 tx_pkts_acc = rx_pkts_acc = tx_bytes_acc = rx_bytes_acc = 0
1435 for stat in stats:
1436 tx_pkts_acc += stat.tx_packets
1437 rx_pkts_acc += stat.rx_packets
1438 tx_bytes_acc += stat.tx_bytes
1439 rx_bytes_acc += stat.rx_bytes
1440 return (tx_pkts_acc, rx_pkts_acc, tx_bytes_acc, rx_bytes_acc)
1441
1442 tx_pkts_before, rx_pkts_before, \
1443 tx_bytes_before, rx_bytes_before = accumulate(initial)
1444
1445 # Wait 10s for counters to update
1446 for i in range(0, 100):
1447 stats = get_port_stats(test, port)
1448 tx_pkts_after, rx_pkts_after, \
1449 tx_bytes_after, rx_bytes_after = accumulate(stats)
1450 tx_pkts_diff = tx_pkts_after - tx_pkts_before
1451 rx_pkts_diff = rx_pkts_after - rx_pkts_before
1452 tx_bytes_diff = tx_bytes_after - tx_bytes_before
1453 rx_bytes_diff = rx_bytes_after - rx_bytes_before
1454 if (tx_pkts == None or tx_pkts == tx_pkts_diff) and \
1455 (rx_pkts == None or rx_pkts == rx_pkts_diff) and \
Rich Lane53b96812013-03-07 16:54:50 -08001456 (tx_bytes == None or tx_bytes <= tx_bytes_diff) and \
1457 (rx_bytes == None or rx_bytes <= rx_bytes_diff):
Rich Lane968b6192013-03-07 15:34:43 -08001458 break
1459 time.sleep(0.1)
1460
1461 if (tx_pkts != None):
1462 test.assertEqual(tx_pkts,tx_pkts_diff,"Port TX packet counter is not updated correctly (expected increase of %d, got increase of %d)" % (tx_pkts, tx_pkts_diff))
1463 if (rx_pkts != None):
1464 test.assertEqual(rx_pkts,rx_pkts_diff,"Port RX packet counter is not updated correctly (expected increase of %d, got increase of %d)" % (rx_pkts, rx_pkts_diff))
1465 if (tx_bytes != None):
Rich Lane53b96812013-03-07 16:54:50 -08001466 test.assertTrue(tx_bytes_diff >= tx_bytes and tx_bytes_diff <= tx_bytes*1.1,
1467 "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 -08001468 if (rx_bytes != None):
Rich Lane53b96812013-03-07 16:54:50 -08001469 test.assertTrue(rx_bytes_diff >= rx_bytes and rx_bytes_diff <= rx_bytes*1.1,
1470 "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 -08001471
Rich Lane6a334922013-03-07 16:14:52 -08001472def verify_queue_stats(test, port_no, queue_id,
1473 initial=[],
1474 pkts=None, bytes=None):
1475 """
1476 Verify that queue stats changed as expected.
1477
1478 Optionally takes an 'initial' list of stats entries, as returned by
1479 get_queue_stats(). If 'initial' is not given the counters are assumed to
1480 begin at 0.
1481 """
1482 def accumulate(stats):
1483 pkts_acc = bytes_acc = 0
1484 for stat in stats:
1485 pkts_acc += stat.tx_packets
1486 bytes_acc += stat.tx_bytes
1487 return (pkts_acc, bytes_acc)
1488
1489 pkts_before, bytes_before = accumulate(initial)
1490
1491 # Wait 10s for counters to update
1492 pkt_diff = byte_diff = None
1493 for i in range(0, 100):
1494 stats = get_queue_stats(test, port_no, queue_id)
1495 pkts_after, bytes_after = accumulate(stats)
1496 pkt_diff = pkts_after - pkts_before
1497 byte_diff = bytes_after - bytes_before
1498 if (pkts == None or pkt_diff >= pkts) and \
1499 (bytes == None or byte_diff >= bytes):
1500 break
Dan Talayco53724732013-03-08 23:54:02 -08001501 time.sleep(0.1)
Rich Lane6a334922013-03-07 16:14:52 -08001502
1503 if pkts != None:
1504 test.assertEquals(pkt_diff, pkts, "Queue packet counter not updated properly (expected increase of %d, got increase of %d)" % (pkts, pkt_diff))
1505
1506 if bytes != None:
Rich Lane53b96812013-03-07 16:54:50 -08001507 test.assertTrue(byte_diff >= bytes and byte_diff <= bytes*1.1,
1508 "Queue byte counter not updated properly (expected increase of %d, got increase of %d)" % (bytes, byte_diff))
Rich Laneae3428c2013-03-07 14:37:42 -08001509
Rich Lane4c504f32013-06-07 17:24:14 -07001510def packet_in_match(msg, data, in_port=None, reason=None):
1511 """
1512 Check whether the packet_in message 'msg' has fields matching 'data',
1513 'in_port', and 'reason'.
1514
1515 This function handles truncated packet_in data. The 'in_port' and 'reason'
1516 parameters are optional.
1517
1518 @param msg packet_in message
1519 @param data Expected packet_in data
1520 @param in_port Expected packet_in in_port, or None
1521 @param reason Expected packet_in reason, or None
1522 """
1523
Rich Lanec0d26dd2013-07-10 12:46:03 -07001524 if ofp.OFP_VERSION <= 2:
1525 pkt_in_port = msg.in_port
1526 else:
1527 oxms = { type(oxm): oxm for oxm in msg.match.oxm_list }
1528 if ofp.oxm.in_port in oxms:
1529 pkt_in_port = oxms[ofp.oxm.in_port].value
1530 else:
1531 logging.warn("Missing in_port in packet-in message")
1532 pkt_in_port = None
1533
1534 if in_port != None and in_port != pkt_in_port:
Rich Lane9f2f17e2013-09-13 13:19:37 -07001535 logging.debug("Incorrect packet_in in_port (expected %d, received %d)", in_port, pkt_in_port)
Rich Lane4c504f32013-06-07 17:24:14 -07001536 return False
1537
Rich Lanec0d26dd2013-07-10 12:46:03 -07001538 if reason != None and reason != msg.reason:
Rich Lane4c504f32013-06-07 17:24:14 -07001539 logging.debug("Incorrect packet_in reason (expected %d, received %d)", reason, msg.reason)
1540 return False
1541
1542 # Check that one of the packets is a prefix of the other.
1543 # The received packet may be either truncated or padded, but not both.
1544 # (Some of the padding may be truncated but that's irrelevant). We
1545 # need to check that the smaller packet is a prefix of the larger one.
1546 # Note that this check succeeds if the switch sends a zero-length
1547 # packet-in.
1548 compare_len = min(len(msg.data), len(data))
1549 if data[:compare_len] != msg.data[:compare_len]:
1550 logging.debug("Incorrect packet_in data")
1551 logging.debug("Expected %s" % format_packet(data[:compare_len]))
1552 logging.debug("Received %s" % format_packet(msg.data[:compare_len]))
1553 return False
1554
1555 return True
1556
1557def verify_packet_in(test, data, in_port, reason, controller=None):
1558 """
1559 Assert that the controller receives a packet_in message matching data 'data'
1560 from port 'in_port' with reason 'reason'. Does not trigger the packet_in
1561 itself, that's up to the test case.
1562
1563 @param test Instance of base_tests.SimpleProtocol
1564 @param pkt String to expect as the packet_in data
1565 @param in_port OpenFlow port number to expect as the packet_in in_port
1566 @param reason One of OFPR_* to expect as the packet_in reason
1567 @param controller Controller instance, defaults to test.controller
1568 @returns The received packet-in message
1569 """
1570
1571 if controller == None:
1572 controller = test.controller
1573
1574 end_time = time.time() + oftest.ofutils.default_timeout
1575
1576 while True:
1577 msg, _ = controller.poll(ofp.OFPT_PACKET_IN, end_time - time.time())
1578 if not msg:
1579 # Timeout
1580 break
1581 elif packet_in_match(msg, data, in_port, reason):
1582 # Found a matching message
1583 break
1584
Kiran Poola58c5c042014-05-15 15:11:06 -07001585 test.assertTrue(msg is not None, 'Packet in message not received on port %r' % in_port)
Rich Lane4c504f32013-06-07 17:24:14 -07001586 return msg
1587
1588def verify_no_packet_in(test, data, in_port, controller=None):
1589 """
1590 Assert that the controller does not receive a packet_in message matching
1591 data 'data' from port 'in_port'.
1592
1593 @param test Instance of base_tests.SimpleProtocol
1594 @param pkt String to expect as the packet_in data
1595 @param in_port OpenFlow port number to expect as the packet_in in_port
1596 @param controller Controller instance, defaults to test.controller
1597 """
1598
1599 if controller == None:
1600 controller = test.controller
1601
1602 # Negative test, need to wait a short amount of time before checking we
1603 # didn't receive the message.
Rich Lane48f6aed2014-03-23 15:51:02 -07001604 time.sleep(oftest.ofutils.default_negative_timeout)
Rich Lane4c504f32013-06-07 17:24:14 -07001605
1606 # Check every packet_in queued in the controller
1607 while True:
1608 msg, _ = controller.poll(ofp.OFPT_PACKET_IN, timeout=0)
1609 if msg == None:
1610 # No more queued packet_in messages
1611 break
1612 elif packet_in_match(msg, data, in_port, None):
1613 # Found a matching message
1614 break
1615
Rich Lane82c882d2013-08-09 17:13:52 -07001616 if in_port == None:
1617 test.assertTrue(msg == None, "Did not expect a packet-in message on any port")
1618 else:
1619 test.assertTrue(msg == None, "Did not expect a packet-in message on port %d" % in_port)
Rich Lane4c504f32013-06-07 17:24:14 -07001620
Rich Lane045db072013-08-06 13:16:30 -07001621def openflow_ports(num=None):
1622 """
1623 Return a list of 'num' OpenFlow port numbers
1624
1625 If 'num' is None, return all available ports. Otherwise, limit the length
1626 of the result to 'num' and raise an exception if not enough ports are
1627 available.
1628 """
1629 ports = sorted(oftest.config["port_map"].keys())
1630 if num != None and len(ports) < num:
1631 raise Exception("test requires %d ports but only %d are available" % (num, len(ports)))
1632 return ports[:num]
1633
Rich Lanee4b384d2013-09-13 14:33:40 -07001634def verify_packet(test, pkt, ofport):
1635 """
1636 Check that an expected packet is received
1637 """
1638 logging.debug("Checking for pkt on port %r", ofport)
1639 (rcv_port, rcv_pkt, pkt_time) = test.dataplane.poll(port_number=ofport, exp_pkt=str(pkt))
1640 test.assertTrue(rcv_pkt != None, "Did not receive pkt on %r" % ofport)
1641
1642def verify_no_packet(test, pkt, ofport):
1643 """
1644 Check that a particular packet is not received
1645 """
1646 logging.debug("Negative check for pkt on port %r", ofport)
Rich Lane48f6aed2014-03-23 15:51:02 -07001647 (rcv_port, rcv_pkt, pkt_time) = \
1648 test.dataplane.poll(
1649 port_number=ofport, exp_pkt=str(pkt),
1650 timeout=oftest.ofutils.default_negative_timeout)
Rich Lanee4b384d2013-09-13 14:33:40 -07001651 test.assertTrue(rcv_pkt == None, "Received packet on %r" % ofport)
1652
1653def verify_no_other_packets(test):
1654 """
1655 Check that no unexpected packets are received
1656
1657 This is a no-op if the --relax option is in effect.
1658 """
1659 if oftest.config["relax"]:
1660 return
1661 logging.debug("Checking for unexpected packets on all ports")
Rich Lane48f6aed2014-03-23 15:51:02 -07001662 (rcv_port, rcv_pkt, pkt_time) = test.dataplane.poll(timeout=oftest.ofutils.default_negative_timeout)
Rich Lanee4b384d2013-09-13 14:33:40 -07001663 if rcv_pkt != None:
1664 logging.debug("Received unexpected packet on port %r: %s", rcv_port, format_packet(rcv_pkt))
1665 test.assertTrue(rcv_pkt == None, "Unexpected packet on port %r" % rcv_port)
1666
1667def verify_packets(test, pkt, ofports):
1668 """
1669 Check that a packet is received on certain ports
1670
1671 Also verifies that the packet is not received on any other ports, and that no
1672 other packets are received (unless --relax is in effect).
1673
1674 This covers the common and simplest cases for checking dataplane outputs.
1675 For more complex usage, like multiple different packets being output, or
1676 multiple packets on the same port, use the primitive verify_packet,
1677 verify_no_packet, and verify_no_other_packets functions directly.
1678 """
1679 pkt = str(pkt)
1680 for ofport in openflow_ports():
1681 if ofport in ofports:
1682 verify_packet(test, pkt, ofport)
1683 else:
1684 verify_no_packet(test, pkt, ofport)
1685 verify_no_other_packets(test)
1686
Rich Lane12d04592013-10-10 17:21:07 -07001687def verify_no_errors(ctrl):
1688 error, _ = ctrl.poll(ofp.OFPT_ERROR, 0)
1689 if error:
1690 raise AssertionError("unexpected error type=%d code=%d" % (error.err_type, error.code))
Rich Lanee4b384d2013-09-13 14:33:40 -07001691
Jonathan Stoutfcee3142014-01-28 15:46:22 -05001692def verify_capability(test, capability):
1693 """
Jonathan Stout073642d2014-02-04 13:41:48 -05001694 Return True if DUT supports the specified capability.
Jonathan Stoutfcee3142014-01-28 15:46:22 -05001695
1696 @param test Instance of base_tests.SimpleProtocol
1697 @param capability One of ofp_capabilities.
1698 """
1699 logging.info("Verifing that capability code is valid.")
1700 test.assertIn(capability, ofp.const.ofp_capabilities_map,
1701 "Capability code %d does not exist." % capability)
1702 capability_str = ofp.const.ofp_capabilities_map[capability]
1703
1704 logging.info(("Sending features_request to test if capability "
Jonathan Stout97e458a2014-01-28 16:08:04 -05001705 "%s is supported."), capability_str)
Jonathan Stoutfcee3142014-01-28 15:46:22 -05001706 req = ofp.message.features_request()
1707 res, raw = test.controller.transact(req)
1708 test.assertIsNotNone(res, "Did not receive a response from the DUT.")
1709 test.assertEqual(res.type, ofp.OFPT_FEATURES_REPLY,
1710 ("Unexpected packet type %d received in response to "
1711 "OFPT_FEATURES_REQUEST") % res.type)
Jonathan Stout641167f2014-02-04 12:07:10 -05001712 logging.info("Received features_reply.")
Jonathan Stoutfcee3142014-01-28 15:46:22 -05001713
Jonathan Stout641167f2014-02-04 12:07:10 -05001714 if (res.capabilities & capability) > 0:
1715 logging.info("Switch capabilities bitmask claims to support %s",
1716 capability_str)
1717 return True, res.capabilities
1718 else:
1719 logging.info("Capabilities bitmask does not support %s.",
1720 capability_str)
1721 return False, res.capabilities
Jonathan Stoutfcee3142014-01-28 15:46:22 -05001722
Jonathan Stouteb3721d2014-02-04 13:59:12 -05001723def verify_configuration_flag(test, flag):
1724 """
1725 Return True if DUT supports specified configuration flag.
1726
1727 @param test Instance of base_tests.SimpleProtocol
1728 @param flag One of ofp_config_flags.
Jonathan Stout1ec8c0f2014-02-04 15:25:38 -05001729 @returns (supported, flags) Bool if flag is set and flag values.
Jonathan Stouteb3721d2014-02-04 13:59:12 -05001730 """
1731 logging.info("Verifing that flag is valid.")
1732 test.assertIn(flag, ofp.const.ofp_config_flags_map,
1733 "flag %s does not exist." % flag)
1734 flag_str = ofp.const.ofp_config_flags_map[flag]
1735
1736 logging.info("Sending OFPT_GET_CONFIG_REQUEST.")
1737 req = ofp.message.get_config_request()
1738 rv = test.controller.message_send(req)
1739 test.assertNotEqual(rv, -1, "Not able to send get_config_request.")
1740
1741 logging.info("Expecting OFPT_GET_CONFIG_REPLY ")
1742 (res, pkt) = test.controller.poll(exp_msg=ofp.OFPT_GET_CONFIG_REPLY,
1743 timeout=2)
1744 test.assertIsNotNone(res, "Did not receive OFPT_GET_CONFIG_REPLY")
1745 logging.info("Received OFPT_GET_CONFIG_REPLY ")
1746
1747 if res.flags == flag:
1748 logging.info("%s flag is set.", flag_str)
1749 return True, res.flags
1750 else:
1751 logging.info("%s flag is not set.", flag_str)
1752 return False, res.flags
1753
Rich Lane7744e112013-01-11 17:23:57 -08001754__all__ = list(set(locals()) - _import_blacklist)