blob: 980099fa82eaeae2adc65d449b19339304ca7b3d [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
676 msg.data = str(pkt)
677 if action_list is not None:
678 for act in action_list:
Rich Lanec495d9e2013-03-08 17:43:36 -0800679 msg.actions.append(act)
Rich Lane89725bb2012-12-03 16:23:27 -0800680
681 # Set up output action
682 if egr_ports is not None:
683 for egr_port in egr_ports:
Rich Lanee717c6e2013-03-12 10:25:50 -0700684 act = ofp.action.output()
Rich Lane89725bb2012-12-03 16:23:27 -0800685 act.port = egr_port
Rich Lanec495d9e2013-03-08 17:43:36 -0800686 msg.actions.append(act)
Rich Lane89725bb2012-12-03 16:23:27 -0800687
688 logging.debug(msg.show())
Rich Lane5c3151c2013-01-03 17:15:41 -0800689 parent.controller.message_send(msg)
Rich Lane89725bb2012-12-03 16:23:27 -0800690
691 if exp_pkt is None:
692 exp_pkt = pkt
693 receive_pkt_verify(parent, egr_ports, exp_pkt, ing_port)
694
Dan Talaycof6e76c02012-03-23 10:56:12 -0700695def get_egr_list(parent, of_ports, how_many, exclude_list=[]):
696 """
697 Generate a list of ports avoiding those in the exclude list
Rich Lane9a003812012-10-04 17:17:59 -0700698 @param parent Supplies logging
Dan Talaycof6e76c02012-03-23 10:56:12 -0700699 @param of_ports List of OF port numbers
700 @param how_many Number of ports to be added to the list
701 @param exclude_list List of ports not to be used
702 @returns An empty list if unable to find enough ports
703 """
704
Dan Talaycoc948d0b2012-03-23 12:17:54 -0700705 if how_many == 0:
706 return []
707
Dan Talaycof6e76c02012-03-23 10:56:12 -0700708 count = 0
709 egr_ports = []
710 for egr_idx in range(len(of_ports)):
711 if of_ports[egr_idx] not in exclude_list:
712 egr_ports.append(of_ports[egr_idx])
713 count += 1
714 if count >= how_many:
715 return egr_ports
Rich Lane9a003812012-10-04 17:17:59 -0700716 logging.debug("Could not generate enough egress ports for test")
Dan Talaycof6e76c02012-03-23 10:56:12 -0700717 return []
718
Rich Laned0478ff2013-03-11 12:46:58 -0700719def flow_match_test(parent, port_map, wildcards=None, vlan_vid=-1, pkt=None,
Rich Lanee5779d32012-10-05 17:56:04 -0700720 exp_pkt=None, action_list=None,
Dan Talaycoc948d0b2012-03-23 12:17:54 -0700721 max_test=0, egr_count=1, ing_port=False):
Dan Talayco551befa2010-07-15 17:05:32 -0700722 """
Rich Lane89725bb2012-12-03 16:23:27 -0800723 Run flow_match_test_port_pair on all port pairs and packet-out
Dan Talayco551befa2010-07-15 17:05:32 -0700724
725 @param max_test If > 0 no more than this number of tests are executed.
726 @param parent Must implement controller, dataplane, assertTrue, assertEqual
Rich Lane9a003812012-10-04 17:17:59 -0700727 and logging
Dan Talayco551befa2010-07-15 17:05:32 -0700728 @param pkt If not None, use this packet for ingress
729 @param wildcards For flow match entry
Rich Laned0478ff2013-03-11 12:46:58 -0700730 @param vlan_vid If not -1, and pkt is None, create a pkt w/ VLAN tag
Dan Talayco551befa2010-07-15 17:05:32 -0700731 @param exp_pkt If not None, use this as the expected output pkt; els use pkt
732 @param action_list Additional actions to add to flow mod
Dan Talaycocfa172f2012-03-23 12:03:00 -0700733 @param egr_count Number of egress ports; -1 means get from config w/ dflt 2
Dan Talayco551befa2010-07-15 17:05:32 -0700734 """
Ed Swierk99a74de2012-08-22 06:40:54 -0700735 if wildcards is None:
736 wildcards = required_wildcards(parent)
Dan Talayco551befa2010-07-15 17:05:32 -0700737 of_ports = port_map.keys()
738 of_ports.sort()
739 parent.assertTrue(len(of_ports) > 1, "Not enough ports for test")
740 test_count = 0
741
Dan Talaycocfa172f2012-03-23 12:03:00 -0700742 if egr_count == -1:
Rich Lane2014f9b2012-10-05 15:29:40 -0700743 egr_count = test_param_get('egr_count', default=2)
Dan Talaycocfa172f2012-03-23 12:03:00 -0700744
Dan Talayco551befa2010-07-15 17:05:32 -0700745 for ing_idx in range(len(of_ports)):
746 ingress_port = of_ports[ing_idx]
Dan Talaycof6e76c02012-03-23 10:56:12 -0700747 egr_ports = get_egr_list(parent, of_ports, egr_count,
748 exclude_list=[ingress_port])
Dan Talaycoc948d0b2012-03-23 12:17:54 -0700749 if ing_port:
Rich Lanee717c6e2013-03-12 10:25:50 -0700750 egr_ports.append(ofp.OFPP_IN_PORT)
Dan Talaycof6e76c02012-03-23 10:56:12 -0700751 if len(egr_ports) == 0:
752 parent.assertTrue(0, "Failed to generate egress port list")
753
754 flow_match_test_port_pair(parent, ingress_port, egr_ports,
Rich Laned0478ff2013-03-11 12:46:58 -0700755 wildcards=wildcards, vlan_vid=vlan_vid,
Dan Talaycof6e76c02012-03-23 10:56:12 -0700756 pkt=pkt, exp_pkt=exp_pkt,
Rich Lanee5779d32012-10-05 17:56:04 -0700757 action_list=action_list)
Dan Talaycof6e76c02012-03-23 10:56:12 -0700758 test_count += 1
759 if (max_test > 0) and (test_count > max_test):
Rich Lane9a003812012-10-04 17:17:59 -0700760 logging.info("Ran " + str(test_count) + " tests; exiting")
Rich Lane89725bb2012-12-03 16:23:27 -0800761 break
762
Ed Swierk38eea082013-01-02 19:46:20 -0800763 if not test_param_get('pktout_actions', default=True):
764 return
Rich Lane89725bb2012-12-03 16:23:27 -0800765
766 ingress_port = of_ports[0]
767 egr_ports = get_egr_list(parent, of_ports, egr_count,
768 exclude_list=[ingress_port])
769 if ing_port:
Rich Lanee717c6e2013-03-12 10:25:50 -0700770 egr_ports.append(ofp.OFPP_IN_PORT)
Rich Lane89725bb2012-12-03 16:23:27 -0800771 flow_match_test_pktout(parent, ingress_port, egr_ports,
Rich Laned0478ff2013-03-11 12:46:58 -0700772 vlan_vid=vlan_vid,
Rich Lane89725bb2012-12-03 16:23:27 -0800773 pkt=pkt, exp_pkt=exp_pkt,
774 action_list=action_list)
Dan Talayco551befa2010-07-15 17:05:32 -0700775
Rich Lane2014f9b2012-10-05 15:29:40 -0700776def test_param_get(key, default=None):
Dan Talayco4b2bee62010-07-20 14:10:05 -0700777 """
778 Return value passed via test-params if present
779
Dan Talayco4b2bee62010-07-20 14:10:05 -0700780 @param key The lookup key
781 @param default Default value to use if not found
782
783 If the pair 'key=val' appeared in the string passed to --test-params
784 on the command line, return val (as interpreted by exec). Otherwise
785 return default value.
Dan Talaycof6e76c02012-03-23 10:56:12 -0700786
787 WARNING: TEST PARAMETERS MUST BE PYTHON IDENTIFIERS;
788 eg egr_count, not egr-count.
Dan Talayco4b2bee62010-07-20 14:10:05 -0700789 """
790 try:
Rich Lanecd97d3d2013-01-07 18:50:06 -0800791 exec oftest.config["test_params"]
Dan Talayco4b2bee62010-07-20 14:10:05 -0700792 except:
793 return default
794
795 s = "val = " + str(key)
796 try:
797 exec s
798 return val
799 except:
800 return default
801
802def action_generate(parent, field_to_mod, mod_field_vals):
803 """
804 Create an action to modify the field indicated in field_to_mod
805
806 @param parent Must implement, assertTrue
807 @param field_to_mod The field to modify as a string name
808 @param mod_field_vals Hash of values to use for modified values
809 """
810
811 act = None
812
813 if field_to_mod in ['pktlen']:
814 return None
815
Rich Laned0478ff2013-03-11 12:46:58 -0700816 if field_to_mod == 'eth_dst':
Rich Lanee717c6e2013-03-12 10:25:50 -0700817 act = ofp.action.set_dl_dst()
Rich Lanef6883512013-03-11 17:00:09 -0700818 act.dl_addr = oftest.parse.parse_mac(mod_field_vals['eth_dst'])
Rich Laned0478ff2013-03-11 12:46:58 -0700819 elif field_to_mod == 'eth_src':
Rich Lanee717c6e2013-03-12 10:25:50 -0700820 act = ofp.action.set_dl_src()
Rich Lanef6883512013-03-11 17:00:09 -0700821 act.dl_addr = oftest.parse.parse_mac(mod_field_vals['eth_src'])
Dan Talayco4b2bee62010-07-20 14:10:05 -0700822 elif field_to_mod == 'dl_vlan_enable':
823 if not mod_field_vals['dl_vlan_enable']: # Strip VLAN tag
Rich Lanee717c6e2013-03-12 10:25:50 -0700824 act = ofp.action.strip_vlan()
Rich Laned0478ff2013-03-11 12:46:58 -0700825 # Add VLAN tag is handled by vlan_vid field
Dan Talayco4b2bee62010-07-20 14:10:05 -0700826 # Will return None in this case
Rich Laned0478ff2013-03-11 12:46:58 -0700827 elif field_to_mod == 'vlan_vid':
Rich Lanee717c6e2013-03-12 10:25:50 -0700828 act = ofp.action.set_vlan_vid()
Rich Laned0478ff2013-03-11 12:46:58 -0700829 act.vlan_vid = mod_field_vals['vlan_vid']
830 elif field_to_mod == 'vlan_pcp':
Rich Lanee717c6e2013-03-12 10:25:50 -0700831 act = ofp.action.set_vlan_pcp()
Rich Laned0478ff2013-03-11 12:46:58 -0700832 act.vlan_pcp = mod_field_vals['vlan_pcp']
Dan Talayco4b2bee62010-07-20 14:10:05 -0700833 elif field_to_mod == 'ip_src':
Rich Lanee717c6e2013-03-12 10:25:50 -0700834 act = ofp.action.set_nw_src()
Rich Lanef6883512013-03-11 17:00:09 -0700835 act.nw_addr = oftest.parse.parse_ip(mod_field_vals['ip_src'])
Dan Talayco4b2bee62010-07-20 14:10:05 -0700836 elif field_to_mod == 'ip_dst':
Rich Lanee717c6e2013-03-12 10:25:50 -0700837 act = ofp.action.set_nw_dst()
Rich Lanef6883512013-03-11 17:00:09 -0700838 act.nw_addr = oftest.parse.parse_ip(mod_field_vals['ip_dst'])
Dan Talayco4b2bee62010-07-20 14:10:05 -0700839 elif field_to_mod == 'ip_tos':
Rich Lanee717c6e2013-03-12 10:25:50 -0700840 act = ofp.action.set_nw_tos()
Dan Talayco4b2bee62010-07-20 14:10:05 -0700841 act.nw_tos = mod_field_vals['ip_tos']
842 elif field_to_mod == 'tcp_sport':
Rich Lanee717c6e2013-03-12 10:25:50 -0700843 act = ofp.action.set_tp_src()
Dan Talayco4b2bee62010-07-20 14:10:05 -0700844 act.tp_port = mod_field_vals['tcp_sport']
845 elif field_to_mod == 'tcp_dport':
Rich Lanee717c6e2013-03-12 10:25:50 -0700846 act = ofp.action.set_tp_dst()
Dan Talayco4b2bee62010-07-20 14:10:05 -0700847 act.tp_port = mod_field_vals['tcp_dport']
Rich Lane110e0e32012-10-26 16:21:46 -0700848 elif field_to_mod == 'udp_sport':
Rich Lanee717c6e2013-03-12 10:25:50 -0700849 act = ofp.action.set_tp_src()
Rich Lane110e0e32012-10-26 16:21:46 -0700850 act.tp_port = mod_field_vals['udp_sport']
851 elif field_to_mod == 'udp_dport':
Rich Lanee717c6e2013-03-12 10:25:50 -0700852 act = ofp.action.set_tp_dst()
Rich Lane110e0e32012-10-26 16:21:46 -0700853 act.tp_port = mod_field_vals['udp_dport']
Dan Talayco4b2bee62010-07-20 14:10:05 -0700854 else:
855 parent.assertTrue(0, "Unknown field to modify: " + str(field_to_mod))
856
857 return act
858
859def pkt_action_setup(parent, start_field_vals={}, mod_field_vals={},
Rich Lane110e0e32012-10-26 16:21:46 -0700860 mod_fields=[], tp="tcp", check_test_params=False):
Dan Talayco4b2bee62010-07-20 14:10:05 -0700861 """
862 Set up the ingress and expected packet and action list for a test
863
Rich Lane2014f9b2012-10-05 15:29:40 -0700864 @param parent Must implement assertTrue
Dan Talayco4b2bee62010-07-20 14:10:05 -0700865 @param start_field_values Field values to use for ingress packet (optional)
866 @param mod_field_values Field values to use for modified packet (optional)
867 @param mod_fields The list of fields to be modified by the switch in the test.
868 @params check_test_params If True, will check the parameters vid, add_vlan
869 and strip_vlan from the command line.
870
871 Returns a triple: pkt-to-send, expected-pkt, action-list
872 """
873
874 new_actions = []
875
Dan Talayco4b2bee62010-07-20 14:10:05 -0700876 base_pkt_params = {}
877 base_pkt_params['pktlen'] = 100
Rich Laned0478ff2013-03-11 12:46:58 -0700878 base_pkt_params['eth_dst'] = '00:DE:F0:12:34:56'
879 base_pkt_params['eth_src'] = '00:23:45:67:89:AB'
Dan Talayco4b2bee62010-07-20 14:10:05 -0700880 base_pkt_params['dl_vlan_enable'] = False
Rich Laned0478ff2013-03-11 12:46:58 -0700881 base_pkt_params['vlan_vid'] = 2
882 base_pkt_params['vlan_pcp'] = 0
Dan Talayco4b2bee62010-07-20 14:10:05 -0700883 base_pkt_params['ip_src'] = '192.168.0.1'
884 base_pkt_params['ip_dst'] = '192.168.0.2'
885 base_pkt_params['ip_tos'] = 0
Rich Lane110e0e32012-10-26 16:21:46 -0700886 if tp == "tcp":
887 base_pkt_params['tcp_sport'] = 1234
888 base_pkt_params['tcp_dport'] = 80
889 elif tp == "udp":
890 base_pkt_params['udp_sport'] = 1234
891 base_pkt_params['udp_dport'] = 80
Dan Talayco4b2bee62010-07-20 14:10:05 -0700892 for keyname in start_field_vals.keys():
893 base_pkt_params[keyname] = start_field_vals[keyname]
894
895 mod_pkt_params = {}
896 mod_pkt_params['pktlen'] = 100
Rich Laned0478ff2013-03-11 12:46:58 -0700897 mod_pkt_params['eth_dst'] = '00:21:0F:ED:CB:A9'
898 mod_pkt_params['eth_src'] = '00:ED:CB:A9:87:65'
Dan Talayco4b2bee62010-07-20 14:10:05 -0700899 mod_pkt_params['dl_vlan_enable'] = False
Rich Laned0478ff2013-03-11 12:46:58 -0700900 mod_pkt_params['vlan_vid'] = 3
901 mod_pkt_params['vlan_pcp'] = 7
Dan Talayco4b2bee62010-07-20 14:10:05 -0700902 mod_pkt_params['ip_src'] = '10.20.30.40'
903 mod_pkt_params['ip_dst'] = '50.60.70.80'
904 mod_pkt_params['ip_tos'] = 0xf0
Rich Lane110e0e32012-10-26 16:21:46 -0700905 if tp == "tcp":
906 mod_pkt_params['tcp_sport'] = 4321
907 mod_pkt_params['tcp_dport'] = 8765
908 elif tp == "udp":
909 mod_pkt_params['udp_sport'] = 4321
910 mod_pkt_params['udp_dport'] = 8765
Dan Talayco4b2bee62010-07-20 14:10:05 -0700911 for keyname in mod_field_vals.keys():
912 mod_pkt_params[keyname] = mod_field_vals[keyname]
913
914 # Check for test param modifications
915 strip = False
916 if check_test_params:
Rich Lane2014f9b2012-10-05 15:29:40 -0700917 add_vlan = test_param_get('add_vlan')
918 strip_vlan = test_param_get('strip_vlan')
919 vid = test_param_get('vid')
Dan Talayco4b2bee62010-07-20 14:10:05 -0700920
921 if add_vlan and strip_vlan:
922 parent.assertTrue(0, "Add and strip VLAN both specified")
923
924 if vid:
925 base_pkt_params['dl_vlan_enable'] = True
Rich Laned0478ff2013-03-11 12:46:58 -0700926 base_pkt_params['vlan_vid'] = vid
927 if 'vlan_vid' in mod_fields:
928 mod_pkt_params['vlan_vid'] = vid + 1
Dan Talayco4b2bee62010-07-20 14:10:05 -0700929
930 if add_vlan:
931 base_pkt_params['dl_vlan_enable'] = False
932 mod_pkt_params['dl_vlan_enable'] = True
933 mod_pkt_params['pktlen'] = base_pkt_params['pktlen'] + 4
934 mod_fields.append('pktlen')
935 mod_fields.append('dl_vlan_enable')
Rich Laned0478ff2013-03-11 12:46:58 -0700936 if 'vlan_vid' not in mod_fields:
937 mod_fields.append('vlan_vid')
Dan Talayco4b2bee62010-07-20 14:10:05 -0700938 elif strip_vlan:
939 base_pkt_params['dl_vlan_enable'] = True
940 mod_pkt_params['dl_vlan_enable'] = False
941 mod_pkt_params['pktlen'] = base_pkt_params['pktlen'] - 4
942 mod_fields.append('dl_vlan_enable')
943 mod_fields.append('pktlen')
944
Rich Lane110e0e32012-10-26 16:21:46 -0700945 if tp == "tcp":
946 packet_builder = simple_tcp_packet
947 elif tp == "udp":
948 packet_builder = simple_udp_packet
949 else:
950 raise NotImplementedError("unknown transport protocol %s" % tp)
951
Dan Talayco4b2bee62010-07-20 14:10:05 -0700952 # Build the ingress packet
Rich Lane110e0e32012-10-26 16:21:46 -0700953 ingress_pkt = packet_builder(**base_pkt_params)
Dan Talayco4b2bee62010-07-20 14:10:05 -0700954
955 # Build the expected packet, modifying the indicated fields
956 for item in mod_fields:
957 base_pkt_params[item] = mod_pkt_params[item]
958 act = action_generate(parent, item, mod_pkt_params)
959 if act:
960 new_actions.append(act)
961
Rich Lane110e0e32012-10-26 16:21:46 -0700962 expected_pkt = packet_builder(**base_pkt_params)
Dan Talayco4b2bee62010-07-20 14:10:05 -0700963
964 return (ingress_pkt, expected_pkt, new_actions)
Dan Talayco677c0b72011-08-23 22:53:38 -0700965
966# Generate a simple "drop" flow mod
967# If in_band is true, then only drop from first test port
968def flow_mod_gen(port_map, in_band):
Rich Lanee717c6e2013-03-12 10:25:50 -0700969 request = ofp.message.flow_add()
970 request.match.wildcards = ofp.OFPFW_ALL
Dan Talayco677c0b72011-08-23 22:53:38 -0700971 if in_band:
Rich Lanee717c6e2013-03-12 10:25:50 -0700972 request.match.wildcards = ofp.OFPFW_ALL - ofp.OFPFW_IN_PORT
Dan Talayco677c0b72011-08-23 22:53:38 -0700973 for of_port, ifname in port_map.items(): # Grab first port
974 break
975 request.match.in_port = of_port
976 request.buffer_id = 0xffffffff
977 return request
Dan Talaycoba3745c2010-07-21 21:51:08 -0700978
979def skip_message_emit(parent, s):
980 """
981 Print out a 'skipped' message to stderr
982
983 @param s The string to print out to the log file
Dan Talaycoba3745c2010-07-21 21:51:08 -0700984 """
985 global skipped_test_count
986
987 skipped_test_count += 1
Rich Lane9a003812012-10-04 17:17:59 -0700988 logging.info("Skipping: " + s)
Dan Talayco2940fdd2013-02-06 15:01:35 -0800989 if oftest.config["debug"] < logging.WARNING:
Dan Talaycoba3745c2010-07-21 21:51:08 -0700990 sys.stderr.write("(skipped) ")
991 else:
992 sys.stderr.write("(S)")
Dan Talayco677c0b72011-08-23 22:53:38 -0700993
Dan Talayco8a64e332012-03-28 14:53:20 -0700994
995def all_stats_get(parent):
996 """
997 Get the aggregate stats for all flows in the table
998 @param parent Test instance with controller connection and assert
999 @returns dict with keys flows, packets, bytes, active (flows),
1000 lookups, matched
1001 """
Rich Lanee717c6e2013-03-12 10:25:50 -07001002 stat_req = ofp.message.aggregate_stats_request()
1003 stat_req.match = ofp.match()
1004 stat_req.match.wildcards = ofp.OFPFW_ALL
Dan Talayco8a64e332012-03-28 14:53:20 -07001005 stat_req.table_id = 0xff
Rich Lanee717c6e2013-03-12 10:25:50 -07001006 stat_req.out_port = ofp.OFPP_NONE
Dan Talayco8a64e332012-03-28 14:53:20 -07001007
1008 rv = {}
1009
Rich Lanec8aaa3e2012-07-26 19:28:02 -07001010 (reply, pkt) = parent.controller.transact(stat_req)
Rich Lane5fd6faf2013-03-11 13:30:20 -07001011 parent.assertTrue(len(reply.entries) == 1, "Did not receive flow stats reply")
Dan Talayco8a64e332012-03-28 14:53:20 -07001012
Rich Lane5fd6faf2013-03-11 13:30:20 -07001013 for obj in reply.entries:
Dan Talayco8a64e332012-03-28 14:53:20 -07001014 (rv["flows"], rv["packets"], rv["bytes"]) = (obj.flow_count,
1015 obj.packet_count, obj.byte_count)
1016 break
1017
Rich Lanee717c6e2013-03-12 10:25:50 -07001018 request = ofp.message.table_stats_request()
Rich Lanec8aaa3e2012-07-26 19:28:02 -07001019 (reply , pkt) = parent.controller.transact(request)
Dan Talayco8a64e332012-03-28 14:53:20 -07001020
1021
1022 (rv["active"], rv["lookups"], rv["matched"]) = (0,0,0)
Rich Lane5fd6faf2013-03-11 13:30:20 -07001023 for obj in reply.entries:
Dan Talayco8a64e332012-03-28 14:53:20 -07001024 rv["active"] += obj.active_count
1025 rv["lookups"] += obj.lookup_count
1026 rv["matched"] += obj.matched_count
1027
1028 return rv
Dan Talayco2baf8b52012-03-30 09:55:42 -07001029
Rich Lane7744e112013-01-11 17:23:57 -08001030_import_blacklist.add('FILTER')
Dan Talayco2baf8b52012-03-30 09:55:42 -07001031FILTER=''.join([(len(repr(chr(x)))==3) and chr(x) or '.'
1032 for x in range(256)])
1033
1034def hex_dump_buffer(src, length=16):
1035 """
1036 Convert src to a hex dump string and return the string
1037 @param src The source buffer
1038 @param length The number of bytes shown in each line
1039 @returns A string showing the hex dump
1040 """
Dan Talaycoc516fa02012-04-12 22:28:43 -07001041 result = ["\n"]
Dan Talayco2baf8b52012-03-30 09:55:42 -07001042 for i in xrange(0, len(src), length):
1043 chars = src[i:i+length]
1044 hex = ' '.join(["%02x" % ord(x) for x in chars])
1045 printable = ''.join(["%s" % ((ord(x) <= 127 and
1046 FILTER[ord(x)]) or '.') for x in chars])
1047 result.append("%04x %-*s %s\n" % (i, length*3, hex, printable))
1048 return ''.join(result)
1049
1050def format_packet(pkt):
1051 return "Packet length %d \n%s" % (len(str(pkt)),
1052 hex_dump_buffer(str(pkt)))
Rich Lane5d7e89a2012-10-26 16:43:13 -07001053
1054def inspect_packet(pkt):
1055 """
1056 Wrapper around scapy's show() method.
1057 @returns A string showing the dissected packet.
1058 """
1059 from cStringIO import StringIO
1060 out = None
1061 backup = sys.stdout
1062 try:
1063 sys.stdout = StringIO()
1064 pkt.show2()
1065 out = sys.stdout.getvalue()
1066 sys.stdout.close()
1067 finally:
1068 sys.stdout = backup
1069 return out
Rich Lane0a4f6372013-01-02 14:40:22 -08001070
1071def nonstandard(cls):
1072 """
Rich Lanecc45b8e2013-01-02 15:55:02 -08001073 Testcase decorator that marks the test as being non-standard.
1074 These tests are not automatically added to the "standard" group.
Rich Lane0a4f6372013-01-02 14:40:22 -08001075 """
Rich Lanecc45b8e2013-01-02 15:55:02 -08001076 cls._nonstandard = True
Rich Lane0a4f6372013-01-02 14:40:22 -08001077 return cls
1078
1079def disabled(cls):
1080 """
Rich Lanecc45b8e2013-01-02 15:55:02 -08001081 Testcase decorator that marks the test as being disabled.
1082 These tests are not automatically added to the "standard" group or
1083 their module's group.
Rich Lane0a4f6372013-01-02 14:40:22 -08001084 """
Rich Lanecc45b8e2013-01-02 15:55:02 -08001085 cls._disabled = True
Rich Lane0a4f6372013-01-02 14:40:22 -08001086 return cls
Rich Lane97e99652013-01-02 17:23:20 -08001087
1088def group(name):
1089 """
1090 Testcase decorator that adds the test to a group.
1091 """
1092 def fn(cls):
1093 if not hasattr(cls, "_groups"):
1094 cls._groups = []
1095 cls._groups.append(name)
1096 return cls
1097 return fn
Rich Lane5a9a1922013-01-11 14:29:30 -08001098
1099def version(ver):
1100 """
1101 Testcase decorator that specifies which versions of OpenFlow the test
1102 supports. The default is 1.0+. This decorator may only be used once.
1103
1104 Supported syntax:
1105 1.0 -> 1.0
1106 1.0,1.2,1.3 -> 1.0, 1.2, 1.3
1107 1.0+ -> 1.0, 1.1, 1.2, 1.3
1108 """
1109 versions = parse_version(ver)
1110 def fn(cls):
1111 cls._versions = versions
1112 return cls
1113 return fn
1114
1115def parse_version(ver):
1116 allowed_versions = ["1.0", "1.1", "1.2", "1.3"]
1117 if re.match("^1\.\d+$", ver):
1118 versions = set([ver])
1119 elif re.match("^(1\.\d+)\+$", ver):
1120 if not ver[:-1] in allowed_versions:
1121 raise ValueError("invalid OpenFlow version %s" % ver[:-1])
1122 versions = set()
1123 if ver != "1.1+": versions.add("1.0")
1124 if ver != "1.2+": versions.add("1.1")
1125 if ver != "1.3+": versions.add("1.2")
1126 versions.add("1.3")
1127 else:
1128 versions = set(ver.split(','))
1129
1130 for version in versions:
1131 if not version in allowed_versions:
1132 raise ValueError("invalid OpenFlow version %s" % version)
1133
1134 return versions
1135
1136assert(parse_version("1.0") == set(["1.0"]))
1137assert(parse_version("1.0,1.2,1.3") == set(["1.0", "1.2", "1.3"]))
1138assert(parse_version("1.0+") == set(["1.0", "1.1", "1.2", "1.3"]))
Rich Lane7744e112013-01-11 17:23:57 -08001139
Rich Laneae3428c2013-03-07 14:37:42 -08001140def get_stats(test, req):
1141 """
1142 Retrieve a list of stats entries. Handles OFPSF_REPLY_MORE.
1143 """
1144 stats = []
1145 reply, _ = test.controller.transact(req)
1146 test.assertTrue(reply is not None, "No response to stats request")
Rich Lane5fd6faf2013-03-11 13:30:20 -07001147 stats.extend(reply.entries)
Rich Lanee717c6e2013-03-12 10:25:50 -07001148 while reply.flags & ofp.OFPSF_REPLY_MORE != 0:
1149 reply, pkt = self.controller.poll(exp_msg=ofp.OFPT_STATS_REPLY)
Rich Laneae3428c2013-03-07 14:37:42 -08001150 test.assertTrue(reply is not None, "No response to stats request")
Rich Lane5fd6faf2013-03-11 13:30:20 -07001151 stats.extend(reply.entries)
Rich Laneae3428c2013-03-07 14:37:42 -08001152 return stats
1153
Rich Lanee717c6e2013-03-12 10:25:50 -07001154def get_flow_stats(test, match, table_id=0xff, out_port=ofp.OFPP_NONE):
Rich Laneae3428c2013-03-07 14:37:42 -08001155 """
1156 Retrieve a list of flow stats entries.
1157 """
Rich Lanee717c6e2013-03-12 10:25:50 -07001158 req = ofp.message.flow_stats_request(match=match,
Rich Laneae3428c2013-03-07 14:37:42 -08001159 table_id=table_id,
1160 out_port=out_port)
1161 return get_stats(test, req)
1162
Rich Lane968b6192013-03-07 15:34:43 -08001163def get_port_stats(test, port_no):
1164 """
1165 Retrieve a list of port stats entries.
1166 """
Rich Lanee717c6e2013-03-12 10:25:50 -07001167 req = ofp.message.port_stats_request(port_no=port_no)
Rich Lane968b6192013-03-07 15:34:43 -08001168 return get_stats(test, req)
1169
Rich Lane6a334922013-03-07 16:14:52 -08001170def get_queue_stats(test, port_no, queue_id):
1171 """
1172 Retrieve a list of queue stats entries.
1173 """
Rich Lanee717c6e2013-03-12 10:25:50 -07001174 req = ofp.message.queue_stats_request(port_no=port_no, queue_id=queue_id)
Rich Lane6a334922013-03-07 16:14:52 -08001175 return get_stats(test, req)
1176
Rich Laneae3428c2013-03-07 14:37:42 -08001177def verify_flow_stats(test, match, table_id=0xff,
Rich Lanee717c6e2013-03-12 10:25:50 -07001178 out_port=ofp.OFPP_NONE,
Rich Laneae3428c2013-03-07 14:37:42 -08001179 initial=[],
1180 pkts=None, bytes=None):
1181 """
1182 Verify that flow stats changed as expected.
1183
1184 Optionally takes an 'initial' list of stats entries, as returned by
1185 get_flow_stats(). If 'initial' is not given the counters are assumed to
1186 begin at 0.
1187 """
1188 def accumulate(stats):
1189 pkts_acc = bytes_acc = 0
1190 for stat in stats:
1191 pkts_acc += stat.packet_count
1192 bytes_acc += stat.byte_count
1193 return (pkts_acc, bytes_acc)
1194
1195 pkts_before, bytes_before = accumulate(initial)
1196
1197 # Wait 10s for counters to update
1198 pkt_diff = byte_diff = None
1199 for i in range(0, 100):
1200 stats = get_flow_stats(test, match, table_id=table_id, out_port=out_port)
1201 pkts_after, bytes_after = accumulate(stats)
1202 pkt_diff = pkts_after - pkts_before
1203 byte_diff = bytes_after - bytes_before
1204 if (pkts == None or pkt_diff >= pkts) and \
1205 (bytes == None or byte_diff >= bytes):
1206 break
Dan Talayco53724732013-03-08 23:54:02 -08001207 time.sleep(0.1)
Rich Laneae3428c2013-03-07 14:37:42 -08001208
1209 if pkts != None:
1210 test.assertEquals(pkt_diff, pkts, "Flow packet counter not updated properly (expected increase of %d, got increase of %d)" % (pkts, pkt_diff))
1211
1212 if bytes != None:
Rich Lane53b96812013-03-07 16:54:50 -08001213 test.assertTrue(byte_diff >= bytes and byte_diff <= bytes*1.1,
1214 "Flow byte counter not updated properly (expected increase of %d, got increase of %d)" % (bytes, byte_diff))
Rich Laneae3428c2013-03-07 14:37:42 -08001215
Rich Lane968b6192013-03-07 15:34:43 -08001216def verify_port_stats(test, port,
1217 initial=[],
1218 tx_pkts=None, rx_pkts=None,
1219 tx_bytes=None, rx_bytes=None):
1220 """
1221 Verify that port stats changed as expected.
1222
1223 Optionally takes an 'initial' list of stats entries, as returned by
1224 get_port_stats(). If 'initial' is not given the counters are assumed to
1225 begin at 0.
1226 """
1227 def accumulate(stats):
1228 tx_pkts_acc = rx_pkts_acc = tx_bytes_acc = rx_bytes_acc = 0
1229 for stat in stats:
1230 tx_pkts_acc += stat.tx_packets
1231 rx_pkts_acc += stat.rx_packets
1232 tx_bytes_acc += stat.tx_bytes
1233 rx_bytes_acc += stat.rx_bytes
1234 return (tx_pkts_acc, rx_pkts_acc, tx_bytes_acc, rx_bytes_acc)
1235
1236 tx_pkts_before, rx_pkts_before, \
1237 tx_bytes_before, rx_bytes_before = accumulate(initial)
1238
1239 # Wait 10s for counters to update
1240 for i in range(0, 100):
1241 stats = get_port_stats(test, port)
1242 tx_pkts_after, rx_pkts_after, \
1243 tx_bytes_after, rx_bytes_after = accumulate(stats)
1244 tx_pkts_diff = tx_pkts_after - tx_pkts_before
1245 rx_pkts_diff = rx_pkts_after - rx_pkts_before
1246 tx_bytes_diff = tx_bytes_after - tx_bytes_before
1247 rx_bytes_diff = rx_bytes_after - rx_bytes_before
1248 if (tx_pkts == None or tx_pkts == tx_pkts_diff) and \
1249 (rx_pkts == None or rx_pkts == rx_pkts_diff) and \
Rich Lane53b96812013-03-07 16:54:50 -08001250 (tx_bytes == None or tx_bytes <= tx_bytes_diff) and \
1251 (rx_bytes == None or rx_bytes <= rx_bytes_diff):
Rich Lane968b6192013-03-07 15:34:43 -08001252 break
1253 time.sleep(0.1)
1254
1255 if (tx_pkts != None):
1256 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))
1257 if (rx_pkts != None):
1258 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))
1259 if (tx_bytes != None):
Rich Lane53b96812013-03-07 16:54:50 -08001260 test.assertTrue(tx_bytes_diff >= tx_bytes and tx_bytes_diff <= tx_bytes*1.1,
1261 "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 -08001262 if (rx_bytes != None):
Rich Lane53b96812013-03-07 16:54:50 -08001263 test.assertTrue(rx_bytes_diff >= rx_bytes and rx_bytes_diff <= rx_bytes*1.1,
1264 "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 -08001265
Rich Lane6a334922013-03-07 16:14:52 -08001266def verify_queue_stats(test, port_no, queue_id,
1267 initial=[],
1268 pkts=None, bytes=None):
1269 """
1270 Verify that queue stats changed as expected.
1271
1272 Optionally takes an 'initial' list of stats entries, as returned by
1273 get_queue_stats(). If 'initial' is not given the counters are assumed to
1274 begin at 0.
1275 """
1276 def accumulate(stats):
1277 pkts_acc = bytes_acc = 0
1278 for stat in stats:
1279 pkts_acc += stat.tx_packets
1280 bytes_acc += stat.tx_bytes
1281 return (pkts_acc, bytes_acc)
1282
1283 pkts_before, bytes_before = accumulate(initial)
1284
1285 # Wait 10s for counters to update
1286 pkt_diff = byte_diff = None
1287 for i in range(0, 100):
1288 stats = get_queue_stats(test, port_no, queue_id)
1289 pkts_after, bytes_after = accumulate(stats)
1290 pkt_diff = pkts_after - pkts_before
1291 byte_diff = bytes_after - bytes_before
1292 if (pkts == None or pkt_diff >= pkts) and \
1293 (bytes == None or byte_diff >= bytes):
1294 break
Dan Talayco53724732013-03-08 23:54:02 -08001295 time.sleep(0.1)
Rich Lane6a334922013-03-07 16:14:52 -08001296
1297 if pkts != None:
1298 test.assertEquals(pkt_diff, pkts, "Queue packet counter not updated properly (expected increase of %d, got increase of %d)" % (pkts, pkt_diff))
1299
1300 if bytes != None:
Rich Lane53b96812013-03-07 16:54:50 -08001301 test.assertTrue(byte_diff >= bytes and byte_diff <= bytes*1.1,
1302 "Queue byte counter not updated properly (expected increase of %d, got increase of %d)" % (bytes, byte_diff))
Rich Laneae3428c2013-03-07 14:37:42 -08001303
Rich Lane7744e112013-01-11 17:23:57 -08001304__all__ = list(set(locals()) - _import_blacklist)