blob: 58672743db4c403c7aa850546248cce24bdc1b16 [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)
Rich Laneab7476f2013-06-13 15:53:52 -0700554 if ofp.OFP_VERSION in [1, 2]:
555 match.wildcards |= required_wildcards(parent)
556 else:
557 # TODO remove incompatible OXM entries
558 pass
Ed Swierk99a74de2012-08-22 06:40:54 -0700559 return match
560
561def flow_msg_create(parent, pkt, ing_port=None, action_list=None, wildcards=None,
Dan Talaycof6e76c02012-03-23 10:56:12 -0700562 egr_ports=None, egr_queue=None, check_expire=False, in_band=False):
Dan Talayco551befa2010-07-15 17:05:32 -0700563 """
564 Create a flow message
565
566 Match on packet with given wildcards.
567 See flow_match_test for other parameter descriptoins
568 @param egr_queue if not None, make the output an enqueue action
Dan Talayco677c0b72011-08-23 22:53:38 -0700569 @param in_band if True, do not wildcard ingress port
Dan Talaycof6e76c02012-03-23 10:56:12 -0700570 @param egr_ports None (drop), single port or list of ports
Dan Talayco551befa2010-07-15 17:05:32 -0700571 """
Rich Lanef6883512013-03-11 17:00:09 -0700572 match = oftest.parse.packet_to_flow_match(pkt)
Dan Talayco551befa2010-07-15 17:05:32 -0700573 parent.assertTrue(match is not None, "Flow match from pkt failed")
Ed Swierk99a74de2012-08-22 06:40:54 -0700574 if wildcards is None:
575 wildcards = required_wildcards(parent)
Dan Talayco677c0b72011-08-23 22:53:38 -0700576 if in_band:
Rich Lanee717c6e2013-03-12 10:25:50 -0700577 wildcards &= ~ofp.OFPFW_IN_PORT
Dan Talayco551befa2010-07-15 17:05:32 -0700578 match.wildcards = wildcards
579 match.in_port = ing_port
580
Dan Talaycof6e76c02012-03-23 10:56:12 -0700581 if type(egr_ports) == type([]):
582 egr_port_list = egr_ports
583 else:
584 egr_port_list = [egr_ports]
585
Rich Lanee717c6e2013-03-12 10:25:50 -0700586 request = ofp.message.flow_add()
Dan Talayco551befa2010-07-15 17:05:32 -0700587 request.match = match
588 request.buffer_id = 0xffffffff
589 if check_expire:
Rich Lanee717c6e2013-03-12 10:25:50 -0700590 request.flags |= ofp.OFPFF_SEND_FLOW_REM
Dan Talayco551befa2010-07-15 17:05:32 -0700591 request.hard_timeout = 1
592
593 if action_list is not None:
594 for act in action_list:
Rich Lane9a003812012-10-04 17:17:59 -0700595 logging.debug("Adding action " + act.show())
Rich Lanec495d9e2013-03-08 17:43:36 -0800596 request.actions.append(act)
Dan Talayco551befa2010-07-15 17:05:32 -0700597
598 # Set up output/enqueue action if directed
599 if egr_queue is not None:
Dan Talaycof6e76c02012-03-23 10:56:12 -0700600 parent.assertTrue(egr_ports is not None, "Egress port not set")
Rich Lanee717c6e2013-03-12 10:25:50 -0700601 act = ofp.action.enqueue()
Dan Talaycof6e76c02012-03-23 10:56:12 -0700602 for egr_port in egr_port_list:
603 act.port = egr_port
604 act.queue_id = egr_queue
Rich Lanec495d9e2013-03-08 17:43:36 -0800605 request.actions.append(act)
Dan Talaycof6e76c02012-03-23 10:56:12 -0700606 elif egr_ports is not None:
607 for egr_port in egr_port_list:
Rich Lanee717c6e2013-03-12 10:25:50 -0700608 act = ofp.action.output()
Dan Talaycof6e76c02012-03-23 10:56:12 -0700609 act.port = egr_port
Rich Lanec495d9e2013-03-08 17:43:36 -0800610 request.actions.append(act)
Dan Talayco551befa2010-07-15 17:05:32 -0700611
Rich Lane9a003812012-10-04 17:17:59 -0700612 logging.debug(request.show())
Dan Talayco551befa2010-07-15 17:05:32 -0700613
614 return request
615
Jeffrey Townsendf3eae9c2012-03-28 18:23:21 -0700616def flow_msg_install(parent, request, clear_table_override=None):
Dan Talayco551befa2010-07-15 17:05:32 -0700617 """
618 Install a flow mod message in the switch
619
620 @param parent Must implement controller, assertEqual, assertTrue
621 @param request The request, all set to go
622 @param clear_table If true, clear the flow table before installing
623 """
Dan Talayco8a64e332012-03-28 14:53:20 -0700624
Rich Lane2014f9b2012-10-05 15:29:40 -0700625 clear_table = test_param_get('clear_table', default=True)
Jeffrey Townsendf3eae9c2012-03-28 18:23:21 -0700626 if(clear_table_override != None):
627 clear_table = clear_table_override
628
629 if clear_table:
Rich Lane9a003812012-10-04 17:17:59 -0700630 logging.debug("Clear flow table")
Rich Lane32bf9482013-01-03 17:26:30 -0800631 delete_all_flows(parent.controller)
Dan Talayco551befa2010-07-15 17:05:32 -0700632
Rich Lane9a003812012-10-04 17:17:59 -0700633 logging.debug("Insert flow")
Rich Lane5c3151c2013-01-03 17:15:41 -0800634 parent.controller.message_send(request)
Rich Lanee912d032012-12-22 14:28:33 -0800635
Rich Lane3a261d52013-01-03 17:45:08 -0800636 do_barrier(parent.controller)
Dan Talayco551befa2010-07-15 17:05:32 -0700637
Ed Swierk99a74de2012-08-22 06:40:54 -0700638def flow_match_test_port_pair(parent, ing_port, egr_ports, wildcards=None,
Rich Laned0478ff2013-03-11 12:46:58 -0700639 vlan_vid=-1, pkt=None, exp_pkt=None,
Rich Lanee5779d32012-10-05 17:56:04 -0700640 action_list=None):
Dan Talayco551befa2010-07-15 17:05:32 -0700641 """
642 Flow match test on single TCP packet
Dan Talaycof6e76c02012-03-23 10:56:12 -0700643 @param egr_ports A single port or list of ports
Dan Talayco551befa2010-07-15 17:05:32 -0700644
645 Run test with packet through switch from ing_port to egr_port
646 See flow_match_test for parameter descriptions
647 """
648
Ed Swierk99a74de2012-08-22 06:40:54 -0700649 if wildcards is None:
650 wildcards = required_wildcards(parent)
Rich Lane9a003812012-10-04 17:17:59 -0700651 logging.info("Pkt match test: " + str(ing_port) + " to " +
Dan Talaycof6e76c02012-03-23 10:56:12 -0700652 str(egr_ports))
Rich Laned0478ff2013-03-11 12:46:58 -0700653 logging.debug(" WC: " + hex(wildcards) + " vlan: " + str(vlan_vid))
Dan Talayco551befa2010-07-15 17:05:32 -0700654 if pkt is None:
Rich Laned0478ff2013-03-11 12:46:58 -0700655 pkt = simple_tcp_packet(dl_vlan_enable=(vlan_vid >= 0), vlan_vid=vlan_vid)
Dan Talayco551befa2010-07-15 17:05:32 -0700656
657 request = flow_msg_create(parent, pkt, ing_port=ing_port,
Dan Talaycof6e76c02012-03-23 10:56:12 -0700658 wildcards=wildcards, egr_ports=egr_ports,
Dan Talayco551befa2010-07-15 17:05:32 -0700659 action_list=action_list)
660
661 flow_msg_install(parent, request)
662
Rich Lane9a003812012-10-04 17:17:59 -0700663 logging.debug("Send packet: " + str(ing_port) + " to " +
Dan Talaycof6e76c02012-03-23 10:56:12 -0700664 str(egr_ports))
Dan Talayco551befa2010-07-15 17:05:32 -0700665 parent.dataplane.send(ing_port, str(pkt))
666
667 if exp_pkt is None:
668 exp_pkt = pkt
Dan Talaycoc948d0b2012-03-23 12:17:54 -0700669 receive_pkt_verify(parent, egr_ports, exp_pkt, ing_port)
Dan Talayco551befa2010-07-15 17:05:32 -0700670
Rich Lane89725bb2012-12-03 16:23:27 -0800671def flow_match_test_pktout(parent, ing_port, egr_ports,
Rich Laned0478ff2013-03-11 12:46:58 -0700672 vlan_vid=-1, pkt=None, exp_pkt=None,
Rich Lane89725bb2012-12-03 16:23:27 -0800673 action_list=None):
674 """
675 Packet-out test on single TCP packet
676 @param egr_ports A single port or list of ports
677
678 Run test sending packet-out to egr_ports. The goal is to test the actions
679 taken on the packet, not the matching which is of course irrelevant.
680 See flow_match_test for parameter descriptions
681 """
682
683 if pkt is None:
Rich Laned0478ff2013-03-11 12:46:58 -0700684 pkt = simple_tcp_packet(dl_vlan_enable=(vlan_vid >= 0), vlan_vid=vlan_vid)
Rich Lane89725bb2012-12-03 16:23:27 -0800685
Rich Lanee717c6e2013-03-12 10:25:50 -0700686 msg = ofp.message.packet_out()
Rich Lane89725bb2012-12-03 16:23:27 -0800687 msg.in_port = ing_port
Rich Laneea8c4722013-04-04 15:30:20 -0700688 msg.buffer_id = 0xffffffff
Rich Lane89725bb2012-12-03 16:23:27 -0800689 msg.data = str(pkt)
690 if action_list is not None:
691 for act in action_list:
Rich Lanec495d9e2013-03-08 17:43:36 -0800692 msg.actions.append(act)
Rich Lane89725bb2012-12-03 16:23:27 -0800693
694 # Set up output action
695 if egr_ports is not None:
696 for egr_port in egr_ports:
Rich Lanee717c6e2013-03-12 10:25:50 -0700697 act = ofp.action.output()
Rich Lane89725bb2012-12-03 16:23:27 -0800698 act.port = egr_port
Rich Lanec495d9e2013-03-08 17:43:36 -0800699 msg.actions.append(act)
Rich Lane89725bb2012-12-03 16:23:27 -0800700
701 logging.debug(msg.show())
Rich Lane5c3151c2013-01-03 17:15:41 -0800702 parent.controller.message_send(msg)
Rich Lane89725bb2012-12-03 16:23:27 -0800703
704 if exp_pkt is None:
705 exp_pkt = pkt
706 receive_pkt_verify(parent, egr_ports, exp_pkt, ing_port)
707
Dan Talaycof6e76c02012-03-23 10:56:12 -0700708def get_egr_list(parent, of_ports, how_many, exclude_list=[]):
709 """
710 Generate a list of ports avoiding those in the exclude list
Rich Lane9a003812012-10-04 17:17:59 -0700711 @param parent Supplies logging
Dan Talaycof6e76c02012-03-23 10:56:12 -0700712 @param of_ports List of OF port numbers
713 @param how_many Number of ports to be added to the list
714 @param exclude_list List of ports not to be used
715 @returns An empty list if unable to find enough ports
716 """
717
Dan Talaycoc948d0b2012-03-23 12:17:54 -0700718 if how_many == 0:
719 return []
720
Dan Talaycof6e76c02012-03-23 10:56:12 -0700721 count = 0
722 egr_ports = []
723 for egr_idx in range(len(of_ports)):
724 if of_ports[egr_idx] not in exclude_list:
725 egr_ports.append(of_ports[egr_idx])
726 count += 1
727 if count >= how_many:
728 return egr_ports
Rich Lane9a003812012-10-04 17:17:59 -0700729 logging.debug("Could not generate enough egress ports for test")
Dan Talaycof6e76c02012-03-23 10:56:12 -0700730 return []
731
Rich Laned0478ff2013-03-11 12:46:58 -0700732def flow_match_test(parent, port_map, wildcards=None, vlan_vid=-1, pkt=None,
Rich Lanee5779d32012-10-05 17:56:04 -0700733 exp_pkt=None, action_list=None,
Dan Talaycoc948d0b2012-03-23 12:17:54 -0700734 max_test=0, egr_count=1, ing_port=False):
Dan Talayco551befa2010-07-15 17:05:32 -0700735 """
Rich Lane89725bb2012-12-03 16:23:27 -0800736 Run flow_match_test_port_pair on all port pairs and packet-out
Dan Talayco551befa2010-07-15 17:05:32 -0700737
738 @param max_test If > 0 no more than this number of tests are executed.
739 @param parent Must implement controller, dataplane, assertTrue, assertEqual
Rich Lane9a003812012-10-04 17:17:59 -0700740 and logging
Dan Talayco551befa2010-07-15 17:05:32 -0700741 @param pkt If not None, use this packet for ingress
742 @param wildcards For flow match entry
Rich Laned0478ff2013-03-11 12:46:58 -0700743 @param vlan_vid If not -1, and pkt is None, create a pkt w/ VLAN tag
Dan Talayco551befa2010-07-15 17:05:32 -0700744 @param exp_pkt If not None, use this as the expected output pkt; els use pkt
745 @param action_list Additional actions to add to flow mod
Dan Talaycocfa172f2012-03-23 12:03:00 -0700746 @param egr_count Number of egress ports; -1 means get from config w/ dflt 2
Dan Talayco551befa2010-07-15 17:05:32 -0700747 """
Ed Swierk99a74de2012-08-22 06:40:54 -0700748 if wildcards is None:
749 wildcards = required_wildcards(parent)
Dan Talayco551befa2010-07-15 17:05:32 -0700750 of_ports = port_map.keys()
751 of_ports.sort()
752 parent.assertTrue(len(of_ports) > 1, "Not enough ports for test")
753 test_count = 0
754
Dan Talaycocfa172f2012-03-23 12:03:00 -0700755 if egr_count == -1:
Rich Lane2014f9b2012-10-05 15:29:40 -0700756 egr_count = test_param_get('egr_count', default=2)
Dan Talaycocfa172f2012-03-23 12:03:00 -0700757
Dan Talayco551befa2010-07-15 17:05:32 -0700758 for ing_idx in range(len(of_ports)):
759 ingress_port = of_ports[ing_idx]
Dan Talaycof6e76c02012-03-23 10:56:12 -0700760 egr_ports = get_egr_list(parent, of_ports, egr_count,
761 exclude_list=[ingress_port])
Dan Talaycoc948d0b2012-03-23 12:17:54 -0700762 if ing_port:
Rich Lanee717c6e2013-03-12 10:25:50 -0700763 egr_ports.append(ofp.OFPP_IN_PORT)
Dan Talaycof6e76c02012-03-23 10:56:12 -0700764 if len(egr_ports) == 0:
765 parent.assertTrue(0, "Failed to generate egress port list")
766
767 flow_match_test_port_pair(parent, ingress_port, egr_ports,
Rich Laned0478ff2013-03-11 12:46:58 -0700768 wildcards=wildcards, vlan_vid=vlan_vid,
Dan Talaycof6e76c02012-03-23 10:56:12 -0700769 pkt=pkt, exp_pkt=exp_pkt,
Rich Lanee5779d32012-10-05 17:56:04 -0700770 action_list=action_list)
Dan Talaycof6e76c02012-03-23 10:56:12 -0700771 test_count += 1
772 if (max_test > 0) and (test_count > max_test):
Rich Lane9a003812012-10-04 17:17:59 -0700773 logging.info("Ran " + str(test_count) + " tests; exiting")
Rich Lane89725bb2012-12-03 16:23:27 -0800774 break
775
Ed Swierk38eea082013-01-02 19:46:20 -0800776 if not test_param_get('pktout_actions', default=True):
777 return
Rich Lane89725bb2012-12-03 16:23:27 -0800778
779 ingress_port = of_ports[0]
780 egr_ports = get_egr_list(parent, of_ports, egr_count,
781 exclude_list=[ingress_port])
782 if ing_port:
Rich Lanee717c6e2013-03-12 10:25:50 -0700783 egr_ports.append(ofp.OFPP_IN_PORT)
Rich Lane89725bb2012-12-03 16:23:27 -0800784 flow_match_test_pktout(parent, ingress_port, egr_ports,
Rich Laned0478ff2013-03-11 12:46:58 -0700785 vlan_vid=vlan_vid,
Rich Lane89725bb2012-12-03 16:23:27 -0800786 pkt=pkt, exp_pkt=exp_pkt,
787 action_list=action_list)
Dan Talayco551befa2010-07-15 17:05:32 -0700788
Rich Lane2014f9b2012-10-05 15:29:40 -0700789def test_param_get(key, default=None):
Dan Talayco4b2bee62010-07-20 14:10:05 -0700790 """
791 Return value passed via test-params if present
792
Dan Talayco4b2bee62010-07-20 14:10:05 -0700793 @param key The lookup key
794 @param default Default value to use if not found
795
796 If the pair 'key=val' appeared in the string passed to --test-params
797 on the command line, return val (as interpreted by exec). Otherwise
798 return default value.
Dan Talaycof6e76c02012-03-23 10:56:12 -0700799
800 WARNING: TEST PARAMETERS MUST BE PYTHON IDENTIFIERS;
801 eg egr_count, not egr-count.
Dan Talayco4b2bee62010-07-20 14:10:05 -0700802 """
803 try:
Rich Lanecd97d3d2013-01-07 18:50:06 -0800804 exec oftest.config["test_params"]
Dan Talayco4b2bee62010-07-20 14:10:05 -0700805 except:
806 return default
807
808 s = "val = " + str(key)
809 try:
810 exec s
811 return val
812 except:
813 return default
814
815def action_generate(parent, field_to_mod, mod_field_vals):
816 """
817 Create an action to modify the field indicated in field_to_mod
818
819 @param parent Must implement, assertTrue
820 @param field_to_mod The field to modify as a string name
821 @param mod_field_vals Hash of values to use for modified values
822 """
823
824 act = None
825
826 if field_to_mod in ['pktlen']:
827 return None
828
Rich Laned0478ff2013-03-11 12:46:58 -0700829 if field_to_mod == 'eth_dst':
Rich Lanee717c6e2013-03-12 10:25:50 -0700830 act = ofp.action.set_dl_dst()
Rich Lanef6883512013-03-11 17:00:09 -0700831 act.dl_addr = oftest.parse.parse_mac(mod_field_vals['eth_dst'])
Rich Laned0478ff2013-03-11 12:46:58 -0700832 elif field_to_mod == 'eth_src':
Rich Lanee717c6e2013-03-12 10:25:50 -0700833 act = ofp.action.set_dl_src()
Rich Lanef6883512013-03-11 17:00:09 -0700834 act.dl_addr = oftest.parse.parse_mac(mod_field_vals['eth_src'])
Dan Talayco4b2bee62010-07-20 14:10:05 -0700835 elif field_to_mod == 'dl_vlan_enable':
836 if not mod_field_vals['dl_vlan_enable']: # Strip VLAN tag
Rich Lanee717c6e2013-03-12 10:25:50 -0700837 act = ofp.action.strip_vlan()
Rich Laned0478ff2013-03-11 12:46:58 -0700838 # Add VLAN tag is handled by vlan_vid field
Dan Talayco4b2bee62010-07-20 14:10:05 -0700839 # Will return None in this case
Rich Laned0478ff2013-03-11 12:46:58 -0700840 elif field_to_mod == 'vlan_vid':
Rich Lanee717c6e2013-03-12 10:25:50 -0700841 act = ofp.action.set_vlan_vid()
Rich Laned0478ff2013-03-11 12:46:58 -0700842 act.vlan_vid = mod_field_vals['vlan_vid']
843 elif field_to_mod == 'vlan_pcp':
Rich Lanee717c6e2013-03-12 10:25:50 -0700844 act = ofp.action.set_vlan_pcp()
Rich Laned0478ff2013-03-11 12:46:58 -0700845 act.vlan_pcp = mod_field_vals['vlan_pcp']
Dan Talayco4b2bee62010-07-20 14:10:05 -0700846 elif field_to_mod == 'ip_src':
Rich Lanee717c6e2013-03-12 10:25:50 -0700847 act = ofp.action.set_nw_src()
Rich Lanef6883512013-03-11 17:00:09 -0700848 act.nw_addr = oftest.parse.parse_ip(mod_field_vals['ip_src'])
Dan Talayco4b2bee62010-07-20 14:10:05 -0700849 elif field_to_mod == 'ip_dst':
Rich Lanee717c6e2013-03-12 10:25:50 -0700850 act = ofp.action.set_nw_dst()
Rich Lanef6883512013-03-11 17:00:09 -0700851 act.nw_addr = oftest.parse.parse_ip(mod_field_vals['ip_dst'])
Dan Talayco4b2bee62010-07-20 14:10:05 -0700852 elif field_to_mod == 'ip_tos':
Rich Lanee717c6e2013-03-12 10:25:50 -0700853 act = ofp.action.set_nw_tos()
Dan Talayco4b2bee62010-07-20 14:10:05 -0700854 act.nw_tos = mod_field_vals['ip_tos']
855 elif field_to_mod == 'tcp_sport':
Rich Lanee717c6e2013-03-12 10:25:50 -0700856 act = ofp.action.set_tp_src()
Dan Talayco4b2bee62010-07-20 14:10:05 -0700857 act.tp_port = mod_field_vals['tcp_sport']
858 elif field_to_mod == 'tcp_dport':
Rich Lanee717c6e2013-03-12 10:25:50 -0700859 act = ofp.action.set_tp_dst()
Dan Talayco4b2bee62010-07-20 14:10:05 -0700860 act.tp_port = mod_field_vals['tcp_dport']
Rich Lane110e0e32012-10-26 16:21:46 -0700861 elif field_to_mod == 'udp_sport':
Rich Lanee717c6e2013-03-12 10:25:50 -0700862 act = ofp.action.set_tp_src()
Rich Lane110e0e32012-10-26 16:21:46 -0700863 act.tp_port = mod_field_vals['udp_sport']
864 elif field_to_mod == 'udp_dport':
Rich Lanee717c6e2013-03-12 10:25:50 -0700865 act = ofp.action.set_tp_dst()
Rich Lane110e0e32012-10-26 16:21:46 -0700866 act.tp_port = mod_field_vals['udp_dport']
Dan Talayco4b2bee62010-07-20 14:10:05 -0700867 else:
868 parent.assertTrue(0, "Unknown field to modify: " + str(field_to_mod))
869
870 return act
871
872def pkt_action_setup(parent, start_field_vals={}, mod_field_vals={},
Rich Lane110e0e32012-10-26 16:21:46 -0700873 mod_fields=[], tp="tcp", check_test_params=False):
Dan Talayco4b2bee62010-07-20 14:10:05 -0700874 """
875 Set up the ingress and expected packet and action list for a test
876
Rich Lane2014f9b2012-10-05 15:29:40 -0700877 @param parent Must implement assertTrue
Dan Talayco4b2bee62010-07-20 14:10:05 -0700878 @param start_field_values Field values to use for ingress packet (optional)
879 @param mod_field_values Field values to use for modified packet (optional)
880 @param mod_fields The list of fields to be modified by the switch in the test.
881 @params check_test_params If True, will check the parameters vid, add_vlan
882 and strip_vlan from the command line.
883
884 Returns a triple: pkt-to-send, expected-pkt, action-list
885 """
886
887 new_actions = []
888
Dan Talayco4b2bee62010-07-20 14:10:05 -0700889 base_pkt_params = {}
890 base_pkt_params['pktlen'] = 100
Rich Laned0478ff2013-03-11 12:46:58 -0700891 base_pkt_params['eth_dst'] = '00:DE:F0:12:34:56'
892 base_pkt_params['eth_src'] = '00:23:45:67:89:AB'
Dan Talayco4b2bee62010-07-20 14:10:05 -0700893 base_pkt_params['dl_vlan_enable'] = False
Rich Laned0478ff2013-03-11 12:46:58 -0700894 base_pkt_params['vlan_vid'] = 2
895 base_pkt_params['vlan_pcp'] = 0
Dan Talayco4b2bee62010-07-20 14:10:05 -0700896 base_pkt_params['ip_src'] = '192.168.0.1'
897 base_pkt_params['ip_dst'] = '192.168.0.2'
898 base_pkt_params['ip_tos'] = 0
Rich Lane110e0e32012-10-26 16:21:46 -0700899 if tp == "tcp":
900 base_pkt_params['tcp_sport'] = 1234
901 base_pkt_params['tcp_dport'] = 80
902 elif tp == "udp":
903 base_pkt_params['udp_sport'] = 1234
904 base_pkt_params['udp_dport'] = 80
Dan Talayco4b2bee62010-07-20 14:10:05 -0700905 for keyname in start_field_vals.keys():
906 base_pkt_params[keyname] = start_field_vals[keyname]
907
908 mod_pkt_params = {}
909 mod_pkt_params['pktlen'] = 100
Rich Laned0478ff2013-03-11 12:46:58 -0700910 mod_pkt_params['eth_dst'] = '00:21:0F:ED:CB:A9'
911 mod_pkt_params['eth_src'] = '00:ED:CB:A9:87:65'
Dan Talayco4b2bee62010-07-20 14:10:05 -0700912 mod_pkt_params['dl_vlan_enable'] = False
Rich Laned0478ff2013-03-11 12:46:58 -0700913 mod_pkt_params['vlan_vid'] = 3
914 mod_pkt_params['vlan_pcp'] = 7
Dan Talayco4b2bee62010-07-20 14:10:05 -0700915 mod_pkt_params['ip_src'] = '10.20.30.40'
916 mod_pkt_params['ip_dst'] = '50.60.70.80'
917 mod_pkt_params['ip_tos'] = 0xf0
Rich Lane110e0e32012-10-26 16:21:46 -0700918 if tp == "tcp":
919 mod_pkt_params['tcp_sport'] = 4321
920 mod_pkt_params['tcp_dport'] = 8765
921 elif tp == "udp":
922 mod_pkt_params['udp_sport'] = 4321
923 mod_pkt_params['udp_dport'] = 8765
Dan Talayco4b2bee62010-07-20 14:10:05 -0700924 for keyname in mod_field_vals.keys():
925 mod_pkt_params[keyname] = mod_field_vals[keyname]
926
927 # Check for test param modifications
928 strip = False
929 if check_test_params:
Rich Lane2014f9b2012-10-05 15:29:40 -0700930 add_vlan = test_param_get('add_vlan')
931 strip_vlan = test_param_get('strip_vlan')
932 vid = test_param_get('vid')
Dan Talayco4b2bee62010-07-20 14:10:05 -0700933
934 if add_vlan and strip_vlan:
935 parent.assertTrue(0, "Add and strip VLAN both specified")
936
937 if vid:
938 base_pkt_params['dl_vlan_enable'] = True
Rich Laned0478ff2013-03-11 12:46:58 -0700939 base_pkt_params['vlan_vid'] = vid
940 if 'vlan_vid' in mod_fields:
941 mod_pkt_params['vlan_vid'] = vid + 1
Dan Talayco4b2bee62010-07-20 14:10:05 -0700942
943 if add_vlan:
944 base_pkt_params['dl_vlan_enable'] = False
945 mod_pkt_params['dl_vlan_enable'] = True
946 mod_pkt_params['pktlen'] = base_pkt_params['pktlen'] + 4
947 mod_fields.append('pktlen')
948 mod_fields.append('dl_vlan_enable')
Rich Laned0478ff2013-03-11 12:46:58 -0700949 if 'vlan_vid' not in mod_fields:
950 mod_fields.append('vlan_vid')
Dan Talayco4b2bee62010-07-20 14:10:05 -0700951 elif strip_vlan:
952 base_pkt_params['dl_vlan_enable'] = True
953 mod_pkt_params['dl_vlan_enable'] = False
954 mod_pkt_params['pktlen'] = base_pkt_params['pktlen'] - 4
955 mod_fields.append('dl_vlan_enable')
956 mod_fields.append('pktlen')
957
Rich Lane110e0e32012-10-26 16:21:46 -0700958 if tp == "tcp":
959 packet_builder = simple_tcp_packet
960 elif tp == "udp":
961 packet_builder = simple_udp_packet
962 else:
963 raise NotImplementedError("unknown transport protocol %s" % tp)
964
Dan Talayco4b2bee62010-07-20 14:10:05 -0700965 # Build the ingress packet
Rich Lane110e0e32012-10-26 16:21:46 -0700966 ingress_pkt = packet_builder(**base_pkt_params)
Dan Talayco4b2bee62010-07-20 14:10:05 -0700967
968 # Build the expected packet, modifying the indicated fields
969 for item in mod_fields:
970 base_pkt_params[item] = mod_pkt_params[item]
971 act = action_generate(parent, item, mod_pkt_params)
972 if act:
973 new_actions.append(act)
974
Rich Lane110e0e32012-10-26 16:21:46 -0700975 expected_pkt = packet_builder(**base_pkt_params)
Dan Talayco4b2bee62010-07-20 14:10:05 -0700976
977 return (ingress_pkt, expected_pkt, new_actions)
Dan Talayco677c0b72011-08-23 22:53:38 -0700978
979# Generate a simple "drop" flow mod
980# If in_band is true, then only drop from first test port
981def flow_mod_gen(port_map, in_band):
Rich Lanee717c6e2013-03-12 10:25:50 -0700982 request = ofp.message.flow_add()
983 request.match.wildcards = ofp.OFPFW_ALL
Dan Talayco677c0b72011-08-23 22:53:38 -0700984 if in_band:
Rich Lanee717c6e2013-03-12 10:25:50 -0700985 request.match.wildcards = ofp.OFPFW_ALL - ofp.OFPFW_IN_PORT
Dan Talayco677c0b72011-08-23 22:53:38 -0700986 for of_port, ifname in port_map.items(): # Grab first port
987 break
988 request.match.in_port = of_port
989 request.buffer_id = 0xffffffff
990 return request
Dan Talaycoba3745c2010-07-21 21:51:08 -0700991
992def skip_message_emit(parent, s):
993 """
994 Print out a 'skipped' message to stderr
995
996 @param s The string to print out to the log file
Dan Talaycoba3745c2010-07-21 21:51:08 -0700997 """
998 global skipped_test_count
999
1000 skipped_test_count += 1
Rich Lane9a003812012-10-04 17:17:59 -07001001 logging.info("Skipping: " + s)
Dan Talayco2940fdd2013-02-06 15:01:35 -08001002 if oftest.config["debug"] < logging.WARNING:
Dan Talaycoba3745c2010-07-21 21:51:08 -07001003 sys.stderr.write("(skipped) ")
1004 else:
1005 sys.stderr.write("(S)")
Dan Talayco677c0b72011-08-23 22:53:38 -07001006
Dan Talayco8a64e332012-03-28 14:53:20 -07001007
1008def all_stats_get(parent):
1009 """
1010 Get the aggregate stats for all flows in the table
1011 @param parent Test instance with controller connection and assert
1012 @returns dict with keys flows, packets, bytes, active (flows),
1013 lookups, matched
1014 """
Rich Lanee717c6e2013-03-12 10:25:50 -07001015 stat_req = ofp.message.aggregate_stats_request()
1016 stat_req.match = ofp.match()
1017 stat_req.match.wildcards = ofp.OFPFW_ALL
Dan Talayco8a64e332012-03-28 14:53:20 -07001018 stat_req.table_id = 0xff
Rich Lanee717c6e2013-03-12 10:25:50 -07001019 stat_req.out_port = ofp.OFPP_NONE
Dan Talayco8a64e332012-03-28 14:53:20 -07001020
1021 rv = {}
1022
Rich Lanec8aaa3e2012-07-26 19:28:02 -07001023 (reply, pkt) = parent.controller.transact(stat_req)
Rich Lane5fd6faf2013-03-11 13:30:20 -07001024 parent.assertTrue(len(reply.entries) == 1, "Did not receive flow stats reply")
Dan Talayco8a64e332012-03-28 14:53:20 -07001025
Rich Lane5fd6faf2013-03-11 13:30:20 -07001026 for obj in reply.entries:
Dan Talayco8a64e332012-03-28 14:53:20 -07001027 (rv["flows"], rv["packets"], rv["bytes"]) = (obj.flow_count,
1028 obj.packet_count, obj.byte_count)
1029 break
1030
Rich Lanee717c6e2013-03-12 10:25:50 -07001031 request = ofp.message.table_stats_request()
Rich Lanec8aaa3e2012-07-26 19:28:02 -07001032 (reply , pkt) = parent.controller.transact(request)
Dan Talayco8a64e332012-03-28 14:53:20 -07001033
1034
1035 (rv["active"], rv["lookups"], rv["matched"]) = (0,0,0)
Rich Lane5fd6faf2013-03-11 13:30:20 -07001036 for obj in reply.entries:
Dan Talayco8a64e332012-03-28 14:53:20 -07001037 rv["active"] += obj.active_count
1038 rv["lookups"] += obj.lookup_count
1039 rv["matched"] += obj.matched_count
1040
1041 return rv
Dan Talayco2baf8b52012-03-30 09:55:42 -07001042
Rich Lane7744e112013-01-11 17:23:57 -08001043_import_blacklist.add('FILTER')
Dan Talayco2baf8b52012-03-30 09:55:42 -07001044FILTER=''.join([(len(repr(chr(x)))==3) and chr(x) or '.'
1045 for x in range(256)])
1046
1047def hex_dump_buffer(src, length=16):
1048 """
1049 Convert src to a hex dump string and return the string
1050 @param src The source buffer
1051 @param length The number of bytes shown in each line
1052 @returns A string showing the hex dump
1053 """
Dan Talaycoc516fa02012-04-12 22:28:43 -07001054 result = ["\n"]
Dan Talayco2baf8b52012-03-30 09:55:42 -07001055 for i in xrange(0, len(src), length):
1056 chars = src[i:i+length]
1057 hex = ' '.join(["%02x" % ord(x) for x in chars])
1058 printable = ''.join(["%s" % ((ord(x) <= 127 and
1059 FILTER[ord(x)]) or '.') for x in chars])
1060 result.append("%04x %-*s %s\n" % (i, length*3, hex, printable))
1061 return ''.join(result)
1062
1063def format_packet(pkt):
1064 return "Packet length %d \n%s" % (len(str(pkt)),
1065 hex_dump_buffer(str(pkt)))
Rich Lane5d7e89a2012-10-26 16:43:13 -07001066
1067def inspect_packet(pkt):
1068 """
1069 Wrapper around scapy's show() method.
1070 @returns A string showing the dissected packet.
1071 """
1072 from cStringIO import StringIO
1073 out = None
1074 backup = sys.stdout
1075 try:
1076 sys.stdout = StringIO()
1077 pkt.show2()
1078 out = sys.stdout.getvalue()
1079 sys.stdout.close()
1080 finally:
1081 sys.stdout = backup
1082 return out
Rich Lane0a4f6372013-01-02 14:40:22 -08001083
1084def nonstandard(cls):
1085 """
Rich Lanecc45b8e2013-01-02 15:55:02 -08001086 Testcase decorator that marks the test as being non-standard.
1087 These tests are not automatically added to the "standard" group.
Rich Lane0a4f6372013-01-02 14:40:22 -08001088 """
Rich Lanecc45b8e2013-01-02 15:55:02 -08001089 cls._nonstandard = True
Rich Lane0a4f6372013-01-02 14:40:22 -08001090 return cls
1091
1092def disabled(cls):
1093 """
Rich Lanecc45b8e2013-01-02 15:55:02 -08001094 Testcase decorator that marks the test as being disabled.
1095 These tests are not automatically added to the "standard" group or
1096 their module's group.
Rich Lane0a4f6372013-01-02 14:40:22 -08001097 """
Rich Lanecc45b8e2013-01-02 15:55:02 -08001098 cls._disabled = True
Rich Lane0a4f6372013-01-02 14:40:22 -08001099 return cls
Rich Lane97e99652013-01-02 17:23:20 -08001100
1101def group(name):
1102 """
1103 Testcase decorator that adds the test to a group.
1104 """
1105 def fn(cls):
1106 if not hasattr(cls, "_groups"):
1107 cls._groups = []
1108 cls._groups.append(name)
1109 return cls
1110 return fn
Rich Lane5a9a1922013-01-11 14:29:30 -08001111
1112def version(ver):
1113 """
1114 Testcase decorator that specifies which versions of OpenFlow the test
1115 supports. The default is 1.0+. This decorator may only be used once.
1116
1117 Supported syntax:
1118 1.0 -> 1.0
1119 1.0,1.2,1.3 -> 1.0, 1.2, 1.3
1120 1.0+ -> 1.0, 1.1, 1.2, 1.3
1121 """
1122 versions = parse_version(ver)
1123 def fn(cls):
1124 cls._versions = versions
1125 return cls
1126 return fn
1127
1128def parse_version(ver):
1129 allowed_versions = ["1.0", "1.1", "1.2", "1.3"]
1130 if re.match("^1\.\d+$", ver):
1131 versions = set([ver])
1132 elif re.match("^(1\.\d+)\+$", ver):
1133 if not ver[:-1] in allowed_versions:
1134 raise ValueError("invalid OpenFlow version %s" % ver[:-1])
1135 versions = set()
1136 if ver != "1.1+": versions.add("1.0")
1137 if ver != "1.2+": versions.add("1.1")
1138 if ver != "1.3+": versions.add("1.2")
1139 versions.add("1.3")
1140 else:
1141 versions = set(ver.split(','))
1142
1143 for version in versions:
1144 if not version in allowed_versions:
1145 raise ValueError("invalid OpenFlow version %s" % version)
1146
1147 return versions
1148
1149assert(parse_version("1.0") == set(["1.0"]))
1150assert(parse_version("1.0,1.2,1.3") == set(["1.0", "1.2", "1.3"]))
1151assert(parse_version("1.0+") == set(["1.0", "1.1", "1.2", "1.3"]))
Rich Lane7744e112013-01-11 17:23:57 -08001152
Rich Laneae3428c2013-03-07 14:37:42 -08001153def get_stats(test, req):
1154 """
1155 Retrieve a list of stats entries. Handles OFPSF_REPLY_MORE.
1156 """
1157 stats = []
1158 reply, _ = test.controller.transact(req)
1159 test.assertTrue(reply is not None, "No response to stats request")
Rich Lane5fd6faf2013-03-11 13:30:20 -07001160 stats.extend(reply.entries)
Rich Lanee717c6e2013-03-12 10:25:50 -07001161 while reply.flags & ofp.OFPSF_REPLY_MORE != 0:
1162 reply, pkt = self.controller.poll(exp_msg=ofp.OFPT_STATS_REPLY)
Rich Laneae3428c2013-03-07 14:37:42 -08001163 test.assertTrue(reply is not None, "No response to stats request")
Rich Lane5fd6faf2013-03-11 13:30:20 -07001164 stats.extend(reply.entries)
Rich Laneae3428c2013-03-07 14:37:42 -08001165 return stats
1166
Rich Lanef3bc48c2013-05-03 17:39:35 -07001167def get_flow_stats(test, match, table_id=0xff, out_port=None):
Rich Laneae3428c2013-03-07 14:37:42 -08001168 """
1169 Retrieve a list of flow stats entries.
1170 """
Rich Lanef3bc48c2013-05-03 17:39:35 -07001171 if out_port == None:
1172 out_port = ofp.OFPP_NONE
Rich Lanee717c6e2013-03-12 10:25:50 -07001173 req = ofp.message.flow_stats_request(match=match,
Rich Laneae3428c2013-03-07 14:37:42 -08001174 table_id=table_id,
1175 out_port=out_port)
1176 return get_stats(test, req)
1177
Rich Lane968b6192013-03-07 15:34:43 -08001178def get_port_stats(test, port_no):
1179 """
1180 Retrieve a list of port stats entries.
1181 """
Rich Lanee717c6e2013-03-12 10:25:50 -07001182 req = ofp.message.port_stats_request(port_no=port_no)
Rich Lane968b6192013-03-07 15:34:43 -08001183 return get_stats(test, req)
1184
Rich Lane6a334922013-03-07 16:14:52 -08001185def get_queue_stats(test, port_no, queue_id):
1186 """
1187 Retrieve a list of queue stats entries.
1188 """
Rich Lanee717c6e2013-03-12 10:25:50 -07001189 req = ofp.message.queue_stats_request(port_no=port_no, queue_id=queue_id)
Rich Lane6a334922013-03-07 16:14:52 -08001190 return get_stats(test, req)
1191
Rich Laneae3428c2013-03-07 14:37:42 -08001192def verify_flow_stats(test, match, table_id=0xff,
Rich Lanef3bc48c2013-05-03 17:39:35 -07001193 out_port=None,
Rich Laneae3428c2013-03-07 14:37:42 -08001194 initial=[],
1195 pkts=None, bytes=None):
1196 """
1197 Verify that flow stats changed as expected.
1198
1199 Optionally takes an 'initial' list of stats entries, as returned by
1200 get_flow_stats(). If 'initial' is not given the counters are assumed to
1201 begin at 0.
1202 """
Rich Lanef3bc48c2013-05-03 17:39:35 -07001203 if out_port == None:
1204 out_port = ofp.OFPP_NONE
1205
Rich Laneae3428c2013-03-07 14:37:42 -08001206 def accumulate(stats):
1207 pkts_acc = bytes_acc = 0
1208 for stat in stats:
1209 pkts_acc += stat.packet_count
1210 bytes_acc += stat.byte_count
1211 return (pkts_acc, bytes_acc)
1212
1213 pkts_before, bytes_before = accumulate(initial)
1214
1215 # Wait 10s for counters to update
1216 pkt_diff = byte_diff = None
1217 for i in range(0, 100):
1218 stats = get_flow_stats(test, match, table_id=table_id, out_port=out_port)
1219 pkts_after, bytes_after = accumulate(stats)
1220 pkt_diff = pkts_after - pkts_before
1221 byte_diff = bytes_after - bytes_before
1222 if (pkts == None or pkt_diff >= pkts) and \
1223 (bytes == None or byte_diff >= bytes):
1224 break
Dan Talayco53724732013-03-08 23:54:02 -08001225 time.sleep(0.1)
Rich Laneae3428c2013-03-07 14:37:42 -08001226
1227 if pkts != None:
1228 test.assertEquals(pkt_diff, pkts, "Flow packet counter not updated properly (expected increase of %d, got increase of %d)" % (pkts, pkt_diff))
1229
1230 if bytes != None:
Rich Lane53b96812013-03-07 16:54:50 -08001231 test.assertTrue(byte_diff >= bytes and byte_diff <= bytes*1.1,
1232 "Flow byte counter not updated properly (expected increase of %d, got increase of %d)" % (bytes, byte_diff))
Rich Laneae3428c2013-03-07 14:37:42 -08001233
Rich Lane968b6192013-03-07 15:34:43 -08001234def verify_port_stats(test, port,
1235 initial=[],
1236 tx_pkts=None, rx_pkts=None,
1237 tx_bytes=None, rx_bytes=None):
1238 """
1239 Verify that port stats changed as expected.
1240
1241 Optionally takes an 'initial' list of stats entries, as returned by
1242 get_port_stats(). If 'initial' is not given the counters are assumed to
1243 begin at 0.
1244 """
1245 def accumulate(stats):
1246 tx_pkts_acc = rx_pkts_acc = tx_bytes_acc = rx_bytes_acc = 0
1247 for stat in stats:
1248 tx_pkts_acc += stat.tx_packets
1249 rx_pkts_acc += stat.rx_packets
1250 tx_bytes_acc += stat.tx_bytes
1251 rx_bytes_acc += stat.rx_bytes
1252 return (tx_pkts_acc, rx_pkts_acc, tx_bytes_acc, rx_bytes_acc)
1253
1254 tx_pkts_before, rx_pkts_before, \
1255 tx_bytes_before, rx_bytes_before = accumulate(initial)
1256
1257 # Wait 10s for counters to update
1258 for i in range(0, 100):
1259 stats = get_port_stats(test, port)
1260 tx_pkts_after, rx_pkts_after, \
1261 tx_bytes_after, rx_bytes_after = accumulate(stats)
1262 tx_pkts_diff = tx_pkts_after - tx_pkts_before
1263 rx_pkts_diff = rx_pkts_after - rx_pkts_before
1264 tx_bytes_diff = tx_bytes_after - tx_bytes_before
1265 rx_bytes_diff = rx_bytes_after - rx_bytes_before
1266 if (tx_pkts == None or tx_pkts == tx_pkts_diff) and \
1267 (rx_pkts == None or rx_pkts == rx_pkts_diff) and \
Rich Lane53b96812013-03-07 16:54:50 -08001268 (tx_bytes == None or tx_bytes <= tx_bytes_diff) and \
1269 (rx_bytes == None or rx_bytes <= rx_bytes_diff):
Rich Lane968b6192013-03-07 15:34:43 -08001270 break
1271 time.sleep(0.1)
1272
1273 if (tx_pkts != None):
1274 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))
1275 if (rx_pkts != None):
1276 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))
1277 if (tx_bytes != None):
Rich Lane53b96812013-03-07 16:54:50 -08001278 test.assertTrue(tx_bytes_diff >= tx_bytes and tx_bytes_diff <= tx_bytes*1.1,
1279 "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 -08001280 if (rx_bytes != None):
Rich Lane53b96812013-03-07 16:54:50 -08001281 test.assertTrue(rx_bytes_diff >= rx_bytes and rx_bytes_diff <= rx_bytes*1.1,
1282 "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 -08001283
Rich Lane6a334922013-03-07 16:14:52 -08001284def verify_queue_stats(test, port_no, queue_id,
1285 initial=[],
1286 pkts=None, bytes=None):
1287 """
1288 Verify that queue stats changed as expected.
1289
1290 Optionally takes an 'initial' list of stats entries, as returned by
1291 get_queue_stats(). If 'initial' is not given the counters are assumed to
1292 begin at 0.
1293 """
1294 def accumulate(stats):
1295 pkts_acc = bytes_acc = 0
1296 for stat in stats:
1297 pkts_acc += stat.tx_packets
1298 bytes_acc += stat.tx_bytes
1299 return (pkts_acc, bytes_acc)
1300
1301 pkts_before, bytes_before = accumulate(initial)
1302
1303 # Wait 10s for counters to update
1304 pkt_diff = byte_diff = None
1305 for i in range(0, 100):
1306 stats = get_queue_stats(test, port_no, queue_id)
1307 pkts_after, bytes_after = accumulate(stats)
1308 pkt_diff = pkts_after - pkts_before
1309 byte_diff = bytes_after - bytes_before
1310 if (pkts == None or pkt_diff >= pkts) and \
1311 (bytes == None or byte_diff >= bytes):
1312 break
Dan Talayco53724732013-03-08 23:54:02 -08001313 time.sleep(0.1)
Rich Lane6a334922013-03-07 16:14:52 -08001314
1315 if pkts != None:
1316 test.assertEquals(pkt_diff, pkts, "Queue packet counter not updated properly (expected increase of %d, got increase of %d)" % (pkts, pkt_diff))
1317
1318 if bytes != None:
Rich Lane53b96812013-03-07 16:54:50 -08001319 test.assertTrue(byte_diff >= bytes and byte_diff <= bytes*1.1,
1320 "Queue byte counter not updated properly (expected increase of %d, got increase of %d)" % (bytes, byte_diff))
Rich Laneae3428c2013-03-07 14:37:42 -08001321
Rich Lane4c504f32013-06-07 17:24:14 -07001322def packet_in_match(msg, data, in_port=None, reason=None):
1323 """
1324 Check whether the packet_in message 'msg' has fields matching 'data',
1325 'in_port', and 'reason'.
1326
1327 This function handles truncated packet_in data. The 'in_port' and 'reason'
1328 parameters are optional.
1329
1330 @param msg packet_in message
1331 @param data Expected packet_in data
1332 @param in_port Expected packet_in in_port, or None
1333 @param reason Expected packet_in reason, or None
1334 """
1335
1336 if in_port and in_port != msg.in_port:
1337 logging.debug("Incorrect packet_in in_port (expected %d, received %d)", in_port, msg.in_port)
1338 return False
1339
1340 if reason and reason != msg.reason:
1341 logging.debug("Incorrect packet_in reason (expected %d, received %d)", reason, msg.reason)
1342 return False
1343
1344 # Check that one of the packets is a prefix of the other.
1345 # The received packet may be either truncated or padded, but not both.
1346 # (Some of the padding may be truncated but that's irrelevant). We
1347 # need to check that the smaller packet is a prefix of the larger one.
1348 # Note that this check succeeds if the switch sends a zero-length
1349 # packet-in.
1350 compare_len = min(len(msg.data), len(data))
1351 if data[:compare_len] != msg.data[:compare_len]:
1352 logging.debug("Incorrect packet_in data")
1353 logging.debug("Expected %s" % format_packet(data[:compare_len]))
1354 logging.debug("Received %s" % format_packet(msg.data[:compare_len]))
1355 return False
1356
1357 return True
1358
1359def verify_packet_in(test, data, in_port, reason, controller=None):
1360 """
1361 Assert that the controller receives a packet_in message matching data 'data'
1362 from port 'in_port' with reason 'reason'. Does not trigger the packet_in
1363 itself, that's up to the test case.
1364
1365 @param test Instance of base_tests.SimpleProtocol
1366 @param pkt String to expect as the packet_in data
1367 @param in_port OpenFlow port number to expect as the packet_in in_port
1368 @param reason One of OFPR_* to expect as the packet_in reason
1369 @param controller Controller instance, defaults to test.controller
1370 @returns The received packet-in message
1371 """
1372
1373 if controller == None:
1374 controller = test.controller
1375
1376 end_time = time.time() + oftest.ofutils.default_timeout
1377
1378 while True:
1379 msg, _ = controller.poll(ofp.OFPT_PACKET_IN, end_time - time.time())
1380 if not msg:
1381 # Timeout
1382 break
1383 elif packet_in_match(msg, data, in_port, reason):
1384 # Found a matching message
1385 break
1386
1387 test.assertTrue(msg is not None, 'Packet in message not received on port %d' % in_port)
1388 return msg
1389
1390def verify_no_packet_in(test, data, in_port, controller=None):
1391 """
1392 Assert that the controller does not receive a packet_in message matching
1393 data 'data' from port 'in_port'.
1394
1395 @param test Instance of base_tests.SimpleProtocol
1396 @param pkt String to expect as the packet_in data
1397 @param in_port OpenFlow port number to expect as the packet_in in_port
1398 @param controller Controller instance, defaults to test.controller
1399 """
1400
1401 if controller == None:
1402 controller = test.controller
1403
1404 # Negative test, need to wait a short amount of time before checking we
1405 # didn't receive the message.
1406 time.sleep(0.5)
1407
1408 # Check every packet_in queued in the controller
1409 while True:
1410 msg, _ = controller.poll(ofp.OFPT_PACKET_IN, timeout=0)
1411 if msg == None:
1412 # No more queued packet_in messages
1413 break
1414 elif packet_in_match(msg, data, in_port, None):
1415 # Found a matching message
1416 break
1417
1418 test.assertTrue(msg == None, "Did not expect a packet-in message on port %d" % in_port)
1419
Rich Lane7744e112013-01-11 17:23:57 -08001420__all__ = list(set(locals()) - _import_blacklist)