blob: f419c212e8712808da81815908049509642e39c2 [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'):
macauley_cheng739f54b2015-11-09 13:52:59 +080074
75 pkt = ''.join(content.split(" ")).decode('hex')
macauley_chengc80249d2015-11-09 14:11:18 +080076 pkt = scapy.Ether(pkt)
macauley_cheng739f54b2015-11-09 13:52:59 +080077 if len(pkt) < 64:
78 pkt = pkt/("D" * (64 - len(pkt)))
macauley_chengc80249d2015-11-09 14:11:18 +080079 #scapy.hexdump(pkt)
macauley_cheng0a0a7f62015-11-06 11:36:50 +080080 return pkt
81
Dan Talayco41eae8b2010-03-10 13:57:06 -080082def simple_tcp_packet(pktlen=100,
Rich Laned0478ff2013-03-11 12:46:58 -070083 eth_dst='00:01:02:03:04:05',
84 eth_src='00:06:07:08:09:0a',
Tatsuya Yabe460321e2010-05-25 17:50:49 -070085 dl_vlan_enable=False,
Rich Laned0478ff2013-03-11 12:46:58 -070086 vlan_vid=0,
87 vlan_pcp=0,
Dan Talayco551befa2010-07-15 17:05:32 -070088 dl_vlan_cfi=0,
Dan Talayco41eae8b2010-03-10 13:57:06 -080089 ip_src='192.168.0.1',
90 ip_dst='192.168.0.2',
Tatsuya Yabe460321e2010-05-25 17:50:49 -070091 ip_tos=0,
Gregor Maier9cc93342013-01-29 16:55:28 -080092 ip_ttl=64,
Dan Talayco41eae8b2010-03-10 13:57:06 -080093 tcp_sport=1234,
Christian Dickmann8b59b4b2012-09-23 16:48:30 -070094 tcp_dport=80,
Harshmeet Singhc51f4042014-05-21 13:32:52 -070095 tcp_flags="S",
Christian Dickmann8b59b4b2012-09-23 16:48:30 -070096 ip_ihl=None,
97 ip_options=False
Dan Talayco41eae8b2010-03-10 13:57:06 -080098 ):
99 """
100 Return a simple dataplane TCP packet
101
102 Supports a few parameters:
103 @param len Length of packet in bytes w/o CRC
Rich Laned0478ff2013-03-11 12:46:58 -0700104 @param eth_dst Destinatino MAC
105 @param eth_src Source MAC
Tatsuya Yabe460321e2010-05-25 17:50:49 -0700106 @param dl_vlan_enable True if the packet is with vlan, False otherwise
Rich Laned0478ff2013-03-11 12:46:58 -0700107 @param vlan_vid VLAN ID
108 @param vlan_pcp VLAN priority
Dan Talayco41eae8b2010-03-10 13:57:06 -0800109 @param ip_src IP source
110 @param ip_dst IP destination
Tatsuya Yabe460321e2010-05-25 17:50:49 -0700111 @param ip_tos IP ToS
Gregor Maier9cc93342013-01-29 16:55:28 -0800112 @param ip_ttl IP TTL
Dan Talayco41eae8b2010-03-10 13:57:06 -0800113 @param tcp_dport TCP destination port
Harshmeet Singhc51f4042014-05-21 13:32:52 -0700114 @param tcp_sport TCP source port
115 @param tcp_flags TCP Control flags
Dan Talayco41eae8b2010-03-10 13:57:06 -0800116
117 Generates a simple TCP request. Users
118 shouldn't assume anything about this packet other than that
119 it is a valid ethernet/IP/TCP frame.
120 """
Jeffrey Townsend5cb7ed32012-08-17 18:11:01 +0000121
122 if MINSIZE > pktlen:
123 pktlen = MINSIZE
124
Dan Talayco551befa2010-07-15 17:05:32 -0700125 # Note Dot1Q.id is really CFI
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800126 if (dl_vlan_enable):
Rich Laned0478ff2013-03-11 12:46:58 -0700127 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
128 scapy.Dot1Q(prio=vlan_pcp, id=dl_vlan_cfi, vlan=vlan_vid)/ \
Gregor Maier9cc93342013-01-29 16:55:28 -0800129 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ttl=ip_ttl, ihl=ip_ihl)/ \
Harshmeet Singhc51f4042014-05-21 13:32:52 -0700130 scapy.TCP(sport=tcp_sport, dport=tcp_dport, flags=tcp_flags)
Tatsuya Yabe460321e2010-05-25 17:50:49 -0700131 else:
Christian Dickmann8b59b4b2012-09-23 16:48:30 -0700132 if not ip_options:
Rich Laned0478ff2013-03-11 12:46:58 -0700133 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
Gregor Maier9cc93342013-01-29 16:55:28 -0800134 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ttl=ip_ttl, ihl=ip_ihl)/ \
Harshmeet Singhc51f4042014-05-21 13:32:52 -0700135 scapy.TCP(sport=tcp_sport, dport=tcp_dport, flags=tcp_flags)
Christian Dickmann8b59b4b2012-09-23 16:48:30 -0700136 else:
Rich Laned0478ff2013-03-11 12:46:58 -0700137 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
Gregor Maier9cc93342013-01-29 16:55:28 -0800138 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 -0700139 scapy.TCP(sport=tcp_sport, dport=tcp_dport, flags=tcp_flags)
Tatsuya Yabe460321e2010-05-25 17:50:49 -0700140
Dan Talayco41eae8b2010-03-10 13:57:06 -0800141 pkt = pkt/("D" * (pktlen - len(pkt)))
142
143 return pkt
144
Rich Lane86aceb02013-07-17 18:45:38 -0700145def simple_tcpv6_packet(pktlen=100,
146 eth_dst='00:01:02:03:04:05',
147 eth_src='00:06:07:08:09:0a',
148 dl_vlan_enable=False,
149 vlan_vid=0,
150 vlan_pcp=0,
151 ipv6_src='2001:db8:85a3::8a2e:370:7334',
152 ipv6_dst='2001:db8:85a3::8a2e:370:7335',
153 ipv6_tc=0,
154 ipv6_hlim=64,
155 ipv6_fl=0,
156 tcp_sport=1234,
Harshmeet Singhc51f4042014-05-21 13:32:52 -0700157 tcp_dport=80,
Harshmeet Singh31ba3312014-05-21 13:48:35 -0700158 tcp_flags="S"):
Rich Lane86aceb02013-07-17 18:45:38 -0700159 """
160 Return a simple IPv6/TCP packet
161
162 Supports a few parameters:
163 @param len Length of packet in bytes w/o CRC
164 @param eth_dst Destination MAC
165 @param eth_src Source MAC
166 @param dl_vlan_enable True if the packet is with vlan, False otherwise
167 @param vlan_vid VLAN ID
168 @param vlan_pcp VLAN priority
169 @param ipv6_src IPv6 source
170 @param ipv6_dst IPv6 destination
171 @param ipv6_tc IPv6 traffic class
172 @param ipv6_ttl IPv6 hop limit
173 @param ipv6_fl IPv6 flow label
174 @param tcp_dport TCP destination port
175 @param tcp_sport TCP source port
Harshmeet Singhc51f4042014-05-21 13:32:52 -0700176 @param tcp_flags TCP Control flags
Rich Lane86aceb02013-07-17 18:45:38 -0700177
178 Generates a simple TCP request. Users shouldn't assume anything about this
179 packet other than that it is a valid ethernet/IPv6/TCP frame.
180 """
181
182 if MINSIZE > pktlen:
183 pktlen = MINSIZE
184
185 pkt = scapy.Ether(dst=eth_dst, src=eth_src)
186 if dl_vlan_enable or vlan_vid or vlan_pcp:
187 pkt /= scapy.Dot1Q(vlan=vlan_vid, prio=vlan_pcp)
188 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 -0700189 pkt /= scapy.TCP(sport=tcp_sport, dport=tcp_dport, flags=tcp_flags)
Rich Lane86aceb02013-07-17 18:45:38 -0700190 pkt /= ("D" * (pktlen - len(pkt)))
191
192 return pkt
193
Rich Lane6ee7bea2012-10-26 16:19:29 -0700194def simple_udp_packet(pktlen=100,
Rich Laned0478ff2013-03-11 12:46:58 -0700195 eth_dst='00:01:02:03:04:05',
196 eth_src='00:06:07:08:09:0a',
Rich Lane6ee7bea2012-10-26 16:19:29 -0700197 dl_vlan_enable=False,
Rich Laned0478ff2013-03-11 12:46:58 -0700198 vlan_vid=0,
199 vlan_pcp=0,
Rich Lane6ee7bea2012-10-26 16:19:29 -0700200 dl_vlan_cfi=0,
201 ip_src='192.168.0.1',
202 ip_dst='192.168.0.2',
203 ip_tos=0,
Gregor Maier9cc93342013-01-29 16:55:28 -0800204 ip_ttl=64,
Rich Lane6ee7bea2012-10-26 16:19:29 -0700205 udp_sport=1234,
206 udp_dport=80,
207 ip_ihl=None,
208 ip_options=False
209 ):
210 """
211 Return a simple dataplane UDP packet
212
213 Supports a few parameters:
214 @param len Length of packet in bytes w/o CRC
Rich Laned0478ff2013-03-11 12:46:58 -0700215 @param eth_dst Destination MAC
216 @param eth_src Source MAC
Rich Lane6ee7bea2012-10-26 16:19:29 -0700217 @param dl_vlan_enable True if the packet is with vlan, False otherwise
Rich Laned0478ff2013-03-11 12:46:58 -0700218 @param vlan_vid VLAN ID
219 @param vlan_pcp VLAN priority
Rich Lane6ee7bea2012-10-26 16:19:29 -0700220 @param ip_src IP source
221 @param ip_dst IP destination
222 @param ip_tos IP ToS
Gregor Maier9cc93342013-01-29 16:55:28 -0800223 @param ip_ttl IP TTL
Rich Lane6ee7bea2012-10-26 16:19:29 -0700224 @param udp_dport UDP destination port
225 @param udp_sport UDP source port
226
227 Generates a simple UDP packet. Users shouldn't assume anything about
228 this packet other than that it is a valid ethernet/IP/UDP frame.
229 """
230
231 if MINSIZE > pktlen:
232 pktlen = MINSIZE
233
234 # Note Dot1Q.id is really CFI
235 if (dl_vlan_enable):
Rich Laned0478ff2013-03-11 12:46:58 -0700236 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
237 scapy.Dot1Q(prio=vlan_pcp, id=dl_vlan_cfi, vlan=vlan_vid)/ \
Gregor Maier9cc93342013-01-29 16:55:28 -0800238 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ttl=ip_ttl, ihl=ip_ihl)/ \
Rich Lane6ee7bea2012-10-26 16:19:29 -0700239 scapy.UDP(sport=udp_sport, dport=udp_dport)
240 else:
241 if not ip_options:
Rich Laned0478ff2013-03-11 12:46:58 -0700242 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
Gregor Maier9cc93342013-01-29 16:55:28 -0800243 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ttl=ip_ttl, ihl=ip_ihl)/ \
Rich Lane6ee7bea2012-10-26 16:19:29 -0700244 scapy.UDP(sport=udp_sport, dport=udp_dport)
245 else:
Rich Laned0478ff2013-03-11 12:46:58 -0700246 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
Gregor Maier9cc93342013-01-29 16:55:28 -0800247 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 -0700248 scapy.UDP(sport=udp_sport, dport=udp_dport)
249
250 pkt = pkt/("D" * (pktlen - len(pkt)))
251
252 return pkt
253
macauley_chengb0ec33d2015-09-04 11:32:44 +0800254
255def simple_tcp_packet_two_vlan(pktlen=100,
256 eth_dst='00:01:02:03:04:05',
257 eth_src='00:06:07:08:09:0a',
258 out_dl_vlan_enable=False,
259 in_dl_vlan_enable=False,
260 out_vlan_vid=0,
261 out_vlan_pcp=0,
262 out_dl_vlan_cfi=0,
263 in_vlan_vid=0,
264 in_vlan_pcp=0,
265 in_dl_vlan_cfi=0,
266 ip_src='192.168.0.1',
267 ip_dst='192.168.0.2',
268 ip_tos=0,
269 ip_ttl=64,
270 tcp_sport=1234,
271 tcp_dport=80,
272 tcp_flags="S",
273 ip_ihl=None,
274 ip_options=False
275 ):
276 """
277 Return a simple dataplane TCP packet
278
279 Supports a few parameters:
280 @param len Length of packet in bytes w/o CRC
281 @param eth_dst Destinatino MAC
282 @param eth_src Source MAC
283 @param dl_vlan_enable True if the packet is with vlan, False otherwise
284 @param vlan_vid VLAN ID
285 @param vlan_pcp VLAN priority
286 @param ip_src IP source
287 @param ip_dst IP destination
288 @param ip_tos IP ToS
289 @param ip_ttl IP TTL
290 @param tcp_dport TCP destination port
291 @param tcp_sport TCP source port
292 @param tcp_flags TCP Control flags
293
294 Generates a simple TCP request. Users
295 shouldn't assume anything about this packet other than that
296 it is a valid ethernet/IP/TCP frame.
297 """
298
299 if MINSIZE > pktlen:
300 pktlen = MINSIZE
301
302 # Note Dot1Q.id is really CFI
303 if (out_dl_vlan_enable and in_dl_vlan_enable):
304 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
305 scapy.Dot1Q(prio=out_vlan_pcp, id=out_dl_vlan_cfi, vlan=out_vlan_vid)
306
307 if in_dl_vlan_enable:
308 pkt = pkt/scapy.Dot1Q(prio=in_vlan_pcp, id=in_dl_vlan_cfi, vlan=in_vlan_vid)
309
310 pkt = pkt/scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ttl=ip_ttl, ihl=ip_ihl)/ \
311 scapy.TCP(sport=tcp_sport, dport=tcp_dport, flags=tcp_flags)
312 elif (out_dl_vlan_enable and (not in_dl_vlan_enable)):
313 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
314 scapy.Dot1Q(prio=out_vlan_pcp, id=out_dl_vlan_cfi, vlan=out_vlan_vid)/ \
315 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ttl=ip_ttl, ihl=ip_ihl)/ \
316 scapy.TCP(sport=tcp_sport, dport=tcp_dport, flags=tcp_flags)
317 elif ((not out_dl_vlan_enable) and in_dl_vlan_enable):
318 assert(0) #shall not have this caes
319 else:
320 if not ip_options:
321 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
322 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ttl=ip_ttl, ihl=ip_ihl)/ \
323 scapy.TCP(sport=tcp_sport, dport=tcp_dport, flags=tcp_flags)
324 else:
325 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
326 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ttl=ip_ttl, ihl=ip_ihl, options=ip_options)/ \
327 scapy.TCP(sport=tcp_sport, dport=tcp_dport, flags=tcp_flags)
328
329 pkt = pkt/("D" * (pktlen - len(pkt)))
330
331 return pkt
332
macauley17cd60d2015-07-27 17:41:18 +0800333def simple_vxlan_packet(eth_dst='00:01:02:03:04:05',
334 eth_src='00:06:07:08:09:0a',
335 dl_vlan_enable=False,
336 vlan_vid=0,
337 vlan_pcp=0,
338 dl_vlan_cfi=0,
339 ip_src='192.168.0.1',
340 ip_dst='192.168.0.2',
341 ip_tos=0,
342 ip_ttl=64,
343 udp_sport=1234,
344 udp_dport=4789,
345 vnid=1,
macauley1b23af82015-07-30 14:06:33 +0800346 inner_payload=None,
macauley17cd60d2015-07-27 17:41:18 +0800347 ip_ihl=None,
348 ip_options=False
349 ):
350 """
351 Return a simple dataplane UDP packet
352
353 Supports a few parameters:
354 @param len Length of packet in bytes w/o CRC
355 @param eth_dst Destination MAC
356 @param eth_src Source MAC
357 @param dl_vlan_enable True if the packet is with vlan, False otherwise
358 @param vlan_vid VLAN ID
359 @param vlan_pcp VLAN priority
360 @param ip_src IP source
361 @param ip_dst IP destination
362 @param ip_tos IP ToS
363 @param ip_ttl IP TTL
364 @param udp_dport UDP destination port
365 @param udp_sport UDP source port
366 @param inner_pyload inner pacekt content
367 Generates a simple UDP packet. Users shouldn't assume anything about
368 this packet other than that it is a valid ethernet/IP/UDP frame.
369 """
370
371 # Note Dot1Q.id is really CFI
372 if (dl_vlan_enable):
373 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
374 scapy.Dot1Q(prio=vlan_pcp, id=dl_vlan_cfi, vlan=vlan_vid)/ \
375 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ttl=ip_ttl, ihl=ip_ihl)/ \
376 scapy.UDP(sport=udp_sport, dport=udp_dport)
377 else:
378 if not ip_options:
379 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
380 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ttl=ip_ttl, ihl=ip_ihl)/ \
381 scapy.UDP(sport=udp_sport, dport=udp_dport)
382 else:
383 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
384 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ttl=ip_ttl, ihl=ip_ihl, options=ip_options)/ \
385 scapy.UDP(sport=udp_sport, dport=udp_dport)
macauley1b23af82015-07-30 14:06:33 +0800386
macauley17cd60d2015-07-27 17:41:18 +0800387 #add vxlan header
388 pkt = pkt/scapy.VXLAN(vni=vnid)
389 #add innder payload
macauley1b23af82015-07-30 14:06:33 +0800390 if inner_payload!=None:
391 pkt=pkt/inner_payload
macauley17cd60d2015-07-27 17:41:18 +0800392
393 return pkt
394
macauley_chengb0ec33d2015-09-04 11:32:44 +0800395
macauley_cheng45833df2015-08-31 15:19:07 +0800396
397def simple_mpls_packet(eth_dst='00:01:02:03:04:05',
398 eth_src='00:06:07:08:09:0a',
399 dl_vlan_enable=False,
400 vlan_vid=0,
401 vlan_pcp=0,
402 dl_vlan_cfi=0,
403 label=None,
404 inner_payload=None
405 ):
406 """
407 Return a simple dataplane MPLS packet
408
409 Supports a few parameters:
410 @param len Length of packet in bytes w/o CRC
411 @param eth_dst Destination MAC
412 @param eth_src Source MAC
413 @param dl_vlan_enable True if the packet is with vlan, False otherwise
414 @param vlan_vid VLAN ID
415 @param vlan_pcp VLAN priority
416 @param inner_pyload inner pacekt content
417 Generates a simple MPLS packet. Users shouldn't assume anything about
418 this packet other than that it is a valid ethernet/IP/UDP frame.
419 """
420
421 # Note Dot1Q.id is really CFI
422 if (dl_vlan_enable):
423 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
424 scapy.Dot1Q(prio=vlan_pcp, id=dl_vlan_cfi, vlan=vlan_vid)
425 else:
426 pkt = scapy.Ether(dst=eth_dst, src=eth_src)
427
428 #add MPLS header
429 for i in range(len(label)):
430 l,c,s,t=label[i]
431 pkt = pkt/scapy.MPLS(label=l, cos=c, s=s, ttl=t)
432
433 #add innder payload
434 if inner_payload!=None:
435 pkt=pkt/inner_payload
436
437 return pkt
438
Rich Lane86aceb02013-07-17 18:45:38 -0700439def simple_udpv6_packet(pktlen=100,
440 eth_dst='00:01:02:03:04:05',
441 eth_src='00:06:07:08:09:0a',
442 dl_vlan_enable=False,
443 vlan_vid=0,
444 vlan_pcp=0,
445 ipv6_src='2001:db8:85a3::8a2e:370:7334',
446 ipv6_dst='2001:db8:85a3::8a2e:370:7335',
447 ipv6_tc=0,
448 ipv6_hlim=64,
449 ipv6_fl=0,
450 udp_sport=1234,
451 udp_dport=80):
452 """
453 Return a simple IPv6/UDP packet
454
455 Supports a few parameters:
456 @param len Length of packet in bytes w/o CRC
457 @param eth_dst Destination MAC
458 @param eth_src Source MAC
459 @param dl_vlan_enable True if the packet is with vlan, False otherwise
460 @param vlan_vid VLAN ID
461 @param vlan_pcp VLAN priority
462 @param ipv6_src IPv6 source
463 @param ipv6_dst IPv6 destination
464 @param ipv6_tc IPv6 traffic class
465 @param ipv6_ttl IPv6 hop limit
466 @param ipv6_fl IPv6 flow label
467 @param udp_dport UDP destination port
468 @param udp_sport UDP source port
469
470 Generates a simple UDP request. Users shouldn't assume anything about this
471 packet other than that it is a valid ethernet/IPv6/UDP frame.
472 """
473
474 if MINSIZE > pktlen:
475 pktlen = MINSIZE
476
477 pkt = scapy.Ether(dst=eth_dst, src=eth_src)
478 if dl_vlan_enable or vlan_vid or vlan_pcp:
479 pkt /= scapy.Dot1Q(vlan=vlan_vid, prio=vlan_pcp)
480 pkt /= scapy.IPv6(src=ipv6_src, dst=ipv6_dst, fl=ipv6_fl, tc=ipv6_tc, hlim=ipv6_hlim)
481 pkt /= scapy.UDP(sport=udp_sport, dport=udp_dport)
482 pkt /= ("D" * (pktlen - len(pkt)))
483
484 return pkt
485
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700486def simple_icmp_packet(pktlen=60,
Rich Laned0478ff2013-03-11 12:46:58 -0700487 eth_dst='00:01:02:03:04:05',
488 eth_src='00:06:07:08:09:0a',
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700489 dl_vlan_enable=False,
Rich Laned0478ff2013-03-11 12:46:58 -0700490 vlan_vid=0,
491 vlan_pcp=0,
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700492 ip_src='192.168.0.1',
493 ip_dst='192.168.0.2',
494 ip_tos=0,
Gregor Maier9cc93342013-01-29 16:55:28 -0800495 ip_ttl=64,
Harshmeet Singhd209c0b2014-01-28 09:48:58 -0600496 ip_id=1,
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700497 icmp_type=8,
Harshmeet Singhd209c0b2014-01-28 09:48:58 -0600498 icmp_code=0,
Harshmeet Singh45b2a9d2014-01-28 13:02:04 -0600499 icmp_data=''):
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700500 """
501 Return a simple ICMP packet
502
503 Supports a few parameters:
504 @param len Length of packet in bytes w/o CRC
Rich Laned0478ff2013-03-11 12:46:58 -0700505 @param eth_dst Destinatino MAC
506 @param eth_src Source MAC
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700507 @param dl_vlan_enable True if the packet is with vlan, False otherwise
Rich Laned0478ff2013-03-11 12:46:58 -0700508 @param vlan_vid VLAN ID
509 @param vlan_pcp VLAN priority
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700510 @param ip_src IP source
511 @param ip_dst IP destination
512 @param ip_tos IP ToS
Gregor Maier9cc93342013-01-29 16:55:28 -0800513 @param ip_ttl IP TTL
Harshmeet Singhd209c0b2014-01-28 09:48:58 -0600514 @param ip_id IP Identification
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700515 @param icmp_type ICMP type
516 @param icmp_code ICMP code
Harshmeet Singhd209c0b2014-01-28 09:48:58 -0600517 @param icmp_data ICMP data
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700518
519 Generates a simple ICMP ECHO REQUEST. Users
520 shouldn't assume anything about this packet other than that
521 it is a valid ethernet/ICMP frame.
522 """
Jeffrey Townsend5cb7ed32012-08-17 18:11:01 +0000523
524 if MINSIZE > pktlen:
525 pktlen = MINSIZE
526
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700527 if (dl_vlan_enable):
Rich Laned0478ff2013-03-11 12:46:58 -0700528 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
529 scapy.Dot1Q(prio=vlan_pcp, id=0, vlan=vlan_vid)/ \
Harshmeet Singhd209c0b2014-01-28 09:48:58 -0600530 scapy.IP(src=ip_src, dst=ip_dst, ttl=ip_ttl, tos=ip_tos, id=ip_id)/ \
Harshmeet Singh45b2a9d2014-01-28 13:02:04 -0600531 scapy.ICMP(type=icmp_type, code=icmp_code)/ icmp_data
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700532 else:
Rich Laned0478ff2013-03-11 12:46:58 -0700533 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
Harshmeet Singhd209c0b2014-01-28 09:48:58 -0600534 scapy.IP(src=ip_src, dst=ip_dst, ttl=ip_ttl, tos=ip_tos, id=ip_id)/ \
Harshmeet Singh45b2a9d2014-01-28 13:02:04 -0600535 scapy.ICMP(type=icmp_type, code=icmp_code)/ icmp_data
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700536
537 pkt = pkt/("0" * (pktlen - len(pkt)))
538
539 return pkt
540
Rich Lane86aceb02013-07-17 18:45:38 -0700541def simple_icmpv6_packet(pktlen=100,
542 eth_dst='00:01:02:03:04:05',
543 eth_src='00:06:07:08:09:0a',
544 dl_vlan_enable=False,
545 vlan_vid=0,
546 vlan_pcp=0,
547 ipv6_src='2001:db8:85a3::8a2e:370:7334',
548 ipv6_dst='2001:db8:85a3::8a2e:370:7335',
549 ipv6_tc=0,
550 ipv6_hlim=64,
551 ipv6_fl=0,
552 icmp_type=8,
553 icmp_code=0):
554 """
555 Return a simple ICMPv6 packet
556
557 Supports a few parameters:
558 @param len Length of packet in bytes w/o CRC
559 @param eth_dst Destination MAC
560 @param eth_src Source MAC
561 @param dl_vlan_enable True if the packet is with vlan, False otherwise
562 @param vlan_vid VLAN ID
563 @param vlan_pcp VLAN priority
564 @param ipv6_src IPv6 source
565 @param ipv6_dst IPv6 destination
566 @param ipv6_tc IPv6 traffic class
567 @param ipv6_ttl IPv6 hop limit
568 @param ipv6_fl IPv6 flow label
569 @param icmp_type ICMP type
570 @param icmp_code ICMP code
571
572 Generates a simple ICMP ECHO REQUEST. Users shouldn't assume anything
573 about this packet other than that it is a valid ethernet/IPv6/ICMP frame.
574 """
575
576 if MINSIZE > pktlen:
577 pktlen = MINSIZE
578
579 pkt = scapy.Ether(dst=eth_dst, src=eth_src)
580 if dl_vlan_enable or vlan_vid or vlan_pcp:
581 pkt /= scapy.Dot1Q(vlan=vlan_vid, prio=vlan_pcp)
582 pkt /= scapy.IPv6(src=ipv6_src, dst=ipv6_dst, fl=ipv6_fl, tc=ipv6_tc, hlim=ipv6_hlim)
583 pkt /= scapy.ICMPv6Unknown(type=icmp_type, code=icmp_code)
584 pkt /= ("D" * (pktlen - len(pkt)))
585
586 return pkt
587
Shudong Zhouc7562b12013-02-06 01:12:18 -0800588def simple_arp_packet(pktlen=60,
Rich Laned0478ff2013-03-11 12:46:58 -0700589 eth_dst='ff:ff:ff:ff:ff:ff',
590 eth_src='00:06:07:08:09:0a',
Rich Lanee01611f2014-01-15 14:55:11 -0800591 vlan_vid=0,
592 vlan_pcp=0,
Shudong Zhouc7562b12013-02-06 01:12:18 -0800593 arp_op=1,
594 ip_snd='192.168.0.1',
595 ip_tgt='192.168.0.2',
596 hw_snd='00:06:07:08:09:0a',
597 hw_tgt='00:00:00:00:00:00',
598 ):
599 """
600 Return a simple ARP packet
601
602 Supports a few parameters:
603 @param len Length of packet in bytes w/o CRC
Rich Laned0478ff2013-03-11 12:46:58 -0700604 @param eth_dst Destinatino MAC
605 @param eth_src Source MAC
Shudong Zhouc7562b12013-02-06 01:12:18 -0800606 @param arp_op Operation (1=request, 2=reply)
607 @param ip_snd Sender IP
608 @param ip_tgt Target IP
609 @param hw_snd Sender hardware address
610 @param hw_tgt Target hardware address
611
612 Generates a simple ARP REQUEST. Users
613 shouldn't assume anything about this packet other than that
614 it is a valid ethernet/ARP frame.
615 """
616
617 if MINSIZE > pktlen:
618 pktlen = MINSIZE
619
Rich Lanee01611f2014-01-15 14:55:11 -0800620 pkt = scapy.Ether(dst=eth_dst, src=eth_src)
621 if vlan_vid or vlan_pcp:
622 pkt /= scapy.Dot1Q(vlan=vlan_vid, prio=vlan_pcp)
623 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 -0800624
Rich Laned459ce52014-01-24 12:09:54 -0800625 pkt = pkt/("\0" * (pktlen - len(pkt)))
Shudong Zhouc7562b12013-02-06 01:12:18 -0800626
627 return pkt
628
Ed Swierk0aeff8c2012-03-23 20:27:18 -0700629def simple_eth_packet(pktlen=60,
Rich Lane53275082013-11-18 23:26:22 -0800630 eth_dst='00:01:02:03:04:05',
631 eth_src='00:06:07:08:09:0a',
Rich Laned0478ff2013-03-11 12:46:58 -0700632 eth_type=0x88cc):
Jeffrey Townsend5cb7ed32012-08-17 18:11:01 +0000633
634 if MINSIZE > pktlen:
635 pktlen = MINSIZE
636
Rich Laned0478ff2013-03-11 12:46:58 -0700637 pkt = scapy.Ether(dst=eth_dst, src=eth_src, type=eth_type)
Ed Swierk0aeff8c2012-03-23 20:27:18 -0700638
639 pkt = pkt/("0" * (pktlen - len(pkt)))
640
641 return pkt
642
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800643def qinq_tcp_packet(pktlen=100,
Rich Laned0478ff2013-03-11 12:46:58 -0700644 eth_dst='00:01:02:03:04:05',
645 eth_src='00:06:07:08:09:0a',
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800646 dl_vlan_outer=20,
647 dl_vlan_pcp_outer=0,
648 dl_vlan_cfi_outer=0,
Rich Laned0478ff2013-03-11 12:46:58 -0700649 vlan_vid=10,
650 vlan_pcp=0,
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800651 dl_vlan_cfi=0,
652 ip_src='192.168.0.1',
653 ip_dst='192.168.0.2',
654 ip_tos=0,
Gregor Maier9cc93342013-01-29 16:55:28 -0800655 ip_ttl=64,
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800656 tcp_sport=1234,
657 tcp_dport=80,
658 ip_ihl=None,
659 ip_options=False
660 ):
661 """
662 Return a doubly tagged dataplane TCP packet
663
664 Supports a few parameters:
665 @param len Length of packet in bytes w/o CRC
Rich Laned0478ff2013-03-11 12:46:58 -0700666 @param eth_dst Destinatino MAC
667 @param eth_src Source MAC
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800668 @param dl_vlan_outer Outer VLAN ID
669 @param dl_vlan_pcp_outer Outer VLAN priority
670 @param dl_vlan_cfi_outer Outer VLAN cfi bit
Rich Laned0478ff2013-03-11 12:46:58 -0700671 @param vlan_vid Inner VLAN ID
672 @param vlan_pcp VLAN priority
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800673 @param dl_vlan_cfi VLAN cfi bit
674 @param ip_src IP source
675 @param ip_dst IP destination
676 @param ip_tos IP ToS
677 @param tcp_dport TCP destination port
678 @param ip_sport TCP source port
679
680 Generates a TCP request. Users
681 shouldn't assume anything about this packet other than that
682 it is a valid ethernet/IP/TCP frame.
683 """
684
685 if MINSIZE > pktlen:
686 pktlen = MINSIZE
687
688 # Note Dot1Q.id is really CFI
Rich Laned0478ff2013-03-11 12:46:58 -0700689 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800690 scapy.Dot1Q(prio=dl_vlan_pcp_outer, id=dl_vlan_cfi_outer, vlan=dl_vlan_outer)/ \
Rich Laned0478ff2013-03-11 12:46:58 -0700691 scapy.Dot1Q(prio=vlan_pcp, id=dl_vlan_cfi, vlan=vlan_vid)/ \
Gregor Maier9cc93342013-01-29 16:55:28 -0800692 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ttl=ip_ttl, ihl=ip_ihl)/ \
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800693 scapy.TCP(sport=tcp_sport, dport=tcp_dport)
694
695 pkt = pkt/("D" * (pktlen - len(pkt)))
696
697 return pkt
698
Shudong Zhoub7f12462012-11-20 13:01:12 -0800699def do_barrier(ctrl, timeout=-1):
Dan Talayco0fc08bd2012-04-09 16:56:18 -0700700 """
701 Do a barrier command
702 Return 0 on success, -1 on error
703 """
Rich Lanee717c6e2013-03-12 10:25:50 -0700704 b = ofp.message.barrier_request()
Shudong Zhoub7f12462012-11-20 13:01:12 -0800705 (resp, pkt) = ctrl.transact(b, timeout=timeout)
Rich Lane3a261d52013-01-03 17:45:08 -0800706 if resp is None:
707 raise AssertionError("barrier failed")
Dan Talaycof6b94832012-04-12 21:50:57 -0700708 # We'll trust the transaction processing in the controller that xid matched
Rich Lane3a261d52013-01-03 17:45:08 -0800709 return 0 # for backwards compatibility
Dan Talayco92c99122010-06-03 13:53:18 -0700710
Rich Lane9a003812012-10-04 17:17:59 -0700711def port_config_get(controller, port_no):
Dan Talayco92c99122010-06-03 13:53:18 -0700712 """
713 Get a port's configuration
714
715 Gets the switch feature configuration and grabs one port's
716 configuration
717
718 @returns (hwaddr, config, advert) The hwaddress, configuration and
719 advertised values
720 """
Rich Lane6dc865c2013-07-10 10:12:13 -0700721
722 if ofp.OFP_VERSION <= 3:
723 request = ofp.message.features_request()
724 reply, _ = controller.transact(request)
725 if reply is None:
726 logging.warn("Get feature request failed")
727 return None, None, None
728 logging.debug(reply.show())
729 ports = reply.ports
730 else:
731 request = ofp.message.port_desc_stats_request()
732 # TODO do multipart correctly
733 reply, _ = controller.transact(request)
734 if reply is None:
735 logging.warn("Port desc stats request failed")
736 return None, None, None
737 logging.debug(reply.show())
738 ports = reply.entries
739
740 for port in ports:
741 if port.port_no == port_no:
742 return (port.hw_addr, port.config, port.advertised)
Dan Talayco92c99122010-06-03 13:53:18 -0700743
Rich Lane9a003812012-10-04 17:17:59 -0700744 logging.warn("Did not find port number for port config")
Dan Talayco92c99122010-06-03 13:53:18 -0700745 return None, None, None
746
Rich Lane9a003812012-10-04 17:17:59 -0700747def port_config_set(controller, port_no, config, mask):
Dan Talayco92c99122010-06-03 13:53:18 -0700748 """
749 Set the port configuration according the given parameters
750
751 Gets the switch feature configuration and updates one port's
752 configuration value according to config and mask
753 """
Rich Lane9a003812012-10-04 17:17:59 -0700754 logging.info("Setting port " + str(port_no) + " to config " + str(config))
Rich Lane6dc865c2013-07-10 10:12:13 -0700755
756 hw_addr, _, _ = port_config_get(controller, port_no)
757
Rich Lanee717c6e2013-03-12 10:25:50 -0700758 mod = ofp.message.port_mod()
Dan Talayco92c99122010-06-03 13:53:18 -0700759 mod.port_no = port_no
Rich Lane6dc865c2013-07-10 10:12:13 -0700760 if hw_addr != None:
761 mod.hw_addr = hw_addr
Dan Talayco92c99122010-06-03 13:53:18 -0700762 mod.config = config
763 mod.mask = mask
Rich Lane6dc865c2013-07-10 10:12:13 -0700764 mod.advertise = 0 # No change
Rich Lane5c3151c2013-01-03 17:15:41 -0800765 controller.message_send(mod)
766 return 0
Dan Talayco92c99122010-06-03 13:53:18 -0700767
Rich Lane2014f9b2012-10-05 15:29:40 -0700768def receive_pkt_check(dp, pkt, yes_ports, no_ports, assert_if):
Dan Talayco92c99122010-06-03 13:53:18 -0700769 """
770 Check for proper receive packets across all ports
Ken Chiang1bf01602012-04-04 10:48:23 -0700771 @param dp The dataplane object
Dan Talayco92c99122010-06-03 13:53:18 -0700772 @param pkt Expected packet; may be None if yes_ports is empty
773 @param yes_ports Set or list of ports that should recieve packet
774 @param no_ports Set or list of ports that should not receive packet
775 @param assert_if Object that implements assertXXX
Rich Lanee4b384d2013-09-13 14:33:40 -0700776
777 DEPRECATED in favor in verify_packets
Dan Talayco92c99122010-06-03 13:53:18 -0700778 """
Rich Lane91765672012-12-06 16:33:04 -0800779
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700780 exp_pkt_arg = None
Rich Lanecd97d3d2013-01-07 18:50:06 -0800781 if oftest.config["relax"]:
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700782 exp_pkt_arg = pkt
783
Dan Talayco92c99122010-06-03 13:53:18 -0700784 for ofport in yes_ports:
Rich Lane9a003812012-10-04 17:17:59 -0700785 logging.debug("Checking for pkt on port " + str(ofport))
Ken Chiang1bf01602012-04-04 10:48:23 -0700786 (rcv_port, rcv_pkt, pkt_time) = dp.poll(
Wilson Ngc2c6b4e2015-03-04 17:30:20 -0800787 port_number=ofport, exp_pkt=exp_pkt_arg)
Dan Talayco92c99122010-06-03 13:53:18 -0700788 assert_if.assertTrue(rcv_pkt is not None,
789 "Did not receive pkt on " + str(ofport))
Rich Lanecd97d3d2013-01-07 18:50:06 -0800790 if not oftest.dataplane.match_exp_pkt(pkt, rcv_pkt):
Rich Lane3c266832013-01-29 18:29:15 -0800791 logging.debug("Expected %s" % format_packet(pkt))
792 logging.debug("Received %s" % format_packet(rcv_pkt))
Rich Lanecd97d3d2013-01-07 18:50:06 -0800793 assert_if.assertTrue(oftest.dataplane.match_exp_pkt(pkt, rcv_pkt),
Rich Lane3c266832013-01-29 18:29:15 -0800794 "Received packet does not match expected packet " +
Ken Chiang1bf01602012-04-04 10:48:23 -0700795 "on port " + str(ofport))
Dan Talayco73f84012012-10-02 09:23:18 -0700796 if len(no_ports) > 0:
Rich Lane57dfee72014-03-24 16:59:47 -0700797 time.sleep(oftest.ofutils.default_negative_timeout)
Dan Talayco92c99122010-06-03 13:53:18 -0700798 for ofport in no_ports:
Rich Lane9a003812012-10-04 17:17:59 -0700799 logging.debug("Negative check for pkt on port " + str(ofport))
Ken Chiang1bf01602012-04-04 10:48:23 -0700800 (rcv_port, rcv_pkt, pkt_time) = dp.poll(
Rich Lane91765672012-12-06 16:33:04 -0800801 port_number=ofport, timeout=0, exp_pkt=exp_pkt_arg)
Dan Talayco92c99122010-06-03 13:53:18 -0700802 assert_if.assertTrue(rcv_pkt is None,
803 "Unexpected pkt on port " + str(ofport))
Dan Talayco551befa2010-07-15 17:05:32 -0700804
805
Dan Talaycoc948d0b2012-03-23 12:17:54 -0700806def receive_pkt_verify(parent, egr_ports, exp_pkt, ing_port):
Dan Talayco551befa2010-07-15 17:05:32 -0700807 """
808 Receive a packet and verify it matches an expected value
Dan Talaycof6e76c02012-03-23 10:56:12 -0700809 @param egr_port A single port or list of ports
Dan Talayco551befa2010-07-15 17:05:32 -0700810
811 parent must implement dataplane, assertTrue and assertEqual
Rich Lanee4b384d2013-09-13 14:33:40 -0700812
813 DEPRECATED in favor in verify_packets
Dan Talayco551befa2010-07-15 17:05:32 -0700814 """
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700815 exp_pkt_arg = None
Rich Lanecd97d3d2013-01-07 18:50:06 -0800816 if oftest.config["relax"]:
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700817 exp_pkt_arg = exp_pkt
818
Dan Talaycof6e76c02012-03-23 10:56:12 -0700819 if type(egr_ports) == type([]):
820 egr_port_list = egr_ports
821 else:
822 egr_port_list = [egr_ports]
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700823
Dan Talaycof6e76c02012-03-23 10:56:12 -0700824 # Expect a packet from each port on egr port list
825 for egr_port in egr_port_list:
Dan Talaycod8ae7582012-03-23 12:24:56 -0700826 check_port = egr_port
Rich Lanee717c6e2013-03-12 10:25:50 -0700827 if egr_port == ofp.OFPP_IN_PORT:
Dan Talaycod8ae7582012-03-23 12:24:56 -0700828 check_port = ing_port
Dan Talaycof6e76c02012-03-23 10:56:12 -0700829 (rcv_port, rcv_pkt, pkt_time) = parent.dataplane.poll(
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700830 port_number=check_port, exp_pkt=exp_pkt_arg)
Dan Talayco551befa2010-07-15 17:05:32 -0700831
Dan Talaycof6e76c02012-03-23 10:56:12 -0700832 if rcv_pkt is None:
Rich Lane9a003812012-10-04 17:17:59 -0700833 logging.error("ERROR: No packet received from " +
Dan Talaycod8ae7582012-03-23 12:24:56 -0700834 str(check_port))
Dan Talayco551befa2010-07-15 17:05:32 -0700835
Dan Talaycof6e76c02012-03-23 10:56:12 -0700836 parent.assertTrue(rcv_pkt is not None,
Dan Talaycod8ae7582012-03-23 12:24:56 -0700837 "Did not receive packet port " + str(check_port))
Rich Lane9a003812012-10-04 17:17:59 -0700838 logging.debug("Packet len " + str(len(rcv_pkt)) + " in on " +
Dan Talaycof6e76c02012-03-23 10:56:12 -0700839 str(rcv_port))
840
841 if str(exp_pkt) != str(rcv_pkt):
Rich Lane9a003812012-10-04 17:17:59 -0700842 logging.error("ERROR: Packet match failed.")
843 logging.debug("Expected len " + str(len(exp_pkt)) + ": "
Dan Talaycof6e76c02012-03-23 10:56:12 -0700844 + str(exp_pkt).encode('hex'))
Rich Lane9a003812012-10-04 17:17:59 -0700845 logging.debug("Received len " + str(len(rcv_pkt)) + ": "
Dan Talaycof6e76c02012-03-23 10:56:12 -0700846 + str(rcv_pkt).encode('hex'))
Rich Lane5d7e89a2012-10-26 16:43:13 -0700847 logging.debug("Expected packet: " + inspect_packet(scapy.Ether(str(exp_pkt))))
848 logging.debug("Received packet: " + inspect_packet(scapy.Ether(str(rcv_pkt))))
Dan Talaycof6e76c02012-03-23 10:56:12 -0700849 parent.assertEqual(str(exp_pkt), str(rcv_pkt),
Dan Talaycod8ae7582012-03-23 12:24:56 -0700850 "Packet match error on port " + str(check_port))
Dan Talaycof6e76c02012-03-23 10:56:12 -0700851
Dan Talayco551befa2010-07-15 17:05:32 -0700852def match_verify(parent, req_match, res_match):
853 """
854 Verify flow matches agree; if they disagree, report where
855
856 parent must implement assertEqual
857 Use str() to ensure content is compared and not pointers
858 """
859
860 parent.assertEqual(req_match.wildcards, res_match.wildcards,
861 'Match failed: wildcards: ' + hex(req_match.wildcards) +
862 " != " + hex(res_match.wildcards))
863 parent.assertEqual(req_match.in_port, res_match.in_port,
864 'Match failed: in_port: ' + str(req_match.in_port) +
865 " != " + str(res_match.in_port))
Rich Laned0478ff2013-03-11 12:46:58 -0700866 parent.assertEqual(str(req_match.eth_src), str(res_match.eth_src),
867 'Match failed: eth_src: ' + str(req_match.eth_src) +
868 " != " + str(res_match.eth_src))
869 parent.assertEqual(str(req_match.eth_dst), str(res_match.eth_dst),
870 'Match failed: eth_dst: ' + str(req_match.eth_dst) +
871 " != " + str(res_match.eth_dst))
872 parent.assertEqual(req_match.vlan_vid, res_match.vlan_vid,
873 'Match failed: vlan_vid: ' + str(req_match.vlan_vid) +
874 " != " + str(res_match.vlan_vid))
875 parent.assertEqual(req_match.vlan_pcp, res_match.vlan_pcp,
876 'Match failed: vlan_pcp: ' +
877 str(req_match.vlan_pcp) + " != " +
878 str(res_match.vlan_pcp))
879 parent.assertEqual(req_match.eth_type, res_match.eth_type,
880 'Match failed: eth_type: ' + str(req_match.eth_type) +
881 " != " + str(res_match.eth_type))
Dan Talayco551befa2010-07-15 17:05:32 -0700882
Rich Lanee717c6e2013-03-12 10:25:50 -0700883 if (not(req_match.wildcards & ofp.OFPFW_DL_TYPE)
Rich Laned0478ff2013-03-11 12:46:58 -0700884 and (req_match.eth_type == IP_ETHERTYPE)):
885 parent.assertEqual(req_match.ip_dscp, res_match.ip_dscp,
886 'Match failed: ip_dscp: ' + str(req_match.ip_dscp) +
887 " != " + str(res_match.ip_dscp))
888 parent.assertEqual(req_match.ip_proto, res_match.ip_proto,
889 'Match failed: ip_proto: ' + str(req_match.ip_proto) +
890 " != " + str(res_match.ip_proto))
891 parent.assertEqual(req_match.ipv4_src, res_match.ipv4_src,
892 'Match failed: ipv4_src: ' + str(req_match.ipv4_src) +
893 " != " + str(res_match.ipv4_src))
894 parent.assertEqual(req_match.ipv4_dst, res_match.ipv4_dst,
895 'Match failed: ipv4_dst: ' + str(req_match.ipv4_dst) +
896 " != " + str(res_match.ipv4_dst))
Dan Talayco551befa2010-07-15 17:05:32 -0700897
Rich Lanee717c6e2013-03-12 10:25:50 -0700898 if (not(req_match.wildcards & ofp.OFPFW_NW_PROTO)
Rich Laned0478ff2013-03-11 12:46:58 -0700899 and ((req_match.ip_proto == TCP_PROTOCOL)
900 or (req_match.ip_proto == UDP_PROTOCOL))):
901 parent.assertEqual(req_match.tcp_src, res_match.tcp_src,
902 'Match failed: tcp_src: ' +
903 str(req_match.tcp_src) +
904 " != " + str(res_match.tcp_src))
905 parent.assertEqual(req_match.tcp_dst, res_match.tcp_dst,
906 'Match failed: tcp_dst: ' +
907 str(req_match.tcp_dst) +
908 " != " + str(res_match.tcp_dst))
Dan Talayco551befa2010-07-15 17:05:32 -0700909
Ed Swierk99a74de2012-08-22 06:40:54 -0700910def packet_to_flow_match(parent, packet):
Rich Lanef6883512013-03-11 17:00:09 -0700911 match = oftest.parse.packet_to_flow_match(packet)
Rich Laneab7476f2013-06-13 15:53:52 -0700912 if ofp.OFP_VERSION in [1, 2]:
913 match.wildcards |= required_wildcards(parent)
914 else:
915 # TODO remove incompatible OXM entries
916 pass
Ed Swierk99a74de2012-08-22 06:40:54 -0700917 return match
918
919def flow_msg_create(parent, pkt, ing_port=None, action_list=None, wildcards=None,
Dan Talaycof6e76c02012-03-23 10:56:12 -0700920 egr_ports=None, egr_queue=None, check_expire=False, in_band=False):
Dan Talayco551befa2010-07-15 17:05:32 -0700921 """
922 Create a flow message
923
924 Match on packet with given wildcards.
925 See flow_match_test for other parameter descriptoins
926 @param egr_queue if not None, make the output an enqueue action
Dan Talayco677c0b72011-08-23 22:53:38 -0700927 @param in_band if True, do not wildcard ingress port
Dan Talaycof6e76c02012-03-23 10:56:12 -0700928 @param egr_ports None (drop), single port or list of ports
Dan Talayco551befa2010-07-15 17:05:32 -0700929 """
Rich Lanef6883512013-03-11 17:00:09 -0700930 match = oftest.parse.packet_to_flow_match(pkt)
Dan Talayco551befa2010-07-15 17:05:32 -0700931 parent.assertTrue(match is not None, "Flow match from pkt failed")
Ed Swierk99a74de2012-08-22 06:40:54 -0700932 if wildcards is None:
933 wildcards = required_wildcards(parent)
Dan Talayco677c0b72011-08-23 22:53:38 -0700934 if in_band:
Rich Lanee717c6e2013-03-12 10:25:50 -0700935 wildcards &= ~ofp.OFPFW_IN_PORT
Dan Talayco551befa2010-07-15 17:05:32 -0700936 match.wildcards = wildcards
937 match.in_port = ing_port
938
Dan Talaycof6e76c02012-03-23 10:56:12 -0700939 if type(egr_ports) == type([]):
940 egr_port_list = egr_ports
941 else:
942 egr_port_list = [egr_ports]
943
Rich Lanee717c6e2013-03-12 10:25:50 -0700944 request = ofp.message.flow_add()
Dan Talayco551befa2010-07-15 17:05:32 -0700945 request.match = match
946 request.buffer_id = 0xffffffff
947 if check_expire:
Rich Lanee717c6e2013-03-12 10:25:50 -0700948 request.flags |= ofp.OFPFF_SEND_FLOW_REM
Dan Talayco551befa2010-07-15 17:05:32 -0700949 request.hard_timeout = 1
950
Rich Lane400fb9b2013-10-10 17:20:54 -0700951 if ofp.OFP_VERSION == 1:
952 actions = request.actions
953 else:
954 actions = []
955 request.instructions.append(ofp.instruction.apply_actions(actions))
956
Dan Talayco551befa2010-07-15 17:05:32 -0700957 if action_list is not None:
Rich Lane400fb9b2013-10-10 17:20:54 -0700958 actions.extend(action_list)
Dan Talayco551befa2010-07-15 17:05:32 -0700959
960 # Set up output/enqueue action if directed
961 if egr_queue is not None:
Dan Talaycof6e76c02012-03-23 10:56:12 -0700962 parent.assertTrue(egr_ports is not None, "Egress port not set")
Rich Lanee717c6e2013-03-12 10:25:50 -0700963 act = ofp.action.enqueue()
Dan Talaycof6e76c02012-03-23 10:56:12 -0700964 for egr_port in egr_port_list:
965 act.port = egr_port
966 act.queue_id = egr_queue
Rich Lane400fb9b2013-10-10 17:20:54 -0700967 actions.append(act)
Dan Talaycof6e76c02012-03-23 10:56:12 -0700968 elif egr_ports is not None:
969 for egr_port in egr_port_list:
Rich Lanee717c6e2013-03-12 10:25:50 -0700970 act = ofp.action.output()
Dan Talaycof6e76c02012-03-23 10:56:12 -0700971 act.port = egr_port
Rich Lane400fb9b2013-10-10 17:20:54 -0700972 actions.append(act)
Dan Talayco551befa2010-07-15 17:05:32 -0700973
Rich Lane9a003812012-10-04 17:17:59 -0700974 logging.debug(request.show())
Dan Talayco551befa2010-07-15 17:05:32 -0700975
976 return request
977
Jeffrey Townsendf3eae9c2012-03-28 18:23:21 -0700978def flow_msg_install(parent, request, clear_table_override=None):
Dan Talayco551befa2010-07-15 17:05:32 -0700979 """
980 Install a flow mod message in the switch
981
982 @param parent Must implement controller, assertEqual, assertTrue
983 @param request The request, all set to go
984 @param clear_table If true, clear the flow table before installing
985 """
Dan Talayco8a64e332012-03-28 14:53:20 -0700986
Rich Lane2014f9b2012-10-05 15:29:40 -0700987 clear_table = test_param_get('clear_table', default=True)
Jeffrey Townsendf3eae9c2012-03-28 18:23:21 -0700988 if(clear_table_override != None):
989 clear_table = clear_table_override
990
991 if clear_table:
Rich Lane9a003812012-10-04 17:17:59 -0700992 logging.debug("Clear flow table")
Rich Lane32bf9482013-01-03 17:26:30 -0800993 delete_all_flows(parent.controller)
Dan Talayco551befa2010-07-15 17:05:32 -0700994
Rich Lane9a003812012-10-04 17:17:59 -0700995 logging.debug("Insert flow")
Rich Lane5c3151c2013-01-03 17:15:41 -0800996 parent.controller.message_send(request)
Rich Lanee912d032012-12-22 14:28:33 -0800997
Rich Lane3a261d52013-01-03 17:45:08 -0800998 do_barrier(parent.controller)
Dan Talayco551befa2010-07-15 17:05:32 -0700999
Ed Swierk99a74de2012-08-22 06:40:54 -07001000def flow_match_test_port_pair(parent, ing_port, egr_ports, wildcards=None,
Rich Laned0478ff2013-03-11 12:46:58 -07001001 vlan_vid=-1, pkt=None, exp_pkt=None,
Rich Lanee5779d32012-10-05 17:56:04 -07001002 action_list=None):
Dan Talayco551befa2010-07-15 17:05:32 -07001003 """
1004 Flow match test on single TCP packet
Dan Talaycof6e76c02012-03-23 10:56:12 -07001005 @param egr_ports A single port or list of ports
Dan Talayco551befa2010-07-15 17:05:32 -07001006
1007 Run test with packet through switch from ing_port to egr_port
1008 See flow_match_test for parameter descriptions
1009 """
1010
Ed Swierk99a74de2012-08-22 06:40:54 -07001011 if wildcards is None:
1012 wildcards = required_wildcards(parent)
Rich Lane9a003812012-10-04 17:17:59 -07001013 logging.info("Pkt match test: " + str(ing_port) + " to " +
Dan Talaycof6e76c02012-03-23 10:56:12 -07001014 str(egr_ports))
Rich Laned0478ff2013-03-11 12:46:58 -07001015 logging.debug(" WC: " + hex(wildcards) + " vlan: " + str(vlan_vid))
Dan Talayco551befa2010-07-15 17:05:32 -07001016 if pkt is None:
Rich Laned0478ff2013-03-11 12:46:58 -07001017 pkt = simple_tcp_packet(dl_vlan_enable=(vlan_vid >= 0), vlan_vid=vlan_vid)
Rich Lanec41fbec2013-10-02 00:27:59 -07001018 if exp_pkt is None:
1019 exp_pkt = pkt
Dan Talayco551befa2010-07-15 17:05:32 -07001020
1021 request = flow_msg_create(parent, pkt, ing_port=ing_port,
Dan Talaycof6e76c02012-03-23 10:56:12 -07001022 wildcards=wildcards, egr_ports=egr_ports,
Dan Talayco551befa2010-07-15 17:05:32 -07001023 action_list=action_list)
1024
1025 flow_msg_install(parent, request)
1026
Rich Lane9a003812012-10-04 17:17:59 -07001027 logging.debug("Send packet: " + str(ing_port) + " to " +
Dan Talaycof6e76c02012-03-23 10:56:12 -07001028 str(egr_ports))
Dan Talayco551befa2010-07-15 17:05:32 -07001029 parent.dataplane.send(ing_port, str(pkt))
1030
Rich Lane8f45e2d2013-10-01 16:06:54 -07001031 exp_ports = [ing_port if port == ofp.OFPP_IN_PORT else port for port in egr_ports]
Rich Lanee4b384d2013-09-13 14:33:40 -07001032 verify_packets(parent, exp_pkt, exp_ports)
Dan Talayco551befa2010-07-15 17:05:32 -07001033
Rich Lane89725bb2012-12-03 16:23:27 -08001034def flow_match_test_pktout(parent, ing_port, egr_ports,
Rich Laned0478ff2013-03-11 12:46:58 -07001035 vlan_vid=-1, pkt=None, exp_pkt=None,
Rich Lane89725bb2012-12-03 16:23:27 -08001036 action_list=None):
1037 """
1038 Packet-out test on single TCP packet
1039 @param egr_ports A single port or list of ports
1040
1041 Run test sending packet-out to egr_ports. The goal is to test the actions
1042 taken on the packet, not the matching which is of course irrelevant.
1043 See flow_match_test for parameter descriptions
1044 """
1045
1046 if pkt is None:
Rich Laned0478ff2013-03-11 12:46:58 -07001047 pkt = simple_tcp_packet(dl_vlan_enable=(vlan_vid >= 0), vlan_vid=vlan_vid)
Rich Lanec41fbec2013-10-02 00:27:59 -07001048 if exp_pkt is None:
1049 exp_pkt = pkt
Rich Lane89725bb2012-12-03 16:23:27 -08001050
Rich Lanee717c6e2013-03-12 10:25:50 -07001051 msg = ofp.message.packet_out()
Rich Lane89725bb2012-12-03 16:23:27 -08001052 msg.in_port = ing_port
Rich Laneea8c4722013-04-04 15:30:20 -07001053 msg.buffer_id = 0xffffffff
Rich Lane89725bb2012-12-03 16:23:27 -08001054 msg.data = str(pkt)
1055 if action_list is not None:
1056 for act in action_list:
Rich Lanec495d9e2013-03-08 17:43:36 -08001057 msg.actions.append(act)
Rich Lane89725bb2012-12-03 16:23:27 -08001058
1059 # Set up output action
1060 if egr_ports is not None:
1061 for egr_port in egr_ports:
Rich Lanee717c6e2013-03-12 10:25:50 -07001062 act = ofp.action.output()
Rich Lane89725bb2012-12-03 16:23:27 -08001063 act.port = egr_port
Rich Lanec495d9e2013-03-08 17:43:36 -08001064 msg.actions.append(act)
Rich Lane89725bb2012-12-03 16:23:27 -08001065
1066 logging.debug(msg.show())
Rich Lane5c3151c2013-01-03 17:15:41 -08001067 parent.controller.message_send(msg)
Rich Lane89725bb2012-12-03 16:23:27 -08001068
Rich Lane8f45e2d2013-10-01 16:06:54 -07001069 exp_ports = [ing_port if port == ofp.OFPP_IN_PORT else port for port in egr_ports]
Rich Lanee4b384d2013-09-13 14:33:40 -07001070 verify_packets(parent, exp_pkt, exp_ports)
Rich Lane89725bb2012-12-03 16:23:27 -08001071
Dan Talaycof6e76c02012-03-23 10:56:12 -07001072def get_egr_list(parent, of_ports, how_many, exclude_list=[]):
1073 """
1074 Generate a list of ports avoiding those in the exclude list
Rich Lane9a003812012-10-04 17:17:59 -07001075 @param parent Supplies logging
Dan Talaycof6e76c02012-03-23 10:56:12 -07001076 @param of_ports List of OF port numbers
1077 @param how_many Number of ports to be added to the list
1078 @param exclude_list List of ports not to be used
1079 @returns An empty list if unable to find enough ports
1080 """
1081
Dan Talaycoc948d0b2012-03-23 12:17:54 -07001082 if how_many == 0:
1083 return []
1084
Dan Talaycof6e76c02012-03-23 10:56:12 -07001085 count = 0
1086 egr_ports = []
1087 for egr_idx in range(len(of_ports)):
1088 if of_ports[egr_idx] not in exclude_list:
1089 egr_ports.append(of_ports[egr_idx])
1090 count += 1
1091 if count >= how_many:
1092 return egr_ports
Rich Lane9a003812012-10-04 17:17:59 -07001093 logging.debug("Could not generate enough egress ports for test")
Dan Talaycof6e76c02012-03-23 10:56:12 -07001094 return []
1095
Rich Laned0478ff2013-03-11 12:46:58 -07001096def flow_match_test(parent, port_map, wildcards=None, vlan_vid=-1, pkt=None,
Rich Lanee5779d32012-10-05 17:56:04 -07001097 exp_pkt=None, action_list=None,
Dan Talaycoc948d0b2012-03-23 12:17:54 -07001098 max_test=0, egr_count=1, ing_port=False):
Dan Talayco551befa2010-07-15 17:05:32 -07001099 """
Rich Lane89725bb2012-12-03 16:23:27 -08001100 Run flow_match_test_port_pair on all port pairs and packet-out
Dan Talayco551befa2010-07-15 17:05:32 -07001101
1102 @param max_test If > 0 no more than this number of tests are executed.
1103 @param parent Must implement controller, dataplane, assertTrue, assertEqual
Rich Lane9a003812012-10-04 17:17:59 -07001104 and logging
Dan Talayco551befa2010-07-15 17:05:32 -07001105 @param pkt If not None, use this packet for ingress
1106 @param wildcards For flow match entry
Rich Laned0478ff2013-03-11 12:46:58 -07001107 @param vlan_vid If not -1, and pkt is None, create a pkt w/ VLAN tag
Dan Talayco551befa2010-07-15 17:05:32 -07001108 @param exp_pkt If not None, use this as the expected output pkt; els use pkt
1109 @param action_list Additional actions to add to flow mod
Dan Talaycocfa172f2012-03-23 12:03:00 -07001110 @param egr_count Number of egress ports; -1 means get from config w/ dflt 2
Dan Talayco551befa2010-07-15 17:05:32 -07001111 """
Ed Swierk99a74de2012-08-22 06:40:54 -07001112 if wildcards is None:
1113 wildcards = required_wildcards(parent)
Dan Talayco551befa2010-07-15 17:05:32 -07001114 of_ports = port_map.keys()
1115 of_ports.sort()
1116 parent.assertTrue(len(of_ports) > 1, "Not enough ports for test")
1117 test_count = 0
1118
Dan Talaycocfa172f2012-03-23 12:03:00 -07001119 if egr_count == -1:
Rich Lane2014f9b2012-10-05 15:29:40 -07001120 egr_count = test_param_get('egr_count', default=2)
Dan Talaycocfa172f2012-03-23 12:03:00 -07001121
Dan Talayco551befa2010-07-15 17:05:32 -07001122 for ing_idx in range(len(of_ports)):
1123 ingress_port = of_ports[ing_idx]
Dan Talaycof6e76c02012-03-23 10:56:12 -07001124 egr_ports = get_egr_list(parent, of_ports, egr_count,
1125 exclude_list=[ingress_port])
Dan Talaycoc948d0b2012-03-23 12:17:54 -07001126 if ing_port:
Rich Lanee717c6e2013-03-12 10:25:50 -07001127 egr_ports.append(ofp.OFPP_IN_PORT)
Dan Talaycof6e76c02012-03-23 10:56:12 -07001128 if len(egr_ports) == 0:
1129 parent.assertTrue(0, "Failed to generate egress port list")
1130
1131 flow_match_test_port_pair(parent, ingress_port, egr_ports,
Rich Laned0478ff2013-03-11 12:46:58 -07001132 wildcards=wildcards, vlan_vid=vlan_vid,
Dan Talaycof6e76c02012-03-23 10:56:12 -07001133 pkt=pkt, exp_pkt=exp_pkt,
Rich Lanee5779d32012-10-05 17:56:04 -07001134 action_list=action_list)
Dan Talaycof6e76c02012-03-23 10:56:12 -07001135 test_count += 1
1136 if (max_test > 0) and (test_count > max_test):
Rich Lane9a003812012-10-04 17:17:59 -07001137 logging.info("Ran " + str(test_count) + " tests; exiting")
Rich Lane89725bb2012-12-03 16:23:27 -08001138 break
1139
Ed Swierk38eea082013-01-02 19:46:20 -08001140 if not test_param_get('pktout_actions', default=True):
1141 return
Rich Lane89725bb2012-12-03 16:23:27 -08001142
1143 ingress_port = of_ports[0]
1144 egr_ports = get_egr_list(parent, of_ports, egr_count,
1145 exclude_list=[ingress_port])
1146 if ing_port:
Rich Lanee717c6e2013-03-12 10:25:50 -07001147 egr_ports.append(ofp.OFPP_IN_PORT)
Rich Lane89725bb2012-12-03 16:23:27 -08001148 flow_match_test_pktout(parent, ingress_port, egr_ports,
Rich Laned0478ff2013-03-11 12:46:58 -07001149 vlan_vid=vlan_vid,
Rich Lane89725bb2012-12-03 16:23:27 -08001150 pkt=pkt, exp_pkt=exp_pkt,
1151 action_list=action_list)
Dan Talayco551befa2010-07-15 17:05:32 -07001152
Rich Lane2014f9b2012-10-05 15:29:40 -07001153def test_param_get(key, default=None):
Dan Talayco4b2bee62010-07-20 14:10:05 -07001154 """
1155 Return value passed via test-params if present
1156
Dan Talayco4b2bee62010-07-20 14:10:05 -07001157 @param key The lookup key
1158 @param default Default value to use if not found
1159
1160 If the pair 'key=val' appeared in the string passed to --test-params
1161 on the command line, return val (as interpreted by exec). Otherwise
1162 return default value.
Dan Talaycof6e76c02012-03-23 10:56:12 -07001163
1164 WARNING: TEST PARAMETERS MUST BE PYTHON IDENTIFIERS;
1165 eg egr_count, not egr-count.
Dan Talayco4b2bee62010-07-20 14:10:05 -07001166 """
1167 try:
Rich Lanecd97d3d2013-01-07 18:50:06 -08001168 exec oftest.config["test_params"]
Dan Talayco4b2bee62010-07-20 14:10:05 -07001169 except:
1170 return default
1171
Dan Talayco4b2bee62010-07-20 14:10:05 -07001172 try:
Rich Lanefdec0fb2013-08-09 18:01:05 -07001173 return eval(str(key))
Dan Talayco4b2bee62010-07-20 14:10:05 -07001174 except:
1175 return default
1176
1177def action_generate(parent, field_to_mod, mod_field_vals):
1178 """
1179 Create an action to modify the field indicated in field_to_mod
1180
1181 @param parent Must implement, assertTrue
1182 @param field_to_mod The field to modify as a string name
1183 @param mod_field_vals Hash of values to use for modified values
1184 """
1185
1186 act = None
1187
1188 if field_to_mod in ['pktlen']:
1189 return None
1190
Rich Laned0478ff2013-03-11 12:46:58 -07001191 if field_to_mod == 'eth_dst':
Rich Lanee717c6e2013-03-12 10:25:50 -07001192 act = ofp.action.set_dl_dst()
Rich Lanef6883512013-03-11 17:00:09 -07001193 act.dl_addr = oftest.parse.parse_mac(mod_field_vals['eth_dst'])
Rich Laned0478ff2013-03-11 12:46:58 -07001194 elif field_to_mod == 'eth_src':
Rich Lanee717c6e2013-03-12 10:25:50 -07001195 act = ofp.action.set_dl_src()
Rich Lanef6883512013-03-11 17:00:09 -07001196 act.dl_addr = oftest.parse.parse_mac(mod_field_vals['eth_src'])
Dan Talayco4b2bee62010-07-20 14:10:05 -07001197 elif field_to_mod == 'dl_vlan_enable':
1198 if not mod_field_vals['dl_vlan_enable']: # Strip VLAN tag
Rich Lanee717c6e2013-03-12 10:25:50 -07001199 act = ofp.action.strip_vlan()
Rich Laned0478ff2013-03-11 12:46:58 -07001200 # Add VLAN tag is handled by vlan_vid field
Dan Talayco4b2bee62010-07-20 14:10:05 -07001201 # Will return None in this case
Rich Laned0478ff2013-03-11 12:46:58 -07001202 elif field_to_mod == 'vlan_vid':
Rich Lanee717c6e2013-03-12 10:25:50 -07001203 act = ofp.action.set_vlan_vid()
Rich Laned0478ff2013-03-11 12:46:58 -07001204 act.vlan_vid = mod_field_vals['vlan_vid']
1205 elif field_to_mod == 'vlan_pcp':
Rich Lanee717c6e2013-03-12 10:25:50 -07001206 act = ofp.action.set_vlan_pcp()
Rich Laned0478ff2013-03-11 12:46:58 -07001207 act.vlan_pcp = mod_field_vals['vlan_pcp']
Dan Talayco4b2bee62010-07-20 14:10:05 -07001208 elif field_to_mod == 'ip_src':
Rich Lanee717c6e2013-03-12 10:25:50 -07001209 act = ofp.action.set_nw_src()
Rich Lanef6883512013-03-11 17:00:09 -07001210 act.nw_addr = oftest.parse.parse_ip(mod_field_vals['ip_src'])
Dan Talayco4b2bee62010-07-20 14:10:05 -07001211 elif field_to_mod == 'ip_dst':
Rich Lanee717c6e2013-03-12 10:25:50 -07001212 act = ofp.action.set_nw_dst()
Rich Lanef6883512013-03-11 17:00:09 -07001213 act.nw_addr = oftest.parse.parse_ip(mod_field_vals['ip_dst'])
Dan Talayco4b2bee62010-07-20 14:10:05 -07001214 elif field_to_mod == 'ip_tos':
Rich Lanee717c6e2013-03-12 10:25:50 -07001215 act = ofp.action.set_nw_tos()
Dan Talayco4b2bee62010-07-20 14:10:05 -07001216 act.nw_tos = mod_field_vals['ip_tos']
1217 elif field_to_mod == 'tcp_sport':
Rich Lanee717c6e2013-03-12 10:25:50 -07001218 act = ofp.action.set_tp_src()
Dan Talayco4b2bee62010-07-20 14:10:05 -07001219 act.tp_port = mod_field_vals['tcp_sport']
1220 elif field_to_mod == 'tcp_dport':
Rich Lanee717c6e2013-03-12 10:25:50 -07001221 act = ofp.action.set_tp_dst()
Dan Talayco4b2bee62010-07-20 14:10:05 -07001222 act.tp_port = mod_field_vals['tcp_dport']
Rich Lane110e0e32012-10-26 16:21:46 -07001223 elif field_to_mod == 'udp_sport':
Rich Lanee717c6e2013-03-12 10:25:50 -07001224 act = ofp.action.set_tp_src()
Rich Lane110e0e32012-10-26 16:21:46 -07001225 act.tp_port = mod_field_vals['udp_sport']
1226 elif field_to_mod == 'udp_dport':
Rich Lanee717c6e2013-03-12 10:25:50 -07001227 act = ofp.action.set_tp_dst()
Rich Lane110e0e32012-10-26 16:21:46 -07001228 act.tp_port = mod_field_vals['udp_dport']
Dan Talayco4b2bee62010-07-20 14:10:05 -07001229 else:
1230 parent.assertTrue(0, "Unknown field to modify: " + str(field_to_mod))
1231
1232 return act
1233
1234def pkt_action_setup(parent, start_field_vals={}, mod_field_vals={},
Rich Lane110e0e32012-10-26 16:21:46 -07001235 mod_fields=[], tp="tcp", check_test_params=False):
Dan Talayco4b2bee62010-07-20 14:10:05 -07001236 """
1237 Set up the ingress and expected packet and action list for a test
1238
Rich Lane2014f9b2012-10-05 15:29:40 -07001239 @param parent Must implement assertTrue
Dan Talayco4b2bee62010-07-20 14:10:05 -07001240 @param start_field_values Field values to use for ingress packet (optional)
1241 @param mod_field_values Field values to use for modified packet (optional)
1242 @param mod_fields The list of fields to be modified by the switch in the test.
1243 @params check_test_params If True, will check the parameters vid, add_vlan
1244 and strip_vlan from the command line.
1245
1246 Returns a triple: pkt-to-send, expected-pkt, action-list
1247 """
1248
1249 new_actions = []
1250
Dan Talayco4b2bee62010-07-20 14:10:05 -07001251 base_pkt_params = {}
1252 base_pkt_params['pktlen'] = 100
Rich Laned0478ff2013-03-11 12:46:58 -07001253 base_pkt_params['eth_dst'] = '00:DE:F0:12:34:56'
1254 base_pkt_params['eth_src'] = '00:23:45:67:89:AB'
Dan Talayco4b2bee62010-07-20 14:10:05 -07001255 base_pkt_params['dl_vlan_enable'] = False
Rich Laned0478ff2013-03-11 12:46:58 -07001256 base_pkt_params['vlan_vid'] = 2
1257 base_pkt_params['vlan_pcp'] = 0
Dan Talayco4b2bee62010-07-20 14:10:05 -07001258 base_pkt_params['ip_src'] = '192.168.0.1'
1259 base_pkt_params['ip_dst'] = '192.168.0.2'
1260 base_pkt_params['ip_tos'] = 0
Rich Lane110e0e32012-10-26 16:21:46 -07001261 if tp == "tcp":
1262 base_pkt_params['tcp_sport'] = 1234
1263 base_pkt_params['tcp_dport'] = 80
1264 elif tp == "udp":
1265 base_pkt_params['udp_sport'] = 1234
1266 base_pkt_params['udp_dport'] = 80
Dan Talayco4b2bee62010-07-20 14:10:05 -07001267 for keyname in start_field_vals.keys():
1268 base_pkt_params[keyname] = start_field_vals[keyname]
1269
1270 mod_pkt_params = {}
1271 mod_pkt_params['pktlen'] = 100
Rich Laned0478ff2013-03-11 12:46:58 -07001272 mod_pkt_params['eth_dst'] = '00:21:0F:ED:CB:A9'
1273 mod_pkt_params['eth_src'] = '00:ED:CB:A9:87:65'
Dan Talayco4b2bee62010-07-20 14:10:05 -07001274 mod_pkt_params['dl_vlan_enable'] = False
Rich Laned0478ff2013-03-11 12:46:58 -07001275 mod_pkt_params['vlan_vid'] = 3
1276 mod_pkt_params['vlan_pcp'] = 7
Dan Talayco4b2bee62010-07-20 14:10:05 -07001277 mod_pkt_params['ip_src'] = '10.20.30.40'
1278 mod_pkt_params['ip_dst'] = '50.60.70.80'
1279 mod_pkt_params['ip_tos'] = 0xf0
Rich Lane110e0e32012-10-26 16:21:46 -07001280 if tp == "tcp":
1281 mod_pkt_params['tcp_sport'] = 4321
1282 mod_pkt_params['tcp_dport'] = 8765
1283 elif tp == "udp":
1284 mod_pkt_params['udp_sport'] = 4321
1285 mod_pkt_params['udp_dport'] = 8765
Dan Talayco4b2bee62010-07-20 14:10:05 -07001286 for keyname in mod_field_vals.keys():
1287 mod_pkt_params[keyname] = mod_field_vals[keyname]
1288
1289 # Check for test param modifications
1290 strip = False
1291 if check_test_params:
Rich Lane2014f9b2012-10-05 15:29:40 -07001292 add_vlan = test_param_get('add_vlan')
1293 strip_vlan = test_param_get('strip_vlan')
1294 vid = test_param_get('vid')
Dan Talayco4b2bee62010-07-20 14:10:05 -07001295
1296 if add_vlan and strip_vlan:
1297 parent.assertTrue(0, "Add and strip VLAN both specified")
1298
1299 if vid:
1300 base_pkt_params['dl_vlan_enable'] = True
Rich Laned0478ff2013-03-11 12:46:58 -07001301 base_pkt_params['vlan_vid'] = vid
1302 if 'vlan_vid' in mod_fields:
1303 mod_pkt_params['vlan_vid'] = vid + 1
Dan Talayco4b2bee62010-07-20 14:10:05 -07001304
1305 if add_vlan:
1306 base_pkt_params['dl_vlan_enable'] = False
1307 mod_pkt_params['dl_vlan_enable'] = True
1308 mod_pkt_params['pktlen'] = base_pkt_params['pktlen'] + 4
1309 mod_fields.append('pktlen')
1310 mod_fields.append('dl_vlan_enable')
Rich Laned0478ff2013-03-11 12:46:58 -07001311 if 'vlan_vid' not in mod_fields:
1312 mod_fields.append('vlan_vid')
Dan Talayco4b2bee62010-07-20 14:10:05 -07001313 elif strip_vlan:
1314 base_pkt_params['dl_vlan_enable'] = True
1315 mod_pkt_params['dl_vlan_enable'] = False
1316 mod_pkt_params['pktlen'] = base_pkt_params['pktlen'] - 4
1317 mod_fields.append('dl_vlan_enable')
1318 mod_fields.append('pktlen')
1319
Rich Lane110e0e32012-10-26 16:21:46 -07001320 if tp == "tcp":
1321 packet_builder = simple_tcp_packet
1322 elif tp == "udp":
1323 packet_builder = simple_udp_packet
1324 else:
1325 raise NotImplementedError("unknown transport protocol %s" % tp)
1326
Dan Talayco4b2bee62010-07-20 14:10:05 -07001327 # Build the ingress packet
Rich Lane110e0e32012-10-26 16:21:46 -07001328 ingress_pkt = packet_builder(**base_pkt_params)
Dan Talayco4b2bee62010-07-20 14:10:05 -07001329
1330 # Build the expected packet, modifying the indicated fields
1331 for item in mod_fields:
1332 base_pkt_params[item] = mod_pkt_params[item]
1333 act = action_generate(parent, item, mod_pkt_params)
1334 if act:
1335 new_actions.append(act)
1336
Rich Lane110e0e32012-10-26 16:21:46 -07001337 expected_pkt = packet_builder(**base_pkt_params)
Dan Talayco4b2bee62010-07-20 14:10:05 -07001338
1339 return (ingress_pkt, expected_pkt, new_actions)
Dan Talayco677c0b72011-08-23 22:53:38 -07001340
1341# Generate a simple "drop" flow mod
1342# If in_band is true, then only drop from first test port
1343def flow_mod_gen(port_map, in_band):
Rich Lanee717c6e2013-03-12 10:25:50 -07001344 request = ofp.message.flow_add()
1345 request.match.wildcards = ofp.OFPFW_ALL
Dan Talayco677c0b72011-08-23 22:53:38 -07001346 if in_band:
Rich Lanee717c6e2013-03-12 10:25:50 -07001347 request.match.wildcards = ofp.OFPFW_ALL - ofp.OFPFW_IN_PORT
Dan Talayco677c0b72011-08-23 22:53:38 -07001348 for of_port, ifname in port_map.items(): # Grab first port
1349 break
1350 request.match.in_port = of_port
1351 request.buffer_id = 0xffffffff
1352 return request
Dan Talaycoba3745c2010-07-21 21:51:08 -07001353
1354def skip_message_emit(parent, s):
1355 """
1356 Print out a 'skipped' message to stderr
1357
1358 @param s The string to print out to the log file
Dan Talaycoba3745c2010-07-21 21:51:08 -07001359 """
1360 global skipped_test_count
1361
1362 skipped_test_count += 1
Rich Lane9a003812012-10-04 17:17:59 -07001363 logging.info("Skipping: " + s)
Dan Talayco2940fdd2013-02-06 15:01:35 -08001364 if oftest.config["debug"] < logging.WARNING:
Dan Talaycoba3745c2010-07-21 21:51:08 -07001365 sys.stderr.write("(skipped) ")
1366 else:
1367 sys.stderr.write("(S)")
Dan Talayco677c0b72011-08-23 22:53:38 -07001368
Dan Talayco8a64e332012-03-28 14:53:20 -07001369
1370def all_stats_get(parent):
1371 """
1372 Get the aggregate stats for all flows in the table
1373 @param parent Test instance with controller connection and assert
1374 @returns dict with keys flows, packets, bytes, active (flows),
1375 lookups, matched
1376 """
Rich Lanee717c6e2013-03-12 10:25:50 -07001377 stat_req = ofp.message.aggregate_stats_request()
1378 stat_req.match = ofp.match()
1379 stat_req.match.wildcards = ofp.OFPFW_ALL
Dan Talayco8a64e332012-03-28 14:53:20 -07001380 stat_req.table_id = 0xff
Rich Lanee717c6e2013-03-12 10:25:50 -07001381 stat_req.out_port = ofp.OFPP_NONE
Dan Talayco8a64e332012-03-28 14:53:20 -07001382
1383 rv = {}
1384
Rich Lanec8aaa3e2012-07-26 19:28:02 -07001385 (reply, pkt) = parent.controller.transact(stat_req)
Rich Lane5fd6faf2013-03-11 13:30:20 -07001386 parent.assertTrue(len(reply.entries) == 1, "Did not receive flow stats reply")
Dan Talayco8a64e332012-03-28 14:53:20 -07001387
Rich Lane5fd6faf2013-03-11 13:30:20 -07001388 for obj in reply.entries:
Dan Talayco8a64e332012-03-28 14:53:20 -07001389 (rv["flows"], rv["packets"], rv["bytes"]) = (obj.flow_count,
1390 obj.packet_count, obj.byte_count)
1391 break
1392
Rich Lanee717c6e2013-03-12 10:25:50 -07001393 request = ofp.message.table_stats_request()
Rich Lanec8aaa3e2012-07-26 19:28:02 -07001394 (reply , pkt) = parent.controller.transact(request)
Dan Talayco8a64e332012-03-28 14:53:20 -07001395
1396
1397 (rv["active"], rv["lookups"], rv["matched"]) = (0,0,0)
Rich Lane5fd6faf2013-03-11 13:30:20 -07001398 for obj in reply.entries:
Dan Talayco8a64e332012-03-28 14:53:20 -07001399 rv["active"] += obj.active_count
1400 rv["lookups"] += obj.lookup_count
1401 rv["matched"] += obj.matched_count
1402
1403 return rv
Dan Talayco2baf8b52012-03-30 09:55:42 -07001404
Rich Lane7744e112013-01-11 17:23:57 -08001405_import_blacklist.add('FILTER')
Dan Talayco2baf8b52012-03-30 09:55:42 -07001406FILTER=''.join([(len(repr(chr(x)))==3) and chr(x) or '.'
1407 for x in range(256)])
1408
1409def hex_dump_buffer(src, length=16):
1410 """
1411 Convert src to a hex dump string and return the string
1412 @param src The source buffer
1413 @param length The number of bytes shown in each line
1414 @returns A string showing the hex dump
1415 """
Dan Talaycoc516fa02012-04-12 22:28:43 -07001416 result = ["\n"]
Dan Talayco2baf8b52012-03-30 09:55:42 -07001417 for i in xrange(0, len(src), length):
1418 chars = src[i:i+length]
1419 hex = ' '.join(["%02x" % ord(x) for x in chars])
1420 printable = ''.join(["%s" % ((ord(x) <= 127 and
1421 FILTER[ord(x)]) or '.') for x in chars])
1422 result.append("%04x %-*s %s\n" % (i, length*3, hex, printable))
1423 return ''.join(result)
1424
1425def format_packet(pkt):
1426 return "Packet length %d \n%s" % (len(str(pkt)),
1427 hex_dump_buffer(str(pkt)))
Rich Lane5d7e89a2012-10-26 16:43:13 -07001428
1429def inspect_packet(pkt):
1430 """
1431 Wrapper around scapy's show() method.
1432 @returns A string showing the dissected packet.
1433 """
1434 from cStringIO import StringIO
1435 out = None
1436 backup = sys.stdout
1437 try:
Rich Lanefdec0fb2013-08-09 18:01:05 -07001438 tmp = StringIO()
1439 sys.stdout = tmp
Rich Lane5d7e89a2012-10-26 16:43:13 -07001440 pkt.show2()
Rich Lanefdec0fb2013-08-09 18:01:05 -07001441 out = tmp.getvalue()
1442 tmp.close()
Rich Lane5d7e89a2012-10-26 16:43:13 -07001443 finally:
1444 sys.stdout = backup
1445 return out
Rich Lane0a4f6372013-01-02 14:40:22 -08001446
1447def nonstandard(cls):
1448 """
Rich Lanecc45b8e2013-01-02 15:55:02 -08001449 Testcase decorator that marks the test as being non-standard.
1450 These tests are not automatically added to the "standard" group.
Rich Lane0a4f6372013-01-02 14:40:22 -08001451 """
Rich Lanecc45b8e2013-01-02 15:55:02 -08001452 cls._nonstandard = True
Rich Lane0a4f6372013-01-02 14:40:22 -08001453 return cls
1454
1455def disabled(cls):
1456 """
Rich Lanecc45b8e2013-01-02 15:55:02 -08001457 Testcase decorator that marks the test as being disabled.
1458 These tests are not automatically added to the "standard" group or
1459 their module's group.
Rich Lane0a4f6372013-01-02 14:40:22 -08001460 """
Rich Lanecc45b8e2013-01-02 15:55:02 -08001461 cls._disabled = True
Rich Lane0a4f6372013-01-02 14:40:22 -08001462 return cls
Rich Lane97e99652013-01-02 17:23:20 -08001463
1464def group(name):
1465 """
1466 Testcase decorator that adds the test to a group.
1467 """
1468 def fn(cls):
1469 if not hasattr(cls, "_groups"):
1470 cls._groups = []
1471 cls._groups.append(name)
1472 return cls
1473 return fn
Rich Lane5a9a1922013-01-11 14:29:30 -08001474
1475def version(ver):
1476 """
1477 Testcase decorator that specifies which versions of OpenFlow the test
1478 supports. The default is 1.0+. This decorator may only be used once.
1479
1480 Supported syntax:
1481 1.0 -> 1.0
1482 1.0,1.2,1.3 -> 1.0, 1.2, 1.3
1483 1.0+ -> 1.0, 1.1, 1.2, 1.3
1484 """
1485 versions = parse_version(ver)
1486 def fn(cls):
1487 cls._versions = versions
1488 return cls
1489 return fn
1490
1491def parse_version(ver):
1492 allowed_versions = ["1.0", "1.1", "1.2", "1.3"]
1493 if re.match("^1\.\d+$", ver):
1494 versions = set([ver])
1495 elif re.match("^(1\.\d+)\+$", ver):
1496 if not ver[:-1] in allowed_versions:
1497 raise ValueError("invalid OpenFlow version %s" % ver[:-1])
1498 versions = set()
1499 if ver != "1.1+": versions.add("1.0")
1500 if ver != "1.2+": versions.add("1.1")
1501 if ver != "1.3+": versions.add("1.2")
1502 versions.add("1.3")
1503 else:
1504 versions = set(ver.split(','))
1505
1506 for version in versions:
1507 if not version in allowed_versions:
1508 raise ValueError("invalid OpenFlow version %s" % version)
1509
1510 return versions
1511
1512assert(parse_version("1.0") == set(["1.0"]))
1513assert(parse_version("1.0,1.2,1.3") == set(["1.0", "1.2", "1.3"]))
1514assert(parse_version("1.0+") == set(["1.0", "1.1", "1.2", "1.3"]))
Rich Lane7744e112013-01-11 17:23:57 -08001515
Rich Laneae3428c2013-03-07 14:37:42 -08001516def get_stats(test, req):
1517 """
1518 Retrieve a list of stats entries. Handles OFPSF_REPLY_MORE.
1519 """
Rich Lane609194f2013-10-21 06:17:37 -07001520 msgtype = ofp.OFPT_STATS_REPLY
1521 more_flag = ofp.OFPSF_REPLY_MORE
Rich Laneae3428c2013-03-07 14:37:42 -08001522 stats = []
1523 reply, _ = test.controller.transact(req)
1524 test.assertTrue(reply is not None, "No response to stats request")
Rich Lane34c68d52013-10-11 10:38:21 -07001525 test.assertEquals(reply.type, msgtype, "Response had unexpected message type")
Rich Lane5fd6faf2013-03-11 13:30:20 -07001526 stats.extend(reply.entries)
Rich Lanebd56ed62013-07-10 15:49:44 -07001527 while reply.flags & more_flag != 0:
Rich Lane34c68d52013-10-11 10:38:21 -07001528 reply, pkt = test.controller.poll(exp_msg=msgtype)
Rich Laneae3428c2013-03-07 14:37:42 -08001529 test.assertTrue(reply is not None, "No response to stats request")
Rich Lane5fd6faf2013-03-11 13:30:20 -07001530 stats.extend(reply.entries)
Rich Laneae3428c2013-03-07 14:37:42 -08001531 return stats
1532
Rich Lanebd56ed62013-07-10 15:49:44 -07001533def get_flow_stats(test, match, table_id=None,
1534 out_port=None, out_group=None,
1535 cookie=0, cookie_mask=0):
Rich Laneae3428c2013-03-07 14:37:42 -08001536 """
1537 Retrieve a list of flow stats entries.
1538 """
Rich Lanebd56ed62013-07-10 15:49:44 -07001539
1540 if table_id == None:
1541 if ofp.OFP_VERSION <= 2:
1542 table_id = 0xff
1543 else:
1544 table_id = ofp.OFPTT_ALL
1545
Rich Lanef3bc48c2013-05-03 17:39:35 -07001546 if out_port == None:
Rich Lanebd56ed62013-07-10 15:49:44 -07001547 if ofp.OFP_VERSION == 1:
1548 out_port = ofp.OFPP_NONE
1549 else:
1550 out_port = ofp.OFPP_ANY
1551
1552 if out_group == None:
1553 if ofp.OFP_VERSION > 1:
1554 out_group = ofp.OFPP_ANY
1555
Rich Lanee717c6e2013-03-12 10:25:50 -07001556 req = ofp.message.flow_stats_request(match=match,
Rich Lanebd56ed62013-07-10 15:49:44 -07001557 table_id=table_id,
1558 out_port=out_port)
1559 if ofp.OFP_VERSION > 1:
1560 req.out_group = out_group
1561 req.cookie = cookie
1562 req.cookie_mask = cookie_mask
1563
Rich Laneae3428c2013-03-07 14:37:42 -08001564 return get_stats(test, req)
1565
Rich Lane968b6192013-03-07 15:34:43 -08001566def get_port_stats(test, port_no):
1567 """
1568 Retrieve a list of port stats entries.
1569 """
Rich Lanee717c6e2013-03-12 10:25:50 -07001570 req = ofp.message.port_stats_request(port_no=port_no)
Rich Lane968b6192013-03-07 15:34:43 -08001571 return get_stats(test, req)
1572
Rich Lane6a334922013-03-07 16:14:52 -08001573def get_queue_stats(test, port_no, queue_id):
1574 """
1575 Retrieve a list of queue stats entries.
1576 """
Rich Lanee717c6e2013-03-12 10:25:50 -07001577 req = ofp.message.queue_stats_request(port_no=port_no, queue_id=queue_id)
Rich Lane6a334922013-03-07 16:14:52 -08001578 return get_stats(test, req)
1579
Rich Laneae3428c2013-03-07 14:37:42 -08001580def verify_flow_stats(test, match, table_id=0xff,
Rich Laneae3428c2013-03-07 14:37:42 -08001581 initial=[],
1582 pkts=None, bytes=None):
1583 """
1584 Verify that flow stats changed as expected.
1585
1586 Optionally takes an 'initial' list of stats entries, as returned by
1587 get_flow_stats(). If 'initial' is not given the counters are assumed to
1588 begin at 0.
1589 """
Rich Lanef3bc48c2013-05-03 17:39:35 -07001590
Rich Laneae3428c2013-03-07 14:37:42 -08001591 def accumulate(stats):
1592 pkts_acc = bytes_acc = 0
1593 for stat in stats:
1594 pkts_acc += stat.packet_count
1595 bytes_acc += stat.byte_count
1596 return (pkts_acc, bytes_acc)
1597
1598 pkts_before, bytes_before = accumulate(initial)
1599
1600 # Wait 10s for counters to update
1601 pkt_diff = byte_diff = None
1602 for i in range(0, 100):
Rich Lane61edad52014-03-28 16:25:08 -07001603 stats = get_flow_stats(test, match, table_id=table_id)
Rich Laneae3428c2013-03-07 14:37:42 -08001604 pkts_after, bytes_after = accumulate(stats)
1605 pkt_diff = pkts_after - pkts_before
1606 byte_diff = bytes_after - bytes_before
1607 if (pkts == None or pkt_diff >= pkts) and \
1608 (bytes == None or byte_diff >= bytes):
1609 break
Dan Talayco53724732013-03-08 23:54:02 -08001610 time.sleep(0.1)
Rich Laneae3428c2013-03-07 14:37:42 -08001611
1612 if pkts != None:
1613 test.assertEquals(pkt_diff, pkts, "Flow packet counter not updated properly (expected increase of %d, got increase of %d)" % (pkts, pkt_diff))
1614
1615 if bytes != None:
Rich Lane53b96812013-03-07 16:54:50 -08001616 test.assertTrue(byte_diff >= bytes and byte_diff <= bytes*1.1,
1617 "Flow byte counter not updated properly (expected increase of %d, got increase of %d)" % (bytes, byte_diff))
Rich Laneae3428c2013-03-07 14:37:42 -08001618
Rich Lane968b6192013-03-07 15:34:43 -08001619def verify_port_stats(test, port,
1620 initial=[],
1621 tx_pkts=None, rx_pkts=None,
1622 tx_bytes=None, rx_bytes=None):
1623 """
1624 Verify that port stats changed as expected.
1625
1626 Optionally takes an 'initial' list of stats entries, as returned by
1627 get_port_stats(). If 'initial' is not given the counters are assumed to
1628 begin at 0.
1629 """
1630 def accumulate(stats):
1631 tx_pkts_acc = rx_pkts_acc = tx_bytes_acc = rx_bytes_acc = 0
1632 for stat in stats:
1633 tx_pkts_acc += stat.tx_packets
1634 rx_pkts_acc += stat.rx_packets
1635 tx_bytes_acc += stat.tx_bytes
1636 rx_bytes_acc += stat.rx_bytes
1637 return (tx_pkts_acc, rx_pkts_acc, tx_bytes_acc, rx_bytes_acc)
1638
1639 tx_pkts_before, rx_pkts_before, \
1640 tx_bytes_before, rx_bytes_before = accumulate(initial)
1641
1642 # Wait 10s for counters to update
1643 for i in range(0, 100):
1644 stats = get_port_stats(test, port)
1645 tx_pkts_after, rx_pkts_after, \
1646 tx_bytes_after, rx_bytes_after = accumulate(stats)
1647 tx_pkts_diff = tx_pkts_after - tx_pkts_before
1648 rx_pkts_diff = rx_pkts_after - rx_pkts_before
1649 tx_bytes_diff = tx_bytes_after - tx_bytes_before
1650 rx_bytes_diff = rx_bytes_after - rx_bytes_before
Rich Lane3a208f82015-04-10 12:37:57 -07001651 if (tx_pkts == None or tx_pkts <= tx_pkts_diff) and \
1652 (rx_pkts == None or rx_pkts <= rx_pkts_diff) and \
Rich Lane53b96812013-03-07 16:54:50 -08001653 (tx_bytes == None or tx_bytes <= tx_bytes_diff) and \
1654 (rx_bytes == None or rx_bytes <= rx_bytes_diff):
Rich Lane968b6192013-03-07 15:34:43 -08001655 break
1656 time.sleep(0.1)
1657
1658 if (tx_pkts != None):
Rich Lane3a208f82015-04-10 12:37:57 -07001659 test.assertGreaterEqual(tx_pkts_diff, tx_pkts,
1660 "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 -08001661 if (rx_pkts != None):
Rich Lane3a208f82015-04-10 12:37:57 -07001662 test.assertGreaterEqual(rx_pkts_diff, rx_pkts,
1663 "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 -08001664 if (tx_bytes != None):
Rich Lane3a208f82015-04-10 12:37:57 -07001665 test.assertGreaterEqual(tx_bytes_diff, tx_bytes,
1666 "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 -08001667 if (rx_bytes != None):
Rich Lane3a208f82015-04-10 12:37:57 -07001668 test.assertGreaterEqual(rx_bytes_diff, rx_bytes,
1669 "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 -08001670
Rich Lane6a334922013-03-07 16:14:52 -08001671def verify_queue_stats(test, port_no, queue_id,
1672 initial=[],
1673 pkts=None, bytes=None):
1674 """
1675 Verify that queue stats changed as expected.
1676
1677 Optionally takes an 'initial' list of stats entries, as returned by
1678 get_queue_stats(). If 'initial' is not given the counters are assumed to
1679 begin at 0.
1680 """
1681 def accumulate(stats):
1682 pkts_acc = bytes_acc = 0
1683 for stat in stats:
1684 pkts_acc += stat.tx_packets
1685 bytes_acc += stat.tx_bytes
1686 return (pkts_acc, bytes_acc)
1687
1688 pkts_before, bytes_before = accumulate(initial)
1689
1690 # Wait 10s for counters to update
1691 pkt_diff = byte_diff = None
1692 for i in range(0, 100):
1693 stats = get_queue_stats(test, port_no, queue_id)
1694 pkts_after, bytes_after = accumulate(stats)
1695 pkt_diff = pkts_after - pkts_before
1696 byte_diff = bytes_after - bytes_before
1697 if (pkts == None or pkt_diff >= pkts) and \
1698 (bytes == None or byte_diff >= bytes):
1699 break
Dan Talayco53724732013-03-08 23:54:02 -08001700 time.sleep(0.1)
Rich Lane6a334922013-03-07 16:14:52 -08001701
1702 if pkts != None:
1703 test.assertEquals(pkt_diff, pkts, "Queue packet counter not updated properly (expected increase of %d, got increase of %d)" % (pkts, pkt_diff))
1704
1705 if bytes != None:
Rich Lane53b96812013-03-07 16:54:50 -08001706 test.assertTrue(byte_diff >= bytes and byte_diff <= bytes*1.1,
1707 "Queue byte counter not updated properly (expected increase of %d, got increase of %d)" % (bytes, byte_diff))
Rich Laneae3428c2013-03-07 14:37:42 -08001708
Rich Lane4c504f32013-06-07 17:24:14 -07001709def packet_in_match(msg, data, in_port=None, reason=None):
1710 """
1711 Check whether the packet_in message 'msg' has fields matching 'data',
1712 'in_port', and 'reason'.
1713
1714 This function handles truncated packet_in data. The 'in_port' and 'reason'
1715 parameters are optional.
1716
1717 @param msg packet_in message
1718 @param data Expected packet_in data
1719 @param in_port Expected packet_in in_port, or None
1720 @param reason Expected packet_in reason, or None
1721 """
1722
Rich Lanec0d26dd2013-07-10 12:46:03 -07001723 if ofp.OFP_VERSION <= 2:
1724 pkt_in_port = msg.in_port
1725 else:
1726 oxms = { type(oxm): oxm for oxm in msg.match.oxm_list }
1727 if ofp.oxm.in_port in oxms:
1728 pkt_in_port = oxms[ofp.oxm.in_port].value
1729 else:
1730 logging.warn("Missing in_port in packet-in message")
1731 pkt_in_port = None
1732
1733 if in_port != None and in_port != pkt_in_port:
Rich Lane9f2f17e2013-09-13 13:19:37 -07001734 logging.debug("Incorrect packet_in in_port (expected %d, received %d)", in_port, pkt_in_port)
Rich Lane4c504f32013-06-07 17:24:14 -07001735 return False
1736
Rich Lanec0d26dd2013-07-10 12:46:03 -07001737 if reason != None and reason != msg.reason:
Rich Lane4c504f32013-06-07 17:24:14 -07001738 logging.debug("Incorrect packet_in reason (expected %d, received %d)", reason, msg.reason)
1739 return False
1740
1741 # Check that one of the packets is a prefix of the other.
1742 # The received packet may be either truncated or padded, but not both.
1743 # (Some of the padding may be truncated but that's irrelevant). We
1744 # need to check that the smaller packet is a prefix of the larger one.
1745 # Note that this check succeeds if the switch sends a zero-length
1746 # packet-in.
1747 compare_len = min(len(msg.data), len(data))
1748 if data[:compare_len] != msg.data[:compare_len]:
1749 logging.debug("Incorrect packet_in data")
1750 logging.debug("Expected %s" % format_packet(data[:compare_len]))
1751 logging.debug("Received %s" % format_packet(msg.data[:compare_len]))
1752 return False
1753
1754 return True
1755
1756def verify_packet_in(test, data, in_port, reason, controller=None):
1757 """
1758 Assert that the controller receives a packet_in message matching data 'data'
1759 from port 'in_port' with reason 'reason'. Does not trigger the packet_in
1760 itself, that's up to the test case.
1761
1762 @param test Instance of base_tests.SimpleProtocol
1763 @param pkt String to expect as the packet_in data
1764 @param in_port OpenFlow port number to expect as the packet_in in_port
1765 @param reason One of OFPR_* to expect as the packet_in reason
1766 @param controller Controller instance, defaults to test.controller
1767 @returns The received packet-in message
1768 """
1769
1770 if controller == None:
1771 controller = test.controller
1772
1773 end_time = time.time() + oftest.ofutils.default_timeout
1774
1775 while True:
1776 msg, _ = controller.poll(ofp.OFPT_PACKET_IN, end_time - time.time())
1777 if not msg:
1778 # Timeout
1779 break
1780 elif packet_in_match(msg, data, in_port, reason):
1781 # Found a matching message
1782 break
1783
Kiran Poola58c5c042014-05-15 15:11:06 -07001784 test.assertTrue(msg is not None, 'Packet in message not received on port %r' % in_port)
Rich Lane4c504f32013-06-07 17:24:14 -07001785 return msg
1786
1787def verify_no_packet_in(test, data, in_port, controller=None):
1788 """
1789 Assert that the controller does not receive a packet_in message matching
1790 data 'data' from port 'in_port'.
1791
1792 @param test Instance of base_tests.SimpleProtocol
1793 @param pkt String to expect as the packet_in data
1794 @param in_port OpenFlow port number to expect as the packet_in in_port
1795 @param controller Controller instance, defaults to test.controller
1796 """
1797
1798 if controller == None:
1799 controller = test.controller
1800
1801 # Negative test, need to wait a short amount of time before checking we
1802 # didn't receive the message.
Rich Lane48f6aed2014-03-23 15:51:02 -07001803 time.sleep(oftest.ofutils.default_negative_timeout)
Rich Lane4c504f32013-06-07 17:24:14 -07001804
1805 # Check every packet_in queued in the controller
1806 while True:
1807 msg, _ = controller.poll(ofp.OFPT_PACKET_IN, timeout=0)
1808 if msg == None:
1809 # No more queued packet_in messages
1810 break
1811 elif packet_in_match(msg, data, in_port, None):
1812 # Found a matching message
1813 break
1814
Rich Lane82c882d2013-08-09 17:13:52 -07001815 if in_port == None:
1816 test.assertTrue(msg == None, "Did not expect a packet-in message on any port")
1817 else:
1818 test.assertTrue(msg == None, "Did not expect a packet-in message on port %d" % in_port)
Rich Lane4c504f32013-06-07 17:24:14 -07001819
Rich Lane045db072013-08-06 13:16:30 -07001820def openflow_ports(num=None):
1821 """
1822 Return a list of 'num' OpenFlow port numbers
1823
1824 If 'num' is None, return all available ports. Otherwise, limit the length
1825 of the result to 'num' and raise an exception if not enough ports are
1826 available.
1827 """
1828 ports = sorted(oftest.config["port_map"].keys())
1829 if num != None and len(ports) < num:
1830 raise Exception("test requires %d ports but only %d are available" % (num, len(ports)))
1831 return ports[:num]
1832
Rich Lanee4b384d2013-09-13 14:33:40 -07001833def verify_packet(test, pkt, ofport):
1834 """
1835 Check that an expected packet is received
1836 """
1837 logging.debug("Checking for pkt on port %r", ofport)
1838 (rcv_port, rcv_pkt, pkt_time) = test.dataplane.poll(port_number=ofport, exp_pkt=str(pkt))
1839 test.assertTrue(rcv_pkt != None, "Did not receive pkt on %r" % ofport)
macauley17cd60d2015-07-27 17:41:18 +08001840 return (rcv_port, rcv_pkt, pkt_time)
1841
Rich Lanee4b384d2013-09-13 14:33:40 -07001842def verify_no_packet(test, pkt, ofport):
1843 """
1844 Check that a particular packet is not received
1845 """
1846 logging.debug("Negative check for pkt on port %r", ofport)
Rich Lane48f6aed2014-03-23 15:51:02 -07001847 (rcv_port, rcv_pkt, pkt_time) = \
1848 test.dataplane.poll(
1849 port_number=ofport, exp_pkt=str(pkt),
1850 timeout=oftest.ofutils.default_negative_timeout)
Rich Lanee4b384d2013-09-13 14:33:40 -07001851 test.assertTrue(rcv_pkt == None, "Received packet on %r" % ofport)
1852
1853def verify_no_other_packets(test):
1854 """
1855 Check that no unexpected packets are received
1856
1857 This is a no-op if the --relax option is in effect.
1858 """
1859 if oftest.config["relax"]:
1860 return
1861 logging.debug("Checking for unexpected packets on all ports")
Rich Lane48f6aed2014-03-23 15:51:02 -07001862 (rcv_port, rcv_pkt, pkt_time) = test.dataplane.poll(timeout=oftest.ofutils.default_negative_timeout)
Rich Lanee4b384d2013-09-13 14:33:40 -07001863 if rcv_pkt != None:
1864 logging.debug("Received unexpected packet on port %r: %s", rcv_port, format_packet(rcv_pkt))
1865 test.assertTrue(rcv_pkt == None, "Unexpected packet on port %r" % rcv_port)
1866
1867def verify_packets(test, pkt, ofports):
1868 """
1869 Check that a packet is received on certain ports
1870
1871 Also verifies that the packet is not received on any other ports, and that no
1872 other packets are received (unless --relax is in effect).
1873
1874 This covers the common and simplest cases for checking dataplane outputs.
1875 For more complex usage, like multiple different packets being output, or
1876 multiple packets on the same port, use the primitive verify_packet,
1877 verify_no_packet, and verify_no_other_packets functions directly.
1878 """
1879 pkt = str(pkt)
1880 for ofport in openflow_ports():
1881 if ofport in ofports:
1882 verify_packet(test, pkt, ofport)
1883 else:
1884 verify_no_packet(test, pkt, ofport)
1885 verify_no_other_packets(test)
1886
Rich Lane12d04592013-10-10 17:21:07 -07001887def verify_no_errors(ctrl):
1888 error, _ = ctrl.poll(ofp.OFPT_ERROR, 0)
1889 if error:
1890 raise AssertionError("unexpected error type=%d code=%d" % (error.err_type, error.code))
Rich Lanee4b384d2013-09-13 14:33:40 -07001891
Jonathan Stoutfcee3142014-01-28 15:46:22 -05001892def verify_capability(test, capability):
1893 """
Jonathan Stout073642d2014-02-04 13:41:48 -05001894 Return True if DUT supports the specified capability.
Jonathan Stoutfcee3142014-01-28 15:46:22 -05001895
1896 @param test Instance of base_tests.SimpleProtocol
1897 @param capability One of ofp_capabilities.
1898 """
1899 logging.info("Verifing that capability code is valid.")
1900 test.assertIn(capability, ofp.const.ofp_capabilities_map,
1901 "Capability code %d does not exist." % capability)
1902 capability_str = ofp.const.ofp_capabilities_map[capability]
1903
1904 logging.info(("Sending features_request to test if capability "
Jonathan Stout97e458a2014-01-28 16:08:04 -05001905 "%s is supported."), capability_str)
Jonathan Stoutfcee3142014-01-28 15:46:22 -05001906 req = ofp.message.features_request()
1907 res, raw = test.controller.transact(req)
1908 test.assertIsNotNone(res, "Did not receive a response from the DUT.")
1909 test.assertEqual(res.type, ofp.OFPT_FEATURES_REPLY,
1910 ("Unexpected packet type %d received in response to "
1911 "OFPT_FEATURES_REQUEST") % res.type)
Jonathan Stout641167f2014-02-04 12:07:10 -05001912 logging.info("Received features_reply.")
Jonathan Stoutfcee3142014-01-28 15:46:22 -05001913
Jonathan Stout641167f2014-02-04 12:07:10 -05001914 if (res.capabilities & capability) > 0:
1915 logging.info("Switch capabilities bitmask claims to support %s",
1916 capability_str)
1917 return True, res.capabilities
1918 else:
1919 logging.info("Capabilities bitmask does not support %s.",
1920 capability_str)
1921 return False, res.capabilities
Jonathan Stoutfcee3142014-01-28 15:46:22 -05001922
Jonathan Stouteb3721d2014-02-04 13:59:12 -05001923def verify_configuration_flag(test, flag):
1924 """
1925 Return True if DUT supports specified configuration flag.
1926
1927 @param test Instance of base_tests.SimpleProtocol
1928 @param flag One of ofp_config_flags.
Jonathan Stout1ec8c0f2014-02-04 15:25:38 -05001929 @returns (supported, flags) Bool if flag is set and flag values.
Jonathan Stouteb3721d2014-02-04 13:59:12 -05001930 """
1931 logging.info("Verifing that flag is valid.")
1932 test.assertIn(flag, ofp.const.ofp_config_flags_map,
1933 "flag %s does not exist." % flag)
1934 flag_str = ofp.const.ofp_config_flags_map[flag]
1935
1936 logging.info("Sending OFPT_GET_CONFIG_REQUEST.")
1937 req = ofp.message.get_config_request()
1938 rv = test.controller.message_send(req)
1939 test.assertNotEqual(rv, -1, "Not able to send get_config_request.")
1940
1941 logging.info("Expecting OFPT_GET_CONFIG_REPLY ")
1942 (res, pkt) = test.controller.poll(exp_msg=ofp.OFPT_GET_CONFIG_REPLY,
1943 timeout=2)
1944 test.assertIsNotNone(res, "Did not receive OFPT_GET_CONFIG_REPLY")
1945 logging.info("Received OFPT_GET_CONFIG_REPLY ")
1946
1947 if res.flags == flag:
1948 logging.info("%s flag is set.", flag_str)
1949 return True, res.flags
1950 else:
1951 logging.info("%s flag is not set.", flag_str)
1952 return False, res.flags
1953
Rich Lane7744e112013-01-11 17:23:57 -08001954__all__ = list(set(locals()) - _import_blacklist)