blob: 5dbc0dcc00729f794f16bbbee6fd03da2c8ad4ab [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
macauley_cheng0a0a7f62015-11-06 11:36:50 +080070def simple_packet(content='00 00 00 11 33 55 00 00 00 11 22 33 81 00 00 03 '
71 '08 00 45 00 00 2e 04 d2 00 00 7f 00 b2 47 c0 a8 '
72 '01 64 c0 a8 02 02 00 00 00 00 00 00 00 00 00 00 '
73 '00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00'):
74 data = (content)
75 data_list = data.split(" ")
76 pkt = ''.join(data_list).decode('hex')
77
78 return pkt
79
Dan Talayco41eae8b2010-03-10 13:57:06 -080080def simple_tcp_packet(pktlen=100,
Rich Laned0478ff2013-03-11 12:46:58 -070081 eth_dst='00:01:02:03:04:05',
82 eth_src='00:06:07:08:09:0a',
Tatsuya Yabe460321e2010-05-25 17:50:49 -070083 dl_vlan_enable=False,
Rich Laned0478ff2013-03-11 12:46:58 -070084 vlan_vid=0,
85 vlan_pcp=0,
Dan Talayco551befa2010-07-15 17:05:32 -070086 dl_vlan_cfi=0,
Dan Talayco41eae8b2010-03-10 13:57:06 -080087 ip_src='192.168.0.1',
88 ip_dst='192.168.0.2',
Tatsuya Yabe460321e2010-05-25 17:50:49 -070089 ip_tos=0,
Gregor Maier9cc93342013-01-29 16:55:28 -080090 ip_ttl=64,
Dan Talayco41eae8b2010-03-10 13:57:06 -080091 tcp_sport=1234,
Christian Dickmann8b59b4b2012-09-23 16:48:30 -070092 tcp_dport=80,
Harshmeet Singhc51f4042014-05-21 13:32:52 -070093 tcp_flags="S",
Christian Dickmann8b59b4b2012-09-23 16:48:30 -070094 ip_ihl=None,
95 ip_options=False
Dan Talayco41eae8b2010-03-10 13:57:06 -080096 ):
97 """
98 Return a simple dataplane TCP packet
99
100 Supports a few parameters:
101 @param len Length of packet in bytes w/o CRC
Rich Laned0478ff2013-03-11 12:46:58 -0700102 @param eth_dst Destinatino MAC
103 @param eth_src Source MAC
Tatsuya Yabe460321e2010-05-25 17:50:49 -0700104 @param dl_vlan_enable True if the packet is with vlan, False otherwise
Rich Laned0478ff2013-03-11 12:46:58 -0700105 @param vlan_vid VLAN ID
106 @param vlan_pcp VLAN priority
Dan Talayco41eae8b2010-03-10 13:57:06 -0800107 @param ip_src IP source
108 @param ip_dst IP destination
Tatsuya Yabe460321e2010-05-25 17:50:49 -0700109 @param ip_tos IP ToS
Gregor Maier9cc93342013-01-29 16:55:28 -0800110 @param ip_ttl IP TTL
Dan Talayco41eae8b2010-03-10 13:57:06 -0800111 @param tcp_dport TCP destination port
Harshmeet Singhc51f4042014-05-21 13:32:52 -0700112 @param tcp_sport TCP source port
113 @param tcp_flags TCP Control flags
Dan Talayco41eae8b2010-03-10 13:57:06 -0800114
115 Generates a simple TCP request. Users
116 shouldn't assume anything about this packet other than that
117 it is a valid ethernet/IP/TCP frame.
118 """
Jeffrey Townsend5cb7ed32012-08-17 18:11:01 +0000119
120 if MINSIZE > pktlen:
121 pktlen = MINSIZE
122
Dan Talayco551befa2010-07-15 17:05:32 -0700123 # Note Dot1Q.id is really CFI
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800124 if (dl_vlan_enable):
Rich Laned0478ff2013-03-11 12:46:58 -0700125 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
126 scapy.Dot1Q(prio=vlan_pcp, id=dl_vlan_cfi, vlan=vlan_vid)/ \
Gregor Maier9cc93342013-01-29 16:55:28 -0800127 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ttl=ip_ttl, ihl=ip_ihl)/ \
Harshmeet Singhc51f4042014-05-21 13:32:52 -0700128 scapy.TCP(sport=tcp_sport, dport=tcp_dport, flags=tcp_flags)
Tatsuya Yabe460321e2010-05-25 17:50:49 -0700129 else:
Christian Dickmann8b59b4b2012-09-23 16:48:30 -0700130 if not ip_options:
Rich Laned0478ff2013-03-11 12:46:58 -0700131 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
Gregor Maier9cc93342013-01-29 16:55:28 -0800132 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ttl=ip_ttl, ihl=ip_ihl)/ \
Harshmeet Singhc51f4042014-05-21 13:32:52 -0700133 scapy.TCP(sport=tcp_sport, dport=tcp_dport, flags=tcp_flags)
Christian Dickmann8b59b4b2012-09-23 16:48:30 -0700134 else:
Rich Laned0478ff2013-03-11 12:46:58 -0700135 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
Gregor Maier9cc93342013-01-29 16:55:28 -0800136 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 -0700137 scapy.TCP(sport=tcp_sport, dport=tcp_dport, flags=tcp_flags)
Tatsuya Yabe460321e2010-05-25 17:50:49 -0700138
Dan Talayco41eae8b2010-03-10 13:57:06 -0800139 pkt = pkt/("D" * (pktlen - len(pkt)))
140
141 return pkt
142
Rich Lane86aceb02013-07-17 18:45:38 -0700143def simple_tcpv6_packet(pktlen=100,
144 eth_dst='00:01:02:03:04:05',
145 eth_src='00:06:07:08:09:0a',
146 dl_vlan_enable=False,
147 vlan_vid=0,
148 vlan_pcp=0,
149 ipv6_src='2001:db8:85a3::8a2e:370:7334',
150 ipv6_dst='2001:db8:85a3::8a2e:370:7335',
151 ipv6_tc=0,
152 ipv6_hlim=64,
153 ipv6_fl=0,
154 tcp_sport=1234,
Harshmeet Singhc51f4042014-05-21 13:32:52 -0700155 tcp_dport=80,
Harshmeet Singh31ba3312014-05-21 13:48:35 -0700156 tcp_flags="S"):
Rich Lane86aceb02013-07-17 18:45:38 -0700157 """
158 Return a simple IPv6/TCP packet
159
160 Supports a few parameters:
161 @param len Length of packet in bytes w/o CRC
162 @param eth_dst Destination MAC
163 @param eth_src Source MAC
164 @param dl_vlan_enable True if the packet is with vlan, False otherwise
165 @param vlan_vid VLAN ID
166 @param vlan_pcp VLAN priority
167 @param ipv6_src IPv6 source
168 @param ipv6_dst IPv6 destination
169 @param ipv6_tc IPv6 traffic class
170 @param ipv6_ttl IPv6 hop limit
171 @param ipv6_fl IPv6 flow label
172 @param tcp_dport TCP destination port
173 @param tcp_sport TCP source port
Harshmeet Singhc51f4042014-05-21 13:32:52 -0700174 @param tcp_flags TCP Control flags
Rich Lane86aceb02013-07-17 18:45:38 -0700175
176 Generates a simple TCP request. Users shouldn't assume anything about this
177 packet other than that it is a valid ethernet/IPv6/TCP frame.
178 """
179
180 if MINSIZE > pktlen:
181 pktlen = MINSIZE
182
183 pkt = scapy.Ether(dst=eth_dst, src=eth_src)
184 if dl_vlan_enable or vlan_vid or vlan_pcp:
185 pkt /= scapy.Dot1Q(vlan=vlan_vid, prio=vlan_pcp)
186 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 -0700187 pkt /= scapy.TCP(sport=tcp_sport, dport=tcp_dport, flags=tcp_flags)
Rich Lane86aceb02013-07-17 18:45:38 -0700188 pkt /= ("D" * (pktlen - len(pkt)))
189
190 return pkt
191
Rich Lane6ee7bea2012-10-26 16:19:29 -0700192def simple_udp_packet(pktlen=100,
Rich Laned0478ff2013-03-11 12:46:58 -0700193 eth_dst='00:01:02:03:04:05',
194 eth_src='00:06:07:08:09:0a',
Rich Lane6ee7bea2012-10-26 16:19:29 -0700195 dl_vlan_enable=False,
Rich Laned0478ff2013-03-11 12:46:58 -0700196 vlan_vid=0,
197 vlan_pcp=0,
Rich Lane6ee7bea2012-10-26 16:19:29 -0700198 dl_vlan_cfi=0,
199 ip_src='192.168.0.1',
200 ip_dst='192.168.0.2',
201 ip_tos=0,
Gregor Maier9cc93342013-01-29 16:55:28 -0800202 ip_ttl=64,
Rich Lane6ee7bea2012-10-26 16:19:29 -0700203 udp_sport=1234,
204 udp_dport=80,
205 ip_ihl=None,
206 ip_options=False
207 ):
208 """
209 Return a simple dataplane UDP packet
210
211 Supports a few parameters:
212 @param len Length of packet in bytes w/o CRC
Rich Laned0478ff2013-03-11 12:46:58 -0700213 @param eth_dst Destination MAC
214 @param eth_src Source MAC
Rich Lane6ee7bea2012-10-26 16:19:29 -0700215 @param dl_vlan_enable True if the packet is with vlan, False otherwise
Rich Laned0478ff2013-03-11 12:46:58 -0700216 @param vlan_vid VLAN ID
217 @param vlan_pcp VLAN priority
Rich Lane6ee7bea2012-10-26 16:19:29 -0700218 @param ip_src IP source
219 @param ip_dst IP destination
220 @param ip_tos IP ToS
Gregor Maier9cc93342013-01-29 16:55:28 -0800221 @param ip_ttl IP TTL
Rich Lane6ee7bea2012-10-26 16:19:29 -0700222 @param udp_dport UDP destination port
223 @param udp_sport UDP source port
224
225 Generates a simple UDP packet. Users shouldn't assume anything about
226 this packet other than that it is a valid ethernet/IP/UDP frame.
227 """
228
229 if MINSIZE > pktlen:
230 pktlen = MINSIZE
231
232 # Note Dot1Q.id is really CFI
233 if (dl_vlan_enable):
Rich Laned0478ff2013-03-11 12:46:58 -0700234 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
235 scapy.Dot1Q(prio=vlan_pcp, id=dl_vlan_cfi, vlan=vlan_vid)/ \
Gregor Maier9cc93342013-01-29 16:55:28 -0800236 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ttl=ip_ttl, ihl=ip_ihl)/ \
Rich Lane6ee7bea2012-10-26 16:19:29 -0700237 scapy.UDP(sport=udp_sport, dport=udp_dport)
238 else:
239 if not ip_options:
Rich Laned0478ff2013-03-11 12:46:58 -0700240 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
Gregor Maier9cc93342013-01-29 16:55:28 -0800241 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ttl=ip_ttl, ihl=ip_ihl)/ \
Rich Lane6ee7bea2012-10-26 16:19:29 -0700242 scapy.UDP(sport=udp_sport, dport=udp_dport)
243 else:
Rich Laned0478ff2013-03-11 12:46:58 -0700244 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
Gregor Maier9cc93342013-01-29 16:55:28 -0800245 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 -0700246 scapy.UDP(sport=udp_sport, dport=udp_dport)
247
248 pkt = pkt/("D" * (pktlen - len(pkt)))
249
250 return pkt
251
macauley_chengb0ec33d2015-09-04 11:32:44 +0800252
253def simple_tcp_packet_two_vlan(pktlen=100,
254 eth_dst='00:01:02:03:04:05',
255 eth_src='00:06:07:08:09:0a',
256 out_dl_vlan_enable=False,
257 in_dl_vlan_enable=False,
258 out_vlan_vid=0,
259 out_vlan_pcp=0,
260 out_dl_vlan_cfi=0,
261 in_vlan_vid=0,
262 in_vlan_pcp=0,
263 in_dl_vlan_cfi=0,
264 ip_src='192.168.0.1',
265 ip_dst='192.168.0.2',
266 ip_tos=0,
267 ip_ttl=64,
268 tcp_sport=1234,
269 tcp_dport=80,
270 tcp_flags="S",
271 ip_ihl=None,
272 ip_options=False
273 ):
274 """
275 Return a simple dataplane TCP packet
276
277 Supports a few parameters:
278 @param len Length of packet in bytes w/o CRC
279 @param eth_dst Destinatino MAC
280 @param eth_src Source MAC
281 @param dl_vlan_enable True if the packet is with vlan, False otherwise
282 @param vlan_vid VLAN ID
283 @param vlan_pcp VLAN priority
284 @param ip_src IP source
285 @param ip_dst IP destination
286 @param ip_tos IP ToS
287 @param ip_ttl IP TTL
288 @param tcp_dport TCP destination port
289 @param tcp_sport TCP source port
290 @param tcp_flags TCP Control flags
291
292 Generates a simple TCP request. Users
293 shouldn't assume anything about this packet other than that
294 it is a valid ethernet/IP/TCP frame.
295 """
296
297 if MINSIZE > pktlen:
298 pktlen = MINSIZE
299
300 # Note Dot1Q.id is really CFI
301 if (out_dl_vlan_enable and in_dl_vlan_enable):
302 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
303 scapy.Dot1Q(prio=out_vlan_pcp, id=out_dl_vlan_cfi, vlan=out_vlan_vid)
304
305 if in_dl_vlan_enable:
306 pkt = pkt/scapy.Dot1Q(prio=in_vlan_pcp, id=in_dl_vlan_cfi, vlan=in_vlan_vid)
307
308 pkt = pkt/scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ttl=ip_ttl, ihl=ip_ihl)/ \
309 scapy.TCP(sport=tcp_sport, dport=tcp_dport, flags=tcp_flags)
310 elif (out_dl_vlan_enable and (not in_dl_vlan_enable)):
311 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
312 scapy.Dot1Q(prio=out_vlan_pcp, id=out_dl_vlan_cfi, vlan=out_vlan_vid)/ \
313 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ttl=ip_ttl, ihl=ip_ihl)/ \
314 scapy.TCP(sport=tcp_sport, dport=tcp_dport, flags=tcp_flags)
315 elif ((not out_dl_vlan_enable) and in_dl_vlan_enable):
316 assert(0) #shall not have this caes
317 else:
318 if not ip_options:
319 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
320 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ttl=ip_ttl, ihl=ip_ihl)/ \
321 scapy.TCP(sport=tcp_sport, dport=tcp_dport, flags=tcp_flags)
322 else:
323 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
324 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ttl=ip_ttl, ihl=ip_ihl, options=ip_options)/ \
325 scapy.TCP(sport=tcp_sport, dport=tcp_dport, flags=tcp_flags)
326
327 pkt = pkt/("D" * (pktlen - len(pkt)))
328
329 return pkt
330
macauley17cd60d2015-07-27 17:41:18 +0800331def simple_vxlan_packet(eth_dst='00:01:02:03:04:05',
332 eth_src='00:06:07:08:09:0a',
333 dl_vlan_enable=False,
334 vlan_vid=0,
335 vlan_pcp=0,
336 dl_vlan_cfi=0,
337 ip_src='192.168.0.1',
338 ip_dst='192.168.0.2',
339 ip_tos=0,
340 ip_ttl=64,
341 udp_sport=1234,
342 udp_dport=4789,
343 vnid=1,
macauley1b23af82015-07-30 14:06:33 +0800344 inner_payload=None,
macauley17cd60d2015-07-27 17:41:18 +0800345 ip_ihl=None,
346 ip_options=False
347 ):
348 """
349 Return a simple dataplane UDP packet
350
351 Supports a few parameters:
352 @param len Length of packet in bytes w/o CRC
353 @param eth_dst Destination MAC
354 @param eth_src Source MAC
355 @param dl_vlan_enable True if the packet is with vlan, False otherwise
356 @param vlan_vid VLAN ID
357 @param vlan_pcp VLAN priority
358 @param ip_src IP source
359 @param ip_dst IP destination
360 @param ip_tos IP ToS
361 @param ip_ttl IP TTL
362 @param udp_dport UDP destination port
363 @param udp_sport UDP source port
364 @param inner_pyload inner pacekt content
365 Generates a simple UDP packet. Users shouldn't assume anything about
366 this packet other than that it is a valid ethernet/IP/UDP frame.
367 """
368
369 # Note Dot1Q.id is really CFI
370 if (dl_vlan_enable):
371 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
372 scapy.Dot1Q(prio=vlan_pcp, id=dl_vlan_cfi, vlan=vlan_vid)/ \
373 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ttl=ip_ttl, ihl=ip_ihl)/ \
374 scapy.UDP(sport=udp_sport, dport=udp_dport)
375 else:
376 if not ip_options:
377 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
378 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ttl=ip_ttl, ihl=ip_ihl)/ \
379 scapy.UDP(sport=udp_sport, dport=udp_dport)
380 else:
381 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
382 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ttl=ip_ttl, ihl=ip_ihl, options=ip_options)/ \
383 scapy.UDP(sport=udp_sport, dport=udp_dport)
macauley1b23af82015-07-30 14:06:33 +0800384
macauley17cd60d2015-07-27 17:41:18 +0800385 #add vxlan header
386 pkt = pkt/scapy.VXLAN(vni=vnid)
387 #add innder payload
macauley1b23af82015-07-30 14:06:33 +0800388 if inner_payload!=None:
389 pkt=pkt/inner_payload
macauley17cd60d2015-07-27 17:41:18 +0800390
391 return pkt
392
macauley_chengb0ec33d2015-09-04 11:32:44 +0800393
macauley_cheng45833df2015-08-31 15:19:07 +0800394
395def simple_mpls_packet(eth_dst='00:01:02:03:04:05',
396 eth_src='00:06:07:08:09:0a',
397 dl_vlan_enable=False,
398 vlan_vid=0,
399 vlan_pcp=0,
400 dl_vlan_cfi=0,
401 label=None,
402 inner_payload=None
403 ):
404 """
405 Return a simple dataplane MPLS packet
406
407 Supports a few parameters:
408 @param len Length of packet in bytes w/o CRC
409 @param eth_dst Destination MAC
410 @param eth_src Source MAC
411 @param dl_vlan_enable True if the packet is with vlan, False otherwise
412 @param vlan_vid VLAN ID
413 @param vlan_pcp VLAN priority
414 @param inner_pyload inner pacekt content
415 Generates a simple MPLS packet. Users shouldn't assume anything about
416 this packet other than that it is a valid ethernet/IP/UDP frame.
417 """
418
419 # Note Dot1Q.id is really CFI
420 if (dl_vlan_enable):
421 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
422 scapy.Dot1Q(prio=vlan_pcp, id=dl_vlan_cfi, vlan=vlan_vid)
423 else:
424 pkt = scapy.Ether(dst=eth_dst, src=eth_src)
425
426 #add MPLS header
427 for i in range(len(label)):
428 l,c,s,t=label[i]
429 pkt = pkt/scapy.MPLS(label=l, cos=c, s=s, ttl=t)
430
431 #add innder payload
432 if inner_payload!=None:
433 pkt=pkt/inner_payload
434
435 return pkt
436
Rich Lane86aceb02013-07-17 18:45:38 -0700437def simple_udpv6_packet(pktlen=100,
438 eth_dst='00:01:02:03:04:05',
439 eth_src='00:06:07:08:09:0a',
440 dl_vlan_enable=False,
441 vlan_vid=0,
442 vlan_pcp=0,
443 ipv6_src='2001:db8:85a3::8a2e:370:7334',
444 ipv6_dst='2001:db8:85a3::8a2e:370:7335',
445 ipv6_tc=0,
446 ipv6_hlim=64,
447 ipv6_fl=0,
448 udp_sport=1234,
449 udp_dport=80):
450 """
451 Return a simple IPv6/UDP packet
452
453 Supports a few parameters:
454 @param len Length of packet in bytes w/o CRC
455 @param eth_dst Destination MAC
456 @param eth_src Source MAC
457 @param dl_vlan_enable True if the packet is with vlan, False otherwise
458 @param vlan_vid VLAN ID
459 @param vlan_pcp VLAN priority
460 @param ipv6_src IPv6 source
461 @param ipv6_dst IPv6 destination
462 @param ipv6_tc IPv6 traffic class
463 @param ipv6_ttl IPv6 hop limit
464 @param ipv6_fl IPv6 flow label
465 @param udp_dport UDP destination port
466 @param udp_sport UDP source port
467
468 Generates a simple UDP request. Users shouldn't assume anything about this
469 packet other than that it is a valid ethernet/IPv6/UDP frame.
470 """
471
472 if MINSIZE > pktlen:
473 pktlen = MINSIZE
474
475 pkt = scapy.Ether(dst=eth_dst, src=eth_src)
476 if dl_vlan_enable or vlan_vid or vlan_pcp:
477 pkt /= scapy.Dot1Q(vlan=vlan_vid, prio=vlan_pcp)
478 pkt /= scapy.IPv6(src=ipv6_src, dst=ipv6_dst, fl=ipv6_fl, tc=ipv6_tc, hlim=ipv6_hlim)
479 pkt /= scapy.UDP(sport=udp_sport, dport=udp_dport)
480 pkt /= ("D" * (pktlen - len(pkt)))
481
482 return pkt
483
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700484def simple_icmp_packet(pktlen=60,
Rich Laned0478ff2013-03-11 12:46:58 -0700485 eth_dst='00:01:02:03:04:05',
486 eth_src='00:06:07:08:09:0a',
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700487 dl_vlan_enable=False,
Rich Laned0478ff2013-03-11 12:46:58 -0700488 vlan_vid=0,
489 vlan_pcp=0,
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700490 ip_src='192.168.0.1',
491 ip_dst='192.168.0.2',
492 ip_tos=0,
Gregor Maier9cc93342013-01-29 16:55:28 -0800493 ip_ttl=64,
Harshmeet Singhd209c0b2014-01-28 09:48:58 -0600494 ip_id=1,
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700495 icmp_type=8,
Harshmeet Singhd209c0b2014-01-28 09:48:58 -0600496 icmp_code=0,
Harshmeet Singh45b2a9d2014-01-28 13:02:04 -0600497 icmp_data=''):
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700498 """
499 Return a simple ICMP packet
500
501 Supports a few parameters:
502 @param len Length of packet in bytes w/o CRC
Rich Laned0478ff2013-03-11 12:46:58 -0700503 @param eth_dst Destinatino MAC
504 @param eth_src Source MAC
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700505 @param dl_vlan_enable True if the packet is with vlan, False otherwise
Rich Laned0478ff2013-03-11 12:46:58 -0700506 @param vlan_vid VLAN ID
507 @param vlan_pcp VLAN priority
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700508 @param ip_src IP source
509 @param ip_dst IP destination
510 @param ip_tos IP ToS
Gregor Maier9cc93342013-01-29 16:55:28 -0800511 @param ip_ttl IP TTL
Harshmeet Singhd209c0b2014-01-28 09:48:58 -0600512 @param ip_id IP Identification
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700513 @param icmp_type ICMP type
514 @param icmp_code ICMP code
Harshmeet Singhd209c0b2014-01-28 09:48:58 -0600515 @param icmp_data ICMP data
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700516
517 Generates a simple ICMP ECHO REQUEST. Users
518 shouldn't assume anything about this packet other than that
519 it is a valid ethernet/ICMP frame.
520 """
Jeffrey Townsend5cb7ed32012-08-17 18:11:01 +0000521
522 if MINSIZE > pktlen:
523 pktlen = MINSIZE
524
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700525 if (dl_vlan_enable):
Rich Laned0478ff2013-03-11 12:46:58 -0700526 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
527 scapy.Dot1Q(prio=vlan_pcp, id=0, vlan=vlan_vid)/ \
Harshmeet Singhd209c0b2014-01-28 09:48:58 -0600528 scapy.IP(src=ip_src, dst=ip_dst, ttl=ip_ttl, tos=ip_tos, id=ip_id)/ \
Harshmeet Singh45b2a9d2014-01-28 13:02:04 -0600529 scapy.ICMP(type=icmp_type, code=icmp_code)/ icmp_data
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700530 else:
Rich Laned0478ff2013-03-11 12:46:58 -0700531 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
Harshmeet Singhd209c0b2014-01-28 09:48:58 -0600532 scapy.IP(src=ip_src, dst=ip_dst, ttl=ip_ttl, tos=ip_tos, id=ip_id)/ \
Harshmeet Singh45b2a9d2014-01-28 13:02:04 -0600533 scapy.ICMP(type=icmp_type, code=icmp_code)/ icmp_data
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700534
535 pkt = pkt/("0" * (pktlen - len(pkt)))
536
537 return pkt
538
Rich Lane86aceb02013-07-17 18:45:38 -0700539def simple_icmpv6_packet(pktlen=100,
540 eth_dst='00:01:02:03:04:05',
541 eth_src='00:06:07:08:09:0a',
542 dl_vlan_enable=False,
543 vlan_vid=0,
544 vlan_pcp=0,
545 ipv6_src='2001:db8:85a3::8a2e:370:7334',
546 ipv6_dst='2001:db8:85a3::8a2e:370:7335',
547 ipv6_tc=0,
548 ipv6_hlim=64,
549 ipv6_fl=0,
550 icmp_type=8,
551 icmp_code=0):
552 """
553 Return a simple ICMPv6 packet
554
555 Supports a few parameters:
556 @param len Length of packet in bytes w/o CRC
557 @param eth_dst Destination MAC
558 @param eth_src Source MAC
559 @param dl_vlan_enable True if the packet is with vlan, False otherwise
560 @param vlan_vid VLAN ID
561 @param vlan_pcp VLAN priority
562 @param ipv6_src IPv6 source
563 @param ipv6_dst IPv6 destination
564 @param ipv6_tc IPv6 traffic class
565 @param ipv6_ttl IPv6 hop limit
566 @param ipv6_fl IPv6 flow label
567 @param icmp_type ICMP type
568 @param icmp_code ICMP code
569
570 Generates a simple ICMP ECHO REQUEST. Users shouldn't assume anything
571 about this packet other than that it is a valid ethernet/IPv6/ICMP frame.
572 """
573
574 if MINSIZE > pktlen:
575 pktlen = MINSIZE
576
577 pkt = scapy.Ether(dst=eth_dst, src=eth_src)
578 if dl_vlan_enable or vlan_vid or vlan_pcp:
579 pkt /= scapy.Dot1Q(vlan=vlan_vid, prio=vlan_pcp)
580 pkt /= scapy.IPv6(src=ipv6_src, dst=ipv6_dst, fl=ipv6_fl, tc=ipv6_tc, hlim=ipv6_hlim)
581 pkt /= scapy.ICMPv6Unknown(type=icmp_type, code=icmp_code)
582 pkt /= ("D" * (pktlen - len(pkt)))
583
584 return pkt
585
Shudong Zhouc7562b12013-02-06 01:12:18 -0800586def simple_arp_packet(pktlen=60,
Rich Laned0478ff2013-03-11 12:46:58 -0700587 eth_dst='ff:ff:ff:ff:ff:ff',
588 eth_src='00:06:07:08:09:0a',
Rich Lanee01611f2014-01-15 14:55:11 -0800589 vlan_vid=0,
590 vlan_pcp=0,
Shudong Zhouc7562b12013-02-06 01:12:18 -0800591 arp_op=1,
592 ip_snd='192.168.0.1',
593 ip_tgt='192.168.0.2',
594 hw_snd='00:06:07:08:09:0a',
595 hw_tgt='00:00:00:00:00:00',
596 ):
597 """
598 Return a simple ARP packet
599
600 Supports a few parameters:
601 @param len Length of packet in bytes w/o CRC
Rich Laned0478ff2013-03-11 12:46:58 -0700602 @param eth_dst Destinatino MAC
603 @param eth_src Source MAC
Shudong Zhouc7562b12013-02-06 01:12:18 -0800604 @param arp_op Operation (1=request, 2=reply)
605 @param ip_snd Sender IP
606 @param ip_tgt Target IP
607 @param hw_snd Sender hardware address
608 @param hw_tgt Target hardware address
609
610 Generates a simple ARP REQUEST. Users
611 shouldn't assume anything about this packet other than that
612 it is a valid ethernet/ARP frame.
613 """
614
615 if MINSIZE > pktlen:
616 pktlen = MINSIZE
617
Rich Lanee01611f2014-01-15 14:55:11 -0800618 pkt = scapy.Ether(dst=eth_dst, src=eth_src)
619 if vlan_vid or vlan_pcp:
620 pkt /= scapy.Dot1Q(vlan=vlan_vid, prio=vlan_pcp)
621 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 -0800622
Rich Laned459ce52014-01-24 12:09:54 -0800623 pkt = pkt/("\0" * (pktlen - len(pkt)))
Shudong Zhouc7562b12013-02-06 01:12:18 -0800624
625 return pkt
626
Ed Swierk0aeff8c2012-03-23 20:27:18 -0700627def simple_eth_packet(pktlen=60,
Rich Lane53275082013-11-18 23:26:22 -0800628 eth_dst='00:01:02:03:04:05',
629 eth_src='00:06:07:08:09:0a',
Rich Laned0478ff2013-03-11 12:46:58 -0700630 eth_type=0x88cc):
Jeffrey Townsend5cb7ed32012-08-17 18:11:01 +0000631
632 if MINSIZE > pktlen:
633 pktlen = MINSIZE
634
Rich Laned0478ff2013-03-11 12:46:58 -0700635 pkt = scapy.Ether(dst=eth_dst, src=eth_src, type=eth_type)
Ed Swierk0aeff8c2012-03-23 20:27:18 -0700636
637 pkt = pkt/("0" * (pktlen - len(pkt)))
638
639 return pkt
640
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800641def qinq_tcp_packet(pktlen=100,
Rich Laned0478ff2013-03-11 12:46:58 -0700642 eth_dst='00:01:02:03:04:05',
643 eth_src='00:06:07:08:09:0a',
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800644 dl_vlan_outer=20,
645 dl_vlan_pcp_outer=0,
646 dl_vlan_cfi_outer=0,
Rich Laned0478ff2013-03-11 12:46:58 -0700647 vlan_vid=10,
648 vlan_pcp=0,
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800649 dl_vlan_cfi=0,
650 ip_src='192.168.0.1',
651 ip_dst='192.168.0.2',
652 ip_tos=0,
Gregor Maier9cc93342013-01-29 16:55:28 -0800653 ip_ttl=64,
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800654 tcp_sport=1234,
655 tcp_dport=80,
656 ip_ihl=None,
657 ip_options=False
658 ):
659 """
660 Return a doubly tagged dataplane TCP packet
661
662 Supports a few parameters:
663 @param len Length of packet in bytes w/o CRC
Rich Laned0478ff2013-03-11 12:46:58 -0700664 @param eth_dst Destinatino MAC
665 @param eth_src Source MAC
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800666 @param dl_vlan_outer Outer VLAN ID
667 @param dl_vlan_pcp_outer Outer VLAN priority
668 @param dl_vlan_cfi_outer Outer VLAN cfi bit
Rich Laned0478ff2013-03-11 12:46:58 -0700669 @param vlan_vid Inner VLAN ID
670 @param vlan_pcp VLAN priority
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800671 @param dl_vlan_cfi VLAN cfi bit
672 @param ip_src IP source
673 @param ip_dst IP destination
674 @param ip_tos IP ToS
675 @param tcp_dport TCP destination port
676 @param ip_sport TCP source port
677
678 Generates a TCP request. Users
679 shouldn't assume anything about this packet other than that
680 it is a valid ethernet/IP/TCP frame.
681 """
682
683 if MINSIZE > pktlen:
684 pktlen = MINSIZE
685
686 # Note Dot1Q.id is really CFI
Rich Laned0478ff2013-03-11 12:46:58 -0700687 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800688 scapy.Dot1Q(prio=dl_vlan_pcp_outer, id=dl_vlan_cfi_outer, vlan=dl_vlan_outer)/ \
Rich Laned0478ff2013-03-11 12:46:58 -0700689 scapy.Dot1Q(prio=vlan_pcp, id=dl_vlan_cfi, vlan=vlan_vid)/ \
Gregor Maier9cc93342013-01-29 16:55:28 -0800690 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ttl=ip_ttl, ihl=ip_ihl)/ \
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800691 scapy.TCP(sport=tcp_sport, dport=tcp_dport)
692
693 pkt = pkt/("D" * (pktlen - len(pkt)))
694
695 return pkt
696
Shudong Zhoub7f12462012-11-20 13:01:12 -0800697def do_barrier(ctrl, timeout=-1):
Dan Talayco0fc08bd2012-04-09 16:56:18 -0700698 """
699 Do a barrier command
700 Return 0 on success, -1 on error
701 """
Rich Lanee717c6e2013-03-12 10:25:50 -0700702 b = ofp.message.barrier_request()
Shudong Zhoub7f12462012-11-20 13:01:12 -0800703 (resp, pkt) = ctrl.transact(b, timeout=timeout)
Rich Lane3a261d52013-01-03 17:45:08 -0800704 if resp is None:
705 raise AssertionError("barrier failed")
Dan Talaycof6b94832012-04-12 21:50:57 -0700706 # We'll trust the transaction processing in the controller that xid matched
Rich Lane3a261d52013-01-03 17:45:08 -0800707 return 0 # for backwards compatibility
Dan Talayco92c99122010-06-03 13:53:18 -0700708
Rich Lane9a003812012-10-04 17:17:59 -0700709def port_config_get(controller, port_no):
Dan Talayco92c99122010-06-03 13:53:18 -0700710 """
711 Get a port's configuration
712
713 Gets the switch feature configuration and grabs one port's
714 configuration
715
716 @returns (hwaddr, config, advert) The hwaddress, configuration and
717 advertised values
718 """
Rich Lane6dc865c2013-07-10 10:12:13 -0700719
720 if ofp.OFP_VERSION <= 3:
721 request = ofp.message.features_request()
722 reply, _ = controller.transact(request)
723 if reply is None:
724 logging.warn("Get feature request failed")
725 return None, None, None
726 logging.debug(reply.show())
727 ports = reply.ports
728 else:
729 request = ofp.message.port_desc_stats_request()
730 # TODO do multipart correctly
731 reply, _ = controller.transact(request)
732 if reply is None:
733 logging.warn("Port desc stats request failed")
734 return None, None, None
735 logging.debug(reply.show())
736 ports = reply.entries
737
738 for port in ports:
739 if port.port_no == port_no:
740 return (port.hw_addr, port.config, port.advertised)
Dan Talayco92c99122010-06-03 13:53:18 -0700741
Rich Lane9a003812012-10-04 17:17:59 -0700742 logging.warn("Did not find port number for port config")
Dan Talayco92c99122010-06-03 13:53:18 -0700743 return None, None, None
744
Rich Lane9a003812012-10-04 17:17:59 -0700745def port_config_set(controller, port_no, config, mask):
Dan Talayco92c99122010-06-03 13:53:18 -0700746 """
747 Set the port configuration according the given parameters
748
749 Gets the switch feature configuration and updates one port's
750 configuration value according to config and mask
751 """
Rich Lane9a003812012-10-04 17:17:59 -0700752 logging.info("Setting port " + str(port_no) + " to config " + str(config))
Rich Lane6dc865c2013-07-10 10:12:13 -0700753
754 hw_addr, _, _ = port_config_get(controller, port_no)
755
Rich Lanee717c6e2013-03-12 10:25:50 -0700756 mod = ofp.message.port_mod()
Dan Talayco92c99122010-06-03 13:53:18 -0700757 mod.port_no = port_no
Rich Lane6dc865c2013-07-10 10:12:13 -0700758 if hw_addr != None:
759 mod.hw_addr = hw_addr
Dan Talayco92c99122010-06-03 13:53:18 -0700760 mod.config = config
761 mod.mask = mask
Rich Lane6dc865c2013-07-10 10:12:13 -0700762 mod.advertise = 0 # No change
Rich Lane5c3151c2013-01-03 17:15:41 -0800763 controller.message_send(mod)
764 return 0
Dan Talayco92c99122010-06-03 13:53:18 -0700765
Rich Lane2014f9b2012-10-05 15:29:40 -0700766def receive_pkt_check(dp, pkt, yes_ports, no_ports, assert_if):
Dan Talayco92c99122010-06-03 13:53:18 -0700767 """
768 Check for proper receive packets across all ports
Ken Chiang1bf01602012-04-04 10:48:23 -0700769 @param dp The dataplane object
Dan Talayco92c99122010-06-03 13:53:18 -0700770 @param pkt Expected packet; may be None if yes_ports is empty
771 @param yes_ports Set or list of ports that should recieve packet
772 @param no_ports Set or list of ports that should not receive packet
773 @param assert_if Object that implements assertXXX
Rich Lanee4b384d2013-09-13 14:33:40 -0700774
775 DEPRECATED in favor in verify_packets
Dan Talayco92c99122010-06-03 13:53:18 -0700776 """
Rich Lane91765672012-12-06 16:33:04 -0800777
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700778 exp_pkt_arg = None
Rich Lanecd97d3d2013-01-07 18:50:06 -0800779 if oftest.config["relax"]:
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700780 exp_pkt_arg = pkt
781
Dan Talayco92c99122010-06-03 13:53:18 -0700782 for ofport in yes_ports:
Rich Lane9a003812012-10-04 17:17:59 -0700783 logging.debug("Checking for pkt on port " + str(ofport))
Ken Chiang1bf01602012-04-04 10:48:23 -0700784 (rcv_port, rcv_pkt, pkt_time) = dp.poll(
Wilson Ngc2c6b4e2015-03-04 17:30:20 -0800785 port_number=ofport, exp_pkt=exp_pkt_arg)
Dan Talayco92c99122010-06-03 13:53:18 -0700786 assert_if.assertTrue(rcv_pkt is not None,
787 "Did not receive pkt on " + str(ofport))
Rich Lanecd97d3d2013-01-07 18:50:06 -0800788 if not oftest.dataplane.match_exp_pkt(pkt, rcv_pkt):
Rich Lane3c266832013-01-29 18:29:15 -0800789 logging.debug("Expected %s" % format_packet(pkt))
790 logging.debug("Received %s" % format_packet(rcv_pkt))
Rich Lanecd97d3d2013-01-07 18:50:06 -0800791 assert_if.assertTrue(oftest.dataplane.match_exp_pkt(pkt, rcv_pkt),
Rich Lane3c266832013-01-29 18:29:15 -0800792 "Received packet does not match expected packet " +
Ken Chiang1bf01602012-04-04 10:48:23 -0700793 "on port " + str(ofport))
Dan Talayco73f84012012-10-02 09:23:18 -0700794 if len(no_ports) > 0:
Rich Lane57dfee72014-03-24 16:59:47 -0700795 time.sleep(oftest.ofutils.default_negative_timeout)
Dan Talayco92c99122010-06-03 13:53:18 -0700796 for ofport in no_ports:
Rich Lane9a003812012-10-04 17:17:59 -0700797 logging.debug("Negative check for pkt on port " + str(ofport))
Ken Chiang1bf01602012-04-04 10:48:23 -0700798 (rcv_port, rcv_pkt, pkt_time) = dp.poll(
Rich Lane91765672012-12-06 16:33:04 -0800799 port_number=ofport, timeout=0, exp_pkt=exp_pkt_arg)
Dan Talayco92c99122010-06-03 13:53:18 -0700800 assert_if.assertTrue(rcv_pkt is None,
801 "Unexpected pkt on port " + str(ofport))
Dan Talayco551befa2010-07-15 17:05:32 -0700802
803
Dan Talaycoc948d0b2012-03-23 12:17:54 -0700804def receive_pkt_verify(parent, egr_ports, exp_pkt, ing_port):
Dan Talayco551befa2010-07-15 17:05:32 -0700805 """
806 Receive a packet and verify it matches an expected value
Dan Talaycof6e76c02012-03-23 10:56:12 -0700807 @param egr_port A single port or list of ports
Dan Talayco551befa2010-07-15 17:05:32 -0700808
809 parent must implement dataplane, assertTrue and assertEqual
Rich Lanee4b384d2013-09-13 14:33:40 -0700810
811 DEPRECATED in favor in verify_packets
Dan Talayco551befa2010-07-15 17:05:32 -0700812 """
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700813 exp_pkt_arg = None
Rich Lanecd97d3d2013-01-07 18:50:06 -0800814 if oftest.config["relax"]:
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700815 exp_pkt_arg = exp_pkt
816
Dan Talaycof6e76c02012-03-23 10:56:12 -0700817 if type(egr_ports) == type([]):
818 egr_port_list = egr_ports
819 else:
820 egr_port_list = [egr_ports]
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700821
Dan Talaycof6e76c02012-03-23 10:56:12 -0700822 # Expect a packet from each port on egr port list
823 for egr_port in egr_port_list:
Dan Talaycod8ae7582012-03-23 12:24:56 -0700824 check_port = egr_port
Rich Lanee717c6e2013-03-12 10:25:50 -0700825 if egr_port == ofp.OFPP_IN_PORT:
Dan Talaycod8ae7582012-03-23 12:24:56 -0700826 check_port = ing_port
Dan Talaycof6e76c02012-03-23 10:56:12 -0700827 (rcv_port, rcv_pkt, pkt_time) = parent.dataplane.poll(
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700828 port_number=check_port, exp_pkt=exp_pkt_arg)
Dan Talayco551befa2010-07-15 17:05:32 -0700829
Dan Talaycof6e76c02012-03-23 10:56:12 -0700830 if rcv_pkt is None:
Rich Lane9a003812012-10-04 17:17:59 -0700831 logging.error("ERROR: No packet received from " +
Dan Talaycod8ae7582012-03-23 12:24:56 -0700832 str(check_port))
Dan Talayco551befa2010-07-15 17:05:32 -0700833
Dan Talaycof6e76c02012-03-23 10:56:12 -0700834 parent.assertTrue(rcv_pkt is not None,
Dan Talaycod8ae7582012-03-23 12:24:56 -0700835 "Did not receive packet port " + str(check_port))
Rich Lane9a003812012-10-04 17:17:59 -0700836 logging.debug("Packet len " + str(len(rcv_pkt)) + " in on " +
Dan Talaycof6e76c02012-03-23 10:56:12 -0700837 str(rcv_port))
838
839 if str(exp_pkt) != str(rcv_pkt):
Rich Lane9a003812012-10-04 17:17:59 -0700840 logging.error("ERROR: Packet match failed.")
841 logging.debug("Expected len " + str(len(exp_pkt)) + ": "
Dan Talaycof6e76c02012-03-23 10:56:12 -0700842 + str(exp_pkt).encode('hex'))
Rich Lane9a003812012-10-04 17:17:59 -0700843 logging.debug("Received len " + str(len(rcv_pkt)) + ": "
Dan Talaycof6e76c02012-03-23 10:56:12 -0700844 + str(rcv_pkt).encode('hex'))
Rich Lane5d7e89a2012-10-26 16:43:13 -0700845 logging.debug("Expected packet: " + inspect_packet(scapy.Ether(str(exp_pkt))))
846 logging.debug("Received packet: " + inspect_packet(scapy.Ether(str(rcv_pkt))))
Dan Talaycof6e76c02012-03-23 10:56:12 -0700847 parent.assertEqual(str(exp_pkt), str(rcv_pkt),
Dan Talaycod8ae7582012-03-23 12:24:56 -0700848 "Packet match error on port " + str(check_port))
Dan Talaycof6e76c02012-03-23 10:56:12 -0700849
Dan Talayco551befa2010-07-15 17:05:32 -0700850def match_verify(parent, req_match, res_match):
851 """
852 Verify flow matches agree; if they disagree, report where
853
854 parent must implement assertEqual
855 Use str() to ensure content is compared and not pointers
856 """
857
858 parent.assertEqual(req_match.wildcards, res_match.wildcards,
859 'Match failed: wildcards: ' + hex(req_match.wildcards) +
860 " != " + hex(res_match.wildcards))
861 parent.assertEqual(req_match.in_port, res_match.in_port,
862 'Match failed: in_port: ' + str(req_match.in_port) +
863 " != " + str(res_match.in_port))
Rich Laned0478ff2013-03-11 12:46:58 -0700864 parent.assertEqual(str(req_match.eth_src), str(res_match.eth_src),
865 'Match failed: eth_src: ' + str(req_match.eth_src) +
866 " != " + str(res_match.eth_src))
867 parent.assertEqual(str(req_match.eth_dst), str(res_match.eth_dst),
868 'Match failed: eth_dst: ' + str(req_match.eth_dst) +
869 " != " + str(res_match.eth_dst))
870 parent.assertEqual(req_match.vlan_vid, res_match.vlan_vid,
871 'Match failed: vlan_vid: ' + str(req_match.vlan_vid) +
872 " != " + str(res_match.vlan_vid))
873 parent.assertEqual(req_match.vlan_pcp, res_match.vlan_pcp,
874 'Match failed: vlan_pcp: ' +
875 str(req_match.vlan_pcp) + " != " +
876 str(res_match.vlan_pcp))
877 parent.assertEqual(req_match.eth_type, res_match.eth_type,
878 'Match failed: eth_type: ' + str(req_match.eth_type) +
879 " != " + str(res_match.eth_type))
Dan Talayco551befa2010-07-15 17:05:32 -0700880
Rich Lanee717c6e2013-03-12 10:25:50 -0700881 if (not(req_match.wildcards & ofp.OFPFW_DL_TYPE)
Rich Laned0478ff2013-03-11 12:46:58 -0700882 and (req_match.eth_type == IP_ETHERTYPE)):
883 parent.assertEqual(req_match.ip_dscp, res_match.ip_dscp,
884 'Match failed: ip_dscp: ' + str(req_match.ip_dscp) +
885 " != " + str(res_match.ip_dscp))
886 parent.assertEqual(req_match.ip_proto, res_match.ip_proto,
887 'Match failed: ip_proto: ' + str(req_match.ip_proto) +
888 " != " + str(res_match.ip_proto))
889 parent.assertEqual(req_match.ipv4_src, res_match.ipv4_src,
890 'Match failed: ipv4_src: ' + str(req_match.ipv4_src) +
891 " != " + str(res_match.ipv4_src))
892 parent.assertEqual(req_match.ipv4_dst, res_match.ipv4_dst,
893 'Match failed: ipv4_dst: ' + str(req_match.ipv4_dst) +
894 " != " + str(res_match.ipv4_dst))
Dan Talayco551befa2010-07-15 17:05:32 -0700895
Rich Lanee717c6e2013-03-12 10:25:50 -0700896 if (not(req_match.wildcards & ofp.OFPFW_NW_PROTO)
Rich Laned0478ff2013-03-11 12:46:58 -0700897 and ((req_match.ip_proto == TCP_PROTOCOL)
898 or (req_match.ip_proto == UDP_PROTOCOL))):
899 parent.assertEqual(req_match.tcp_src, res_match.tcp_src,
900 'Match failed: tcp_src: ' +
901 str(req_match.tcp_src) +
902 " != " + str(res_match.tcp_src))
903 parent.assertEqual(req_match.tcp_dst, res_match.tcp_dst,
904 'Match failed: tcp_dst: ' +
905 str(req_match.tcp_dst) +
906 " != " + str(res_match.tcp_dst))
Dan Talayco551befa2010-07-15 17:05:32 -0700907
Ed Swierk99a74de2012-08-22 06:40:54 -0700908def packet_to_flow_match(parent, packet):
Rich Lanef6883512013-03-11 17:00:09 -0700909 match = oftest.parse.packet_to_flow_match(packet)
Rich Laneab7476f2013-06-13 15:53:52 -0700910 if ofp.OFP_VERSION in [1, 2]:
911 match.wildcards |= required_wildcards(parent)
912 else:
913 # TODO remove incompatible OXM entries
914 pass
Ed Swierk99a74de2012-08-22 06:40:54 -0700915 return match
916
917def flow_msg_create(parent, pkt, ing_port=None, action_list=None, wildcards=None,
Dan Talaycof6e76c02012-03-23 10:56:12 -0700918 egr_ports=None, egr_queue=None, check_expire=False, in_band=False):
Dan Talayco551befa2010-07-15 17:05:32 -0700919 """
920 Create a flow message
921
922 Match on packet with given wildcards.
923 See flow_match_test for other parameter descriptoins
924 @param egr_queue if not None, make the output an enqueue action
Dan Talayco677c0b72011-08-23 22:53:38 -0700925 @param in_band if True, do not wildcard ingress port
Dan Talaycof6e76c02012-03-23 10:56:12 -0700926 @param egr_ports None (drop), single port or list of ports
Dan Talayco551befa2010-07-15 17:05:32 -0700927 """
Rich Lanef6883512013-03-11 17:00:09 -0700928 match = oftest.parse.packet_to_flow_match(pkt)
Dan Talayco551befa2010-07-15 17:05:32 -0700929 parent.assertTrue(match is not None, "Flow match from pkt failed")
Ed Swierk99a74de2012-08-22 06:40:54 -0700930 if wildcards is None:
931 wildcards = required_wildcards(parent)
Dan Talayco677c0b72011-08-23 22:53:38 -0700932 if in_band:
Rich Lanee717c6e2013-03-12 10:25:50 -0700933 wildcards &= ~ofp.OFPFW_IN_PORT
Dan Talayco551befa2010-07-15 17:05:32 -0700934 match.wildcards = wildcards
935 match.in_port = ing_port
936
Dan Talaycof6e76c02012-03-23 10:56:12 -0700937 if type(egr_ports) == type([]):
938 egr_port_list = egr_ports
939 else:
940 egr_port_list = [egr_ports]
941
Rich Lanee717c6e2013-03-12 10:25:50 -0700942 request = ofp.message.flow_add()
Dan Talayco551befa2010-07-15 17:05:32 -0700943 request.match = match
944 request.buffer_id = 0xffffffff
945 if check_expire:
Rich Lanee717c6e2013-03-12 10:25:50 -0700946 request.flags |= ofp.OFPFF_SEND_FLOW_REM
Dan Talayco551befa2010-07-15 17:05:32 -0700947 request.hard_timeout = 1
948
Rich Lane400fb9b2013-10-10 17:20:54 -0700949 if ofp.OFP_VERSION == 1:
950 actions = request.actions
951 else:
952 actions = []
953 request.instructions.append(ofp.instruction.apply_actions(actions))
954
Dan Talayco551befa2010-07-15 17:05:32 -0700955 if action_list is not None:
Rich Lane400fb9b2013-10-10 17:20:54 -0700956 actions.extend(action_list)
Dan Talayco551befa2010-07-15 17:05:32 -0700957
958 # Set up output/enqueue action if directed
959 if egr_queue is not None:
Dan Talaycof6e76c02012-03-23 10:56:12 -0700960 parent.assertTrue(egr_ports is not None, "Egress port not set")
Rich Lanee717c6e2013-03-12 10:25:50 -0700961 act = ofp.action.enqueue()
Dan Talaycof6e76c02012-03-23 10:56:12 -0700962 for egr_port in egr_port_list:
963 act.port = egr_port
964 act.queue_id = egr_queue
Rich Lane400fb9b2013-10-10 17:20:54 -0700965 actions.append(act)
Dan Talaycof6e76c02012-03-23 10:56:12 -0700966 elif egr_ports is not None:
967 for egr_port in egr_port_list:
Rich Lanee717c6e2013-03-12 10:25:50 -0700968 act = ofp.action.output()
Dan Talaycof6e76c02012-03-23 10:56:12 -0700969 act.port = egr_port
Rich Lane400fb9b2013-10-10 17:20:54 -0700970 actions.append(act)
Dan Talayco551befa2010-07-15 17:05:32 -0700971
Rich Lane9a003812012-10-04 17:17:59 -0700972 logging.debug(request.show())
Dan Talayco551befa2010-07-15 17:05:32 -0700973
974 return request
975
Jeffrey Townsendf3eae9c2012-03-28 18:23:21 -0700976def flow_msg_install(parent, request, clear_table_override=None):
Dan Talayco551befa2010-07-15 17:05:32 -0700977 """
978 Install a flow mod message in the switch
979
980 @param parent Must implement controller, assertEqual, assertTrue
981 @param request The request, all set to go
982 @param clear_table If true, clear the flow table before installing
983 """
Dan Talayco8a64e332012-03-28 14:53:20 -0700984
Rich Lane2014f9b2012-10-05 15:29:40 -0700985 clear_table = test_param_get('clear_table', default=True)
Jeffrey Townsendf3eae9c2012-03-28 18:23:21 -0700986 if(clear_table_override != None):
987 clear_table = clear_table_override
988
989 if clear_table:
Rich Lane9a003812012-10-04 17:17:59 -0700990 logging.debug("Clear flow table")
Rich Lane32bf9482013-01-03 17:26:30 -0800991 delete_all_flows(parent.controller)
Dan Talayco551befa2010-07-15 17:05:32 -0700992
Rich Lane9a003812012-10-04 17:17:59 -0700993 logging.debug("Insert flow")
Rich Lane5c3151c2013-01-03 17:15:41 -0800994 parent.controller.message_send(request)
Rich Lanee912d032012-12-22 14:28:33 -0800995
Rich Lane3a261d52013-01-03 17:45:08 -0800996 do_barrier(parent.controller)
Dan Talayco551befa2010-07-15 17:05:32 -0700997
Ed Swierk99a74de2012-08-22 06:40:54 -0700998def flow_match_test_port_pair(parent, ing_port, egr_ports, wildcards=None,
Rich Laned0478ff2013-03-11 12:46:58 -0700999 vlan_vid=-1, pkt=None, exp_pkt=None,
Rich Lanee5779d32012-10-05 17:56:04 -07001000 action_list=None):
Dan Talayco551befa2010-07-15 17:05:32 -07001001 """
1002 Flow match test on single TCP packet
Dan Talaycof6e76c02012-03-23 10:56:12 -07001003 @param egr_ports A single port or list of ports
Dan Talayco551befa2010-07-15 17:05:32 -07001004
1005 Run test with packet through switch from ing_port to egr_port
1006 See flow_match_test for parameter descriptions
1007 """
1008
Ed Swierk99a74de2012-08-22 06:40:54 -07001009 if wildcards is None:
1010 wildcards = required_wildcards(parent)
Rich Lane9a003812012-10-04 17:17:59 -07001011 logging.info("Pkt match test: " + str(ing_port) + " to " +
Dan Talaycof6e76c02012-03-23 10:56:12 -07001012 str(egr_ports))
Rich Laned0478ff2013-03-11 12:46:58 -07001013 logging.debug(" WC: " + hex(wildcards) + " vlan: " + str(vlan_vid))
Dan Talayco551befa2010-07-15 17:05:32 -07001014 if pkt is None:
Rich Laned0478ff2013-03-11 12:46:58 -07001015 pkt = simple_tcp_packet(dl_vlan_enable=(vlan_vid >= 0), vlan_vid=vlan_vid)
Rich Lanec41fbec2013-10-02 00:27:59 -07001016 if exp_pkt is None:
1017 exp_pkt = pkt
Dan Talayco551befa2010-07-15 17:05:32 -07001018
1019 request = flow_msg_create(parent, pkt, ing_port=ing_port,
Dan Talaycof6e76c02012-03-23 10:56:12 -07001020 wildcards=wildcards, egr_ports=egr_ports,
Dan Talayco551befa2010-07-15 17:05:32 -07001021 action_list=action_list)
1022
1023 flow_msg_install(parent, request)
1024
Rich Lane9a003812012-10-04 17:17:59 -07001025 logging.debug("Send packet: " + str(ing_port) + " to " +
Dan Talaycof6e76c02012-03-23 10:56:12 -07001026 str(egr_ports))
Dan Talayco551befa2010-07-15 17:05:32 -07001027 parent.dataplane.send(ing_port, str(pkt))
1028
Rich Lane8f45e2d2013-10-01 16:06:54 -07001029 exp_ports = [ing_port if port == ofp.OFPP_IN_PORT else port for port in egr_ports]
Rich Lanee4b384d2013-09-13 14:33:40 -07001030 verify_packets(parent, exp_pkt, exp_ports)
Dan Talayco551befa2010-07-15 17:05:32 -07001031
Rich Lane89725bb2012-12-03 16:23:27 -08001032def flow_match_test_pktout(parent, ing_port, egr_ports,
Rich Laned0478ff2013-03-11 12:46:58 -07001033 vlan_vid=-1, pkt=None, exp_pkt=None,
Rich Lane89725bb2012-12-03 16:23:27 -08001034 action_list=None):
1035 """
1036 Packet-out test on single TCP packet
1037 @param egr_ports A single port or list of ports
1038
1039 Run test sending packet-out to egr_ports. The goal is to test the actions
1040 taken on the packet, not the matching which is of course irrelevant.
1041 See flow_match_test for parameter descriptions
1042 """
1043
1044 if pkt is None:
Rich Laned0478ff2013-03-11 12:46:58 -07001045 pkt = simple_tcp_packet(dl_vlan_enable=(vlan_vid >= 0), vlan_vid=vlan_vid)
Rich Lanec41fbec2013-10-02 00:27:59 -07001046 if exp_pkt is None:
1047 exp_pkt = pkt
Rich Lane89725bb2012-12-03 16:23:27 -08001048
Rich Lanee717c6e2013-03-12 10:25:50 -07001049 msg = ofp.message.packet_out()
Rich Lane89725bb2012-12-03 16:23:27 -08001050 msg.in_port = ing_port
Rich Laneea8c4722013-04-04 15:30:20 -07001051 msg.buffer_id = 0xffffffff
Rich Lane89725bb2012-12-03 16:23:27 -08001052 msg.data = str(pkt)
1053 if action_list is not None:
1054 for act in action_list:
Rich Lanec495d9e2013-03-08 17:43:36 -08001055 msg.actions.append(act)
Rich Lane89725bb2012-12-03 16:23:27 -08001056
1057 # Set up output action
1058 if egr_ports is not None:
1059 for egr_port in egr_ports:
Rich Lanee717c6e2013-03-12 10:25:50 -07001060 act = ofp.action.output()
Rich Lane89725bb2012-12-03 16:23:27 -08001061 act.port = egr_port
Rich Lanec495d9e2013-03-08 17:43:36 -08001062 msg.actions.append(act)
Rich Lane89725bb2012-12-03 16:23:27 -08001063
1064 logging.debug(msg.show())
Rich Lane5c3151c2013-01-03 17:15:41 -08001065 parent.controller.message_send(msg)
Rich Lane89725bb2012-12-03 16:23:27 -08001066
Rich Lane8f45e2d2013-10-01 16:06:54 -07001067 exp_ports = [ing_port if port == ofp.OFPP_IN_PORT else port for port in egr_ports]
Rich Lanee4b384d2013-09-13 14:33:40 -07001068 verify_packets(parent, exp_pkt, exp_ports)
Rich Lane89725bb2012-12-03 16:23:27 -08001069
Dan Talaycof6e76c02012-03-23 10:56:12 -07001070def get_egr_list(parent, of_ports, how_many, exclude_list=[]):
1071 """
1072 Generate a list of ports avoiding those in the exclude list
Rich Lane9a003812012-10-04 17:17:59 -07001073 @param parent Supplies logging
Dan Talaycof6e76c02012-03-23 10:56:12 -07001074 @param of_ports List of OF port numbers
1075 @param how_many Number of ports to be added to the list
1076 @param exclude_list List of ports not to be used
1077 @returns An empty list if unable to find enough ports
1078 """
1079
Dan Talaycoc948d0b2012-03-23 12:17:54 -07001080 if how_many == 0:
1081 return []
1082
Dan Talaycof6e76c02012-03-23 10:56:12 -07001083 count = 0
1084 egr_ports = []
1085 for egr_idx in range(len(of_ports)):
1086 if of_ports[egr_idx] not in exclude_list:
1087 egr_ports.append(of_ports[egr_idx])
1088 count += 1
1089 if count >= how_many:
1090 return egr_ports
Rich Lane9a003812012-10-04 17:17:59 -07001091 logging.debug("Could not generate enough egress ports for test")
Dan Talaycof6e76c02012-03-23 10:56:12 -07001092 return []
1093
Rich Laned0478ff2013-03-11 12:46:58 -07001094def flow_match_test(parent, port_map, wildcards=None, vlan_vid=-1, pkt=None,
Rich Lanee5779d32012-10-05 17:56:04 -07001095 exp_pkt=None, action_list=None,
Dan Talaycoc948d0b2012-03-23 12:17:54 -07001096 max_test=0, egr_count=1, ing_port=False):
Dan Talayco551befa2010-07-15 17:05:32 -07001097 """
Rich Lane89725bb2012-12-03 16:23:27 -08001098 Run flow_match_test_port_pair on all port pairs and packet-out
Dan Talayco551befa2010-07-15 17:05:32 -07001099
1100 @param max_test If > 0 no more than this number of tests are executed.
1101 @param parent Must implement controller, dataplane, assertTrue, assertEqual
Rich Lane9a003812012-10-04 17:17:59 -07001102 and logging
Dan Talayco551befa2010-07-15 17:05:32 -07001103 @param pkt If not None, use this packet for ingress
1104 @param wildcards For flow match entry
Rich Laned0478ff2013-03-11 12:46:58 -07001105 @param vlan_vid If not -1, and pkt is None, create a pkt w/ VLAN tag
Dan Talayco551befa2010-07-15 17:05:32 -07001106 @param exp_pkt If not None, use this as the expected output pkt; els use pkt
1107 @param action_list Additional actions to add to flow mod
Dan Talaycocfa172f2012-03-23 12:03:00 -07001108 @param egr_count Number of egress ports; -1 means get from config w/ dflt 2
Dan Talayco551befa2010-07-15 17:05:32 -07001109 """
Ed Swierk99a74de2012-08-22 06:40:54 -07001110 if wildcards is None:
1111 wildcards = required_wildcards(parent)
Dan Talayco551befa2010-07-15 17:05:32 -07001112 of_ports = port_map.keys()
1113 of_ports.sort()
1114 parent.assertTrue(len(of_ports) > 1, "Not enough ports for test")
1115 test_count = 0
1116
Dan Talaycocfa172f2012-03-23 12:03:00 -07001117 if egr_count == -1:
Rich Lane2014f9b2012-10-05 15:29:40 -07001118 egr_count = test_param_get('egr_count', default=2)
Dan Talaycocfa172f2012-03-23 12:03:00 -07001119
Dan Talayco551befa2010-07-15 17:05:32 -07001120 for ing_idx in range(len(of_ports)):
1121 ingress_port = of_ports[ing_idx]
Dan Talaycof6e76c02012-03-23 10:56:12 -07001122 egr_ports = get_egr_list(parent, of_ports, egr_count,
1123 exclude_list=[ingress_port])
Dan Talaycoc948d0b2012-03-23 12:17:54 -07001124 if ing_port:
Rich Lanee717c6e2013-03-12 10:25:50 -07001125 egr_ports.append(ofp.OFPP_IN_PORT)
Dan Talaycof6e76c02012-03-23 10:56:12 -07001126 if len(egr_ports) == 0:
1127 parent.assertTrue(0, "Failed to generate egress port list")
1128
1129 flow_match_test_port_pair(parent, ingress_port, egr_ports,
Rich Laned0478ff2013-03-11 12:46:58 -07001130 wildcards=wildcards, vlan_vid=vlan_vid,
Dan Talaycof6e76c02012-03-23 10:56:12 -07001131 pkt=pkt, exp_pkt=exp_pkt,
Rich Lanee5779d32012-10-05 17:56:04 -07001132 action_list=action_list)
Dan Talaycof6e76c02012-03-23 10:56:12 -07001133 test_count += 1
1134 if (max_test > 0) and (test_count > max_test):
Rich Lane9a003812012-10-04 17:17:59 -07001135 logging.info("Ran " + str(test_count) + " tests; exiting")
Rich Lane89725bb2012-12-03 16:23:27 -08001136 break
1137
Ed Swierk38eea082013-01-02 19:46:20 -08001138 if not test_param_get('pktout_actions', default=True):
1139 return
Rich Lane89725bb2012-12-03 16:23:27 -08001140
1141 ingress_port = of_ports[0]
1142 egr_ports = get_egr_list(parent, of_ports, egr_count,
1143 exclude_list=[ingress_port])
1144 if ing_port:
Rich Lanee717c6e2013-03-12 10:25:50 -07001145 egr_ports.append(ofp.OFPP_IN_PORT)
Rich Lane89725bb2012-12-03 16:23:27 -08001146 flow_match_test_pktout(parent, ingress_port, egr_ports,
Rich Laned0478ff2013-03-11 12:46:58 -07001147 vlan_vid=vlan_vid,
Rich Lane89725bb2012-12-03 16:23:27 -08001148 pkt=pkt, exp_pkt=exp_pkt,
1149 action_list=action_list)
Dan Talayco551befa2010-07-15 17:05:32 -07001150
Rich Lane2014f9b2012-10-05 15:29:40 -07001151def test_param_get(key, default=None):
Dan Talayco4b2bee62010-07-20 14:10:05 -07001152 """
1153 Return value passed via test-params if present
1154
Dan Talayco4b2bee62010-07-20 14:10:05 -07001155 @param key The lookup key
1156 @param default Default value to use if not found
1157
1158 If the pair 'key=val' appeared in the string passed to --test-params
1159 on the command line, return val (as interpreted by exec). Otherwise
1160 return default value.
Dan Talaycof6e76c02012-03-23 10:56:12 -07001161
1162 WARNING: TEST PARAMETERS MUST BE PYTHON IDENTIFIERS;
1163 eg egr_count, not egr-count.
Dan Talayco4b2bee62010-07-20 14:10:05 -07001164 """
1165 try:
Rich Lanecd97d3d2013-01-07 18:50:06 -08001166 exec oftest.config["test_params"]
Dan Talayco4b2bee62010-07-20 14:10:05 -07001167 except:
1168 return default
1169
Dan Talayco4b2bee62010-07-20 14:10:05 -07001170 try:
Rich Lanefdec0fb2013-08-09 18:01:05 -07001171 return eval(str(key))
Dan Talayco4b2bee62010-07-20 14:10:05 -07001172 except:
1173 return default
1174
1175def action_generate(parent, field_to_mod, mod_field_vals):
1176 """
1177 Create an action to modify the field indicated in field_to_mod
1178
1179 @param parent Must implement, assertTrue
1180 @param field_to_mod The field to modify as a string name
1181 @param mod_field_vals Hash of values to use for modified values
1182 """
1183
1184 act = None
1185
1186 if field_to_mod in ['pktlen']:
1187 return None
1188
Rich Laned0478ff2013-03-11 12:46:58 -07001189 if field_to_mod == 'eth_dst':
Rich Lanee717c6e2013-03-12 10:25:50 -07001190 act = ofp.action.set_dl_dst()
Rich Lanef6883512013-03-11 17:00:09 -07001191 act.dl_addr = oftest.parse.parse_mac(mod_field_vals['eth_dst'])
Rich Laned0478ff2013-03-11 12:46:58 -07001192 elif field_to_mod == 'eth_src':
Rich Lanee717c6e2013-03-12 10:25:50 -07001193 act = ofp.action.set_dl_src()
Rich Lanef6883512013-03-11 17:00:09 -07001194 act.dl_addr = oftest.parse.parse_mac(mod_field_vals['eth_src'])
Dan Talayco4b2bee62010-07-20 14:10:05 -07001195 elif field_to_mod == 'dl_vlan_enable':
1196 if not mod_field_vals['dl_vlan_enable']: # Strip VLAN tag
Rich Lanee717c6e2013-03-12 10:25:50 -07001197 act = ofp.action.strip_vlan()
Rich Laned0478ff2013-03-11 12:46:58 -07001198 # Add VLAN tag is handled by vlan_vid field
Dan Talayco4b2bee62010-07-20 14:10:05 -07001199 # Will return None in this case
Rich Laned0478ff2013-03-11 12:46:58 -07001200 elif field_to_mod == 'vlan_vid':
Rich Lanee717c6e2013-03-12 10:25:50 -07001201 act = ofp.action.set_vlan_vid()
Rich Laned0478ff2013-03-11 12:46:58 -07001202 act.vlan_vid = mod_field_vals['vlan_vid']
1203 elif field_to_mod == 'vlan_pcp':
Rich Lanee717c6e2013-03-12 10:25:50 -07001204 act = ofp.action.set_vlan_pcp()
Rich Laned0478ff2013-03-11 12:46:58 -07001205 act.vlan_pcp = mod_field_vals['vlan_pcp']
Dan Talayco4b2bee62010-07-20 14:10:05 -07001206 elif field_to_mod == 'ip_src':
Rich Lanee717c6e2013-03-12 10:25:50 -07001207 act = ofp.action.set_nw_src()
Rich Lanef6883512013-03-11 17:00:09 -07001208 act.nw_addr = oftest.parse.parse_ip(mod_field_vals['ip_src'])
Dan Talayco4b2bee62010-07-20 14:10:05 -07001209 elif field_to_mod == 'ip_dst':
Rich Lanee717c6e2013-03-12 10:25:50 -07001210 act = ofp.action.set_nw_dst()
Rich Lanef6883512013-03-11 17:00:09 -07001211 act.nw_addr = oftest.parse.parse_ip(mod_field_vals['ip_dst'])
Dan Talayco4b2bee62010-07-20 14:10:05 -07001212 elif field_to_mod == 'ip_tos':
Rich Lanee717c6e2013-03-12 10:25:50 -07001213 act = ofp.action.set_nw_tos()
Dan Talayco4b2bee62010-07-20 14:10:05 -07001214 act.nw_tos = mod_field_vals['ip_tos']
1215 elif field_to_mod == 'tcp_sport':
Rich Lanee717c6e2013-03-12 10:25:50 -07001216 act = ofp.action.set_tp_src()
Dan Talayco4b2bee62010-07-20 14:10:05 -07001217 act.tp_port = mod_field_vals['tcp_sport']
1218 elif field_to_mod == 'tcp_dport':
Rich Lanee717c6e2013-03-12 10:25:50 -07001219 act = ofp.action.set_tp_dst()
Dan Talayco4b2bee62010-07-20 14:10:05 -07001220 act.tp_port = mod_field_vals['tcp_dport']
Rich Lane110e0e32012-10-26 16:21:46 -07001221 elif field_to_mod == 'udp_sport':
Rich Lanee717c6e2013-03-12 10:25:50 -07001222 act = ofp.action.set_tp_src()
Rich Lane110e0e32012-10-26 16:21:46 -07001223 act.tp_port = mod_field_vals['udp_sport']
1224 elif field_to_mod == 'udp_dport':
Rich Lanee717c6e2013-03-12 10:25:50 -07001225 act = ofp.action.set_tp_dst()
Rich Lane110e0e32012-10-26 16:21:46 -07001226 act.tp_port = mod_field_vals['udp_dport']
Dan Talayco4b2bee62010-07-20 14:10:05 -07001227 else:
1228 parent.assertTrue(0, "Unknown field to modify: " + str(field_to_mod))
1229
1230 return act
1231
1232def pkt_action_setup(parent, start_field_vals={}, mod_field_vals={},
Rich Lane110e0e32012-10-26 16:21:46 -07001233 mod_fields=[], tp="tcp", check_test_params=False):
Dan Talayco4b2bee62010-07-20 14:10:05 -07001234 """
1235 Set up the ingress and expected packet and action list for a test
1236
Rich Lane2014f9b2012-10-05 15:29:40 -07001237 @param parent Must implement assertTrue
Dan Talayco4b2bee62010-07-20 14:10:05 -07001238 @param start_field_values Field values to use for ingress packet (optional)
1239 @param mod_field_values Field values to use for modified packet (optional)
1240 @param mod_fields The list of fields to be modified by the switch in the test.
1241 @params check_test_params If True, will check the parameters vid, add_vlan
1242 and strip_vlan from the command line.
1243
1244 Returns a triple: pkt-to-send, expected-pkt, action-list
1245 """
1246
1247 new_actions = []
1248
Dan Talayco4b2bee62010-07-20 14:10:05 -07001249 base_pkt_params = {}
1250 base_pkt_params['pktlen'] = 100
Rich Laned0478ff2013-03-11 12:46:58 -07001251 base_pkt_params['eth_dst'] = '00:DE:F0:12:34:56'
1252 base_pkt_params['eth_src'] = '00:23:45:67:89:AB'
Dan Talayco4b2bee62010-07-20 14:10:05 -07001253 base_pkt_params['dl_vlan_enable'] = False
Rich Laned0478ff2013-03-11 12:46:58 -07001254 base_pkt_params['vlan_vid'] = 2
1255 base_pkt_params['vlan_pcp'] = 0
Dan Talayco4b2bee62010-07-20 14:10:05 -07001256 base_pkt_params['ip_src'] = '192.168.0.1'
1257 base_pkt_params['ip_dst'] = '192.168.0.2'
1258 base_pkt_params['ip_tos'] = 0
Rich Lane110e0e32012-10-26 16:21:46 -07001259 if tp == "tcp":
1260 base_pkt_params['tcp_sport'] = 1234
1261 base_pkt_params['tcp_dport'] = 80
1262 elif tp == "udp":
1263 base_pkt_params['udp_sport'] = 1234
1264 base_pkt_params['udp_dport'] = 80
Dan Talayco4b2bee62010-07-20 14:10:05 -07001265 for keyname in start_field_vals.keys():
1266 base_pkt_params[keyname] = start_field_vals[keyname]
1267
1268 mod_pkt_params = {}
1269 mod_pkt_params['pktlen'] = 100
Rich Laned0478ff2013-03-11 12:46:58 -07001270 mod_pkt_params['eth_dst'] = '00:21:0F:ED:CB:A9'
1271 mod_pkt_params['eth_src'] = '00:ED:CB:A9:87:65'
Dan Talayco4b2bee62010-07-20 14:10:05 -07001272 mod_pkt_params['dl_vlan_enable'] = False
Rich Laned0478ff2013-03-11 12:46:58 -07001273 mod_pkt_params['vlan_vid'] = 3
1274 mod_pkt_params['vlan_pcp'] = 7
Dan Talayco4b2bee62010-07-20 14:10:05 -07001275 mod_pkt_params['ip_src'] = '10.20.30.40'
1276 mod_pkt_params['ip_dst'] = '50.60.70.80'
1277 mod_pkt_params['ip_tos'] = 0xf0
Rich Lane110e0e32012-10-26 16:21:46 -07001278 if tp == "tcp":
1279 mod_pkt_params['tcp_sport'] = 4321
1280 mod_pkt_params['tcp_dport'] = 8765
1281 elif tp == "udp":
1282 mod_pkt_params['udp_sport'] = 4321
1283 mod_pkt_params['udp_dport'] = 8765
Dan Talayco4b2bee62010-07-20 14:10:05 -07001284 for keyname in mod_field_vals.keys():
1285 mod_pkt_params[keyname] = mod_field_vals[keyname]
1286
1287 # Check for test param modifications
1288 strip = False
1289 if check_test_params:
Rich Lane2014f9b2012-10-05 15:29:40 -07001290 add_vlan = test_param_get('add_vlan')
1291 strip_vlan = test_param_get('strip_vlan')
1292 vid = test_param_get('vid')
Dan Talayco4b2bee62010-07-20 14:10:05 -07001293
1294 if add_vlan and strip_vlan:
1295 parent.assertTrue(0, "Add and strip VLAN both specified")
1296
1297 if vid:
1298 base_pkt_params['dl_vlan_enable'] = True
Rich Laned0478ff2013-03-11 12:46:58 -07001299 base_pkt_params['vlan_vid'] = vid
1300 if 'vlan_vid' in mod_fields:
1301 mod_pkt_params['vlan_vid'] = vid + 1
Dan Talayco4b2bee62010-07-20 14:10:05 -07001302
1303 if add_vlan:
1304 base_pkt_params['dl_vlan_enable'] = False
1305 mod_pkt_params['dl_vlan_enable'] = True
1306 mod_pkt_params['pktlen'] = base_pkt_params['pktlen'] + 4
1307 mod_fields.append('pktlen')
1308 mod_fields.append('dl_vlan_enable')
Rich Laned0478ff2013-03-11 12:46:58 -07001309 if 'vlan_vid' not in mod_fields:
1310 mod_fields.append('vlan_vid')
Dan Talayco4b2bee62010-07-20 14:10:05 -07001311 elif strip_vlan:
1312 base_pkt_params['dl_vlan_enable'] = True
1313 mod_pkt_params['dl_vlan_enable'] = False
1314 mod_pkt_params['pktlen'] = base_pkt_params['pktlen'] - 4
1315 mod_fields.append('dl_vlan_enable')
1316 mod_fields.append('pktlen')
1317
Rich Lane110e0e32012-10-26 16:21:46 -07001318 if tp == "tcp":
1319 packet_builder = simple_tcp_packet
1320 elif tp == "udp":
1321 packet_builder = simple_udp_packet
1322 else:
1323 raise NotImplementedError("unknown transport protocol %s" % tp)
1324
Dan Talayco4b2bee62010-07-20 14:10:05 -07001325 # Build the ingress packet
Rich Lane110e0e32012-10-26 16:21:46 -07001326 ingress_pkt = packet_builder(**base_pkt_params)
Dan Talayco4b2bee62010-07-20 14:10:05 -07001327
1328 # Build the expected packet, modifying the indicated fields
1329 for item in mod_fields:
1330 base_pkt_params[item] = mod_pkt_params[item]
1331 act = action_generate(parent, item, mod_pkt_params)
1332 if act:
1333 new_actions.append(act)
1334
Rich Lane110e0e32012-10-26 16:21:46 -07001335 expected_pkt = packet_builder(**base_pkt_params)
Dan Talayco4b2bee62010-07-20 14:10:05 -07001336
1337 return (ingress_pkt, expected_pkt, new_actions)
Dan Talayco677c0b72011-08-23 22:53:38 -07001338
1339# Generate a simple "drop" flow mod
1340# If in_band is true, then only drop from first test port
1341def flow_mod_gen(port_map, in_band):
Rich Lanee717c6e2013-03-12 10:25:50 -07001342 request = ofp.message.flow_add()
1343 request.match.wildcards = ofp.OFPFW_ALL
Dan Talayco677c0b72011-08-23 22:53:38 -07001344 if in_band:
Rich Lanee717c6e2013-03-12 10:25:50 -07001345 request.match.wildcards = ofp.OFPFW_ALL - ofp.OFPFW_IN_PORT
Dan Talayco677c0b72011-08-23 22:53:38 -07001346 for of_port, ifname in port_map.items(): # Grab first port
1347 break
1348 request.match.in_port = of_port
1349 request.buffer_id = 0xffffffff
1350 return request
Dan Talaycoba3745c2010-07-21 21:51:08 -07001351
1352def skip_message_emit(parent, s):
1353 """
1354 Print out a 'skipped' message to stderr
1355
1356 @param s The string to print out to the log file
Dan Talaycoba3745c2010-07-21 21:51:08 -07001357 """
1358 global skipped_test_count
1359
1360 skipped_test_count += 1
Rich Lane9a003812012-10-04 17:17:59 -07001361 logging.info("Skipping: " + s)
Dan Talayco2940fdd2013-02-06 15:01:35 -08001362 if oftest.config["debug"] < logging.WARNING:
Dan Talaycoba3745c2010-07-21 21:51:08 -07001363 sys.stderr.write("(skipped) ")
1364 else:
1365 sys.stderr.write("(S)")
Dan Talayco677c0b72011-08-23 22:53:38 -07001366
Dan Talayco8a64e332012-03-28 14:53:20 -07001367
1368def all_stats_get(parent):
1369 """
1370 Get the aggregate stats for all flows in the table
1371 @param parent Test instance with controller connection and assert
1372 @returns dict with keys flows, packets, bytes, active (flows),
1373 lookups, matched
1374 """
Rich Lanee717c6e2013-03-12 10:25:50 -07001375 stat_req = ofp.message.aggregate_stats_request()
1376 stat_req.match = ofp.match()
1377 stat_req.match.wildcards = ofp.OFPFW_ALL
Dan Talayco8a64e332012-03-28 14:53:20 -07001378 stat_req.table_id = 0xff
Rich Lanee717c6e2013-03-12 10:25:50 -07001379 stat_req.out_port = ofp.OFPP_NONE
Dan Talayco8a64e332012-03-28 14:53:20 -07001380
1381 rv = {}
1382
Rich Lanec8aaa3e2012-07-26 19:28:02 -07001383 (reply, pkt) = parent.controller.transact(stat_req)
Rich Lane5fd6faf2013-03-11 13:30:20 -07001384 parent.assertTrue(len(reply.entries) == 1, "Did not receive flow stats reply")
Dan Talayco8a64e332012-03-28 14:53:20 -07001385
Rich Lane5fd6faf2013-03-11 13:30:20 -07001386 for obj in reply.entries:
Dan Talayco8a64e332012-03-28 14:53:20 -07001387 (rv["flows"], rv["packets"], rv["bytes"]) = (obj.flow_count,
1388 obj.packet_count, obj.byte_count)
1389 break
1390
Rich Lanee717c6e2013-03-12 10:25:50 -07001391 request = ofp.message.table_stats_request()
Rich Lanec8aaa3e2012-07-26 19:28:02 -07001392 (reply , pkt) = parent.controller.transact(request)
Dan Talayco8a64e332012-03-28 14:53:20 -07001393
1394
1395 (rv["active"], rv["lookups"], rv["matched"]) = (0,0,0)
Rich Lane5fd6faf2013-03-11 13:30:20 -07001396 for obj in reply.entries:
Dan Talayco8a64e332012-03-28 14:53:20 -07001397 rv["active"] += obj.active_count
1398 rv["lookups"] += obj.lookup_count
1399 rv["matched"] += obj.matched_count
1400
1401 return rv
Dan Talayco2baf8b52012-03-30 09:55:42 -07001402
Rich Lane7744e112013-01-11 17:23:57 -08001403_import_blacklist.add('FILTER')
Dan Talayco2baf8b52012-03-30 09:55:42 -07001404FILTER=''.join([(len(repr(chr(x)))==3) and chr(x) or '.'
1405 for x in range(256)])
1406
1407def hex_dump_buffer(src, length=16):
1408 """
1409 Convert src to a hex dump string and return the string
1410 @param src The source buffer
1411 @param length The number of bytes shown in each line
1412 @returns A string showing the hex dump
1413 """
Dan Talaycoc516fa02012-04-12 22:28:43 -07001414 result = ["\n"]
Dan Talayco2baf8b52012-03-30 09:55:42 -07001415 for i in xrange(0, len(src), length):
1416 chars = src[i:i+length]
1417 hex = ' '.join(["%02x" % ord(x) for x in chars])
1418 printable = ''.join(["%s" % ((ord(x) <= 127 and
1419 FILTER[ord(x)]) or '.') for x in chars])
1420 result.append("%04x %-*s %s\n" % (i, length*3, hex, printable))
1421 return ''.join(result)
1422
1423def format_packet(pkt):
1424 return "Packet length %d \n%s" % (len(str(pkt)),
1425 hex_dump_buffer(str(pkt)))
Rich Lane5d7e89a2012-10-26 16:43:13 -07001426
1427def inspect_packet(pkt):
1428 """
1429 Wrapper around scapy's show() method.
1430 @returns A string showing the dissected packet.
1431 """
1432 from cStringIO import StringIO
1433 out = None
1434 backup = sys.stdout
1435 try:
Rich Lanefdec0fb2013-08-09 18:01:05 -07001436 tmp = StringIO()
1437 sys.stdout = tmp
Rich Lane5d7e89a2012-10-26 16:43:13 -07001438 pkt.show2()
Rich Lanefdec0fb2013-08-09 18:01:05 -07001439 out = tmp.getvalue()
1440 tmp.close()
Rich Lane5d7e89a2012-10-26 16:43:13 -07001441 finally:
1442 sys.stdout = backup
1443 return out
Rich Lane0a4f6372013-01-02 14:40:22 -08001444
1445def nonstandard(cls):
1446 """
Rich Lanecc45b8e2013-01-02 15:55:02 -08001447 Testcase decorator that marks the test as being non-standard.
1448 These tests are not automatically added to the "standard" group.
Rich Lane0a4f6372013-01-02 14:40:22 -08001449 """
Rich Lanecc45b8e2013-01-02 15:55:02 -08001450 cls._nonstandard = True
Rich Lane0a4f6372013-01-02 14:40:22 -08001451 return cls
1452
1453def disabled(cls):
1454 """
Rich Lanecc45b8e2013-01-02 15:55:02 -08001455 Testcase decorator that marks the test as being disabled.
1456 These tests are not automatically added to the "standard" group or
1457 their module's group.
Rich Lane0a4f6372013-01-02 14:40:22 -08001458 """
Rich Lanecc45b8e2013-01-02 15:55:02 -08001459 cls._disabled = True
Rich Lane0a4f6372013-01-02 14:40:22 -08001460 return cls
Rich Lane97e99652013-01-02 17:23:20 -08001461
1462def group(name):
1463 """
1464 Testcase decorator that adds the test to a group.
1465 """
1466 def fn(cls):
1467 if not hasattr(cls, "_groups"):
1468 cls._groups = []
1469 cls._groups.append(name)
1470 return cls
1471 return fn
Rich Lane5a9a1922013-01-11 14:29:30 -08001472
1473def version(ver):
1474 """
1475 Testcase decorator that specifies which versions of OpenFlow the test
1476 supports. The default is 1.0+. This decorator may only be used once.
1477
1478 Supported syntax:
1479 1.0 -> 1.0
1480 1.0,1.2,1.3 -> 1.0, 1.2, 1.3
1481 1.0+ -> 1.0, 1.1, 1.2, 1.3
1482 """
1483 versions = parse_version(ver)
1484 def fn(cls):
1485 cls._versions = versions
1486 return cls
1487 return fn
1488
1489def parse_version(ver):
1490 allowed_versions = ["1.0", "1.1", "1.2", "1.3"]
1491 if re.match("^1\.\d+$", ver):
1492 versions = set([ver])
1493 elif re.match("^(1\.\d+)\+$", ver):
1494 if not ver[:-1] in allowed_versions:
1495 raise ValueError("invalid OpenFlow version %s" % ver[:-1])
1496 versions = set()
1497 if ver != "1.1+": versions.add("1.0")
1498 if ver != "1.2+": versions.add("1.1")
1499 if ver != "1.3+": versions.add("1.2")
1500 versions.add("1.3")
1501 else:
1502 versions = set(ver.split(','))
1503
1504 for version in versions:
1505 if not version in allowed_versions:
1506 raise ValueError("invalid OpenFlow version %s" % version)
1507
1508 return versions
1509
1510assert(parse_version("1.0") == set(["1.0"]))
1511assert(parse_version("1.0,1.2,1.3") == set(["1.0", "1.2", "1.3"]))
1512assert(parse_version("1.0+") == set(["1.0", "1.1", "1.2", "1.3"]))
Rich Lane7744e112013-01-11 17:23:57 -08001513
Rich Laneae3428c2013-03-07 14:37:42 -08001514def get_stats(test, req):
1515 """
1516 Retrieve a list of stats entries. Handles OFPSF_REPLY_MORE.
1517 """
Rich Lane609194f2013-10-21 06:17:37 -07001518 msgtype = ofp.OFPT_STATS_REPLY
1519 more_flag = ofp.OFPSF_REPLY_MORE
Rich Laneae3428c2013-03-07 14:37:42 -08001520 stats = []
1521 reply, _ = test.controller.transact(req)
1522 test.assertTrue(reply is not None, "No response to stats request")
Rich Lane34c68d52013-10-11 10:38:21 -07001523 test.assertEquals(reply.type, msgtype, "Response had unexpected message type")
Rich Lane5fd6faf2013-03-11 13:30:20 -07001524 stats.extend(reply.entries)
Rich Lanebd56ed62013-07-10 15:49:44 -07001525 while reply.flags & more_flag != 0:
Rich Lane34c68d52013-10-11 10:38:21 -07001526 reply, pkt = test.controller.poll(exp_msg=msgtype)
Rich Laneae3428c2013-03-07 14:37:42 -08001527 test.assertTrue(reply is not None, "No response to stats request")
Rich Lane5fd6faf2013-03-11 13:30:20 -07001528 stats.extend(reply.entries)
Rich Laneae3428c2013-03-07 14:37:42 -08001529 return stats
1530
Rich Lanebd56ed62013-07-10 15:49:44 -07001531def get_flow_stats(test, match, table_id=None,
1532 out_port=None, out_group=None,
1533 cookie=0, cookie_mask=0):
Rich Laneae3428c2013-03-07 14:37:42 -08001534 """
1535 Retrieve a list of flow stats entries.
1536 """
Rich Lanebd56ed62013-07-10 15:49:44 -07001537
1538 if table_id == None:
1539 if ofp.OFP_VERSION <= 2:
1540 table_id = 0xff
1541 else:
1542 table_id = ofp.OFPTT_ALL
1543
Rich Lanef3bc48c2013-05-03 17:39:35 -07001544 if out_port == None:
Rich Lanebd56ed62013-07-10 15:49:44 -07001545 if ofp.OFP_VERSION == 1:
1546 out_port = ofp.OFPP_NONE
1547 else:
1548 out_port = ofp.OFPP_ANY
1549
1550 if out_group == None:
1551 if ofp.OFP_VERSION > 1:
1552 out_group = ofp.OFPP_ANY
1553
Rich Lanee717c6e2013-03-12 10:25:50 -07001554 req = ofp.message.flow_stats_request(match=match,
Rich Lanebd56ed62013-07-10 15:49:44 -07001555 table_id=table_id,
1556 out_port=out_port)
1557 if ofp.OFP_VERSION > 1:
1558 req.out_group = out_group
1559 req.cookie = cookie
1560 req.cookie_mask = cookie_mask
1561
Rich Laneae3428c2013-03-07 14:37:42 -08001562 return get_stats(test, req)
1563
Rich Lane968b6192013-03-07 15:34:43 -08001564def get_port_stats(test, port_no):
1565 """
1566 Retrieve a list of port stats entries.
1567 """
Rich Lanee717c6e2013-03-12 10:25:50 -07001568 req = ofp.message.port_stats_request(port_no=port_no)
Rich Lane968b6192013-03-07 15:34:43 -08001569 return get_stats(test, req)
1570
Rich Lane6a334922013-03-07 16:14:52 -08001571def get_queue_stats(test, port_no, queue_id):
1572 """
1573 Retrieve a list of queue stats entries.
1574 """
Rich Lanee717c6e2013-03-12 10:25:50 -07001575 req = ofp.message.queue_stats_request(port_no=port_no, queue_id=queue_id)
Rich Lane6a334922013-03-07 16:14:52 -08001576 return get_stats(test, req)
1577
Rich Laneae3428c2013-03-07 14:37:42 -08001578def verify_flow_stats(test, match, table_id=0xff,
Rich Laneae3428c2013-03-07 14:37:42 -08001579 initial=[],
1580 pkts=None, bytes=None):
1581 """
1582 Verify that flow stats changed as expected.
1583
1584 Optionally takes an 'initial' list of stats entries, as returned by
1585 get_flow_stats(). If 'initial' is not given the counters are assumed to
1586 begin at 0.
1587 """
Rich Lanef3bc48c2013-05-03 17:39:35 -07001588
Rich Laneae3428c2013-03-07 14:37:42 -08001589 def accumulate(stats):
1590 pkts_acc = bytes_acc = 0
1591 for stat in stats:
1592 pkts_acc += stat.packet_count
1593 bytes_acc += stat.byte_count
1594 return (pkts_acc, bytes_acc)
1595
1596 pkts_before, bytes_before = accumulate(initial)
1597
1598 # Wait 10s for counters to update
1599 pkt_diff = byte_diff = None
1600 for i in range(0, 100):
Rich Lane61edad52014-03-28 16:25:08 -07001601 stats = get_flow_stats(test, match, table_id=table_id)
Rich Laneae3428c2013-03-07 14:37:42 -08001602 pkts_after, bytes_after = accumulate(stats)
1603 pkt_diff = pkts_after - pkts_before
1604 byte_diff = bytes_after - bytes_before
1605 if (pkts == None or pkt_diff >= pkts) and \
1606 (bytes == None or byte_diff >= bytes):
1607 break
Dan Talayco53724732013-03-08 23:54:02 -08001608 time.sleep(0.1)
Rich Laneae3428c2013-03-07 14:37:42 -08001609
1610 if pkts != None:
1611 test.assertEquals(pkt_diff, pkts, "Flow packet counter not updated properly (expected increase of %d, got increase of %d)" % (pkts, pkt_diff))
1612
1613 if bytes != None:
Rich Lane53b96812013-03-07 16:54:50 -08001614 test.assertTrue(byte_diff >= bytes and byte_diff <= bytes*1.1,
1615 "Flow byte counter not updated properly (expected increase of %d, got increase of %d)" % (bytes, byte_diff))
Rich Laneae3428c2013-03-07 14:37:42 -08001616
Rich Lane968b6192013-03-07 15:34:43 -08001617def verify_port_stats(test, port,
1618 initial=[],
1619 tx_pkts=None, rx_pkts=None,
1620 tx_bytes=None, rx_bytes=None):
1621 """
1622 Verify that port stats changed as expected.
1623
1624 Optionally takes an 'initial' list of stats entries, as returned by
1625 get_port_stats(). If 'initial' is not given the counters are assumed to
1626 begin at 0.
1627 """
1628 def accumulate(stats):
1629 tx_pkts_acc = rx_pkts_acc = tx_bytes_acc = rx_bytes_acc = 0
1630 for stat in stats:
1631 tx_pkts_acc += stat.tx_packets
1632 rx_pkts_acc += stat.rx_packets
1633 tx_bytes_acc += stat.tx_bytes
1634 rx_bytes_acc += stat.rx_bytes
1635 return (tx_pkts_acc, rx_pkts_acc, tx_bytes_acc, rx_bytes_acc)
1636
1637 tx_pkts_before, rx_pkts_before, \
1638 tx_bytes_before, rx_bytes_before = accumulate(initial)
1639
1640 # Wait 10s for counters to update
1641 for i in range(0, 100):
1642 stats = get_port_stats(test, port)
1643 tx_pkts_after, rx_pkts_after, \
1644 tx_bytes_after, rx_bytes_after = accumulate(stats)
1645 tx_pkts_diff = tx_pkts_after - tx_pkts_before
1646 rx_pkts_diff = rx_pkts_after - rx_pkts_before
1647 tx_bytes_diff = tx_bytes_after - tx_bytes_before
1648 rx_bytes_diff = rx_bytes_after - rx_bytes_before
Rich Lane3a208f82015-04-10 12:37:57 -07001649 if (tx_pkts == None or tx_pkts <= tx_pkts_diff) and \
1650 (rx_pkts == None or rx_pkts <= rx_pkts_diff) and \
Rich Lane53b96812013-03-07 16:54:50 -08001651 (tx_bytes == None or tx_bytes <= tx_bytes_diff) and \
1652 (rx_bytes == None or rx_bytes <= rx_bytes_diff):
Rich Lane968b6192013-03-07 15:34:43 -08001653 break
1654 time.sleep(0.1)
1655
1656 if (tx_pkts != None):
Rich Lane3a208f82015-04-10 12:37:57 -07001657 test.assertGreaterEqual(tx_pkts_diff, tx_pkts,
1658 "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 -08001659 if (rx_pkts != None):
Rich Lane3a208f82015-04-10 12:37:57 -07001660 test.assertGreaterEqual(rx_pkts_diff, rx_pkts,
1661 "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 -08001662 if (tx_bytes != None):
Rich Lane3a208f82015-04-10 12:37:57 -07001663 test.assertGreaterEqual(tx_bytes_diff, tx_bytes,
1664 "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 -08001665 if (rx_bytes != None):
Rich Lane3a208f82015-04-10 12:37:57 -07001666 test.assertGreaterEqual(rx_bytes_diff, rx_bytes,
1667 "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 -08001668
Rich Lane6a334922013-03-07 16:14:52 -08001669def verify_queue_stats(test, port_no, queue_id,
1670 initial=[],
1671 pkts=None, bytes=None):
1672 """
1673 Verify that queue stats changed as expected.
1674
1675 Optionally takes an 'initial' list of stats entries, as returned by
1676 get_queue_stats(). If 'initial' is not given the counters are assumed to
1677 begin at 0.
1678 """
1679 def accumulate(stats):
1680 pkts_acc = bytes_acc = 0
1681 for stat in stats:
1682 pkts_acc += stat.tx_packets
1683 bytes_acc += stat.tx_bytes
1684 return (pkts_acc, bytes_acc)
1685
1686 pkts_before, bytes_before = accumulate(initial)
1687
1688 # Wait 10s for counters to update
1689 pkt_diff = byte_diff = None
1690 for i in range(0, 100):
1691 stats = get_queue_stats(test, port_no, queue_id)
1692 pkts_after, bytes_after = accumulate(stats)
1693 pkt_diff = pkts_after - pkts_before
1694 byte_diff = bytes_after - bytes_before
1695 if (pkts == None or pkt_diff >= pkts) and \
1696 (bytes == None or byte_diff >= bytes):
1697 break
Dan Talayco53724732013-03-08 23:54:02 -08001698 time.sleep(0.1)
Rich Lane6a334922013-03-07 16:14:52 -08001699
1700 if pkts != None:
1701 test.assertEquals(pkt_diff, pkts, "Queue packet counter not updated properly (expected increase of %d, got increase of %d)" % (pkts, pkt_diff))
1702
1703 if bytes != None:
Rich Lane53b96812013-03-07 16:54:50 -08001704 test.assertTrue(byte_diff >= bytes and byte_diff <= bytes*1.1,
1705 "Queue byte counter not updated properly (expected increase of %d, got increase of %d)" % (bytes, byte_diff))
Rich Laneae3428c2013-03-07 14:37:42 -08001706
Rich Lane4c504f32013-06-07 17:24:14 -07001707def packet_in_match(msg, data, in_port=None, reason=None):
1708 """
1709 Check whether the packet_in message 'msg' has fields matching 'data',
1710 'in_port', and 'reason'.
1711
1712 This function handles truncated packet_in data. The 'in_port' and 'reason'
1713 parameters are optional.
1714
1715 @param msg packet_in message
1716 @param data Expected packet_in data
1717 @param in_port Expected packet_in in_port, or None
1718 @param reason Expected packet_in reason, or None
1719 """
1720
Rich Lanec0d26dd2013-07-10 12:46:03 -07001721 if ofp.OFP_VERSION <= 2:
1722 pkt_in_port = msg.in_port
1723 else:
1724 oxms = { type(oxm): oxm for oxm in msg.match.oxm_list }
1725 if ofp.oxm.in_port in oxms:
1726 pkt_in_port = oxms[ofp.oxm.in_port].value
1727 else:
1728 logging.warn("Missing in_port in packet-in message")
1729 pkt_in_port = None
1730
1731 if in_port != None and in_port != pkt_in_port:
Rich Lane9f2f17e2013-09-13 13:19:37 -07001732 logging.debug("Incorrect packet_in in_port (expected %d, received %d)", in_port, pkt_in_port)
Rich Lane4c504f32013-06-07 17:24:14 -07001733 return False
1734
Rich Lanec0d26dd2013-07-10 12:46:03 -07001735 if reason != None and reason != msg.reason:
Rich Lane4c504f32013-06-07 17:24:14 -07001736 logging.debug("Incorrect packet_in reason (expected %d, received %d)", reason, msg.reason)
1737 return False
1738
1739 # Check that one of the packets is a prefix of the other.
1740 # The received packet may be either truncated or padded, but not both.
1741 # (Some of the padding may be truncated but that's irrelevant). We
1742 # need to check that the smaller packet is a prefix of the larger one.
1743 # Note that this check succeeds if the switch sends a zero-length
1744 # packet-in.
1745 compare_len = min(len(msg.data), len(data))
1746 if data[:compare_len] != msg.data[:compare_len]:
1747 logging.debug("Incorrect packet_in data")
1748 logging.debug("Expected %s" % format_packet(data[:compare_len]))
1749 logging.debug("Received %s" % format_packet(msg.data[:compare_len]))
1750 return False
1751
1752 return True
1753
1754def verify_packet_in(test, data, in_port, reason, controller=None):
1755 """
1756 Assert that the controller receives a packet_in message matching data 'data'
1757 from port 'in_port' with reason 'reason'. Does not trigger the packet_in
1758 itself, that's up to the test case.
1759
1760 @param test Instance of base_tests.SimpleProtocol
1761 @param pkt String to expect as the packet_in data
1762 @param in_port OpenFlow port number to expect as the packet_in in_port
1763 @param reason One of OFPR_* to expect as the packet_in reason
1764 @param controller Controller instance, defaults to test.controller
1765 @returns The received packet-in message
1766 """
1767
1768 if controller == None:
1769 controller = test.controller
1770
1771 end_time = time.time() + oftest.ofutils.default_timeout
1772
1773 while True:
1774 msg, _ = controller.poll(ofp.OFPT_PACKET_IN, end_time - time.time())
1775 if not msg:
1776 # Timeout
1777 break
1778 elif packet_in_match(msg, data, in_port, reason):
1779 # Found a matching message
1780 break
1781
Kiran Poola58c5c042014-05-15 15:11:06 -07001782 test.assertTrue(msg is not None, 'Packet in message not received on port %r' % in_port)
Rich Lane4c504f32013-06-07 17:24:14 -07001783 return msg
1784
1785def verify_no_packet_in(test, data, in_port, controller=None):
1786 """
1787 Assert that the controller does not receive a packet_in message matching
1788 data 'data' from port 'in_port'.
1789
1790 @param test Instance of base_tests.SimpleProtocol
1791 @param pkt String to expect as the packet_in data
1792 @param in_port OpenFlow port number to expect as the packet_in in_port
1793 @param controller Controller instance, defaults to test.controller
1794 """
1795
1796 if controller == None:
1797 controller = test.controller
1798
1799 # Negative test, need to wait a short amount of time before checking we
1800 # didn't receive the message.
Rich Lane48f6aed2014-03-23 15:51:02 -07001801 time.sleep(oftest.ofutils.default_negative_timeout)
Rich Lane4c504f32013-06-07 17:24:14 -07001802
1803 # Check every packet_in queued in the controller
1804 while True:
1805 msg, _ = controller.poll(ofp.OFPT_PACKET_IN, timeout=0)
1806 if msg == None:
1807 # No more queued packet_in messages
1808 break
1809 elif packet_in_match(msg, data, in_port, None):
1810 # Found a matching message
1811 break
1812
Rich Lane82c882d2013-08-09 17:13:52 -07001813 if in_port == None:
1814 test.assertTrue(msg == None, "Did not expect a packet-in message on any port")
1815 else:
1816 test.assertTrue(msg == None, "Did not expect a packet-in message on port %d" % in_port)
Rich Lane4c504f32013-06-07 17:24:14 -07001817
Rich Lane045db072013-08-06 13:16:30 -07001818def openflow_ports(num=None):
1819 """
1820 Return a list of 'num' OpenFlow port numbers
1821
1822 If 'num' is None, return all available ports. Otherwise, limit the length
1823 of the result to 'num' and raise an exception if not enough ports are
1824 available.
1825 """
1826 ports = sorted(oftest.config["port_map"].keys())
1827 if num != None and len(ports) < num:
1828 raise Exception("test requires %d ports but only %d are available" % (num, len(ports)))
1829 return ports[:num]
1830
Rich Lanee4b384d2013-09-13 14:33:40 -07001831def verify_packet(test, pkt, ofport):
1832 """
1833 Check that an expected packet is received
1834 """
1835 logging.debug("Checking for pkt on port %r", ofport)
1836 (rcv_port, rcv_pkt, pkt_time) = test.dataplane.poll(port_number=ofport, exp_pkt=str(pkt))
1837 test.assertTrue(rcv_pkt != None, "Did not receive pkt on %r" % ofport)
macauley17cd60d2015-07-27 17:41:18 +08001838 return (rcv_port, rcv_pkt, pkt_time)
1839
Rich Lanee4b384d2013-09-13 14:33:40 -07001840def verify_no_packet(test, pkt, ofport):
1841 """
1842 Check that a particular packet is not received
1843 """
1844 logging.debug("Negative check for pkt on port %r", ofport)
Rich Lane48f6aed2014-03-23 15:51:02 -07001845 (rcv_port, rcv_pkt, pkt_time) = \
1846 test.dataplane.poll(
1847 port_number=ofport, exp_pkt=str(pkt),
1848 timeout=oftest.ofutils.default_negative_timeout)
Rich Lanee4b384d2013-09-13 14:33:40 -07001849 test.assertTrue(rcv_pkt == None, "Received packet on %r" % ofport)
1850
1851def verify_no_other_packets(test):
1852 """
1853 Check that no unexpected packets are received
1854
1855 This is a no-op if the --relax option is in effect.
1856 """
1857 if oftest.config["relax"]:
1858 return
1859 logging.debug("Checking for unexpected packets on all ports")
Rich Lane48f6aed2014-03-23 15:51:02 -07001860 (rcv_port, rcv_pkt, pkt_time) = test.dataplane.poll(timeout=oftest.ofutils.default_negative_timeout)
Rich Lanee4b384d2013-09-13 14:33:40 -07001861 if rcv_pkt != None:
1862 logging.debug("Received unexpected packet on port %r: %s", rcv_port, format_packet(rcv_pkt))
1863 test.assertTrue(rcv_pkt == None, "Unexpected packet on port %r" % rcv_port)
1864
1865def verify_packets(test, pkt, ofports):
1866 """
1867 Check that a packet is received on certain ports
1868
1869 Also verifies that the packet is not received on any other ports, and that no
1870 other packets are received (unless --relax is in effect).
1871
1872 This covers the common and simplest cases for checking dataplane outputs.
1873 For more complex usage, like multiple different packets being output, or
1874 multiple packets on the same port, use the primitive verify_packet,
1875 verify_no_packet, and verify_no_other_packets functions directly.
1876 """
1877 pkt = str(pkt)
1878 for ofport in openflow_ports():
1879 if ofport in ofports:
1880 verify_packet(test, pkt, ofport)
1881 else:
1882 verify_no_packet(test, pkt, ofport)
1883 verify_no_other_packets(test)
1884
Rich Lane12d04592013-10-10 17:21:07 -07001885def verify_no_errors(ctrl):
1886 error, _ = ctrl.poll(ofp.OFPT_ERROR, 0)
1887 if error:
1888 raise AssertionError("unexpected error type=%d code=%d" % (error.err_type, error.code))
Rich Lanee4b384d2013-09-13 14:33:40 -07001889
Jonathan Stoutfcee3142014-01-28 15:46:22 -05001890def verify_capability(test, capability):
1891 """
Jonathan Stout073642d2014-02-04 13:41:48 -05001892 Return True if DUT supports the specified capability.
Jonathan Stoutfcee3142014-01-28 15:46:22 -05001893
1894 @param test Instance of base_tests.SimpleProtocol
1895 @param capability One of ofp_capabilities.
1896 """
1897 logging.info("Verifing that capability code is valid.")
1898 test.assertIn(capability, ofp.const.ofp_capabilities_map,
1899 "Capability code %d does not exist." % capability)
1900 capability_str = ofp.const.ofp_capabilities_map[capability]
1901
1902 logging.info(("Sending features_request to test if capability "
Jonathan Stout97e458a2014-01-28 16:08:04 -05001903 "%s is supported."), capability_str)
Jonathan Stoutfcee3142014-01-28 15:46:22 -05001904 req = ofp.message.features_request()
1905 res, raw = test.controller.transact(req)
1906 test.assertIsNotNone(res, "Did not receive a response from the DUT.")
1907 test.assertEqual(res.type, ofp.OFPT_FEATURES_REPLY,
1908 ("Unexpected packet type %d received in response to "
1909 "OFPT_FEATURES_REQUEST") % res.type)
Jonathan Stout641167f2014-02-04 12:07:10 -05001910 logging.info("Received features_reply.")
Jonathan Stoutfcee3142014-01-28 15:46:22 -05001911
Jonathan Stout641167f2014-02-04 12:07:10 -05001912 if (res.capabilities & capability) > 0:
1913 logging.info("Switch capabilities bitmask claims to support %s",
1914 capability_str)
1915 return True, res.capabilities
1916 else:
1917 logging.info("Capabilities bitmask does not support %s.",
1918 capability_str)
1919 return False, res.capabilities
Jonathan Stoutfcee3142014-01-28 15:46:22 -05001920
Jonathan Stouteb3721d2014-02-04 13:59:12 -05001921def verify_configuration_flag(test, flag):
1922 """
1923 Return True if DUT supports specified configuration flag.
1924
1925 @param test Instance of base_tests.SimpleProtocol
1926 @param flag One of ofp_config_flags.
Jonathan Stout1ec8c0f2014-02-04 15:25:38 -05001927 @returns (supported, flags) Bool if flag is set and flag values.
Jonathan Stouteb3721d2014-02-04 13:59:12 -05001928 """
1929 logging.info("Verifing that flag is valid.")
1930 test.assertIn(flag, ofp.const.ofp_config_flags_map,
1931 "flag %s does not exist." % flag)
1932 flag_str = ofp.const.ofp_config_flags_map[flag]
1933
1934 logging.info("Sending OFPT_GET_CONFIG_REQUEST.")
1935 req = ofp.message.get_config_request()
1936 rv = test.controller.message_send(req)
1937 test.assertNotEqual(rv, -1, "Not able to send get_config_request.")
1938
1939 logging.info("Expecting OFPT_GET_CONFIG_REPLY ")
1940 (res, pkt) = test.controller.poll(exp_msg=ofp.OFPT_GET_CONFIG_REPLY,
1941 timeout=2)
1942 test.assertIsNotNone(res, "Did not receive OFPT_GET_CONFIG_REPLY")
1943 logging.info("Received OFPT_GET_CONFIG_REPLY ")
1944
1945 if res.flags == flag:
1946 logging.info("%s flag is set.", flag_str)
1947 return True, res.flags
1948 else:
1949 logging.info("%s flag is not set.", flag_str)
1950 return False, res.flags
1951
Rich Lane7744e112013-01-11 17:23:57 -08001952__all__ = list(set(locals()) - _import_blacklist)