blob: 5c3f6f3fcf6fb1b292668fc276e6b7e83ed27c77 [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 Lanee717c6e2013-03-12 10:25:50 -070020import ofp
Dan Talaycoc901f4d2010-03-07 21:55:45 -080021
Dan Talaycoba3745c2010-07-21 21:51:08 -070022global skipped_test_count
23skipped_test_count = 0
24
Rich Lane7744e112013-01-11 17:23:57 -080025_import_blacklist = set(locals().keys())
26
Dan Talayco551befa2010-07-15 17:05:32 -070027# Some useful defines
28IP_ETHERTYPE = 0x800
29TCP_PROTOCOL = 0x6
30UDP_PROTOCOL = 0x11
31
Jeffrey Townsend5cb7ed32012-08-17 18:11:01 +000032MINSIZE = 0
33
Rich Lane9a003812012-10-04 17:17:59 -070034def delete_all_flows(ctrl):
Dan Talayco41eae8b2010-03-10 13:57:06 -080035 """
36 Delete all flows on the switch
37 @param ctrl The controller object for the test
Dan Talayco41eae8b2010-03-10 13:57:06 -080038 """
39
Rich Lane9a003812012-10-04 17:17:59 -070040 logging.info("Deleting all flows")
Rich Lanee717c6e2013-03-12 10:25:50 -070041 msg = ofp.message.flow_delete()
42 msg.match.wildcards = ofp.OFPFW_ALL
43 msg.out_port = ofp.OFPP_NONE
Dan Talaycoc901f4d2010-03-07 21:55:45 -080044 msg.buffer_id = 0xffffffff
Rich Lane5c3151c2013-01-03 17:15:41 -080045 ctrl.message_send(msg)
Rich Lane32bf9482013-01-03 17:26:30 -080046 return 0 # for backwards compatibility
Dan Talayco41eae8b2010-03-10 13:57:06 -080047
Ed Swierk99a74de2012-08-22 06:40:54 -070048def required_wildcards(parent):
Rich Lane2014f9b2012-10-05 15:29:40 -070049 w = test_param_get('required_wildcards', default='default')
Ed Swierk99a74de2012-08-22 06:40:54 -070050 if w == 'l3-l4':
Rich Lanee717c6e2013-03-12 10:25:50 -070051 return (ofp.OFPFW_NW_SRC_ALL | ofp.OFPFW_NW_DST_ALL | ofp.OFPFW_NW_TOS
52 | ofp.OFPFW_NW_PROTO | ofp.OFPFW_TP_SRC | ofp.OFPFW_TP_DST)
Ed Swierk99a74de2012-08-22 06:40:54 -070053 else:
54 return 0
55
Dan Talayco41eae8b2010-03-10 13:57:06 -080056def simple_tcp_packet(pktlen=100,
Rich Laned0478ff2013-03-11 12:46:58 -070057 eth_dst='00:01:02:03:04:05',
58 eth_src='00:06:07:08:09:0a',
Tatsuya Yabe460321e2010-05-25 17:50:49 -070059 dl_vlan_enable=False,
Rich Laned0478ff2013-03-11 12:46:58 -070060 vlan_vid=0,
61 vlan_pcp=0,
Dan Talayco551befa2010-07-15 17:05:32 -070062 dl_vlan_cfi=0,
Dan Talayco41eae8b2010-03-10 13:57:06 -080063 ip_src='192.168.0.1',
64 ip_dst='192.168.0.2',
Tatsuya Yabe460321e2010-05-25 17:50:49 -070065 ip_tos=0,
Gregor Maier9cc93342013-01-29 16:55:28 -080066 ip_ttl=64,
Dan Talayco41eae8b2010-03-10 13:57:06 -080067 tcp_sport=1234,
Christian Dickmann8b59b4b2012-09-23 16:48:30 -070068 tcp_dport=80,
69 ip_ihl=None,
70 ip_options=False
Dan Talayco41eae8b2010-03-10 13:57:06 -080071 ):
72 """
73 Return a simple dataplane TCP packet
74
75 Supports a few parameters:
76 @param len Length of packet in bytes w/o CRC
Rich Laned0478ff2013-03-11 12:46:58 -070077 @param eth_dst Destinatino MAC
78 @param eth_src Source MAC
Tatsuya Yabe460321e2010-05-25 17:50:49 -070079 @param dl_vlan_enable True if the packet is with vlan, False otherwise
Rich Laned0478ff2013-03-11 12:46:58 -070080 @param vlan_vid VLAN ID
81 @param vlan_pcp VLAN priority
Dan Talayco41eae8b2010-03-10 13:57:06 -080082 @param ip_src IP source
83 @param ip_dst IP destination
Tatsuya Yabe460321e2010-05-25 17:50:49 -070084 @param ip_tos IP ToS
Gregor Maier9cc93342013-01-29 16:55:28 -080085 @param ip_ttl IP TTL
Dan Talayco41eae8b2010-03-10 13:57:06 -080086 @param tcp_dport TCP destination port
87 @param ip_sport TCP source port
88
89 Generates a simple TCP request. Users
90 shouldn't assume anything about this packet other than that
91 it is a valid ethernet/IP/TCP frame.
92 """
Jeffrey Townsend5cb7ed32012-08-17 18:11:01 +000093
94 if MINSIZE > pktlen:
95 pktlen = MINSIZE
96
Dan Talayco551befa2010-07-15 17:05:32 -070097 # Note Dot1Q.id is really CFI
Shudong Zhou43ee54c2012-12-13 15:52:37 -080098 if (dl_vlan_enable):
Rich Laned0478ff2013-03-11 12:46:58 -070099 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
100 scapy.Dot1Q(prio=vlan_pcp, id=dl_vlan_cfi, vlan=vlan_vid)/ \
Gregor Maier9cc93342013-01-29 16:55:28 -0800101 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ttl=ip_ttl, ihl=ip_ihl)/ \
Tatsuya Yabe460321e2010-05-25 17:50:49 -0700102 scapy.TCP(sport=tcp_sport, dport=tcp_dport)
103 else:
Christian Dickmann8b59b4b2012-09-23 16:48:30 -0700104 if not ip_options:
Rich Laned0478ff2013-03-11 12:46:58 -0700105 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
Gregor Maier9cc93342013-01-29 16:55:28 -0800106 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ttl=ip_ttl, ihl=ip_ihl)/ \
Christian Dickmann8b59b4b2012-09-23 16:48:30 -0700107 scapy.TCP(sport=tcp_sport, dport=tcp_dport)
108 else:
Rich Laned0478ff2013-03-11 12:46:58 -0700109 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
Gregor Maier9cc93342013-01-29 16:55:28 -0800110 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 -0700111 scapy.TCP(sport=tcp_sport, dport=tcp_dport)
Tatsuya Yabe460321e2010-05-25 17:50:49 -0700112
Dan Talayco41eae8b2010-03-10 13:57:06 -0800113 pkt = pkt/("D" * (pktlen - len(pkt)))
114
115 return pkt
116
Rich Lane6ee7bea2012-10-26 16:19:29 -0700117def simple_udp_packet(pktlen=100,
Rich Laned0478ff2013-03-11 12:46:58 -0700118 eth_dst='00:01:02:03:04:05',
119 eth_src='00:06:07:08:09:0a',
Rich Lane6ee7bea2012-10-26 16:19:29 -0700120 dl_vlan_enable=False,
Rich Laned0478ff2013-03-11 12:46:58 -0700121 vlan_vid=0,
122 vlan_pcp=0,
Rich Lane6ee7bea2012-10-26 16:19:29 -0700123 dl_vlan_cfi=0,
124 ip_src='192.168.0.1',
125 ip_dst='192.168.0.2',
126 ip_tos=0,
Gregor Maier9cc93342013-01-29 16:55:28 -0800127 ip_ttl=64,
Rich Lane6ee7bea2012-10-26 16:19:29 -0700128 udp_sport=1234,
129 udp_dport=80,
130 ip_ihl=None,
131 ip_options=False
132 ):
133 """
134 Return a simple dataplane UDP packet
135
136 Supports a few parameters:
137 @param len Length of packet in bytes w/o CRC
Rich Laned0478ff2013-03-11 12:46:58 -0700138 @param eth_dst Destination MAC
139 @param eth_src Source MAC
Rich Lane6ee7bea2012-10-26 16:19:29 -0700140 @param dl_vlan_enable True if the packet is with vlan, False otherwise
Rich Laned0478ff2013-03-11 12:46:58 -0700141 @param vlan_vid VLAN ID
142 @param vlan_pcp VLAN priority
Rich Lane6ee7bea2012-10-26 16:19:29 -0700143 @param ip_src IP source
144 @param ip_dst IP destination
145 @param ip_tos IP ToS
Gregor Maier9cc93342013-01-29 16:55:28 -0800146 @param ip_ttl IP TTL
Rich Lane6ee7bea2012-10-26 16:19:29 -0700147 @param udp_dport UDP destination port
148 @param udp_sport UDP source port
149
150 Generates a simple UDP packet. Users shouldn't assume anything about
151 this packet other than that it is a valid ethernet/IP/UDP frame.
152 """
153
154 if MINSIZE > pktlen:
155 pktlen = MINSIZE
156
157 # Note Dot1Q.id is really CFI
158 if (dl_vlan_enable):
Rich Laned0478ff2013-03-11 12:46:58 -0700159 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
160 scapy.Dot1Q(prio=vlan_pcp, id=dl_vlan_cfi, vlan=vlan_vid)/ \
Gregor Maier9cc93342013-01-29 16:55:28 -0800161 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ttl=ip_ttl, ihl=ip_ihl)/ \
Rich Lane6ee7bea2012-10-26 16:19:29 -0700162 scapy.UDP(sport=udp_sport, dport=udp_dport)
163 else:
164 if not ip_options:
Rich Laned0478ff2013-03-11 12:46:58 -0700165 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
Gregor Maier9cc93342013-01-29 16:55:28 -0800166 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ttl=ip_ttl, ihl=ip_ihl)/ \
Rich Lane6ee7bea2012-10-26 16:19:29 -0700167 scapy.UDP(sport=udp_sport, dport=udp_dport)
168 else:
Rich Laned0478ff2013-03-11 12:46:58 -0700169 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
Gregor Maier9cc93342013-01-29 16:55:28 -0800170 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 -0700171 scapy.UDP(sport=udp_sport, dport=udp_dport)
172
173 pkt = pkt/("D" * (pktlen - len(pkt)))
174
175 return pkt
176
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700177def simple_icmp_packet(pktlen=60,
Rich Laned0478ff2013-03-11 12:46:58 -0700178 eth_dst='00:01:02:03:04:05',
179 eth_src='00:06:07:08:09:0a',
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700180 dl_vlan_enable=False,
Rich Laned0478ff2013-03-11 12:46:58 -0700181 vlan_vid=0,
182 vlan_pcp=0,
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700183 ip_src='192.168.0.1',
184 ip_dst='192.168.0.2',
185 ip_tos=0,
Gregor Maier9cc93342013-01-29 16:55:28 -0800186 ip_ttl=64,
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700187 icmp_type=8,
188 icmp_code=0
189 ):
190 """
191 Return a simple ICMP packet
192
193 Supports a few parameters:
194 @param len Length of packet in bytes w/o CRC
Rich Laned0478ff2013-03-11 12:46:58 -0700195 @param eth_dst Destinatino MAC
196 @param eth_src Source MAC
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700197 @param dl_vlan_enable True if the packet is with vlan, False otherwise
Rich Laned0478ff2013-03-11 12:46:58 -0700198 @param vlan_vid VLAN ID
199 @param vlan_pcp VLAN priority
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700200 @param ip_src IP source
201 @param ip_dst IP destination
202 @param ip_tos IP ToS
Gregor Maier9cc93342013-01-29 16:55:28 -0800203 @param ip_ttl IP TTL
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700204 @param icmp_type ICMP type
205 @param icmp_code ICMP code
206
207 Generates a simple ICMP ECHO REQUEST. Users
208 shouldn't assume anything about this packet other than that
209 it is a valid ethernet/ICMP frame.
210 """
Jeffrey Townsend5cb7ed32012-08-17 18:11:01 +0000211
212 if MINSIZE > pktlen:
213 pktlen = MINSIZE
214
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700215 if (dl_vlan_enable):
Rich Laned0478ff2013-03-11 12:46:58 -0700216 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
217 scapy.Dot1Q(prio=vlan_pcp, id=0, vlan=vlan_vid)/ \
Gregor Maier9cc93342013-01-29 16:55:28 -0800218 scapy.IP(src=ip_src, dst=ip_dst, ttl=ip_ttl, tos=ip_tos)/ \
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700219 scapy.ICMP(type=icmp_type, code=icmp_code)
220 else:
Rich Laned0478ff2013-03-11 12:46:58 -0700221 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
Gregor Maier9cc93342013-01-29 16:55:28 -0800222 scapy.IP(src=ip_src, dst=ip_dst, ttl=ip_ttl, tos=ip_tos)/ \
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700223 scapy.ICMP(type=icmp_type, code=icmp_code)
224
225 pkt = pkt/("0" * (pktlen - len(pkt)))
226
227 return pkt
228
Shudong Zhouc7562b12013-02-06 01:12:18 -0800229def simple_arp_packet(pktlen=60,
Rich Laned0478ff2013-03-11 12:46:58 -0700230 eth_dst='ff:ff:ff:ff:ff:ff',
231 eth_src='00:06:07:08:09:0a',
Shudong Zhouc7562b12013-02-06 01:12:18 -0800232 arp_op=1,
233 ip_snd='192.168.0.1',
234 ip_tgt='192.168.0.2',
235 hw_snd='00:06:07:08:09:0a',
236 hw_tgt='00:00:00:00:00:00',
237 ):
238 """
239 Return a simple ARP packet
240
241 Supports a few parameters:
242 @param len Length of packet in bytes w/o CRC
Rich Laned0478ff2013-03-11 12:46:58 -0700243 @param eth_dst Destinatino MAC
244 @param eth_src Source MAC
Shudong Zhouc7562b12013-02-06 01:12:18 -0800245 @param arp_op Operation (1=request, 2=reply)
246 @param ip_snd Sender IP
247 @param ip_tgt Target IP
248 @param hw_snd Sender hardware address
249 @param hw_tgt Target hardware address
250
251 Generates a simple ARP REQUEST. Users
252 shouldn't assume anything about this packet other than that
253 it is a valid ethernet/ARP frame.
254 """
255
256 if MINSIZE > pktlen:
257 pktlen = MINSIZE
258
Rich Laned0478ff2013-03-11 12:46:58 -0700259 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
Shudong Zhouc7562b12013-02-06 01:12:18 -0800260 scapy.ARP(hwsrc=hw_snd, hwdst=hw_tgt, pdst=ip_tgt, psrc=ip_snd, op=arp_op)
261
262 pkt = pkt/("0" * (pktlen - len(pkt)))
263
264 return pkt
265
Ed Swierk0aeff8c2012-03-23 20:27:18 -0700266def simple_eth_packet(pktlen=60,
Rich Laned0478ff2013-03-11 12:46:58 -0700267 eth_dst='00:01:02:03:04:05',
268 eth_src='01:80:c2:00:00:00',
269 eth_type=0x88cc):
Jeffrey Townsend5cb7ed32012-08-17 18:11:01 +0000270
271 if MINSIZE > pktlen:
272 pktlen = MINSIZE
273
Rich Laned0478ff2013-03-11 12:46:58 -0700274 pkt = scapy.Ether(dst=eth_dst, src=eth_src, type=eth_type)
Ed Swierk0aeff8c2012-03-23 20:27:18 -0700275
276 pkt = pkt/("0" * (pktlen - len(pkt)))
277
278 return pkt
279
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800280def qinq_tcp_packet(pktlen=100,
Rich Laned0478ff2013-03-11 12:46:58 -0700281 eth_dst='00:01:02:03:04:05',
282 eth_src='00:06:07:08:09:0a',
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800283 dl_vlan_outer=20,
284 dl_vlan_pcp_outer=0,
285 dl_vlan_cfi_outer=0,
Rich Laned0478ff2013-03-11 12:46:58 -0700286 vlan_vid=10,
287 vlan_pcp=0,
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800288 dl_vlan_cfi=0,
289 ip_src='192.168.0.1',
290 ip_dst='192.168.0.2',
291 ip_tos=0,
Gregor Maier9cc93342013-01-29 16:55:28 -0800292 ip_ttl=64,
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800293 tcp_sport=1234,
294 tcp_dport=80,
295 ip_ihl=None,
296 ip_options=False
297 ):
298 """
299 Return a doubly tagged dataplane TCP packet
300
301 Supports a few parameters:
302 @param len Length of packet in bytes w/o CRC
Rich Laned0478ff2013-03-11 12:46:58 -0700303 @param eth_dst Destinatino MAC
304 @param eth_src Source MAC
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800305 @param dl_vlan_outer Outer VLAN ID
306 @param dl_vlan_pcp_outer Outer VLAN priority
307 @param dl_vlan_cfi_outer Outer VLAN cfi bit
Rich Laned0478ff2013-03-11 12:46:58 -0700308 @param vlan_vid Inner VLAN ID
309 @param vlan_pcp VLAN priority
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800310 @param dl_vlan_cfi VLAN cfi bit
311 @param ip_src IP source
312 @param ip_dst IP destination
313 @param ip_tos IP ToS
314 @param tcp_dport TCP destination port
315 @param ip_sport TCP source port
316
317 Generates a TCP request. Users
318 shouldn't assume anything about this packet other than that
319 it is a valid ethernet/IP/TCP frame.
320 """
321
322 if MINSIZE > pktlen:
323 pktlen = MINSIZE
324
325 # Note Dot1Q.id is really CFI
Rich Laned0478ff2013-03-11 12:46:58 -0700326 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800327 scapy.Dot1Q(prio=dl_vlan_pcp_outer, id=dl_vlan_cfi_outer, vlan=dl_vlan_outer)/ \
Rich Laned0478ff2013-03-11 12:46:58 -0700328 scapy.Dot1Q(prio=vlan_pcp, id=dl_vlan_cfi, vlan=vlan_vid)/ \
Gregor Maier9cc93342013-01-29 16:55:28 -0800329 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ttl=ip_ttl, ihl=ip_ihl)/ \
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800330 scapy.TCP(sport=tcp_sport, dport=tcp_dport)
331
332 pkt = pkt/("D" * (pktlen - len(pkt)))
333
334 return pkt
335
Shudong Zhoub7f12462012-11-20 13:01:12 -0800336def do_barrier(ctrl, timeout=-1):
Dan Talayco0fc08bd2012-04-09 16:56:18 -0700337 """
338 Do a barrier command
339 Return 0 on success, -1 on error
340 """
Rich Lanee717c6e2013-03-12 10:25:50 -0700341 b = ofp.message.barrier_request()
Shudong Zhoub7f12462012-11-20 13:01:12 -0800342 (resp, pkt) = ctrl.transact(b, timeout=timeout)
Rich Lane3a261d52013-01-03 17:45:08 -0800343 if resp is None:
344 raise AssertionError("barrier failed")
Dan Talaycof6b94832012-04-12 21:50:57 -0700345 # We'll trust the transaction processing in the controller that xid matched
Rich Lane3a261d52013-01-03 17:45:08 -0800346 return 0 # for backwards compatibility
Dan Talayco92c99122010-06-03 13:53:18 -0700347
Rich Lane9a003812012-10-04 17:17:59 -0700348def port_config_get(controller, port_no):
Dan Talayco92c99122010-06-03 13:53:18 -0700349 """
350 Get a port's configuration
351
352 Gets the switch feature configuration and grabs one port's
353 configuration
354
355 @returns (hwaddr, config, advert) The hwaddress, configuration and
356 advertised values
357 """
Rich Lanee717c6e2013-03-12 10:25:50 -0700358 request = ofp.message.features_request()
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700359 reply, pkt = controller.transact(request)
Rich Lane9a003812012-10-04 17:17:59 -0700360 logging.debug(reply.show())
Dan Talayco92c99122010-06-03 13:53:18 -0700361 if reply is None:
Rich Lane9a003812012-10-04 17:17:59 -0700362 logging.warn("Get feature request failed")
Dan Talayco92c99122010-06-03 13:53:18 -0700363 return None, None, None
364 for idx in range(len(reply.ports)):
365 if reply.ports[idx].port_no == port_no:
366 return (reply.ports[idx].hw_addr, reply.ports[idx].config,
367 reply.ports[idx].advertised)
368
Rich Lane9a003812012-10-04 17:17:59 -0700369 logging.warn("Did not find port number for port config")
Dan Talayco92c99122010-06-03 13:53:18 -0700370 return None, None, None
371
Rich Lane9a003812012-10-04 17:17:59 -0700372def port_config_set(controller, port_no, config, mask):
Dan Talayco92c99122010-06-03 13:53:18 -0700373 """
374 Set the port configuration according the given parameters
375
376 Gets the switch feature configuration and updates one port's
377 configuration value according to config and mask
378 """
Rich Lane9a003812012-10-04 17:17:59 -0700379 logging.info("Setting port " + str(port_no) + " to config " + str(config))
Rich Lanee717c6e2013-03-12 10:25:50 -0700380 request = ofp.message.features_request()
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700381 reply, pkt = controller.transact(request)
Dan Talayco92c99122010-06-03 13:53:18 -0700382 if reply is None:
383 return -1
Rich Lane9a003812012-10-04 17:17:59 -0700384 logging.debug(reply.show())
Ed Swierk8d84ce02012-12-27 15:36:48 -0800385 p = None
Dan Talayco92c99122010-06-03 13:53:18 -0700386 for idx in range(len(reply.ports)):
387 if reply.ports[idx].port_no == port_no:
Ed Swierk8d84ce02012-12-27 15:36:48 -0800388 p = reply.ports[idx]
Dan Talayco92c99122010-06-03 13:53:18 -0700389 break
Rich Lanee717c6e2013-03-12 10:25:50 -0700390 mod = ofp.message.port_mod()
Dan Talayco92c99122010-06-03 13:53:18 -0700391 mod.port_no = port_no
Ed Swierk8d84ce02012-12-27 15:36:48 -0800392 if p:
393 mod.hw_addr = p.hw_addr
Dan Talayco92c99122010-06-03 13:53:18 -0700394 mod.config = config
395 mod.mask = mask
Ed Swierk8d84ce02012-12-27 15:36:48 -0800396 if p:
397 mod.advertise = p.advertised
Rich Lane5c3151c2013-01-03 17:15:41 -0800398 controller.message_send(mod)
399 return 0
Dan Talayco92c99122010-06-03 13:53:18 -0700400
Rich Lane2014f9b2012-10-05 15:29:40 -0700401def receive_pkt_check(dp, pkt, yes_ports, no_ports, assert_if):
Dan Talayco92c99122010-06-03 13:53:18 -0700402 """
403 Check for proper receive packets across all ports
Ken Chiang1bf01602012-04-04 10:48:23 -0700404 @param dp The dataplane object
Dan Talayco92c99122010-06-03 13:53:18 -0700405 @param pkt Expected packet; may be None if yes_ports is empty
406 @param yes_ports Set or list of ports that should recieve packet
407 @param no_ports Set or list of ports that should not receive packet
408 @param assert_if Object that implements assertXXX
409 """
Rich Lane91765672012-12-06 16:33:04 -0800410
411 # Wait this long for packets that we don't expect to receive.
412 # 100ms is (rarely) too short for positive tests on slow
413 # switches but is definitely not too short for a negative test.
414 negative_timeout = 0.1
415
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700416 exp_pkt_arg = None
Rich Lanecd97d3d2013-01-07 18:50:06 -0800417 if oftest.config["relax"]:
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700418 exp_pkt_arg = pkt
419
Dan Talayco92c99122010-06-03 13:53:18 -0700420 for ofport in yes_ports:
Rich Lane9a003812012-10-04 17:17:59 -0700421 logging.debug("Checking for pkt on port " + str(ofport))
Ken Chiang1bf01602012-04-04 10:48:23 -0700422 (rcv_port, rcv_pkt, pkt_time) = dp.poll(
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700423 port_number=ofport, exp_pkt=exp_pkt_arg)
Dan Talayco92c99122010-06-03 13:53:18 -0700424 assert_if.assertTrue(rcv_pkt is not None,
425 "Did not receive pkt on " + str(ofport))
Rich Lanecd97d3d2013-01-07 18:50:06 -0800426 if not oftest.dataplane.match_exp_pkt(pkt, rcv_pkt):
Rich Lane3c266832013-01-29 18:29:15 -0800427 logging.debug("Expected %s" % format_packet(pkt))
428 logging.debug("Received %s" % format_packet(rcv_pkt))
Rich Lanecd97d3d2013-01-07 18:50:06 -0800429 assert_if.assertTrue(oftest.dataplane.match_exp_pkt(pkt, rcv_pkt),
Rich Lane3c266832013-01-29 18:29:15 -0800430 "Received packet does not match expected packet " +
Ken Chiang1bf01602012-04-04 10:48:23 -0700431 "on port " + str(ofport))
Dan Talayco73f84012012-10-02 09:23:18 -0700432 if len(no_ports) > 0:
Rich Lane91765672012-12-06 16:33:04 -0800433 time.sleep(negative_timeout)
Dan Talayco92c99122010-06-03 13:53:18 -0700434 for ofport in no_ports:
Rich Lane9a003812012-10-04 17:17:59 -0700435 logging.debug("Negative check for pkt on port " + str(ofport))
Ken Chiang1bf01602012-04-04 10:48:23 -0700436 (rcv_port, rcv_pkt, pkt_time) = dp.poll(
Rich Lane91765672012-12-06 16:33:04 -0800437 port_number=ofport, timeout=0, exp_pkt=exp_pkt_arg)
Dan Talayco92c99122010-06-03 13:53:18 -0700438 assert_if.assertTrue(rcv_pkt is None,
439 "Unexpected pkt on port " + str(ofport))
Dan Talayco551befa2010-07-15 17:05:32 -0700440
441
Dan Talaycoc948d0b2012-03-23 12:17:54 -0700442def receive_pkt_verify(parent, egr_ports, exp_pkt, ing_port):
Dan Talayco551befa2010-07-15 17:05:32 -0700443 """
444 Receive a packet and verify it matches an expected value
Dan Talaycof6e76c02012-03-23 10:56:12 -0700445 @param egr_port A single port or list of ports
Dan Talayco551befa2010-07-15 17:05:32 -0700446
447 parent must implement dataplane, assertTrue and assertEqual
448 """
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700449 exp_pkt_arg = None
Rich Lanecd97d3d2013-01-07 18:50:06 -0800450 if oftest.config["relax"]:
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700451 exp_pkt_arg = exp_pkt
452
Dan Talaycof6e76c02012-03-23 10:56:12 -0700453 if type(egr_ports) == type([]):
454 egr_port_list = egr_ports
455 else:
456 egr_port_list = [egr_ports]
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700457
Dan Talaycof6e76c02012-03-23 10:56:12 -0700458 # Expect a packet from each port on egr port list
459 for egr_port in egr_port_list:
Dan Talaycod8ae7582012-03-23 12:24:56 -0700460 check_port = egr_port
Rich Lanee717c6e2013-03-12 10:25:50 -0700461 if egr_port == ofp.OFPP_IN_PORT:
Dan Talaycod8ae7582012-03-23 12:24:56 -0700462 check_port = ing_port
Dan Talaycof6e76c02012-03-23 10:56:12 -0700463 (rcv_port, rcv_pkt, pkt_time) = parent.dataplane.poll(
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700464 port_number=check_port, exp_pkt=exp_pkt_arg)
Dan Talayco551befa2010-07-15 17:05:32 -0700465
Dan Talaycof6e76c02012-03-23 10:56:12 -0700466 if rcv_pkt is None:
Rich Lane9a003812012-10-04 17:17:59 -0700467 logging.error("ERROR: No packet received from " +
Dan Talaycod8ae7582012-03-23 12:24:56 -0700468 str(check_port))
Dan Talayco551befa2010-07-15 17:05:32 -0700469
Dan Talaycof6e76c02012-03-23 10:56:12 -0700470 parent.assertTrue(rcv_pkt is not None,
Dan Talaycod8ae7582012-03-23 12:24:56 -0700471 "Did not receive packet port " + str(check_port))
Rich Lane9a003812012-10-04 17:17:59 -0700472 logging.debug("Packet len " + str(len(rcv_pkt)) + " in on " +
Dan Talaycof6e76c02012-03-23 10:56:12 -0700473 str(rcv_port))
474
475 if str(exp_pkt) != str(rcv_pkt):
Rich Lane9a003812012-10-04 17:17:59 -0700476 logging.error("ERROR: Packet match failed.")
477 logging.debug("Expected len " + str(len(exp_pkt)) + ": "
Dan Talaycof6e76c02012-03-23 10:56:12 -0700478 + str(exp_pkt).encode('hex'))
Rich Lane9a003812012-10-04 17:17:59 -0700479 logging.debug("Received len " + str(len(rcv_pkt)) + ": "
Dan Talaycof6e76c02012-03-23 10:56:12 -0700480 + str(rcv_pkt).encode('hex'))
Rich Lane5d7e89a2012-10-26 16:43:13 -0700481 logging.debug("Expected packet: " + inspect_packet(scapy.Ether(str(exp_pkt))))
482 logging.debug("Received packet: " + inspect_packet(scapy.Ether(str(rcv_pkt))))
Dan Talaycof6e76c02012-03-23 10:56:12 -0700483 parent.assertEqual(str(exp_pkt), str(rcv_pkt),
Dan Talaycod8ae7582012-03-23 12:24:56 -0700484 "Packet match error on port " + str(check_port))
Dan Talaycof6e76c02012-03-23 10:56:12 -0700485
Dan Talayco551befa2010-07-15 17:05:32 -0700486def match_verify(parent, req_match, res_match):
487 """
488 Verify flow matches agree; if they disagree, report where
489
490 parent must implement assertEqual
491 Use str() to ensure content is compared and not pointers
492 """
493
494 parent.assertEqual(req_match.wildcards, res_match.wildcards,
495 'Match failed: wildcards: ' + hex(req_match.wildcards) +
496 " != " + hex(res_match.wildcards))
497 parent.assertEqual(req_match.in_port, res_match.in_port,
498 'Match failed: in_port: ' + str(req_match.in_port) +
499 " != " + str(res_match.in_port))
Rich Laned0478ff2013-03-11 12:46:58 -0700500 parent.assertEqual(str(req_match.eth_src), str(res_match.eth_src),
501 'Match failed: eth_src: ' + str(req_match.eth_src) +
502 " != " + str(res_match.eth_src))
503 parent.assertEqual(str(req_match.eth_dst), str(res_match.eth_dst),
504 'Match failed: eth_dst: ' + str(req_match.eth_dst) +
505 " != " + str(res_match.eth_dst))
506 parent.assertEqual(req_match.vlan_vid, res_match.vlan_vid,
507 'Match failed: vlan_vid: ' + str(req_match.vlan_vid) +
508 " != " + str(res_match.vlan_vid))
509 parent.assertEqual(req_match.vlan_pcp, res_match.vlan_pcp,
510 'Match failed: vlan_pcp: ' +
511 str(req_match.vlan_pcp) + " != " +
512 str(res_match.vlan_pcp))
513 parent.assertEqual(req_match.eth_type, res_match.eth_type,
514 'Match failed: eth_type: ' + str(req_match.eth_type) +
515 " != " + str(res_match.eth_type))
Dan Talayco551befa2010-07-15 17:05:32 -0700516
Rich Lanee717c6e2013-03-12 10:25:50 -0700517 if (not(req_match.wildcards & ofp.OFPFW_DL_TYPE)
Rich Laned0478ff2013-03-11 12:46:58 -0700518 and (req_match.eth_type == IP_ETHERTYPE)):
519 parent.assertEqual(req_match.ip_dscp, res_match.ip_dscp,
520 'Match failed: ip_dscp: ' + str(req_match.ip_dscp) +
521 " != " + str(res_match.ip_dscp))
522 parent.assertEqual(req_match.ip_proto, res_match.ip_proto,
523 'Match failed: ip_proto: ' + str(req_match.ip_proto) +
524 " != " + str(res_match.ip_proto))
525 parent.assertEqual(req_match.ipv4_src, res_match.ipv4_src,
526 'Match failed: ipv4_src: ' + str(req_match.ipv4_src) +
527 " != " + str(res_match.ipv4_src))
528 parent.assertEqual(req_match.ipv4_dst, res_match.ipv4_dst,
529 'Match failed: ipv4_dst: ' + str(req_match.ipv4_dst) +
530 " != " + str(res_match.ipv4_dst))
Dan Talayco551befa2010-07-15 17:05:32 -0700531
Rich Lanee717c6e2013-03-12 10:25:50 -0700532 if (not(req_match.wildcards & ofp.OFPFW_NW_PROTO)
Rich Laned0478ff2013-03-11 12:46:58 -0700533 and ((req_match.ip_proto == TCP_PROTOCOL)
534 or (req_match.ip_proto == UDP_PROTOCOL))):
535 parent.assertEqual(req_match.tcp_src, res_match.tcp_src,
536 'Match failed: tcp_src: ' +
537 str(req_match.tcp_src) +
538 " != " + str(res_match.tcp_src))
539 parent.assertEqual(req_match.tcp_dst, res_match.tcp_dst,
540 'Match failed: tcp_dst: ' +
541 str(req_match.tcp_dst) +
542 " != " + str(res_match.tcp_dst))
Dan Talayco551befa2010-07-15 17:05:32 -0700543
Ed Swierk99a74de2012-08-22 06:40:54 -0700544def packet_to_flow_match(parent, packet):
Rich Lanef6883512013-03-11 17:00:09 -0700545 match = oftest.parse.packet_to_flow_match(packet)
Ed Swierk99a74de2012-08-22 06:40:54 -0700546 match.wildcards |= required_wildcards(parent)
547 return match
548
549def flow_msg_create(parent, pkt, ing_port=None, action_list=None, wildcards=None,
Dan Talaycof6e76c02012-03-23 10:56:12 -0700550 egr_ports=None, egr_queue=None, check_expire=False, in_band=False):
Dan Talayco551befa2010-07-15 17:05:32 -0700551 """
552 Create a flow message
553
554 Match on packet with given wildcards.
555 See flow_match_test for other parameter descriptoins
556 @param egr_queue if not None, make the output an enqueue action
Dan Talayco677c0b72011-08-23 22:53:38 -0700557 @param in_band if True, do not wildcard ingress port
Dan Talaycof6e76c02012-03-23 10:56:12 -0700558 @param egr_ports None (drop), single port or list of ports
Dan Talayco551befa2010-07-15 17:05:32 -0700559 """
Rich Lanef6883512013-03-11 17:00:09 -0700560 match = oftest.parse.packet_to_flow_match(pkt)
Dan Talayco551befa2010-07-15 17:05:32 -0700561 parent.assertTrue(match is not None, "Flow match from pkt failed")
Ed Swierk99a74de2012-08-22 06:40:54 -0700562 if wildcards is None:
563 wildcards = required_wildcards(parent)
Dan Talayco677c0b72011-08-23 22:53:38 -0700564 if in_band:
Rich Lanee717c6e2013-03-12 10:25:50 -0700565 wildcards &= ~ofp.OFPFW_IN_PORT
Dan Talayco551befa2010-07-15 17:05:32 -0700566 match.wildcards = wildcards
567 match.in_port = ing_port
568
Dan Talaycof6e76c02012-03-23 10:56:12 -0700569 if type(egr_ports) == type([]):
570 egr_port_list = egr_ports
571 else:
572 egr_port_list = [egr_ports]
573
Rich Lanee717c6e2013-03-12 10:25:50 -0700574 request = ofp.message.flow_add()
Dan Talayco551befa2010-07-15 17:05:32 -0700575 request.match = match
576 request.buffer_id = 0xffffffff
577 if check_expire:
Rich Lanee717c6e2013-03-12 10:25:50 -0700578 request.flags |= ofp.OFPFF_SEND_FLOW_REM
Dan Talayco551befa2010-07-15 17:05:32 -0700579 request.hard_timeout = 1
580
581 if action_list is not None:
582 for act in action_list:
Rich Lane9a003812012-10-04 17:17:59 -0700583 logging.debug("Adding action " + act.show())
Rich Lanec495d9e2013-03-08 17:43:36 -0800584 request.actions.append(act)
Dan Talayco551befa2010-07-15 17:05:32 -0700585
586 # Set up output/enqueue action if directed
587 if egr_queue is not None:
Dan Talaycof6e76c02012-03-23 10:56:12 -0700588 parent.assertTrue(egr_ports is not None, "Egress port not set")
Rich Lanee717c6e2013-03-12 10:25:50 -0700589 act = ofp.action.enqueue()
Dan Talaycof6e76c02012-03-23 10:56:12 -0700590 for egr_port in egr_port_list:
591 act.port = egr_port
592 act.queue_id = egr_queue
Rich Lanec495d9e2013-03-08 17:43:36 -0800593 request.actions.append(act)
Dan Talaycof6e76c02012-03-23 10:56:12 -0700594 elif egr_ports is not None:
595 for egr_port in egr_port_list:
Rich Lanee717c6e2013-03-12 10:25:50 -0700596 act = ofp.action.output()
Dan Talaycof6e76c02012-03-23 10:56:12 -0700597 act.port = egr_port
Rich Lanec495d9e2013-03-08 17:43:36 -0800598 request.actions.append(act)
Dan Talayco551befa2010-07-15 17:05:32 -0700599
Rich Lane9a003812012-10-04 17:17:59 -0700600 logging.debug(request.show())
Dan Talayco551befa2010-07-15 17:05:32 -0700601
602 return request
603
Jeffrey Townsendf3eae9c2012-03-28 18:23:21 -0700604def flow_msg_install(parent, request, clear_table_override=None):
Dan Talayco551befa2010-07-15 17:05:32 -0700605 """
606 Install a flow mod message in the switch
607
608 @param parent Must implement controller, assertEqual, assertTrue
609 @param request The request, all set to go
610 @param clear_table If true, clear the flow table before installing
611 """
Dan Talayco8a64e332012-03-28 14:53:20 -0700612
Rich Lane2014f9b2012-10-05 15:29:40 -0700613 clear_table = test_param_get('clear_table', default=True)
Jeffrey Townsendf3eae9c2012-03-28 18:23:21 -0700614 if(clear_table_override != None):
615 clear_table = clear_table_override
616
617 if clear_table:
Rich Lane9a003812012-10-04 17:17:59 -0700618 logging.debug("Clear flow table")
Rich Lane32bf9482013-01-03 17:26:30 -0800619 delete_all_flows(parent.controller)
Dan Talayco551befa2010-07-15 17:05:32 -0700620
Rich Lane9a003812012-10-04 17:17:59 -0700621 logging.debug("Insert flow")
Rich Lane5c3151c2013-01-03 17:15:41 -0800622 parent.controller.message_send(request)
Rich Lanee912d032012-12-22 14:28:33 -0800623
Rich Lane3a261d52013-01-03 17:45:08 -0800624 do_barrier(parent.controller)
Dan Talayco551befa2010-07-15 17:05:32 -0700625
Ed Swierk99a74de2012-08-22 06:40:54 -0700626def flow_match_test_port_pair(parent, ing_port, egr_ports, wildcards=None,
Rich Laned0478ff2013-03-11 12:46:58 -0700627 vlan_vid=-1, pkt=None, exp_pkt=None,
Rich Lanee5779d32012-10-05 17:56:04 -0700628 action_list=None):
Dan Talayco551befa2010-07-15 17:05:32 -0700629 """
630 Flow match test on single TCP packet
Dan Talaycof6e76c02012-03-23 10:56:12 -0700631 @param egr_ports A single port or list of ports
Dan Talayco551befa2010-07-15 17:05:32 -0700632
633 Run test with packet through switch from ing_port to egr_port
634 See flow_match_test for parameter descriptions
635 """
636
Ed Swierk99a74de2012-08-22 06:40:54 -0700637 if wildcards is None:
638 wildcards = required_wildcards(parent)
Rich Lane9a003812012-10-04 17:17:59 -0700639 logging.info("Pkt match test: " + str(ing_port) + " to " +
Dan Talaycof6e76c02012-03-23 10:56:12 -0700640 str(egr_ports))
Rich Laned0478ff2013-03-11 12:46:58 -0700641 logging.debug(" WC: " + hex(wildcards) + " vlan: " + str(vlan_vid))
Dan Talayco551befa2010-07-15 17:05:32 -0700642 if pkt is None:
Rich Laned0478ff2013-03-11 12:46:58 -0700643 pkt = simple_tcp_packet(dl_vlan_enable=(vlan_vid >= 0), vlan_vid=vlan_vid)
Dan Talayco551befa2010-07-15 17:05:32 -0700644
645 request = flow_msg_create(parent, pkt, ing_port=ing_port,
Dan Talaycof6e76c02012-03-23 10:56:12 -0700646 wildcards=wildcards, egr_ports=egr_ports,
Dan Talayco551befa2010-07-15 17:05:32 -0700647 action_list=action_list)
648
649 flow_msg_install(parent, request)
650
Rich Lane9a003812012-10-04 17:17:59 -0700651 logging.debug("Send packet: " + str(ing_port) + " to " +
Dan Talaycof6e76c02012-03-23 10:56:12 -0700652 str(egr_ports))
Dan Talayco551befa2010-07-15 17:05:32 -0700653 parent.dataplane.send(ing_port, str(pkt))
654
655 if exp_pkt is None:
656 exp_pkt = pkt
Dan Talaycoc948d0b2012-03-23 12:17:54 -0700657 receive_pkt_verify(parent, egr_ports, exp_pkt, ing_port)
Dan Talayco551befa2010-07-15 17:05:32 -0700658
Rich Lane89725bb2012-12-03 16:23:27 -0800659def flow_match_test_pktout(parent, ing_port, egr_ports,
Rich Laned0478ff2013-03-11 12:46:58 -0700660 vlan_vid=-1, pkt=None, exp_pkt=None,
Rich Lane89725bb2012-12-03 16:23:27 -0800661 action_list=None):
662 """
663 Packet-out test on single TCP packet
664 @param egr_ports A single port or list of ports
665
666 Run test sending packet-out to egr_ports. The goal is to test the actions
667 taken on the packet, not the matching which is of course irrelevant.
668 See flow_match_test for parameter descriptions
669 """
670
671 if pkt is None:
Rich Laned0478ff2013-03-11 12:46:58 -0700672 pkt = simple_tcp_packet(dl_vlan_enable=(vlan_vid >= 0), vlan_vid=vlan_vid)
Rich Lane89725bb2012-12-03 16:23:27 -0800673
Rich Lanee717c6e2013-03-12 10:25:50 -0700674 msg = ofp.message.packet_out()
Rich Lane89725bb2012-12-03 16:23:27 -0800675 msg.in_port = ing_port
Rich Laneea8c4722013-04-04 15:30:20 -0700676 msg.buffer_id = 0xffffffff
Rich Lane89725bb2012-12-03 16:23:27 -0800677 msg.data = str(pkt)
678 if action_list is not None:
679 for act in action_list:
Rich Lanec495d9e2013-03-08 17:43:36 -0800680 msg.actions.append(act)
Rich Lane89725bb2012-12-03 16:23:27 -0800681
682 # Set up output action
683 if egr_ports is not None:
684 for egr_port in egr_ports:
Rich Lanee717c6e2013-03-12 10:25:50 -0700685 act = ofp.action.output()
Rich Lane89725bb2012-12-03 16:23:27 -0800686 act.port = egr_port
Rich Lanec495d9e2013-03-08 17:43:36 -0800687 msg.actions.append(act)
Rich Lane89725bb2012-12-03 16:23:27 -0800688
689 logging.debug(msg.show())
Rich Lane5c3151c2013-01-03 17:15:41 -0800690 parent.controller.message_send(msg)
Rich Lane89725bb2012-12-03 16:23:27 -0800691
692 if exp_pkt is None:
693 exp_pkt = pkt
694 receive_pkt_verify(parent, egr_ports, exp_pkt, ing_port)
695
Dan Talaycof6e76c02012-03-23 10:56:12 -0700696def get_egr_list(parent, of_ports, how_many, exclude_list=[]):
697 """
698 Generate a list of ports avoiding those in the exclude list
Rich Lane9a003812012-10-04 17:17:59 -0700699 @param parent Supplies logging
Dan Talaycof6e76c02012-03-23 10:56:12 -0700700 @param of_ports List of OF port numbers
701 @param how_many Number of ports to be added to the list
702 @param exclude_list List of ports not to be used
703 @returns An empty list if unable to find enough ports
704 """
705
Dan Talaycoc948d0b2012-03-23 12:17:54 -0700706 if how_many == 0:
707 return []
708
Dan Talaycof6e76c02012-03-23 10:56:12 -0700709 count = 0
710 egr_ports = []
711 for egr_idx in range(len(of_ports)):
712 if of_ports[egr_idx] not in exclude_list:
713 egr_ports.append(of_ports[egr_idx])
714 count += 1
715 if count >= how_many:
716 return egr_ports
Rich Lane9a003812012-10-04 17:17:59 -0700717 logging.debug("Could not generate enough egress ports for test")
Dan Talaycof6e76c02012-03-23 10:56:12 -0700718 return []
719
Rich Laned0478ff2013-03-11 12:46:58 -0700720def flow_match_test(parent, port_map, wildcards=None, vlan_vid=-1, pkt=None,
Rich Lanee5779d32012-10-05 17:56:04 -0700721 exp_pkt=None, action_list=None,
Dan Talaycoc948d0b2012-03-23 12:17:54 -0700722 max_test=0, egr_count=1, ing_port=False):
Dan Talayco551befa2010-07-15 17:05:32 -0700723 """
Rich Lane89725bb2012-12-03 16:23:27 -0800724 Run flow_match_test_port_pair on all port pairs and packet-out
Dan Talayco551befa2010-07-15 17:05:32 -0700725
726 @param max_test If > 0 no more than this number of tests are executed.
727 @param parent Must implement controller, dataplane, assertTrue, assertEqual
Rich Lane9a003812012-10-04 17:17:59 -0700728 and logging
Dan Talayco551befa2010-07-15 17:05:32 -0700729 @param pkt If not None, use this packet for ingress
730 @param wildcards For flow match entry
Rich Laned0478ff2013-03-11 12:46:58 -0700731 @param vlan_vid If not -1, and pkt is None, create a pkt w/ VLAN tag
Dan Talayco551befa2010-07-15 17:05:32 -0700732 @param exp_pkt If not None, use this as the expected output pkt; els use pkt
733 @param action_list Additional actions to add to flow mod
Dan Talaycocfa172f2012-03-23 12:03:00 -0700734 @param egr_count Number of egress ports; -1 means get from config w/ dflt 2
Dan Talayco551befa2010-07-15 17:05:32 -0700735 """
Ed Swierk99a74de2012-08-22 06:40:54 -0700736 if wildcards is None:
737 wildcards = required_wildcards(parent)
Dan Talayco551befa2010-07-15 17:05:32 -0700738 of_ports = port_map.keys()
739 of_ports.sort()
740 parent.assertTrue(len(of_ports) > 1, "Not enough ports for test")
741 test_count = 0
742
Dan Talaycocfa172f2012-03-23 12:03:00 -0700743 if egr_count == -1:
Rich Lane2014f9b2012-10-05 15:29:40 -0700744 egr_count = test_param_get('egr_count', default=2)
Dan Talaycocfa172f2012-03-23 12:03:00 -0700745
Dan Talayco551befa2010-07-15 17:05:32 -0700746 for ing_idx in range(len(of_ports)):
747 ingress_port = of_ports[ing_idx]
Dan Talaycof6e76c02012-03-23 10:56:12 -0700748 egr_ports = get_egr_list(parent, of_ports, egr_count,
749 exclude_list=[ingress_port])
Dan Talaycoc948d0b2012-03-23 12:17:54 -0700750 if ing_port:
Rich Lanee717c6e2013-03-12 10:25:50 -0700751 egr_ports.append(ofp.OFPP_IN_PORT)
Dan Talaycof6e76c02012-03-23 10:56:12 -0700752 if len(egr_ports) == 0:
753 parent.assertTrue(0, "Failed to generate egress port list")
754
755 flow_match_test_port_pair(parent, ingress_port, egr_ports,
Rich Laned0478ff2013-03-11 12:46:58 -0700756 wildcards=wildcards, vlan_vid=vlan_vid,
Dan Talaycof6e76c02012-03-23 10:56:12 -0700757 pkt=pkt, exp_pkt=exp_pkt,
Rich Lanee5779d32012-10-05 17:56:04 -0700758 action_list=action_list)
Dan Talaycof6e76c02012-03-23 10:56:12 -0700759 test_count += 1
760 if (max_test > 0) and (test_count > max_test):
Rich Lane9a003812012-10-04 17:17:59 -0700761 logging.info("Ran " + str(test_count) + " tests; exiting")
Rich Lane89725bb2012-12-03 16:23:27 -0800762 break
763
Ed Swierk38eea082013-01-02 19:46:20 -0800764 if not test_param_get('pktout_actions', default=True):
765 return
Rich Lane89725bb2012-12-03 16:23:27 -0800766
767 ingress_port = of_ports[0]
768 egr_ports = get_egr_list(parent, of_ports, egr_count,
769 exclude_list=[ingress_port])
770 if ing_port:
Rich Lanee717c6e2013-03-12 10:25:50 -0700771 egr_ports.append(ofp.OFPP_IN_PORT)
Rich Lane89725bb2012-12-03 16:23:27 -0800772 flow_match_test_pktout(parent, ingress_port, egr_ports,
Rich Laned0478ff2013-03-11 12:46:58 -0700773 vlan_vid=vlan_vid,
Rich Lane89725bb2012-12-03 16:23:27 -0800774 pkt=pkt, exp_pkt=exp_pkt,
775 action_list=action_list)
Dan Talayco551befa2010-07-15 17:05:32 -0700776
Rich Lane2014f9b2012-10-05 15:29:40 -0700777def test_param_get(key, default=None):
Dan Talayco4b2bee62010-07-20 14:10:05 -0700778 """
779 Return value passed via test-params if present
780
Dan Talayco4b2bee62010-07-20 14:10:05 -0700781 @param key The lookup key
782 @param default Default value to use if not found
783
784 If the pair 'key=val' appeared in the string passed to --test-params
785 on the command line, return val (as interpreted by exec). Otherwise
786 return default value.
Dan Talaycof6e76c02012-03-23 10:56:12 -0700787
788 WARNING: TEST PARAMETERS MUST BE PYTHON IDENTIFIERS;
789 eg egr_count, not egr-count.
Dan Talayco4b2bee62010-07-20 14:10:05 -0700790 """
791 try:
Rich Lanecd97d3d2013-01-07 18:50:06 -0800792 exec oftest.config["test_params"]
Dan Talayco4b2bee62010-07-20 14:10:05 -0700793 except:
794 return default
795
796 s = "val = " + str(key)
797 try:
798 exec s
799 return val
800 except:
801 return default
802
803def action_generate(parent, field_to_mod, mod_field_vals):
804 """
805 Create an action to modify the field indicated in field_to_mod
806
807 @param parent Must implement, assertTrue
808 @param field_to_mod The field to modify as a string name
809 @param mod_field_vals Hash of values to use for modified values
810 """
811
812 act = None
813
814 if field_to_mod in ['pktlen']:
815 return None
816
Rich Laned0478ff2013-03-11 12:46:58 -0700817 if field_to_mod == 'eth_dst':
Rich Lanee717c6e2013-03-12 10:25:50 -0700818 act = ofp.action.set_dl_dst()
Rich Lanef6883512013-03-11 17:00:09 -0700819 act.dl_addr = oftest.parse.parse_mac(mod_field_vals['eth_dst'])
Rich Laned0478ff2013-03-11 12:46:58 -0700820 elif field_to_mod == 'eth_src':
Rich Lanee717c6e2013-03-12 10:25:50 -0700821 act = ofp.action.set_dl_src()
Rich Lanef6883512013-03-11 17:00:09 -0700822 act.dl_addr = oftest.parse.parse_mac(mod_field_vals['eth_src'])
Dan Talayco4b2bee62010-07-20 14:10:05 -0700823 elif field_to_mod == 'dl_vlan_enable':
824 if not mod_field_vals['dl_vlan_enable']: # Strip VLAN tag
Rich Lanee717c6e2013-03-12 10:25:50 -0700825 act = ofp.action.strip_vlan()
Rich Laned0478ff2013-03-11 12:46:58 -0700826 # Add VLAN tag is handled by vlan_vid field
Dan Talayco4b2bee62010-07-20 14:10:05 -0700827 # Will return None in this case
Rich Laned0478ff2013-03-11 12:46:58 -0700828 elif field_to_mod == 'vlan_vid':
Rich Lanee717c6e2013-03-12 10:25:50 -0700829 act = ofp.action.set_vlan_vid()
Rich Laned0478ff2013-03-11 12:46:58 -0700830 act.vlan_vid = mod_field_vals['vlan_vid']
831 elif field_to_mod == 'vlan_pcp':
Rich Lanee717c6e2013-03-12 10:25:50 -0700832 act = ofp.action.set_vlan_pcp()
Rich Laned0478ff2013-03-11 12:46:58 -0700833 act.vlan_pcp = mod_field_vals['vlan_pcp']
Dan Talayco4b2bee62010-07-20 14:10:05 -0700834 elif field_to_mod == 'ip_src':
Rich Lanee717c6e2013-03-12 10:25:50 -0700835 act = ofp.action.set_nw_src()
Rich Lanef6883512013-03-11 17:00:09 -0700836 act.nw_addr = oftest.parse.parse_ip(mod_field_vals['ip_src'])
Dan Talayco4b2bee62010-07-20 14:10:05 -0700837 elif field_to_mod == 'ip_dst':
Rich Lanee717c6e2013-03-12 10:25:50 -0700838 act = ofp.action.set_nw_dst()
Rich Lanef6883512013-03-11 17:00:09 -0700839 act.nw_addr = oftest.parse.parse_ip(mod_field_vals['ip_dst'])
Dan Talayco4b2bee62010-07-20 14:10:05 -0700840 elif field_to_mod == 'ip_tos':
Rich Lanee717c6e2013-03-12 10:25:50 -0700841 act = ofp.action.set_nw_tos()
Dan Talayco4b2bee62010-07-20 14:10:05 -0700842 act.nw_tos = mod_field_vals['ip_tos']
843 elif field_to_mod == 'tcp_sport':
Rich Lanee717c6e2013-03-12 10:25:50 -0700844 act = ofp.action.set_tp_src()
Dan Talayco4b2bee62010-07-20 14:10:05 -0700845 act.tp_port = mod_field_vals['tcp_sport']
846 elif field_to_mod == 'tcp_dport':
Rich Lanee717c6e2013-03-12 10:25:50 -0700847 act = ofp.action.set_tp_dst()
Dan Talayco4b2bee62010-07-20 14:10:05 -0700848 act.tp_port = mod_field_vals['tcp_dport']
Rich Lane110e0e32012-10-26 16:21:46 -0700849 elif field_to_mod == 'udp_sport':
Rich Lanee717c6e2013-03-12 10:25:50 -0700850 act = ofp.action.set_tp_src()
Rich Lane110e0e32012-10-26 16:21:46 -0700851 act.tp_port = mod_field_vals['udp_sport']
852 elif field_to_mod == 'udp_dport':
Rich Lanee717c6e2013-03-12 10:25:50 -0700853 act = ofp.action.set_tp_dst()
Rich Lane110e0e32012-10-26 16:21:46 -0700854 act.tp_port = mod_field_vals['udp_dport']
Dan Talayco4b2bee62010-07-20 14:10:05 -0700855 else:
856 parent.assertTrue(0, "Unknown field to modify: " + str(field_to_mod))
857
858 return act
859
860def pkt_action_setup(parent, start_field_vals={}, mod_field_vals={},
Rich Lane110e0e32012-10-26 16:21:46 -0700861 mod_fields=[], tp="tcp", check_test_params=False):
Dan Talayco4b2bee62010-07-20 14:10:05 -0700862 """
863 Set up the ingress and expected packet and action list for a test
864
Rich Lane2014f9b2012-10-05 15:29:40 -0700865 @param parent Must implement assertTrue
Dan Talayco4b2bee62010-07-20 14:10:05 -0700866 @param start_field_values Field values to use for ingress packet (optional)
867 @param mod_field_values Field values to use for modified packet (optional)
868 @param mod_fields The list of fields to be modified by the switch in the test.
869 @params check_test_params If True, will check the parameters vid, add_vlan
870 and strip_vlan from the command line.
871
872 Returns a triple: pkt-to-send, expected-pkt, action-list
873 """
874
875 new_actions = []
876
Dan Talayco4b2bee62010-07-20 14:10:05 -0700877 base_pkt_params = {}
878 base_pkt_params['pktlen'] = 100
Rich Laned0478ff2013-03-11 12:46:58 -0700879 base_pkt_params['eth_dst'] = '00:DE:F0:12:34:56'
880 base_pkt_params['eth_src'] = '00:23:45:67:89:AB'
Dan Talayco4b2bee62010-07-20 14:10:05 -0700881 base_pkt_params['dl_vlan_enable'] = False
Rich Laned0478ff2013-03-11 12:46:58 -0700882 base_pkt_params['vlan_vid'] = 2
883 base_pkt_params['vlan_pcp'] = 0
Dan Talayco4b2bee62010-07-20 14:10:05 -0700884 base_pkt_params['ip_src'] = '192.168.0.1'
885 base_pkt_params['ip_dst'] = '192.168.0.2'
886 base_pkt_params['ip_tos'] = 0
Rich Lane110e0e32012-10-26 16:21:46 -0700887 if tp == "tcp":
888 base_pkt_params['tcp_sport'] = 1234
889 base_pkt_params['tcp_dport'] = 80
890 elif tp == "udp":
891 base_pkt_params['udp_sport'] = 1234
892 base_pkt_params['udp_dport'] = 80
Dan Talayco4b2bee62010-07-20 14:10:05 -0700893 for keyname in start_field_vals.keys():
894 base_pkt_params[keyname] = start_field_vals[keyname]
895
896 mod_pkt_params = {}
897 mod_pkt_params['pktlen'] = 100
Rich Laned0478ff2013-03-11 12:46:58 -0700898 mod_pkt_params['eth_dst'] = '00:21:0F:ED:CB:A9'
899 mod_pkt_params['eth_src'] = '00:ED:CB:A9:87:65'
Dan Talayco4b2bee62010-07-20 14:10:05 -0700900 mod_pkt_params['dl_vlan_enable'] = False
Rich Laned0478ff2013-03-11 12:46:58 -0700901 mod_pkt_params['vlan_vid'] = 3
902 mod_pkt_params['vlan_pcp'] = 7
Dan Talayco4b2bee62010-07-20 14:10:05 -0700903 mod_pkt_params['ip_src'] = '10.20.30.40'
904 mod_pkt_params['ip_dst'] = '50.60.70.80'
905 mod_pkt_params['ip_tos'] = 0xf0
Rich Lane110e0e32012-10-26 16:21:46 -0700906 if tp == "tcp":
907 mod_pkt_params['tcp_sport'] = 4321
908 mod_pkt_params['tcp_dport'] = 8765
909 elif tp == "udp":
910 mod_pkt_params['udp_sport'] = 4321
911 mod_pkt_params['udp_dport'] = 8765
Dan Talayco4b2bee62010-07-20 14:10:05 -0700912 for keyname in mod_field_vals.keys():
913 mod_pkt_params[keyname] = mod_field_vals[keyname]
914
915 # Check for test param modifications
916 strip = False
917 if check_test_params:
Rich Lane2014f9b2012-10-05 15:29:40 -0700918 add_vlan = test_param_get('add_vlan')
919 strip_vlan = test_param_get('strip_vlan')
920 vid = test_param_get('vid')
Dan Talayco4b2bee62010-07-20 14:10:05 -0700921
922 if add_vlan and strip_vlan:
923 parent.assertTrue(0, "Add and strip VLAN both specified")
924
925 if vid:
926 base_pkt_params['dl_vlan_enable'] = True
Rich Laned0478ff2013-03-11 12:46:58 -0700927 base_pkt_params['vlan_vid'] = vid
928 if 'vlan_vid' in mod_fields:
929 mod_pkt_params['vlan_vid'] = vid + 1
Dan Talayco4b2bee62010-07-20 14:10:05 -0700930
931 if add_vlan:
932 base_pkt_params['dl_vlan_enable'] = False
933 mod_pkt_params['dl_vlan_enable'] = True
934 mod_pkt_params['pktlen'] = base_pkt_params['pktlen'] + 4
935 mod_fields.append('pktlen')
936 mod_fields.append('dl_vlan_enable')
Rich Laned0478ff2013-03-11 12:46:58 -0700937 if 'vlan_vid' not in mod_fields:
938 mod_fields.append('vlan_vid')
Dan Talayco4b2bee62010-07-20 14:10:05 -0700939 elif strip_vlan:
940 base_pkt_params['dl_vlan_enable'] = True
941 mod_pkt_params['dl_vlan_enable'] = False
942 mod_pkt_params['pktlen'] = base_pkt_params['pktlen'] - 4
943 mod_fields.append('dl_vlan_enable')
944 mod_fields.append('pktlen')
945
Rich Lane110e0e32012-10-26 16:21:46 -0700946 if tp == "tcp":
947 packet_builder = simple_tcp_packet
948 elif tp == "udp":
949 packet_builder = simple_udp_packet
950 else:
951 raise NotImplementedError("unknown transport protocol %s" % tp)
952
Dan Talayco4b2bee62010-07-20 14:10:05 -0700953 # Build the ingress packet
Rich Lane110e0e32012-10-26 16:21:46 -0700954 ingress_pkt = packet_builder(**base_pkt_params)
Dan Talayco4b2bee62010-07-20 14:10:05 -0700955
956 # Build the expected packet, modifying the indicated fields
957 for item in mod_fields:
958 base_pkt_params[item] = mod_pkt_params[item]
959 act = action_generate(parent, item, mod_pkt_params)
960 if act:
961 new_actions.append(act)
962
Rich Lane110e0e32012-10-26 16:21:46 -0700963 expected_pkt = packet_builder(**base_pkt_params)
Dan Talayco4b2bee62010-07-20 14:10:05 -0700964
965 return (ingress_pkt, expected_pkt, new_actions)
Dan Talayco677c0b72011-08-23 22:53:38 -0700966
967# Generate a simple "drop" flow mod
968# If in_band is true, then only drop from first test port
969def flow_mod_gen(port_map, in_band):
Rich Lanee717c6e2013-03-12 10:25:50 -0700970 request = ofp.message.flow_add()
971 request.match.wildcards = ofp.OFPFW_ALL
Dan Talayco677c0b72011-08-23 22:53:38 -0700972 if in_band:
Rich Lanee717c6e2013-03-12 10:25:50 -0700973 request.match.wildcards = ofp.OFPFW_ALL - ofp.OFPFW_IN_PORT
Dan Talayco677c0b72011-08-23 22:53:38 -0700974 for of_port, ifname in port_map.items(): # Grab first port
975 break
976 request.match.in_port = of_port
977 request.buffer_id = 0xffffffff
978 return request
Dan Talaycoba3745c2010-07-21 21:51:08 -0700979
980def skip_message_emit(parent, s):
981 """
982 Print out a 'skipped' message to stderr
983
984 @param s The string to print out to the log file
Dan Talaycoba3745c2010-07-21 21:51:08 -0700985 """
986 global skipped_test_count
987
988 skipped_test_count += 1
Rich Lane9a003812012-10-04 17:17:59 -0700989 logging.info("Skipping: " + s)
Dan Talayco2940fdd2013-02-06 15:01:35 -0800990 if oftest.config["debug"] < logging.WARNING:
Dan Talaycoba3745c2010-07-21 21:51:08 -0700991 sys.stderr.write("(skipped) ")
992 else:
993 sys.stderr.write("(S)")
Dan Talayco677c0b72011-08-23 22:53:38 -0700994
Dan Talayco8a64e332012-03-28 14:53:20 -0700995
996def all_stats_get(parent):
997 """
998 Get the aggregate stats for all flows in the table
999 @param parent Test instance with controller connection and assert
1000 @returns dict with keys flows, packets, bytes, active (flows),
1001 lookups, matched
1002 """
Rich Lanee717c6e2013-03-12 10:25:50 -07001003 stat_req = ofp.message.aggregate_stats_request()
1004 stat_req.match = ofp.match()
1005 stat_req.match.wildcards = ofp.OFPFW_ALL
Dan Talayco8a64e332012-03-28 14:53:20 -07001006 stat_req.table_id = 0xff
Rich Lanee717c6e2013-03-12 10:25:50 -07001007 stat_req.out_port = ofp.OFPP_NONE
Dan Talayco8a64e332012-03-28 14:53:20 -07001008
1009 rv = {}
1010
Rich Lanec8aaa3e2012-07-26 19:28:02 -07001011 (reply, pkt) = parent.controller.transact(stat_req)
Rich Lane5fd6faf2013-03-11 13:30:20 -07001012 parent.assertTrue(len(reply.entries) == 1, "Did not receive flow stats reply")
Dan Talayco8a64e332012-03-28 14:53:20 -07001013
Rich Lane5fd6faf2013-03-11 13:30:20 -07001014 for obj in reply.entries:
Dan Talayco8a64e332012-03-28 14:53:20 -07001015 (rv["flows"], rv["packets"], rv["bytes"]) = (obj.flow_count,
1016 obj.packet_count, obj.byte_count)
1017 break
1018
Rich Lanee717c6e2013-03-12 10:25:50 -07001019 request = ofp.message.table_stats_request()
Rich Lanec8aaa3e2012-07-26 19:28:02 -07001020 (reply , pkt) = parent.controller.transact(request)
Dan Talayco8a64e332012-03-28 14:53:20 -07001021
1022
1023 (rv["active"], rv["lookups"], rv["matched"]) = (0,0,0)
Rich Lane5fd6faf2013-03-11 13:30:20 -07001024 for obj in reply.entries:
Dan Talayco8a64e332012-03-28 14:53:20 -07001025 rv["active"] += obj.active_count
1026 rv["lookups"] += obj.lookup_count
1027 rv["matched"] += obj.matched_count
1028
1029 return rv
Dan Talayco2baf8b52012-03-30 09:55:42 -07001030
Rich Lane7744e112013-01-11 17:23:57 -08001031_import_blacklist.add('FILTER')
Dan Talayco2baf8b52012-03-30 09:55:42 -07001032FILTER=''.join([(len(repr(chr(x)))==3) and chr(x) or '.'
1033 for x in range(256)])
1034
1035def hex_dump_buffer(src, length=16):
1036 """
1037 Convert src to a hex dump string and return the string
1038 @param src The source buffer
1039 @param length The number of bytes shown in each line
1040 @returns A string showing the hex dump
1041 """
Dan Talaycoc516fa02012-04-12 22:28:43 -07001042 result = ["\n"]
Dan Talayco2baf8b52012-03-30 09:55:42 -07001043 for i in xrange(0, len(src), length):
1044 chars = src[i:i+length]
1045 hex = ' '.join(["%02x" % ord(x) for x in chars])
1046 printable = ''.join(["%s" % ((ord(x) <= 127 and
1047 FILTER[ord(x)]) or '.') for x in chars])
1048 result.append("%04x %-*s %s\n" % (i, length*3, hex, printable))
1049 return ''.join(result)
1050
1051def format_packet(pkt):
1052 return "Packet length %d \n%s" % (len(str(pkt)),
1053 hex_dump_buffer(str(pkt)))
Rich Lane5d7e89a2012-10-26 16:43:13 -07001054
1055def inspect_packet(pkt):
1056 """
1057 Wrapper around scapy's show() method.
1058 @returns A string showing the dissected packet.
1059 """
1060 from cStringIO import StringIO
1061 out = None
1062 backup = sys.stdout
1063 try:
1064 sys.stdout = StringIO()
1065 pkt.show2()
1066 out = sys.stdout.getvalue()
1067 sys.stdout.close()
1068 finally:
1069 sys.stdout = backup
1070 return out
Rich Lane0a4f6372013-01-02 14:40:22 -08001071
1072def nonstandard(cls):
1073 """
Rich Lanecc45b8e2013-01-02 15:55:02 -08001074 Testcase decorator that marks the test as being non-standard.
1075 These tests are not automatically added to the "standard" group.
Rich Lane0a4f6372013-01-02 14:40:22 -08001076 """
Rich Lanecc45b8e2013-01-02 15:55:02 -08001077 cls._nonstandard = True
Rich Lane0a4f6372013-01-02 14:40:22 -08001078 return cls
1079
1080def disabled(cls):
1081 """
Rich Lanecc45b8e2013-01-02 15:55:02 -08001082 Testcase decorator that marks the test as being disabled.
1083 These tests are not automatically added to the "standard" group or
1084 their module's group.
Rich Lane0a4f6372013-01-02 14:40:22 -08001085 """
Rich Lanecc45b8e2013-01-02 15:55:02 -08001086 cls._disabled = True
Rich Lane0a4f6372013-01-02 14:40:22 -08001087 return cls
Rich Lane97e99652013-01-02 17:23:20 -08001088
1089def group(name):
1090 """
1091 Testcase decorator that adds the test to a group.
1092 """
1093 def fn(cls):
1094 if not hasattr(cls, "_groups"):
1095 cls._groups = []
1096 cls._groups.append(name)
1097 return cls
1098 return fn
Rich Lane5a9a1922013-01-11 14:29:30 -08001099
1100def version(ver):
1101 """
1102 Testcase decorator that specifies which versions of OpenFlow the test
1103 supports. The default is 1.0+. This decorator may only be used once.
1104
1105 Supported syntax:
1106 1.0 -> 1.0
1107 1.0,1.2,1.3 -> 1.0, 1.2, 1.3
1108 1.0+ -> 1.0, 1.1, 1.2, 1.3
1109 """
1110 versions = parse_version(ver)
1111 def fn(cls):
1112 cls._versions = versions
1113 return cls
1114 return fn
1115
1116def parse_version(ver):
1117 allowed_versions = ["1.0", "1.1", "1.2", "1.3"]
1118 if re.match("^1\.\d+$", ver):
1119 versions = set([ver])
1120 elif re.match("^(1\.\d+)\+$", ver):
1121 if not ver[:-1] in allowed_versions:
1122 raise ValueError("invalid OpenFlow version %s" % ver[:-1])
1123 versions = set()
1124 if ver != "1.1+": versions.add("1.0")
1125 if ver != "1.2+": versions.add("1.1")
1126 if ver != "1.3+": versions.add("1.2")
1127 versions.add("1.3")
1128 else:
1129 versions = set(ver.split(','))
1130
1131 for version in versions:
1132 if not version in allowed_versions:
1133 raise ValueError("invalid OpenFlow version %s" % version)
1134
1135 return versions
1136
1137assert(parse_version("1.0") == set(["1.0"]))
1138assert(parse_version("1.0,1.2,1.3") == set(["1.0", "1.2", "1.3"]))
1139assert(parse_version("1.0+") == set(["1.0", "1.1", "1.2", "1.3"]))
Rich Lane7744e112013-01-11 17:23:57 -08001140
Rich Laneae3428c2013-03-07 14:37:42 -08001141def get_stats(test, req):
1142 """
1143 Retrieve a list of stats entries. Handles OFPSF_REPLY_MORE.
1144 """
1145 stats = []
1146 reply, _ = test.controller.transact(req)
1147 test.assertTrue(reply is not None, "No response to stats request")
Rich Lane5fd6faf2013-03-11 13:30:20 -07001148 stats.extend(reply.entries)
Rich Lanee717c6e2013-03-12 10:25:50 -07001149 while reply.flags & ofp.OFPSF_REPLY_MORE != 0:
1150 reply, pkt = self.controller.poll(exp_msg=ofp.OFPT_STATS_REPLY)
Rich Laneae3428c2013-03-07 14:37:42 -08001151 test.assertTrue(reply is not None, "No response to stats request")
Rich Lane5fd6faf2013-03-11 13:30:20 -07001152 stats.extend(reply.entries)
Rich Laneae3428c2013-03-07 14:37:42 -08001153 return stats
1154
Rich Lanee717c6e2013-03-12 10:25:50 -07001155def get_flow_stats(test, match, table_id=0xff, out_port=ofp.OFPP_NONE):
Rich Laneae3428c2013-03-07 14:37:42 -08001156 """
1157 Retrieve a list of flow stats entries.
1158 """
Rich Lanee717c6e2013-03-12 10:25:50 -07001159 req = ofp.message.flow_stats_request(match=match,
Rich Laneae3428c2013-03-07 14:37:42 -08001160 table_id=table_id,
1161 out_port=out_port)
1162 return get_stats(test, req)
1163
Rich Lane968b6192013-03-07 15:34:43 -08001164def get_port_stats(test, port_no):
1165 """
1166 Retrieve a list of port stats entries.
1167 """
Rich Lanee717c6e2013-03-12 10:25:50 -07001168 req = ofp.message.port_stats_request(port_no=port_no)
Rich Lane968b6192013-03-07 15:34:43 -08001169 return get_stats(test, req)
1170
Rich Lane6a334922013-03-07 16:14:52 -08001171def get_queue_stats(test, port_no, queue_id):
1172 """
1173 Retrieve a list of queue stats entries.
1174 """
Rich Lanee717c6e2013-03-12 10:25:50 -07001175 req = ofp.message.queue_stats_request(port_no=port_no, queue_id=queue_id)
Rich Lane6a334922013-03-07 16:14:52 -08001176 return get_stats(test, req)
1177
Rich Laneae3428c2013-03-07 14:37:42 -08001178def verify_flow_stats(test, match, table_id=0xff,
Rich Lanee717c6e2013-03-12 10:25:50 -07001179 out_port=ofp.OFPP_NONE,
Rich Laneae3428c2013-03-07 14:37:42 -08001180 initial=[],
1181 pkts=None, bytes=None):
1182 """
1183 Verify that flow stats changed as expected.
1184
1185 Optionally takes an 'initial' list of stats entries, as returned by
1186 get_flow_stats(). If 'initial' is not given the counters are assumed to
1187 begin at 0.
1188 """
1189 def accumulate(stats):
1190 pkts_acc = bytes_acc = 0
1191 for stat in stats:
1192 pkts_acc += stat.packet_count
1193 bytes_acc += stat.byte_count
1194 return (pkts_acc, bytes_acc)
1195
1196 pkts_before, bytes_before = accumulate(initial)
1197
1198 # Wait 10s for counters to update
1199 pkt_diff = byte_diff = None
1200 for i in range(0, 100):
1201 stats = get_flow_stats(test, match, table_id=table_id, out_port=out_port)
1202 pkts_after, bytes_after = accumulate(stats)
1203 pkt_diff = pkts_after - pkts_before
1204 byte_diff = bytes_after - bytes_before
1205 if (pkts == None or pkt_diff >= pkts) and \
1206 (bytes == None or byte_diff >= bytes):
1207 break
Dan Talayco53724732013-03-08 23:54:02 -08001208 time.sleep(0.1)
Rich Laneae3428c2013-03-07 14:37:42 -08001209
1210 if pkts != None:
1211 test.assertEquals(pkt_diff, pkts, "Flow packet counter not updated properly (expected increase of %d, got increase of %d)" % (pkts, pkt_diff))
1212
1213 if bytes != None:
Rich Lane53b96812013-03-07 16:54:50 -08001214 test.assertTrue(byte_diff >= bytes and byte_diff <= bytes*1.1,
1215 "Flow byte counter not updated properly (expected increase of %d, got increase of %d)" % (bytes, byte_diff))
Rich Laneae3428c2013-03-07 14:37:42 -08001216
Rich Lane968b6192013-03-07 15:34:43 -08001217def verify_port_stats(test, port,
1218 initial=[],
1219 tx_pkts=None, rx_pkts=None,
1220 tx_bytes=None, rx_bytes=None):
1221 """
1222 Verify that port stats changed as expected.
1223
1224 Optionally takes an 'initial' list of stats entries, as returned by
1225 get_port_stats(). If 'initial' is not given the counters are assumed to
1226 begin at 0.
1227 """
1228 def accumulate(stats):
1229 tx_pkts_acc = rx_pkts_acc = tx_bytes_acc = rx_bytes_acc = 0
1230 for stat in stats:
1231 tx_pkts_acc += stat.tx_packets
1232 rx_pkts_acc += stat.rx_packets
1233 tx_bytes_acc += stat.tx_bytes
1234 rx_bytes_acc += stat.rx_bytes
1235 return (tx_pkts_acc, rx_pkts_acc, tx_bytes_acc, rx_bytes_acc)
1236
1237 tx_pkts_before, rx_pkts_before, \
1238 tx_bytes_before, rx_bytes_before = accumulate(initial)
1239
1240 # Wait 10s for counters to update
1241 for i in range(0, 100):
1242 stats = get_port_stats(test, port)
1243 tx_pkts_after, rx_pkts_after, \
1244 tx_bytes_after, rx_bytes_after = accumulate(stats)
1245 tx_pkts_diff = tx_pkts_after - tx_pkts_before
1246 rx_pkts_diff = rx_pkts_after - rx_pkts_before
1247 tx_bytes_diff = tx_bytes_after - tx_bytes_before
1248 rx_bytes_diff = rx_bytes_after - rx_bytes_before
1249 if (tx_pkts == None or tx_pkts == tx_pkts_diff) and \
1250 (rx_pkts == None or rx_pkts == rx_pkts_diff) and \
Rich Lane53b96812013-03-07 16:54:50 -08001251 (tx_bytes == None or tx_bytes <= tx_bytes_diff) and \
1252 (rx_bytes == None or rx_bytes <= rx_bytes_diff):
Rich Lane968b6192013-03-07 15:34:43 -08001253 break
1254 time.sleep(0.1)
1255
1256 if (tx_pkts != None):
1257 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))
1258 if (rx_pkts != None):
1259 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))
1260 if (tx_bytes != None):
Rich Lane53b96812013-03-07 16:54:50 -08001261 test.assertTrue(tx_bytes_diff >= tx_bytes and tx_bytes_diff <= tx_bytes*1.1,
1262 "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 -08001263 if (rx_bytes != None):
Rich Lane53b96812013-03-07 16:54:50 -08001264 test.assertTrue(rx_bytes_diff >= rx_bytes and rx_bytes_diff <= rx_bytes*1.1,
1265 "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 -08001266
Rich Lane6a334922013-03-07 16:14:52 -08001267def verify_queue_stats(test, port_no, queue_id,
1268 initial=[],
1269 pkts=None, bytes=None):
1270 """
1271 Verify that queue stats changed as expected.
1272
1273 Optionally takes an 'initial' list of stats entries, as returned by
1274 get_queue_stats(). If 'initial' is not given the counters are assumed to
1275 begin at 0.
1276 """
1277 def accumulate(stats):
1278 pkts_acc = bytes_acc = 0
1279 for stat in stats:
1280 pkts_acc += stat.tx_packets
1281 bytes_acc += stat.tx_bytes
1282 return (pkts_acc, bytes_acc)
1283
1284 pkts_before, bytes_before = accumulate(initial)
1285
1286 # Wait 10s for counters to update
1287 pkt_diff = byte_diff = None
1288 for i in range(0, 100):
1289 stats = get_queue_stats(test, port_no, queue_id)
1290 pkts_after, bytes_after = accumulate(stats)
1291 pkt_diff = pkts_after - pkts_before
1292 byte_diff = bytes_after - bytes_before
1293 if (pkts == None or pkt_diff >= pkts) and \
1294 (bytes == None or byte_diff >= bytes):
1295 break
Dan Talayco53724732013-03-08 23:54:02 -08001296 time.sleep(0.1)
Rich Lane6a334922013-03-07 16:14:52 -08001297
1298 if pkts != None:
1299 test.assertEquals(pkt_diff, pkts, "Queue packet counter not updated properly (expected increase of %d, got increase of %d)" % (pkts, pkt_diff))
1300
1301 if bytes != None:
Rich Lane53b96812013-03-07 16:54:50 -08001302 test.assertTrue(byte_diff >= bytes and byte_diff <= bytes*1.1,
1303 "Queue byte counter not updated properly (expected increase of %d, got increase of %d)" % (bytes, byte_diff))
Rich Laneae3428c2013-03-07 14:37:42 -08001304
Rich Lane7744e112013-01-11 17:23:57 -08001305__all__ = list(set(locals()) - _import_blacklist)