blob: a5d626d83d66d584df76e3c4ef37939e00cef3b6 [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
Dan Talaycod2ca1032010-03-10 14:40:26 -08007
8try:
9 import scapy.all as scapy
10except:
11 try:
12 import scapy as scapy
13 except:
14 sys.exit("Need to install scapy for packet parsing")
Dan Talayco41eae8b2010-03-10 13:57:06 -080015
Rich Lanecd97d3d2013-01-07 18:50:06 -080016import oftest
17import oftest.controller
18import oftest.dataplane
Rich Lanef6883512013-03-11 17:00:09 -070019import oftest.parse
Rich Lane4c504f32013-06-07 17:24:14 -070020import oftest.ofutils
Rich Lanee717c6e2013-03-12 10:25:50 -070021import ofp
Dan Talaycoc901f4d2010-03-07 21:55:45 -080022
Dan Talaycoba3745c2010-07-21 21:51:08 -070023global skipped_test_count
24skipped_test_count = 0
25
Rich Lane7744e112013-01-11 17:23:57 -080026_import_blacklist = set(locals().keys())
27
Dan Talayco551befa2010-07-15 17:05:32 -070028# Some useful defines
29IP_ETHERTYPE = 0x800
30TCP_PROTOCOL = 0x6
31UDP_PROTOCOL = 0x11
32
Jeffrey Townsend5cb7ed32012-08-17 18:11:01 +000033MINSIZE = 0
34
Rich Lane9a003812012-10-04 17:17:59 -070035def delete_all_flows(ctrl):
Dan Talayco41eae8b2010-03-10 13:57:06 -080036 """
37 Delete all flows on the switch
38 @param ctrl The controller object for the test
Dan Talayco41eae8b2010-03-10 13:57:06 -080039 """
40
Rich Lane9a003812012-10-04 17:17:59 -070041 logging.info("Deleting all flows")
Rich Lanee717c6e2013-03-12 10:25:50 -070042 msg = ofp.message.flow_delete()
Rich Lanec717f442013-06-13 15:49:09 -070043 if ofp.OFP_VERSION in [1, 2]:
44 msg.match.wildcards = ofp.OFPFW_ALL
45 msg.out_port = ofp.OFPP_NONE
46 msg.buffer_id = 0xffffffff
47 elif ofp.OFP_VERSION >= 3:
48 msg.table_id = ofp.OFPTT_ALL
49 msg.buffer_id = ofp.OFP_NO_BUFFER
50 msg.out_port = ofp.OFPP_ANY
51 msg.out_group = ofp.OFPG_ANY
Rich Lane5c3151c2013-01-03 17:15:41 -080052 ctrl.message_send(msg)
Rich Lane44c4e3f2013-07-08 10:17:49 -070053 do_barrier(ctrl)
Rich Lane32bf9482013-01-03 17:26:30 -080054 return 0 # for backwards compatibility
Dan Talayco41eae8b2010-03-10 13:57:06 -080055
Ed Swierk99a74de2012-08-22 06:40:54 -070056def required_wildcards(parent):
Rich Lane2014f9b2012-10-05 15:29:40 -070057 w = test_param_get('required_wildcards', default='default')
Ed Swierk99a74de2012-08-22 06:40:54 -070058 if w == 'l3-l4':
Rich Lanee717c6e2013-03-12 10:25:50 -070059 return (ofp.OFPFW_NW_SRC_ALL | ofp.OFPFW_NW_DST_ALL | ofp.OFPFW_NW_TOS
60 | ofp.OFPFW_NW_PROTO | ofp.OFPFW_TP_SRC | ofp.OFPFW_TP_DST)
Ed Swierk99a74de2012-08-22 06:40:54 -070061 else:
62 return 0
63
Dan Talayco41eae8b2010-03-10 13:57:06 -080064def simple_tcp_packet(pktlen=100,
Rich Laned0478ff2013-03-11 12:46:58 -070065 eth_dst='00:01:02:03:04:05',
66 eth_src='00:06:07:08:09:0a',
Tatsuya Yabe460321e2010-05-25 17:50:49 -070067 dl_vlan_enable=False,
Rich Laned0478ff2013-03-11 12:46:58 -070068 vlan_vid=0,
69 vlan_pcp=0,
Dan Talayco551befa2010-07-15 17:05:32 -070070 dl_vlan_cfi=0,
Dan Talayco41eae8b2010-03-10 13:57:06 -080071 ip_src='192.168.0.1',
72 ip_dst='192.168.0.2',
Tatsuya Yabe460321e2010-05-25 17:50:49 -070073 ip_tos=0,
Gregor Maier9cc93342013-01-29 16:55:28 -080074 ip_ttl=64,
Dan Talayco41eae8b2010-03-10 13:57:06 -080075 tcp_sport=1234,
Christian Dickmann8b59b4b2012-09-23 16:48:30 -070076 tcp_dport=80,
77 ip_ihl=None,
78 ip_options=False
Dan Talayco41eae8b2010-03-10 13:57:06 -080079 ):
80 """
81 Return a simple dataplane TCP packet
82
83 Supports a few parameters:
84 @param len Length of packet in bytes w/o CRC
Rich Laned0478ff2013-03-11 12:46:58 -070085 @param eth_dst Destinatino MAC
86 @param eth_src Source MAC
Tatsuya Yabe460321e2010-05-25 17:50:49 -070087 @param dl_vlan_enable True if the packet is with vlan, False otherwise
Rich Laned0478ff2013-03-11 12:46:58 -070088 @param vlan_vid VLAN ID
89 @param vlan_pcp VLAN priority
Dan Talayco41eae8b2010-03-10 13:57:06 -080090 @param ip_src IP source
91 @param ip_dst IP destination
Tatsuya Yabe460321e2010-05-25 17:50:49 -070092 @param ip_tos IP ToS
Gregor Maier9cc93342013-01-29 16:55:28 -080093 @param ip_ttl IP TTL
Dan Talayco41eae8b2010-03-10 13:57:06 -080094 @param tcp_dport TCP destination port
95 @param ip_sport TCP source port
96
97 Generates a simple TCP request. Users
98 shouldn't assume anything about this packet other than that
99 it is a valid ethernet/IP/TCP frame.
100 """
Jeffrey Townsend5cb7ed32012-08-17 18:11:01 +0000101
102 if MINSIZE > pktlen:
103 pktlen = MINSIZE
104
Dan Talayco551befa2010-07-15 17:05:32 -0700105 # Note Dot1Q.id is really CFI
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800106 if (dl_vlan_enable):
Rich Laned0478ff2013-03-11 12:46:58 -0700107 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
108 scapy.Dot1Q(prio=vlan_pcp, id=dl_vlan_cfi, vlan=vlan_vid)/ \
Gregor Maier9cc93342013-01-29 16:55:28 -0800109 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ttl=ip_ttl, ihl=ip_ihl)/ \
Tatsuya Yabe460321e2010-05-25 17:50:49 -0700110 scapy.TCP(sport=tcp_sport, dport=tcp_dport)
111 else:
Christian Dickmann8b59b4b2012-09-23 16:48:30 -0700112 if not ip_options:
Rich Laned0478ff2013-03-11 12:46:58 -0700113 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
Gregor Maier9cc93342013-01-29 16:55:28 -0800114 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ttl=ip_ttl, ihl=ip_ihl)/ \
Christian Dickmann8b59b4b2012-09-23 16:48:30 -0700115 scapy.TCP(sport=tcp_sport, dport=tcp_dport)
116 else:
Rich Laned0478ff2013-03-11 12:46:58 -0700117 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
Gregor Maier9cc93342013-01-29 16:55:28 -0800118 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ttl=ip_ttl, ihl=ip_ihl, options=ip_options)/ \
Christian Dickmann8b59b4b2012-09-23 16:48:30 -0700119 scapy.TCP(sport=tcp_sport, dport=tcp_dport)
Tatsuya Yabe460321e2010-05-25 17:50:49 -0700120
Dan Talayco41eae8b2010-03-10 13:57:06 -0800121 pkt = pkt/("D" * (pktlen - len(pkt)))
122
123 return pkt
124
Rich Lane6ee7bea2012-10-26 16:19:29 -0700125def simple_udp_packet(pktlen=100,
Rich Laned0478ff2013-03-11 12:46:58 -0700126 eth_dst='00:01:02:03:04:05',
127 eth_src='00:06:07:08:09:0a',
Rich Lane6ee7bea2012-10-26 16:19:29 -0700128 dl_vlan_enable=False,
Rich Laned0478ff2013-03-11 12:46:58 -0700129 vlan_vid=0,
130 vlan_pcp=0,
Rich Lane6ee7bea2012-10-26 16:19:29 -0700131 dl_vlan_cfi=0,
132 ip_src='192.168.0.1',
133 ip_dst='192.168.0.2',
134 ip_tos=0,
Gregor Maier9cc93342013-01-29 16:55:28 -0800135 ip_ttl=64,
Rich Lane6ee7bea2012-10-26 16:19:29 -0700136 udp_sport=1234,
137 udp_dport=80,
138 ip_ihl=None,
139 ip_options=False
140 ):
141 """
142 Return a simple dataplane UDP packet
143
144 Supports a few parameters:
145 @param len Length of packet in bytes w/o CRC
Rich Laned0478ff2013-03-11 12:46:58 -0700146 @param eth_dst Destination MAC
147 @param eth_src Source MAC
Rich Lane6ee7bea2012-10-26 16:19:29 -0700148 @param dl_vlan_enable True if the packet is with vlan, False otherwise
Rich Laned0478ff2013-03-11 12:46:58 -0700149 @param vlan_vid VLAN ID
150 @param vlan_pcp VLAN priority
Rich Lane6ee7bea2012-10-26 16:19:29 -0700151 @param ip_src IP source
152 @param ip_dst IP destination
153 @param ip_tos IP ToS
Gregor Maier9cc93342013-01-29 16:55:28 -0800154 @param ip_ttl IP TTL
Rich Lane6ee7bea2012-10-26 16:19:29 -0700155 @param udp_dport UDP destination port
156 @param udp_sport UDP source port
157
158 Generates a simple UDP packet. Users shouldn't assume anything about
159 this packet other than that it is a valid ethernet/IP/UDP frame.
160 """
161
162 if MINSIZE > pktlen:
163 pktlen = MINSIZE
164
165 # Note Dot1Q.id is really CFI
166 if (dl_vlan_enable):
Rich Laned0478ff2013-03-11 12:46:58 -0700167 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
168 scapy.Dot1Q(prio=vlan_pcp, id=dl_vlan_cfi, vlan=vlan_vid)/ \
Gregor Maier9cc93342013-01-29 16:55:28 -0800169 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ttl=ip_ttl, ihl=ip_ihl)/ \
Rich Lane6ee7bea2012-10-26 16:19:29 -0700170 scapy.UDP(sport=udp_sport, dport=udp_dport)
171 else:
172 if not ip_options:
Rich Laned0478ff2013-03-11 12:46:58 -0700173 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
Gregor Maier9cc93342013-01-29 16:55:28 -0800174 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ttl=ip_ttl, ihl=ip_ihl)/ \
Rich Lane6ee7bea2012-10-26 16:19:29 -0700175 scapy.UDP(sport=udp_sport, dport=udp_dport)
176 else:
Rich Laned0478ff2013-03-11 12:46:58 -0700177 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
Gregor Maier9cc93342013-01-29 16:55:28 -0800178 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 -0700179 scapy.UDP(sport=udp_sport, dport=udp_dport)
180
181 pkt = pkt/("D" * (pktlen - len(pkt)))
182
183 return pkt
184
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700185def simple_icmp_packet(pktlen=60,
Rich Laned0478ff2013-03-11 12:46:58 -0700186 eth_dst='00:01:02:03:04:05',
187 eth_src='00:06:07:08:09:0a',
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700188 dl_vlan_enable=False,
Rich Laned0478ff2013-03-11 12:46:58 -0700189 vlan_vid=0,
190 vlan_pcp=0,
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700191 ip_src='192.168.0.1',
192 ip_dst='192.168.0.2',
193 ip_tos=0,
Gregor Maier9cc93342013-01-29 16:55:28 -0800194 ip_ttl=64,
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700195 icmp_type=8,
196 icmp_code=0
197 ):
198 """
199 Return a simple ICMP packet
200
201 Supports a few parameters:
202 @param len Length of packet in bytes w/o CRC
Rich Laned0478ff2013-03-11 12:46:58 -0700203 @param eth_dst Destinatino MAC
204 @param eth_src Source MAC
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700205 @param dl_vlan_enable True if the packet is with vlan, False otherwise
Rich Laned0478ff2013-03-11 12:46:58 -0700206 @param vlan_vid VLAN ID
207 @param vlan_pcp VLAN priority
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700208 @param ip_src IP source
209 @param ip_dst IP destination
210 @param ip_tos IP ToS
Gregor Maier9cc93342013-01-29 16:55:28 -0800211 @param ip_ttl IP TTL
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700212 @param icmp_type ICMP type
213 @param icmp_code ICMP code
214
215 Generates a simple ICMP ECHO REQUEST. Users
216 shouldn't assume anything about this packet other than that
217 it is a valid ethernet/ICMP frame.
218 """
Jeffrey Townsend5cb7ed32012-08-17 18:11:01 +0000219
220 if MINSIZE > pktlen:
221 pktlen = MINSIZE
222
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700223 if (dl_vlan_enable):
Rich Laned0478ff2013-03-11 12:46:58 -0700224 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
225 scapy.Dot1Q(prio=vlan_pcp, id=0, vlan=vlan_vid)/ \
Gregor Maier9cc93342013-01-29 16:55:28 -0800226 scapy.IP(src=ip_src, dst=ip_dst, ttl=ip_ttl, tos=ip_tos)/ \
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700227 scapy.ICMP(type=icmp_type, code=icmp_code)
228 else:
Rich Laned0478ff2013-03-11 12:46:58 -0700229 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
Gregor Maier9cc93342013-01-29 16:55:28 -0800230 scapy.IP(src=ip_src, dst=ip_dst, ttl=ip_ttl, tos=ip_tos)/ \
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700231 scapy.ICMP(type=icmp_type, code=icmp_code)
232
233 pkt = pkt/("0" * (pktlen - len(pkt)))
234
235 return pkt
236
Shudong Zhouc7562b12013-02-06 01:12:18 -0800237def simple_arp_packet(pktlen=60,
Rich Laned0478ff2013-03-11 12:46:58 -0700238 eth_dst='ff:ff:ff:ff:ff:ff',
239 eth_src='00:06:07:08:09:0a',
Shudong Zhouc7562b12013-02-06 01:12:18 -0800240 arp_op=1,
241 ip_snd='192.168.0.1',
242 ip_tgt='192.168.0.2',
243 hw_snd='00:06:07:08:09:0a',
244 hw_tgt='00:00:00:00:00:00',
245 ):
246 """
247 Return a simple ARP packet
248
249 Supports a few parameters:
250 @param len Length of packet in bytes w/o CRC
Rich Laned0478ff2013-03-11 12:46:58 -0700251 @param eth_dst Destinatino MAC
252 @param eth_src Source MAC
Shudong Zhouc7562b12013-02-06 01:12:18 -0800253 @param arp_op Operation (1=request, 2=reply)
254 @param ip_snd Sender IP
255 @param ip_tgt Target IP
256 @param hw_snd Sender hardware address
257 @param hw_tgt Target hardware address
258
259 Generates a simple ARP REQUEST. Users
260 shouldn't assume anything about this packet other than that
261 it is a valid ethernet/ARP frame.
262 """
263
264 if MINSIZE > pktlen:
265 pktlen = MINSIZE
266
Rich Laned0478ff2013-03-11 12:46:58 -0700267 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
Shudong Zhouc7562b12013-02-06 01:12:18 -0800268 scapy.ARP(hwsrc=hw_snd, hwdst=hw_tgt, pdst=ip_tgt, psrc=ip_snd, op=arp_op)
269
270 pkt = pkt/("0" * (pktlen - len(pkt)))
271
272 return pkt
273
Ed Swierk0aeff8c2012-03-23 20:27:18 -0700274def simple_eth_packet(pktlen=60,
Rich Laned0478ff2013-03-11 12:46:58 -0700275 eth_dst='00:01:02:03:04:05',
276 eth_src='01:80:c2:00:00:00',
277 eth_type=0x88cc):
Jeffrey Townsend5cb7ed32012-08-17 18:11:01 +0000278
279 if MINSIZE > pktlen:
280 pktlen = MINSIZE
281
Rich Laned0478ff2013-03-11 12:46:58 -0700282 pkt = scapy.Ether(dst=eth_dst, src=eth_src, type=eth_type)
Ed Swierk0aeff8c2012-03-23 20:27:18 -0700283
284 pkt = pkt/("0" * (pktlen - len(pkt)))
285
286 return pkt
287
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800288def qinq_tcp_packet(pktlen=100,
Rich Laned0478ff2013-03-11 12:46:58 -0700289 eth_dst='00:01:02:03:04:05',
290 eth_src='00:06:07:08:09:0a',
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800291 dl_vlan_outer=20,
292 dl_vlan_pcp_outer=0,
293 dl_vlan_cfi_outer=0,
Rich Laned0478ff2013-03-11 12:46:58 -0700294 vlan_vid=10,
295 vlan_pcp=0,
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800296 dl_vlan_cfi=0,
297 ip_src='192.168.0.1',
298 ip_dst='192.168.0.2',
299 ip_tos=0,
Gregor Maier9cc93342013-01-29 16:55:28 -0800300 ip_ttl=64,
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800301 tcp_sport=1234,
302 tcp_dport=80,
303 ip_ihl=None,
304 ip_options=False
305 ):
306 """
307 Return a doubly tagged dataplane TCP packet
308
309 Supports a few parameters:
310 @param len Length of packet in bytes w/o CRC
Rich Laned0478ff2013-03-11 12:46:58 -0700311 @param eth_dst Destinatino MAC
312 @param eth_src Source MAC
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800313 @param dl_vlan_outer Outer VLAN ID
314 @param dl_vlan_pcp_outer Outer VLAN priority
315 @param dl_vlan_cfi_outer Outer VLAN cfi bit
Rich Laned0478ff2013-03-11 12:46:58 -0700316 @param vlan_vid Inner VLAN ID
317 @param vlan_pcp VLAN priority
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800318 @param dl_vlan_cfi VLAN cfi bit
319 @param ip_src IP source
320 @param ip_dst IP destination
321 @param ip_tos IP ToS
322 @param tcp_dport TCP destination port
323 @param ip_sport TCP source port
324
325 Generates a TCP request. Users
326 shouldn't assume anything about this packet other than that
327 it is a valid ethernet/IP/TCP frame.
328 """
329
330 if MINSIZE > pktlen:
331 pktlen = MINSIZE
332
333 # Note Dot1Q.id is really CFI
Rich Laned0478ff2013-03-11 12:46:58 -0700334 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800335 scapy.Dot1Q(prio=dl_vlan_pcp_outer, id=dl_vlan_cfi_outer, vlan=dl_vlan_outer)/ \
Rich Laned0478ff2013-03-11 12:46:58 -0700336 scapy.Dot1Q(prio=vlan_pcp, id=dl_vlan_cfi, vlan=vlan_vid)/ \
Gregor Maier9cc93342013-01-29 16:55:28 -0800337 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ttl=ip_ttl, ihl=ip_ihl)/ \
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800338 scapy.TCP(sport=tcp_sport, dport=tcp_dport)
339
340 pkt = pkt/("D" * (pktlen - len(pkt)))
341
342 return pkt
343
Shudong Zhoub7f12462012-11-20 13:01:12 -0800344def do_barrier(ctrl, timeout=-1):
Dan Talayco0fc08bd2012-04-09 16:56:18 -0700345 """
346 Do a barrier command
347 Return 0 on success, -1 on error
348 """
Rich Lanee717c6e2013-03-12 10:25:50 -0700349 b = ofp.message.barrier_request()
Shudong Zhoub7f12462012-11-20 13:01:12 -0800350 (resp, pkt) = ctrl.transact(b, timeout=timeout)
Rich Lane3a261d52013-01-03 17:45:08 -0800351 if resp is None:
352 raise AssertionError("barrier failed")
Dan Talaycof6b94832012-04-12 21:50:57 -0700353 # We'll trust the transaction processing in the controller that xid matched
Rich Lane3a261d52013-01-03 17:45:08 -0800354 return 0 # for backwards compatibility
Dan Talayco92c99122010-06-03 13:53:18 -0700355
Rich Lane9a003812012-10-04 17:17:59 -0700356def port_config_get(controller, port_no):
Dan Talayco92c99122010-06-03 13:53:18 -0700357 """
358 Get a port's configuration
359
360 Gets the switch feature configuration and grabs one port's
361 configuration
362
363 @returns (hwaddr, config, advert) The hwaddress, configuration and
364 advertised values
365 """
Rich Lanee717c6e2013-03-12 10:25:50 -0700366 request = ofp.message.features_request()
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700367 reply, pkt = controller.transact(request)
Rich Lane9a003812012-10-04 17:17:59 -0700368 logging.debug(reply.show())
Dan Talayco92c99122010-06-03 13:53:18 -0700369 if reply is None:
Rich Lane9a003812012-10-04 17:17:59 -0700370 logging.warn("Get feature request failed")
Dan Talayco92c99122010-06-03 13:53:18 -0700371 return None, None, None
372 for idx in range(len(reply.ports)):
373 if reply.ports[idx].port_no == port_no:
374 return (reply.ports[idx].hw_addr, reply.ports[idx].config,
375 reply.ports[idx].advertised)
376
Rich Lane9a003812012-10-04 17:17:59 -0700377 logging.warn("Did not find port number for port config")
Dan Talayco92c99122010-06-03 13:53:18 -0700378 return None, None, None
379
Rich Lane9a003812012-10-04 17:17:59 -0700380def port_config_set(controller, port_no, config, mask):
Dan Talayco92c99122010-06-03 13:53:18 -0700381 """
382 Set the port configuration according the given parameters
383
384 Gets the switch feature configuration and updates one port's
385 configuration value according to config and mask
386 """
Rich Lane9a003812012-10-04 17:17:59 -0700387 logging.info("Setting port " + str(port_no) + " to config " + str(config))
Rich Lanee717c6e2013-03-12 10:25:50 -0700388 request = ofp.message.features_request()
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700389 reply, pkt = controller.transact(request)
Dan Talayco92c99122010-06-03 13:53:18 -0700390 if reply is None:
391 return -1
Rich Lane9a003812012-10-04 17:17:59 -0700392 logging.debug(reply.show())
Ed Swierk8d84ce02012-12-27 15:36:48 -0800393 p = None
Dan Talayco92c99122010-06-03 13:53:18 -0700394 for idx in range(len(reply.ports)):
395 if reply.ports[idx].port_no == port_no:
Ed Swierk8d84ce02012-12-27 15:36:48 -0800396 p = reply.ports[idx]
Dan Talayco92c99122010-06-03 13:53:18 -0700397 break
Rich Lanee717c6e2013-03-12 10:25:50 -0700398 mod = ofp.message.port_mod()
Dan Talayco92c99122010-06-03 13:53:18 -0700399 mod.port_no = port_no
Ed Swierk8d84ce02012-12-27 15:36:48 -0800400 if p:
401 mod.hw_addr = p.hw_addr
Dan Talayco92c99122010-06-03 13:53:18 -0700402 mod.config = config
403 mod.mask = mask
Ed Swierk8d84ce02012-12-27 15:36:48 -0800404 if p:
405 mod.advertise = p.advertised
Rich Lane5c3151c2013-01-03 17:15:41 -0800406 controller.message_send(mod)
407 return 0
Dan Talayco92c99122010-06-03 13:53:18 -0700408
Rich Lane2014f9b2012-10-05 15:29:40 -0700409def receive_pkt_check(dp, pkt, yes_ports, no_ports, assert_if):
Dan Talayco92c99122010-06-03 13:53:18 -0700410 """
411 Check for proper receive packets across all ports
Ken Chiang1bf01602012-04-04 10:48:23 -0700412 @param dp The dataplane object
Dan Talayco92c99122010-06-03 13:53:18 -0700413 @param pkt Expected packet; may be None if yes_ports is empty
414 @param yes_ports Set or list of ports that should recieve packet
415 @param no_ports Set or list of ports that should not receive packet
416 @param assert_if Object that implements assertXXX
417 """
Rich Lane91765672012-12-06 16:33:04 -0800418
419 # Wait this long for packets that we don't expect to receive.
420 # 100ms is (rarely) too short for positive tests on slow
421 # switches but is definitely not too short for a negative test.
422 negative_timeout = 0.1
423
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700424 exp_pkt_arg = None
Rich Lanecd97d3d2013-01-07 18:50:06 -0800425 if oftest.config["relax"]:
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700426 exp_pkt_arg = pkt
427
Dan Talayco92c99122010-06-03 13:53:18 -0700428 for ofport in yes_ports:
Rich Lane9a003812012-10-04 17:17:59 -0700429 logging.debug("Checking for pkt on port " + str(ofport))
Ken Chiang1bf01602012-04-04 10:48:23 -0700430 (rcv_port, rcv_pkt, pkt_time) = dp.poll(
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700431 port_number=ofport, exp_pkt=exp_pkt_arg)
Dan Talayco92c99122010-06-03 13:53:18 -0700432 assert_if.assertTrue(rcv_pkt is not None,
433 "Did not receive pkt on " + str(ofport))
Rich Lanecd97d3d2013-01-07 18:50:06 -0800434 if not oftest.dataplane.match_exp_pkt(pkt, rcv_pkt):
Rich Lane3c266832013-01-29 18:29:15 -0800435 logging.debug("Expected %s" % format_packet(pkt))
436 logging.debug("Received %s" % format_packet(rcv_pkt))
Rich Lanecd97d3d2013-01-07 18:50:06 -0800437 assert_if.assertTrue(oftest.dataplane.match_exp_pkt(pkt, rcv_pkt),
Rich Lane3c266832013-01-29 18:29:15 -0800438 "Received packet does not match expected packet " +
Ken Chiang1bf01602012-04-04 10:48:23 -0700439 "on port " + str(ofport))
Dan Talayco73f84012012-10-02 09:23:18 -0700440 if len(no_ports) > 0:
Rich Lane91765672012-12-06 16:33:04 -0800441 time.sleep(negative_timeout)
Dan Talayco92c99122010-06-03 13:53:18 -0700442 for ofport in no_ports:
Rich Lane9a003812012-10-04 17:17:59 -0700443 logging.debug("Negative check for pkt on port " + str(ofport))
Ken Chiang1bf01602012-04-04 10:48:23 -0700444 (rcv_port, rcv_pkt, pkt_time) = dp.poll(
Rich Lane91765672012-12-06 16:33:04 -0800445 port_number=ofport, timeout=0, exp_pkt=exp_pkt_arg)
Dan Talayco92c99122010-06-03 13:53:18 -0700446 assert_if.assertTrue(rcv_pkt is None,
447 "Unexpected pkt on port " + str(ofport))
Dan Talayco551befa2010-07-15 17:05:32 -0700448
449
Dan Talaycoc948d0b2012-03-23 12:17:54 -0700450def receive_pkt_verify(parent, egr_ports, exp_pkt, ing_port):
Dan Talayco551befa2010-07-15 17:05:32 -0700451 """
452 Receive a packet and verify it matches an expected value
Dan Talaycof6e76c02012-03-23 10:56:12 -0700453 @param egr_port A single port or list of ports
Dan Talayco551befa2010-07-15 17:05:32 -0700454
455 parent must implement dataplane, assertTrue and assertEqual
456 """
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700457 exp_pkt_arg = None
Rich Lanecd97d3d2013-01-07 18:50:06 -0800458 if oftest.config["relax"]:
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700459 exp_pkt_arg = exp_pkt
460
Dan Talaycof6e76c02012-03-23 10:56:12 -0700461 if type(egr_ports) == type([]):
462 egr_port_list = egr_ports
463 else:
464 egr_port_list = [egr_ports]
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700465
Dan Talaycof6e76c02012-03-23 10:56:12 -0700466 # Expect a packet from each port on egr port list
467 for egr_port in egr_port_list:
Dan Talaycod8ae7582012-03-23 12:24:56 -0700468 check_port = egr_port
Rich Lanee717c6e2013-03-12 10:25:50 -0700469 if egr_port == ofp.OFPP_IN_PORT:
Dan Talaycod8ae7582012-03-23 12:24:56 -0700470 check_port = ing_port
Dan Talaycof6e76c02012-03-23 10:56:12 -0700471 (rcv_port, rcv_pkt, pkt_time) = parent.dataplane.poll(
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700472 port_number=check_port, exp_pkt=exp_pkt_arg)
Dan Talayco551befa2010-07-15 17:05:32 -0700473
Dan Talaycof6e76c02012-03-23 10:56:12 -0700474 if rcv_pkt is None:
Rich Lane9a003812012-10-04 17:17:59 -0700475 logging.error("ERROR: No packet received from " +
Dan Talaycod8ae7582012-03-23 12:24:56 -0700476 str(check_port))
Dan Talayco551befa2010-07-15 17:05:32 -0700477
Dan Talaycof6e76c02012-03-23 10:56:12 -0700478 parent.assertTrue(rcv_pkt is not None,
Dan Talaycod8ae7582012-03-23 12:24:56 -0700479 "Did not receive packet port " + str(check_port))
Rich Lane9a003812012-10-04 17:17:59 -0700480 logging.debug("Packet len " + str(len(rcv_pkt)) + " in on " +
Dan Talaycof6e76c02012-03-23 10:56:12 -0700481 str(rcv_port))
482
483 if str(exp_pkt) != str(rcv_pkt):
Rich Lane9a003812012-10-04 17:17:59 -0700484 logging.error("ERROR: Packet match failed.")
485 logging.debug("Expected len " + str(len(exp_pkt)) + ": "
Dan Talaycof6e76c02012-03-23 10:56:12 -0700486 + str(exp_pkt).encode('hex'))
Rich Lane9a003812012-10-04 17:17:59 -0700487 logging.debug("Received len " + str(len(rcv_pkt)) + ": "
Dan Talaycof6e76c02012-03-23 10:56:12 -0700488 + str(rcv_pkt).encode('hex'))
Rich Lane5d7e89a2012-10-26 16:43:13 -0700489 logging.debug("Expected packet: " + inspect_packet(scapy.Ether(str(exp_pkt))))
490 logging.debug("Received packet: " + inspect_packet(scapy.Ether(str(rcv_pkt))))
Dan Talaycof6e76c02012-03-23 10:56:12 -0700491 parent.assertEqual(str(exp_pkt), str(rcv_pkt),
Dan Talaycod8ae7582012-03-23 12:24:56 -0700492 "Packet match error on port " + str(check_port))
Dan Talaycof6e76c02012-03-23 10:56:12 -0700493
Dan Talayco551befa2010-07-15 17:05:32 -0700494def match_verify(parent, req_match, res_match):
495 """
496 Verify flow matches agree; if they disagree, report where
497
498 parent must implement assertEqual
499 Use str() to ensure content is compared and not pointers
500 """
501
502 parent.assertEqual(req_match.wildcards, res_match.wildcards,
503 'Match failed: wildcards: ' + hex(req_match.wildcards) +
504 " != " + hex(res_match.wildcards))
505 parent.assertEqual(req_match.in_port, res_match.in_port,
506 'Match failed: in_port: ' + str(req_match.in_port) +
507 " != " + str(res_match.in_port))
Rich Laned0478ff2013-03-11 12:46:58 -0700508 parent.assertEqual(str(req_match.eth_src), str(res_match.eth_src),
509 'Match failed: eth_src: ' + str(req_match.eth_src) +
510 " != " + str(res_match.eth_src))
511 parent.assertEqual(str(req_match.eth_dst), str(res_match.eth_dst),
512 'Match failed: eth_dst: ' + str(req_match.eth_dst) +
513 " != " + str(res_match.eth_dst))
514 parent.assertEqual(req_match.vlan_vid, res_match.vlan_vid,
515 'Match failed: vlan_vid: ' + str(req_match.vlan_vid) +
516 " != " + str(res_match.vlan_vid))
517 parent.assertEqual(req_match.vlan_pcp, res_match.vlan_pcp,
518 'Match failed: vlan_pcp: ' +
519 str(req_match.vlan_pcp) + " != " +
520 str(res_match.vlan_pcp))
521 parent.assertEqual(req_match.eth_type, res_match.eth_type,
522 'Match failed: eth_type: ' + str(req_match.eth_type) +
523 " != " + str(res_match.eth_type))
Dan Talayco551befa2010-07-15 17:05:32 -0700524
Rich Lanee717c6e2013-03-12 10:25:50 -0700525 if (not(req_match.wildcards & ofp.OFPFW_DL_TYPE)
Rich Laned0478ff2013-03-11 12:46:58 -0700526 and (req_match.eth_type == IP_ETHERTYPE)):
527 parent.assertEqual(req_match.ip_dscp, res_match.ip_dscp,
528 'Match failed: ip_dscp: ' + str(req_match.ip_dscp) +
529 " != " + str(res_match.ip_dscp))
530 parent.assertEqual(req_match.ip_proto, res_match.ip_proto,
531 'Match failed: ip_proto: ' + str(req_match.ip_proto) +
532 " != " + str(res_match.ip_proto))
533 parent.assertEqual(req_match.ipv4_src, res_match.ipv4_src,
534 'Match failed: ipv4_src: ' + str(req_match.ipv4_src) +
535 " != " + str(res_match.ipv4_src))
536 parent.assertEqual(req_match.ipv4_dst, res_match.ipv4_dst,
537 'Match failed: ipv4_dst: ' + str(req_match.ipv4_dst) +
538 " != " + str(res_match.ipv4_dst))
Dan Talayco551befa2010-07-15 17:05:32 -0700539
Rich Lanee717c6e2013-03-12 10:25:50 -0700540 if (not(req_match.wildcards & ofp.OFPFW_NW_PROTO)
Rich Laned0478ff2013-03-11 12:46:58 -0700541 and ((req_match.ip_proto == TCP_PROTOCOL)
542 or (req_match.ip_proto == UDP_PROTOCOL))):
543 parent.assertEqual(req_match.tcp_src, res_match.tcp_src,
544 'Match failed: tcp_src: ' +
545 str(req_match.tcp_src) +
546 " != " + str(res_match.tcp_src))
547 parent.assertEqual(req_match.tcp_dst, res_match.tcp_dst,
548 'Match failed: tcp_dst: ' +
549 str(req_match.tcp_dst) +
550 " != " + str(res_match.tcp_dst))
Dan Talayco551befa2010-07-15 17:05:32 -0700551
Ed Swierk99a74de2012-08-22 06:40:54 -0700552def packet_to_flow_match(parent, packet):
Rich Lanef6883512013-03-11 17:00:09 -0700553 match = oftest.parse.packet_to_flow_match(packet)
Ed Swierk99a74de2012-08-22 06:40:54 -0700554 match.wildcards |= required_wildcards(parent)
555 return match
556
557def flow_msg_create(parent, pkt, ing_port=None, action_list=None, wildcards=None,
Dan Talaycof6e76c02012-03-23 10:56:12 -0700558 egr_ports=None, egr_queue=None, check_expire=False, in_band=False):
Dan Talayco551befa2010-07-15 17:05:32 -0700559 """
560 Create a flow message
561
562 Match on packet with given wildcards.
563 See flow_match_test for other parameter descriptoins
564 @param egr_queue if not None, make the output an enqueue action
Dan Talayco677c0b72011-08-23 22:53:38 -0700565 @param in_band if True, do not wildcard ingress port
Dan Talaycof6e76c02012-03-23 10:56:12 -0700566 @param egr_ports None (drop), single port or list of ports
Dan Talayco551befa2010-07-15 17:05:32 -0700567 """
Rich Lanef6883512013-03-11 17:00:09 -0700568 match = oftest.parse.packet_to_flow_match(pkt)
Dan Talayco551befa2010-07-15 17:05:32 -0700569 parent.assertTrue(match is not None, "Flow match from pkt failed")
Ed Swierk99a74de2012-08-22 06:40:54 -0700570 if wildcards is None:
571 wildcards = required_wildcards(parent)
Dan Talayco677c0b72011-08-23 22:53:38 -0700572 if in_band:
Rich Lanee717c6e2013-03-12 10:25:50 -0700573 wildcards &= ~ofp.OFPFW_IN_PORT
Dan Talayco551befa2010-07-15 17:05:32 -0700574 match.wildcards = wildcards
575 match.in_port = ing_port
576
Dan Talaycof6e76c02012-03-23 10:56:12 -0700577 if type(egr_ports) == type([]):
578 egr_port_list = egr_ports
579 else:
580 egr_port_list = [egr_ports]
581
Rich Lanee717c6e2013-03-12 10:25:50 -0700582 request = ofp.message.flow_add()
Dan Talayco551befa2010-07-15 17:05:32 -0700583 request.match = match
584 request.buffer_id = 0xffffffff
585 if check_expire:
Rich Lanee717c6e2013-03-12 10:25:50 -0700586 request.flags |= ofp.OFPFF_SEND_FLOW_REM
Dan Talayco551befa2010-07-15 17:05:32 -0700587 request.hard_timeout = 1
588
589 if action_list is not None:
590 for act in action_list:
Rich Lane9a003812012-10-04 17:17:59 -0700591 logging.debug("Adding action " + act.show())
Rich Lanec495d9e2013-03-08 17:43:36 -0800592 request.actions.append(act)
Dan Talayco551befa2010-07-15 17:05:32 -0700593
594 # Set up output/enqueue action if directed
595 if egr_queue is not None:
Dan Talaycof6e76c02012-03-23 10:56:12 -0700596 parent.assertTrue(egr_ports is not None, "Egress port not set")
Rich Lanee717c6e2013-03-12 10:25:50 -0700597 act = ofp.action.enqueue()
Dan Talaycof6e76c02012-03-23 10:56:12 -0700598 for egr_port in egr_port_list:
599 act.port = egr_port
600 act.queue_id = egr_queue
Rich Lanec495d9e2013-03-08 17:43:36 -0800601 request.actions.append(act)
Dan Talaycof6e76c02012-03-23 10:56:12 -0700602 elif egr_ports is not None:
603 for egr_port in egr_port_list:
Rich Lanee717c6e2013-03-12 10:25:50 -0700604 act = ofp.action.output()
Dan Talaycof6e76c02012-03-23 10:56:12 -0700605 act.port = egr_port
Rich Lanec495d9e2013-03-08 17:43:36 -0800606 request.actions.append(act)
Dan Talayco551befa2010-07-15 17:05:32 -0700607
Rich Lane9a003812012-10-04 17:17:59 -0700608 logging.debug(request.show())
Dan Talayco551befa2010-07-15 17:05:32 -0700609
610 return request
611
Jeffrey Townsendf3eae9c2012-03-28 18:23:21 -0700612def flow_msg_install(parent, request, clear_table_override=None):
Dan Talayco551befa2010-07-15 17:05:32 -0700613 """
614 Install a flow mod message in the switch
615
616 @param parent Must implement controller, assertEqual, assertTrue
617 @param request The request, all set to go
618 @param clear_table If true, clear the flow table before installing
619 """
Dan Talayco8a64e332012-03-28 14:53:20 -0700620
Rich Lane2014f9b2012-10-05 15:29:40 -0700621 clear_table = test_param_get('clear_table', default=True)
Jeffrey Townsendf3eae9c2012-03-28 18:23:21 -0700622 if(clear_table_override != None):
623 clear_table = clear_table_override
624
625 if clear_table:
Rich Lane9a003812012-10-04 17:17:59 -0700626 logging.debug("Clear flow table")
Rich Lane32bf9482013-01-03 17:26:30 -0800627 delete_all_flows(parent.controller)
Dan Talayco551befa2010-07-15 17:05:32 -0700628
Rich Lane9a003812012-10-04 17:17:59 -0700629 logging.debug("Insert flow")
Rich Lane5c3151c2013-01-03 17:15:41 -0800630 parent.controller.message_send(request)
Rich Lanee912d032012-12-22 14:28:33 -0800631
Rich Lane3a261d52013-01-03 17:45:08 -0800632 do_barrier(parent.controller)
Dan Talayco551befa2010-07-15 17:05:32 -0700633
Ed Swierk99a74de2012-08-22 06:40:54 -0700634def flow_match_test_port_pair(parent, ing_port, egr_ports, wildcards=None,
Rich Laned0478ff2013-03-11 12:46:58 -0700635 vlan_vid=-1, pkt=None, exp_pkt=None,
Rich Lanee5779d32012-10-05 17:56:04 -0700636 action_list=None):
Dan Talayco551befa2010-07-15 17:05:32 -0700637 """
638 Flow match test on single TCP packet
Dan Talaycof6e76c02012-03-23 10:56:12 -0700639 @param egr_ports A single port or list of ports
Dan Talayco551befa2010-07-15 17:05:32 -0700640
641 Run test with packet through switch from ing_port to egr_port
642 See flow_match_test for parameter descriptions
643 """
644
Ed Swierk99a74de2012-08-22 06:40:54 -0700645 if wildcards is None:
646 wildcards = required_wildcards(parent)
Rich Lane9a003812012-10-04 17:17:59 -0700647 logging.info("Pkt match test: " + str(ing_port) + " to " +
Dan Talaycof6e76c02012-03-23 10:56:12 -0700648 str(egr_ports))
Rich Laned0478ff2013-03-11 12:46:58 -0700649 logging.debug(" WC: " + hex(wildcards) + " vlan: " + str(vlan_vid))
Dan Talayco551befa2010-07-15 17:05:32 -0700650 if pkt is None:
Rich Laned0478ff2013-03-11 12:46:58 -0700651 pkt = simple_tcp_packet(dl_vlan_enable=(vlan_vid >= 0), vlan_vid=vlan_vid)
Dan Talayco551befa2010-07-15 17:05:32 -0700652
653 request = flow_msg_create(parent, pkt, ing_port=ing_port,
Dan Talaycof6e76c02012-03-23 10:56:12 -0700654 wildcards=wildcards, egr_ports=egr_ports,
Dan Talayco551befa2010-07-15 17:05:32 -0700655 action_list=action_list)
656
657 flow_msg_install(parent, request)
658
Rich Lane9a003812012-10-04 17:17:59 -0700659 logging.debug("Send packet: " + str(ing_port) + " to " +
Dan Talaycof6e76c02012-03-23 10:56:12 -0700660 str(egr_ports))
Dan Talayco551befa2010-07-15 17:05:32 -0700661 parent.dataplane.send(ing_port, str(pkt))
662
663 if exp_pkt is None:
664 exp_pkt = pkt
Dan Talaycoc948d0b2012-03-23 12:17:54 -0700665 receive_pkt_verify(parent, egr_ports, exp_pkt, ing_port)
Dan Talayco551befa2010-07-15 17:05:32 -0700666
Rich Lane89725bb2012-12-03 16:23:27 -0800667def flow_match_test_pktout(parent, ing_port, egr_ports,
Rich Laned0478ff2013-03-11 12:46:58 -0700668 vlan_vid=-1, pkt=None, exp_pkt=None,
Rich Lane89725bb2012-12-03 16:23:27 -0800669 action_list=None):
670 """
671 Packet-out test on single TCP packet
672 @param egr_ports A single port or list of ports
673
674 Run test sending packet-out to egr_ports. The goal is to test the actions
675 taken on the packet, not the matching which is of course irrelevant.
676 See flow_match_test for parameter descriptions
677 """
678
679 if pkt is None:
Rich Laned0478ff2013-03-11 12:46:58 -0700680 pkt = simple_tcp_packet(dl_vlan_enable=(vlan_vid >= 0), vlan_vid=vlan_vid)
Rich Lane89725bb2012-12-03 16:23:27 -0800681
Rich Lanee717c6e2013-03-12 10:25:50 -0700682 msg = ofp.message.packet_out()
Rich Lane89725bb2012-12-03 16:23:27 -0800683 msg.in_port = ing_port
Rich Laneea8c4722013-04-04 15:30:20 -0700684 msg.buffer_id = 0xffffffff
Rich Lane89725bb2012-12-03 16:23:27 -0800685 msg.data = str(pkt)
686 if action_list is not None:
687 for act in action_list:
Rich Lanec495d9e2013-03-08 17:43:36 -0800688 msg.actions.append(act)
Rich Lane89725bb2012-12-03 16:23:27 -0800689
690 # Set up output action
691 if egr_ports is not None:
692 for egr_port in egr_ports:
Rich Lanee717c6e2013-03-12 10:25:50 -0700693 act = ofp.action.output()
Rich Lane89725bb2012-12-03 16:23:27 -0800694 act.port = egr_port
Rich Lanec495d9e2013-03-08 17:43:36 -0800695 msg.actions.append(act)
Rich Lane89725bb2012-12-03 16:23:27 -0800696
697 logging.debug(msg.show())
Rich Lane5c3151c2013-01-03 17:15:41 -0800698 parent.controller.message_send(msg)
Rich Lane89725bb2012-12-03 16:23:27 -0800699
700 if exp_pkt is None:
701 exp_pkt = pkt
702 receive_pkt_verify(parent, egr_ports, exp_pkt, ing_port)
703
Dan Talaycof6e76c02012-03-23 10:56:12 -0700704def get_egr_list(parent, of_ports, how_many, exclude_list=[]):
705 """
706 Generate a list of ports avoiding those in the exclude list
Rich Lane9a003812012-10-04 17:17:59 -0700707 @param parent Supplies logging
Dan Talaycof6e76c02012-03-23 10:56:12 -0700708 @param of_ports List of OF port numbers
709 @param how_many Number of ports to be added to the list
710 @param exclude_list List of ports not to be used
711 @returns An empty list if unable to find enough ports
712 """
713
Dan Talaycoc948d0b2012-03-23 12:17:54 -0700714 if how_many == 0:
715 return []
716
Dan Talaycof6e76c02012-03-23 10:56:12 -0700717 count = 0
718 egr_ports = []
719 for egr_idx in range(len(of_ports)):
720 if of_ports[egr_idx] not in exclude_list:
721 egr_ports.append(of_ports[egr_idx])
722 count += 1
723 if count >= how_many:
724 return egr_ports
Rich Lane9a003812012-10-04 17:17:59 -0700725 logging.debug("Could not generate enough egress ports for test")
Dan Talaycof6e76c02012-03-23 10:56:12 -0700726 return []
727
Rich Laned0478ff2013-03-11 12:46:58 -0700728def flow_match_test(parent, port_map, wildcards=None, vlan_vid=-1, pkt=None,
Rich Lanee5779d32012-10-05 17:56:04 -0700729 exp_pkt=None, action_list=None,
Dan Talaycoc948d0b2012-03-23 12:17:54 -0700730 max_test=0, egr_count=1, ing_port=False):
Dan Talayco551befa2010-07-15 17:05:32 -0700731 """
Rich Lane89725bb2012-12-03 16:23:27 -0800732 Run flow_match_test_port_pair on all port pairs and packet-out
Dan Talayco551befa2010-07-15 17:05:32 -0700733
734 @param max_test If > 0 no more than this number of tests are executed.
735 @param parent Must implement controller, dataplane, assertTrue, assertEqual
Rich Lane9a003812012-10-04 17:17:59 -0700736 and logging
Dan Talayco551befa2010-07-15 17:05:32 -0700737 @param pkt If not None, use this packet for ingress
738 @param wildcards For flow match entry
Rich Laned0478ff2013-03-11 12:46:58 -0700739 @param vlan_vid If not -1, and pkt is None, create a pkt w/ VLAN tag
Dan Talayco551befa2010-07-15 17:05:32 -0700740 @param exp_pkt If not None, use this as the expected output pkt; els use pkt
741 @param action_list Additional actions to add to flow mod
Dan Talaycocfa172f2012-03-23 12:03:00 -0700742 @param egr_count Number of egress ports; -1 means get from config w/ dflt 2
Dan Talayco551befa2010-07-15 17:05:32 -0700743 """
Ed Swierk99a74de2012-08-22 06:40:54 -0700744 if wildcards is None:
745 wildcards = required_wildcards(parent)
Dan Talayco551befa2010-07-15 17:05:32 -0700746 of_ports = port_map.keys()
747 of_ports.sort()
748 parent.assertTrue(len(of_ports) > 1, "Not enough ports for test")
749 test_count = 0
750
Dan Talaycocfa172f2012-03-23 12:03:00 -0700751 if egr_count == -1:
Rich Lane2014f9b2012-10-05 15:29:40 -0700752 egr_count = test_param_get('egr_count', default=2)
Dan Talaycocfa172f2012-03-23 12:03:00 -0700753
Dan Talayco551befa2010-07-15 17:05:32 -0700754 for ing_idx in range(len(of_ports)):
755 ingress_port = of_ports[ing_idx]
Dan Talaycof6e76c02012-03-23 10:56:12 -0700756 egr_ports = get_egr_list(parent, of_ports, egr_count,
757 exclude_list=[ingress_port])
Dan Talaycoc948d0b2012-03-23 12:17:54 -0700758 if ing_port:
Rich Lanee717c6e2013-03-12 10:25:50 -0700759 egr_ports.append(ofp.OFPP_IN_PORT)
Dan Talaycof6e76c02012-03-23 10:56:12 -0700760 if len(egr_ports) == 0:
761 parent.assertTrue(0, "Failed to generate egress port list")
762
763 flow_match_test_port_pair(parent, ingress_port, egr_ports,
Rich Laned0478ff2013-03-11 12:46:58 -0700764 wildcards=wildcards, vlan_vid=vlan_vid,
Dan Talaycof6e76c02012-03-23 10:56:12 -0700765 pkt=pkt, exp_pkt=exp_pkt,
Rich Lanee5779d32012-10-05 17:56:04 -0700766 action_list=action_list)
Dan Talaycof6e76c02012-03-23 10:56:12 -0700767 test_count += 1
768 if (max_test > 0) and (test_count > max_test):
Rich Lane9a003812012-10-04 17:17:59 -0700769 logging.info("Ran " + str(test_count) + " tests; exiting")
Rich Lane89725bb2012-12-03 16:23:27 -0800770 break
771
Ed Swierk38eea082013-01-02 19:46:20 -0800772 if not test_param_get('pktout_actions', default=True):
773 return
Rich Lane89725bb2012-12-03 16:23:27 -0800774
775 ingress_port = of_ports[0]
776 egr_ports = get_egr_list(parent, of_ports, egr_count,
777 exclude_list=[ingress_port])
778 if ing_port:
Rich Lanee717c6e2013-03-12 10:25:50 -0700779 egr_ports.append(ofp.OFPP_IN_PORT)
Rich Lane89725bb2012-12-03 16:23:27 -0800780 flow_match_test_pktout(parent, ingress_port, egr_ports,
Rich Laned0478ff2013-03-11 12:46:58 -0700781 vlan_vid=vlan_vid,
Rich Lane89725bb2012-12-03 16:23:27 -0800782 pkt=pkt, exp_pkt=exp_pkt,
783 action_list=action_list)
Dan Talayco551befa2010-07-15 17:05:32 -0700784
Rich Lane2014f9b2012-10-05 15:29:40 -0700785def test_param_get(key, default=None):
Dan Talayco4b2bee62010-07-20 14:10:05 -0700786 """
787 Return value passed via test-params if present
788
Dan Talayco4b2bee62010-07-20 14:10:05 -0700789 @param key The lookup key
790 @param default Default value to use if not found
791
792 If the pair 'key=val' appeared in the string passed to --test-params
793 on the command line, return val (as interpreted by exec). Otherwise
794 return default value.
Dan Talaycof6e76c02012-03-23 10:56:12 -0700795
796 WARNING: TEST PARAMETERS MUST BE PYTHON IDENTIFIERS;
797 eg egr_count, not egr-count.
Dan Talayco4b2bee62010-07-20 14:10:05 -0700798 """
799 try:
Rich Lanecd97d3d2013-01-07 18:50:06 -0800800 exec oftest.config["test_params"]
Dan Talayco4b2bee62010-07-20 14:10:05 -0700801 except:
802 return default
803
804 s = "val = " + str(key)
805 try:
806 exec s
807 return val
808 except:
809 return default
810
811def action_generate(parent, field_to_mod, mod_field_vals):
812 """
813 Create an action to modify the field indicated in field_to_mod
814
815 @param parent Must implement, assertTrue
816 @param field_to_mod The field to modify as a string name
817 @param mod_field_vals Hash of values to use for modified values
818 """
819
820 act = None
821
822 if field_to_mod in ['pktlen']:
823 return None
824
Rich Laned0478ff2013-03-11 12:46:58 -0700825 if field_to_mod == 'eth_dst':
Rich Lanee717c6e2013-03-12 10:25:50 -0700826 act = ofp.action.set_dl_dst()
Rich Lanef6883512013-03-11 17:00:09 -0700827 act.dl_addr = oftest.parse.parse_mac(mod_field_vals['eth_dst'])
Rich Laned0478ff2013-03-11 12:46:58 -0700828 elif field_to_mod == 'eth_src':
Rich Lanee717c6e2013-03-12 10:25:50 -0700829 act = ofp.action.set_dl_src()
Rich Lanef6883512013-03-11 17:00:09 -0700830 act.dl_addr = oftest.parse.parse_mac(mod_field_vals['eth_src'])
Dan Talayco4b2bee62010-07-20 14:10:05 -0700831 elif field_to_mod == 'dl_vlan_enable':
832 if not mod_field_vals['dl_vlan_enable']: # Strip VLAN tag
Rich Lanee717c6e2013-03-12 10:25:50 -0700833 act = ofp.action.strip_vlan()
Rich Laned0478ff2013-03-11 12:46:58 -0700834 # Add VLAN tag is handled by vlan_vid field
Dan Talayco4b2bee62010-07-20 14:10:05 -0700835 # Will return None in this case
Rich Laned0478ff2013-03-11 12:46:58 -0700836 elif field_to_mod == 'vlan_vid':
Rich Lanee717c6e2013-03-12 10:25:50 -0700837 act = ofp.action.set_vlan_vid()
Rich Laned0478ff2013-03-11 12:46:58 -0700838 act.vlan_vid = mod_field_vals['vlan_vid']
839 elif field_to_mod == 'vlan_pcp':
Rich Lanee717c6e2013-03-12 10:25:50 -0700840 act = ofp.action.set_vlan_pcp()
Rich Laned0478ff2013-03-11 12:46:58 -0700841 act.vlan_pcp = mod_field_vals['vlan_pcp']
Dan Talayco4b2bee62010-07-20 14:10:05 -0700842 elif field_to_mod == 'ip_src':
Rich Lanee717c6e2013-03-12 10:25:50 -0700843 act = ofp.action.set_nw_src()
Rich Lanef6883512013-03-11 17:00:09 -0700844 act.nw_addr = oftest.parse.parse_ip(mod_field_vals['ip_src'])
Dan Talayco4b2bee62010-07-20 14:10:05 -0700845 elif field_to_mod == 'ip_dst':
Rich Lanee717c6e2013-03-12 10:25:50 -0700846 act = ofp.action.set_nw_dst()
Rich Lanef6883512013-03-11 17:00:09 -0700847 act.nw_addr = oftest.parse.parse_ip(mod_field_vals['ip_dst'])
Dan Talayco4b2bee62010-07-20 14:10:05 -0700848 elif field_to_mod == 'ip_tos':
Rich Lanee717c6e2013-03-12 10:25:50 -0700849 act = ofp.action.set_nw_tos()
Dan Talayco4b2bee62010-07-20 14:10:05 -0700850 act.nw_tos = mod_field_vals['ip_tos']
851 elif field_to_mod == 'tcp_sport':
Rich Lanee717c6e2013-03-12 10:25:50 -0700852 act = ofp.action.set_tp_src()
Dan Talayco4b2bee62010-07-20 14:10:05 -0700853 act.tp_port = mod_field_vals['tcp_sport']
854 elif field_to_mod == 'tcp_dport':
Rich Lanee717c6e2013-03-12 10:25:50 -0700855 act = ofp.action.set_tp_dst()
Dan Talayco4b2bee62010-07-20 14:10:05 -0700856 act.tp_port = mod_field_vals['tcp_dport']
Rich Lane110e0e32012-10-26 16:21:46 -0700857 elif field_to_mod == 'udp_sport':
Rich Lanee717c6e2013-03-12 10:25:50 -0700858 act = ofp.action.set_tp_src()
Rich Lane110e0e32012-10-26 16:21:46 -0700859 act.tp_port = mod_field_vals['udp_sport']
860 elif field_to_mod == 'udp_dport':
Rich Lanee717c6e2013-03-12 10:25:50 -0700861 act = ofp.action.set_tp_dst()
Rich Lane110e0e32012-10-26 16:21:46 -0700862 act.tp_port = mod_field_vals['udp_dport']
Dan Talayco4b2bee62010-07-20 14:10:05 -0700863 else:
864 parent.assertTrue(0, "Unknown field to modify: " + str(field_to_mod))
865
866 return act
867
868def pkt_action_setup(parent, start_field_vals={}, mod_field_vals={},
Rich Lane110e0e32012-10-26 16:21:46 -0700869 mod_fields=[], tp="tcp", check_test_params=False):
Dan Talayco4b2bee62010-07-20 14:10:05 -0700870 """
871 Set up the ingress and expected packet and action list for a test
872
Rich Lane2014f9b2012-10-05 15:29:40 -0700873 @param parent Must implement assertTrue
Dan Talayco4b2bee62010-07-20 14:10:05 -0700874 @param start_field_values Field values to use for ingress packet (optional)
875 @param mod_field_values Field values to use for modified packet (optional)
876 @param mod_fields The list of fields to be modified by the switch in the test.
877 @params check_test_params If True, will check the parameters vid, add_vlan
878 and strip_vlan from the command line.
879
880 Returns a triple: pkt-to-send, expected-pkt, action-list
881 """
882
883 new_actions = []
884
Dan Talayco4b2bee62010-07-20 14:10:05 -0700885 base_pkt_params = {}
886 base_pkt_params['pktlen'] = 100
Rich Laned0478ff2013-03-11 12:46:58 -0700887 base_pkt_params['eth_dst'] = '00:DE:F0:12:34:56'
888 base_pkt_params['eth_src'] = '00:23:45:67:89:AB'
Dan Talayco4b2bee62010-07-20 14:10:05 -0700889 base_pkt_params['dl_vlan_enable'] = False
Rich Laned0478ff2013-03-11 12:46:58 -0700890 base_pkt_params['vlan_vid'] = 2
891 base_pkt_params['vlan_pcp'] = 0
Dan Talayco4b2bee62010-07-20 14:10:05 -0700892 base_pkt_params['ip_src'] = '192.168.0.1'
893 base_pkt_params['ip_dst'] = '192.168.0.2'
894 base_pkt_params['ip_tos'] = 0
Rich Lane110e0e32012-10-26 16:21:46 -0700895 if tp == "tcp":
896 base_pkt_params['tcp_sport'] = 1234
897 base_pkt_params['tcp_dport'] = 80
898 elif tp == "udp":
899 base_pkt_params['udp_sport'] = 1234
900 base_pkt_params['udp_dport'] = 80
Dan Talayco4b2bee62010-07-20 14:10:05 -0700901 for keyname in start_field_vals.keys():
902 base_pkt_params[keyname] = start_field_vals[keyname]
903
904 mod_pkt_params = {}
905 mod_pkt_params['pktlen'] = 100
Rich Laned0478ff2013-03-11 12:46:58 -0700906 mod_pkt_params['eth_dst'] = '00:21:0F:ED:CB:A9'
907 mod_pkt_params['eth_src'] = '00:ED:CB:A9:87:65'
Dan Talayco4b2bee62010-07-20 14:10:05 -0700908 mod_pkt_params['dl_vlan_enable'] = False
Rich Laned0478ff2013-03-11 12:46:58 -0700909 mod_pkt_params['vlan_vid'] = 3
910 mod_pkt_params['vlan_pcp'] = 7
Dan Talayco4b2bee62010-07-20 14:10:05 -0700911 mod_pkt_params['ip_src'] = '10.20.30.40'
912 mod_pkt_params['ip_dst'] = '50.60.70.80'
913 mod_pkt_params['ip_tos'] = 0xf0
Rich Lane110e0e32012-10-26 16:21:46 -0700914 if tp == "tcp":
915 mod_pkt_params['tcp_sport'] = 4321
916 mod_pkt_params['tcp_dport'] = 8765
917 elif tp == "udp":
918 mod_pkt_params['udp_sport'] = 4321
919 mod_pkt_params['udp_dport'] = 8765
Dan Talayco4b2bee62010-07-20 14:10:05 -0700920 for keyname in mod_field_vals.keys():
921 mod_pkt_params[keyname] = mod_field_vals[keyname]
922
923 # Check for test param modifications
924 strip = False
925 if check_test_params:
Rich Lane2014f9b2012-10-05 15:29:40 -0700926 add_vlan = test_param_get('add_vlan')
927 strip_vlan = test_param_get('strip_vlan')
928 vid = test_param_get('vid')
Dan Talayco4b2bee62010-07-20 14:10:05 -0700929
930 if add_vlan and strip_vlan:
931 parent.assertTrue(0, "Add and strip VLAN both specified")
932
933 if vid:
934 base_pkt_params['dl_vlan_enable'] = True
Rich Laned0478ff2013-03-11 12:46:58 -0700935 base_pkt_params['vlan_vid'] = vid
936 if 'vlan_vid' in mod_fields:
937 mod_pkt_params['vlan_vid'] = vid + 1
Dan Talayco4b2bee62010-07-20 14:10:05 -0700938
939 if add_vlan:
940 base_pkt_params['dl_vlan_enable'] = False
941 mod_pkt_params['dl_vlan_enable'] = True
942 mod_pkt_params['pktlen'] = base_pkt_params['pktlen'] + 4
943 mod_fields.append('pktlen')
944 mod_fields.append('dl_vlan_enable')
Rich Laned0478ff2013-03-11 12:46:58 -0700945 if 'vlan_vid' not in mod_fields:
946 mod_fields.append('vlan_vid')
Dan Talayco4b2bee62010-07-20 14:10:05 -0700947 elif strip_vlan:
948 base_pkt_params['dl_vlan_enable'] = True
949 mod_pkt_params['dl_vlan_enable'] = False
950 mod_pkt_params['pktlen'] = base_pkt_params['pktlen'] - 4
951 mod_fields.append('dl_vlan_enable')
952 mod_fields.append('pktlen')
953
Rich Lane110e0e32012-10-26 16:21:46 -0700954 if tp == "tcp":
955 packet_builder = simple_tcp_packet
956 elif tp == "udp":
957 packet_builder = simple_udp_packet
958 else:
959 raise NotImplementedError("unknown transport protocol %s" % tp)
960
Dan Talayco4b2bee62010-07-20 14:10:05 -0700961 # Build the ingress packet
Rich Lane110e0e32012-10-26 16:21:46 -0700962 ingress_pkt = packet_builder(**base_pkt_params)
Dan Talayco4b2bee62010-07-20 14:10:05 -0700963
964 # Build the expected packet, modifying the indicated fields
965 for item in mod_fields:
966 base_pkt_params[item] = mod_pkt_params[item]
967 act = action_generate(parent, item, mod_pkt_params)
968 if act:
969 new_actions.append(act)
970
Rich Lane110e0e32012-10-26 16:21:46 -0700971 expected_pkt = packet_builder(**base_pkt_params)
Dan Talayco4b2bee62010-07-20 14:10:05 -0700972
973 return (ingress_pkt, expected_pkt, new_actions)
Dan Talayco677c0b72011-08-23 22:53:38 -0700974
975# Generate a simple "drop" flow mod
976# If in_band is true, then only drop from first test port
977def flow_mod_gen(port_map, in_band):
Rich Lanee717c6e2013-03-12 10:25:50 -0700978 request = ofp.message.flow_add()
979 request.match.wildcards = ofp.OFPFW_ALL
Dan Talayco677c0b72011-08-23 22:53:38 -0700980 if in_band:
Rich Lanee717c6e2013-03-12 10:25:50 -0700981 request.match.wildcards = ofp.OFPFW_ALL - ofp.OFPFW_IN_PORT
Dan Talayco677c0b72011-08-23 22:53:38 -0700982 for of_port, ifname in port_map.items(): # Grab first port
983 break
984 request.match.in_port = of_port
985 request.buffer_id = 0xffffffff
986 return request
Dan Talaycoba3745c2010-07-21 21:51:08 -0700987
988def skip_message_emit(parent, s):
989 """
990 Print out a 'skipped' message to stderr
991
992 @param s The string to print out to the log file
Dan Talaycoba3745c2010-07-21 21:51:08 -0700993 """
994 global skipped_test_count
995
996 skipped_test_count += 1
Rich Lane9a003812012-10-04 17:17:59 -0700997 logging.info("Skipping: " + s)
Dan Talayco2940fdd2013-02-06 15:01:35 -0800998 if oftest.config["debug"] < logging.WARNING:
Dan Talaycoba3745c2010-07-21 21:51:08 -0700999 sys.stderr.write("(skipped) ")
1000 else:
1001 sys.stderr.write("(S)")
Dan Talayco677c0b72011-08-23 22:53:38 -07001002
Dan Talayco8a64e332012-03-28 14:53:20 -07001003
1004def all_stats_get(parent):
1005 """
1006 Get the aggregate stats for all flows in the table
1007 @param parent Test instance with controller connection and assert
1008 @returns dict with keys flows, packets, bytes, active (flows),
1009 lookups, matched
1010 """
Rich Lanee717c6e2013-03-12 10:25:50 -07001011 stat_req = ofp.message.aggregate_stats_request()
1012 stat_req.match = ofp.match()
1013 stat_req.match.wildcards = ofp.OFPFW_ALL
Dan Talayco8a64e332012-03-28 14:53:20 -07001014 stat_req.table_id = 0xff
Rich Lanee717c6e2013-03-12 10:25:50 -07001015 stat_req.out_port = ofp.OFPP_NONE
Dan Talayco8a64e332012-03-28 14:53:20 -07001016
1017 rv = {}
1018
Rich Lanec8aaa3e2012-07-26 19:28:02 -07001019 (reply, pkt) = parent.controller.transact(stat_req)
Rich Lane5fd6faf2013-03-11 13:30:20 -07001020 parent.assertTrue(len(reply.entries) == 1, "Did not receive flow stats reply")
Dan Talayco8a64e332012-03-28 14:53:20 -07001021
Rich Lane5fd6faf2013-03-11 13:30:20 -07001022 for obj in reply.entries:
Dan Talayco8a64e332012-03-28 14:53:20 -07001023 (rv["flows"], rv["packets"], rv["bytes"]) = (obj.flow_count,
1024 obj.packet_count, obj.byte_count)
1025 break
1026
Rich Lanee717c6e2013-03-12 10:25:50 -07001027 request = ofp.message.table_stats_request()
Rich Lanec8aaa3e2012-07-26 19:28:02 -07001028 (reply , pkt) = parent.controller.transact(request)
Dan Talayco8a64e332012-03-28 14:53:20 -07001029
1030
1031 (rv["active"], rv["lookups"], rv["matched"]) = (0,0,0)
Rich Lane5fd6faf2013-03-11 13:30:20 -07001032 for obj in reply.entries:
Dan Talayco8a64e332012-03-28 14:53:20 -07001033 rv["active"] += obj.active_count
1034 rv["lookups"] += obj.lookup_count
1035 rv["matched"] += obj.matched_count
1036
1037 return rv
Dan Talayco2baf8b52012-03-30 09:55:42 -07001038
Rich Lane7744e112013-01-11 17:23:57 -08001039_import_blacklist.add('FILTER')
Dan Talayco2baf8b52012-03-30 09:55:42 -07001040FILTER=''.join([(len(repr(chr(x)))==3) and chr(x) or '.'
1041 for x in range(256)])
1042
1043def hex_dump_buffer(src, length=16):
1044 """
1045 Convert src to a hex dump string and return the string
1046 @param src The source buffer
1047 @param length The number of bytes shown in each line
1048 @returns A string showing the hex dump
1049 """
Dan Talaycoc516fa02012-04-12 22:28:43 -07001050 result = ["\n"]
Dan Talayco2baf8b52012-03-30 09:55:42 -07001051 for i in xrange(0, len(src), length):
1052 chars = src[i:i+length]
1053 hex = ' '.join(["%02x" % ord(x) for x in chars])
1054 printable = ''.join(["%s" % ((ord(x) <= 127 and
1055 FILTER[ord(x)]) or '.') for x in chars])
1056 result.append("%04x %-*s %s\n" % (i, length*3, hex, printable))
1057 return ''.join(result)
1058
1059def format_packet(pkt):
1060 return "Packet length %d \n%s" % (len(str(pkt)),
1061 hex_dump_buffer(str(pkt)))
Rich Lane5d7e89a2012-10-26 16:43:13 -07001062
1063def inspect_packet(pkt):
1064 """
1065 Wrapper around scapy's show() method.
1066 @returns A string showing the dissected packet.
1067 """
1068 from cStringIO import StringIO
1069 out = None
1070 backup = sys.stdout
1071 try:
1072 sys.stdout = StringIO()
1073 pkt.show2()
1074 out = sys.stdout.getvalue()
1075 sys.stdout.close()
1076 finally:
1077 sys.stdout = backup
1078 return out
Rich Lane0a4f6372013-01-02 14:40:22 -08001079
1080def nonstandard(cls):
1081 """
Rich Lanecc45b8e2013-01-02 15:55:02 -08001082 Testcase decorator that marks the test as being non-standard.
1083 These tests are not automatically added to the "standard" group.
Rich Lane0a4f6372013-01-02 14:40:22 -08001084 """
Rich Lanecc45b8e2013-01-02 15:55:02 -08001085 cls._nonstandard = True
Rich Lane0a4f6372013-01-02 14:40:22 -08001086 return cls
1087
1088def disabled(cls):
1089 """
Rich Lanecc45b8e2013-01-02 15:55:02 -08001090 Testcase decorator that marks the test as being disabled.
1091 These tests are not automatically added to the "standard" group or
1092 their module's group.
Rich Lane0a4f6372013-01-02 14:40:22 -08001093 """
Rich Lanecc45b8e2013-01-02 15:55:02 -08001094 cls._disabled = True
Rich Lane0a4f6372013-01-02 14:40:22 -08001095 return cls
Rich Lane97e99652013-01-02 17:23:20 -08001096
1097def group(name):
1098 """
1099 Testcase decorator that adds the test to a group.
1100 """
1101 def fn(cls):
1102 if not hasattr(cls, "_groups"):
1103 cls._groups = []
1104 cls._groups.append(name)
1105 return cls
1106 return fn
Rich Lane5a9a1922013-01-11 14:29:30 -08001107
1108def version(ver):
1109 """
1110 Testcase decorator that specifies which versions of OpenFlow the test
1111 supports. The default is 1.0+. This decorator may only be used once.
1112
1113 Supported syntax:
1114 1.0 -> 1.0
1115 1.0,1.2,1.3 -> 1.0, 1.2, 1.3
1116 1.0+ -> 1.0, 1.1, 1.2, 1.3
1117 """
1118 versions = parse_version(ver)
1119 def fn(cls):
1120 cls._versions = versions
1121 return cls
1122 return fn
1123
1124def parse_version(ver):
1125 allowed_versions = ["1.0", "1.1", "1.2", "1.3"]
1126 if re.match("^1\.\d+$", ver):
1127 versions = set([ver])
1128 elif re.match("^(1\.\d+)\+$", ver):
1129 if not ver[:-1] in allowed_versions:
1130 raise ValueError("invalid OpenFlow version %s" % ver[:-1])
1131 versions = set()
1132 if ver != "1.1+": versions.add("1.0")
1133 if ver != "1.2+": versions.add("1.1")
1134 if ver != "1.3+": versions.add("1.2")
1135 versions.add("1.3")
1136 else:
1137 versions = set(ver.split(','))
1138
1139 for version in versions:
1140 if not version in allowed_versions:
1141 raise ValueError("invalid OpenFlow version %s" % version)
1142
1143 return versions
1144
1145assert(parse_version("1.0") == set(["1.0"]))
1146assert(parse_version("1.0,1.2,1.3") == set(["1.0", "1.2", "1.3"]))
1147assert(parse_version("1.0+") == set(["1.0", "1.1", "1.2", "1.3"]))
Rich Lane7744e112013-01-11 17:23:57 -08001148
Rich Laneae3428c2013-03-07 14:37:42 -08001149def get_stats(test, req):
1150 """
1151 Retrieve a list of stats entries. Handles OFPSF_REPLY_MORE.
1152 """
1153 stats = []
1154 reply, _ = test.controller.transact(req)
1155 test.assertTrue(reply is not None, "No response to stats request")
Rich Lane5fd6faf2013-03-11 13:30:20 -07001156 stats.extend(reply.entries)
Rich Lanee717c6e2013-03-12 10:25:50 -07001157 while reply.flags & ofp.OFPSF_REPLY_MORE != 0:
1158 reply, pkt = self.controller.poll(exp_msg=ofp.OFPT_STATS_REPLY)
Rich Laneae3428c2013-03-07 14:37:42 -08001159 test.assertTrue(reply is not None, "No response to stats request")
Rich Lane5fd6faf2013-03-11 13:30:20 -07001160 stats.extend(reply.entries)
Rich Laneae3428c2013-03-07 14:37:42 -08001161 return stats
1162
Rich Lanef3bc48c2013-05-03 17:39:35 -07001163def get_flow_stats(test, match, table_id=0xff, out_port=None):
Rich Laneae3428c2013-03-07 14:37:42 -08001164 """
1165 Retrieve a list of flow stats entries.
1166 """
Rich Lanef3bc48c2013-05-03 17:39:35 -07001167 if out_port == None:
1168 out_port = ofp.OFPP_NONE
Rich Lanee717c6e2013-03-12 10:25:50 -07001169 req = ofp.message.flow_stats_request(match=match,
Rich Laneae3428c2013-03-07 14:37:42 -08001170 table_id=table_id,
1171 out_port=out_port)
1172 return get_stats(test, req)
1173
Rich Lane968b6192013-03-07 15:34:43 -08001174def get_port_stats(test, port_no):
1175 """
1176 Retrieve a list of port stats entries.
1177 """
Rich Lanee717c6e2013-03-12 10:25:50 -07001178 req = ofp.message.port_stats_request(port_no=port_no)
Rich Lane968b6192013-03-07 15:34:43 -08001179 return get_stats(test, req)
1180
Rich Lane6a334922013-03-07 16:14:52 -08001181def get_queue_stats(test, port_no, queue_id):
1182 """
1183 Retrieve a list of queue stats entries.
1184 """
Rich Lanee717c6e2013-03-12 10:25:50 -07001185 req = ofp.message.queue_stats_request(port_no=port_no, queue_id=queue_id)
Rich Lane6a334922013-03-07 16:14:52 -08001186 return get_stats(test, req)
1187
Rich Laneae3428c2013-03-07 14:37:42 -08001188def verify_flow_stats(test, match, table_id=0xff,
Rich Lanef3bc48c2013-05-03 17:39:35 -07001189 out_port=None,
Rich Laneae3428c2013-03-07 14:37:42 -08001190 initial=[],
1191 pkts=None, bytes=None):
1192 """
1193 Verify that flow stats changed as expected.
1194
1195 Optionally takes an 'initial' list of stats entries, as returned by
1196 get_flow_stats(). If 'initial' is not given the counters are assumed to
1197 begin at 0.
1198 """
Rich Lanef3bc48c2013-05-03 17:39:35 -07001199 if out_port == None:
1200 out_port = ofp.OFPP_NONE
1201
Rich Laneae3428c2013-03-07 14:37:42 -08001202 def accumulate(stats):
1203 pkts_acc = bytes_acc = 0
1204 for stat in stats:
1205 pkts_acc += stat.packet_count
1206 bytes_acc += stat.byte_count
1207 return (pkts_acc, bytes_acc)
1208
1209 pkts_before, bytes_before = accumulate(initial)
1210
1211 # Wait 10s for counters to update
1212 pkt_diff = byte_diff = None
1213 for i in range(0, 100):
1214 stats = get_flow_stats(test, match, table_id=table_id, out_port=out_port)
1215 pkts_after, bytes_after = accumulate(stats)
1216 pkt_diff = pkts_after - pkts_before
1217 byte_diff = bytes_after - bytes_before
1218 if (pkts == None or pkt_diff >= pkts) and \
1219 (bytes == None or byte_diff >= bytes):
1220 break
Dan Talayco53724732013-03-08 23:54:02 -08001221 time.sleep(0.1)
Rich Laneae3428c2013-03-07 14:37:42 -08001222
1223 if pkts != None:
1224 test.assertEquals(pkt_diff, pkts, "Flow packet counter not updated properly (expected increase of %d, got increase of %d)" % (pkts, pkt_diff))
1225
1226 if bytes != None:
Rich Lane53b96812013-03-07 16:54:50 -08001227 test.assertTrue(byte_diff >= bytes and byte_diff <= bytes*1.1,
1228 "Flow byte counter not updated properly (expected increase of %d, got increase of %d)" % (bytes, byte_diff))
Rich Laneae3428c2013-03-07 14:37:42 -08001229
Rich Lane968b6192013-03-07 15:34:43 -08001230def verify_port_stats(test, port,
1231 initial=[],
1232 tx_pkts=None, rx_pkts=None,
1233 tx_bytes=None, rx_bytes=None):
1234 """
1235 Verify that port stats changed as expected.
1236
1237 Optionally takes an 'initial' list of stats entries, as returned by
1238 get_port_stats(). If 'initial' is not given the counters are assumed to
1239 begin at 0.
1240 """
1241 def accumulate(stats):
1242 tx_pkts_acc = rx_pkts_acc = tx_bytes_acc = rx_bytes_acc = 0
1243 for stat in stats:
1244 tx_pkts_acc += stat.tx_packets
1245 rx_pkts_acc += stat.rx_packets
1246 tx_bytes_acc += stat.tx_bytes
1247 rx_bytes_acc += stat.rx_bytes
1248 return (tx_pkts_acc, rx_pkts_acc, tx_bytes_acc, rx_bytes_acc)
1249
1250 tx_pkts_before, rx_pkts_before, \
1251 tx_bytes_before, rx_bytes_before = accumulate(initial)
1252
1253 # Wait 10s for counters to update
1254 for i in range(0, 100):
1255 stats = get_port_stats(test, port)
1256 tx_pkts_after, rx_pkts_after, \
1257 tx_bytes_after, rx_bytes_after = accumulate(stats)
1258 tx_pkts_diff = tx_pkts_after - tx_pkts_before
1259 rx_pkts_diff = rx_pkts_after - rx_pkts_before
1260 tx_bytes_diff = tx_bytes_after - tx_bytes_before
1261 rx_bytes_diff = rx_bytes_after - rx_bytes_before
1262 if (tx_pkts == None or tx_pkts == tx_pkts_diff) and \
1263 (rx_pkts == None or rx_pkts == rx_pkts_diff) and \
Rich Lane53b96812013-03-07 16:54:50 -08001264 (tx_bytes == None or tx_bytes <= tx_bytes_diff) and \
1265 (rx_bytes == None or rx_bytes <= rx_bytes_diff):
Rich Lane968b6192013-03-07 15:34:43 -08001266 break
1267 time.sleep(0.1)
1268
1269 if (tx_pkts != None):
1270 test.assertEqual(tx_pkts,tx_pkts_diff,"Port TX packet counter is not updated correctly (expected increase of %d, got increase of %d)" % (tx_pkts, tx_pkts_diff))
1271 if (rx_pkts != None):
1272 test.assertEqual(rx_pkts,rx_pkts_diff,"Port RX packet counter is not updated correctly (expected increase of %d, got increase of %d)" % (rx_pkts, rx_pkts_diff))
1273 if (tx_bytes != None):
Rich Lane53b96812013-03-07 16:54:50 -08001274 test.assertTrue(tx_bytes_diff >= tx_bytes and tx_bytes_diff <= tx_bytes*1.1,
1275 "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 -08001276 if (rx_bytes != None):
Rich Lane53b96812013-03-07 16:54:50 -08001277 test.assertTrue(rx_bytes_diff >= rx_bytes and rx_bytes_diff <= rx_bytes*1.1,
1278 "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 -08001279
Rich Lane6a334922013-03-07 16:14:52 -08001280def verify_queue_stats(test, port_no, queue_id,
1281 initial=[],
1282 pkts=None, bytes=None):
1283 """
1284 Verify that queue stats changed as expected.
1285
1286 Optionally takes an 'initial' list of stats entries, as returned by
1287 get_queue_stats(). If 'initial' is not given the counters are assumed to
1288 begin at 0.
1289 """
1290 def accumulate(stats):
1291 pkts_acc = bytes_acc = 0
1292 for stat in stats:
1293 pkts_acc += stat.tx_packets
1294 bytes_acc += stat.tx_bytes
1295 return (pkts_acc, bytes_acc)
1296
1297 pkts_before, bytes_before = accumulate(initial)
1298
1299 # Wait 10s for counters to update
1300 pkt_diff = byte_diff = None
1301 for i in range(0, 100):
1302 stats = get_queue_stats(test, port_no, queue_id)
1303 pkts_after, bytes_after = accumulate(stats)
1304 pkt_diff = pkts_after - pkts_before
1305 byte_diff = bytes_after - bytes_before
1306 if (pkts == None or pkt_diff >= pkts) and \
1307 (bytes == None or byte_diff >= bytes):
1308 break
Dan Talayco53724732013-03-08 23:54:02 -08001309 time.sleep(0.1)
Rich Lane6a334922013-03-07 16:14:52 -08001310
1311 if pkts != None:
1312 test.assertEquals(pkt_diff, pkts, "Queue packet counter not updated properly (expected increase of %d, got increase of %d)" % (pkts, pkt_diff))
1313
1314 if bytes != None:
Rich Lane53b96812013-03-07 16:54:50 -08001315 test.assertTrue(byte_diff >= bytes and byte_diff <= bytes*1.1,
1316 "Queue byte counter not updated properly (expected increase of %d, got increase of %d)" % (bytes, byte_diff))
Rich Laneae3428c2013-03-07 14:37:42 -08001317
Rich Lane4c504f32013-06-07 17:24:14 -07001318def packet_in_match(msg, data, in_port=None, reason=None):
1319 """
1320 Check whether the packet_in message 'msg' has fields matching 'data',
1321 'in_port', and 'reason'.
1322
1323 This function handles truncated packet_in data. The 'in_port' and 'reason'
1324 parameters are optional.
1325
1326 @param msg packet_in message
1327 @param data Expected packet_in data
1328 @param in_port Expected packet_in in_port, or None
1329 @param reason Expected packet_in reason, or None
1330 """
1331
1332 if in_port and in_port != msg.in_port:
1333 logging.debug("Incorrect packet_in in_port (expected %d, received %d)", in_port, msg.in_port)
1334 return False
1335
1336 if reason and reason != msg.reason:
1337 logging.debug("Incorrect packet_in reason (expected %d, received %d)", reason, msg.reason)
1338 return False
1339
1340 # Check that one of the packets is a prefix of the other.
1341 # The received packet may be either truncated or padded, but not both.
1342 # (Some of the padding may be truncated but that's irrelevant). We
1343 # need to check that the smaller packet is a prefix of the larger one.
1344 # Note that this check succeeds if the switch sends a zero-length
1345 # packet-in.
1346 compare_len = min(len(msg.data), len(data))
1347 if data[:compare_len] != msg.data[:compare_len]:
1348 logging.debug("Incorrect packet_in data")
1349 logging.debug("Expected %s" % format_packet(data[:compare_len]))
1350 logging.debug("Received %s" % format_packet(msg.data[:compare_len]))
1351 return False
1352
1353 return True
1354
1355def verify_packet_in(test, data, in_port, reason, controller=None):
1356 """
1357 Assert that the controller receives a packet_in message matching data 'data'
1358 from port 'in_port' with reason 'reason'. Does not trigger the packet_in
1359 itself, that's up to the test case.
1360
1361 @param test Instance of base_tests.SimpleProtocol
1362 @param pkt String to expect as the packet_in data
1363 @param in_port OpenFlow port number to expect as the packet_in in_port
1364 @param reason One of OFPR_* to expect as the packet_in reason
1365 @param controller Controller instance, defaults to test.controller
1366 @returns The received packet-in message
1367 """
1368
1369 if controller == None:
1370 controller = test.controller
1371
1372 end_time = time.time() + oftest.ofutils.default_timeout
1373
1374 while True:
1375 msg, _ = controller.poll(ofp.OFPT_PACKET_IN, end_time - time.time())
1376 if not msg:
1377 # Timeout
1378 break
1379 elif packet_in_match(msg, data, in_port, reason):
1380 # Found a matching message
1381 break
1382
1383 test.assertTrue(msg is not None, 'Packet in message not received on port %d' % in_port)
1384 return msg
1385
1386def verify_no_packet_in(test, data, in_port, controller=None):
1387 """
1388 Assert that the controller does not receive a packet_in message matching
1389 data 'data' from port 'in_port'.
1390
1391 @param test Instance of base_tests.SimpleProtocol
1392 @param pkt String to expect as the packet_in data
1393 @param in_port OpenFlow port number to expect as the packet_in in_port
1394 @param controller Controller instance, defaults to test.controller
1395 """
1396
1397 if controller == None:
1398 controller = test.controller
1399
1400 # Negative test, need to wait a short amount of time before checking we
1401 # didn't receive the message.
1402 time.sleep(0.5)
1403
1404 # Check every packet_in queued in the controller
1405 while True:
1406 msg, _ = controller.poll(ofp.OFPT_PACKET_IN, timeout=0)
1407 if msg == None:
1408 # No more queued packet_in messages
1409 break
1410 elif packet_in_match(msg, data, in_port, None):
1411 # Found a matching message
1412 break
1413
1414 test.assertTrue(msg == None, "Did not expect a packet-in message on port %d" % in_port)
1415
Rich Lane7744e112013-01-11 17:23:57 -08001416__all__ = list(set(locals()) - _import_blacklist)