blob: 54e22e8a50c56072ceb70446603cee94f43561dc [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 Lane6dc865c2013-07-10 10:12:13 -0700366
367 if ofp.OFP_VERSION <= 3:
368 request = ofp.message.features_request()
369 reply, _ = controller.transact(request)
370 if reply is None:
371 logging.warn("Get feature request failed")
372 return None, None, None
373 logging.debug(reply.show())
374 ports = reply.ports
375 else:
376 request = ofp.message.port_desc_stats_request()
377 # TODO do multipart correctly
378 reply, _ = controller.transact(request)
379 if reply is None:
380 logging.warn("Port desc stats request failed")
381 return None, None, None
382 logging.debug(reply.show())
383 ports = reply.entries
384
385 for port in ports:
386 if port.port_no == port_no:
387 return (port.hw_addr, port.config, port.advertised)
Dan Talayco92c99122010-06-03 13:53:18 -0700388
Rich Lane9a003812012-10-04 17:17:59 -0700389 logging.warn("Did not find port number for port config")
Dan Talayco92c99122010-06-03 13:53:18 -0700390 return None, None, None
391
Rich Lane9a003812012-10-04 17:17:59 -0700392def port_config_set(controller, port_no, config, mask):
Dan Talayco92c99122010-06-03 13:53:18 -0700393 """
394 Set the port configuration according the given parameters
395
396 Gets the switch feature configuration and updates one port's
397 configuration value according to config and mask
398 """
Rich Lane9a003812012-10-04 17:17:59 -0700399 logging.info("Setting port " + str(port_no) + " to config " + str(config))
Rich Lane6dc865c2013-07-10 10:12:13 -0700400
401 hw_addr, _, _ = port_config_get(controller, port_no)
402
Rich Lanee717c6e2013-03-12 10:25:50 -0700403 mod = ofp.message.port_mod()
Dan Talayco92c99122010-06-03 13:53:18 -0700404 mod.port_no = port_no
Rich Lane6dc865c2013-07-10 10:12:13 -0700405 if hw_addr != None:
406 mod.hw_addr = hw_addr
Dan Talayco92c99122010-06-03 13:53:18 -0700407 mod.config = config
408 mod.mask = mask
Rich Lane6dc865c2013-07-10 10:12:13 -0700409 mod.advertise = 0 # No change
Rich Lane5c3151c2013-01-03 17:15:41 -0800410 controller.message_send(mod)
411 return 0
Dan Talayco92c99122010-06-03 13:53:18 -0700412
Rich Lane2014f9b2012-10-05 15:29:40 -0700413def receive_pkt_check(dp, pkt, yes_ports, no_ports, assert_if):
Dan Talayco92c99122010-06-03 13:53:18 -0700414 """
415 Check for proper receive packets across all ports
Ken Chiang1bf01602012-04-04 10:48:23 -0700416 @param dp The dataplane object
Dan Talayco92c99122010-06-03 13:53:18 -0700417 @param pkt Expected packet; may be None if yes_ports is empty
418 @param yes_ports Set or list of ports that should recieve packet
419 @param no_ports Set or list of ports that should not receive packet
420 @param assert_if Object that implements assertXXX
421 """
Rich Lane91765672012-12-06 16:33:04 -0800422
423 # Wait this long for packets that we don't expect to receive.
424 # 100ms is (rarely) too short for positive tests on slow
425 # switches but is definitely not too short for a negative test.
426 negative_timeout = 0.1
427
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700428 exp_pkt_arg = None
Rich Lanecd97d3d2013-01-07 18:50:06 -0800429 if oftest.config["relax"]:
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700430 exp_pkt_arg = pkt
431
Dan Talayco92c99122010-06-03 13:53:18 -0700432 for ofport in yes_ports:
Rich Lane9a003812012-10-04 17:17:59 -0700433 logging.debug("Checking for pkt on port " + str(ofport))
Ken Chiang1bf01602012-04-04 10:48:23 -0700434 (rcv_port, rcv_pkt, pkt_time) = dp.poll(
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700435 port_number=ofport, exp_pkt=exp_pkt_arg)
Dan Talayco92c99122010-06-03 13:53:18 -0700436 assert_if.assertTrue(rcv_pkt is not None,
437 "Did not receive pkt on " + str(ofport))
Rich Lanecd97d3d2013-01-07 18:50:06 -0800438 if not oftest.dataplane.match_exp_pkt(pkt, rcv_pkt):
Rich Lane3c266832013-01-29 18:29:15 -0800439 logging.debug("Expected %s" % format_packet(pkt))
440 logging.debug("Received %s" % format_packet(rcv_pkt))
Rich Lanecd97d3d2013-01-07 18:50:06 -0800441 assert_if.assertTrue(oftest.dataplane.match_exp_pkt(pkt, rcv_pkt),
Rich Lane3c266832013-01-29 18:29:15 -0800442 "Received packet does not match expected packet " +
Ken Chiang1bf01602012-04-04 10:48:23 -0700443 "on port " + str(ofport))
Dan Talayco73f84012012-10-02 09:23:18 -0700444 if len(no_ports) > 0:
Rich Lane91765672012-12-06 16:33:04 -0800445 time.sleep(negative_timeout)
Dan Talayco92c99122010-06-03 13:53:18 -0700446 for ofport in no_ports:
Rich Lane9a003812012-10-04 17:17:59 -0700447 logging.debug("Negative check for pkt on port " + str(ofport))
Ken Chiang1bf01602012-04-04 10:48:23 -0700448 (rcv_port, rcv_pkt, pkt_time) = dp.poll(
Rich Lane91765672012-12-06 16:33:04 -0800449 port_number=ofport, timeout=0, exp_pkt=exp_pkt_arg)
Dan Talayco92c99122010-06-03 13:53:18 -0700450 assert_if.assertTrue(rcv_pkt is None,
451 "Unexpected pkt on port " + str(ofport))
Dan Talayco551befa2010-07-15 17:05:32 -0700452
453
Dan Talaycoc948d0b2012-03-23 12:17:54 -0700454def receive_pkt_verify(parent, egr_ports, exp_pkt, ing_port):
Dan Talayco551befa2010-07-15 17:05:32 -0700455 """
456 Receive a packet and verify it matches an expected value
Dan Talaycof6e76c02012-03-23 10:56:12 -0700457 @param egr_port A single port or list of ports
Dan Talayco551befa2010-07-15 17:05:32 -0700458
459 parent must implement dataplane, assertTrue and assertEqual
460 """
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700461 exp_pkt_arg = None
Rich Lanecd97d3d2013-01-07 18:50:06 -0800462 if oftest.config["relax"]:
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700463 exp_pkt_arg = exp_pkt
464
Dan Talaycof6e76c02012-03-23 10:56:12 -0700465 if type(egr_ports) == type([]):
466 egr_port_list = egr_ports
467 else:
468 egr_port_list = [egr_ports]
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700469
Dan Talaycof6e76c02012-03-23 10:56:12 -0700470 # Expect a packet from each port on egr port list
471 for egr_port in egr_port_list:
Dan Talaycod8ae7582012-03-23 12:24:56 -0700472 check_port = egr_port
Rich Lanee717c6e2013-03-12 10:25:50 -0700473 if egr_port == ofp.OFPP_IN_PORT:
Dan Talaycod8ae7582012-03-23 12:24:56 -0700474 check_port = ing_port
Dan Talaycof6e76c02012-03-23 10:56:12 -0700475 (rcv_port, rcv_pkt, pkt_time) = parent.dataplane.poll(
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700476 port_number=check_port, exp_pkt=exp_pkt_arg)
Dan Talayco551befa2010-07-15 17:05:32 -0700477
Dan Talaycof6e76c02012-03-23 10:56:12 -0700478 if rcv_pkt is None:
Rich Lane9a003812012-10-04 17:17:59 -0700479 logging.error("ERROR: No packet received from " +
Dan Talaycod8ae7582012-03-23 12:24:56 -0700480 str(check_port))
Dan Talayco551befa2010-07-15 17:05:32 -0700481
Dan Talaycof6e76c02012-03-23 10:56:12 -0700482 parent.assertTrue(rcv_pkt is not None,
Dan Talaycod8ae7582012-03-23 12:24:56 -0700483 "Did not receive packet port " + str(check_port))
Rich Lane9a003812012-10-04 17:17:59 -0700484 logging.debug("Packet len " + str(len(rcv_pkt)) + " in on " +
Dan Talaycof6e76c02012-03-23 10:56:12 -0700485 str(rcv_port))
486
487 if str(exp_pkt) != str(rcv_pkt):
Rich Lane9a003812012-10-04 17:17:59 -0700488 logging.error("ERROR: Packet match failed.")
489 logging.debug("Expected len " + str(len(exp_pkt)) + ": "
Dan Talaycof6e76c02012-03-23 10:56:12 -0700490 + str(exp_pkt).encode('hex'))
Rich Lane9a003812012-10-04 17:17:59 -0700491 logging.debug("Received len " + str(len(rcv_pkt)) + ": "
Dan Talaycof6e76c02012-03-23 10:56:12 -0700492 + str(rcv_pkt).encode('hex'))
Rich Lane5d7e89a2012-10-26 16:43:13 -0700493 logging.debug("Expected packet: " + inspect_packet(scapy.Ether(str(exp_pkt))))
494 logging.debug("Received packet: " + inspect_packet(scapy.Ether(str(rcv_pkt))))
Dan Talaycof6e76c02012-03-23 10:56:12 -0700495 parent.assertEqual(str(exp_pkt), str(rcv_pkt),
Dan Talaycod8ae7582012-03-23 12:24:56 -0700496 "Packet match error on port " + str(check_port))
Dan Talaycof6e76c02012-03-23 10:56:12 -0700497
Dan Talayco551befa2010-07-15 17:05:32 -0700498def match_verify(parent, req_match, res_match):
499 """
500 Verify flow matches agree; if they disagree, report where
501
502 parent must implement assertEqual
503 Use str() to ensure content is compared and not pointers
504 """
505
506 parent.assertEqual(req_match.wildcards, res_match.wildcards,
507 'Match failed: wildcards: ' + hex(req_match.wildcards) +
508 " != " + hex(res_match.wildcards))
509 parent.assertEqual(req_match.in_port, res_match.in_port,
510 'Match failed: in_port: ' + str(req_match.in_port) +
511 " != " + str(res_match.in_port))
Rich Laned0478ff2013-03-11 12:46:58 -0700512 parent.assertEqual(str(req_match.eth_src), str(res_match.eth_src),
513 'Match failed: eth_src: ' + str(req_match.eth_src) +
514 " != " + str(res_match.eth_src))
515 parent.assertEqual(str(req_match.eth_dst), str(res_match.eth_dst),
516 'Match failed: eth_dst: ' + str(req_match.eth_dst) +
517 " != " + str(res_match.eth_dst))
518 parent.assertEqual(req_match.vlan_vid, res_match.vlan_vid,
519 'Match failed: vlan_vid: ' + str(req_match.vlan_vid) +
520 " != " + str(res_match.vlan_vid))
521 parent.assertEqual(req_match.vlan_pcp, res_match.vlan_pcp,
522 'Match failed: vlan_pcp: ' +
523 str(req_match.vlan_pcp) + " != " +
524 str(res_match.vlan_pcp))
525 parent.assertEqual(req_match.eth_type, res_match.eth_type,
526 'Match failed: eth_type: ' + str(req_match.eth_type) +
527 " != " + str(res_match.eth_type))
Dan Talayco551befa2010-07-15 17:05:32 -0700528
Rich Lanee717c6e2013-03-12 10:25:50 -0700529 if (not(req_match.wildcards & ofp.OFPFW_DL_TYPE)
Rich Laned0478ff2013-03-11 12:46:58 -0700530 and (req_match.eth_type == IP_ETHERTYPE)):
531 parent.assertEqual(req_match.ip_dscp, res_match.ip_dscp,
532 'Match failed: ip_dscp: ' + str(req_match.ip_dscp) +
533 " != " + str(res_match.ip_dscp))
534 parent.assertEqual(req_match.ip_proto, res_match.ip_proto,
535 'Match failed: ip_proto: ' + str(req_match.ip_proto) +
536 " != " + str(res_match.ip_proto))
537 parent.assertEqual(req_match.ipv4_src, res_match.ipv4_src,
538 'Match failed: ipv4_src: ' + str(req_match.ipv4_src) +
539 " != " + str(res_match.ipv4_src))
540 parent.assertEqual(req_match.ipv4_dst, res_match.ipv4_dst,
541 'Match failed: ipv4_dst: ' + str(req_match.ipv4_dst) +
542 " != " + str(res_match.ipv4_dst))
Dan Talayco551befa2010-07-15 17:05:32 -0700543
Rich Lanee717c6e2013-03-12 10:25:50 -0700544 if (not(req_match.wildcards & ofp.OFPFW_NW_PROTO)
Rich Laned0478ff2013-03-11 12:46:58 -0700545 and ((req_match.ip_proto == TCP_PROTOCOL)
546 or (req_match.ip_proto == UDP_PROTOCOL))):
547 parent.assertEqual(req_match.tcp_src, res_match.tcp_src,
548 'Match failed: tcp_src: ' +
549 str(req_match.tcp_src) +
550 " != " + str(res_match.tcp_src))
551 parent.assertEqual(req_match.tcp_dst, res_match.tcp_dst,
552 'Match failed: tcp_dst: ' +
553 str(req_match.tcp_dst) +
554 " != " + str(res_match.tcp_dst))
Dan Talayco551befa2010-07-15 17:05:32 -0700555
Ed Swierk99a74de2012-08-22 06:40:54 -0700556def packet_to_flow_match(parent, packet):
Rich Lanef6883512013-03-11 17:00:09 -0700557 match = oftest.parse.packet_to_flow_match(packet)
Rich Laneab7476f2013-06-13 15:53:52 -0700558 if ofp.OFP_VERSION in [1, 2]:
559 match.wildcards |= required_wildcards(parent)
560 else:
561 # TODO remove incompatible OXM entries
562 pass
Ed Swierk99a74de2012-08-22 06:40:54 -0700563 return match
564
565def flow_msg_create(parent, pkt, ing_port=None, action_list=None, wildcards=None,
Dan Talaycof6e76c02012-03-23 10:56:12 -0700566 egr_ports=None, egr_queue=None, check_expire=False, in_band=False):
Dan Talayco551befa2010-07-15 17:05:32 -0700567 """
568 Create a flow message
569
570 Match on packet with given wildcards.
571 See flow_match_test for other parameter descriptoins
572 @param egr_queue if not None, make the output an enqueue action
Dan Talayco677c0b72011-08-23 22:53:38 -0700573 @param in_band if True, do not wildcard ingress port
Dan Talaycof6e76c02012-03-23 10:56:12 -0700574 @param egr_ports None (drop), single port or list of ports
Dan Talayco551befa2010-07-15 17:05:32 -0700575 """
Rich Lanef6883512013-03-11 17:00:09 -0700576 match = oftest.parse.packet_to_flow_match(pkt)
Dan Talayco551befa2010-07-15 17:05:32 -0700577 parent.assertTrue(match is not None, "Flow match from pkt failed")
Ed Swierk99a74de2012-08-22 06:40:54 -0700578 if wildcards is None:
579 wildcards = required_wildcards(parent)
Dan Talayco677c0b72011-08-23 22:53:38 -0700580 if in_band:
Rich Lanee717c6e2013-03-12 10:25:50 -0700581 wildcards &= ~ofp.OFPFW_IN_PORT
Dan Talayco551befa2010-07-15 17:05:32 -0700582 match.wildcards = wildcards
583 match.in_port = ing_port
584
Dan Talaycof6e76c02012-03-23 10:56:12 -0700585 if type(egr_ports) == type([]):
586 egr_port_list = egr_ports
587 else:
588 egr_port_list = [egr_ports]
589
Rich Lanee717c6e2013-03-12 10:25:50 -0700590 request = ofp.message.flow_add()
Dan Talayco551befa2010-07-15 17:05:32 -0700591 request.match = match
592 request.buffer_id = 0xffffffff
593 if check_expire:
Rich Lanee717c6e2013-03-12 10:25:50 -0700594 request.flags |= ofp.OFPFF_SEND_FLOW_REM
Dan Talayco551befa2010-07-15 17:05:32 -0700595 request.hard_timeout = 1
596
597 if action_list is not None:
598 for act in action_list:
Rich Lane9a003812012-10-04 17:17:59 -0700599 logging.debug("Adding action " + act.show())
Rich Lanec495d9e2013-03-08 17:43:36 -0800600 request.actions.append(act)
Dan Talayco551befa2010-07-15 17:05:32 -0700601
602 # Set up output/enqueue action if directed
603 if egr_queue is not None:
Dan Talaycof6e76c02012-03-23 10:56:12 -0700604 parent.assertTrue(egr_ports is not None, "Egress port not set")
Rich Lanee717c6e2013-03-12 10:25:50 -0700605 act = ofp.action.enqueue()
Dan Talaycof6e76c02012-03-23 10:56:12 -0700606 for egr_port in egr_port_list:
607 act.port = egr_port
608 act.queue_id = egr_queue
Rich Lanec495d9e2013-03-08 17:43:36 -0800609 request.actions.append(act)
Dan Talaycof6e76c02012-03-23 10:56:12 -0700610 elif egr_ports is not None:
611 for egr_port in egr_port_list:
Rich Lanee717c6e2013-03-12 10:25:50 -0700612 act = ofp.action.output()
Dan Talaycof6e76c02012-03-23 10:56:12 -0700613 act.port = egr_port
Rich Lanec495d9e2013-03-08 17:43:36 -0800614 request.actions.append(act)
Dan Talayco551befa2010-07-15 17:05:32 -0700615
Rich Lane9a003812012-10-04 17:17:59 -0700616 logging.debug(request.show())
Dan Talayco551befa2010-07-15 17:05:32 -0700617
618 return request
619
Jeffrey Townsendf3eae9c2012-03-28 18:23:21 -0700620def flow_msg_install(parent, request, clear_table_override=None):
Dan Talayco551befa2010-07-15 17:05:32 -0700621 """
622 Install a flow mod message in the switch
623
624 @param parent Must implement controller, assertEqual, assertTrue
625 @param request The request, all set to go
626 @param clear_table If true, clear the flow table before installing
627 """
Dan Talayco8a64e332012-03-28 14:53:20 -0700628
Rich Lane2014f9b2012-10-05 15:29:40 -0700629 clear_table = test_param_get('clear_table', default=True)
Jeffrey Townsendf3eae9c2012-03-28 18:23:21 -0700630 if(clear_table_override != None):
631 clear_table = clear_table_override
632
633 if clear_table:
Rich Lane9a003812012-10-04 17:17:59 -0700634 logging.debug("Clear flow table")
Rich Lane32bf9482013-01-03 17:26:30 -0800635 delete_all_flows(parent.controller)
Dan Talayco551befa2010-07-15 17:05:32 -0700636
Rich Lane9a003812012-10-04 17:17:59 -0700637 logging.debug("Insert flow")
Rich Lane5c3151c2013-01-03 17:15:41 -0800638 parent.controller.message_send(request)
Rich Lanee912d032012-12-22 14:28:33 -0800639
Rich Lane3a261d52013-01-03 17:45:08 -0800640 do_barrier(parent.controller)
Dan Talayco551befa2010-07-15 17:05:32 -0700641
Ed Swierk99a74de2012-08-22 06:40:54 -0700642def flow_match_test_port_pair(parent, ing_port, egr_ports, wildcards=None,
Rich Laned0478ff2013-03-11 12:46:58 -0700643 vlan_vid=-1, pkt=None, exp_pkt=None,
Rich Lanee5779d32012-10-05 17:56:04 -0700644 action_list=None):
Dan Talayco551befa2010-07-15 17:05:32 -0700645 """
646 Flow match test on single TCP packet
Dan Talaycof6e76c02012-03-23 10:56:12 -0700647 @param egr_ports A single port or list of ports
Dan Talayco551befa2010-07-15 17:05:32 -0700648
649 Run test with packet through switch from ing_port to egr_port
650 See flow_match_test for parameter descriptions
651 """
652
Ed Swierk99a74de2012-08-22 06:40:54 -0700653 if wildcards is None:
654 wildcards = required_wildcards(parent)
Rich Lane9a003812012-10-04 17:17:59 -0700655 logging.info("Pkt match test: " + str(ing_port) + " to " +
Dan Talaycof6e76c02012-03-23 10:56:12 -0700656 str(egr_ports))
Rich Laned0478ff2013-03-11 12:46:58 -0700657 logging.debug(" WC: " + hex(wildcards) + " vlan: " + str(vlan_vid))
Dan Talayco551befa2010-07-15 17:05:32 -0700658 if pkt is None:
Rich Laned0478ff2013-03-11 12:46:58 -0700659 pkt = simple_tcp_packet(dl_vlan_enable=(vlan_vid >= 0), vlan_vid=vlan_vid)
Dan Talayco551befa2010-07-15 17:05:32 -0700660
661 request = flow_msg_create(parent, pkt, ing_port=ing_port,
Dan Talaycof6e76c02012-03-23 10:56:12 -0700662 wildcards=wildcards, egr_ports=egr_ports,
Dan Talayco551befa2010-07-15 17:05:32 -0700663 action_list=action_list)
664
665 flow_msg_install(parent, request)
666
Rich Lane9a003812012-10-04 17:17:59 -0700667 logging.debug("Send packet: " + str(ing_port) + " to " +
Dan Talaycof6e76c02012-03-23 10:56:12 -0700668 str(egr_ports))
Dan Talayco551befa2010-07-15 17:05:32 -0700669 parent.dataplane.send(ing_port, str(pkt))
670
671 if exp_pkt is None:
672 exp_pkt = pkt
Dan Talaycoc948d0b2012-03-23 12:17:54 -0700673 receive_pkt_verify(parent, egr_ports, exp_pkt, ing_port)
Dan Talayco551befa2010-07-15 17:05:32 -0700674
Rich Lane89725bb2012-12-03 16:23:27 -0800675def flow_match_test_pktout(parent, ing_port, egr_ports,
Rich Laned0478ff2013-03-11 12:46:58 -0700676 vlan_vid=-1, pkt=None, exp_pkt=None,
Rich Lane89725bb2012-12-03 16:23:27 -0800677 action_list=None):
678 """
679 Packet-out test on single TCP packet
680 @param egr_ports A single port or list of ports
681
682 Run test sending packet-out to egr_ports. The goal is to test the actions
683 taken on the packet, not the matching which is of course irrelevant.
684 See flow_match_test for parameter descriptions
685 """
686
687 if pkt is None:
Rich Laned0478ff2013-03-11 12:46:58 -0700688 pkt = simple_tcp_packet(dl_vlan_enable=(vlan_vid >= 0), vlan_vid=vlan_vid)
Rich Lane89725bb2012-12-03 16:23:27 -0800689
Rich Lanee717c6e2013-03-12 10:25:50 -0700690 msg = ofp.message.packet_out()
Rich Lane89725bb2012-12-03 16:23:27 -0800691 msg.in_port = ing_port
Rich Laneea8c4722013-04-04 15:30:20 -0700692 msg.buffer_id = 0xffffffff
Rich Lane89725bb2012-12-03 16:23:27 -0800693 msg.data = str(pkt)
694 if action_list is not None:
695 for act in action_list:
Rich Lanec495d9e2013-03-08 17:43:36 -0800696 msg.actions.append(act)
Rich Lane89725bb2012-12-03 16:23:27 -0800697
698 # Set up output action
699 if egr_ports is not None:
700 for egr_port in egr_ports:
Rich Lanee717c6e2013-03-12 10:25:50 -0700701 act = ofp.action.output()
Rich Lane89725bb2012-12-03 16:23:27 -0800702 act.port = egr_port
Rich Lanec495d9e2013-03-08 17:43:36 -0800703 msg.actions.append(act)
Rich Lane89725bb2012-12-03 16:23:27 -0800704
705 logging.debug(msg.show())
Rich Lane5c3151c2013-01-03 17:15:41 -0800706 parent.controller.message_send(msg)
Rich Lane89725bb2012-12-03 16:23:27 -0800707
708 if exp_pkt is None:
709 exp_pkt = pkt
710 receive_pkt_verify(parent, egr_ports, exp_pkt, ing_port)
711
Dan Talaycof6e76c02012-03-23 10:56:12 -0700712def get_egr_list(parent, of_ports, how_many, exclude_list=[]):
713 """
714 Generate a list of ports avoiding those in the exclude list
Rich Lane9a003812012-10-04 17:17:59 -0700715 @param parent Supplies logging
Dan Talaycof6e76c02012-03-23 10:56:12 -0700716 @param of_ports List of OF port numbers
717 @param how_many Number of ports to be added to the list
718 @param exclude_list List of ports not to be used
719 @returns An empty list if unable to find enough ports
720 """
721
Dan Talaycoc948d0b2012-03-23 12:17:54 -0700722 if how_many == 0:
723 return []
724
Dan Talaycof6e76c02012-03-23 10:56:12 -0700725 count = 0
726 egr_ports = []
727 for egr_idx in range(len(of_ports)):
728 if of_ports[egr_idx] not in exclude_list:
729 egr_ports.append(of_ports[egr_idx])
730 count += 1
731 if count >= how_many:
732 return egr_ports
Rich Lane9a003812012-10-04 17:17:59 -0700733 logging.debug("Could not generate enough egress ports for test")
Dan Talaycof6e76c02012-03-23 10:56:12 -0700734 return []
735
Rich Laned0478ff2013-03-11 12:46:58 -0700736def flow_match_test(parent, port_map, wildcards=None, vlan_vid=-1, pkt=None,
Rich Lanee5779d32012-10-05 17:56:04 -0700737 exp_pkt=None, action_list=None,
Dan Talaycoc948d0b2012-03-23 12:17:54 -0700738 max_test=0, egr_count=1, ing_port=False):
Dan Talayco551befa2010-07-15 17:05:32 -0700739 """
Rich Lane89725bb2012-12-03 16:23:27 -0800740 Run flow_match_test_port_pair on all port pairs and packet-out
Dan Talayco551befa2010-07-15 17:05:32 -0700741
742 @param max_test If > 0 no more than this number of tests are executed.
743 @param parent Must implement controller, dataplane, assertTrue, assertEqual
Rich Lane9a003812012-10-04 17:17:59 -0700744 and logging
Dan Talayco551befa2010-07-15 17:05:32 -0700745 @param pkt If not None, use this packet for ingress
746 @param wildcards For flow match entry
Rich Laned0478ff2013-03-11 12:46:58 -0700747 @param vlan_vid If not -1, and pkt is None, create a pkt w/ VLAN tag
Dan Talayco551befa2010-07-15 17:05:32 -0700748 @param exp_pkt If not None, use this as the expected output pkt; els use pkt
749 @param action_list Additional actions to add to flow mod
Dan Talaycocfa172f2012-03-23 12:03:00 -0700750 @param egr_count Number of egress ports; -1 means get from config w/ dflt 2
Dan Talayco551befa2010-07-15 17:05:32 -0700751 """
Ed Swierk99a74de2012-08-22 06:40:54 -0700752 if wildcards is None:
753 wildcards = required_wildcards(parent)
Dan Talayco551befa2010-07-15 17:05:32 -0700754 of_ports = port_map.keys()
755 of_ports.sort()
756 parent.assertTrue(len(of_ports) > 1, "Not enough ports for test")
757 test_count = 0
758
Dan Talaycocfa172f2012-03-23 12:03:00 -0700759 if egr_count == -1:
Rich Lane2014f9b2012-10-05 15:29:40 -0700760 egr_count = test_param_get('egr_count', default=2)
Dan Talaycocfa172f2012-03-23 12:03:00 -0700761
Dan Talayco551befa2010-07-15 17:05:32 -0700762 for ing_idx in range(len(of_ports)):
763 ingress_port = of_ports[ing_idx]
Dan Talaycof6e76c02012-03-23 10:56:12 -0700764 egr_ports = get_egr_list(parent, of_ports, egr_count,
765 exclude_list=[ingress_port])
Dan Talaycoc948d0b2012-03-23 12:17:54 -0700766 if ing_port:
Rich Lanee717c6e2013-03-12 10:25:50 -0700767 egr_ports.append(ofp.OFPP_IN_PORT)
Dan Talaycof6e76c02012-03-23 10:56:12 -0700768 if len(egr_ports) == 0:
769 parent.assertTrue(0, "Failed to generate egress port list")
770
771 flow_match_test_port_pair(parent, ingress_port, egr_ports,
Rich Laned0478ff2013-03-11 12:46:58 -0700772 wildcards=wildcards, vlan_vid=vlan_vid,
Dan Talaycof6e76c02012-03-23 10:56:12 -0700773 pkt=pkt, exp_pkt=exp_pkt,
Rich Lanee5779d32012-10-05 17:56:04 -0700774 action_list=action_list)
Dan Talaycof6e76c02012-03-23 10:56:12 -0700775 test_count += 1
776 if (max_test > 0) and (test_count > max_test):
Rich Lane9a003812012-10-04 17:17:59 -0700777 logging.info("Ran " + str(test_count) + " tests; exiting")
Rich Lane89725bb2012-12-03 16:23:27 -0800778 break
779
Ed Swierk38eea082013-01-02 19:46:20 -0800780 if not test_param_get('pktout_actions', default=True):
781 return
Rich Lane89725bb2012-12-03 16:23:27 -0800782
783 ingress_port = of_ports[0]
784 egr_ports = get_egr_list(parent, of_ports, egr_count,
785 exclude_list=[ingress_port])
786 if ing_port:
Rich Lanee717c6e2013-03-12 10:25:50 -0700787 egr_ports.append(ofp.OFPP_IN_PORT)
Rich Lane89725bb2012-12-03 16:23:27 -0800788 flow_match_test_pktout(parent, ingress_port, egr_ports,
Rich Laned0478ff2013-03-11 12:46:58 -0700789 vlan_vid=vlan_vid,
Rich Lane89725bb2012-12-03 16:23:27 -0800790 pkt=pkt, exp_pkt=exp_pkt,
791 action_list=action_list)
Dan Talayco551befa2010-07-15 17:05:32 -0700792
Rich Lane2014f9b2012-10-05 15:29:40 -0700793def test_param_get(key, default=None):
Dan Talayco4b2bee62010-07-20 14:10:05 -0700794 """
795 Return value passed via test-params if present
796
Dan Talayco4b2bee62010-07-20 14:10:05 -0700797 @param key The lookup key
798 @param default Default value to use if not found
799
800 If the pair 'key=val' appeared in the string passed to --test-params
801 on the command line, return val (as interpreted by exec). Otherwise
802 return default value.
Dan Talaycof6e76c02012-03-23 10:56:12 -0700803
804 WARNING: TEST PARAMETERS MUST BE PYTHON IDENTIFIERS;
805 eg egr_count, not egr-count.
Dan Talayco4b2bee62010-07-20 14:10:05 -0700806 """
807 try:
Rich Lanecd97d3d2013-01-07 18:50:06 -0800808 exec oftest.config["test_params"]
Dan Talayco4b2bee62010-07-20 14:10:05 -0700809 except:
810 return default
811
812 s = "val = " + str(key)
813 try:
814 exec s
815 return val
816 except:
817 return default
818
819def action_generate(parent, field_to_mod, mod_field_vals):
820 """
821 Create an action to modify the field indicated in field_to_mod
822
823 @param parent Must implement, assertTrue
824 @param field_to_mod The field to modify as a string name
825 @param mod_field_vals Hash of values to use for modified values
826 """
827
828 act = None
829
830 if field_to_mod in ['pktlen']:
831 return None
832
Rich Laned0478ff2013-03-11 12:46:58 -0700833 if field_to_mod == 'eth_dst':
Rich Lanee717c6e2013-03-12 10:25:50 -0700834 act = ofp.action.set_dl_dst()
Rich Lanef6883512013-03-11 17:00:09 -0700835 act.dl_addr = oftest.parse.parse_mac(mod_field_vals['eth_dst'])
Rich Laned0478ff2013-03-11 12:46:58 -0700836 elif field_to_mod == 'eth_src':
Rich Lanee717c6e2013-03-12 10:25:50 -0700837 act = ofp.action.set_dl_src()
Rich Lanef6883512013-03-11 17:00:09 -0700838 act.dl_addr = oftest.parse.parse_mac(mod_field_vals['eth_src'])
Dan Talayco4b2bee62010-07-20 14:10:05 -0700839 elif field_to_mod == 'dl_vlan_enable':
840 if not mod_field_vals['dl_vlan_enable']: # Strip VLAN tag
Rich Lanee717c6e2013-03-12 10:25:50 -0700841 act = ofp.action.strip_vlan()
Rich Laned0478ff2013-03-11 12:46:58 -0700842 # Add VLAN tag is handled by vlan_vid field
Dan Talayco4b2bee62010-07-20 14:10:05 -0700843 # Will return None in this case
Rich Laned0478ff2013-03-11 12:46:58 -0700844 elif field_to_mod == 'vlan_vid':
Rich Lanee717c6e2013-03-12 10:25:50 -0700845 act = ofp.action.set_vlan_vid()
Rich Laned0478ff2013-03-11 12:46:58 -0700846 act.vlan_vid = mod_field_vals['vlan_vid']
847 elif field_to_mod == 'vlan_pcp':
Rich Lanee717c6e2013-03-12 10:25:50 -0700848 act = ofp.action.set_vlan_pcp()
Rich Laned0478ff2013-03-11 12:46:58 -0700849 act.vlan_pcp = mod_field_vals['vlan_pcp']
Dan Talayco4b2bee62010-07-20 14:10:05 -0700850 elif field_to_mod == 'ip_src':
Rich Lanee717c6e2013-03-12 10:25:50 -0700851 act = ofp.action.set_nw_src()
Rich Lanef6883512013-03-11 17:00:09 -0700852 act.nw_addr = oftest.parse.parse_ip(mod_field_vals['ip_src'])
Dan Talayco4b2bee62010-07-20 14:10:05 -0700853 elif field_to_mod == 'ip_dst':
Rich Lanee717c6e2013-03-12 10:25:50 -0700854 act = ofp.action.set_nw_dst()
Rich Lanef6883512013-03-11 17:00:09 -0700855 act.nw_addr = oftest.parse.parse_ip(mod_field_vals['ip_dst'])
Dan Talayco4b2bee62010-07-20 14:10:05 -0700856 elif field_to_mod == 'ip_tos':
Rich Lanee717c6e2013-03-12 10:25:50 -0700857 act = ofp.action.set_nw_tos()
Dan Talayco4b2bee62010-07-20 14:10:05 -0700858 act.nw_tos = mod_field_vals['ip_tos']
859 elif field_to_mod == 'tcp_sport':
Rich Lanee717c6e2013-03-12 10:25:50 -0700860 act = ofp.action.set_tp_src()
Dan Talayco4b2bee62010-07-20 14:10:05 -0700861 act.tp_port = mod_field_vals['tcp_sport']
862 elif field_to_mod == 'tcp_dport':
Rich Lanee717c6e2013-03-12 10:25:50 -0700863 act = ofp.action.set_tp_dst()
Dan Talayco4b2bee62010-07-20 14:10:05 -0700864 act.tp_port = mod_field_vals['tcp_dport']
Rich Lane110e0e32012-10-26 16:21:46 -0700865 elif field_to_mod == 'udp_sport':
Rich Lanee717c6e2013-03-12 10:25:50 -0700866 act = ofp.action.set_tp_src()
Rich Lane110e0e32012-10-26 16:21:46 -0700867 act.tp_port = mod_field_vals['udp_sport']
868 elif field_to_mod == 'udp_dport':
Rich Lanee717c6e2013-03-12 10:25:50 -0700869 act = ofp.action.set_tp_dst()
Rich Lane110e0e32012-10-26 16:21:46 -0700870 act.tp_port = mod_field_vals['udp_dport']
Dan Talayco4b2bee62010-07-20 14:10:05 -0700871 else:
872 parent.assertTrue(0, "Unknown field to modify: " + str(field_to_mod))
873
874 return act
875
876def pkt_action_setup(parent, start_field_vals={}, mod_field_vals={},
Rich Lane110e0e32012-10-26 16:21:46 -0700877 mod_fields=[], tp="tcp", check_test_params=False):
Dan Talayco4b2bee62010-07-20 14:10:05 -0700878 """
879 Set up the ingress and expected packet and action list for a test
880
Rich Lane2014f9b2012-10-05 15:29:40 -0700881 @param parent Must implement assertTrue
Dan Talayco4b2bee62010-07-20 14:10:05 -0700882 @param start_field_values Field values to use for ingress packet (optional)
883 @param mod_field_values Field values to use for modified packet (optional)
884 @param mod_fields The list of fields to be modified by the switch in the test.
885 @params check_test_params If True, will check the parameters vid, add_vlan
886 and strip_vlan from the command line.
887
888 Returns a triple: pkt-to-send, expected-pkt, action-list
889 """
890
891 new_actions = []
892
Dan Talayco4b2bee62010-07-20 14:10:05 -0700893 base_pkt_params = {}
894 base_pkt_params['pktlen'] = 100
Rich Laned0478ff2013-03-11 12:46:58 -0700895 base_pkt_params['eth_dst'] = '00:DE:F0:12:34:56'
896 base_pkt_params['eth_src'] = '00:23:45:67:89:AB'
Dan Talayco4b2bee62010-07-20 14:10:05 -0700897 base_pkt_params['dl_vlan_enable'] = False
Rich Laned0478ff2013-03-11 12:46:58 -0700898 base_pkt_params['vlan_vid'] = 2
899 base_pkt_params['vlan_pcp'] = 0
Dan Talayco4b2bee62010-07-20 14:10:05 -0700900 base_pkt_params['ip_src'] = '192.168.0.1'
901 base_pkt_params['ip_dst'] = '192.168.0.2'
902 base_pkt_params['ip_tos'] = 0
Rich Lane110e0e32012-10-26 16:21:46 -0700903 if tp == "tcp":
904 base_pkt_params['tcp_sport'] = 1234
905 base_pkt_params['tcp_dport'] = 80
906 elif tp == "udp":
907 base_pkt_params['udp_sport'] = 1234
908 base_pkt_params['udp_dport'] = 80
Dan Talayco4b2bee62010-07-20 14:10:05 -0700909 for keyname in start_field_vals.keys():
910 base_pkt_params[keyname] = start_field_vals[keyname]
911
912 mod_pkt_params = {}
913 mod_pkt_params['pktlen'] = 100
Rich Laned0478ff2013-03-11 12:46:58 -0700914 mod_pkt_params['eth_dst'] = '00:21:0F:ED:CB:A9'
915 mod_pkt_params['eth_src'] = '00:ED:CB:A9:87:65'
Dan Talayco4b2bee62010-07-20 14:10:05 -0700916 mod_pkt_params['dl_vlan_enable'] = False
Rich Laned0478ff2013-03-11 12:46:58 -0700917 mod_pkt_params['vlan_vid'] = 3
918 mod_pkt_params['vlan_pcp'] = 7
Dan Talayco4b2bee62010-07-20 14:10:05 -0700919 mod_pkt_params['ip_src'] = '10.20.30.40'
920 mod_pkt_params['ip_dst'] = '50.60.70.80'
921 mod_pkt_params['ip_tos'] = 0xf0
Rich Lane110e0e32012-10-26 16:21:46 -0700922 if tp == "tcp":
923 mod_pkt_params['tcp_sport'] = 4321
924 mod_pkt_params['tcp_dport'] = 8765
925 elif tp == "udp":
926 mod_pkt_params['udp_sport'] = 4321
927 mod_pkt_params['udp_dport'] = 8765
Dan Talayco4b2bee62010-07-20 14:10:05 -0700928 for keyname in mod_field_vals.keys():
929 mod_pkt_params[keyname] = mod_field_vals[keyname]
930
931 # Check for test param modifications
932 strip = False
933 if check_test_params:
Rich Lane2014f9b2012-10-05 15:29:40 -0700934 add_vlan = test_param_get('add_vlan')
935 strip_vlan = test_param_get('strip_vlan')
936 vid = test_param_get('vid')
Dan Talayco4b2bee62010-07-20 14:10:05 -0700937
938 if add_vlan and strip_vlan:
939 parent.assertTrue(0, "Add and strip VLAN both specified")
940
941 if vid:
942 base_pkt_params['dl_vlan_enable'] = True
Rich Laned0478ff2013-03-11 12:46:58 -0700943 base_pkt_params['vlan_vid'] = vid
944 if 'vlan_vid' in mod_fields:
945 mod_pkt_params['vlan_vid'] = vid + 1
Dan Talayco4b2bee62010-07-20 14:10:05 -0700946
947 if add_vlan:
948 base_pkt_params['dl_vlan_enable'] = False
949 mod_pkt_params['dl_vlan_enable'] = True
950 mod_pkt_params['pktlen'] = base_pkt_params['pktlen'] + 4
951 mod_fields.append('pktlen')
952 mod_fields.append('dl_vlan_enable')
Rich Laned0478ff2013-03-11 12:46:58 -0700953 if 'vlan_vid' not in mod_fields:
954 mod_fields.append('vlan_vid')
Dan Talayco4b2bee62010-07-20 14:10:05 -0700955 elif strip_vlan:
956 base_pkt_params['dl_vlan_enable'] = True
957 mod_pkt_params['dl_vlan_enable'] = False
958 mod_pkt_params['pktlen'] = base_pkt_params['pktlen'] - 4
959 mod_fields.append('dl_vlan_enable')
960 mod_fields.append('pktlen')
961
Rich Lane110e0e32012-10-26 16:21:46 -0700962 if tp == "tcp":
963 packet_builder = simple_tcp_packet
964 elif tp == "udp":
965 packet_builder = simple_udp_packet
966 else:
967 raise NotImplementedError("unknown transport protocol %s" % tp)
968
Dan Talayco4b2bee62010-07-20 14:10:05 -0700969 # Build the ingress packet
Rich Lane110e0e32012-10-26 16:21:46 -0700970 ingress_pkt = packet_builder(**base_pkt_params)
Dan Talayco4b2bee62010-07-20 14:10:05 -0700971
972 # Build the expected packet, modifying the indicated fields
973 for item in mod_fields:
974 base_pkt_params[item] = mod_pkt_params[item]
975 act = action_generate(parent, item, mod_pkt_params)
976 if act:
977 new_actions.append(act)
978
Rich Lane110e0e32012-10-26 16:21:46 -0700979 expected_pkt = packet_builder(**base_pkt_params)
Dan Talayco4b2bee62010-07-20 14:10:05 -0700980
981 return (ingress_pkt, expected_pkt, new_actions)
Dan Talayco677c0b72011-08-23 22:53:38 -0700982
983# Generate a simple "drop" flow mod
984# If in_band is true, then only drop from first test port
985def flow_mod_gen(port_map, in_band):
Rich Lanee717c6e2013-03-12 10:25:50 -0700986 request = ofp.message.flow_add()
987 request.match.wildcards = ofp.OFPFW_ALL
Dan Talayco677c0b72011-08-23 22:53:38 -0700988 if in_band:
Rich Lanee717c6e2013-03-12 10:25:50 -0700989 request.match.wildcards = ofp.OFPFW_ALL - ofp.OFPFW_IN_PORT
Dan Talayco677c0b72011-08-23 22:53:38 -0700990 for of_port, ifname in port_map.items(): # Grab first port
991 break
992 request.match.in_port = of_port
993 request.buffer_id = 0xffffffff
994 return request
Dan Talaycoba3745c2010-07-21 21:51:08 -0700995
996def skip_message_emit(parent, s):
997 """
998 Print out a 'skipped' message to stderr
999
1000 @param s The string to print out to the log file
Dan Talaycoba3745c2010-07-21 21:51:08 -07001001 """
1002 global skipped_test_count
1003
1004 skipped_test_count += 1
Rich Lane9a003812012-10-04 17:17:59 -07001005 logging.info("Skipping: " + s)
Dan Talayco2940fdd2013-02-06 15:01:35 -08001006 if oftest.config["debug"] < logging.WARNING:
Dan Talaycoba3745c2010-07-21 21:51:08 -07001007 sys.stderr.write("(skipped) ")
1008 else:
1009 sys.stderr.write("(S)")
Dan Talayco677c0b72011-08-23 22:53:38 -07001010
Dan Talayco8a64e332012-03-28 14:53:20 -07001011
1012def all_stats_get(parent):
1013 """
1014 Get the aggregate stats for all flows in the table
1015 @param parent Test instance with controller connection and assert
1016 @returns dict with keys flows, packets, bytes, active (flows),
1017 lookups, matched
1018 """
Rich Lanee717c6e2013-03-12 10:25:50 -07001019 stat_req = ofp.message.aggregate_stats_request()
1020 stat_req.match = ofp.match()
1021 stat_req.match.wildcards = ofp.OFPFW_ALL
Dan Talayco8a64e332012-03-28 14:53:20 -07001022 stat_req.table_id = 0xff
Rich Lanee717c6e2013-03-12 10:25:50 -07001023 stat_req.out_port = ofp.OFPP_NONE
Dan Talayco8a64e332012-03-28 14:53:20 -07001024
1025 rv = {}
1026
Rich Lanec8aaa3e2012-07-26 19:28:02 -07001027 (reply, pkt) = parent.controller.transact(stat_req)
Rich Lane5fd6faf2013-03-11 13:30:20 -07001028 parent.assertTrue(len(reply.entries) == 1, "Did not receive flow stats reply")
Dan Talayco8a64e332012-03-28 14:53:20 -07001029
Rich Lane5fd6faf2013-03-11 13:30:20 -07001030 for obj in reply.entries:
Dan Talayco8a64e332012-03-28 14:53:20 -07001031 (rv["flows"], rv["packets"], rv["bytes"]) = (obj.flow_count,
1032 obj.packet_count, obj.byte_count)
1033 break
1034
Rich Lanee717c6e2013-03-12 10:25:50 -07001035 request = ofp.message.table_stats_request()
Rich Lanec8aaa3e2012-07-26 19:28:02 -07001036 (reply , pkt) = parent.controller.transact(request)
Dan Talayco8a64e332012-03-28 14:53:20 -07001037
1038
1039 (rv["active"], rv["lookups"], rv["matched"]) = (0,0,0)
Rich Lane5fd6faf2013-03-11 13:30:20 -07001040 for obj in reply.entries:
Dan Talayco8a64e332012-03-28 14:53:20 -07001041 rv["active"] += obj.active_count
1042 rv["lookups"] += obj.lookup_count
1043 rv["matched"] += obj.matched_count
1044
1045 return rv
Dan Talayco2baf8b52012-03-30 09:55:42 -07001046
Rich Lane7744e112013-01-11 17:23:57 -08001047_import_blacklist.add('FILTER')
Dan Talayco2baf8b52012-03-30 09:55:42 -07001048FILTER=''.join([(len(repr(chr(x)))==3) and chr(x) or '.'
1049 for x in range(256)])
1050
1051def hex_dump_buffer(src, length=16):
1052 """
1053 Convert src to a hex dump string and return the string
1054 @param src The source buffer
1055 @param length The number of bytes shown in each line
1056 @returns A string showing the hex dump
1057 """
Dan Talaycoc516fa02012-04-12 22:28:43 -07001058 result = ["\n"]
Dan Talayco2baf8b52012-03-30 09:55:42 -07001059 for i in xrange(0, len(src), length):
1060 chars = src[i:i+length]
1061 hex = ' '.join(["%02x" % ord(x) for x in chars])
1062 printable = ''.join(["%s" % ((ord(x) <= 127 and
1063 FILTER[ord(x)]) or '.') for x in chars])
1064 result.append("%04x %-*s %s\n" % (i, length*3, hex, printable))
1065 return ''.join(result)
1066
1067def format_packet(pkt):
1068 return "Packet length %d \n%s" % (len(str(pkt)),
1069 hex_dump_buffer(str(pkt)))
Rich Lane5d7e89a2012-10-26 16:43:13 -07001070
1071def inspect_packet(pkt):
1072 """
1073 Wrapper around scapy's show() method.
1074 @returns A string showing the dissected packet.
1075 """
1076 from cStringIO import StringIO
1077 out = None
1078 backup = sys.stdout
1079 try:
1080 sys.stdout = StringIO()
1081 pkt.show2()
1082 out = sys.stdout.getvalue()
1083 sys.stdout.close()
1084 finally:
1085 sys.stdout = backup
1086 return out
Rich Lane0a4f6372013-01-02 14:40:22 -08001087
1088def nonstandard(cls):
1089 """
Rich Lanecc45b8e2013-01-02 15:55:02 -08001090 Testcase decorator that marks the test as being non-standard.
1091 These tests are not automatically added to the "standard" group.
Rich Lane0a4f6372013-01-02 14:40:22 -08001092 """
Rich Lanecc45b8e2013-01-02 15:55:02 -08001093 cls._nonstandard = True
Rich Lane0a4f6372013-01-02 14:40:22 -08001094 return cls
1095
1096def disabled(cls):
1097 """
Rich Lanecc45b8e2013-01-02 15:55:02 -08001098 Testcase decorator that marks the test as being disabled.
1099 These tests are not automatically added to the "standard" group or
1100 their module's group.
Rich Lane0a4f6372013-01-02 14:40:22 -08001101 """
Rich Lanecc45b8e2013-01-02 15:55:02 -08001102 cls._disabled = True
Rich Lane0a4f6372013-01-02 14:40:22 -08001103 return cls
Rich Lane97e99652013-01-02 17:23:20 -08001104
1105def group(name):
1106 """
1107 Testcase decorator that adds the test to a group.
1108 """
1109 def fn(cls):
1110 if not hasattr(cls, "_groups"):
1111 cls._groups = []
1112 cls._groups.append(name)
1113 return cls
1114 return fn
Rich Lane5a9a1922013-01-11 14:29:30 -08001115
1116def version(ver):
1117 """
1118 Testcase decorator that specifies which versions of OpenFlow the test
1119 supports. The default is 1.0+. This decorator may only be used once.
1120
1121 Supported syntax:
1122 1.0 -> 1.0
1123 1.0,1.2,1.3 -> 1.0, 1.2, 1.3
1124 1.0+ -> 1.0, 1.1, 1.2, 1.3
1125 """
1126 versions = parse_version(ver)
1127 def fn(cls):
1128 cls._versions = versions
1129 return cls
1130 return fn
1131
1132def parse_version(ver):
1133 allowed_versions = ["1.0", "1.1", "1.2", "1.3"]
1134 if re.match("^1\.\d+$", ver):
1135 versions = set([ver])
1136 elif re.match("^(1\.\d+)\+$", ver):
1137 if not ver[:-1] in allowed_versions:
1138 raise ValueError("invalid OpenFlow version %s" % ver[:-1])
1139 versions = set()
1140 if ver != "1.1+": versions.add("1.0")
1141 if ver != "1.2+": versions.add("1.1")
1142 if ver != "1.3+": versions.add("1.2")
1143 versions.add("1.3")
1144 else:
1145 versions = set(ver.split(','))
1146
1147 for version in versions:
1148 if not version in allowed_versions:
1149 raise ValueError("invalid OpenFlow version %s" % version)
1150
1151 return versions
1152
1153assert(parse_version("1.0") == set(["1.0"]))
1154assert(parse_version("1.0,1.2,1.3") == set(["1.0", "1.2", "1.3"]))
1155assert(parse_version("1.0+") == set(["1.0", "1.1", "1.2", "1.3"]))
Rich Lane7744e112013-01-11 17:23:57 -08001156
Rich Laneae3428c2013-03-07 14:37:42 -08001157def get_stats(test, req):
1158 """
1159 Retrieve a list of stats entries. Handles OFPSF_REPLY_MORE.
1160 """
1161 stats = []
1162 reply, _ = test.controller.transact(req)
1163 test.assertTrue(reply is not None, "No response to stats request")
Rich Lane5fd6faf2013-03-11 13:30:20 -07001164 stats.extend(reply.entries)
Rich Lanee717c6e2013-03-12 10:25:50 -07001165 while reply.flags & ofp.OFPSF_REPLY_MORE != 0:
1166 reply, pkt = self.controller.poll(exp_msg=ofp.OFPT_STATS_REPLY)
Rich Laneae3428c2013-03-07 14:37:42 -08001167 test.assertTrue(reply is not None, "No response to stats request")
Rich Lane5fd6faf2013-03-11 13:30:20 -07001168 stats.extend(reply.entries)
Rich Laneae3428c2013-03-07 14:37:42 -08001169 return stats
1170
Rich Lanef3bc48c2013-05-03 17:39:35 -07001171def get_flow_stats(test, match, table_id=0xff, out_port=None):
Rich Laneae3428c2013-03-07 14:37:42 -08001172 """
1173 Retrieve a list of flow stats entries.
1174 """
Rich Lanef3bc48c2013-05-03 17:39:35 -07001175 if out_port == None:
1176 out_port = ofp.OFPP_NONE
Rich Lanee717c6e2013-03-12 10:25:50 -07001177 req = ofp.message.flow_stats_request(match=match,
Rich Laneae3428c2013-03-07 14:37:42 -08001178 table_id=table_id,
1179 out_port=out_port)
1180 return get_stats(test, req)
1181
Rich Lane968b6192013-03-07 15:34:43 -08001182def get_port_stats(test, port_no):
1183 """
1184 Retrieve a list of port stats entries.
1185 """
Rich Lanee717c6e2013-03-12 10:25:50 -07001186 req = ofp.message.port_stats_request(port_no=port_no)
Rich Lane968b6192013-03-07 15:34:43 -08001187 return get_stats(test, req)
1188
Rich Lane6a334922013-03-07 16:14:52 -08001189def get_queue_stats(test, port_no, queue_id):
1190 """
1191 Retrieve a list of queue stats entries.
1192 """
Rich Lanee717c6e2013-03-12 10:25:50 -07001193 req = ofp.message.queue_stats_request(port_no=port_no, queue_id=queue_id)
Rich Lane6a334922013-03-07 16:14:52 -08001194 return get_stats(test, req)
1195
Rich Laneae3428c2013-03-07 14:37:42 -08001196def verify_flow_stats(test, match, table_id=0xff,
Rich Lanef3bc48c2013-05-03 17:39:35 -07001197 out_port=None,
Rich Laneae3428c2013-03-07 14:37:42 -08001198 initial=[],
1199 pkts=None, bytes=None):
1200 """
1201 Verify that flow stats changed as expected.
1202
1203 Optionally takes an 'initial' list of stats entries, as returned by
1204 get_flow_stats(). If 'initial' is not given the counters are assumed to
1205 begin at 0.
1206 """
Rich Lanef3bc48c2013-05-03 17:39:35 -07001207 if out_port == None:
1208 out_port = ofp.OFPP_NONE
1209
Rich Laneae3428c2013-03-07 14:37:42 -08001210 def accumulate(stats):
1211 pkts_acc = bytes_acc = 0
1212 for stat in stats:
1213 pkts_acc += stat.packet_count
1214 bytes_acc += stat.byte_count
1215 return (pkts_acc, bytes_acc)
1216
1217 pkts_before, bytes_before = accumulate(initial)
1218
1219 # Wait 10s for counters to update
1220 pkt_diff = byte_diff = None
1221 for i in range(0, 100):
1222 stats = get_flow_stats(test, match, table_id=table_id, out_port=out_port)
1223 pkts_after, bytes_after = accumulate(stats)
1224 pkt_diff = pkts_after - pkts_before
1225 byte_diff = bytes_after - bytes_before
1226 if (pkts == None or pkt_diff >= pkts) and \
1227 (bytes == None or byte_diff >= bytes):
1228 break
Dan Talayco53724732013-03-08 23:54:02 -08001229 time.sleep(0.1)
Rich Laneae3428c2013-03-07 14:37:42 -08001230
1231 if pkts != None:
1232 test.assertEquals(pkt_diff, pkts, "Flow packet counter not updated properly (expected increase of %d, got increase of %d)" % (pkts, pkt_diff))
1233
1234 if bytes != None:
Rich Lane53b96812013-03-07 16:54:50 -08001235 test.assertTrue(byte_diff >= bytes and byte_diff <= bytes*1.1,
1236 "Flow byte counter not updated properly (expected increase of %d, got increase of %d)" % (bytes, byte_diff))
Rich Laneae3428c2013-03-07 14:37:42 -08001237
Rich Lane968b6192013-03-07 15:34:43 -08001238def verify_port_stats(test, port,
1239 initial=[],
1240 tx_pkts=None, rx_pkts=None,
1241 tx_bytes=None, rx_bytes=None):
1242 """
1243 Verify that port stats changed as expected.
1244
1245 Optionally takes an 'initial' list of stats entries, as returned by
1246 get_port_stats(). If 'initial' is not given the counters are assumed to
1247 begin at 0.
1248 """
1249 def accumulate(stats):
1250 tx_pkts_acc = rx_pkts_acc = tx_bytes_acc = rx_bytes_acc = 0
1251 for stat in stats:
1252 tx_pkts_acc += stat.tx_packets
1253 rx_pkts_acc += stat.rx_packets
1254 tx_bytes_acc += stat.tx_bytes
1255 rx_bytes_acc += stat.rx_bytes
1256 return (tx_pkts_acc, rx_pkts_acc, tx_bytes_acc, rx_bytes_acc)
1257
1258 tx_pkts_before, rx_pkts_before, \
1259 tx_bytes_before, rx_bytes_before = accumulate(initial)
1260
1261 # Wait 10s for counters to update
1262 for i in range(0, 100):
1263 stats = get_port_stats(test, port)
1264 tx_pkts_after, rx_pkts_after, \
1265 tx_bytes_after, rx_bytes_after = accumulate(stats)
1266 tx_pkts_diff = tx_pkts_after - tx_pkts_before
1267 rx_pkts_diff = rx_pkts_after - rx_pkts_before
1268 tx_bytes_diff = tx_bytes_after - tx_bytes_before
1269 rx_bytes_diff = rx_bytes_after - rx_bytes_before
1270 if (tx_pkts == None or tx_pkts == tx_pkts_diff) and \
1271 (rx_pkts == None or rx_pkts == rx_pkts_diff) and \
Rich Lane53b96812013-03-07 16:54:50 -08001272 (tx_bytes == None or tx_bytes <= tx_bytes_diff) and \
1273 (rx_bytes == None or rx_bytes <= rx_bytes_diff):
Rich Lane968b6192013-03-07 15:34:43 -08001274 break
1275 time.sleep(0.1)
1276
1277 if (tx_pkts != None):
1278 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))
1279 if (rx_pkts != None):
1280 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))
1281 if (tx_bytes != None):
Rich Lane53b96812013-03-07 16:54:50 -08001282 test.assertTrue(tx_bytes_diff >= tx_bytes and tx_bytes_diff <= tx_bytes*1.1,
1283 "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 -08001284 if (rx_bytes != None):
Rich Lane53b96812013-03-07 16:54:50 -08001285 test.assertTrue(rx_bytes_diff >= rx_bytes and rx_bytes_diff <= rx_bytes*1.1,
1286 "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 -08001287
Rich Lane6a334922013-03-07 16:14:52 -08001288def verify_queue_stats(test, port_no, queue_id,
1289 initial=[],
1290 pkts=None, bytes=None):
1291 """
1292 Verify that queue stats changed as expected.
1293
1294 Optionally takes an 'initial' list of stats entries, as returned by
1295 get_queue_stats(). If 'initial' is not given the counters are assumed to
1296 begin at 0.
1297 """
1298 def accumulate(stats):
1299 pkts_acc = bytes_acc = 0
1300 for stat in stats:
1301 pkts_acc += stat.tx_packets
1302 bytes_acc += stat.tx_bytes
1303 return (pkts_acc, bytes_acc)
1304
1305 pkts_before, bytes_before = accumulate(initial)
1306
1307 # Wait 10s for counters to update
1308 pkt_diff = byte_diff = None
1309 for i in range(0, 100):
1310 stats = get_queue_stats(test, port_no, queue_id)
1311 pkts_after, bytes_after = accumulate(stats)
1312 pkt_diff = pkts_after - pkts_before
1313 byte_diff = bytes_after - bytes_before
1314 if (pkts == None or pkt_diff >= pkts) and \
1315 (bytes == None or byte_diff >= bytes):
1316 break
Dan Talayco53724732013-03-08 23:54:02 -08001317 time.sleep(0.1)
Rich Lane6a334922013-03-07 16:14:52 -08001318
1319 if pkts != None:
1320 test.assertEquals(pkt_diff, pkts, "Queue packet counter not updated properly (expected increase of %d, got increase of %d)" % (pkts, pkt_diff))
1321
1322 if bytes != None:
Rich Lane53b96812013-03-07 16:54:50 -08001323 test.assertTrue(byte_diff >= bytes and byte_diff <= bytes*1.1,
1324 "Queue byte counter not updated properly (expected increase of %d, got increase of %d)" % (bytes, byte_diff))
Rich Laneae3428c2013-03-07 14:37:42 -08001325
Rich Lane4c504f32013-06-07 17:24:14 -07001326def packet_in_match(msg, data, in_port=None, reason=None):
1327 """
1328 Check whether the packet_in message 'msg' has fields matching 'data',
1329 'in_port', and 'reason'.
1330
1331 This function handles truncated packet_in data. The 'in_port' and 'reason'
1332 parameters are optional.
1333
1334 @param msg packet_in message
1335 @param data Expected packet_in data
1336 @param in_port Expected packet_in in_port, or None
1337 @param reason Expected packet_in reason, or None
1338 """
1339
1340 if in_port and in_port != msg.in_port:
1341 logging.debug("Incorrect packet_in in_port (expected %d, received %d)", in_port, msg.in_port)
1342 return False
1343
1344 if reason and reason != msg.reason:
1345 logging.debug("Incorrect packet_in reason (expected %d, received %d)", reason, msg.reason)
1346 return False
1347
1348 # Check that one of the packets is a prefix of the other.
1349 # The received packet may be either truncated or padded, but not both.
1350 # (Some of the padding may be truncated but that's irrelevant). We
1351 # need to check that the smaller packet is a prefix of the larger one.
1352 # Note that this check succeeds if the switch sends a zero-length
1353 # packet-in.
1354 compare_len = min(len(msg.data), len(data))
1355 if data[:compare_len] != msg.data[:compare_len]:
1356 logging.debug("Incorrect packet_in data")
1357 logging.debug("Expected %s" % format_packet(data[:compare_len]))
1358 logging.debug("Received %s" % format_packet(msg.data[:compare_len]))
1359 return False
1360
1361 return True
1362
1363def verify_packet_in(test, data, in_port, reason, controller=None):
1364 """
1365 Assert that the controller receives a packet_in message matching data 'data'
1366 from port 'in_port' with reason 'reason'. Does not trigger the packet_in
1367 itself, that's up to the test case.
1368
1369 @param test Instance of base_tests.SimpleProtocol
1370 @param pkt String to expect as the packet_in data
1371 @param in_port OpenFlow port number to expect as the packet_in in_port
1372 @param reason One of OFPR_* to expect as the packet_in reason
1373 @param controller Controller instance, defaults to test.controller
1374 @returns The received packet-in message
1375 """
1376
1377 if controller == None:
1378 controller = test.controller
1379
1380 end_time = time.time() + oftest.ofutils.default_timeout
1381
1382 while True:
1383 msg, _ = controller.poll(ofp.OFPT_PACKET_IN, end_time - time.time())
1384 if not msg:
1385 # Timeout
1386 break
1387 elif packet_in_match(msg, data, in_port, reason):
1388 # Found a matching message
1389 break
1390
1391 test.assertTrue(msg is not None, 'Packet in message not received on port %d' % in_port)
1392 return msg
1393
1394def verify_no_packet_in(test, data, in_port, controller=None):
1395 """
1396 Assert that the controller does not receive a packet_in message matching
1397 data 'data' from port 'in_port'.
1398
1399 @param test Instance of base_tests.SimpleProtocol
1400 @param pkt String to expect as the packet_in data
1401 @param in_port OpenFlow port number to expect as the packet_in in_port
1402 @param controller Controller instance, defaults to test.controller
1403 """
1404
1405 if controller == None:
1406 controller = test.controller
1407
1408 # Negative test, need to wait a short amount of time before checking we
1409 # didn't receive the message.
1410 time.sleep(0.5)
1411
1412 # Check every packet_in queued in the controller
1413 while True:
1414 msg, _ = controller.poll(ofp.OFPT_PACKET_IN, timeout=0)
1415 if msg == None:
1416 # No more queued packet_in messages
1417 break
1418 elif packet_in_match(msg, data, in_port, None):
1419 # Found a matching message
1420 break
1421
1422 test.assertTrue(msg == None, "Did not expect a packet-in message on port %d" % in_port)
1423
Rich Lane7744e112013-01-11 17:23:57 -08001424__all__ = list(set(locals()) - _import_blacklist)