blob: faf2c896aa2804bc5ade85782c6894a22bf88ab4 [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
19import of10.cstruct
20import 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 Lanecd97d3d2013-01-07 18:50:06 -080043 msg = of10.message.flow_mod()
44 msg.match.wildcards = of10.cstruct.OFPFW_ALL
45 msg.out_port = of10.cstruct.OFPP_NONE
46 msg.command = of10.cstruct.OFPFC_DELETE
Dan Talaycoc901f4d2010-03-07 21:55:45 -080047 msg.buffer_id = 0xffffffff
Rich Lane5c3151c2013-01-03 17:15:41 -080048 ctrl.message_send(msg)
Rich Lane32bf9482013-01-03 17:26:30 -080049 return 0 # for backwards compatibility
Dan Talayco41eae8b2010-03-10 13:57:06 -080050
Ed Swierk99a74de2012-08-22 06:40:54 -070051def required_wildcards(parent):
Rich Lane2014f9b2012-10-05 15:29:40 -070052 w = test_param_get('required_wildcards', default='default')
Ed Swierk99a74de2012-08-22 06:40:54 -070053 if w == 'l3-l4':
Rich Lanecd97d3d2013-01-07 18:50:06 -080054 return (of10.cstruct.OFPFW_NW_SRC_ALL | of10.cstruct.OFPFW_NW_DST_ALL | of10.cstruct.OFPFW_NW_TOS
55 | of10.cstruct.OFPFW_NW_PROTO | of10.cstruct.OFPFW_TP_SRC | of10.cstruct.OFPFW_TP_DST)
Ed Swierk99a74de2012-08-22 06:40:54 -070056 else:
57 return 0
58
Dan Talayco41eae8b2010-03-10 13:57:06 -080059def simple_tcp_packet(pktlen=100,
60 dl_dst='00:01:02:03:04:05',
61 dl_src='00:06:07:08:09:0a',
Tatsuya Yabe460321e2010-05-25 17:50:49 -070062 dl_vlan_enable=False,
63 dl_vlan=0,
64 dl_vlan_pcp=0,
Dan Talayco551befa2010-07-15 17:05:32 -070065 dl_vlan_cfi=0,
Dan Talayco41eae8b2010-03-10 13:57:06 -080066 ip_src='192.168.0.1',
67 ip_dst='192.168.0.2',
Tatsuya Yabe460321e2010-05-25 17:50:49 -070068 ip_tos=0,
Gregor Maier9cc93342013-01-29 16:55:28 -080069 ip_ttl=64,
Dan Talayco41eae8b2010-03-10 13:57:06 -080070 tcp_sport=1234,
Christian Dickmann8b59b4b2012-09-23 16:48:30 -070071 tcp_dport=80,
72 ip_ihl=None,
73 ip_options=False
Dan Talayco41eae8b2010-03-10 13:57:06 -080074 ):
75 """
76 Return a simple dataplane TCP packet
77
78 Supports a few parameters:
79 @param len Length of packet in bytes w/o CRC
80 @param dl_dst Destinatino MAC
81 @param dl_src Source MAC
Tatsuya Yabe460321e2010-05-25 17:50:49 -070082 @param dl_vlan_enable True if the packet is with vlan, False otherwise
83 @param dl_vlan VLAN ID
84 @param dl_vlan_pcp VLAN priority
Dan Talayco41eae8b2010-03-10 13:57:06 -080085 @param ip_src IP source
86 @param ip_dst IP destination
Tatsuya Yabe460321e2010-05-25 17:50:49 -070087 @param ip_tos IP ToS
Gregor Maier9cc93342013-01-29 16:55:28 -080088 @param ip_ttl IP TTL
Dan Talayco41eae8b2010-03-10 13:57:06 -080089 @param tcp_dport TCP destination port
90 @param ip_sport TCP source port
91
92 Generates a simple TCP request. Users
93 shouldn't assume anything about this packet other than that
94 it is a valid ethernet/IP/TCP frame.
95 """
Jeffrey Townsend5cb7ed32012-08-17 18:11:01 +000096
97 if MINSIZE > pktlen:
98 pktlen = MINSIZE
99
Dan Talayco551befa2010-07-15 17:05:32 -0700100 # Note Dot1Q.id is really CFI
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800101 if (dl_vlan_enable):
Tatsuya Yabe460321e2010-05-25 17:50:49 -0700102 pkt = scapy.Ether(dst=dl_dst, src=dl_src)/ \
Dan Talayco551befa2010-07-15 17:05:32 -0700103 scapy.Dot1Q(prio=dl_vlan_pcp, id=dl_vlan_cfi, vlan=dl_vlan)/ \
Gregor Maier9cc93342013-01-29 16:55:28 -0800104 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ttl=ip_ttl, ihl=ip_ihl)/ \
Tatsuya Yabe460321e2010-05-25 17:50:49 -0700105 scapy.TCP(sport=tcp_sport, dport=tcp_dport)
106 else:
Christian Dickmann8b59b4b2012-09-23 16:48:30 -0700107 if not ip_options:
108 pkt = scapy.Ether(dst=dl_dst, src=dl_src)/ \
Gregor Maier9cc93342013-01-29 16:55:28 -0800109 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ttl=ip_ttl, ihl=ip_ihl)/ \
Christian Dickmann8b59b4b2012-09-23 16:48:30 -0700110 scapy.TCP(sport=tcp_sport, dport=tcp_dport)
111 else:
112 pkt = scapy.Ether(dst=dl_dst, src=dl_src)/ \
Gregor Maier9cc93342013-01-29 16:55:28 -0800113 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 -0700114 scapy.TCP(sport=tcp_sport, dport=tcp_dport)
Tatsuya Yabe460321e2010-05-25 17:50:49 -0700115
Dan Talayco41eae8b2010-03-10 13:57:06 -0800116 pkt = pkt/("D" * (pktlen - len(pkt)))
117
118 return pkt
119
Rich Lane6ee7bea2012-10-26 16:19:29 -0700120def simple_udp_packet(pktlen=100,
121 dl_dst='00:01:02:03:04:05',
122 dl_src='00:06:07:08:09:0a',
123 dl_vlan_enable=False,
124 dl_vlan=0,
125 dl_vlan_pcp=0,
126 dl_vlan_cfi=0,
127 ip_src='192.168.0.1',
128 ip_dst='192.168.0.2',
129 ip_tos=0,
Gregor Maier9cc93342013-01-29 16:55:28 -0800130 ip_ttl=64,
Rich Lane6ee7bea2012-10-26 16:19:29 -0700131 udp_sport=1234,
132 udp_dport=80,
133 ip_ihl=None,
134 ip_options=False
135 ):
136 """
137 Return a simple dataplane UDP packet
138
139 Supports a few parameters:
140 @param len Length of packet in bytes w/o CRC
141 @param dl_dst Destination MAC
142 @param dl_src Source MAC
143 @param dl_vlan_enable True if the packet is with vlan, False otherwise
144 @param dl_vlan VLAN ID
145 @param dl_vlan_pcp VLAN priority
146 @param ip_src IP source
147 @param ip_dst IP destination
148 @param ip_tos IP ToS
Gregor Maier9cc93342013-01-29 16:55:28 -0800149 @param ip_ttl IP TTL
Rich Lane6ee7bea2012-10-26 16:19:29 -0700150 @param udp_dport UDP destination port
151 @param udp_sport UDP source port
152
153 Generates a simple UDP packet. Users shouldn't assume anything about
154 this packet other than that it is a valid ethernet/IP/UDP frame.
155 """
156
157 if MINSIZE > pktlen:
158 pktlen = MINSIZE
159
160 # Note Dot1Q.id is really CFI
161 if (dl_vlan_enable):
162 pkt = scapy.Ether(dst=dl_dst, src=dl_src)/ \
163 scapy.Dot1Q(prio=dl_vlan_pcp, id=dl_vlan_cfi, vlan=dl_vlan)/ \
Gregor Maier9cc93342013-01-29 16:55:28 -0800164 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ttl=ip_ttl, ihl=ip_ihl)/ \
Rich Lane6ee7bea2012-10-26 16:19:29 -0700165 scapy.UDP(sport=udp_sport, dport=udp_dport)
166 else:
167 if not ip_options:
168 pkt = scapy.Ether(dst=dl_dst, src=dl_src)/ \
Gregor Maier9cc93342013-01-29 16:55:28 -0800169 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ttl=ip_ttl, ihl=ip_ihl)/ \
Rich Lane6ee7bea2012-10-26 16:19:29 -0700170 scapy.UDP(sport=udp_sport, dport=udp_dport)
171 else:
172 pkt = scapy.Ether(dst=dl_dst, src=dl_src)/ \
Gregor Maier9cc93342013-01-29 16:55:28 -0800173 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 -0700174 scapy.UDP(sport=udp_sport, dport=udp_dport)
175
176 pkt = pkt/("D" * (pktlen - len(pkt)))
177
178 return pkt
179
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700180def simple_icmp_packet(pktlen=60,
181 dl_dst='00:01:02:03:04:05',
182 dl_src='00:06:07:08:09:0a',
183 dl_vlan_enable=False,
184 dl_vlan=0,
185 dl_vlan_pcp=0,
186 ip_src='192.168.0.1',
187 ip_dst='192.168.0.2',
188 ip_tos=0,
Gregor Maier9cc93342013-01-29 16:55:28 -0800189 ip_ttl=64,
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700190 icmp_type=8,
191 icmp_code=0
192 ):
193 """
194 Return a simple ICMP packet
195
196 Supports a few parameters:
197 @param len Length of packet in bytes w/o CRC
198 @param dl_dst Destinatino MAC
199 @param dl_src Source MAC
200 @param dl_vlan_enable True if the packet is with vlan, False otherwise
201 @param dl_vlan VLAN ID
202 @param dl_vlan_pcp VLAN priority
203 @param ip_src IP source
204 @param ip_dst IP destination
205 @param ip_tos IP ToS
Gregor Maier9cc93342013-01-29 16:55:28 -0800206 @param ip_ttl IP TTL
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700207 @param icmp_type ICMP type
208 @param icmp_code ICMP code
209
210 Generates a simple ICMP ECHO REQUEST. Users
211 shouldn't assume anything about this packet other than that
212 it is a valid ethernet/ICMP frame.
213 """
Jeffrey Townsend5cb7ed32012-08-17 18:11:01 +0000214
215 if MINSIZE > pktlen:
216 pktlen = MINSIZE
217
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700218 if (dl_vlan_enable):
219 pkt = scapy.Ether(dst=dl_dst, src=dl_src)/ \
220 scapy.Dot1Q(prio=dl_vlan_pcp, id=0, vlan=dl_vlan)/ \
Gregor Maier9cc93342013-01-29 16:55:28 -0800221 scapy.IP(src=ip_src, dst=ip_dst, ttl=ip_ttl, tos=ip_tos)/ \
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700222 scapy.ICMP(type=icmp_type, code=icmp_code)
223 else:
224 pkt = scapy.Ether(dst=dl_dst, src=dl_src)/ \
Gregor Maier9cc93342013-01-29 16:55:28 -0800225 scapy.IP(src=ip_src, dst=ip_dst, ttl=ip_ttl, tos=ip_tos)/ \
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700226 scapy.ICMP(type=icmp_type, code=icmp_code)
227
228 pkt = pkt/("0" * (pktlen - len(pkt)))
229
230 return pkt
231
Ed Swierk0aeff8c2012-03-23 20:27:18 -0700232def simple_eth_packet(pktlen=60,
233 dl_dst='00:01:02:03:04:05',
234 dl_src='01:80:c2:00:00:00',
235 dl_type=0x88cc):
Jeffrey Townsend5cb7ed32012-08-17 18:11:01 +0000236
237 if MINSIZE > pktlen:
238 pktlen = MINSIZE
239
Ed Swierk0aeff8c2012-03-23 20:27:18 -0700240 pkt = scapy.Ether(dst=dl_dst, src=dl_src, type=dl_type)
241
242 pkt = pkt/("0" * (pktlen - len(pkt)))
243
244 return pkt
245
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800246def qinq_tcp_packet(pktlen=100,
247 dl_dst='00:01:02:03:04:05',
248 dl_src='00:06:07:08:09:0a',
249 dl_vlan_outer=20,
250 dl_vlan_pcp_outer=0,
251 dl_vlan_cfi_outer=0,
252 dl_vlan=10,
253 dl_vlan_pcp=0,
254 dl_vlan_cfi=0,
255 ip_src='192.168.0.1',
256 ip_dst='192.168.0.2',
257 ip_tos=0,
Gregor Maier9cc93342013-01-29 16:55:28 -0800258 ip_ttl=64,
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800259 tcp_sport=1234,
260 tcp_dport=80,
261 ip_ihl=None,
262 ip_options=False
263 ):
264 """
265 Return a doubly tagged dataplane TCP packet
266
267 Supports a few parameters:
268 @param len Length of packet in bytes w/o CRC
269 @param dl_dst Destinatino MAC
270 @param dl_src Source MAC
271 @param dl_vlan_outer Outer VLAN ID
272 @param dl_vlan_pcp_outer Outer VLAN priority
273 @param dl_vlan_cfi_outer Outer VLAN cfi bit
274 @param dl_vlan Inner VLAN ID
275 @param dl_vlan_pcp VLAN priority
276 @param dl_vlan_cfi VLAN cfi bit
277 @param ip_src IP source
278 @param ip_dst IP destination
279 @param ip_tos IP ToS
280 @param tcp_dport TCP destination port
281 @param ip_sport TCP source port
282
283 Generates a TCP request. Users
284 shouldn't assume anything about this packet other than that
285 it is a valid ethernet/IP/TCP frame.
286 """
287
288 if MINSIZE > pktlen:
289 pktlen = MINSIZE
290
291 # Note Dot1Q.id is really CFI
292 pkt = scapy.Ether(dst=dl_dst, src=dl_src)/ \
293 scapy.Dot1Q(prio=dl_vlan_pcp_outer, id=dl_vlan_cfi_outer, vlan=dl_vlan_outer)/ \
294 scapy.Dot1Q(prio=dl_vlan_pcp, id=dl_vlan_cfi, vlan=dl_vlan)/ \
Gregor Maier9cc93342013-01-29 16:55:28 -0800295 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ttl=ip_ttl, ihl=ip_ihl)/ \
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800296 scapy.TCP(sport=tcp_sport, dport=tcp_dport)
297
298 pkt = pkt/("D" * (pktlen - len(pkt)))
299
300 return pkt
301
Shudong Zhoub7f12462012-11-20 13:01:12 -0800302def do_barrier(ctrl, timeout=-1):
Dan Talayco0fc08bd2012-04-09 16:56:18 -0700303 """
304 Do a barrier command
305 Return 0 on success, -1 on error
306 """
Rich Lanecd97d3d2013-01-07 18:50:06 -0800307 b = of10.message.barrier_request()
Shudong Zhoub7f12462012-11-20 13:01:12 -0800308 (resp, pkt) = ctrl.transact(b, timeout=timeout)
Rich Lane3a261d52013-01-03 17:45:08 -0800309 if resp is None:
310 raise AssertionError("barrier failed")
Dan Talaycof6b94832012-04-12 21:50:57 -0700311 # We'll trust the transaction processing in the controller that xid matched
Rich Lane3a261d52013-01-03 17:45:08 -0800312 return 0 # for backwards compatibility
Dan Talayco92c99122010-06-03 13:53:18 -0700313
Rich Lane9a003812012-10-04 17:17:59 -0700314def port_config_get(controller, port_no):
Dan Talayco92c99122010-06-03 13:53:18 -0700315 """
316 Get a port's configuration
317
318 Gets the switch feature configuration and grabs one port's
319 configuration
320
321 @returns (hwaddr, config, advert) The hwaddress, configuration and
322 advertised values
323 """
Rich Lanecd97d3d2013-01-07 18:50:06 -0800324 request = of10.message.features_request()
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700325 reply, pkt = controller.transact(request)
Rich Lane9a003812012-10-04 17:17:59 -0700326 logging.debug(reply.show())
Dan Talayco92c99122010-06-03 13:53:18 -0700327 if reply is None:
Rich Lane9a003812012-10-04 17:17:59 -0700328 logging.warn("Get feature request failed")
Dan Talayco92c99122010-06-03 13:53:18 -0700329 return None, None, None
330 for idx in range(len(reply.ports)):
331 if reply.ports[idx].port_no == port_no:
332 return (reply.ports[idx].hw_addr, reply.ports[idx].config,
333 reply.ports[idx].advertised)
334
Rich Lane9a003812012-10-04 17:17:59 -0700335 logging.warn("Did not find port number for port config")
Dan Talayco92c99122010-06-03 13:53:18 -0700336 return None, None, None
337
Rich Lane9a003812012-10-04 17:17:59 -0700338def port_config_set(controller, port_no, config, mask):
Dan Talayco92c99122010-06-03 13:53:18 -0700339 """
340 Set the port configuration according the given parameters
341
342 Gets the switch feature configuration and updates one port's
343 configuration value according to config and mask
344 """
Rich Lane9a003812012-10-04 17:17:59 -0700345 logging.info("Setting port " + str(port_no) + " to config " + str(config))
Rich Lanecd97d3d2013-01-07 18:50:06 -0800346 request = of10.message.features_request()
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700347 reply, pkt = controller.transact(request)
Dan Talayco92c99122010-06-03 13:53:18 -0700348 if reply is None:
349 return -1
Rich Lane9a003812012-10-04 17:17:59 -0700350 logging.debug(reply.show())
Ed Swierk8d84ce02012-12-27 15:36:48 -0800351 p = None
Dan Talayco92c99122010-06-03 13:53:18 -0700352 for idx in range(len(reply.ports)):
353 if reply.ports[idx].port_no == port_no:
Ed Swierk8d84ce02012-12-27 15:36:48 -0800354 p = reply.ports[idx]
Dan Talayco92c99122010-06-03 13:53:18 -0700355 break
Rich Lanecd97d3d2013-01-07 18:50:06 -0800356 mod = of10.message.port_mod()
Dan Talayco92c99122010-06-03 13:53:18 -0700357 mod.port_no = port_no
Ed Swierk8d84ce02012-12-27 15:36:48 -0800358 if p:
359 mod.hw_addr = p.hw_addr
Dan Talayco92c99122010-06-03 13:53:18 -0700360 mod.config = config
361 mod.mask = mask
Ed Swierk8d84ce02012-12-27 15:36:48 -0800362 if p:
363 mod.advertise = p.advertised
Rich Lane5c3151c2013-01-03 17:15:41 -0800364 controller.message_send(mod)
365 return 0
Dan Talayco92c99122010-06-03 13:53:18 -0700366
Rich Lane2014f9b2012-10-05 15:29:40 -0700367def receive_pkt_check(dp, pkt, yes_ports, no_ports, assert_if):
Dan Talayco92c99122010-06-03 13:53:18 -0700368 """
369 Check for proper receive packets across all ports
Ken Chiang1bf01602012-04-04 10:48:23 -0700370 @param dp The dataplane object
Dan Talayco92c99122010-06-03 13:53:18 -0700371 @param pkt Expected packet; may be None if yes_ports is empty
372 @param yes_ports Set or list of ports that should recieve packet
373 @param no_ports Set or list of ports that should not receive packet
374 @param assert_if Object that implements assertXXX
375 """
Rich Lane91765672012-12-06 16:33:04 -0800376
377 # Wait this long for packets that we don't expect to receive.
378 # 100ms is (rarely) too short for positive tests on slow
379 # switches but is definitely not too short for a negative test.
380 negative_timeout = 0.1
381
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700382 exp_pkt_arg = None
Rich Lanecd97d3d2013-01-07 18:50:06 -0800383 if oftest.config["relax"]:
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700384 exp_pkt_arg = pkt
385
Dan Talayco92c99122010-06-03 13:53:18 -0700386 for ofport in yes_ports:
Rich Lane9a003812012-10-04 17:17:59 -0700387 logging.debug("Checking for pkt on port " + str(ofport))
Ken Chiang1bf01602012-04-04 10:48:23 -0700388 (rcv_port, rcv_pkt, pkt_time) = dp.poll(
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700389 port_number=ofport, exp_pkt=exp_pkt_arg)
Dan Talayco92c99122010-06-03 13:53:18 -0700390 assert_if.assertTrue(rcv_pkt is not None,
391 "Did not receive pkt on " + str(ofport))
Rich Lanecd97d3d2013-01-07 18:50:06 -0800392 if not oftest.dataplane.match_exp_pkt(pkt, rcv_pkt):
Rich Lane3c266832013-01-29 18:29:15 -0800393 logging.debug("Expected %s" % format_packet(pkt))
394 logging.debug("Received %s" % format_packet(rcv_pkt))
Rich Lanecd97d3d2013-01-07 18:50:06 -0800395 assert_if.assertTrue(oftest.dataplane.match_exp_pkt(pkt, rcv_pkt),
Rich Lane3c266832013-01-29 18:29:15 -0800396 "Received packet does not match expected packet " +
Ken Chiang1bf01602012-04-04 10:48:23 -0700397 "on port " + str(ofport))
Dan Talayco73f84012012-10-02 09:23:18 -0700398 if len(no_ports) > 0:
Rich Lane91765672012-12-06 16:33:04 -0800399 time.sleep(negative_timeout)
Dan Talayco92c99122010-06-03 13:53:18 -0700400 for ofport in no_ports:
Rich Lane9a003812012-10-04 17:17:59 -0700401 logging.debug("Negative check for pkt on port " + str(ofport))
Ken Chiang1bf01602012-04-04 10:48:23 -0700402 (rcv_port, rcv_pkt, pkt_time) = dp.poll(
Rich Lane91765672012-12-06 16:33:04 -0800403 port_number=ofport, timeout=0, exp_pkt=exp_pkt_arg)
Dan Talayco92c99122010-06-03 13:53:18 -0700404 assert_if.assertTrue(rcv_pkt is None,
405 "Unexpected pkt on port " + str(ofport))
Dan Talayco551befa2010-07-15 17:05:32 -0700406
407
Dan Talaycoc948d0b2012-03-23 12:17:54 -0700408def receive_pkt_verify(parent, egr_ports, exp_pkt, ing_port):
Dan Talayco551befa2010-07-15 17:05:32 -0700409 """
410 Receive a packet and verify it matches an expected value
Dan Talaycof6e76c02012-03-23 10:56:12 -0700411 @param egr_port A single port or list of ports
Dan Talayco551befa2010-07-15 17:05:32 -0700412
413 parent must implement dataplane, assertTrue and assertEqual
414 """
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700415 exp_pkt_arg = None
Rich Lanecd97d3d2013-01-07 18:50:06 -0800416 if oftest.config["relax"]:
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700417 exp_pkt_arg = exp_pkt
418
Dan Talaycof6e76c02012-03-23 10:56:12 -0700419 if type(egr_ports) == type([]):
420 egr_port_list = egr_ports
421 else:
422 egr_port_list = [egr_ports]
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700423
Dan Talaycof6e76c02012-03-23 10:56:12 -0700424 # Expect a packet from each port on egr port list
425 for egr_port in egr_port_list:
Dan Talaycod8ae7582012-03-23 12:24:56 -0700426 check_port = egr_port
Rich Lanecd97d3d2013-01-07 18:50:06 -0800427 if egr_port == of10.cstruct.OFPP_IN_PORT:
Dan Talaycod8ae7582012-03-23 12:24:56 -0700428 check_port = ing_port
Dan Talaycof6e76c02012-03-23 10:56:12 -0700429 (rcv_port, rcv_pkt, pkt_time) = parent.dataplane.poll(
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700430 port_number=check_port, exp_pkt=exp_pkt_arg)
Dan Talayco551befa2010-07-15 17:05:32 -0700431
Dan Talaycof6e76c02012-03-23 10:56:12 -0700432 if rcv_pkt is None:
Rich Lane9a003812012-10-04 17:17:59 -0700433 logging.error("ERROR: No packet received from " +
Dan Talaycod8ae7582012-03-23 12:24:56 -0700434 str(check_port))
Dan Talayco551befa2010-07-15 17:05:32 -0700435
Dan Talaycof6e76c02012-03-23 10:56:12 -0700436 parent.assertTrue(rcv_pkt is not None,
Dan Talaycod8ae7582012-03-23 12:24:56 -0700437 "Did not receive packet port " + str(check_port))
Rich Lane9a003812012-10-04 17:17:59 -0700438 logging.debug("Packet len " + str(len(rcv_pkt)) + " in on " +
Dan Talaycof6e76c02012-03-23 10:56:12 -0700439 str(rcv_port))
440
441 if str(exp_pkt) != str(rcv_pkt):
Rich Lane9a003812012-10-04 17:17:59 -0700442 logging.error("ERROR: Packet match failed.")
443 logging.debug("Expected len " + str(len(exp_pkt)) + ": "
Dan Talaycof6e76c02012-03-23 10:56:12 -0700444 + str(exp_pkt).encode('hex'))
Rich Lane9a003812012-10-04 17:17:59 -0700445 logging.debug("Received len " + str(len(rcv_pkt)) + ": "
Dan Talaycof6e76c02012-03-23 10:56:12 -0700446 + str(rcv_pkt).encode('hex'))
Rich Lane5d7e89a2012-10-26 16:43:13 -0700447 logging.debug("Expected packet: " + inspect_packet(scapy.Ether(str(exp_pkt))))
448 logging.debug("Received packet: " + inspect_packet(scapy.Ether(str(rcv_pkt))))
Dan Talaycof6e76c02012-03-23 10:56:12 -0700449 parent.assertEqual(str(exp_pkt), str(rcv_pkt),
Dan Talaycod8ae7582012-03-23 12:24:56 -0700450 "Packet match error on port " + str(check_port))
Dan Talaycof6e76c02012-03-23 10:56:12 -0700451
Dan Talayco551befa2010-07-15 17:05:32 -0700452def match_verify(parent, req_match, res_match):
453 """
454 Verify flow matches agree; if they disagree, report where
455
456 parent must implement assertEqual
457 Use str() to ensure content is compared and not pointers
458 """
459
460 parent.assertEqual(req_match.wildcards, res_match.wildcards,
461 'Match failed: wildcards: ' + hex(req_match.wildcards) +
462 " != " + hex(res_match.wildcards))
463 parent.assertEqual(req_match.in_port, res_match.in_port,
464 'Match failed: in_port: ' + str(req_match.in_port) +
465 " != " + str(res_match.in_port))
466 parent.assertEqual(str(req_match.dl_src), str(res_match.dl_src),
467 'Match failed: dl_src: ' + str(req_match.dl_src) +
468 " != " + str(res_match.dl_src))
469 parent.assertEqual(str(req_match.dl_dst), str(res_match.dl_dst),
470 'Match failed: dl_dst: ' + str(req_match.dl_dst) +
471 " != " + str(res_match.dl_dst))
472 parent.assertEqual(req_match.dl_vlan, res_match.dl_vlan,
473 'Match failed: dl_vlan: ' + str(req_match.dl_vlan) +
474 " != " + str(res_match.dl_vlan))
475 parent.assertEqual(req_match.dl_vlan_pcp, res_match.dl_vlan_pcp,
476 'Match failed: dl_vlan_pcp: ' +
477 str(req_match.dl_vlan_pcp) + " != " +
478 str(res_match.dl_vlan_pcp))
479 parent.assertEqual(req_match.dl_type, res_match.dl_type,
480 'Match failed: dl_type: ' + str(req_match.dl_type) +
481 " != " + str(res_match.dl_type))
482
Rich Lanecd97d3d2013-01-07 18:50:06 -0800483 if (not(req_match.wildcards & of10.cstruct.OFPFW_DL_TYPE)
Dan Talayco551befa2010-07-15 17:05:32 -0700484 and (req_match.dl_type == IP_ETHERTYPE)):
485 parent.assertEqual(req_match.nw_tos, res_match.nw_tos,
486 'Match failed: nw_tos: ' + str(req_match.nw_tos) +
487 " != " + str(res_match.nw_tos))
488 parent.assertEqual(req_match.nw_proto, res_match.nw_proto,
489 'Match failed: nw_proto: ' + str(req_match.nw_proto) +
490 " != " + str(res_match.nw_proto))
491 parent.assertEqual(req_match.nw_src, res_match.nw_src,
492 'Match failed: nw_src: ' + str(req_match.nw_src) +
493 " != " + str(res_match.nw_src))
494 parent.assertEqual(req_match.nw_dst, res_match.nw_dst,
495 'Match failed: nw_dst: ' + str(req_match.nw_dst) +
496 " != " + str(res_match.nw_dst))
497
Rich Lanecd97d3d2013-01-07 18:50:06 -0800498 if (not(req_match.wildcards & of10.cstruct.OFPFW_NW_PROTO)
Dan Talayco551befa2010-07-15 17:05:32 -0700499 and ((req_match.nw_proto == TCP_PROTOCOL)
500 or (req_match.nw_proto == UDP_PROTOCOL))):
501 parent.assertEqual(req_match.tp_src, res_match.tp_src,
502 'Match failed: tp_src: ' +
503 str(req_match.tp_src) +
504 " != " + str(res_match.tp_src))
505 parent.assertEqual(req_match.tp_dst, res_match.tp_dst,
506 'Match failed: tp_dst: ' +
507 str(req_match.tp_dst) +
508 " != " + str(res_match.tp_dst))
509
Ed Swierk99a74de2012-08-22 06:40:54 -0700510def packet_to_flow_match(parent, packet):
Rich Lanecd97d3d2013-01-07 18:50:06 -0800511 match = of10.parse.packet_to_flow_match(packet)
Ed Swierk99a74de2012-08-22 06:40:54 -0700512 match.wildcards |= required_wildcards(parent)
513 return match
514
515def flow_msg_create(parent, pkt, ing_port=None, action_list=None, wildcards=None,
Dan Talaycof6e76c02012-03-23 10:56:12 -0700516 egr_ports=None, egr_queue=None, check_expire=False, in_band=False):
Dan Talayco551befa2010-07-15 17:05:32 -0700517 """
518 Create a flow message
519
520 Match on packet with given wildcards.
521 See flow_match_test for other parameter descriptoins
522 @param egr_queue if not None, make the output an enqueue action
Dan Talayco677c0b72011-08-23 22:53:38 -0700523 @param in_band if True, do not wildcard ingress port
Dan Talaycof6e76c02012-03-23 10:56:12 -0700524 @param egr_ports None (drop), single port or list of ports
Dan Talayco551befa2010-07-15 17:05:32 -0700525 """
Rich Lanecd97d3d2013-01-07 18:50:06 -0800526 match = of10.parse.packet_to_flow_match(pkt)
Dan Talayco551befa2010-07-15 17:05:32 -0700527 parent.assertTrue(match is not None, "Flow match from pkt failed")
Ed Swierk99a74de2012-08-22 06:40:54 -0700528 if wildcards is None:
529 wildcards = required_wildcards(parent)
Dan Talayco677c0b72011-08-23 22:53:38 -0700530 if in_band:
Rich Lanecd97d3d2013-01-07 18:50:06 -0800531 wildcards &= ~of10.cstruct.OFPFW_IN_PORT
Dan Talayco551befa2010-07-15 17:05:32 -0700532 match.wildcards = wildcards
533 match.in_port = ing_port
534
Dan Talaycof6e76c02012-03-23 10:56:12 -0700535 if type(egr_ports) == type([]):
536 egr_port_list = egr_ports
537 else:
538 egr_port_list = [egr_ports]
539
Rich Lanecd97d3d2013-01-07 18:50:06 -0800540 request = of10.message.flow_mod()
Dan Talayco551befa2010-07-15 17:05:32 -0700541 request.match = match
542 request.buffer_id = 0xffffffff
543 if check_expire:
Rich Lanecd97d3d2013-01-07 18:50:06 -0800544 request.flags |= of10.cstruct.OFPFF_SEND_FLOW_REM
Dan Talayco551befa2010-07-15 17:05:32 -0700545 request.hard_timeout = 1
546
547 if action_list is not None:
548 for act in action_list:
Rich Lane9a003812012-10-04 17:17:59 -0700549 logging.debug("Adding action " + act.show())
Rich Lanee30455b2013-01-03 16:24:44 -0800550 request.actions.add(act)
Dan Talayco551befa2010-07-15 17:05:32 -0700551
552 # Set up output/enqueue action if directed
553 if egr_queue is not None:
Dan Talaycof6e76c02012-03-23 10:56:12 -0700554 parent.assertTrue(egr_ports is not None, "Egress port not set")
Rich Lanecd97d3d2013-01-07 18:50:06 -0800555 act = of10.action.action_enqueue()
Dan Talaycof6e76c02012-03-23 10:56:12 -0700556 for egr_port in egr_port_list:
557 act.port = egr_port
558 act.queue_id = egr_queue
Rich Lanee30455b2013-01-03 16:24:44 -0800559 request.actions.add(act)
Dan Talaycof6e76c02012-03-23 10:56:12 -0700560 elif egr_ports is not None:
561 for egr_port in egr_port_list:
Rich Lanecd97d3d2013-01-07 18:50:06 -0800562 act = of10.action.action_output()
Dan Talaycof6e76c02012-03-23 10:56:12 -0700563 act.port = egr_port
Rich Lanee30455b2013-01-03 16:24:44 -0800564 request.actions.add(act)
Dan Talayco551befa2010-07-15 17:05:32 -0700565
Rich Lane9a003812012-10-04 17:17:59 -0700566 logging.debug(request.show())
Dan Talayco551befa2010-07-15 17:05:32 -0700567
568 return request
569
Jeffrey Townsendf3eae9c2012-03-28 18:23:21 -0700570def flow_msg_install(parent, request, clear_table_override=None):
Dan Talayco551befa2010-07-15 17:05:32 -0700571 """
572 Install a flow mod message in the switch
573
574 @param parent Must implement controller, assertEqual, assertTrue
575 @param request The request, all set to go
576 @param clear_table If true, clear the flow table before installing
577 """
Dan Talayco8a64e332012-03-28 14:53:20 -0700578
Rich Lane2014f9b2012-10-05 15:29:40 -0700579 clear_table = test_param_get('clear_table', default=True)
Jeffrey Townsendf3eae9c2012-03-28 18:23:21 -0700580 if(clear_table_override != None):
581 clear_table = clear_table_override
582
583 if clear_table:
Rich Lane9a003812012-10-04 17:17:59 -0700584 logging.debug("Clear flow table")
Rich Lane32bf9482013-01-03 17:26:30 -0800585 delete_all_flows(parent.controller)
Dan Talayco551befa2010-07-15 17:05:32 -0700586
Rich Lane9a003812012-10-04 17:17:59 -0700587 logging.debug("Insert flow")
Rich Lane5c3151c2013-01-03 17:15:41 -0800588 parent.controller.message_send(request)
Rich Lanee912d032012-12-22 14:28:33 -0800589
Rich Lane3a261d52013-01-03 17:45:08 -0800590 do_barrier(parent.controller)
Dan Talayco551befa2010-07-15 17:05:32 -0700591
Ed Swierk99a74de2012-08-22 06:40:54 -0700592def flow_match_test_port_pair(parent, ing_port, egr_ports, wildcards=None,
Dan Talayco551befa2010-07-15 17:05:32 -0700593 dl_vlan=-1, pkt=None, exp_pkt=None,
Rich Lanee5779d32012-10-05 17:56:04 -0700594 action_list=None):
Dan Talayco551befa2010-07-15 17:05:32 -0700595 """
596 Flow match test on single TCP packet
Dan Talaycof6e76c02012-03-23 10:56:12 -0700597 @param egr_ports A single port or list of ports
Dan Talayco551befa2010-07-15 17:05:32 -0700598
599 Run test with packet through switch from ing_port to egr_port
600 See flow_match_test for parameter descriptions
601 """
602
Ed Swierk99a74de2012-08-22 06:40:54 -0700603 if wildcards is None:
604 wildcards = required_wildcards(parent)
Rich Lane9a003812012-10-04 17:17:59 -0700605 logging.info("Pkt match test: " + str(ing_port) + " to " +
Dan Talaycof6e76c02012-03-23 10:56:12 -0700606 str(egr_ports))
Rich Lanee5779d32012-10-05 17:56:04 -0700607 logging.debug(" WC: " + hex(wildcards) + " vlan: " + str(dl_vlan))
Dan Talayco551befa2010-07-15 17:05:32 -0700608 if pkt is None:
609 pkt = simple_tcp_packet(dl_vlan_enable=(dl_vlan >= 0), dl_vlan=dl_vlan)
610
611 request = flow_msg_create(parent, pkt, ing_port=ing_port,
Dan Talaycof6e76c02012-03-23 10:56:12 -0700612 wildcards=wildcards, egr_ports=egr_ports,
Dan Talayco551befa2010-07-15 17:05:32 -0700613 action_list=action_list)
614
615 flow_msg_install(parent, request)
616
Rich Lane9a003812012-10-04 17:17:59 -0700617 logging.debug("Send packet: " + str(ing_port) + " to " +
Dan Talaycof6e76c02012-03-23 10:56:12 -0700618 str(egr_ports))
Dan Talayco551befa2010-07-15 17:05:32 -0700619 parent.dataplane.send(ing_port, str(pkt))
620
621 if exp_pkt is None:
622 exp_pkt = pkt
Dan Talaycoc948d0b2012-03-23 12:17:54 -0700623 receive_pkt_verify(parent, egr_ports, exp_pkt, ing_port)
Dan Talayco551befa2010-07-15 17:05:32 -0700624
Rich Lane89725bb2012-12-03 16:23:27 -0800625def flow_match_test_pktout(parent, ing_port, egr_ports,
626 dl_vlan=-1, pkt=None, exp_pkt=None,
627 action_list=None):
628 """
629 Packet-out test on single TCP packet
630 @param egr_ports A single port or list of ports
631
632 Run test sending packet-out to egr_ports. The goal is to test the actions
633 taken on the packet, not the matching which is of course irrelevant.
634 See flow_match_test for parameter descriptions
635 """
636
637 if pkt is None:
638 pkt = simple_tcp_packet(dl_vlan_enable=(dl_vlan >= 0), dl_vlan=dl_vlan)
639
Rich Lanecd97d3d2013-01-07 18:50:06 -0800640 msg = of10.message.packet_out()
Rich Lane89725bb2012-12-03 16:23:27 -0800641 msg.in_port = ing_port
642 msg.data = str(pkt)
643 if action_list is not None:
644 for act in action_list:
Rich Lanee30455b2013-01-03 16:24:44 -0800645 msg.actions.add(act)
Rich Lane89725bb2012-12-03 16:23:27 -0800646
647 # Set up output action
648 if egr_ports is not None:
649 for egr_port in egr_ports:
Rich Lanecd97d3d2013-01-07 18:50:06 -0800650 act = of10.action.action_output()
Rich Lane89725bb2012-12-03 16:23:27 -0800651 act.port = egr_port
Rich Lanee30455b2013-01-03 16:24:44 -0800652 msg.actions.add(act)
Rich Lane89725bb2012-12-03 16:23:27 -0800653
654 logging.debug(msg.show())
Rich Lane5c3151c2013-01-03 17:15:41 -0800655 parent.controller.message_send(msg)
Rich Lane89725bb2012-12-03 16:23:27 -0800656
657 if exp_pkt is None:
658 exp_pkt = pkt
659 receive_pkt_verify(parent, egr_ports, exp_pkt, ing_port)
660
Dan Talaycof6e76c02012-03-23 10:56:12 -0700661def get_egr_list(parent, of_ports, how_many, exclude_list=[]):
662 """
663 Generate a list of ports avoiding those in the exclude list
Rich Lane9a003812012-10-04 17:17:59 -0700664 @param parent Supplies logging
Dan Talaycof6e76c02012-03-23 10:56:12 -0700665 @param of_ports List of OF port numbers
666 @param how_many Number of ports to be added to the list
667 @param exclude_list List of ports not to be used
668 @returns An empty list if unable to find enough ports
669 """
670
Dan Talaycoc948d0b2012-03-23 12:17:54 -0700671 if how_many == 0:
672 return []
673
Dan Talaycof6e76c02012-03-23 10:56:12 -0700674 count = 0
675 egr_ports = []
676 for egr_idx in range(len(of_ports)):
677 if of_ports[egr_idx] not in exclude_list:
678 egr_ports.append(of_ports[egr_idx])
679 count += 1
680 if count >= how_many:
681 return egr_ports
Rich Lane9a003812012-10-04 17:17:59 -0700682 logging.debug("Could not generate enough egress ports for test")
Dan Talaycof6e76c02012-03-23 10:56:12 -0700683 return []
684
Ed Swierk99a74de2012-08-22 06:40:54 -0700685def flow_match_test(parent, port_map, wildcards=None, dl_vlan=-1, pkt=None,
Rich Lanee5779d32012-10-05 17:56:04 -0700686 exp_pkt=None, action_list=None,
Dan Talaycoc948d0b2012-03-23 12:17:54 -0700687 max_test=0, egr_count=1, ing_port=False):
Dan Talayco551befa2010-07-15 17:05:32 -0700688 """
Rich Lane89725bb2012-12-03 16:23:27 -0800689 Run flow_match_test_port_pair on all port pairs and packet-out
Dan Talayco551befa2010-07-15 17:05:32 -0700690
691 @param max_test If > 0 no more than this number of tests are executed.
692 @param parent Must implement controller, dataplane, assertTrue, assertEqual
Rich Lane9a003812012-10-04 17:17:59 -0700693 and logging
Dan Talayco551befa2010-07-15 17:05:32 -0700694 @param pkt If not None, use this packet for ingress
695 @param wildcards For flow match entry
Dan Talayco79184222010-11-01 12:24:29 -0700696 @param dl_vlan If not -1, and pkt is None, create a pkt w/ VLAN tag
Dan Talayco551befa2010-07-15 17:05:32 -0700697 @param exp_pkt If not None, use this as the expected output pkt; els use pkt
698 @param action_list Additional actions to add to flow mod
Dan Talaycocfa172f2012-03-23 12:03:00 -0700699 @param egr_count Number of egress ports; -1 means get from config w/ dflt 2
Dan Talayco551befa2010-07-15 17:05:32 -0700700 """
Ed Swierk99a74de2012-08-22 06:40:54 -0700701 if wildcards is None:
702 wildcards = required_wildcards(parent)
Dan Talayco551befa2010-07-15 17:05:32 -0700703 of_ports = port_map.keys()
704 of_ports.sort()
705 parent.assertTrue(len(of_ports) > 1, "Not enough ports for test")
706 test_count = 0
707
Dan Talaycocfa172f2012-03-23 12:03:00 -0700708 if egr_count == -1:
Rich Lane2014f9b2012-10-05 15:29:40 -0700709 egr_count = test_param_get('egr_count', default=2)
Dan Talaycocfa172f2012-03-23 12:03:00 -0700710
Dan Talayco551befa2010-07-15 17:05:32 -0700711 for ing_idx in range(len(of_ports)):
712 ingress_port = of_ports[ing_idx]
Dan Talaycof6e76c02012-03-23 10:56:12 -0700713 egr_ports = get_egr_list(parent, of_ports, egr_count,
714 exclude_list=[ingress_port])
Dan Talaycoc948d0b2012-03-23 12:17:54 -0700715 if ing_port:
Rich Lanecd97d3d2013-01-07 18:50:06 -0800716 egr_ports.append(of10.cstruct.OFPP_IN_PORT)
Dan Talaycof6e76c02012-03-23 10:56:12 -0700717 if len(egr_ports) == 0:
718 parent.assertTrue(0, "Failed to generate egress port list")
719
720 flow_match_test_port_pair(parent, ingress_port, egr_ports,
721 wildcards=wildcards, dl_vlan=dl_vlan,
722 pkt=pkt, exp_pkt=exp_pkt,
Rich Lanee5779d32012-10-05 17:56:04 -0700723 action_list=action_list)
Dan Talaycof6e76c02012-03-23 10:56:12 -0700724 test_count += 1
725 if (max_test > 0) and (test_count > max_test):
Rich Lane9a003812012-10-04 17:17:59 -0700726 logging.info("Ran " + str(test_count) + " tests; exiting")
Rich Lane89725bb2012-12-03 16:23:27 -0800727 break
728
Ed Swierk38eea082013-01-02 19:46:20 -0800729 if not test_param_get('pktout_actions', default=True):
730 return
Rich Lane89725bb2012-12-03 16:23:27 -0800731
732 ingress_port = of_ports[0]
733 egr_ports = get_egr_list(parent, of_ports, egr_count,
734 exclude_list=[ingress_port])
735 if ing_port:
Rich Lanecd97d3d2013-01-07 18:50:06 -0800736 egr_ports.append(of10.cstruct.OFPP_IN_PORT)
Rich Lane89725bb2012-12-03 16:23:27 -0800737 flow_match_test_pktout(parent, ingress_port, egr_ports,
738 dl_vlan=dl_vlan,
739 pkt=pkt, exp_pkt=exp_pkt,
740 action_list=action_list)
Dan Talayco551befa2010-07-15 17:05:32 -0700741
Rich Lane2014f9b2012-10-05 15:29:40 -0700742def test_param_get(key, default=None):
Dan Talayco4b2bee62010-07-20 14:10:05 -0700743 """
744 Return value passed via test-params if present
745
Dan Talayco4b2bee62010-07-20 14:10:05 -0700746 @param key The lookup key
747 @param default Default value to use if not found
748
749 If the pair 'key=val' appeared in the string passed to --test-params
750 on the command line, return val (as interpreted by exec). Otherwise
751 return default value.
Dan Talaycof6e76c02012-03-23 10:56:12 -0700752
753 WARNING: TEST PARAMETERS MUST BE PYTHON IDENTIFIERS;
754 eg egr_count, not egr-count.
Dan Talayco4b2bee62010-07-20 14:10:05 -0700755 """
756 try:
Rich Lanecd97d3d2013-01-07 18:50:06 -0800757 exec oftest.config["test_params"]
Dan Talayco4b2bee62010-07-20 14:10:05 -0700758 except:
759 return default
760
761 s = "val = " + str(key)
762 try:
763 exec s
764 return val
765 except:
766 return default
767
768def action_generate(parent, field_to_mod, mod_field_vals):
769 """
770 Create an action to modify the field indicated in field_to_mod
771
772 @param parent Must implement, assertTrue
773 @param field_to_mod The field to modify as a string name
774 @param mod_field_vals Hash of values to use for modified values
775 """
776
777 act = None
778
779 if field_to_mod in ['pktlen']:
780 return None
781
782 if field_to_mod == 'dl_dst':
Rich Lanecd97d3d2013-01-07 18:50:06 -0800783 act = of10.action.action_set_dl_dst()
784 act.dl_addr = of10.parse.parse_mac(mod_field_vals['dl_dst'])
Dan Talayco4b2bee62010-07-20 14:10:05 -0700785 elif field_to_mod == 'dl_src':
Rich Lanecd97d3d2013-01-07 18:50:06 -0800786 act = of10.action.action_set_dl_src()
787 act.dl_addr = of10.parse.parse_mac(mod_field_vals['dl_src'])
Dan Talayco4b2bee62010-07-20 14:10:05 -0700788 elif field_to_mod == 'dl_vlan_enable':
789 if not mod_field_vals['dl_vlan_enable']: # Strip VLAN tag
Rich Lanecd97d3d2013-01-07 18:50:06 -0800790 act = of10.action.action_strip_vlan()
Dan Talayco4b2bee62010-07-20 14:10:05 -0700791 # Add VLAN tag is handled by dl_vlan field
792 # Will return None in this case
793 elif field_to_mod == 'dl_vlan':
Rich Lanecd97d3d2013-01-07 18:50:06 -0800794 act = of10.action.action_set_vlan_vid()
Dan Talayco4b2bee62010-07-20 14:10:05 -0700795 act.vlan_vid = mod_field_vals['dl_vlan']
796 elif field_to_mod == 'dl_vlan_pcp':
Rich Lanecd97d3d2013-01-07 18:50:06 -0800797 act = of10.action.action_set_vlan_pcp()
Dan Talayco4b2bee62010-07-20 14:10:05 -0700798 act.vlan_pcp = mod_field_vals['dl_vlan_pcp']
799 elif field_to_mod == 'ip_src':
Rich Lanecd97d3d2013-01-07 18:50:06 -0800800 act = of10.action.action_set_nw_src()
801 act.nw_addr = of10.parse.parse_ip(mod_field_vals['ip_src'])
Dan Talayco4b2bee62010-07-20 14:10:05 -0700802 elif field_to_mod == 'ip_dst':
Rich Lanecd97d3d2013-01-07 18:50:06 -0800803 act = of10.action.action_set_nw_dst()
804 act.nw_addr = of10.parse.parse_ip(mod_field_vals['ip_dst'])
Dan Talayco4b2bee62010-07-20 14:10:05 -0700805 elif field_to_mod == 'ip_tos':
Rich Lanecd97d3d2013-01-07 18:50:06 -0800806 act = of10.action.action_set_nw_tos()
Dan Talayco4b2bee62010-07-20 14:10:05 -0700807 act.nw_tos = mod_field_vals['ip_tos']
808 elif field_to_mod == 'tcp_sport':
Rich Lanecd97d3d2013-01-07 18:50:06 -0800809 act = of10.action.action_set_tp_src()
Dan Talayco4b2bee62010-07-20 14:10:05 -0700810 act.tp_port = mod_field_vals['tcp_sport']
811 elif field_to_mod == 'tcp_dport':
Rich Lanecd97d3d2013-01-07 18:50:06 -0800812 act = of10.action.action_set_tp_dst()
Dan Talayco4b2bee62010-07-20 14:10:05 -0700813 act.tp_port = mod_field_vals['tcp_dport']
Rich Lane110e0e32012-10-26 16:21:46 -0700814 elif field_to_mod == 'udp_sport':
Rich Lanecd97d3d2013-01-07 18:50:06 -0800815 act = of10.action.action_set_tp_src()
Rich Lane110e0e32012-10-26 16:21:46 -0700816 act.tp_port = mod_field_vals['udp_sport']
817 elif field_to_mod == 'udp_dport':
Rich Lanecd97d3d2013-01-07 18:50:06 -0800818 act = of10.action.action_set_tp_dst()
Rich Lane110e0e32012-10-26 16:21:46 -0700819 act.tp_port = mod_field_vals['udp_dport']
Dan Talayco4b2bee62010-07-20 14:10:05 -0700820 else:
821 parent.assertTrue(0, "Unknown field to modify: " + str(field_to_mod))
822
823 return act
824
825def pkt_action_setup(parent, start_field_vals={}, mod_field_vals={},
Rich Lane110e0e32012-10-26 16:21:46 -0700826 mod_fields=[], tp="tcp", check_test_params=False):
Dan Talayco4b2bee62010-07-20 14:10:05 -0700827 """
828 Set up the ingress and expected packet and action list for a test
829
Rich Lane2014f9b2012-10-05 15:29:40 -0700830 @param parent Must implement assertTrue
Dan Talayco4b2bee62010-07-20 14:10:05 -0700831 @param start_field_values Field values to use for ingress packet (optional)
832 @param mod_field_values Field values to use for modified packet (optional)
833 @param mod_fields The list of fields to be modified by the switch in the test.
834 @params check_test_params If True, will check the parameters vid, add_vlan
835 and strip_vlan from the command line.
836
837 Returns a triple: pkt-to-send, expected-pkt, action-list
838 """
839
840 new_actions = []
841
Dan Talayco4b2bee62010-07-20 14:10:05 -0700842 base_pkt_params = {}
843 base_pkt_params['pktlen'] = 100
844 base_pkt_params['dl_dst'] = '00:DE:F0:12:34:56'
845 base_pkt_params['dl_src'] = '00:23:45:67:89:AB'
846 base_pkt_params['dl_vlan_enable'] = False
847 base_pkt_params['dl_vlan'] = 2
848 base_pkt_params['dl_vlan_pcp'] = 0
849 base_pkt_params['ip_src'] = '192.168.0.1'
850 base_pkt_params['ip_dst'] = '192.168.0.2'
851 base_pkt_params['ip_tos'] = 0
Rich Lane110e0e32012-10-26 16:21:46 -0700852 if tp == "tcp":
853 base_pkt_params['tcp_sport'] = 1234
854 base_pkt_params['tcp_dport'] = 80
855 elif tp == "udp":
856 base_pkt_params['udp_sport'] = 1234
857 base_pkt_params['udp_dport'] = 80
Dan Talayco4b2bee62010-07-20 14:10:05 -0700858 for keyname in start_field_vals.keys():
859 base_pkt_params[keyname] = start_field_vals[keyname]
860
861 mod_pkt_params = {}
862 mod_pkt_params['pktlen'] = 100
863 mod_pkt_params['dl_dst'] = '00:21:0F:ED:CB:A9'
864 mod_pkt_params['dl_src'] = '00:ED:CB:A9:87:65'
865 mod_pkt_params['dl_vlan_enable'] = False
866 mod_pkt_params['dl_vlan'] = 3
867 mod_pkt_params['dl_vlan_pcp'] = 7
868 mod_pkt_params['ip_src'] = '10.20.30.40'
869 mod_pkt_params['ip_dst'] = '50.60.70.80'
870 mod_pkt_params['ip_tos'] = 0xf0
Rich Lane110e0e32012-10-26 16:21:46 -0700871 if tp == "tcp":
872 mod_pkt_params['tcp_sport'] = 4321
873 mod_pkt_params['tcp_dport'] = 8765
874 elif tp == "udp":
875 mod_pkt_params['udp_sport'] = 4321
876 mod_pkt_params['udp_dport'] = 8765
Dan Talayco4b2bee62010-07-20 14:10:05 -0700877 for keyname in mod_field_vals.keys():
878 mod_pkt_params[keyname] = mod_field_vals[keyname]
879
880 # Check for test param modifications
881 strip = False
882 if check_test_params:
Rich Lane2014f9b2012-10-05 15:29:40 -0700883 add_vlan = test_param_get('add_vlan')
884 strip_vlan = test_param_get('strip_vlan')
885 vid = test_param_get('vid')
Dan Talayco4b2bee62010-07-20 14:10:05 -0700886
887 if add_vlan and strip_vlan:
888 parent.assertTrue(0, "Add and strip VLAN both specified")
889
890 if vid:
891 base_pkt_params['dl_vlan_enable'] = True
892 base_pkt_params['dl_vlan'] = vid
893 if 'dl_vlan' in mod_fields:
894 mod_pkt_params['dl_vlan'] = vid + 1
895
896 if add_vlan:
897 base_pkt_params['dl_vlan_enable'] = False
898 mod_pkt_params['dl_vlan_enable'] = True
899 mod_pkt_params['pktlen'] = base_pkt_params['pktlen'] + 4
900 mod_fields.append('pktlen')
901 mod_fields.append('dl_vlan_enable')
902 if 'dl_vlan' not in mod_fields:
903 mod_fields.append('dl_vlan')
904 elif strip_vlan:
905 base_pkt_params['dl_vlan_enable'] = True
906 mod_pkt_params['dl_vlan_enable'] = False
907 mod_pkt_params['pktlen'] = base_pkt_params['pktlen'] - 4
908 mod_fields.append('dl_vlan_enable')
909 mod_fields.append('pktlen')
910
Rich Lane110e0e32012-10-26 16:21:46 -0700911 if tp == "tcp":
912 packet_builder = simple_tcp_packet
913 elif tp == "udp":
914 packet_builder = simple_udp_packet
915 else:
916 raise NotImplementedError("unknown transport protocol %s" % tp)
917
Dan Talayco4b2bee62010-07-20 14:10:05 -0700918 # Build the ingress packet
Rich Lane110e0e32012-10-26 16:21:46 -0700919 ingress_pkt = packet_builder(**base_pkt_params)
Dan Talayco4b2bee62010-07-20 14:10:05 -0700920
921 # Build the expected packet, modifying the indicated fields
922 for item in mod_fields:
923 base_pkt_params[item] = mod_pkt_params[item]
924 act = action_generate(parent, item, mod_pkt_params)
925 if act:
926 new_actions.append(act)
927
Rich Lane110e0e32012-10-26 16:21:46 -0700928 expected_pkt = packet_builder(**base_pkt_params)
Dan Talayco4b2bee62010-07-20 14:10:05 -0700929
930 return (ingress_pkt, expected_pkt, new_actions)
Dan Talayco677c0b72011-08-23 22:53:38 -0700931
932# Generate a simple "drop" flow mod
933# If in_band is true, then only drop from first test port
934def flow_mod_gen(port_map, in_band):
Rich Lanecd97d3d2013-01-07 18:50:06 -0800935 request = of10.message.flow_mod()
936 request.match.wildcards = of10.cstruct.OFPFW_ALL
Dan Talayco677c0b72011-08-23 22:53:38 -0700937 if in_band:
Rich Lanecd97d3d2013-01-07 18:50:06 -0800938 request.match.wildcards = of10.cstruct.OFPFW_ALL - of10.cstruct.OFPFW_IN_PORT
Dan Talayco677c0b72011-08-23 22:53:38 -0700939 for of_port, ifname in port_map.items(): # Grab first port
940 break
941 request.match.in_port = of_port
942 request.buffer_id = 0xffffffff
943 return request
Dan Talaycoba3745c2010-07-21 21:51:08 -0700944
945def skip_message_emit(parent, s):
946 """
947 Print out a 'skipped' message to stderr
948
949 @param s The string to print out to the log file
Dan Talaycoba3745c2010-07-21 21:51:08 -0700950 """
951 global skipped_test_count
952
953 skipped_test_count += 1
Rich Lane9a003812012-10-04 17:17:59 -0700954 logging.info("Skipping: " + s)
Rich Lanecd97d3d2013-01-07 18:50:06 -0800955 if oftest.config["dbg_level"] < logging.WARNING:
Dan Talaycoba3745c2010-07-21 21:51:08 -0700956 sys.stderr.write("(skipped) ")
957 else:
958 sys.stderr.write("(S)")
Dan Talayco677c0b72011-08-23 22:53:38 -0700959
Dan Talayco8a64e332012-03-28 14:53:20 -0700960
961def all_stats_get(parent):
962 """
963 Get the aggregate stats for all flows in the table
964 @param parent Test instance with controller connection and assert
965 @returns dict with keys flows, packets, bytes, active (flows),
966 lookups, matched
967 """
Rich Lanecd97d3d2013-01-07 18:50:06 -0800968 stat_req = of10.message.aggregate_stats_request()
969 stat_req.match = of10.cstruct.ofp_match()
970 stat_req.match.wildcards = of10.cstruct.OFPFW_ALL
Dan Talayco8a64e332012-03-28 14:53:20 -0700971 stat_req.table_id = 0xff
Rich Lanecd97d3d2013-01-07 18:50:06 -0800972 stat_req.out_port = of10.cstruct.OFPP_NONE
Dan Talayco8a64e332012-03-28 14:53:20 -0700973
974 rv = {}
975
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700976 (reply, pkt) = parent.controller.transact(stat_req)
Dan Talayco8a64e332012-03-28 14:53:20 -0700977 parent.assertTrue(len(reply.stats) == 1, "Did not receive flow stats reply")
978
979 for obj in reply.stats:
980 (rv["flows"], rv["packets"], rv["bytes"]) = (obj.flow_count,
981 obj.packet_count, obj.byte_count)
982 break
983
Rich Lanecd97d3d2013-01-07 18:50:06 -0800984 request = of10.message.table_stats_request()
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700985 (reply , pkt) = parent.controller.transact(request)
Dan Talayco8a64e332012-03-28 14:53:20 -0700986
987
988 (rv["active"], rv["lookups"], rv["matched"]) = (0,0,0)
989 for obj in reply.stats:
990 rv["active"] += obj.active_count
991 rv["lookups"] += obj.lookup_count
992 rv["matched"] += obj.matched_count
993
994 return rv
Dan Talayco2baf8b52012-03-30 09:55:42 -0700995
Rich Lane7744e112013-01-11 17:23:57 -0800996_import_blacklist.add('FILTER')
Dan Talayco2baf8b52012-03-30 09:55:42 -0700997FILTER=''.join([(len(repr(chr(x)))==3) and chr(x) or '.'
998 for x in range(256)])
999
1000def hex_dump_buffer(src, length=16):
1001 """
1002 Convert src to a hex dump string and return the string
1003 @param src The source buffer
1004 @param length The number of bytes shown in each line
1005 @returns A string showing the hex dump
1006 """
Dan Talaycoc516fa02012-04-12 22:28:43 -07001007 result = ["\n"]
Dan Talayco2baf8b52012-03-30 09:55:42 -07001008 for i in xrange(0, len(src), length):
1009 chars = src[i:i+length]
1010 hex = ' '.join(["%02x" % ord(x) for x in chars])
1011 printable = ''.join(["%s" % ((ord(x) <= 127 and
1012 FILTER[ord(x)]) or '.') for x in chars])
1013 result.append("%04x %-*s %s\n" % (i, length*3, hex, printable))
1014 return ''.join(result)
1015
1016def format_packet(pkt):
1017 return "Packet length %d \n%s" % (len(str(pkt)),
1018 hex_dump_buffer(str(pkt)))
Rich Lane5d7e89a2012-10-26 16:43:13 -07001019
1020def inspect_packet(pkt):
1021 """
1022 Wrapper around scapy's show() method.
1023 @returns A string showing the dissected packet.
1024 """
1025 from cStringIO import StringIO
1026 out = None
1027 backup = sys.stdout
1028 try:
1029 sys.stdout = StringIO()
1030 pkt.show2()
1031 out = sys.stdout.getvalue()
1032 sys.stdout.close()
1033 finally:
1034 sys.stdout = backup
1035 return out
Rich Lane0a4f6372013-01-02 14:40:22 -08001036
1037def nonstandard(cls):
1038 """
Rich Lanecc45b8e2013-01-02 15:55:02 -08001039 Testcase decorator that marks the test as being non-standard.
1040 These tests are not automatically added to the "standard" group.
Rich Lane0a4f6372013-01-02 14:40:22 -08001041 """
Rich Lanecc45b8e2013-01-02 15:55:02 -08001042 cls._nonstandard = True
Rich Lane0a4f6372013-01-02 14:40:22 -08001043 return cls
1044
1045def disabled(cls):
1046 """
Rich Lanecc45b8e2013-01-02 15:55:02 -08001047 Testcase decorator that marks the test as being disabled.
1048 These tests are not automatically added to the "standard" group or
1049 their module's group.
Rich Lane0a4f6372013-01-02 14:40:22 -08001050 """
Rich Lanecc45b8e2013-01-02 15:55:02 -08001051 cls._disabled = True
Rich Lane0a4f6372013-01-02 14:40:22 -08001052 return cls
Rich Lane97e99652013-01-02 17:23:20 -08001053
1054def group(name):
1055 """
1056 Testcase decorator that adds the test to a group.
1057 """
1058 def fn(cls):
1059 if not hasattr(cls, "_groups"):
1060 cls._groups = []
1061 cls._groups.append(name)
1062 return cls
1063 return fn
Rich Lane5a9a1922013-01-11 14:29:30 -08001064
1065def version(ver):
1066 """
1067 Testcase decorator that specifies which versions of OpenFlow the test
1068 supports. The default is 1.0+. This decorator may only be used once.
1069
1070 Supported syntax:
1071 1.0 -> 1.0
1072 1.0,1.2,1.3 -> 1.0, 1.2, 1.3
1073 1.0+ -> 1.0, 1.1, 1.2, 1.3
1074 """
1075 versions = parse_version(ver)
1076 def fn(cls):
1077 cls._versions = versions
1078 return cls
1079 return fn
1080
1081def parse_version(ver):
1082 allowed_versions = ["1.0", "1.1", "1.2", "1.3"]
1083 if re.match("^1\.\d+$", ver):
1084 versions = set([ver])
1085 elif re.match("^(1\.\d+)\+$", ver):
1086 if not ver[:-1] in allowed_versions:
1087 raise ValueError("invalid OpenFlow version %s" % ver[:-1])
1088 versions = set()
1089 if ver != "1.1+": versions.add("1.0")
1090 if ver != "1.2+": versions.add("1.1")
1091 if ver != "1.3+": versions.add("1.2")
1092 versions.add("1.3")
1093 else:
1094 versions = set(ver.split(','))
1095
1096 for version in versions:
1097 if not version in allowed_versions:
1098 raise ValueError("invalid OpenFlow version %s" % version)
1099
1100 return versions
1101
1102assert(parse_version("1.0") == set(["1.0"]))
1103assert(parse_version("1.0,1.2,1.3") == set(["1.0", "1.2", "1.3"]))
1104assert(parse_version("1.0+") == set(["1.0", "1.1", "1.2", "1.3"]))
Rich Lane7744e112013-01-11 17:23:57 -08001105
1106__all__ = list(set(locals()) - _import_blacklist)