blob: fc5e5bbea1459cf7a66ca00b4ee37995a8fe8f44 [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,
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
79 @param dl_dst Destinatino MAC
80 @param dl_src Source MAC
Tatsuya Yabe460321e2010-05-25 17:50:49 -070081 @param dl_vlan_enable True if the packet is with vlan, False otherwise
82 @param dl_vlan VLAN ID
83 @param dl_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
Dan Talayco41eae8b2010-03-10 13:57:06 -080087 @param tcp_dport TCP destination port
88 @param ip_sport TCP source port
89
90 Generates a simple TCP request. Users
91 shouldn't assume anything about this packet other than that
92 it is a valid ethernet/IP/TCP frame.
93 """
Jeffrey Townsend5cb7ed32012-08-17 18:11:01 +000094
95 if MINSIZE > pktlen:
96 pktlen = MINSIZE
97
Dan Talayco551befa2010-07-15 17:05:32 -070098 # Note Dot1Q.id is really CFI
Shudong Zhou43ee54c2012-12-13 15:52:37 -080099 if (dl_vlan_enable):
Tatsuya Yabe460321e2010-05-25 17:50:49 -0700100 pkt = scapy.Ether(dst=dl_dst, src=dl_src)/ \
Dan Talayco551befa2010-07-15 17:05:32 -0700101 scapy.Dot1Q(prio=dl_vlan_pcp, id=dl_vlan_cfi, vlan=dl_vlan)/ \
Christian Dickmann8b59b4b2012-09-23 16:48:30 -0700102 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ihl=ip_ihl)/ \
Tatsuya Yabe460321e2010-05-25 17:50:49 -0700103 scapy.TCP(sport=tcp_sport, dport=tcp_dport)
104 else:
Christian Dickmann8b59b4b2012-09-23 16:48:30 -0700105 if not ip_options:
106 pkt = scapy.Ether(dst=dl_dst, src=dl_src)/ \
107 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ihl=ip_ihl)/ \
108 scapy.TCP(sport=tcp_sport, dport=tcp_dport)
109 else:
110 pkt = scapy.Ether(dst=dl_dst, src=dl_src)/ \
111 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ihl=ip_ihl, options=ip_options)/ \
112 scapy.TCP(sport=tcp_sport, dport=tcp_dport)
Tatsuya Yabe460321e2010-05-25 17:50:49 -0700113
Dan Talayco41eae8b2010-03-10 13:57:06 -0800114 pkt = pkt/("D" * (pktlen - len(pkt)))
115
116 return pkt
117
Rich Lane6ee7bea2012-10-26 16:19:29 -0700118def simple_udp_packet(pktlen=100,
119 dl_dst='00:01:02:03:04:05',
120 dl_src='00:06:07:08:09:0a',
121 dl_vlan_enable=False,
122 dl_vlan=0,
123 dl_vlan_pcp=0,
124 dl_vlan_cfi=0,
125 ip_src='192.168.0.1',
126 ip_dst='192.168.0.2',
127 ip_tos=0,
128 udp_sport=1234,
129 udp_dport=80,
130 ip_ihl=None,
131 ip_options=False
132 ):
133 """
134 Return a simple dataplane UDP packet
135
136 Supports a few parameters:
137 @param len Length of packet in bytes w/o CRC
138 @param dl_dst Destination MAC
139 @param dl_src Source MAC
140 @param dl_vlan_enable True if the packet is with vlan, False otherwise
141 @param dl_vlan VLAN ID
142 @param dl_vlan_pcp VLAN priority
143 @param ip_src IP source
144 @param ip_dst IP destination
145 @param ip_tos IP ToS
146 @param udp_dport UDP destination port
147 @param udp_sport UDP source port
148
149 Generates a simple UDP packet. Users shouldn't assume anything about
150 this packet other than that it is a valid ethernet/IP/UDP frame.
151 """
152
153 if MINSIZE > pktlen:
154 pktlen = MINSIZE
155
156 # Note Dot1Q.id is really CFI
157 if (dl_vlan_enable):
158 pkt = scapy.Ether(dst=dl_dst, src=dl_src)/ \
159 scapy.Dot1Q(prio=dl_vlan_pcp, id=dl_vlan_cfi, vlan=dl_vlan)/ \
160 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ihl=ip_ihl)/ \
161 scapy.UDP(sport=udp_sport, dport=udp_dport)
162 else:
163 if not ip_options:
164 pkt = scapy.Ether(dst=dl_dst, src=dl_src)/ \
165 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ihl=ip_ihl)/ \
166 scapy.UDP(sport=udp_sport, dport=udp_dport)
167 else:
168 pkt = scapy.Ether(dst=dl_dst, src=dl_src)/ \
169 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ihl=ip_ihl, options=ip_options)/ \
170 scapy.UDP(sport=udp_sport, dport=udp_dport)
171
172 pkt = pkt/("D" * (pktlen - len(pkt)))
173
174 return pkt
175
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700176def simple_icmp_packet(pktlen=60,
177 dl_dst='00:01:02:03:04:05',
178 dl_src='00:06:07:08:09:0a',
179 dl_vlan_enable=False,
180 dl_vlan=0,
181 dl_vlan_pcp=0,
182 ip_src='192.168.0.1',
183 ip_dst='192.168.0.2',
184 ip_tos=0,
185 icmp_type=8,
186 icmp_code=0
187 ):
188 """
189 Return a simple ICMP packet
190
191 Supports a few parameters:
192 @param len Length of packet in bytes w/o CRC
193 @param dl_dst Destinatino MAC
194 @param dl_src Source MAC
195 @param dl_vlan_enable True if the packet is with vlan, False otherwise
196 @param dl_vlan VLAN ID
197 @param dl_vlan_pcp VLAN priority
198 @param ip_src IP source
199 @param ip_dst IP destination
200 @param ip_tos IP ToS
201 @param icmp_type ICMP type
202 @param icmp_code ICMP code
203
204 Generates a simple ICMP ECHO REQUEST. Users
205 shouldn't assume anything about this packet other than that
206 it is a valid ethernet/ICMP frame.
207 """
Jeffrey Townsend5cb7ed32012-08-17 18:11:01 +0000208
209 if MINSIZE > pktlen:
210 pktlen = MINSIZE
211
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700212 if (dl_vlan_enable):
213 pkt = scapy.Ether(dst=dl_dst, src=dl_src)/ \
214 scapy.Dot1Q(prio=dl_vlan_pcp, id=0, vlan=dl_vlan)/ \
215 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos)/ \
216 scapy.ICMP(type=icmp_type, code=icmp_code)
217 else:
218 pkt = scapy.Ether(dst=dl_dst, src=dl_src)/ \
219 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos)/ \
220 scapy.ICMP(type=icmp_type, code=icmp_code)
221
222 pkt = pkt/("0" * (pktlen - len(pkt)))
223
224 return pkt
225
Ed Swierk0aeff8c2012-03-23 20:27:18 -0700226def simple_eth_packet(pktlen=60,
227 dl_dst='00:01:02:03:04:05',
228 dl_src='01:80:c2:00:00:00',
229 dl_type=0x88cc):
Jeffrey Townsend5cb7ed32012-08-17 18:11:01 +0000230
231 if MINSIZE > pktlen:
232 pktlen = MINSIZE
233
Ed Swierk0aeff8c2012-03-23 20:27:18 -0700234 pkt = scapy.Ether(dst=dl_dst, src=dl_src, type=dl_type)
235
236 pkt = pkt/("0" * (pktlen - len(pkt)))
237
238 return pkt
239
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800240def qinq_tcp_packet(pktlen=100,
241 dl_dst='00:01:02:03:04:05',
242 dl_src='00:06:07:08:09:0a',
243 dl_vlan_outer=20,
244 dl_vlan_pcp_outer=0,
245 dl_vlan_cfi_outer=0,
246 dl_vlan=10,
247 dl_vlan_pcp=0,
248 dl_vlan_cfi=0,
249 ip_src='192.168.0.1',
250 ip_dst='192.168.0.2',
251 ip_tos=0,
252 tcp_sport=1234,
253 tcp_dport=80,
254 ip_ihl=None,
255 ip_options=False
256 ):
257 """
258 Return a doubly tagged dataplane TCP packet
259
260 Supports a few parameters:
261 @param len Length of packet in bytes w/o CRC
262 @param dl_dst Destinatino MAC
263 @param dl_src Source MAC
264 @param dl_vlan_outer Outer VLAN ID
265 @param dl_vlan_pcp_outer Outer VLAN priority
266 @param dl_vlan_cfi_outer Outer VLAN cfi bit
267 @param dl_vlan Inner VLAN ID
268 @param dl_vlan_pcp VLAN priority
269 @param dl_vlan_cfi VLAN cfi bit
270 @param ip_src IP source
271 @param ip_dst IP destination
272 @param ip_tos IP ToS
273 @param tcp_dport TCP destination port
274 @param ip_sport TCP source port
275
276 Generates a TCP request. Users
277 shouldn't assume anything about this packet other than that
278 it is a valid ethernet/IP/TCP frame.
279 """
280
281 if MINSIZE > pktlen:
282 pktlen = MINSIZE
283
284 # Note Dot1Q.id is really CFI
285 pkt = scapy.Ether(dst=dl_dst, src=dl_src)/ \
286 scapy.Dot1Q(prio=dl_vlan_pcp_outer, id=dl_vlan_cfi_outer, vlan=dl_vlan_outer)/ \
287 scapy.Dot1Q(prio=dl_vlan_pcp, id=dl_vlan_cfi, vlan=dl_vlan)/ \
288 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ihl=ip_ihl)/ \
289 scapy.TCP(sport=tcp_sport, dport=tcp_dport)
290
291 pkt = pkt/("D" * (pktlen - len(pkt)))
292
293 return pkt
294
Shudong Zhoub7f12462012-11-20 13:01:12 -0800295def do_barrier(ctrl, timeout=-1):
Dan Talayco0fc08bd2012-04-09 16:56:18 -0700296 """
297 Do a barrier command
298 Return 0 on success, -1 on error
299 """
Rich Lanecd97d3d2013-01-07 18:50:06 -0800300 b = of10.message.barrier_request()
Shudong Zhoub7f12462012-11-20 13:01:12 -0800301 (resp, pkt) = ctrl.transact(b, timeout=timeout)
Rich Lane3a261d52013-01-03 17:45:08 -0800302 if resp is None:
303 raise AssertionError("barrier failed")
Dan Talaycof6b94832012-04-12 21:50:57 -0700304 # We'll trust the transaction processing in the controller that xid matched
Rich Lane3a261d52013-01-03 17:45:08 -0800305 return 0 # for backwards compatibility
Dan Talayco92c99122010-06-03 13:53:18 -0700306
Rich Lane9a003812012-10-04 17:17:59 -0700307def port_config_get(controller, port_no):
Dan Talayco92c99122010-06-03 13:53:18 -0700308 """
309 Get a port's configuration
310
311 Gets the switch feature configuration and grabs one port's
312 configuration
313
314 @returns (hwaddr, config, advert) The hwaddress, configuration and
315 advertised values
316 """
Rich Lanecd97d3d2013-01-07 18:50:06 -0800317 request = of10.message.features_request()
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700318 reply, pkt = controller.transact(request)
Rich Lane9a003812012-10-04 17:17:59 -0700319 logging.debug(reply.show())
Dan Talayco92c99122010-06-03 13:53:18 -0700320 if reply is None:
Rich Lane9a003812012-10-04 17:17:59 -0700321 logging.warn("Get feature request failed")
Dan Talayco92c99122010-06-03 13:53:18 -0700322 return None, None, None
323 for idx in range(len(reply.ports)):
324 if reply.ports[idx].port_no == port_no:
325 return (reply.ports[idx].hw_addr, reply.ports[idx].config,
326 reply.ports[idx].advertised)
327
Rich Lane9a003812012-10-04 17:17:59 -0700328 logging.warn("Did not find port number for port config")
Dan Talayco92c99122010-06-03 13:53:18 -0700329 return None, None, None
330
Rich Lane9a003812012-10-04 17:17:59 -0700331def port_config_set(controller, port_no, config, mask):
Dan Talayco92c99122010-06-03 13:53:18 -0700332 """
333 Set the port configuration according the given parameters
334
335 Gets the switch feature configuration and updates one port's
336 configuration value according to config and mask
337 """
Rich Lane9a003812012-10-04 17:17:59 -0700338 logging.info("Setting port " + str(port_no) + " to config " + str(config))
Rich Lanecd97d3d2013-01-07 18:50:06 -0800339 request = of10.message.features_request()
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700340 reply, pkt = controller.transact(request)
Dan Talayco92c99122010-06-03 13:53:18 -0700341 if reply is None:
342 return -1
Rich Lane9a003812012-10-04 17:17:59 -0700343 logging.debug(reply.show())
Ed Swierk8d84ce02012-12-27 15:36:48 -0800344 p = None
Dan Talayco92c99122010-06-03 13:53:18 -0700345 for idx in range(len(reply.ports)):
346 if reply.ports[idx].port_no == port_no:
Ed Swierk8d84ce02012-12-27 15:36:48 -0800347 p = reply.ports[idx]
Dan Talayco92c99122010-06-03 13:53:18 -0700348 break
Rich Lanecd97d3d2013-01-07 18:50:06 -0800349 mod = of10.message.port_mod()
Dan Talayco92c99122010-06-03 13:53:18 -0700350 mod.port_no = port_no
Ed Swierk8d84ce02012-12-27 15:36:48 -0800351 if p:
352 mod.hw_addr = p.hw_addr
Dan Talayco92c99122010-06-03 13:53:18 -0700353 mod.config = config
354 mod.mask = mask
Ed Swierk8d84ce02012-12-27 15:36:48 -0800355 if p:
356 mod.advertise = p.advertised
Rich Lane5c3151c2013-01-03 17:15:41 -0800357 controller.message_send(mod)
358 return 0
Dan Talayco92c99122010-06-03 13:53:18 -0700359
Rich Lane2014f9b2012-10-05 15:29:40 -0700360def receive_pkt_check(dp, pkt, yes_ports, no_ports, assert_if):
Dan Talayco92c99122010-06-03 13:53:18 -0700361 """
362 Check for proper receive packets across all ports
Ken Chiang1bf01602012-04-04 10:48:23 -0700363 @param dp The dataplane object
Dan Talayco92c99122010-06-03 13:53:18 -0700364 @param pkt Expected packet; may be None if yes_ports is empty
365 @param yes_ports Set or list of ports that should recieve packet
366 @param no_ports Set or list of ports that should not receive packet
367 @param assert_if Object that implements assertXXX
368 """
Rich Lane91765672012-12-06 16:33:04 -0800369
370 # Wait this long for packets that we don't expect to receive.
371 # 100ms is (rarely) too short for positive tests on slow
372 # switches but is definitely not too short for a negative test.
373 negative_timeout = 0.1
374
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700375 exp_pkt_arg = None
Rich Lanecd97d3d2013-01-07 18:50:06 -0800376 if oftest.config["relax"]:
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700377 exp_pkt_arg = pkt
378
Dan Talayco92c99122010-06-03 13:53:18 -0700379 for ofport in yes_ports:
Rich Lane9a003812012-10-04 17:17:59 -0700380 logging.debug("Checking for pkt on port " + str(ofport))
Ken Chiang1bf01602012-04-04 10:48:23 -0700381 (rcv_port, rcv_pkt, pkt_time) = dp.poll(
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700382 port_number=ofport, exp_pkt=exp_pkt_arg)
Dan Talayco92c99122010-06-03 13:53:18 -0700383 assert_if.assertTrue(rcv_pkt is not None,
384 "Did not receive pkt on " + str(ofport))
Rich Lanecd97d3d2013-01-07 18:50:06 -0800385 if not oftest.dataplane.match_exp_pkt(pkt, rcv_pkt):
Rich Lane9a003812012-10-04 17:17:59 -0700386 logging.debug("Sent %s" % format_packet(pkt))
387 logging.debug("Resp %s" % format_packet(rcv_pkt))
Rich Lanecd97d3d2013-01-07 18:50:06 -0800388 assert_if.assertTrue(oftest.dataplane.match_exp_pkt(pkt, rcv_pkt),
Ken Chiang1bf01602012-04-04 10:48:23 -0700389 "Response packet does not match send packet " +
390 "on port " + str(ofport))
Dan Talayco73f84012012-10-02 09:23:18 -0700391 if len(no_ports) > 0:
Rich Lane91765672012-12-06 16:33:04 -0800392 time.sleep(negative_timeout)
Dan Talayco92c99122010-06-03 13:53:18 -0700393 for ofport in no_ports:
Rich Lane9a003812012-10-04 17:17:59 -0700394 logging.debug("Negative check for pkt on port " + str(ofport))
Ken Chiang1bf01602012-04-04 10:48:23 -0700395 (rcv_port, rcv_pkt, pkt_time) = dp.poll(
Rich Lane91765672012-12-06 16:33:04 -0800396 port_number=ofport, timeout=0, exp_pkt=exp_pkt_arg)
Dan Talayco92c99122010-06-03 13:53:18 -0700397 assert_if.assertTrue(rcv_pkt is None,
398 "Unexpected pkt on port " + str(ofport))
Dan Talayco551befa2010-07-15 17:05:32 -0700399
400
Dan Talaycoc948d0b2012-03-23 12:17:54 -0700401def receive_pkt_verify(parent, egr_ports, exp_pkt, ing_port):
Dan Talayco551befa2010-07-15 17:05:32 -0700402 """
403 Receive a packet and verify it matches an expected value
Dan Talaycof6e76c02012-03-23 10:56:12 -0700404 @param egr_port A single port or list of ports
Dan Talayco551befa2010-07-15 17:05:32 -0700405
406 parent must implement dataplane, assertTrue and assertEqual
407 """
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700408 exp_pkt_arg = None
Rich Lanecd97d3d2013-01-07 18:50:06 -0800409 if oftest.config["relax"]:
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700410 exp_pkt_arg = exp_pkt
411
Dan Talaycof6e76c02012-03-23 10:56:12 -0700412 if type(egr_ports) == type([]):
413 egr_port_list = egr_ports
414 else:
415 egr_port_list = [egr_ports]
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700416
Dan Talaycof6e76c02012-03-23 10:56:12 -0700417 # Expect a packet from each port on egr port list
418 for egr_port in egr_port_list:
Dan Talaycod8ae7582012-03-23 12:24:56 -0700419 check_port = egr_port
Rich Lanecd97d3d2013-01-07 18:50:06 -0800420 if egr_port == of10.cstruct.OFPP_IN_PORT:
Dan Talaycod8ae7582012-03-23 12:24:56 -0700421 check_port = ing_port
Dan Talaycof6e76c02012-03-23 10:56:12 -0700422 (rcv_port, rcv_pkt, pkt_time) = parent.dataplane.poll(
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700423 port_number=check_port, exp_pkt=exp_pkt_arg)
Dan Talayco551befa2010-07-15 17:05:32 -0700424
Dan Talaycof6e76c02012-03-23 10:56:12 -0700425 if rcv_pkt is None:
Rich Lane9a003812012-10-04 17:17:59 -0700426 logging.error("ERROR: No packet received from " +
Dan Talaycod8ae7582012-03-23 12:24:56 -0700427 str(check_port))
Dan Talayco551befa2010-07-15 17:05:32 -0700428
Dan Talaycof6e76c02012-03-23 10:56:12 -0700429 parent.assertTrue(rcv_pkt is not None,
Dan Talaycod8ae7582012-03-23 12:24:56 -0700430 "Did not receive packet port " + str(check_port))
Rich Lane9a003812012-10-04 17:17:59 -0700431 logging.debug("Packet len " + str(len(rcv_pkt)) + " in on " +
Dan Talaycof6e76c02012-03-23 10:56:12 -0700432 str(rcv_port))
433
434 if str(exp_pkt) != str(rcv_pkt):
Rich Lane9a003812012-10-04 17:17:59 -0700435 logging.error("ERROR: Packet match failed.")
436 logging.debug("Expected len " + str(len(exp_pkt)) + ": "
Dan Talaycof6e76c02012-03-23 10:56:12 -0700437 + str(exp_pkt).encode('hex'))
Rich Lane9a003812012-10-04 17:17:59 -0700438 logging.debug("Received len " + str(len(rcv_pkt)) + ": "
Dan Talaycof6e76c02012-03-23 10:56:12 -0700439 + str(rcv_pkt).encode('hex'))
Rich Lane5d7e89a2012-10-26 16:43:13 -0700440 logging.debug("Expected packet: " + inspect_packet(scapy.Ether(str(exp_pkt))))
441 logging.debug("Received packet: " + inspect_packet(scapy.Ether(str(rcv_pkt))))
Dan Talaycof6e76c02012-03-23 10:56:12 -0700442 parent.assertEqual(str(exp_pkt), str(rcv_pkt),
Dan Talaycod8ae7582012-03-23 12:24:56 -0700443 "Packet match error on port " + str(check_port))
Dan Talaycof6e76c02012-03-23 10:56:12 -0700444
Dan Talayco551befa2010-07-15 17:05:32 -0700445def match_verify(parent, req_match, res_match):
446 """
447 Verify flow matches agree; if they disagree, report where
448
449 parent must implement assertEqual
450 Use str() to ensure content is compared and not pointers
451 """
452
453 parent.assertEqual(req_match.wildcards, res_match.wildcards,
454 'Match failed: wildcards: ' + hex(req_match.wildcards) +
455 " != " + hex(res_match.wildcards))
456 parent.assertEqual(req_match.in_port, res_match.in_port,
457 'Match failed: in_port: ' + str(req_match.in_port) +
458 " != " + str(res_match.in_port))
459 parent.assertEqual(str(req_match.dl_src), str(res_match.dl_src),
460 'Match failed: dl_src: ' + str(req_match.dl_src) +
461 " != " + str(res_match.dl_src))
462 parent.assertEqual(str(req_match.dl_dst), str(res_match.dl_dst),
463 'Match failed: dl_dst: ' + str(req_match.dl_dst) +
464 " != " + str(res_match.dl_dst))
465 parent.assertEqual(req_match.dl_vlan, res_match.dl_vlan,
466 'Match failed: dl_vlan: ' + str(req_match.dl_vlan) +
467 " != " + str(res_match.dl_vlan))
468 parent.assertEqual(req_match.dl_vlan_pcp, res_match.dl_vlan_pcp,
469 'Match failed: dl_vlan_pcp: ' +
470 str(req_match.dl_vlan_pcp) + " != " +
471 str(res_match.dl_vlan_pcp))
472 parent.assertEqual(req_match.dl_type, res_match.dl_type,
473 'Match failed: dl_type: ' + str(req_match.dl_type) +
474 " != " + str(res_match.dl_type))
475
Rich Lanecd97d3d2013-01-07 18:50:06 -0800476 if (not(req_match.wildcards & of10.cstruct.OFPFW_DL_TYPE)
Dan Talayco551befa2010-07-15 17:05:32 -0700477 and (req_match.dl_type == IP_ETHERTYPE)):
478 parent.assertEqual(req_match.nw_tos, res_match.nw_tos,
479 'Match failed: nw_tos: ' + str(req_match.nw_tos) +
480 " != " + str(res_match.nw_tos))
481 parent.assertEqual(req_match.nw_proto, res_match.nw_proto,
482 'Match failed: nw_proto: ' + str(req_match.nw_proto) +
483 " != " + str(res_match.nw_proto))
484 parent.assertEqual(req_match.nw_src, res_match.nw_src,
485 'Match failed: nw_src: ' + str(req_match.nw_src) +
486 " != " + str(res_match.nw_src))
487 parent.assertEqual(req_match.nw_dst, res_match.nw_dst,
488 'Match failed: nw_dst: ' + str(req_match.nw_dst) +
489 " != " + str(res_match.nw_dst))
490
Rich Lanecd97d3d2013-01-07 18:50:06 -0800491 if (not(req_match.wildcards & of10.cstruct.OFPFW_NW_PROTO)
Dan Talayco551befa2010-07-15 17:05:32 -0700492 and ((req_match.nw_proto == TCP_PROTOCOL)
493 or (req_match.nw_proto == UDP_PROTOCOL))):
494 parent.assertEqual(req_match.tp_src, res_match.tp_src,
495 'Match failed: tp_src: ' +
496 str(req_match.tp_src) +
497 " != " + str(res_match.tp_src))
498 parent.assertEqual(req_match.tp_dst, res_match.tp_dst,
499 'Match failed: tp_dst: ' +
500 str(req_match.tp_dst) +
501 " != " + str(res_match.tp_dst))
502
Ed Swierk99a74de2012-08-22 06:40:54 -0700503def packet_to_flow_match(parent, packet):
Rich Lanecd97d3d2013-01-07 18:50:06 -0800504 match = of10.parse.packet_to_flow_match(packet)
Ed Swierk99a74de2012-08-22 06:40:54 -0700505 match.wildcards |= required_wildcards(parent)
506 return match
507
508def flow_msg_create(parent, pkt, ing_port=None, action_list=None, wildcards=None,
Dan Talaycof6e76c02012-03-23 10:56:12 -0700509 egr_ports=None, egr_queue=None, check_expire=False, in_band=False):
Dan Talayco551befa2010-07-15 17:05:32 -0700510 """
511 Create a flow message
512
513 Match on packet with given wildcards.
514 See flow_match_test for other parameter descriptoins
515 @param egr_queue if not None, make the output an enqueue action
Dan Talayco677c0b72011-08-23 22:53:38 -0700516 @param in_band if True, do not wildcard ingress port
Dan Talaycof6e76c02012-03-23 10:56:12 -0700517 @param egr_ports None (drop), single port or list of ports
Dan Talayco551befa2010-07-15 17:05:32 -0700518 """
Rich Lanecd97d3d2013-01-07 18:50:06 -0800519 match = of10.parse.packet_to_flow_match(pkt)
Dan Talayco551befa2010-07-15 17:05:32 -0700520 parent.assertTrue(match is not None, "Flow match from pkt failed")
Ed Swierk99a74de2012-08-22 06:40:54 -0700521 if wildcards is None:
522 wildcards = required_wildcards(parent)
Dan Talayco677c0b72011-08-23 22:53:38 -0700523 if in_band:
Rich Lanecd97d3d2013-01-07 18:50:06 -0800524 wildcards &= ~of10.cstruct.OFPFW_IN_PORT
Dan Talayco551befa2010-07-15 17:05:32 -0700525 match.wildcards = wildcards
526 match.in_port = ing_port
527
Dan Talaycof6e76c02012-03-23 10:56:12 -0700528 if type(egr_ports) == type([]):
529 egr_port_list = egr_ports
530 else:
531 egr_port_list = [egr_ports]
532
Rich Lanecd97d3d2013-01-07 18:50:06 -0800533 request = of10.message.flow_mod()
Dan Talayco551befa2010-07-15 17:05:32 -0700534 request.match = match
535 request.buffer_id = 0xffffffff
536 if check_expire:
Rich Lanecd97d3d2013-01-07 18:50:06 -0800537 request.flags |= of10.cstruct.OFPFF_SEND_FLOW_REM
Dan Talayco551befa2010-07-15 17:05:32 -0700538 request.hard_timeout = 1
539
540 if action_list is not None:
541 for act in action_list:
Rich Lane9a003812012-10-04 17:17:59 -0700542 logging.debug("Adding action " + act.show())
Rich Lanee30455b2013-01-03 16:24:44 -0800543 request.actions.add(act)
Dan Talayco551befa2010-07-15 17:05:32 -0700544
545 # Set up output/enqueue action if directed
546 if egr_queue is not None:
Dan Talaycof6e76c02012-03-23 10:56:12 -0700547 parent.assertTrue(egr_ports is not None, "Egress port not set")
Rich Lanecd97d3d2013-01-07 18:50:06 -0800548 act = of10.action.action_enqueue()
Dan Talaycof6e76c02012-03-23 10:56:12 -0700549 for egr_port in egr_port_list:
550 act.port = egr_port
551 act.queue_id = egr_queue
Rich Lanee30455b2013-01-03 16:24:44 -0800552 request.actions.add(act)
Dan Talaycof6e76c02012-03-23 10:56:12 -0700553 elif egr_ports is not None:
554 for egr_port in egr_port_list:
Rich Lanecd97d3d2013-01-07 18:50:06 -0800555 act = of10.action.action_output()
Dan Talaycof6e76c02012-03-23 10:56:12 -0700556 act.port = egr_port
Rich Lanee30455b2013-01-03 16:24:44 -0800557 request.actions.add(act)
Dan Talayco551befa2010-07-15 17:05:32 -0700558
Rich Lane9a003812012-10-04 17:17:59 -0700559 logging.debug(request.show())
Dan Talayco551befa2010-07-15 17:05:32 -0700560
561 return request
562
Jeffrey Townsendf3eae9c2012-03-28 18:23:21 -0700563def flow_msg_install(parent, request, clear_table_override=None):
Dan Talayco551befa2010-07-15 17:05:32 -0700564 """
565 Install a flow mod message in the switch
566
567 @param parent Must implement controller, assertEqual, assertTrue
568 @param request The request, all set to go
569 @param clear_table If true, clear the flow table before installing
570 """
Dan Talayco8a64e332012-03-28 14:53:20 -0700571
Rich Lane2014f9b2012-10-05 15:29:40 -0700572 clear_table = test_param_get('clear_table', default=True)
Jeffrey Townsendf3eae9c2012-03-28 18:23:21 -0700573 if(clear_table_override != None):
574 clear_table = clear_table_override
575
576 if clear_table:
Rich Lane9a003812012-10-04 17:17:59 -0700577 logging.debug("Clear flow table")
Rich Lane32bf9482013-01-03 17:26:30 -0800578 delete_all_flows(parent.controller)
Dan Talayco551befa2010-07-15 17:05:32 -0700579
Rich Lane9a003812012-10-04 17:17:59 -0700580 logging.debug("Insert flow")
Rich Lane5c3151c2013-01-03 17:15:41 -0800581 parent.controller.message_send(request)
Rich Lanee912d032012-12-22 14:28:33 -0800582
Rich Lane3a261d52013-01-03 17:45:08 -0800583 do_barrier(parent.controller)
Dan Talayco551befa2010-07-15 17:05:32 -0700584
Ed Swierk99a74de2012-08-22 06:40:54 -0700585def flow_match_test_port_pair(parent, ing_port, egr_ports, wildcards=None,
Dan Talayco551befa2010-07-15 17:05:32 -0700586 dl_vlan=-1, pkt=None, exp_pkt=None,
Rich Lanee5779d32012-10-05 17:56:04 -0700587 action_list=None):
Dan Talayco551befa2010-07-15 17:05:32 -0700588 """
589 Flow match test on single TCP packet
Dan Talaycof6e76c02012-03-23 10:56:12 -0700590 @param egr_ports A single port or list of ports
Dan Talayco551befa2010-07-15 17:05:32 -0700591
592 Run test with packet through switch from ing_port to egr_port
593 See flow_match_test for parameter descriptions
594 """
595
Ed Swierk99a74de2012-08-22 06:40:54 -0700596 if wildcards is None:
597 wildcards = required_wildcards(parent)
Rich Lane9a003812012-10-04 17:17:59 -0700598 logging.info("Pkt match test: " + str(ing_port) + " to " +
Dan Talaycof6e76c02012-03-23 10:56:12 -0700599 str(egr_ports))
Rich Lanee5779d32012-10-05 17:56:04 -0700600 logging.debug(" WC: " + hex(wildcards) + " vlan: " + str(dl_vlan))
Dan Talayco551befa2010-07-15 17:05:32 -0700601 if pkt is None:
602 pkt = simple_tcp_packet(dl_vlan_enable=(dl_vlan >= 0), dl_vlan=dl_vlan)
603
604 request = flow_msg_create(parent, pkt, ing_port=ing_port,
Dan Talaycof6e76c02012-03-23 10:56:12 -0700605 wildcards=wildcards, egr_ports=egr_ports,
Dan Talayco551befa2010-07-15 17:05:32 -0700606 action_list=action_list)
607
608 flow_msg_install(parent, request)
609
Rich Lane9a003812012-10-04 17:17:59 -0700610 logging.debug("Send packet: " + str(ing_port) + " to " +
Dan Talaycof6e76c02012-03-23 10:56:12 -0700611 str(egr_ports))
Dan Talayco551befa2010-07-15 17:05:32 -0700612 parent.dataplane.send(ing_port, str(pkt))
613
614 if exp_pkt is None:
615 exp_pkt = pkt
Dan Talaycoc948d0b2012-03-23 12:17:54 -0700616 receive_pkt_verify(parent, egr_ports, exp_pkt, ing_port)
Dan Talayco551befa2010-07-15 17:05:32 -0700617
Rich Lane89725bb2012-12-03 16:23:27 -0800618def flow_match_test_pktout(parent, ing_port, egr_ports,
619 dl_vlan=-1, pkt=None, exp_pkt=None,
620 action_list=None):
621 """
622 Packet-out test on single TCP packet
623 @param egr_ports A single port or list of ports
624
625 Run test sending packet-out to egr_ports. The goal is to test the actions
626 taken on the packet, not the matching which is of course irrelevant.
627 See flow_match_test for parameter descriptions
628 """
629
630 if pkt is None:
631 pkt = simple_tcp_packet(dl_vlan_enable=(dl_vlan >= 0), dl_vlan=dl_vlan)
632
Rich Lanecd97d3d2013-01-07 18:50:06 -0800633 msg = of10.message.packet_out()
Rich Lane89725bb2012-12-03 16:23:27 -0800634 msg.in_port = ing_port
635 msg.data = str(pkt)
636 if action_list is not None:
637 for act in action_list:
Rich Lanee30455b2013-01-03 16:24:44 -0800638 msg.actions.add(act)
Rich Lane89725bb2012-12-03 16:23:27 -0800639
640 # Set up output action
641 if egr_ports is not None:
642 for egr_port in egr_ports:
Rich Lanecd97d3d2013-01-07 18:50:06 -0800643 act = of10.action.action_output()
Rich Lane89725bb2012-12-03 16:23:27 -0800644 act.port = egr_port
Rich Lanee30455b2013-01-03 16:24:44 -0800645 msg.actions.add(act)
Rich Lane89725bb2012-12-03 16:23:27 -0800646
647 logging.debug(msg.show())
Rich Lane5c3151c2013-01-03 17:15:41 -0800648 parent.controller.message_send(msg)
Rich Lane89725bb2012-12-03 16:23:27 -0800649
650 if exp_pkt is None:
651 exp_pkt = pkt
652 receive_pkt_verify(parent, egr_ports, exp_pkt, ing_port)
653
Dan Talaycof6e76c02012-03-23 10:56:12 -0700654def get_egr_list(parent, of_ports, how_many, exclude_list=[]):
655 """
656 Generate a list of ports avoiding those in the exclude list
Rich Lane9a003812012-10-04 17:17:59 -0700657 @param parent Supplies logging
Dan Talaycof6e76c02012-03-23 10:56:12 -0700658 @param of_ports List of OF port numbers
659 @param how_many Number of ports to be added to the list
660 @param exclude_list List of ports not to be used
661 @returns An empty list if unable to find enough ports
662 """
663
Dan Talaycoc948d0b2012-03-23 12:17:54 -0700664 if how_many == 0:
665 return []
666
Dan Talaycof6e76c02012-03-23 10:56:12 -0700667 count = 0
668 egr_ports = []
669 for egr_idx in range(len(of_ports)):
670 if of_ports[egr_idx] not in exclude_list:
671 egr_ports.append(of_ports[egr_idx])
672 count += 1
673 if count >= how_many:
674 return egr_ports
Rich Lane9a003812012-10-04 17:17:59 -0700675 logging.debug("Could not generate enough egress ports for test")
Dan Talaycof6e76c02012-03-23 10:56:12 -0700676 return []
677
Ed Swierk99a74de2012-08-22 06:40:54 -0700678def flow_match_test(parent, port_map, wildcards=None, dl_vlan=-1, pkt=None,
Rich Lanee5779d32012-10-05 17:56:04 -0700679 exp_pkt=None, action_list=None,
Dan Talaycoc948d0b2012-03-23 12:17:54 -0700680 max_test=0, egr_count=1, ing_port=False):
Dan Talayco551befa2010-07-15 17:05:32 -0700681 """
Rich Lane89725bb2012-12-03 16:23:27 -0800682 Run flow_match_test_port_pair on all port pairs and packet-out
Dan Talayco551befa2010-07-15 17:05:32 -0700683
684 @param max_test If > 0 no more than this number of tests are executed.
685 @param parent Must implement controller, dataplane, assertTrue, assertEqual
Rich Lane9a003812012-10-04 17:17:59 -0700686 and logging
Dan Talayco551befa2010-07-15 17:05:32 -0700687 @param pkt If not None, use this packet for ingress
688 @param wildcards For flow match entry
Dan Talayco79184222010-11-01 12:24:29 -0700689 @param dl_vlan If not -1, and pkt is None, create a pkt w/ VLAN tag
Dan Talayco551befa2010-07-15 17:05:32 -0700690 @param exp_pkt If not None, use this as the expected output pkt; els use pkt
691 @param action_list Additional actions to add to flow mod
Dan Talaycocfa172f2012-03-23 12:03:00 -0700692 @param egr_count Number of egress ports; -1 means get from config w/ dflt 2
Dan Talayco551befa2010-07-15 17:05:32 -0700693 """
Ed Swierk99a74de2012-08-22 06:40:54 -0700694 if wildcards is None:
695 wildcards = required_wildcards(parent)
Dan Talayco551befa2010-07-15 17:05:32 -0700696 of_ports = port_map.keys()
697 of_ports.sort()
698 parent.assertTrue(len(of_ports) > 1, "Not enough ports for test")
699 test_count = 0
700
Dan Talaycocfa172f2012-03-23 12:03:00 -0700701 if egr_count == -1:
Rich Lane2014f9b2012-10-05 15:29:40 -0700702 egr_count = test_param_get('egr_count', default=2)
Dan Talaycocfa172f2012-03-23 12:03:00 -0700703
Dan Talayco551befa2010-07-15 17:05:32 -0700704 for ing_idx in range(len(of_ports)):
705 ingress_port = of_ports[ing_idx]
Dan Talaycof6e76c02012-03-23 10:56:12 -0700706 egr_ports = get_egr_list(parent, of_ports, egr_count,
707 exclude_list=[ingress_port])
Dan Talaycoc948d0b2012-03-23 12:17:54 -0700708 if ing_port:
Rich Lanecd97d3d2013-01-07 18:50:06 -0800709 egr_ports.append(of10.cstruct.OFPP_IN_PORT)
Dan Talaycof6e76c02012-03-23 10:56:12 -0700710 if len(egr_ports) == 0:
711 parent.assertTrue(0, "Failed to generate egress port list")
712
713 flow_match_test_port_pair(parent, ingress_port, egr_ports,
714 wildcards=wildcards, dl_vlan=dl_vlan,
715 pkt=pkt, exp_pkt=exp_pkt,
Rich Lanee5779d32012-10-05 17:56:04 -0700716 action_list=action_list)
Dan Talaycof6e76c02012-03-23 10:56:12 -0700717 test_count += 1
718 if (max_test > 0) and (test_count > max_test):
Rich Lane9a003812012-10-04 17:17:59 -0700719 logging.info("Ran " + str(test_count) + " tests; exiting")
Rich Lane89725bb2012-12-03 16:23:27 -0800720 break
721
Ed Swierk38eea082013-01-02 19:46:20 -0800722 if not test_param_get('pktout_actions', default=True):
723 return
Rich Lane89725bb2012-12-03 16:23:27 -0800724
725 ingress_port = of_ports[0]
726 egr_ports = get_egr_list(parent, of_ports, egr_count,
727 exclude_list=[ingress_port])
728 if ing_port:
Rich Lanecd97d3d2013-01-07 18:50:06 -0800729 egr_ports.append(of10.cstruct.OFPP_IN_PORT)
Rich Lane89725bb2012-12-03 16:23:27 -0800730 flow_match_test_pktout(parent, ingress_port, egr_ports,
731 dl_vlan=dl_vlan,
732 pkt=pkt, exp_pkt=exp_pkt,
733 action_list=action_list)
Dan Talayco551befa2010-07-15 17:05:32 -0700734
Rich Lane2014f9b2012-10-05 15:29:40 -0700735def test_param_get(key, default=None):
Dan Talayco4b2bee62010-07-20 14:10:05 -0700736 """
737 Return value passed via test-params if present
738
Dan Talayco4b2bee62010-07-20 14:10:05 -0700739 @param key The lookup key
740 @param default Default value to use if not found
741
742 If the pair 'key=val' appeared in the string passed to --test-params
743 on the command line, return val (as interpreted by exec). Otherwise
744 return default value.
Dan Talaycof6e76c02012-03-23 10:56:12 -0700745
746 WARNING: TEST PARAMETERS MUST BE PYTHON IDENTIFIERS;
747 eg egr_count, not egr-count.
Dan Talayco4b2bee62010-07-20 14:10:05 -0700748 """
749 try:
Rich Lanecd97d3d2013-01-07 18:50:06 -0800750 exec oftest.config["test_params"]
Dan Talayco4b2bee62010-07-20 14:10:05 -0700751 except:
752 return default
753
754 s = "val = " + str(key)
755 try:
756 exec s
757 return val
758 except:
759 return default
760
761def action_generate(parent, field_to_mod, mod_field_vals):
762 """
763 Create an action to modify the field indicated in field_to_mod
764
765 @param parent Must implement, assertTrue
766 @param field_to_mod The field to modify as a string name
767 @param mod_field_vals Hash of values to use for modified values
768 """
769
770 act = None
771
772 if field_to_mod in ['pktlen']:
773 return None
774
775 if field_to_mod == 'dl_dst':
Rich Lanecd97d3d2013-01-07 18:50:06 -0800776 act = of10.action.action_set_dl_dst()
777 act.dl_addr = of10.parse.parse_mac(mod_field_vals['dl_dst'])
Dan Talayco4b2bee62010-07-20 14:10:05 -0700778 elif field_to_mod == 'dl_src':
Rich Lanecd97d3d2013-01-07 18:50:06 -0800779 act = of10.action.action_set_dl_src()
780 act.dl_addr = of10.parse.parse_mac(mod_field_vals['dl_src'])
Dan Talayco4b2bee62010-07-20 14:10:05 -0700781 elif field_to_mod == 'dl_vlan_enable':
782 if not mod_field_vals['dl_vlan_enable']: # Strip VLAN tag
Rich Lanecd97d3d2013-01-07 18:50:06 -0800783 act = of10.action.action_strip_vlan()
Dan Talayco4b2bee62010-07-20 14:10:05 -0700784 # Add VLAN tag is handled by dl_vlan field
785 # Will return None in this case
786 elif field_to_mod == 'dl_vlan':
Rich Lanecd97d3d2013-01-07 18:50:06 -0800787 act = of10.action.action_set_vlan_vid()
Dan Talayco4b2bee62010-07-20 14:10:05 -0700788 act.vlan_vid = mod_field_vals['dl_vlan']
789 elif field_to_mod == 'dl_vlan_pcp':
Rich Lanecd97d3d2013-01-07 18:50:06 -0800790 act = of10.action.action_set_vlan_pcp()
Dan Talayco4b2bee62010-07-20 14:10:05 -0700791 act.vlan_pcp = mod_field_vals['dl_vlan_pcp']
792 elif field_to_mod == 'ip_src':
Rich Lanecd97d3d2013-01-07 18:50:06 -0800793 act = of10.action.action_set_nw_src()
794 act.nw_addr = of10.parse.parse_ip(mod_field_vals['ip_src'])
Dan Talayco4b2bee62010-07-20 14:10:05 -0700795 elif field_to_mod == 'ip_dst':
Rich Lanecd97d3d2013-01-07 18:50:06 -0800796 act = of10.action.action_set_nw_dst()
797 act.nw_addr = of10.parse.parse_ip(mod_field_vals['ip_dst'])
Dan Talayco4b2bee62010-07-20 14:10:05 -0700798 elif field_to_mod == 'ip_tos':
Rich Lanecd97d3d2013-01-07 18:50:06 -0800799 act = of10.action.action_set_nw_tos()
Dan Talayco4b2bee62010-07-20 14:10:05 -0700800 act.nw_tos = mod_field_vals['ip_tos']
801 elif field_to_mod == 'tcp_sport':
Rich Lanecd97d3d2013-01-07 18:50:06 -0800802 act = of10.action.action_set_tp_src()
Dan Talayco4b2bee62010-07-20 14:10:05 -0700803 act.tp_port = mod_field_vals['tcp_sport']
804 elif field_to_mod == 'tcp_dport':
Rich Lanecd97d3d2013-01-07 18:50:06 -0800805 act = of10.action.action_set_tp_dst()
Dan Talayco4b2bee62010-07-20 14:10:05 -0700806 act.tp_port = mod_field_vals['tcp_dport']
Rich Lane110e0e32012-10-26 16:21:46 -0700807 elif field_to_mod == 'udp_sport':
Rich Lanecd97d3d2013-01-07 18:50:06 -0800808 act = of10.action.action_set_tp_src()
Rich Lane110e0e32012-10-26 16:21:46 -0700809 act.tp_port = mod_field_vals['udp_sport']
810 elif field_to_mod == 'udp_dport':
Rich Lanecd97d3d2013-01-07 18:50:06 -0800811 act = of10.action.action_set_tp_dst()
Rich Lane110e0e32012-10-26 16:21:46 -0700812 act.tp_port = mod_field_vals['udp_dport']
Dan Talayco4b2bee62010-07-20 14:10:05 -0700813 else:
814 parent.assertTrue(0, "Unknown field to modify: " + str(field_to_mod))
815
816 return act
817
818def pkt_action_setup(parent, start_field_vals={}, mod_field_vals={},
Rich Lane110e0e32012-10-26 16:21:46 -0700819 mod_fields=[], tp="tcp", check_test_params=False):
Dan Talayco4b2bee62010-07-20 14:10:05 -0700820 """
821 Set up the ingress and expected packet and action list for a test
822
Rich Lane2014f9b2012-10-05 15:29:40 -0700823 @param parent Must implement assertTrue
Dan Talayco4b2bee62010-07-20 14:10:05 -0700824 @param start_field_values Field values to use for ingress packet (optional)
825 @param mod_field_values Field values to use for modified packet (optional)
826 @param mod_fields The list of fields to be modified by the switch in the test.
827 @params check_test_params If True, will check the parameters vid, add_vlan
828 and strip_vlan from the command line.
829
830 Returns a triple: pkt-to-send, expected-pkt, action-list
831 """
832
833 new_actions = []
834
Dan Talayco4b2bee62010-07-20 14:10:05 -0700835 base_pkt_params = {}
836 base_pkt_params['pktlen'] = 100
837 base_pkt_params['dl_dst'] = '00:DE:F0:12:34:56'
838 base_pkt_params['dl_src'] = '00:23:45:67:89:AB'
839 base_pkt_params['dl_vlan_enable'] = False
840 base_pkt_params['dl_vlan'] = 2
841 base_pkt_params['dl_vlan_pcp'] = 0
842 base_pkt_params['ip_src'] = '192.168.0.1'
843 base_pkt_params['ip_dst'] = '192.168.0.2'
844 base_pkt_params['ip_tos'] = 0
Rich Lane110e0e32012-10-26 16:21:46 -0700845 if tp == "tcp":
846 base_pkt_params['tcp_sport'] = 1234
847 base_pkt_params['tcp_dport'] = 80
848 elif tp == "udp":
849 base_pkt_params['udp_sport'] = 1234
850 base_pkt_params['udp_dport'] = 80
Dan Talayco4b2bee62010-07-20 14:10:05 -0700851 for keyname in start_field_vals.keys():
852 base_pkt_params[keyname] = start_field_vals[keyname]
853
854 mod_pkt_params = {}
855 mod_pkt_params['pktlen'] = 100
856 mod_pkt_params['dl_dst'] = '00:21:0F:ED:CB:A9'
857 mod_pkt_params['dl_src'] = '00:ED:CB:A9:87:65'
858 mod_pkt_params['dl_vlan_enable'] = False
859 mod_pkt_params['dl_vlan'] = 3
860 mod_pkt_params['dl_vlan_pcp'] = 7
861 mod_pkt_params['ip_src'] = '10.20.30.40'
862 mod_pkt_params['ip_dst'] = '50.60.70.80'
863 mod_pkt_params['ip_tos'] = 0xf0
Rich Lane110e0e32012-10-26 16:21:46 -0700864 if tp == "tcp":
865 mod_pkt_params['tcp_sport'] = 4321
866 mod_pkt_params['tcp_dport'] = 8765
867 elif tp == "udp":
868 mod_pkt_params['udp_sport'] = 4321
869 mod_pkt_params['udp_dport'] = 8765
Dan Talayco4b2bee62010-07-20 14:10:05 -0700870 for keyname in mod_field_vals.keys():
871 mod_pkt_params[keyname] = mod_field_vals[keyname]
872
873 # Check for test param modifications
874 strip = False
875 if check_test_params:
Rich Lane2014f9b2012-10-05 15:29:40 -0700876 add_vlan = test_param_get('add_vlan')
877 strip_vlan = test_param_get('strip_vlan')
878 vid = test_param_get('vid')
Dan Talayco4b2bee62010-07-20 14:10:05 -0700879
880 if add_vlan and strip_vlan:
881 parent.assertTrue(0, "Add and strip VLAN both specified")
882
883 if vid:
884 base_pkt_params['dl_vlan_enable'] = True
885 base_pkt_params['dl_vlan'] = vid
886 if 'dl_vlan' in mod_fields:
887 mod_pkt_params['dl_vlan'] = vid + 1
888
889 if add_vlan:
890 base_pkt_params['dl_vlan_enable'] = False
891 mod_pkt_params['dl_vlan_enable'] = True
892 mod_pkt_params['pktlen'] = base_pkt_params['pktlen'] + 4
893 mod_fields.append('pktlen')
894 mod_fields.append('dl_vlan_enable')
895 if 'dl_vlan' not in mod_fields:
896 mod_fields.append('dl_vlan')
897 elif strip_vlan:
898 base_pkt_params['dl_vlan_enable'] = True
899 mod_pkt_params['dl_vlan_enable'] = False
900 mod_pkt_params['pktlen'] = base_pkt_params['pktlen'] - 4
901 mod_fields.append('dl_vlan_enable')
902 mod_fields.append('pktlen')
903
Rich Lane110e0e32012-10-26 16:21:46 -0700904 if tp == "tcp":
905 packet_builder = simple_tcp_packet
906 elif tp == "udp":
907 packet_builder = simple_udp_packet
908 else:
909 raise NotImplementedError("unknown transport protocol %s" % tp)
910
Dan Talayco4b2bee62010-07-20 14:10:05 -0700911 # Build the ingress packet
Rich Lane110e0e32012-10-26 16:21:46 -0700912 ingress_pkt = packet_builder(**base_pkt_params)
Dan Talayco4b2bee62010-07-20 14:10:05 -0700913
914 # Build the expected packet, modifying the indicated fields
915 for item in mod_fields:
916 base_pkt_params[item] = mod_pkt_params[item]
917 act = action_generate(parent, item, mod_pkt_params)
918 if act:
919 new_actions.append(act)
920
Rich Lane110e0e32012-10-26 16:21:46 -0700921 expected_pkt = packet_builder(**base_pkt_params)
Dan Talayco4b2bee62010-07-20 14:10:05 -0700922
923 return (ingress_pkt, expected_pkt, new_actions)
Dan Talayco677c0b72011-08-23 22:53:38 -0700924
925# Generate a simple "drop" flow mod
926# If in_band is true, then only drop from first test port
927def flow_mod_gen(port_map, in_band):
Rich Lanecd97d3d2013-01-07 18:50:06 -0800928 request = of10.message.flow_mod()
929 request.match.wildcards = of10.cstruct.OFPFW_ALL
Dan Talayco677c0b72011-08-23 22:53:38 -0700930 if in_band:
Rich Lanecd97d3d2013-01-07 18:50:06 -0800931 request.match.wildcards = of10.cstruct.OFPFW_ALL - of10.cstruct.OFPFW_IN_PORT
Dan Talayco677c0b72011-08-23 22:53:38 -0700932 for of_port, ifname in port_map.items(): # Grab first port
933 break
934 request.match.in_port = of_port
935 request.buffer_id = 0xffffffff
936 return request
Dan Talaycoba3745c2010-07-21 21:51:08 -0700937
938def skip_message_emit(parent, s):
939 """
940 Print out a 'skipped' message to stderr
941
942 @param s The string to print out to the log file
Dan Talaycoba3745c2010-07-21 21:51:08 -0700943 """
944 global skipped_test_count
945
946 skipped_test_count += 1
Rich Lane9a003812012-10-04 17:17:59 -0700947 logging.info("Skipping: " + s)
Rich Lanecd97d3d2013-01-07 18:50:06 -0800948 if oftest.config["dbg_level"] < logging.WARNING:
Dan Talaycoba3745c2010-07-21 21:51:08 -0700949 sys.stderr.write("(skipped) ")
950 else:
951 sys.stderr.write("(S)")
Dan Talayco677c0b72011-08-23 22:53:38 -0700952
Dan Talayco8a64e332012-03-28 14:53:20 -0700953
954def all_stats_get(parent):
955 """
956 Get the aggregate stats for all flows in the table
957 @param parent Test instance with controller connection and assert
958 @returns dict with keys flows, packets, bytes, active (flows),
959 lookups, matched
960 """
Rich Lanecd97d3d2013-01-07 18:50:06 -0800961 stat_req = of10.message.aggregate_stats_request()
962 stat_req.match = of10.cstruct.ofp_match()
963 stat_req.match.wildcards = of10.cstruct.OFPFW_ALL
Dan Talayco8a64e332012-03-28 14:53:20 -0700964 stat_req.table_id = 0xff
Rich Lanecd97d3d2013-01-07 18:50:06 -0800965 stat_req.out_port = of10.cstruct.OFPP_NONE
Dan Talayco8a64e332012-03-28 14:53:20 -0700966
967 rv = {}
968
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700969 (reply, pkt) = parent.controller.transact(stat_req)
Dan Talayco8a64e332012-03-28 14:53:20 -0700970 parent.assertTrue(len(reply.stats) == 1, "Did not receive flow stats reply")
971
972 for obj in reply.stats:
973 (rv["flows"], rv["packets"], rv["bytes"]) = (obj.flow_count,
974 obj.packet_count, obj.byte_count)
975 break
976
Rich Lanecd97d3d2013-01-07 18:50:06 -0800977 request = of10.message.table_stats_request()
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700978 (reply , pkt) = parent.controller.transact(request)
Dan Talayco8a64e332012-03-28 14:53:20 -0700979
980
981 (rv["active"], rv["lookups"], rv["matched"]) = (0,0,0)
982 for obj in reply.stats:
983 rv["active"] += obj.active_count
984 rv["lookups"] += obj.lookup_count
985 rv["matched"] += obj.matched_count
986
987 return rv
Dan Talayco2baf8b52012-03-30 09:55:42 -0700988
Rich Lane7744e112013-01-11 17:23:57 -0800989_import_blacklist.add('FILTER')
Dan Talayco2baf8b52012-03-30 09:55:42 -0700990FILTER=''.join([(len(repr(chr(x)))==3) and chr(x) or '.'
991 for x in range(256)])
992
993def hex_dump_buffer(src, length=16):
994 """
995 Convert src to a hex dump string and return the string
996 @param src The source buffer
997 @param length The number of bytes shown in each line
998 @returns A string showing the hex dump
999 """
Dan Talaycoc516fa02012-04-12 22:28:43 -07001000 result = ["\n"]
Dan Talayco2baf8b52012-03-30 09:55:42 -07001001 for i in xrange(0, len(src), length):
1002 chars = src[i:i+length]
1003 hex = ' '.join(["%02x" % ord(x) for x in chars])
1004 printable = ''.join(["%s" % ((ord(x) <= 127 and
1005 FILTER[ord(x)]) or '.') for x in chars])
1006 result.append("%04x %-*s %s\n" % (i, length*3, hex, printable))
1007 return ''.join(result)
1008
1009def format_packet(pkt):
1010 return "Packet length %d \n%s" % (len(str(pkt)),
1011 hex_dump_buffer(str(pkt)))
Rich Lane5d7e89a2012-10-26 16:43:13 -07001012
1013def inspect_packet(pkt):
1014 """
1015 Wrapper around scapy's show() method.
1016 @returns A string showing the dissected packet.
1017 """
1018 from cStringIO import StringIO
1019 out = None
1020 backup = sys.stdout
1021 try:
1022 sys.stdout = StringIO()
1023 pkt.show2()
1024 out = sys.stdout.getvalue()
1025 sys.stdout.close()
1026 finally:
1027 sys.stdout = backup
1028 return out
Rich Lane0a4f6372013-01-02 14:40:22 -08001029
1030def nonstandard(cls):
1031 """
Rich Lanecc45b8e2013-01-02 15:55:02 -08001032 Testcase decorator that marks the test as being non-standard.
1033 These tests are not automatically added to the "standard" group.
Rich Lane0a4f6372013-01-02 14:40:22 -08001034 """
Rich Lanecc45b8e2013-01-02 15:55:02 -08001035 cls._nonstandard = True
Rich Lane0a4f6372013-01-02 14:40:22 -08001036 return cls
1037
1038def disabled(cls):
1039 """
Rich Lanecc45b8e2013-01-02 15:55:02 -08001040 Testcase decorator that marks the test as being disabled.
1041 These tests are not automatically added to the "standard" group or
1042 their module's group.
Rich Lane0a4f6372013-01-02 14:40:22 -08001043 """
Rich Lanecc45b8e2013-01-02 15:55:02 -08001044 cls._disabled = True
Rich Lane0a4f6372013-01-02 14:40:22 -08001045 return cls
Rich Lane97e99652013-01-02 17:23:20 -08001046
1047def group(name):
1048 """
1049 Testcase decorator that adds the test to a group.
1050 """
1051 def fn(cls):
1052 if not hasattr(cls, "_groups"):
1053 cls._groups = []
1054 cls._groups.append(name)
1055 return cls
1056 return fn
Rich Lane5a9a1922013-01-11 14:29:30 -08001057
1058def version(ver):
1059 """
1060 Testcase decorator that specifies which versions of OpenFlow the test
1061 supports. The default is 1.0+. This decorator may only be used once.
1062
1063 Supported syntax:
1064 1.0 -> 1.0
1065 1.0,1.2,1.3 -> 1.0, 1.2, 1.3
1066 1.0+ -> 1.0, 1.1, 1.2, 1.3
1067 """
1068 versions = parse_version(ver)
1069 def fn(cls):
1070 cls._versions = versions
1071 return cls
1072 return fn
1073
1074def parse_version(ver):
1075 allowed_versions = ["1.0", "1.1", "1.2", "1.3"]
1076 if re.match("^1\.\d+$", ver):
1077 versions = set([ver])
1078 elif re.match("^(1\.\d+)\+$", ver):
1079 if not ver[:-1] in allowed_versions:
1080 raise ValueError("invalid OpenFlow version %s" % ver[:-1])
1081 versions = set()
1082 if ver != "1.1+": versions.add("1.0")
1083 if ver != "1.2+": versions.add("1.1")
1084 if ver != "1.3+": versions.add("1.2")
1085 versions.add("1.3")
1086 else:
1087 versions = set(ver.split(','))
1088
1089 for version in versions:
1090 if not version in allowed_versions:
1091 raise ValueError("invalid OpenFlow version %s" % version)
1092
1093 return versions
1094
1095assert(parse_version("1.0") == set(["1.0"]))
1096assert(parse_version("1.0,1.2,1.3") == set(["1.0", "1.2", "1.3"]))
1097assert(parse_version("1.0+") == set(["1.0", "1.1", "1.2", "1.3"]))
Rich Lane7744e112013-01-11 17:23:57 -08001098
1099__all__ = list(set(locals()) - _import_blacklist)