blob: a1db2e0ab0541a53ba54ab987834db04add16ece [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 Laned7b0ffa2013-03-08 15:53:42 -080019import of10
Rich Lanecd97d3d2013-01-07 18:50:06 -080020import of10.message
21import of10.action
22import of10.parse
Dan Talaycoc901f4d2010-03-07 21:55:45 -080023
Dan Talaycoba3745c2010-07-21 21:51:08 -070024global skipped_test_count
25skipped_test_count = 0
26
Rich Lane7744e112013-01-11 17:23:57 -080027_import_blacklist = set(locals().keys())
28
Dan Talayco551befa2010-07-15 17:05:32 -070029# Some useful defines
30IP_ETHERTYPE = 0x800
31TCP_PROTOCOL = 0x6
32UDP_PROTOCOL = 0x11
33
Jeffrey Townsend5cb7ed32012-08-17 18:11:01 +000034MINSIZE = 0
35
Rich Lane9a003812012-10-04 17:17:59 -070036def delete_all_flows(ctrl):
Dan Talayco41eae8b2010-03-10 13:57:06 -080037 """
38 Delete all flows on the switch
39 @param ctrl The controller object for the test
Dan Talayco41eae8b2010-03-10 13:57:06 -080040 """
41
Rich Lane9a003812012-10-04 17:17:59 -070042 logging.info("Deleting all flows")
Rich Laneba3f0e22013-03-11 16:43:57 -070043 msg = of10.message.flow_delete()
Rich Laned7b0ffa2013-03-08 15:53:42 -080044 msg.match.wildcards = of10.OFPFW_ALL
45 msg.out_port = of10.OFPP_NONE
Dan Talaycoc901f4d2010-03-07 21:55:45 -080046 msg.buffer_id = 0xffffffff
Rich Lane5c3151c2013-01-03 17:15:41 -080047 ctrl.message_send(msg)
Rich Lane32bf9482013-01-03 17:26:30 -080048 return 0 # for backwards compatibility
Dan Talayco41eae8b2010-03-10 13:57:06 -080049
Ed Swierk99a74de2012-08-22 06:40:54 -070050def required_wildcards(parent):
Rich Lane2014f9b2012-10-05 15:29:40 -070051 w = test_param_get('required_wildcards', default='default')
Ed Swierk99a74de2012-08-22 06:40:54 -070052 if w == 'l3-l4':
Rich Laned7b0ffa2013-03-08 15:53:42 -080053 return (of10.OFPFW_NW_SRC_ALL | of10.OFPFW_NW_DST_ALL | of10.OFPFW_NW_TOS
54 | of10.OFPFW_NW_PROTO | of10.OFPFW_TP_SRC | of10.OFPFW_TP_DST)
Ed Swierk99a74de2012-08-22 06:40:54 -070055 else:
56 return 0
57
Dan Talayco41eae8b2010-03-10 13:57:06 -080058def simple_tcp_packet(pktlen=100,
Rich Laned0478ff2013-03-11 12:46:58 -070059 eth_dst='00:01:02:03:04:05',
60 eth_src='00:06:07:08:09:0a',
Tatsuya Yabe460321e2010-05-25 17:50:49 -070061 dl_vlan_enable=False,
Rich Laned0478ff2013-03-11 12:46:58 -070062 vlan_vid=0,
63 vlan_pcp=0,
Dan Talayco551befa2010-07-15 17:05:32 -070064 dl_vlan_cfi=0,
Dan Talayco41eae8b2010-03-10 13:57:06 -080065 ip_src='192.168.0.1',
66 ip_dst='192.168.0.2',
Tatsuya Yabe460321e2010-05-25 17:50:49 -070067 ip_tos=0,
Gregor Maier9cc93342013-01-29 16:55:28 -080068 ip_ttl=64,
Dan Talayco41eae8b2010-03-10 13:57:06 -080069 tcp_sport=1234,
Christian Dickmann8b59b4b2012-09-23 16:48:30 -070070 tcp_dport=80,
71 ip_ihl=None,
72 ip_options=False
Dan Talayco41eae8b2010-03-10 13:57:06 -080073 ):
74 """
75 Return a simple dataplane TCP packet
76
77 Supports a few parameters:
78 @param len Length of packet in bytes w/o CRC
Rich Laned0478ff2013-03-11 12:46:58 -070079 @param eth_dst Destinatino MAC
80 @param eth_src Source MAC
Tatsuya Yabe460321e2010-05-25 17:50:49 -070081 @param dl_vlan_enable True if the packet is with vlan, False otherwise
Rich Laned0478ff2013-03-11 12:46:58 -070082 @param vlan_vid VLAN ID
83 @param vlan_pcp VLAN priority
Dan Talayco41eae8b2010-03-10 13:57:06 -080084 @param ip_src IP source
85 @param ip_dst IP destination
Tatsuya Yabe460321e2010-05-25 17:50:49 -070086 @param ip_tos IP ToS
Gregor Maier9cc93342013-01-29 16:55:28 -080087 @param ip_ttl IP TTL
Dan Talayco41eae8b2010-03-10 13:57:06 -080088 @param tcp_dport TCP destination port
89 @param ip_sport TCP source port
90
91 Generates a simple TCP request. Users
92 shouldn't assume anything about this packet other than that
93 it is a valid ethernet/IP/TCP frame.
94 """
Jeffrey Townsend5cb7ed32012-08-17 18:11:01 +000095
96 if MINSIZE > pktlen:
97 pktlen = MINSIZE
98
Dan Talayco551befa2010-07-15 17:05:32 -070099 # Note Dot1Q.id is really CFI
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800100 if (dl_vlan_enable):
Rich Laned0478ff2013-03-11 12:46:58 -0700101 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
102 scapy.Dot1Q(prio=vlan_pcp, id=dl_vlan_cfi, vlan=vlan_vid)/ \
Gregor Maier9cc93342013-01-29 16:55:28 -0800103 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ttl=ip_ttl, ihl=ip_ihl)/ \
Tatsuya Yabe460321e2010-05-25 17:50:49 -0700104 scapy.TCP(sport=tcp_sport, dport=tcp_dport)
105 else:
Christian Dickmann8b59b4b2012-09-23 16:48:30 -0700106 if not ip_options:
Rich Laned0478ff2013-03-11 12:46:58 -0700107 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
Gregor Maier9cc93342013-01-29 16:55:28 -0800108 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ttl=ip_ttl, ihl=ip_ihl)/ \
Christian Dickmann8b59b4b2012-09-23 16:48:30 -0700109 scapy.TCP(sport=tcp_sport, dport=tcp_dport)
110 else:
Rich Laned0478ff2013-03-11 12:46:58 -0700111 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
Gregor Maier9cc93342013-01-29 16:55:28 -0800112 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 -0700113 scapy.TCP(sport=tcp_sport, dport=tcp_dport)
Tatsuya Yabe460321e2010-05-25 17:50:49 -0700114
Dan Talayco41eae8b2010-03-10 13:57:06 -0800115 pkt = pkt/("D" * (pktlen - len(pkt)))
116
117 return pkt
118
Rich Lane6ee7bea2012-10-26 16:19:29 -0700119def simple_udp_packet(pktlen=100,
Rich Laned0478ff2013-03-11 12:46:58 -0700120 eth_dst='00:01:02:03:04:05',
121 eth_src='00:06:07:08:09:0a',
Rich Lane6ee7bea2012-10-26 16:19:29 -0700122 dl_vlan_enable=False,
Rich Laned0478ff2013-03-11 12:46:58 -0700123 vlan_vid=0,
124 vlan_pcp=0,
Rich Lane6ee7bea2012-10-26 16:19:29 -0700125 dl_vlan_cfi=0,
126 ip_src='192.168.0.1',
127 ip_dst='192.168.0.2',
128 ip_tos=0,
Gregor Maier9cc93342013-01-29 16:55:28 -0800129 ip_ttl=64,
Rich Lane6ee7bea2012-10-26 16:19:29 -0700130 udp_sport=1234,
131 udp_dport=80,
132 ip_ihl=None,
133 ip_options=False
134 ):
135 """
136 Return a simple dataplane UDP packet
137
138 Supports a few parameters:
139 @param len Length of packet in bytes w/o CRC
Rich Laned0478ff2013-03-11 12:46:58 -0700140 @param eth_dst Destination MAC
141 @param eth_src Source MAC
Rich Lane6ee7bea2012-10-26 16:19:29 -0700142 @param dl_vlan_enable True if the packet is with vlan, False otherwise
Rich Laned0478ff2013-03-11 12:46:58 -0700143 @param vlan_vid VLAN ID
144 @param vlan_pcp VLAN priority
Rich Lane6ee7bea2012-10-26 16:19:29 -0700145 @param ip_src IP source
146 @param ip_dst IP destination
147 @param ip_tos IP ToS
Gregor Maier9cc93342013-01-29 16:55:28 -0800148 @param ip_ttl IP TTL
Rich Lane6ee7bea2012-10-26 16:19:29 -0700149 @param udp_dport UDP destination port
150 @param udp_sport UDP source port
151
152 Generates a simple UDP packet. Users shouldn't assume anything about
153 this packet other than that it is a valid ethernet/IP/UDP frame.
154 """
155
156 if MINSIZE > pktlen:
157 pktlen = MINSIZE
158
159 # Note Dot1Q.id is really CFI
160 if (dl_vlan_enable):
Rich Laned0478ff2013-03-11 12:46:58 -0700161 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
162 scapy.Dot1Q(prio=vlan_pcp, id=dl_vlan_cfi, vlan=vlan_vid)/ \
Gregor Maier9cc93342013-01-29 16:55:28 -0800163 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ttl=ip_ttl, ihl=ip_ihl)/ \
Rich Lane6ee7bea2012-10-26 16:19:29 -0700164 scapy.UDP(sport=udp_sport, dport=udp_dport)
165 else:
166 if not ip_options:
Rich Laned0478ff2013-03-11 12:46:58 -0700167 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
Gregor Maier9cc93342013-01-29 16:55:28 -0800168 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ttl=ip_ttl, ihl=ip_ihl)/ \
Rich Lane6ee7bea2012-10-26 16:19:29 -0700169 scapy.UDP(sport=udp_sport, dport=udp_dport)
170 else:
Rich Laned0478ff2013-03-11 12:46:58 -0700171 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
Gregor Maier9cc93342013-01-29 16:55:28 -0800172 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 -0700173 scapy.UDP(sport=udp_sport, dport=udp_dport)
174
175 pkt = pkt/("D" * (pktlen - len(pkt)))
176
177 return pkt
178
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700179def simple_icmp_packet(pktlen=60,
Rich Laned0478ff2013-03-11 12:46:58 -0700180 eth_dst='00:01:02:03:04:05',
181 eth_src='00:06:07:08:09:0a',
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700182 dl_vlan_enable=False,
Rich Laned0478ff2013-03-11 12:46:58 -0700183 vlan_vid=0,
184 vlan_pcp=0,
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700185 ip_src='192.168.0.1',
186 ip_dst='192.168.0.2',
187 ip_tos=0,
Gregor Maier9cc93342013-01-29 16:55:28 -0800188 ip_ttl=64,
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700189 icmp_type=8,
190 icmp_code=0
191 ):
192 """
193 Return a simple ICMP packet
194
195 Supports a few parameters:
196 @param len Length of packet in bytes w/o CRC
Rich Laned0478ff2013-03-11 12:46:58 -0700197 @param eth_dst Destinatino MAC
198 @param eth_src Source MAC
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700199 @param dl_vlan_enable True if the packet is with vlan, False otherwise
Rich Laned0478ff2013-03-11 12:46:58 -0700200 @param vlan_vid VLAN ID
201 @param vlan_pcp VLAN priority
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700202 @param ip_src IP source
203 @param ip_dst IP destination
204 @param ip_tos IP ToS
Gregor Maier9cc93342013-01-29 16:55:28 -0800205 @param ip_ttl IP TTL
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700206 @param icmp_type ICMP type
207 @param icmp_code ICMP code
208
209 Generates a simple ICMP ECHO REQUEST. Users
210 shouldn't assume anything about this packet other than that
211 it is a valid ethernet/ICMP frame.
212 """
Jeffrey Townsend5cb7ed32012-08-17 18:11:01 +0000213
214 if MINSIZE > pktlen:
215 pktlen = MINSIZE
216
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700217 if (dl_vlan_enable):
Rich Laned0478ff2013-03-11 12:46:58 -0700218 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
219 scapy.Dot1Q(prio=vlan_pcp, id=0, vlan=vlan_vid)/ \
Gregor Maier9cc93342013-01-29 16:55:28 -0800220 scapy.IP(src=ip_src, dst=ip_dst, ttl=ip_ttl, tos=ip_tos)/ \
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700221 scapy.ICMP(type=icmp_type, code=icmp_code)
222 else:
Rich Laned0478ff2013-03-11 12:46:58 -0700223 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
Gregor Maier9cc93342013-01-29 16:55:28 -0800224 scapy.IP(src=ip_src, dst=ip_dst, ttl=ip_ttl, tos=ip_tos)/ \
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700225 scapy.ICMP(type=icmp_type, code=icmp_code)
226
227 pkt = pkt/("0" * (pktlen - len(pkt)))
228
229 return pkt
230
Shudong Zhouc7562b12013-02-06 01:12:18 -0800231def simple_arp_packet(pktlen=60,
Rich Laned0478ff2013-03-11 12:46:58 -0700232 eth_dst='ff:ff:ff:ff:ff:ff',
233 eth_src='00:06:07:08:09:0a',
Shudong Zhouc7562b12013-02-06 01:12:18 -0800234 arp_op=1,
235 ip_snd='192.168.0.1',
236 ip_tgt='192.168.0.2',
237 hw_snd='00:06:07:08:09:0a',
238 hw_tgt='00:00:00:00:00:00',
239 ):
240 """
241 Return a simple ARP packet
242
243 Supports a few parameters:
244 @param len Length of packet in bytes w/o CRC
Rich Laned0478ff2013-03-11 12:46:58 -0700245 @param eth_dst Destinatino MAC
246 @param eth_src Source MAC
Shudong Zhouc7562b12013-02-06 01:12:18 -0800247 @param arp_op Operation (1=request, 2=reply)
248 @param ip_snd Sender IP
249 @param ip_tgt Target IP
250 @param hw_snd Sender hardware address
251 @param hw_tgt Target hardware address
252
253 Generates a simple ARP REQUEST. Users
254 shouldn't assume anything about this packet other than that
255 it is a valid ethernet/ARP frame.
256 """
257
258 if MINSIZE > pktlen:
259 pktlen = MINSIZE
260
Rich Laned0478ff2013-03-11 12:46:58 -0700261 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
Shudong Zhouc7562b12013-02-06 01:12:18 -0800262 scapy.ARP(hwsrc=hw_snd, hwdst=hw_tgt, pdst=ip_tgt, psrc=ip_snd, op=arp_op)
263
264 pkt = pkt/("0" * (pktlen - len(pkt)))
265
266 return pkt
267
Ed Swierk0aeff8c2012-03-23 20:27:18 -0700268def simple_eth_packet(pktlen=60,
Rich Laned0478ff2013-03-11 12:46:58 -0700269 eth_dst='00:01:02:03:04:05',
270 eth_src='01:80:c2:00:00:00',
271 eth_type=0x88cc):
Jeffrey Townsend5cb7ed32012-08-17 18:11:01 +0000272
273 if MINSIZE > pktlen:
274 pktlen = MINSIZE
275
Rich Laned0478ff2013-03-11 12:46:58 -0700276 pkt = scapy.Ether(dst=eth_dst, src=eth_src, type=eth_type)
Ed Swierk0aeff8c2012-03-23 20:27:18 -0700277
278 pkt = pkt/("0" * (pktlen - len(pkt)))
279
280 return pkt
281
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800282def qinq_tcp_packet(pktlen=100,
Rich Laned0478ff2013-03-11 12:46:58 -0700283 eth_dst='00:01:02:03:04:05',
284 eth_src='00:06:07:08:09:0a',
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800285 dl_vlan_outer=20,
286 dl_vlan_pcp_outer=0,
287 dl_vlan_cfi_outer=0,
Rich Laned0478ff2013-03-11 12:46:58 -0700288 vlan_vid=10,
289 vlan_pcp=0,
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800290 dl_vlan_cfi=0,
291 ip_src='192.168.0.1',
292 ip_dst='192.168.0.2',
293 ip_tos=0,
Gregor Maier9cc93342013-01-29 16:55:28 -0800294 ip_ttl=64,
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800295 tcp_sport=1234,
296 tcp_dport=80,
297 ip_ihl=None,
298 ip_options=False
299 ):
300 """
301 Return a doubly tagged dataplane TCP packet
302
303 Supports a few parameters:
304 @param len Length of packet in bytes w/o CRC
Rich Laned0478ff2013-03-11 12:46:58 -0700305 @param eth_dst Destinatino MAC
306 @param eth_src Source MAC
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800307 @param dl_vlan_outer Outer VLAN ID
308 @param dl_vlan_pcp_outer Outer VLAN priority
309 @param dl_vlan_cfi_outer Outer VLAN cfi bit
Rich Laned0478ff2013-03-11 12:46:58 -0700310 @param vlan_vid Inner VLAN ID
311 @param vlan_pcp VLAN priority
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800312 @param dl_vlan_cfi VLAN cfi bit
313 @param ip_src IP source
314 @param ip_dst IP destination
315 @param ip_tos IP ToS
316 @param tcp_dport TCP destination port
317 @param ip_sport TCP source port
318
319 Generates a TCP request. Users
320 shouldn't assume anything about this packet other than that
321 it is a valid ethernet/IP/TCP frame.
322 """
323
324 if MINSIZE > pktlen:
325 pktlen = MINSIZE
326
327 # Note Dot1Q.id is really CFI
Rich Laned0478ff2013-03-11 12:46:58 -0700328 pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800329 scapy.Dot1Q(prio=dl_vlan_pcp_outer, id=dl_vlan_cfi_outer, vlan=dl_vlan_outer)/ \
Rich Laned0478ff2013-03-11 12:46:58 -0700330 scapy.Dot1Q(prio=vlan_pcp, id=dl_vlan_cfi, vlan=vlan_vid)/ \
Gregor Maier9cc93342013-01-29 16:55:28 -0800331 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ttl=ip_ttl, ihl=ip_ihl)/ \
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800332 scapy.TCP(sport=tcp_sport, dport=tcp_dport)
333
334 pkt = pkt/("D" * (pktlen - len(pkt)))
335
336 return pkt
337
Shudong Zhoub7f12462012-11-20 13:01:12 -0800338def do_barrier(ctrl, timeout=-1):
Dan Talayco0fc08bd2012-04-09 16:56:18 -0700339 """
340 Do a barrier command
341 Return 0 on success, -1 on error
342 """
Rich Lanecd97d3d2013-01-07 18:50:06 -0800343 b = of10.message.barrier_request()
Shudong Zhoub7f12462012-11-20 13:01:12 -0800344 (resp, pkt) = ctrl.transact(b, timeout=timeout)
Rich Lane3a261d52013-01-03 17:45:08 -0800345 if resp is None:
346 raise AssertionError("barrier failed")
Dan Talaycof6b94832012-04-12 21:50:57 -0700347 # We'll trust the transaction processing in the controller that xid matched
Rich Lane3a261d52013-01-03 17:45:08 -0800348 return 0 # for backwards compatibility
Dan Talayco92c99122010-06-03 13:53:18 -0700349
Rich Lane9a003812012-10-04 17:17:59 -0700350def port_config_get(controller, port_no):
Dan Talayco92c99122010-06-03 13:53:18 -0700351 """
352 Get a port's configuration
353
354 Gets the switch feature configuration and grabs one port's
355 configuration
356
357 @returns (hwaddr, config, advert) The hwaddress, configuration and
358 advertised values
359 """
Rich Lanecd97d3d2013-01-07 18:50:06 -0800360 request = of10.message.features_request()
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700361 reply, pkt = controller.transact(request)
Rich Lane9a003812012-10-04 17:17:59 -0700362 logging.debug(reply.show())
Dan Talayco92c99122010-06-03 13:53:18 -0700363 if reply is None:
Rich Lane9a003812012-10-04 17:17:59 -0700364 logging.warn("Get feature request failed")
Dan Talayco92c99122010-06-03 13:53:18 -0700365 return None, None, None
366 for idx in range(len(reply.ports)):
367 if reply.ports[idx].port_no == port_no:
368 return (reply.ports[idx].hw_addr, reply.ports[idx].config,
369 reply.ports[idx].advertised)
370
Rich Lane9a003812012-10-04 17:17:59 -0700371 logging.warn("Did not find port number for port config")
Dan Talayco92c99122010-06-03 13:53:18 -0700372 return None, None, None
373
Rich Lane9a003812012-10-04 17:17:59 -0700374def port_config_set(controller, port_no, config, mask):
Dan Talayco92c99122010-06-03 13:53:18 -0700375 """
376 Set the port configuration according the given parameters
377
378 Gets the switch feature configuration and updates one port's
379 configuration value according to config and mask
380 """
Rich Lane9a003812012-10-04 17:17:59 -0700381 logging.info("Setting port " + str(port_no) + " to config " + str(config))
Rich Lanecd97d3d2013-01-07 18:50:06 -0800382 request = of10.message.features_request()
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700383 reply, pkt = controller.transact(request)
Dan Talayco92c99122010-06-03 13:53:18 -0700384 if reply is None:
385 return -1
Rich Lane9a003812012-10-04 17:17:59 -0700386 logging.debug(reply.show())
Ed Swierk8d84ce02012-12-27 15:36:48 -0800387 p = None
Dan Talayco92c99122010-06-03 13:53:18 -0700388 for idx in range(len(reply.ports)):
389 if reply.ports[idx].port_no == port_no:
Ed Swierk8d84ce02012-12-27 15:36:48 -0800390 p = reply.ports[idx]
Dan Talayco92c99122010-06-03 13:53:18 -0700391 break
Rich Lanecd97d3d2013-01-07 18:50:06 -0800392 mod = of10.message.port_mod()
Dan Talayco92c99122010-06-03 13:53:18 -0700393 mod.port_no = port_no
Ed Swierk8d84ce02012-12-27 15:36:48 -0800394 if p:
395 mod.hw_addr = p.hw_addr
Dan Talayco92c99122010-06-03 13:53:18 -0700396 mod.config = config
397 mod.mask = mask
Ed Swierk8d84ce02012-12-27 15:36:48 -0800398 if p:
399 mod.advertise = p.advertised
Rich Lane5c3151c2013-01-03 17:15:41 -0800400 controller.message_send(mod)
401 return 0
Dan Talayco92c99122010-06-03 13:53:18 -0700402
Rich Lane2014f9b2012-10-05 15:29:40 -0700403def receive_pkt_check(dp, pkt, yes_ports, no_ports, assert_if):
Dan Talayco92c99122010-06-03 13:53:18 -0700404 """
405 Check for proper receive packets across all ports
Ken Chiang1bf01602012-04-04 10:48:23 -0700406 @param dp The dataplane object
Dan Talayco92c99122010-06-03 13:53:18 -0700407 @param pkt Expected packet; may be None if yes_ports is empty
408 @param yes_ports Set or list of ports that should recieve packet
409 @param no_ports Set or list of ports that should not receive packet
410 @param assert_if Object that implements assertXXX
411 """
Rich Lane91765672012-12-06 16:33:04 -0800412
413 # Wait this long for packets that we don't expect to receive.
414 # 100ms is (rarely) too short for positive tests on slow
415 # switches but is definitely not too short for a negative test.
416 negative_timeout = 0.1
417
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700418 exp_pkt_arg = None
Rich Lanecd97d3d2013-01-07 18:50:06 -0800419 if oftest.config["relax"]:
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700420 exp_pkt_arg = pkt
421
Dan Talayco92c99122010-06-03 13:53:18 -0700422 for ofport in yes_ports:
Rich Lane9a003812012-10-04 17:17:59 -0700423 logging.debug("Checking for pkt on port " + str(ofport))
Ken Chiang1bf01602012-04-04 10:48:23 -0700424 (rcv_port, rcv_pkt, pkt_time) = dp.poll(
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700425 port_number=ofport, exp_pkt=exp_pkt_arg)
Dan Talayco92c99122010-06-03 13:53:18 -0700426 assert_if.assertTrue(rcv_pkt is not None,
427 "Did not receive pkt on " + str(ofport))
Rich Lanecd97d3d2013-01-07 18:50:06 -0800428 if not oftest.dataplane.match_exp_pkt(pkt, rcv_pkt):
Rich Lane3c266832013-01-29 18:29:15 -0800429 logging.debug("Expected %s" % format_packet(pkt))
430 logging.debug("Received %s" % format_packet(rcv_pkt))
Rich Lanecd97d3d2013-01-07 18:50:06 -0800431 assert_if.assertTrue(oftest.dataplane.match_exp_pkt(pkt, rcv_pkt),
Rich Lane3c266832013-01-29 18:29:15 -0800432 "Received packet does not match expected packet " +
Ken Chiang1bf01602012-04-04 10:48:23 -0700433 "on port " + str(ofport))
Dan Talayco73f84012012-10-02 09:23:18 -0700434 if len(no_ports) > 0:
Rich Lane91765672012-12-06 16:33:04 -0800435 time.sleep(negative_timeout)
Dan Talayco92c99122010-06-03 13:53:18 -0700436 for ofport in no_ports:
Rich Lane9a003812012-10-04 17:17:59 -0700437 logging.debug("Negative check for pkt on port " + str(ofport))
Ken Chiang1bf01602012-04-04 10:48:23 -0700438 (rcv_port, rcv_pkt, pkt_time) = dp.poll(
Rich Lane91765672012-12-06 16:33:04 -0800439 port_number=ofport, timeout=0, exp_pkt=exp_pkt_arg)
Dan Talayco92c99122010-06-03 13:53:18 -0700440 assert_if.assertTrue(rcv_pkt is None,
441 "Unexpected pkt on port " + str(ofport))
Dan Talayco551befa2010-07-15 17:05:32 -0700442
443
Dan Talaycoc948d0b2012-03-23 12:17:54 -0700444def receive_pkt_verify(parent, egr_ports, exp_pkt, ing_port):
Dan Talayco551befa2010-07-15 17:05:32 -0700445 """
446 Receive a packet and verify it matches an expected value
Dan Talaycof6e76c02012-03-23 10:56:12 -0700447 @param egr_port A single port or list of ports
Dan Talayco551befa2010-07-15 17:05:32 -0700448
449 parent must implement dataplane, assertTrue and assertEqual
450 """
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700451 exp_pkt_arg = None
Rich Lanecd97d3d2013-01-07 18:50:06 -0800452 if oftest.config["relax"]:
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700453 exp_pkt_arg = exp_pkt
454
Dan Talaycof6e76c02012-03-23 10:56:12 -0700455 if type(egr_ports) == type([]):
456 egr_port_list = egr_ports
457 else:
458 egr_port_list = [egr_ports]
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700459
Dan Talaycof6e76c02012-03-23 10:56:12 -0700460 # Expect a packet from each port on egr port list
461 for egr_port in egr_port_list:
Dan Talaycod8ae7582012-03-23 12:24:56 -0700462 check_port = egr_port
Rich Laned7b0ffa2013-03-08 15:53:42 -0800463 if egr_port == of10.OFPP_IN_PORT:
Dan Talaycod8ae7582012-03-23 12:24:56 -0700464 check_port = ing_port
Dan Talaycof6e76c02012-03-23 10:56:12 -0700465 (rcv_port, rcv_pkt, pkt_time) = parent.dataplane.poll(
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700466 port_number=check_port, exp_pkt=exp_pkt_arg)
Dan Talayco551befa2010-07-15 17:05:32 -0700467
Dan Talaycof6e76c02012-03-23 10:56:12 -0700468 if rcv_pkt is None:
Rich Lane9a003812012-10-04 17:17:59 -0700469 logging.error("ERROR: No packet received from " +
Dan Talaycod8ae7582012-03-23 12:24:56 -0700470 str(check_port))
Dan Talayco551befa2010-07-15 17:05:32 -0700471
Dan Talaycof6e76c02012-03-23 10:56:12 -0700472 parent.assertTrue(rcv_pkt is not None,
Dan Talaycod8ae7582012-03-23 12:24:56 -0700473 "Did not receive packet port " + str(check_port))
Rich Lane9a003812012-10-04 17:17:59 -0700474 logging.debug("Packet len " + str(len(rcv_pkt)) + " in on " +
Dan Talaycof6e76c02012-03-23 10:56:12 -0700475 str(rcv_port))
476
477 if str(exp_pkt) != str(rcv_pkt):
Rich Lane9a003812012-10-04 17:17:59 -0700478 logging.error("ERROR: Packet match failed.")
479 logging.debug("Expected len " + str(len(exp_pkt)) + ": "
Dan Talaycof6e76c02012-03-23 10:56:12 -0700480 + str(exp_pkt).encode('hex'))
Rich Lane9a003812012-10-04 17:17:59 -0700481 logging.debug("Received len " + str(len(rcv_pkt)) + ": "
Dan Talaycof6e76c02012-03-23 10:56:12 -0700482 + str(rcv_pkt).encode('hex'))
Rich Lane5d7e89a2012-10-26 16:43:13 -0700483 logging.debug("Expected packet: " + inspect_packet(scapy.Ether(str(exp_pkt))))
484 logging.debug("Received packet: " + inspect_packet(scapy.Ether(str(rcv_pkt))))
Dan Talaycof6e76c02012-03-23 10:56:12 -0700485 parent.assertEqual(str(exp_pkt), str(rcv_pkt),
Dan Talaycod8ae7582012-03-23 12:24:56 -0700486 "Packet match error on port " + str(check_port))
Dan Talaycof6e76c02012-03-23 10:56:12 -0700487
Dan Talayco551befa2010-07-15 17:05:32 -0700488def match_verify(parent, req_match, res_match):
489 """
490 Verify flow matches agree; if they disagree, report where
491
492 parent must implement assertEqual
493 Use str() to ensure content is compared and not pointers
494 """
495
496 parent.assertEqual(req_match.wildcards, res_match.wildcards,
497 'Match failed: wildcards: ' + hex(req_match.wildcards) +
498 " != " + hex(res_match.wildcards))
499 parent.assertEqual(req_match.in_port, res_match.in_port,
500 'Match failed: in_port: ' + str(req_match.in_port) +
501 " != " + str(res_match.in_port))
Rich Laned0478ff2013-03-11 12:46:58 -0700502 parent.assertEqual(str(req_match.eth_src), str(res_match.eth_src),
503 'Match failed: eth_src: ' + str(req_match.eth_src) +
504 " != " + str(res_match.eth_src))
505 parent.assertEqual(str(req_match.eth_dst), str(res_match.eth_dst),
506 'Match failed: eth_dst: ' + str(req_match.eth_dst) +
507 " != " + str(res_match.eth_dst))
508 parent.assertEqual(req_match.vlan_vid, res_match.vlan_vid,
509 'Match failed: vlan_vid: ' + str(req_match.vlan_vid) +
510 " != " + str(res_match.vlan_vid))
511 parent.assertEqual(req_match.vlan_pcp, res_match.vlan_pcp,
512 'Match failed: vlan_pcp: ' +
513 str(req_match.vlan_pcp) + " != " +
514 str(res_match.vlan_pcp))
515 parent.assertEqual(req_match.eth_type, res_match.eth_type,
516 'Match failed: eth_type: ' + str(req_match.eth_type) +
517 " != " + str(res_match.eth_type))
Dan Talayco551befa2010-07-15 17:05:32 -0700518
Rich Laned7b0ffa2013-03-08 15:53:42 -0800519 if (not(req_match.wildcards & of10.OFPFW_DL_TYPE)
Rich Laned0478ff2013-03-11 12:46:58 -0700520 and (req_match.eth_type == IP_ETHERTYPE)):
521 parent.assertEqual(req_match.ip_dscp, res_match.ip_dscp,
522 'Match failed: ip_dscp: ' + str(req_match.ip_dscp) +
523 " != " + str(res_match.ip_dscp))
524 parent.assertEqual(req_match.ip_proto, res_match.ip_proto,
525 'Match failed: ip_proto: ' + str(req_match.ip_proto) +
526 " != " + str(res_match.ip_proto))
527 parent.assertEqual(req_match.ipv4_src, res_match.ipv4_src,
528 'Match failed: ipv4_src: ' + str(req_match.ipv4_src) +
529 " != " + str(res_match.ipv4_src))
530 parent.assertEqual(req_match.ipv4_dst, res_match.ipv4_dst,
531 'Match failed: ipv4_dst: ' + str(req_match.ipv4_dst) +
532 " != " + str(res_match.ipv4_dst))
Dan Talayco551befa2010-07-15 17:05:32 -0700533
Rich Laned7b0ffa2013-03-08 15:53:42 -0800534 if (not(req_match.wildcards & of10.OFPFW_NW_PROTO)
Rich Laned0478ff2013-03-11 12:46:58 -0700535 and ((req_match.ip_proto == TCP_PROTOCOL)
536 or (req_match.ip_proto == UDP_PROTOCOL))):
537 parent.assertEqual(req_match.tcp_src, res_match.tcp_src,
538 'Match failed: tcp_src: ' +
539 str(req_match.tcp_src) +
540 " != " + str(res_match.tcp_src))
541 parent.assertEqual(req_match.tcp_dst, res_match.tcp_dst,
542 'Match failed: tcp_dst: ' +
543 str(req_match.tcp_dst) +
544 " != " + str(res_match.tcp_dst))
Dan Talayco551befa2010-07-15 17:05:32 -0700545
Ed Swierk99a74de2012-08-22 06:40:54 -0700546def packet_to_flow_match(parent, packet):
Rich Lanecd97d3d2013-01-07 18:50:06 -0800547 match = of10.parse.packet_to_flow_match(packet)
Ed Swierk99a74de2012-08-22 06:40:54 -0700548 match.wildcards |= required_wildcards(parent)
549 return match
550
551def flow_msg_create(parent, pkt, ing_port=None, action_list=None, wildcards=None,
Dan Talaycof6e76c02012-03-23 10:56:12 -0700552 egr_ports=None, egr_queue=None, check_expire=False, in_band=False):
Dan Talayco551befa2010-07-15 17:05:32 -0700553 """
554 Create a flow message
555
556 Match on packet with given wildcards.
557 See flow_match_test for other parameter descriptoins
558 @param egr_queue if not None, make the output an enqueue action
Dan Talayco677c0b72011-08-23 22:53:38 -0700559 @param in_band if True, do not wildcard ingress port
Dan Talaycof6e76c02012-03-23 10:56:12 -0700560 @param egr_ports None (drop), single port or list of ports
Dan Talayco551befa2010-07-15 17:05:32 -0700561 """
Rich Lanecd97d3d2013-01-07 18:50:06 -0800562 match = of10.parse.packet_to_flow_match(pkt)
Dan Talayco551befa2010-07-15 17:05:32 -0700563 parent.assertTrue(match is not None, "Flow match from pkt failed")
Ed Swierk99a74de2012-08-22 06:40:54 -0700564 if wildcards is None:
565 wildcards = required_wildcards(parent)
Dan Talayco677c0b72011-08-23 22:53:38 -0700566 if in_band:
Rich Laned7b0ffa2013-03-08 15:53:42 -0800567 wildcards &= ~of10.OFPFW_IN_PORT
Dan Talayco551befa2010-07-15 17:05:32 -0700568 match.wildcards = wildcards
569 match.in_port = ing_port
570
Dan Talaycof6e76c02012-03-23 10:56:12 -0700571 if type(egr_ports) == type([]):
572 egr_port_list = egr_ports
573 else:
574 egr_port_list = [egr_ports]
575
Rich Laneba3f0e22013-03-11 16:43:57 -0700576 request = of10.message.flow_add()
Dan Talayco551befa2010-07-15 17:05:32 -0700577 request.match = match
578 request.buffer_id = 0xffffffff
579 if check_expire:
Rich Laned7b0ffa2013-03-08 15:53:42 -0800580 request.flags |= of10.OFPFF_SEND_FLOW_REM
Dan Talayco551befa2010-07-15 17:05:32 -0700581 request.hard_timeout = 1
582
583 if action_list is not None:
584 for act in action_list:
Rich Lane9a003812012-10-04 17:17:59 -0700585 logging.debug("Adding action " + act.show())
Rich Lanec495d9e2013-03-08 17:43:36 -0800586 request.actions.append(act)
Dan Talayco551befa2010-07-15 17:05:32 -0700587
588 # Set up output/enqueue action if directed
589 if egr_queue is not None:
Dan Talaycof6e76c02012-03-23 10:56:12 -0700590 parent.assertTrue(egr_ports is not None, "Egress port not set")
Rich Lanecd97d3d2013-01-07 18:50:06 -0800591 act = of10.action.action_enqueue()
Dan Talaycof6e76c02012-03-23 10:56:12 -0700592 for egr_port in egr_port_list:
593 act.port = egr_port
594 act.queue_id = egr_queue
Rich Lanec495d9e2013-03-08 17:43:36 -0800595 request.actions.append(act)
Dan Talaycof6e76c02012-03-23 10:56:12 -0700596 elif egr_ports is not None:
597 for egr_port in egr_port_list:
Rich Lanecd97d3d2013-01-07 18:50:06 -0800598 act = of10.action.action_output()
Dan Talaycof6e76c02012-03-23 10:56:12 -0700599 act.port = egr_port
Rich Lanec495d9e2013-03-08 17:43:36 -0800600 request.actions.append(act)
Dan Talayco551befa2010-07-15 17:05:32 -0700601
Rich Lane9a003812012-10-04 17:17:59 -0700602 logging.debug(request.show())
Dan Talayco551befa2010-07-15 17:05:32 -0700603
604 return request
605
Jeffrey Townsendf3eae9c2012-03-28 18:23:21 -0700606def flow_msg_install(parent, request, clear_table_override=None):
Dan Talayco551befa2010-07-15 17:05:32 -0700607 """
608 Install a flow mod message in the switch
609
610 @param parent Must implement controller, assertEqual, assertTrue
611 @param request The request, all set to go
612 @param clear_table If true, clear the flow table before installing
613 """
Dan Talayco8a64e332012-03-28 14:53:20 -0700614
Rich Lane2014f9b2012-10-05 15:29:40 -0700615 clear_table = test_param_get('clear_table', default=True)
Jeffrey Townsendf3eae9c2012-03-28 18:23:21 -0700616 if(clear_table_override != None):
617 clear_table = clear_table_override
618
619 if clear_table:
Rich Lane9a003812012-10-04 17:17:59 -0700620 logging.debug("Clear flow table")
Rich Lane32bf9482013-01-03 17:26:30 -0800621 delete_all_flows(parent.controller)
Dan Talayco551befa2010-07-15 17:05:32 -0700622
Rich Lane9a003812012-10-04 17:17:59 -0700623 logging.debug("Insert flow")
Rich Lane5c3151c2013-01-03 17:15:41 -0800624 parent.controller.message_send(request)
Rich Lanee912d032012-12-22 14:28:33 -0800625
Rich Lane3a261d52013-01-03 17:45:08 -0800626 do_barrier(parent.controller)
Dan Talayco551befa2010-07-15 17:05:32 -0700627
Ed Swierk99a74de2012-08-22 06:40:54 -0700628def flow_match_test_port_pair(parent, ing_port, egr_ports, wildcards=None,
Rich Laned0478ff2013-03-11 12:46:58 -0700629 vlan_vid=-1, pkt=None, exp_pkt=None,
Rich Lanee5779d32012-10-05 17:56:04 -0700630 action_list=None):
Dan Talayco551befa2010-07-15 17:05:32 -0700631 """
632 Flow match test on single TCP packet
Dan Talaycof6e76c02012-03-23 10:56:12 -0700633 @param egr_ports A single port or list of ports
Dan Talayco551befa2010-07-15 17:05:32 -0700634
635 Run test with packet through switch from ing_port to egr_port
636 See flow_match_test for parameter descriptions
637 """
638
Ed Swierk99a74de2012-08-22 06:40:54 -0700639 if wildcards is None:
640 wildcards = required_wildcards(parent)
Rich Lane9a003812012-10-04 17:17:59 -0700641 logging.info("Pkt match test: " + str(ing_port) + " to " +
Dan Talaycof6e76c02012-03-23 10:56:12 -0700642 str(egr_ports))
Rich Laned0478ff2013-03-11 12:46:58 -0700643 logging.debug(" WC: " + hex(wildcards) + " vlan: " + str(vlan_vid))
Dan Talayco551befa2010-07-15 17:05:32 -0700644 if pkt is None:
Rich Laned0478ff2013-03-11 12:46:58 -0700645 pkt = simple_tcp_packet(dl_vlan_enable=(vlan_vid >= 0), vlan_vid=vlan_vid)
Dan Talayco551befa2010-07-15 17:05:32 -0700646
647 request = flow_msg_create(parent, pkt, ing_port=ing_port,
Dan Talaycof6e76c02012-03-23 10:56:12 -0700648 wildcards=wildcards, egr_ports=egr_ports,
Dan Talayco551befa2010-07-15 17:05:32 -0700649 action_list=action_list)
650
651 flow_msg_install(parent, request)
652
Rich Lane9a003812012-10-04 17:17:59 -0700653 logging.debug("Send packet: " + str(ing_port) + " to " +
Dan Talaycof6e76c02012-03-23 10:56:12 -0700654 str(egr_ports))
Dan Talayco551befa2010-07-15 17:05:32 -0700655 parent.dataplane.send(ing_port, str(pkt))
656
657 if exp_pkt is None:
658 exp_pkt = pkt
Dan Talaycoc948d0b2012-03-23 12:17:54 -0700659 receive_pkt_verify(parent, egr_ports, exp_pkt, ing_port)
Dan Talayco551befa2010-07-15 17:05:32 -0700660
Rich Lane89725bb2012-12-03 16:23:27 -0800661def flow_match_test_pktout(parent, ing_port, egr_ports,
Rich Laned0478ff2013-03-11 12:46:58 -0700662 vlan_vid=-1, pkt=None, exp_pkt=None,
Rich Lane89725bb2012-12-03 16:23:27 -0800663 action_list=None):
664 """
665 Packet-out test on single TCP packet
666 @param egr_ports A single port or list of ports
667
668 Run test sending packet-out to egr_ports. The goal is to test the actions
669 taken on the packet, not the matching which is of course irrelevant.
670 See flow_match_test for parameter descriptions
671 """
672
673 if pkt is None:
Rich Laned0478ff2013-03-11 12:46:58 -0700674 pkt = simple_tcp_packet(dl_vlan_enable=(vlan_vid >= 0), vlan_vid=vlan_vid)
Rich Lane89725bb2012-12-03 16:23:27 -0800675
Rich Lanecd97d3d2013-01-07 18:50:06 -0800676 msg = of10.message.packet_out()
Rich Lane89725bb2012-12-03 16:23:27 -0800677 msg.in_port = ing_port
678 msg.data = str(pkt)
679 if action_list is not None:
680 for act in action_list:
Rich Lanec495d9e2013-03-08 17:43:36 -0800681 msg.actions.append(act)
Rich Lane89725bb2012-12-03 16:23:27 -0800682
683 # Set up output action
684 if egr_ports is not None:
685 for egr_port in egr_ports:
Rich Lanecd97d3d2013-01-07 18:50:06 -0800686 act = of10.action.action_output()
Rich Lane89725bb2012-12-03 16:23:27 -0800687 act.port = egr_port
Rich Lanec495d9e2013-03-08 17:43:36 -0800688 msg.actions.append(act)
Rich Lane89725bb2012-12-03 16:23:27 -0800689
690 logging.debug(msg.show())
Rich Lane5c3151c2013-01-03 17:15:41 -0800691 parent.controller.message_send(msg)
Rich Lane89725bb2012-12-03 16:23:27 -0800692
693 if exp_pkt is None:
694 exp_pkt = pkt
695 receive_pkt_verify(parent, egr_ports, exp_pkt, ing_port)
696
Dan Talaycof6e76c02012-03-23 10:56:12 -0700697def get_egr_list(parent, of_ports, how_many, exclude_list=[]):
698 """
699 Generate a list of ports avoiding those in the exclude list
Rich Lane9a003812012-10-04 17:17:59 -0700700 @param parent Supplies logging
Dan Talaycof6e76c02012-03-23 10:56:12 -0700701 @param of_ports List of OF port numbers
702 @param how_many Number of ports to be added to the list
703 @param exclude_list List of ports not to be used
704 @returns An empty list if unable to find enough ports
705 """
706
Dan Talaycoc948d0b2012-03-23 12:17:54 -0700707 if how_many == 0:
708 return []
709
Dan Talaycof6e76c02012-03-23 10:56:12 -0700710 count = 0
711 egr_ports = []
712 for egr_idx in range(len(of_ports)):
713 if of_ports[egr_idx] not in exclude_list:
714 egr_ports.append(of_ports[egr_idx])
715 count += 1
716 if count >= how_many:
717 return egr_ports
Rich Lane9a003812012-10-04 17:17:59 -0700718 logging.debug("Could not generate enough egress ports for test")
Dan Talaycof6e76c02012-03-23 10:56:12 -0700719 return []
720
Rich Laned0478ff2013-03-11 12:46:58 -0700721def flow_match_test(parent, port_map, wildcards=None, vlan_vid=-1, pkt=None,
Rich Lanee5779d32012-10-05 17:56:04 -0700722 exp_pkt=None, action_list=None,
Dan Talaycoc948d0b2012-03-23 12:17:54 -0700723 max_test=0, egr_count=1, ing_port=False):
Dan Talayco551befa2010-07-15 17:05:32 -0700724 """
Rich Lane89725bb2012-12-03 16:23:27 -0800725 Run flow_match_test_port_pair on all port pairs and packet-out
Dan Talayco551befa2010-07-15 17:05:32 -0700726
727 @param max_test If > 0 no more than this number of tests are executed.
728 @param parent Must implement controller, dataplane, assertTrue, assertEqual
Rich Lane9a003812012-10-04 17:17:59 -0700729 and logging
Dan Talayco551befa2010-07-15 17:05:32 -0700730 @param pkt If not None, use this packet for ingress
731 @param wildcards For flow match entry
Rich Laned0478ff2013-03-11 12:46:58 -0700732 @param vlan_vid If not -1, and pkt is None, create a pkt w/ VLAN tag
Dan Talayco551befa2010-07-15 17:05:32 -0700733 @param exp_pkt If not None, use this as the expected output pkt; els use pkt
734 @param action_list Additional actions to add to flow mod
Dan Talaycocfa172f2012-03-23 12:03:00 -0700735 @param egr_count Number of egress ports; -1 means get from config w/ dflt 2
Dan Talayco551befa2010-07-15 17:05:32 -0700736 """
Ed Swierk99a74de2012-08-22 06:40:54 -0700737 if wildcards is None:
738 wildcards = required_wildcards(parent)
Dan Talayco551befa2010-07-15 17:05:32 -0700739 of_ports = port_map.keys()
740 of_ports.sort()
741 parent.assertTrue(len(of_ports) > 1, "Not enough ports for test")
742 test_count = 0
743
Dan Talaycocfa172f2012-03-23 12:03:00 -0700744 if egr_count == -1:
Rich Lane2014f9b2012-10-05 15:29:40 -0700745 egr_count = test_param_get('egr_count', default=2)
Dan Talaycocfa172f2012-03-23 12:03:00 -0700746
Dan Talayco551befa2010-07-15 17:05:32 -0700747 for ing_idx in range(len(of_ports)):
748 ingress_port = of_ports[ing_idx]
Dan Talaycof6e76c02012-03-23 10:56:12 -0700749 egr_ports = get_egr_list(parent, of_ports, egr_count,
750 exclude_list=[ingress_port])
Dan Talaycoc948d0b2012-03-23 12:17:54 -0700751 if ing_port:
Rich Laned7b0ffa2013-03-08 15:53:42 -0800752 egr_ports.append(of10.OFPP_IN_PORT)
Dan Talaycof6e76c02012-03-23 10:56:12 -0700753 if len(egr_ports) == 0:
754 parent.assertTrue(0, "Failed to generate egress port list")
755
756 flow_match_test_port_pair(parent, ingress_port, egr_ports,
Rich Laned0478ff2013-03-11 12:46:58 -0700757 wildcards=wildcards, vlan_vid=vlan_vid,
Dan Talaycof6e76c02012-03-23 10:56:12 -0700758 pkt=pkt, exp_pkt=exp_pkt,
Rich Lanee5779d32012-10-05 17:56:04 -0700759 action_list=action_list)
Dan Talaycof6e76c02012-03-23 10:56:12 -0700760 test_count += 1
761 if (max_test > 0) and (test_count > max_test):
Rich Lane9a003812012-10-04 17:17:59 -0700762 logging.info("Ran " + str(test_count) + " tests; exiting")
Rich Lane89725bb2012-12-03 16:23:27 -0800763 break
764
Ed Swierk38eea082013-01-02 19:46:20 -0800765 if not test_param_get('pktout_actions', default=True):
766 return
Rich Lane89725bb2012-12-03 16:23:27 -0800767
768 ingress_port = of_ports[0]
769 egr_ports = get_egr_list(parent, of_ports, egr_count,
770 exclude_list=[ingress_port])
771 if ing_port:
Rich Laned7b0ffa2013-03-08 15:53:42 -0800772 egr_ports.append(of10.OFPP_IN_PORT)
Rich Lane89725bb2012-12-03 16:23:27 -0800773 flow_match_test_pktout(parent, ingress_port, egr_ports,
Rich Laned0478ff2013-03-11 12:46:58 -0700774 vlan_vid=vlan_vid,
Rich Lane89725bb2012-12-03 16:23:27 -0800775 pkt=pkt, exp_pkt=exp_pkt,
776 action_list=action_list)
Dan Talayco551befa2010-07-15 17:05:32 -0700777
Rich Lane2014f9b2012-10-05 15:29:40 -0700778def test_param_get(key, default=None):
Dan Talayco4b2bee62010-07-20 14:10:05 -0700779 """
780 Return value passed via test-params if present
781
Dan Talayco4b2bee62010-07-20 14:10:05 -0700782 @param key The lookup key
783 @param default Default value to use if not found
784
785 If the pair 'key=val' appeared in the string passed to --test-params
786 on the command line, return val (as interpreted by exec). Otherwise
787 return default value.
Dan Talaycof6e76c02012-03-23 10:56:12 -0700788
789 WARNING: TEST PARAMETERS MUST BE PYTHON IDENTIFIERS;
790 eg egr_count, not egr-count.
Dan Talayco4b2bee62010-07-20 14:10:05 -0700791 """
792 try:
Rich Lanecd97d3d2013-01-07 18:50:06 -0800793 exec oftest.config["test_params"]
Dan Talayco4b2bee62010-07-20 14:10:05 -0700794 except:
795 return default
796
797 s = "val = " + str(key)
798 try:
799 exec s
800 return val
801 except:
802 return default
803
804def action_generate(parent, field_to_mod, mod_field_vals):
805 """
806 Create an action to modify the field indicated in field_to_mod
807
808 @param parent Must implement, assertTrue
809 @param field_to_mod The field to modify as a string name
810 @param mod_field_vals Hash of values to use for modified values
811 """
812
813 act = None
814
815 if field_to_mod in ['pktlen']:
816 return None
817
Rich Laned0478ff2013-03-11 12:46:58 -0700818 if field_to_mod == 'eth_dst':
Rich Lanecd97d3d2013-01-07 18:50:06 -0800819 act = of10.action.action_set_dl_dst()
Rich Laned0478ff2013-03-11 12:46:58 -0700820 act.dl_addr = of10.parse.parse_mac(mod_field_vals['eth_dst'])
821 elif field_to_mod == 'eth_src':
Rich Lanecd97d3d2013-01-07 18:50:06 -0800822 act = of10.action.action_set_dl_src()
Rich Laned0478ff2013-03-11 12:46:58 -0700823 act.dl_addr = of10.parse.parse_mac(mod_field_vals['eth_src'])
Dan Talayco4b2bee62010-07-20 14:10:05 -0700824 elif field_to_mod == 'dl_vlan_enable':
825 if not mod_field_vals['dl_vlan_enable']: # Strip VLAN tag
Rich Lanecd97d3d2013-01-07 18:50:06 -0800826 act = of10.action.action_strip_vlan()
Rich Laned0478ff2013-03-11 12:46:58 -0700827 # Add VLAN tag is handled by vlan_vid field
Dan Talayco4b2bee62010-07-20 14:10:05 -0700828 # Will return None in this case
Rich Laned0478ff2013-03-11 12:46:58 -0700829 elif field_to_mod == 'vlan_vid':
Rich Lanecd97d3d2013-01-07 18:50:06 -0800830 act = of10.action.action_set_vlan_vid()
Rich Laned0478ff2013-03-11 12:46:58 -0700831 act.vlan_vid = mod_field_vals['vlan_vid']
832 elif field_to_mod == 'vlan_pcp':
Rich Lanecd97d3d2013-01-07 18:50:06 -0800833 act = of10.action.action_set_vlan_pcp()
Rich Laned0478ff2013-03-11 12:46:58 -0700834 act.vlan_pcp = mod_field_vals['vlan_pcp']
Dan Talayco4b2bee62010-07-20 14:10:05 -0700835 elif field_to_mod == 'ip_src':
Rich Lanecd97d3d2013-01-07 18:50:06 -0800836 act = of10.action.action_set_nw_src()
837 act.nw_addr = of10.parse.parse_ip(mod_field_vals['ip_src'])
Dan Talayco4b2bee62010-07-20 14:10:05 -0700838 elif field_to_mod == 'ip_dst':
Rich Lanecd97d3d2013-01-07 18:50:06 -0800839 act = of10.action.action_set_nw_dst()
840 act.nw_addr = of10.parse.parse_ip(mod_field_vals['ip_dst'])
Dan Talayco4b2bee62010-07-20 14:10:05 -0700841 elif field_to_mod == 'ip_tos':
Rich Lanecd97d3d2013-01-07 18:50:06 -0800842 act = of10.action.action_set_nw_tos()
Dan Talayco4b2bee62010-07-20 14:10:05 -0700843 act.nw_tos = mod_field_vals['ip_tos']
844 elif field_to_mod == 'tcp_sport':
Rich Lanecd97d3d2013-01-07 18:50:06 -0800845 act = of10.action.action_set_tp_src()
Dan Talayco4b2bee62010-07-20 14:10:05 -0700846 act.tp_port = mod_field_vals['tcp_sport']
847 elif field_to_mod == 'tcp_dport':
Rich Lanecd97d3d2013-01-07 18:50:06 -0800848 act = of10.action.action_set_tp_dst()
Dan Talayco4b2bee62010-07-20 14:10:05 -0700849 act.tp_port = mod_field_vals['tcp_dport']
Rich Lane110e0e32012-10-26 16:21:46 -0700850 elif field_to_mod == 'udp_sport':
Rich Lanecd97d3d2013-01-07 18:50:06 -0800851 act = of10.action.action_set_tp_src()
Rich Lane110e0e32012-10-26 16:21:46 -0700852 act.tp_port = mod_field_vals['udp_sport']
853 elif field_to_mod == 'udp_dport':
Rich Lanecd97d3d2013-01-07 18:50:06 -0800854 act = of10.action.action_set_tp_dst()
Rich Lane110e0e32012-10-26 16:21:46 -0700855 act.tp_port = mod_field_vals['udp_dport']
Dan Talayco4b2bee62010-07-20 14:10:05 -0700856 else:
857 parent.assertTrue(0, "Unknown field to modify: " + str(field_to_mod))
858
859 return act
860
861def pkt_action_setup(parent, start_field_vals={}, mod_field_vals={},
Rich Lane110e0e32012-10-26 16:21:46 -0700862 mod_fields=[], tp="tcp", check_test_params=False):
Dan Talayco4b2bee62010-07-20 14:10:05 -0700863 """
864 Set up the ingress and expected packet and action list for a test
865
Rich Lane2014f9b2012-10-05 15:29:40 -0700866 @param parent Must implement assertTrue
Dan Talayco4b2bee62010-07-20 14:10:05 -0700867 @param start_field_values Field values to use for ingress packet (optional)
868 @param mod_field_values Field values to use for modified packet (optional)
869 @param mod_fields The list of fields to be modified by the switch in the test.
870 @params check_test_params If True, will check the parameters vid, add_vlan
871 and strip_vlan from the command line.
872
873 Returns a triple: pkt-to-send, expected-pkt, action-list
874 """
875
876 new_actions = []
877
Dan Talayco4b2bee62010-07-20 14:10:05 -0700878 base_pkt_params = {}
879 base_pkt_params['pktlen'] = 100
Rich Laned0478ff2013-03-11 12:46:58 -0700880 base_pkt_params['eth_dst'] = '00:DE:F0:12:34:56'
881 base_pkt_params['eth_src'] = '00:23:45:67:89:AB'
Dan Talayco4b2bee62010-07-20 14:10:05 -0700882 base_pkt_params['dl_vlan_enable'] = False
Rich Laned0478ff2013-03-11 12:46:58 -0700883 base_pkt_params['vlan_vid'] = 2
884 base_pkt_params['vlan_pcp'] = 0
Dan Talayco4b2bee62010-07-20 14:10:05 -0700885 base_pkt_params['ip_src'] = '192.168.0.1'
886 base_pkt_params['ip_dst'] = '192.168.0.2'
887 base_pkt_params['ip_tos'] = 0
Rich Lane110e0e32012-10-26 16:21:46 -0700888 if tp == "tcp":
889 base_pkt_params['tcp_sport'] = 1234
890 base_pkt_params['tcp_dport'] = 80
891 elif tp == "udp":
892 base_pkt_params['udp_sport'] = 1234
893 base_pkt_params['udp_dport'] = 80
Dan Talayco4b2bee62010-07-20 14:10:05 -0700894 for keyname in start_field_vals.keys():
895 base_pkt_params[keyname] = start_field_vals[keyname]
896
897 mod_pkt_params = {}
898 mod_pkt_params['pktlen'] = 100
Rich Laned0478ff2013-03-11 12:46:58 -0700899 mod_pkt_params['eth_dst'] = '00:21:0F:ED:CB:A9'
900 mod_pkt_params['eth_src'] = '00:ED:CB:A9:87:65'
Dan Talayco4b2bee62010-07-20 14:10:05 -0700901 mod_pkt_params['dl_vlan_enable'] = False
Rich Laned0478ff2013-03-11 12:46:58 -0700902 mod_pkt_params['vlan_vid'] = 3
903 mod_pkt_params['vlan_pcp'] = 7
Dan Talayco4b2bee62010-07-20 14:10:05 -0700904 mod_pkt_params['ip_src'] = '10.20.30.40'
905 mod_pkt_params['ip_dst'] = '50.60.70.80'
906 mod_pkt_params['ip_tos'] = 0xf0
Rich Lane110e0e32012-10-26 16:21:46 -0700907 if tp == "tcp":
908 mod_pkt_params['tcp_sport'] = 4321
909 mod_pkt_params['tcp_dport'] = 8765
910 elif tp == "udp":
911 mod_pkt_params['udp_sport'] = 4321
912 mod_pkt_params['udp_dport'] = 8765
Dan Talayco4b2bee62010-07-20 14:10:05 -0700913 for keyname in mod_field_vals.keys():
914 mod_pkt_params[keyname] = mod_field_vals[keyname]
915
916 # Check for test param modifications
917 strip = False
918 if check_test_params:
Rich Lane2014f9b2012-10-05 15:29:40 -0700919 add_vlan = test_param_get('add_vlan')
920 strip_vlan = test_param_get('strip_vlan')
921 vid = test_param_get('vid')
Dan Talayco4b2bee62010-07-20 14:10:05 -0700922
923 if add_vlan and strip_vlan:
924 parent.assertTrue(0, "Add and strip VLAN both specified")
925
926 if vid:
927 base_pkt_params['dl_vlan_enable'] = True
Rich Laned0478ff2013-03-11 12:46:58 -0700928 base_pkt_params['vlan_vid'] = vid
929 if 'vlan_vid' in mod_fields:
930 mod_pkt_params['vlan_vid'] = vid + 1
Dan Talayco4b2bee62010-07-20 14:10:05 -0700931
932 if add_vlan:
933 base_pkt_params['dl_vlan_enable'] = False
934 mod_pkt_params['dl_vlan_enable'] = True
935 mod_pkt_params['pktlen'] = base_pkt_params['pktlen'] + 4
936 mod_fields.append('pktlen')
937 mod_fields.append('dl_vlan_enable')
Rich Laned0478ff2013-03-11 12:46:58 -0700938 if 'vlan_vid' not in mod_fields:
939 mod_fields.append('vlan_vid')
Dan Talayco4b2bee62010-07-20 14:10:05 -0700940 elif strip_vlan:
941 base_pkt_params['dl_vlan_enable'] = True
942 mod_pkt_params['dl_vlan_enable'] = False
943 mod_pkt_params['pktlen'] = base_pkt_params['pktlen'] - 4
944 mod_fields.append('dl_vlan_enable')
945 mod_fields.append('pktlen')
946
Rich Lane110e0e32012-10-26 16:21:46 -0700947 if tp == "tcp":
948 packet_builder = simple_tcp_packet
949 elif tp == "udp":
950 packet_builder = simple_udp_packet
951 else:
952 raise NotImplementedError("unknown transport protocol %s" % tp)
953
Dan Talayco4b2bee62010-07-20 14:10:05 -0700954 # Build the ingress packet
Rich Lane110e0e32012-10-26 16:21:46 -0700955 ingress_pkt = packet_builder(**base_pkt_params)
Dan Talayco4b2bee62010-07-20 14:10:05 -0700956
957 # Build the expected packet, modifying the indicated fields
958 for item in mod_fields:
959 base_pkt_params[item] = mod_pkt_params[item]
960 act = action_generate(parent, item, mod_pkt_params)
961 if act:
962 new_actions.append(act)
963
Rich Lane110e0e32012-10-26 16:21:46 -0700964 expected_pkt = packet_builder(**base_pkt_params)
Dan Talayco4b2bee62010-07-20 14:10:05 -0700965
966 return (ingress_pkt, expected_pkt, new_actions)
Dan Talayco677c0b72011-08-23 22:53:38 -0700967
968# Generate a simple "drop" flow mod
969# If in_band is true, then only drop from first test port
970def flow_mod_gen(port_map, in_band):
Rich Laneba3f0e22013-03-11 16:43:57 -0700971 request = of10.message.flow_add()
Rich Laned7b0ffa2013-03-08 15:53:42 -0800972 request.match.wildcards = of10.OFPFW_ALL
Dan Talayco677c0b72011-08-23 22:53:38 -0700973 if in_band:
Rich Laned7b0ffa2013-03-08 15:53:42 -0800974 request.match.wildcards = of10.OFPFW_ALL - of10.OFPFW_IN_PORT
Dan Talayco677c0b72011-08-23 22:53:38 -0700975 for of_port, ifname in port_map.items(): # Grab first port
976 break
977 request.match.in_port = of_port
978 request.buffer_id = 0xffffffff
979 return request
Dan Talaycoba3745c2010-07-21 21:51:08 -0700980
981def skip_message_emit(parent, s):
982 """
983 Print out a 'skipped' message to stderr
984
985 @param s The string to print out to the log file
Dan Talaycoba3745c2010-07-21 21:51:08 -0700986 """
987 global skipped_test_count
988
989 skipped_test_count += 1
Rich Lane9a003812012-10-04 17:17:59 -0700990 logging.info("Skipping: " + s)
Dan Talayco2940fdd2013-02-06 15:01:35 -0800991 if oftest.config["debug"] < logging.WARNING:
Dan Talaycoba3745c2010-07-21 21:51:08 -0700992 sys.stderr.write("(skipped) ")
993 else:
994 sys.stderr.write("(S)")
Dan Talayco677c0b72011-08-23 22:53:38 -0700995
Dan Talayco8a64e332012-03-28 14:53:20 -0700996
997def all_stats_get(parent):
998 """
999 Get the aggregate stats for all flows in the table
1000 @param parent Test instance with controller connection and assert
1001 @returns dict with keys flows, packets, bytes, active (flows),
1002 lookups, matched
1003 """
Rich Lanecd97d3d2013-01-07 18:50:06 -08001004 stat_req = of10.message.aggregate_stats_request()
Rich Laned7b0ffa2013-03-08 15:53:42 -08001005 stat_req.match = of10.ofp_match()
1006 stat_req.match.wildcards = of10.OFPFW_ALL
Dan Talayco8a64e332012-03-28 14:53:20 -07001007 stat_req.table_id = 0xff
Rich Laned7b0ffa2013-03-08 15:53:42 -08001008 stat_req.out_port = of10.OFPP_NONE
Dan Talayco8a64e332012-03-28 14:53:20 -07001009
1010 rv = {}
1011
Rich Lanec8aaa3e2012-07-26 19:28:02 -07001012 (reply, pkt) = parent.controller.transact(stat_req)
Rich Lane5fd6faf2013-03-11 13:30:20 -07001013 parent.assertTrue(len(reply.entries) == 1, "Did not receive flow stats reply")
Dan Talayco8a64e332012-03-28 14:53:20 -07001014
Rich Lane5fd6faf2013-03-11 13:30:20 -07001015 for obj in reply.entries:
Dan Talayco8a64e332012-03-28 14:53:20 -07001016 (rv["flows"], rv["packets"], rv["bytes"]) = (obj.flow_count,
1017 obj.packet_count, obj.byte_count)
1018 break
1019
Rich Lanecd97d3d2013-01-07 18:50:06 -08001020 request = of10.message.table_stats_request()
Rich Lanec8aaa3e2012-07-26 19:28:02 -07001021 (reply , pkt) = parent.controller.transact(request)
Dan Talayco8a64e332012-03-28 14:53:20 -07001022
1023
1024 (rv["active"], rv["lookups"], rv["matched"]) = (0,0,0)
Rich Lane5fd6faf2013-03-11 13:30:20 -07001025 for obj in reply.entries:
Dan Talayco8a64e332012-03-28 14:53:20 -07001026 rv["active"] += obj.active_count
1027 rv["lookups"] += obj.lookup_count
1028 rv["matched"] += obj.matched_count
1029
1030 return rv
Dan Talayco2baf8b52012-03-30 09:55:42 -07001031
Rich Lane7744e112013-01-11 17:23:57 -08001032_import_blacklist.add('FILTER')
Dan Talayco2baf8b52012-03-30 09:55:42 -07001033FILTER=''.join([(len(repr(chr(x)))==3) and chr(x) or '.'
1034 for x in range(256)])
1035
1036def hex_dump_buffer(src, length=16):
1037 """
1038 Convert src to a hex dump string and return the string
1039 @param src The source buffer
1040 @param length The number of bytes shown in each line
1041 @returns A string showing the hex dump
1042 """
Dan Talaycoc516fa02012-04-12 22:28:43 -07001043 result = ["\n"]
Dan Talayco2baf8b52012-03-30 09:55:42 -07001044 for i in xrange(0, len(src), length):
1045 chars = src[i:i+length]
1046 hex = ' '.join(["%02x" % ord(x) for x in chars])
1047 printable = ''.join(["%s" % ((ord(x) <= 127 and
1048 FILTER[ord(x)]) or '.') for x in chars])
1049 result.append("%04x %-*s %s\n" % (i, length*3, hex, printable))
1050 return ''.join(result)
1051
1052def format_packet(pkt):
1053 return "Packet length %d \n%s" % (len(str(pkt)),
1054 hex_dump_buffer(str(pkt)))
Rich Lane5d7e89a2012-10-26 16:43:13 -07001055
1056def inspect_packet(pkt):
1057 """
1058 Wrapper around scapy's show() method.
1059 @returns A string showing the dissected packet.
1060 """
1061 from cStringIO import StringIO
1062 out = None
1063 backup = sys.stdout
1064 try:
1065 sys.stdout = StringIO()
1066 pkt.show2()
1067 out = sys.stdout.getvalue()
1068 sys.stdout.close()
1069 finally:
1070 sys.stdout = backup
1071 return out
Rich Lane0a4f6372013-01-02 14:40:22 -08001072
1073def nonstandard(cls):
1074 """
Rich Lanecc45b8e2013-01-02 15:55:02 -08001075 Testcase decorator that marks the test as being non-standard.
1076 These tests are not automatically added to the "standard" group.
Rich Lane0a4f6372013-01-02 14:40:22 -08001077 """
Rich Lanecc45b8e2013-01-02 15:55:02 -08001078 cls._nonstandard = True
Rich Lane0a4f6372013-01-02 14:40:22 -08001079 return cls
1080
1081def disabled(cls):
1082 """
Rich Lanecc45b8e2013-01-02 15:55:02 -08001083 Testcase decorator that marks the test as being disabled.
1084 These tests are not automatically added to the "standard" group or
1085 their module's group.
Rich Lane0a4f6372013-01-02 14:40:22 -08001086 """
Rich Lanecc45b8e2013-01-02 15:55:02 -08001087 cls._disabled = True
Rich Lane0a4f6372013-01-02 14:40:22 -08001088 return cls
Rich Lane97e99652013-01-02 17:23:20 -08001089
1090def group(name):
1091 """
1092 Testcase decorator that adds the test to a group.
1093 """
1094 def fn(cls):
1095 if not hasattr(cls, "_groups"):
1096 cls._groups = []
1097 cls._groups.append(name)
1098 return cls
1099 return fn
Rich Lane5a9a1922013-01-11 14:29:30 -08001100
1101def version(ver):
1102 """
1103 Testcase decorator that specifies which versions of OpenFlow the test
1104 supports. The default is 1.0+. This decorator may only be used once.
1105
1106 Supported syntax:
1107 1.0 -> 1.0
1108 1.0,1.2,1.3 -> 1.0, 1.2, 1.3
1109 1.0+ -> 1.0, 1.1, 1.2, 1.3
1110 """
1111 versions = parse_version(ver)
1112 def fn(cls):
1113 cls._versions = versions
1114 return cls
1115 return fn
1116
1117def parse_version(ver):
1118 allowed_versions = ["1.0", "1.1", "1.2", "1.3"]
1119 if re.match("^1\.\d+$", ver):
1120 versions = set([ver])
1121 elif re.match("^(1\.\d+)\+$", ver):
1122 if not ver[:-1] in allowed_versions:
1123 raise ValueError("invalid OpenFlow version %s" % ver[:-1])
1124 versions = set()
1125 if ver != "1.1+": versions.add("1.0")
1126 if ver != "1.2+": versions.add("1.1")
1127 if ver != "1.3+": versions.add("1.2")
1128 versions.add("1.3")
1129 else:
1130 versions = set(ver.split(','))
1131
1132 for version in versions:
1133 if not version in allowed_versions:
1134 raise ValueError("invalid OpenFlow version %s" % version)
1135
1136 return versions
1137
1138assert(parse_version("1.0") == set(["1.0"]))
1139assert(parse_version("1.0,1.2,1.3") == set(["1.0", "1.2", "1.3"]))
1140assert(parse_version("1.0+") == set(["1.0", "1.1", "1.2", "1.3"]))
Rich Lane7744e112013-01-11 17:23:57 -08001141
Rich Laneae3428c2013-03-07 14:37:42 -08001142def get_stats(test, req):
1143 """
1144 Retrieve a list of stats entries. Handles OFPSF_REPLY_MORE.
1145 """
1146 stats = []
1147 reply, _ = test.controller.transact(req)
1148 test.assertTrue(reply is not None, "No response to stats request")
Rich Lane5fd6faf2013-03-11 13:30:20 -07001149 stats.extend(reply.entries)
Rich Laneae3428c2013-03-07 14:37:42 -08001150 while reply.flags & of10.OFPSF_REPLY_MORE != 0:
1151 reply, pkt = self.controller.poll(exp_msg=of10.OFPT_STATS_REPLY)
1152 test.assertTrue(reply is not None, "No response to stats request")
Rich Lane5fd6faf2013-03-11 13:30:20 -07001153 stats.extend(reply.entries)
Rich Laneae3428c2013-03-07 14:37:42 -08001154 return stats
1155
Rich Laned7b0ffa2013-03-08 15:53:42 -08001156def get_flow_stats(test, match, table_id=0xff, out_port=of10.OFPP_NONE):
Rich Laneae3428c2013-03-07 14:37:42 -08001157 """
1158 Retrieve a list of flow stats entries.
1159 """
1160 req = of10.message.flow_stats_request(match=match,
1161 table_id=table_id,
1162 out_port=out_port)
1163 return get_stats(test, req)
1164
Rich Lane968b6192013-03-07 15:34:43 -08001165def get_port_stats(test, port_no):
1166 """
1167 Retrieve a list of port stats entries.
1168 """
1169 req = of10.message.port_stats_request(port_no=port_no)
1170 return get_stats(test, req)
1171
Rich Lane6a334922013-03-07 16:14:52 -08001172def get_queue_stats(test, port_no, queue_id):
1173 """
1174 Retrieve a list of queue stats entries.
1175 """
1176 req = of10.message.queue_stats_request(port_no=port_no, queue_id=queue_id)
1177 return get_stats(test, req)
1178
Rich Laneae3428c2013-03-07 14:37:42 -08001179def verify_flow_stats(test, match, table_id=0xff,
Rich Laned7b0ffa2013-03-08 15:53:42 -08001180 out_port=of10.OFPP_NONE,
Rich Laneae3428c2013-03-07 14:37:42 -08001181 initial=[],
1182 pkts=None, bytes=None):
1183 """
1184 Verify that flow stats changed as expected.
1185
1186 Optionally takes an 'initial' list of stats entries, as returned by
1187 get_flow_stats(). If 'initial' is not given the counters are assumed to
1188 begin at 0.
1189 """
1190 def accumulate(stats):
1191 pkts_acc = bytes_acc = 0
1192 for stat in stats:
1193 pkts_acc += stat.packet_count
1194 bytes_acc += stat.byte_count
1195 return (pkts_acc, bytes_acc)
1196
1197 pkts_before, bytes_before = accumulate(initial)
1198
1199 # Wait 10s for counters to update
1200 pkt_diff = byte_diff = None
1201 for i in range(0, 100):
1202 stats = get_flow_stats(test, match, table_id=table_id, out_port=out_port)
1203 pkts_after, bytes_after = accumulate(stats)
1204 pkt_diff = pkts_after - pkts_before
1205 byte_diff = bytes_after - bytes_before
1206 if (pkts == None or pkt_diff >= pkts) and \
1207 (bytes == None or byte_diff >= bytes):
1208 break
Dan Talayco53724732013-03-08 23:54:02 -08001209 time.sleep(0.1)
Rich Laneae3428c2013-03-07 14:37:42 -08001210
1211 if pkts != None:
1212 test.assertEquals(pkt_diff, pkts, "Flow packet counter not updated properly (expected increase of %d, got increase of %d)" % (pkts, pkt_diff))
1213
1214 if bytes != None:
Rich Lane53b96812013-03-07 16:54:50 -08001215 test.assertTrue(byte_diff >= bytes and byte_diff <= bytes*1.1,
1216 "Flow byte counter not updated properly (expected increase of %d, got increase of %d)" % (bytes, byte_diff))
Rich Laneae3428c2013-03-07 14:37:42 -08001217
Rich Lane968b6192013-03-07 15:34:43 -08001218def verify_port_stats(test, port,
1219 initial=[],
1220 tx_pkts=None, rx_pkts=None,
1221 tx_bytes=None, rx_bytes=None):
1222 """
1223 Verify that port stats changed as expected.
1224
1225 Optionally takes an 'initial' list of stats entries, as returned by
1226 get_port_stats(). If 'initial' is not given the counters are assumed to
1227 begin at 0.
1228 """
1229 def accumulate(stats):
1230 tx_pkts_acc = rx_pkts_acc = tx_bytes_acc = rx_bytes_acc = 0
1231 for stat in stats:
1232 tx_pkts_acc += stat.tx_packets
1233 rx_pkts_acc += stat.rx_packets
1234 tx_bytes_acc += stat.tx_bytes
1235 rx_bytes_acc += stat.rx_bytes
1236 return (tx_pkts_acc, rx_pkts_acc, tx_bytes_acc, rx_bytes_acc)
1237
1238 tx_pkts_before, rx_pkts_before, \
1239 tx_bytes_before, rx_bytes_before = accumulate(initial)
1240
1241 # Wait 10s for counters to update
1242 for i in range(0, 100):
1243 stats = get_port_stats(test, port)
1244 tx_pkts_after, rx_pkts_after, \
1245 tx_bytes_after, rx_bytes_after = accumulate(stats)
1246 tx_pkts_diff = tx_pkts_after - tx_pkts_before
1247 rx_pkts_diff = rx_pkts_after - rx_pkts_before
1248 tx_bytes_diff = tx_bytes_after - tx_bytes_before
1249 rx_bytes_diff = rx_bytes_after - rx_bytes_before
1250 if (tx_pkts == None or tx_pkts == tx_pkts_diff) and \
1251 (rx_pkts == None or rx_pkts == rx_pkts_diff) and \
Rich Lane53b96812013-03-07 16:54:50 -08001252 (tx_bytes == None or tx_bytes <= tx_bytes_diff) and \
1253 (rx_bytes == None or rx_bytes <= rx_bytes_diff):
Rich Lane968b6192013-03-07 15:34:43 -08001254 break
1255 time.sleep(0.1)
1256
1257 if (tx_pkts != None):
1258 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))
1259 if (rx_pkts != None):
1260 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))
1261 if (tx_bytes != None):
Rich Lane53b96812013-03-07 16:54:50 -08001262 test.assertTrue(tx_bytes_diff >= tx_bytes and tx_bytes_diff <= tx_bytes*1.1,
1263 "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 -08001264 if (rx_bytes != None):
Rich Lane53b96812013-03-07 16:54:50 -08001265 test.assertTrue(rx_bytes_diff >= rx_bytes and rx_bytes_diff <= rx_bytes*1.1,
1266 "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 -08001267
Rich Lane6a334922013-03-07 16:14:52 -08001268def verify_queue_stats(test, port_no, queue_id,
1269 initial=[],
1270 pkts=None, bytes=None):
1271 """
1272 Verify that queue stats changed as expected.
1273
1274 Optionally takes an 'initial' list of stats entries, as returned by
1275 get_queue_stats(). If 'initial' is not given the counters are assumed to
1276 begin at 0.
1277 """
1278 def accumulate(stats):
1279 pkts_acc = bytes_acc = 0
1280 for stat in stats:
1281 pkts_acc += stat.tx_packets
1282 bytes_acc += stat.tx_bytes
1283 return (pkts_acc, bytes_acc)
1284
1285 pkts_before, bytes_before = accumulate(initial)
1286
1287 # Wait 10s for counters to update
1288 pkt_diff = byte_diff = None
1289 for i in range(0, 100):
1290 stats = get_queue_stats(test, port_no, queue_id)
1291 pkts_after, bytes_after = accumulate(stats)
1292 pkt_diff = pkts_after - pkts_before
1293 byte_diff = bytes_after - bytes_before
1294 if (pkts == None or pkt_diff >= pkts) and \
1295 (bytes == None or byte_diff >= bytes):
1296 break
Dan Talayco53724732013-03-08 23:54:02 -08001297 time.sleep(0.1)
Rich Lane6a334922013-03-07 16:14:52 -08001298
1299 if pkts != None:
1300 test.assertEquals(pkt_diff, pkts, "Queue packet counter not updated properly (expected increase of %d, got increase of %d)" % (pkts, pkt_diff))
1301
1302 if bytes != None:
Rich Lane53b96812013-03-07 16:54:50 -08001303 test.assertTrue(byte_diff >= bytes and byte_diff <= bytes*1.1,
1304 "Queue byte counter not updated properly (expected increase of %d, got increase of %d)" % (bytes, byte_diff))
Rich Laneae3428c2013-03-07 14:37:42 -08001305
Rich Lane7744e112013-01-11 17:23:57 -08001306__all__ = list(set(locals()) - _import_blacklist)