blob: ef2e517a5c7e3075ea6dbef72f7fa0ddb02975f2 [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
Dan Talaycod2ca1032010-03-10 14:40:26 -08006
7try:
8 import scapy.all as scapy
9except:
10 try:
11 import scapy as scapy
12 except:
13 sys.exit("Need to install scapy for packet parsing")
Dan Talayco41eae8b2010-03-10 13:57:06 -080014
Rich Lanecd97d3d2013-01-07 18:50:06 -080015import oftest
16import oftest.controller
17import oftest.dataplane
18import of10.cstruct
19import of10.message
20import of10.action
21import of10.parse
Dan Talaycoc901f4d2010-03-07 21:55:45 -080022
Dan Talaycoba3745c2010-07-21 21:51:08 -070023global skipped_test_count
24skipped_test_count = 0
25
Dan Talayco551befa2010-07-15 17:05:32 -070026# Some useful defines
27IP_ETHERTYPE = 0x800
28TCP_PROTOCOL = 0x6
29UDP_PROTOCOL = 0x11
30
Jeffrey Townsend5cb7ed32012-08-17 18:11:01 +000031MINSIZE = 0
32
Rich Lane9a003812012-10-04 17:17:59 -070033def delete_all_flows(ctrl):
Dan Talayco41eae8b2010-03-10 13:57:06 -080034 """
35 Delete all flows on the switch
36 @param ctrl The controller object for the test
Dan Talayco41eae8b2010-03-10 13:57:06 -080037 """
38
Rich Lane9a003812012-10-04 17:17:59 -070039 logging.info("Deleting all flows")
Rich Lanecd97d3d2013-01-07 18:50:06 -080040 msg = of10.message.flow_mod()
41 msg.match.wildcards = of10.cstruct.OFPFW_ALL
42 msg.out_port = of10.cstruct.OFPP_NONE
43 msg.command = of10.cstruct.OFPFC_DELETE
Dan Talaycoc901f4d2010-03-07 21:55:45 -080044 msg.buffer_id = 0xffffffff
Rich Lane5c3151c2013-01-03 17:15:41 -080045 ctrl.message_send(msg)
Rich Lane32bf9482013-01-03 17:26:30 -080046 return 0 # for backwards compatibility
Dan Talayco41eae8b2010-03-10 13:57:06 -080047
Ed Swierk99a74de2012-08-22 06:40:54 -070048def required_wildcards(parent):
Rich Lane2014f9b2012-10-05 15:29:40 -070049 w = test_param_get('required_wildcards', default='default')
Ed Swierk99a74de2012-08-22 06:40:54 -070050 if w == 'l3-l4':
Rich Lanecd97d3d2013-01-07 18:50:06 -080051 return (of10.cstruct.OFPFW_NW_SRC_ALL | of10.cstruct.OFPFW_NW_DST_ALL | of10.cstruct.OFPFW_NW_TOS
52 | of10.cstruct.OFPFW_NW_PROTO | of10.cstruct.OFPFW_TP_SRC | of10.cstruct.OFPFW_TP_DST)
Ed Swierk99a74de2012-08-22 06:40:54 -070053 else:
54 return 0
55
Dan Talayco41eae8b2010-03-10 13:57:06 -080056def simple_tcp_packet(pktlen=100,
57 dl_dst='00:01:02:03:04:05',
58 dl_src='00:06:07:08:09:0a',
Tatsuya Yabe460321e2010-05-25 17:50:49 -070059 dl_vlan_enable=False,
60 dl_vlan=0,
61 dl_vlan_pcp=0,
Dan Talayco551befa2010-07-15 17:05:32 -070062 dl_vlan_cfi=0,
Dan Talayco41eae8b2010-03-10 13:57:06 -080063 ip_src='192.168.0.1',
64 ip_dst='192.168.0.2',
Tatsuya Yabe460321e2010-05-25 17:50:49 -070065 ip_tos=0,
Dan Talayco41eae8b2010-03-10 13:57:06 -080066 tcp_sport=1234,
Christian Dickmann8b59b4b2012-09-23 16:48:30 -070067 tcp_dport=80,
68 ip_ihl=None,
69 ip_options=False
Dan Talayco41eae8b2010-03-10 13:57:06 -080070 ):
71 """
72 Return a simple dataplane TCP packet
73
74 Supports a few parameters:
75 @param len Length of packet in bytes w/o CRC
76 @param dl_dst Destinatino MAC
77 @param dl_src Source MAC
Tatsuya Yabe460321e2010-05-25 17:50:49 -070078 @param dl_vlan_enable True if the packet is with vlan, False otherwise
79 @param dl_vlan VLAN ID
80 @param dl_vlan_pcp VLAN priority
Dan Talayco41eae8b2010-03-10 13:57:06 -080081 @param ip_src IP source
82 @param ip_dst IP destination
Tatsuya Yabe460321e2010-05-25 17:50:49 -070083 @param ip_tos IP ToS
Dan Talayco41eae8b2010-03-10 13:57:06 -080084 @param tcp_dport TCP destination port
85 @param ip_sport TCP source port
86
87 Generates a simple TCP request. Users
88 shouldn't assume anything about this packet other than that
89 it is a valid ethernet/IP/TCP frame.
90 """
Jeffrey Townsend5cb7ed32012-08-17 18:11:01 +000091
92 if MINSIZE > pktlen:
93 pktlen = MINSIZE
94
Dan Talayco551befa2010-07-15 17:05:32 -070095 # Note Dot1Q.id is really CFI
Shudong Zhou43ee54c2012-12-13 15:52:37 -080096 if (dl_vlan_enable):
Tatsuya Yabe460321e2010-05-25 17:50:49 -070097 pkt = scapy.Ether(dst=dl_dst, src=dl_src)/ \
Dan Talayco551befa2010-07-15 17:05:32 -070098 scapy.Dot1Q(prio=dl_vlan_pcp, id=dl_vlan_cfi, vlan=dl_vlan)/ \
Christian Dickmann8b59b4b2012-09-23 16:48:30 -070099 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ihl=ip_ihl)/ \
Tatsuya Yabe460321e2010-05-25 17:50:49 -0700100 scapy.TCP(sport=tcp_sport, dport=tcp_dport)
101 else:
Christian Dickmann8b59b4b2012-09-23 16:48:30 -0700102 if not ip_options:
103 pkt = scapy.Ether(dst=dl_dst, src=dl_src)/ \
104 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ihl=ip_ihl)/ \
105 scapy.TCP(sport=tcp_sport, dport=tcp_dport)
106 else:
107 pkt = scapy.Ether(dst=dl_dst, src=dl_src)/ \
108 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ihl=ip_ihl, options=ip_options)/ \
109 scapy.TCP(sport=tcp_sport, dport=tcp_dport)
Tatsuya Yabe460321e2010-05-25 17:50:49 -0700110
Dan Talayco41eae8b2010-03-10 13:57:06 -0800111 pkt = pkt/("D" * (pktlen - len(pkt)))
112
113 return pkt
114
Rich Lane6ee7bea2012-10-26 16:19:29 -0700115def simple_udp_packet(pktlen=100,
116 dl_dst='00:01:02:03:04:05',
117 dl_src='00:06:07:08:09:0a',
118 dl_vlan_enable=False,
119 dl_vlan=0,
120 dl_vlan_pcp=0,
121 dl_vlan_cfi=0,
122 ip_src='192.168.0.1',
123 ip_dst='192.168.0.2',
124 ip_tos=0,
125 udp_sport=1234,
126 udp_dport=80,
127 ip_ihl=None,
128 ip_options=False
129 ):
130 """
131 Return a simple dataplane UDP packet
132
133 Supports a few parameters:
134 @param len Length of packet in bytes w/o CRC
135 @param dl_dst Destination MAC
136 @param dl_src Source MAC
137 @param dl_vlan_enable True if the packet is with vlan, False otherwise
138 @param dl_vlan VLAN ID
139 @param dl_vlan_pcp VLAN priority
140 @param ip_src IP source
141 @param ip_dst IP destination
142 @param ip_tos IP ToS
143 @param udp_dport UDP destination port
144 @param udp_sport UDP source port
145
146 Generates a simple UDP packet. Users shouldn't assume anything about
147 this packet other than that it is a valid ethernet/IP/UDP frame.
148 """
149
150 if MINSIZE > pktlen:
151 pktlen = MINSIZE
152
153 # Note Dot1Q.id is really CFI
154 if (dl_vlan_enable):
155 pkt = scapy.Ether(dst=dl_dst, src=dl_src)/ \
156 scapy.Dot1Q(prio=dl_vlan_pcp, id=dl_vlan_cfi, vlan=dl_vlan)/ \
157 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ihl=ip_ihl)/ \
158 scapy.UDP(sport=udp_sport, dport=udp_dport)
159 else:
160 if not ip_options:
161 pkt = scapy.Ether(dst=dl_dst, src=dl_src)/ \
162 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ihl=ip_ihl)/ \
163 scapy.UDP(sport=udp_sport, dport=udp_dport)
164 else:
165 pkt = scapy.Ether(dst=dl_dst, src=dl_src)/ \
166 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ihl=ip_ihl, options=ip_options)/ \
167 scapy.UDP(sport=udp_sport, dport=udp_dport)
168
169 pkt = pkt/("D" * (pktlen - len(pkt)))
170
171 return pkt
172
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700173def simple_icmp_packet(pktlen=60,
174 dl_dst='00:01:02:03:04:05',
175 dl_src='00:06:07:08:09:0a',
176 dl_vlan_enable=False,
177 dl_vlan=0,
178 dl_vlan_pcp=0,
179 ip_src='192.168.0.1',
180 ip_dst='192.168.0.2',
181 ip_tos=0,
182 icmp_type=8,
183 icmp_code=0
184 ):
185 """
186 Return a simple ICMP packet
187
188 Supports a few parameters:
189 @param len Length of packet in bytes w/o CRC
190 @param dl_dst Destinatino MAC
191 @param dl_src Source MAC
192 @param dl_vlan_enable True if the packet is with vlan, False otherwise
193 @param dl_vlan VLAN ID
194 @param dl_vlan_pcp VLAN priority
195 @param ip_src IP source
196 @param ip_dst IP destination
197 @param ip_tos IP ToS
198 @param icmp_type ICMP type
199 @param icmp_code ICMP code
200
201 Generates a simple ICMP ECHO REQUEST. Users
202 shouldn't assume anything about this packet other than that
203 it is a valid ethernet/ICMP frame.
204 """
Jeffrey Townsend5cb7ed32012-08-17 18:11:01 +0000205
206 if MINSIZE > pktlen:
207 pktlen = MINSIZE
208
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700209 if (dl_vlan_enable):
210 pkt = scapy.Ether(dst=dl_dst, src=dl_src)/ \
211 scapy.Dot1Q(prio=dl_vlan_pcp, id=0, vlan=dl_vlan)/ \
212 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos)/ \
213 scapy.ICMP(type=icmp_type, code=icmp_code)
214 else:
215 pkt = scapy.Ether(dst=dl_dst, src=dl_src)/ \
216 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos)/ \
217 scapy.ICMP(type=icmp_type, code=icmp_code)
218
219 pkt = pkt/("0" * (pktlen - len(pkt)))
220
221 return pkt
222
Ed Swierk0aeff8c2012-03-23 20:27:18 -0700223def simple_eth_packet(pktlen=60,
224 dl_dst='00:01:02:03:04:05',
225 dl_src='01:80:c2:00:00:00',
226 dl_type=0x88cc):
Jeffrey Townsend5cb7ed32012-08-17 18:11:01 +0000227
228 if MINSIZE > pktlen:
229 pktlen = MINSIZE
230
Ed Swierk0aeff8c2012-03-23 20:27:18 -0700231 pkt = scapy.Ether(dst=dl_dst, src=dl_src, type=dl_type)
232
233 pkt = pkt/("0" * (pktlen - len(pkt)))
234
235 return pkt
236
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800237def qinq_tcp_packet(pktlen=100,
238 dl_dst='00:01:02:03:04:05',
239 dl_src='00:06:07:08:09:0a',
240 dl_vlan_outer=20,
241 dl_vlan_pcp_outer=0,
242 dl_vlan_cfi_outer=0,
243 dl_vlan=10,
244 dl_vlan_pcp=0,
245 dl_vlan_cfi=0,
246 ip_src='192.168.0.1',
247 ip_dst='192.168.0.2',
248 ip_tos=0,
249 tcp_sport=1234,
250 tcp_dport=80,
251 ip_ihl=None,
252 ip_options=False
253 ):
254 """
255 Return a doubly tagged dataplane TCP packet
256
257 Supports a few parameters:
258 @param len Length of packet in bytes w/o CRC
259 @param dl_dst Destinatino MAC
260 @param dl_src Source MAC
261 @param dl_vlan_outer Outer VLAN ID
262 @param dl_vlan_pcp_outer Outer VLAN priority
263 @param dl_vlan_cfi_outer Outer VLAN cfi bit
264 @param dl_vlan Inner VLAN ID
265 @param dl_vlan_pcp VLAN priority
266 @param dl_vlan_cfi VLAN cfi bit
267 @param ip_src IP source
268 @param ip_dst IP destination
269 @param ip_tos IP ToS
270 @param tcp_dport TCP destination port
271 @param ip_sport TCP source port
272
273 Generates a TCP request. Users
274 shouldn't assume anything about this packet other than that
275 it is a valid ethernet/IP/TCP frame.
276 """
277
278 if MINSIZE > pktlen:
279 pktlen = MINSIZE
280
281 # Note Dot1Q.id is really CFI
282 pkt = scapy.Ether(dst=dl_dst, src=dl_src)/ \
283 scapy.Dot1Q(prio=dl_vlan_pcp_outer, id=dl_vlan_cfi_outer, vlan=dl_vlan_outer)/ \
284 scapy.Dot1Q(prio=dl_vlan_pcp, id=dl_vlan_cfi, vlan=dl_vlan)/ \
285 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ihl=ip_ihl)/ \
286 scapy.TCP(sport=tcp_sport, dport=tcp_dport)
287
288 pkt = pkt/("D" * (pktlen - len(pkt)))
289
290 return pkt
291
Shudong Zhoub7f12462012-11-20 13:01:12 -0800292def do_barrier(ctrl, timeout=-1):
Dan Talayco0fc08bd2012-04-09 16:56:18 -0700293 """
294 Do a barrier command
295 Return 0 on success, -1 on error
296 """
Rich Lanecd97d3d2013-01-07 18:50:06 -0800297 b = of10.message.barrier_request()
Shudong Zhoub7f12462012-11-20 13:01:12 -0800298 (resp, pkt) = ctrl.transact(b, timeout=timeout)
Rich Lane3a261d52013-01-03 17:45:08 -0800299 if resp is None:
300 raise AssertionError("barrier failed")
Dan Talaycof6b94832012-04-12 21:50:57 -0700301 # We'll trust the transaction processing in the controller that xid matched
Rich Lane3a261d52013-01-03 17:45:08 -0800302 return 0 # for backwards compatibility
Dan Talayco92c99122010-06-03 13:53:18 -0700303
Rich Lane9a003812012-10-04 17:17:59 -0700304def port_config_get(controller, port_no):
Dan Talayco92c99122010-06-03 13:53:18 -0700305 """
306 Get a port's configuration
307
308 Gets the switch feature configuration and grabs one port's
309 configuration
310
311 @returns (hwaddr, config, advert) The hwaddress, configuration and
312 advertised values
313 """
Rich Lanecd97d3d2013-01-07 18:50:06 -0800314 request = of10.message.features_request()
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700315 reply, pkt = controller.transact(request)
Rich Lane9a003812012-10-04 17:17:59 -0700316 logging.debug(reply.show())
Dan Talayco92c99122010-06-03 13:53:18 -0700317 if reply is None:
Rich Lane9a003812012-10-04 17:17:59 -0700318 logging.warn("Get feature request failed")
Dan Talayco92c99122010-06-03 13:53:18 -0700319 return None, None, None
320 for idx in range(len(reply.ports)):
321 if reply.ports[idx].port_no == port_no:
322 return (reply.ports[idx].hw_addr, reply.ports[idx].config,
323 reply.ports[idx].advertised)
324
Rich Lane9a003812012-10-04 17:17:59 -0700325 logging.warn("Did not find port number for port config")
Dan Talayco92c99122010-06-03 13:53:18 -0700326 return None, None, None
327
Rich Lane9a003812012-10-04 17:17:59 -0700328def port_config_set(controller, port_no, config, mask):
Dan Talayco92c99122010-06-03 13:53:18 -0700329 """
330 Set the port configuration according the given parameters
331
332 Gets the switch feature configuration and updates one port's
333 configuration value according to config and mask
334 """
Rich Lane9a003812012-10-04 17:17:59 -0700335 logging.info("Setting port " + str(port_no) + " to config " + str(config))
Rich Lanecd97d3d2013-01-07 18:50:06 -0800336 request = of10.message.features_request()
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700337 reply, pkt = controller.transact(request)
Dan Talayco92c99122010-06-03 13:53:18 -0700338 if reply is None:
339 return -1
Rich Lane9a003812012-10-04 17:17:59 -0700340 logging.debug(reply.show())
Ed Swierk8d84ce02012-12-27 15:36:48 -0800341 p = None
Dan Talayco92c99122010-06-03 13:53:18 -0700342 for idx in range(len(reply.ports)):
343 if reply.ports[idx].port_no == port_no:
Ed Swierk8d84ce02012-12-27 15:36:48 -0800344 p = reply.ports[idx]
Dan Talayco92c99122010-06-03 13:53:18 -0700345 break
Rich Lanecd97d3d2013-01-07 18:50:06 -0800346 mod = of10.message.port_mod()
Dan Talayco92c99122010-06-03 13:53:18 -0700347 mod.port_no = port_no
Ed Swierk8d84ce02012-12-27 15:36:48 -0800348 if p:
349 mod.hw_addr = p.hw_addr
Dan Talayco92c99122010-06-03 13:53:18 -0700350 mod.config = config
351 mod.mask = mask
Ed Swierk8d84ce02012-12-27 15:36:48 -0800352 if p:
353 mod.advertise = p.advertised
Rich Lane5c3151c2013-01-03 17:15:41 -0800354 controller.message_send(mod)
355 return 0
Dan Talayco92c99122010-06-03 13:53:18 -0700356
Rich Lane2014f9b2012-10-05 15:29:40 -0700357def receive_pkt_check(dp, pkt, yes_ports, no_ports, assert_if):
Dan Talayco92c99122010-06-03 13:53:18 -0700358 """
359 Check for proper receive packets across all ports
Ken Chiang1bf01602012-04-04 10:48:23 -0700360 @param dp The dataplane object
Dan Talayco92c99122010-06-03 13:53:18 -0700361 @param pkt Expected packet; may be None if yes_ports is empty
362 @param yes_ports Set or list of ports that should recieve packet
363 @param no_ports Set or list of ports that should not receive packet
364 @param assert_if Object that implements assertXXX
365 """
Rich Lane91765672012-12-06 16:33:04 -0800366
367 # Wait this long for packets that we don't expect to receive.
368 # 100ms is (rarely) too short for positive tests on slow
369 # switches but is definitely not too short for a negative test.
370 negative_timeout = 0.1
371
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700372 exp_pkt_arg = None
Rich Lanecd97d3d2013-01-07 18:50:06 -0800373 if oftest.config["relax"]:
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700374 exp_pkt_arg = pkt
375
Dan Talayco92c99122010-06-03 13:53:18 -0700376 for ofport in yes_ports:
Rich Lane9a003812012-10-04 17:17:59 -0700377 logging.debug("Checking for pkt on port " + str(ofport))
Ken Chiang1bf01602012-04-04 10:48:23 -0700378 (rcv_port, rcv_pkt, pkt_time) = dp.poll(
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700379 port_number=ofport, exp_pkt=exp_pkt_arg)
Dan Talayco92c99122010-06-03 13:53:18 -0700380 assert_if.assertTrue(rcv_pkt is not None,
381 "Did not receive pkt on " + str(ofport))
Rich Lanecd97d3d2013-01-07 18:50:06 -0800382 if not oftest.dataplane.match_exp_pkt(pkt, rcv_pkt):
Rich Lane9a003812012-10-04 17:17:59 -0700383 logging.debug("Sent %s" % format_packet(pkt))
384 logging.debug("Resp %s" % format_packet(rcv_pkt))
Rich Lanecd97d3d2013-01-07 18:50:06 -0800385 assert_if.assertTrue(oftest.dataplane.match_exp_pkt(pkt, rcv_pkt),
Ken Chiang1bf01602012-04-04 10:48:23 -0700386 "Response packet does not match send packet " +
387 "on port " + str(ofport))
Dan Talayco73f84012012-10-02 09:23:18 -0700388 if len(no_ports) > 0:
Rich Lane91765672012-12-06 16:33:04 -0800389 time.sleep(negative_timeout)
Dan Talayco92c99122010-06-03 13:53:18 -0700390 for ofport in no_ports:
Rich Lane9a003812012-10-04 17:17:59 -0700391 logging.debug("Negative check for pkt on port " + str(ofport))
Ken Chiang1bf01602012-04-04 10:48:23 -0700392 (rcv_port, rcv_pkt, pkt_time) = dp.poll(
Rich Lane91765672012-12-06 16:33:04 -0800393 port_number=ofport, timeout=0, exp_pkt=exp_pkt_arg)
Dan Talayco92c99122010-06-03 13:53:18 -0700394 assert_if.assertTrue(rcv_pkt is None,
395 "Unexpected pkt on port " + str(ofport))
Dan Talayco551befa2010-07-15 17:05:32 -0700396
397
Dan Talaycoc948d0b2012-03-23 12:17:54 -0700398def receive_pkt_verify(parent, egr_ports, exp_pkt, ing_port):
Dan Talayco551befa2010-07-15 17:05:32 -0700399 """
400 Receive a packet and verify it matches an expected value
Dan Talaycof6e76c02012-03-23 10:56:12 -0700401 @param egr_port A single port or list of ports
Dan Talayco551befa2010-07-15 17:05:32 -0700402
403 parent must implement dataplane, assertTrue and assertEqual
404 """
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700405 exp_pkt_arg = None
Rich Lanecd97d3d2013-01-07 18:50:06 -0800406 if oftest.config["relax"]:
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700407 exp_pkt_arg = exp_pkt
408
Dan Talaycof6e76c02012-03-23 10:56:12 -0700409 if type(egr_ports) == type([]):
410 egr_port_list = egr_ports
411 else:
412 egr_port_list = [egr_ports]
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700413
Dan Talaycof6e76c02012-03-23 10:56:12 -0700414 # Expect a packet from each port on egr port list
415 for egr_port in egr_port_list:
Dan Talaycod8ae7582012-03-23 12:24:56 -0700416 check_port = egr_port
Rich Lanecd97d3d2013-01-07 18:50:06 -0800417 if egr_port == of10.cstruct.OFPP_IN_PORT:
Dan Talaycod8ae7582012-03-23 12:24:56 -0700418 check_port = ing_port
Dan Talaycof6e76c02012-03-23 10:56:12 -0700419 (rcv_port, rcv_pkt, pkt_time) = parent.dataplane.poll(
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700420 port_number=check_port, exp_pkt=exp_pkt_arg)
Dan Talayco551befa2010-07-15 17:05:32 -0700421
Dan Talaycof6e76c02012-03-23 10:56:12 -0700422 if rcv_pkt is None:
Rich Lane9a003812012-10-04 17:17:59 -0700423 logging.error("ERROR: No packet received from " +
Dan Talaycod8ae7582012-03-23 12:24:56 -0700424 str(check_port))
Dan Talayco551befa2010-07-15 17:05:32 -0700425
Dan Talaycof6e76c02012-03-23 10:56:12 -0700426 parent.assertTrue(rcv_pkt is not None,
Dan Talaycod8ae7582012-03-23 12:24:56 -0700427 "Did not receive packet port " + str(check_port))
Rich Lane9a003812012-10-04 17:17:59 -0700428 logging.debug("Packet len " + str(len(rcv_pkt)) + " in on " +
Dan Talaycof6e76c02012-03-23 10:56:12 -0700429 str(rcv_port))
430
431 if str(exp_pkt) != str(rcv_pkt):
Rich Lane9a003812012-10-04 17:17:59 -0700432 logging.error("ERROR: Packet match failed.")
433 logging.debug("Expected len " + str(len(exp_pkt)) + ": "
Dan Talaycof6e76c02012-03-23 10:56:12 -0700434 + str(exp_pkt).encode('hex'))
Rich Lane9a003812012-10-04 17:17:59 -0700435 logging.debug("Received len " + str(len(rcv_pkt)) + ": "
Dan Talaycof6e76c02012-03-23 10:56:12 -0700436 + str(rcv_pkt).encode('hex'))
Rich Lane5d7e89a2012-10-26 16:43:13 -0700437 logging.debug("Expected packet: " + inspect_packet(scapy.Ether(str(exp_pkt))))
438 logging.debug("Received packet: " + inspect_packet(scapy.Ether(str(rcv_pkt))))
Dan Talaycof6e76c02012-03-23 10:56:12 -0700439 parent.assertEqual(str(exp_pkt), str(rcv_pkt),
Dan Talaycod8ae7582012-03-23 12:24:56 -0700440 "Packet match error on port " + str(check_port))
Dan Talaycof6e76c02012-03-23 10:56:12 -0700441
Dan Talayco551befa2010-07-15 17:05:32 -0700442def match_verify(parent, req_match, res_match):
443 """
444 Verify flow matches agree; if they disagree, report where
445
446 parent must implement assertEqual
447 Use str() to ensure content is compared and not pointers
448 """
449
450 parent.assertEqual(req_match.wildcards, res_match.wildcards,
451 'Match failed: wildcards: ' + hex(req_match.wildcards) +
452 " != " + hex(res_match.wildcards))
453 parent.assertEqual(req_match.in_port, res_match.in_port,
454 'Match failed: in_port: ' + str(req_match.in_port) +
455 " != " + str(res_match.in_port))
456 parent.assertEqual(str(req_match.dl_src), str(res_match.dl_src),
457 'Match failed: dl_src: ' + str(req_match.dl_src) +
458 " != " + str(res_match.dl_src))
459 parent.assertEqual(str(req_match.dl_dst), str(res_match.dl_dst),
460 'Match failed: dl_dst: ' + str(req_match.dl_dst) +
461 " != " + str(res_match.dl_dst))
462 parent.assertEqual(req_match.dl_vlan, res_match.dl_vlan,
463 'Match failed: dl_vlan: ' + str(req_match.dl_vlan) +
464 " != " + str(res_match.dl_vlan))
465 parent.assertEqual(req_match.dl_vlan_pcp, res_match.dl_vlan_pcp,
466 'Match failed: dl_vlan_pcp: ' +
467 str(req_match.dl_vlan_pcp) + " != " +
468 str(res_match.dl_vlan_pcp))
469 parent.assertEqual(req_match.dl_type, res_match.dl_type,
470 'Match failed: dl_type: ' + str(req_match.dl_type) +
471 " != " + str(res_match.dl_type))
472
Rich Lanecd97d3d2013-01-07 18:50:06 -0800473 if (not(req_match.wildcards & of10.cstruct.OFPFW_DL_TYPE)
Dan Talayco551befa2010-07-15 17:05:32 -0700474 and (req_match.dl_type == IP_ETHERTYPE)):
475 parent.assertEqual(req_match.nw_tos, res_match.nw_tos,
476 'Match failed: nw_tos: ' + str(req_match.nw_tos) +
477 " != " + str(res_match.nw_tos))
478 parent.assertEqual(req_match.nw_proto, res_match.nw_proto,
479 'Match failed: nw_proto: ' + str(req_match.nw_proto) +
480 " != " + str(res_match.nw_proto))
481 parent.assertEqual(req_match.nw_src, res_match.nw_src,
482 'Match failed: nw_src: ' + str(req_match.nw_src) +
483 " != " + str(res_match.nw_src))
484 parent.assertEqual(req_match.nw_dst, res_match.nw_dst,
485 'Match failed: nw_dst: ' + str(req_match.nw_dst) +
486 " != " + str(res_match.nw_dst))
487
Rich Lanecd97d3d2013-01-07 18:50:06 -0800488 if (not(req_match.wildcards & of10.cstruct.OFPFW_NW_PROTO)
Dan Talayco551befa2010-07-15 17:05:32 -0700489 and ((req_match.nw_proto == TCP_PROTOCOL)
490 or (req_match.nw_proto == UDP_PROTOCOL))):
491 parent.assertEqual(req_match.tp_src, res_match.tp_src,
492 'Match failed: tp_src: ' +
493 str(req_match.tp_src) +
494 " != " + str(res_match.tp_src))
495 parent.assertEqual(req_match.tp_dst, res_match.tp_dst,
496 'Match failed: tp_dst: ' +
497 str(req_match.tp_dst) +
498 " != " + str(res_match.tp_dst))
499
Ed Swierk99a74de2012-08-22 06:40:54 -0700500def packet_to_flow_match(parent, packet):
Rich Lanecd97d3d2013-01-07 18:50:06 -0800501 match = of10.parse.packet_to_flow_match(packet)
Ed Swierk99a74de2012-08-22 06:40:54 -0700502 match.wildcards |= required_wildcards(parent)
503 return match
504
505def flow_msg_create(parent, pkt, ing_port=None, action_list=None, wildcards=None,
Dan Talaycof6e76c02012-03-23 10:56:12 -0700506 egr_ports=None, egr_queue=None, check_expire=False, in_band=False):
Dan Talayco551befa2010-07-15 17:05:32 -0700507 """
508 Create a flow message
509
510 Match on packet with given wildcards.
511 See flow_match_test for other parameter descriptoins
512 @param egr_queue if not None, make the output an enqueue action
Dan Talayco677c0b72011-08-23 22:53:38 -0700513 @param in_band if True, do not wildcard ingress port
Dan Talaycof6e76c02012-03-23 10:56:12 -0700514 @param egr_ports None (drop), single port or list of ports
Dan Talayco551befa2010-07-15 17:05:32 -0700515 """
Rich Lanecd97d3d2013-01-07 18:50:06 -0800516 match = of10.parse.packet_to_flow_match(pkt)
Dan Talayco551befa2010-07-15 17:05:32 -0700517 parent.assertTrue(match is not None, "Flow match from pkt failed")
Ed Swierk99a74de2012-08-22 06:40:54 -0700518 if wildcards is None:
519 wildcards = required_wildcards(parent)
Dan Talayco677c0b72011-08-23 22:53:38 -0700520 if in_band:
Rich Lanecd97d3d2013-01-07 18:50:06 -0800521 wildcards &= ~of10.cstruct.OFPFW_IN_PORT
Dan Talayco551befa2010-07-15 17:05:32 -0700522 match.wildcards = wildcards
523 match.in_port = ing_port
524
Dan Talaycof6e76c02012-03-23 10:56:12 -0700525 if type(egr_ports) == type([]):
526 egr_port_list = egr_ports
527 else:
528 egr_port_list = [egr_ports]
529
Rich Lanecd97d3d2013-01-07 18:50:06 -0800530 request = of10.message.flow_mod()
Dan Talayco551befa2010-07-15 17:05:32 -0700531 request.match = match
532 request.buffer_id = 0xffffffff
533 if check_expire:
Rich Lanecd97d3d2013-01-07 18:50:06 -0800534 request.flags |= of10.cstruct.OFPFF_SEND_FLOW_REM
Dan Talayco551befa2010-07-15 17:05:32 -0700535 request.hard_timeout = 1
536
537 if action_list is not None:
538 for act in action_list:
Rich Lane9a003812012-10-04 17:17:59 -0700539 logging.debug("Adding action " + act.show())
Rich Lanee30455b2013-01-03 16:24:44 -0800540 request.actions.add(act)
Dan Talayco551befa2010-07-15 17:05:32 -0700541
542 # Set up output/enqueue action if directed
543 if egr_queue is not None:
Dan Talaycof6e76c02012-03-23 10:56:12 -0700544 parent.assertTrue(egr_ports is not None, "Egress port not set")
Rich Lanecd97d3d2013-01-07 18:50:06 -0800545 act = of10.action.action_enqueue()
Dan Talaycof6e76c02012-03-23 10:56:12 -0700546 for egr_port in egr_port_list:
547 act.port = egr_port
548 act.queue_id = egr_queue
Rich Lanee30455b2013-01-03 16:24:44 -0800549 request.actions.add(act)
Dan Talaycof6e76c02012-03-23 10:56:12 -0700550 elif egr_ports is not None:
551 for egr_port in egr_port_list:
Rich Lanecd97d3d2013-01-07 18:50:06 -0800552 act = of10.action.action_output()
Dan Talaycof6e76c02012-03-23 10:56:12 -0700553 act.port = egr_port
Rich Lanee30455b2013-01-03 16:24:44 -0800554 request.actions.add(act)
Dan Talayco551befa2010-07-15 17:05:32 -0700555
Rich Lane9a003812012-10-04 17:17:59 -0700556 logging.debug(request.show())
Dan Talayco551befa2010-07-15 17:05:32 -0700557
558 return request
559
Jeffrey Townsendf3eae9c2012-03-28 18:23:21 -0700560def flow_msg_install(parent, request, clear_table_override=None):
Dan Talayco551befa2010-07-15 17:05:32 -0700561 """
562 Install a flow mod message in the switch
563
564 @param parent Must implement controller, assertEqual, assertTrue
565 @param request The request, all set to go
566 @param clear_table If true, clear the flow table before installing
567 """
Dan Talayco8a64e332012-03-28 14:53:20 -0700568
Rich Lane2014f9b2012-10-05 15:29:40 -0700569 clear_table = test_param_get('clear_table', default=True)
Jeffrey Townsendf3eae9c2012-03-28 18:23:21 -0700570 if(clear_table_override != None):
571 clear_table = clear_table_override
572
573 if clear_table:
Rich Lane9a003812012-10-04 17:17:59 -0700574 logging.debug("Clear flow table")
Rich Lane32bf9482013-01-03 17:26:30 -0800575 delete_all_flows(parent.controller)
Dan Talayco551befa2010-07-15 17:05:32 -0700576
Rich Lane9a003812012-10-04 17:17:59 -0700577 logging.debug("Insert flow")
Rich Lane5c3151c2013-01-03 17:15:41 -0800578 parent.controller.message_send(request)
Rich Lanee912d032012-12-22 14:28:33 -0800579
Rich Lane3a261d52013-01-03 17:45:08 -0800580 do_barrier(parent.controller)
Dan Talayco551befa2010-07-15 17:05:32 -0700581
Ed Swierk99a74de2012-08-22 06:40:54 -0700582def flow_match_test_port_pair(parent, ing_port, egr_ports, wildcards=None,
Dan Talayco551befa2010-07-15 17:05:32 -0700583 dl_vlan=-1, pkt=None, exp_pkt=None,
Rich Lanee5779d32012-10-05 17:56:04 -0700584 action_list=None):
Dan Talayco551befa2010-07-15 17:05:32 -0700585 """
586 Flow match test on single TCP packet
Dan Talaycof6e76c02012-03-23 10:56:12 -0700587 @param egr_ports A single port or list of ports
Dan Talayco551befa2010-07-15 17:05:32 -0700588
589 Run test with packet through switch from ing_port to egr_port
590 See flow_match_test for parameter descriptions
591 """
592
Ed Swierk99a74de2012-08-22 06:40:54 -0700593 if wildcards is None:
594 wildcards = required_wildcards(parent)
Rich Lane9a003812012-10-04 17:17:59 -0700595 logging.info("Pkt match test: " + str(ing_port) + " to " +
Dan Talaycof6e76c02012-03-23 10:56:12 -0700596 str(egr_ports))
Rich Lanee5779d32012-10-05 17:56:04 -0700597 logging.debug(" WC: " + hex(wildcards) + " vlan: " + str(dl_vlan))
Dan Talayco551befa2010-07-15 17:05:32 -0700598 if pkt is None:
599 pkt = simple_tcp_packet(dl_vlan_enable=(dl_vlan >= 0), dl_vlan=dl_vlan)
600
601 request = flow_msg_create(parent, pkt, ing_port=ing_port,
Dan Talaycof6e76c02012-03-23 10:56:12 -0700602 wildcards=wildcards, egr_ports=egr_ports,
Dan Talayco551befa2010-07-15 17:05:32 -0700603 action_list=action_list)
604
605 flow_msg_install(parent, request)
606
Rich Lane9a003812012-10-04 17:17:59 -0700607 logging.debug("Send packet: " + str(ing_port) + " to " +
Dan Talaycof6e76c02012-03-23 10:56:12 -0700608 str(egr_ports))
Dan Talayco551befa2010-07-15 17:05:32 -0700609 parent.dataplane.send(ing_port, str(pkt))
610
611 if exp_pkt is None:
612 exp_pkt = pkt
Dan Talaycoc948d0b2012-03-23 12:17:54 -0700613 receive_pkt_verify(parent, egr_ports, exp_pkt, ing_port)
Dan Talayco551befa2010-07-15 17:05:32 -0700614
Rich Lane89725bb2012-12-03 16:23:27 -0800615def flow_match_test_pktout(parent, ing_port, egr_ports,
616 dl_vlan=-1, pkt=None, exp_pkt=None,
617 action_list=None):
618 """
619 Packet-out test on single TCP packet
620 @param egr_ports A single port or list of ports
621
622 Run test sending packet-out to egr_ports. The goal is to test the actions
623 taken on the packet, not the matching which is of course irrelevant.
624 See flow_match_test for parameter descriptions
625 """
626
627 if pkt is None:
628 pkt = simple_tcp_packet(dl_vlan_enable=(dl_vlan >= 0), dl_vlan=dl_vlan)
629
Rich Lanecd97d3d2013-01-07 18:50:06 -0800630 msg = of10.message.packet_out()
Rich Lane89725bb2012-12-03 16:23:27 -0800631 msg.in_port = ing_port
632 msg.data = str(pkt)
633 if action_list is not None:
634 for act in action_list:
Rich Lanee30455b2013-01-03 16:24:44 -0800635 msg.actions.add(act)
Rich Lane89725bb2012-12-03 16:23:27 -0800636
637 # Set up output action
638 if egr_ports is not None:
639 for egr_port in egr_ports:
Rich Lanecd97d3d2013-01-07 18:50:06 -0800640 act = of10.action.action_output()
Rich Lane89725bb2012-12-03 16:23:27 -0800641 act.port = egr_port
Rich Lanee30455b2013-01-03 16:24:44 -0800642 msg.actions.add(act)
Rich Lane89725bb2012-12-03 16:23:27 -0800643
644 logging.debug(msg.show())
Rich Lane5c3151c2013-01-03 17:15:41 -0800645 parent.controller.message_send(msg)
Rich Lane89725bb2012-12-03 16:23:27 -0800646
647 if exp_pkt is None:
648 exp_pkt = pkt
649 receive_pkt_verify(parent, egr_ports, exp_pkt, ing_port)
650
Dan Talaycof6e76c02012-03-23 10:56:12 -0700651def get_egr_list(parent, of_ports, how_many, exclude_list=[]):
652 """
653 Generate a list of ports avoiding those in the exclude list
Rich Lane9a003812012-10-04 17:17:59 -0700654 @param parent Supplies logging
Dan Talaycof6e76c02012-03-23 10:56:12 -0700655 @param of_ports List of OF port numbers
656 @param how_many Number of ports to be added to the list
657 @param exclude_list List of ports not to be used
658 @returns An empty list if unable to find enough ports
659 """
660
Dan Talaycoc948d0b2012-03-23 12:17:54 -0700661 if how_many == 0:
662 return []
663
Dan Talaycof6e76c02012-03-23 10:56:12 -0700664 count = 0
665 egr_ports = []
666 for egr_idx in range(len(of_ports)):
667 if of_ports[egr_idx] not in exclude_list:
668 egr_ports.append(of_ports[egr_idx])
669 count += 1
670 if count >= how_many:
671 return egr_ports
Rich Lane9a003812012-10-04 17:17:59 -0700672 logging.debug("Could not generate enough egress ports for test")
Dan Talaycof6e76c02012-03-23 10:56:12 -0700673 return []
674
Ed Swierk99a74de2012-08-22 06:40:54 -0700675def flow_match_test(parent, port_map, wildcards=None, dl_vlan=-1, pkt=None,
Rich Lanee5779d32012-10-05 17:56:04 -0700676 exp_pkt=None, action_list=None,
Dan Talaycoc948d0b2012-03-23 12:17:54 -0700677 max_test=0, egr_count=1, ing_port=False):
Dan Talayco551befa2010-07-15 17:05:32 -0700678 """
Rich Lane89725bb2012-12-03 16:23:27 -0800679 Run flow_match_test_port_pair on all port pairs and packet-out
Dan Talayco551befa2010-07-15 17:05:32 -0700680
681 @param max_test If > 0 no more than this number of tests are executed.
682 @param parent Must implement controller, dataplane, assertTrue, assertEqual
Rich Lane9a003812012-10-04 17:17:59 -0700683 and logging
Dan Talayco551befa2010-07-15 17:05:32 -0700684 @param pkt If not None, use this packet for ingress
685 @param wildcards For flow match entry
Dan Talayco79184222010-11-01 12:24:29 -0700686 @param dl_vlan If not -1, and pkt is None, create a pkt w/ VLAN tag
Dan Talayco551befa2010-07-15 17:05:32 -0700687 @param exp_pkt If not None, use this as the expected output pkt; els use pkt
688 @param action_list Additional actions to add to flow mod
Dan Talaycocfa172f2012-03-23 12:03:00 -0700689 @param egr_count Number of egress ports; -1 means get from config w/ dflt 2
Dan Talayco551befa2010-07-15 17:05:32 -0700690 """
Ed Swierk99a74de2012-08-22 06:40:54 -0700691 if wildcards is None:
692 wildcards = required_wildcards(parent)
Dan Talayco551befa2010-07-15 17:05:32 -0700693 of_ports = port_map.keys()
694 of_ports.sort()
695 parent.assertTrue(len(of_ports) > 1, "Not enough ports for test")
696 test_count = 0
697
Dan Talaycocfa172f2012-03-23 12:03:00 -0700698 if egr_count == -1:
Rich Lane2014f9b2012-10-05 15:29:40 -0700699 egr_count = test_param_get('egr_count', default=2)
Dan Talaycocfa172f2012-03-23 12:03:00 -0700700
Dan Talayco551befa2010-07-15 17:05:32 -0700701 for ing_idx in range(len(of_ports)):
702 ingress_port = of_ports[ing_idx]
Dan Talaycof6e76c02012-03-23 10:56:12 -0700703 egr_ports = get_egr_list(parent, of_ports, egr_count,
704 exclude_list=[ingress_port])
Dan Talaycoc948d0b2012-03-23 12:17:54 -0700705 if ing_port:
Rich Lanecd97d3d2013-01-07 18:50:06 -0800706 egr_ports.append(of10.cstruct.OFPP_IN_PORT)
Dan Talaycof6e76c02012-03-23 10:56:12 -0700707 if len(egr_ports) == 0:
708 parent.assertTrue(0, "Failed to generate egress port list")
709
710 flow_match_test_port_pair(parent, ingress_port, egr_ports,
711 wildcards=wildcards, dl_vlan=dl_vlan,
712 pkt=pkt, exp_pkt=exp_pkt,
Rich Lanee5779d32012-10-05 17:56:04 -0700713 action_list=action_list)
Dan Talaycof6e76c02012-03-23 10:56:12 -0700714 test_count += 1
715 if (max_test > 0) and (test_count > max_test):
Rich Lane9a003812012-10-04 17:17:59 -0700716 logging.info("Ran " + str(test_count) + " tests; exiting")
Rich Lane89725bb2012-12-03 16:23:27 -0800717 break
718
Ed Swierk38eea082013-01-02 19:46:20 -0800719 if not test_param_get('pktout_actions', default=True):
720 return
Rich Lane89725bb2012-12-03 16:23:27 -0800721
722 ingress_port = of_ports[0]
723 egr_ports = get_egr_list(parent, of_ports, egr_count,
724 exclude_list=[ingress_port])
725 if ing_port:
Rich Lanecd97d3d2013-01-07 18:50:06 -0800726 egr_ports.append(of10.cstruct.OFPP_IN_PORT)
Rich Lane89725bb2012-12-03 16:23:27 -0800727 flow_match_test_pktout(parent, ingress_port, egr_ports,
728 dl_vlan=dl_vlan,
729 pkt=pkt, exp_pkt=exp_pkt,
730 action_list=action_list)
Dan Talayco551befa2010-07-15 17:05:32 -0700731
Rich Lane2014f9b2012-10-05 15:29:40 -0700732def test_param_get(key, default=None):
Dan Talayco4b2bee62010-07-20 14:10:05 -0700733 """
734 Return value passed via test-params if present
735
Dan Talayco4b2bee62010-07-20 14:10:05 -0700736 @param key The lookup key
737 @param default Default value to use if not found
738
739 If the pair 'key=val' appeared in the string passed to --test-params
740 on the command line, return val (as interpreted by exec). Otherwise
741 return default value.
Dan Talaycof6e76c02012-03-23 10:56:12 -0700742
743 WARNING: TEST PARAMETERS MUST BE PYTHON IDENTIFIERS;
744 eg egr_count, not egr-count.
Dan Talayco4b2bee62010-07-20 14:10:05 -0700745 """
746 try:
Rich Lanecd97d3d2013-01-07 18:50:06 -0800747 exec oftest.config["test_params"]
Dan Talayco4b2bee62010-07-20 14:10:05 -0700748 except:
749 return default
750
751 s = "val = " + str(key)
752 try:
753 exec s
754 return val
755 except:
756 return default
757
758def action_generate(parent, field_to_mod, mod_field_vals):
759 """
760 Create an action to modify the field indicated in field_to_mod
761
762 @param parent Must implement, assertTrue
763 @param field_to_mod The field to modify as a string name
764 @param mod_field_vals Hash of values to use for modified values
765 """
766
767 act = None
768
769 if field_to_mod in ['pktlen']:
770 return None
771
772 if field_to_mod == 'dl_dst':
Rich Lanecd97d3d2013-01-07 18:50:06 -0800773 act = of10.action.action_set_dl_dst()
774 act.dl_addr = of10.parse.parse_mac(mod_field_vals['dl_dst'])
Dan Talayco4b2bee62010-07-20 14:10:05 -0700775 elif field_to_mod == 'dl_src':
Rich Lanecd97d3d2013-01-07 18:50:06 -0800776 act = of10.action.action_set_dl_src()
777 act.dl_addr = of10.parse.parse_mac(mod_field_vals['dl_src'])
Dan Talayco4b2bee62010-07-20 14:10:05 -0700778 elif field_to_mod == 'dl_vlan_enable':
779 if not mod_field_vals['dl_vlan_enable']: # Strip VLAN tag
Rich Lanecd97d3d2013-01-07 18:50:06 -0800780 act = of10.action.action_strip_vlan()
Dan Talayco4b2bee62010-07-20 14:10:05 -0700781 # Add VLAN tag is handled by dl_vlan field
782 # Will return None in this case
783 elif field_to_mod == 'dl_vlan':
Rich Lanecd97d3d2013-01-07 18:50:06 -0800784 act = of10.action.action_set_vlan_vid()
Dan Talayco4b2bee62010-07-20 14:10:05 -0700785 act.vlan_vid = mod_field_vals['dl_vlan']
786 elif field_to_mod == 'dl_vlan_pcp':
Rich Lanecd97d3d2013-01-07 18:50:06 -0800787 act = of10.action.action_set_vlan_pcp()
Dan Talayco4b2bee62010-07-20 14:10:05 -0700788 act.vlan_pcp = mod_field_vals['dl_vlan_pcp']
789 elif field_to_mod == 'ip_src':
Rich Lanecd97d3d2013-01-07 18:50:06 -0800790 act = of10.action.action_set_nw_src()
791 act.nw_addr = of10.parse.parse_ip(mod_field_vals['ip_src'])
Dan Talayco4b2bee62010-07-20 14:10:05 -0700792 elif field_to_mod == 'ip_dst':
Rich Lanecd97d3d2013-01-07 18:50:06 -0800793 act = of10.action.action_set_nw_dst()
794 act.nw_addr = of10.parse.parse_ip(mod_field_vals['ip_dst'])
Dan Talayco4b2bee62010-07-20 14:10:05 -0700795 elif field_to_mod == 'ip_tos':
Rich Lanecd97d3d2013-01-07 18:50:06 -0800796 act = of10.action.action_set_nw_tos()
Dan Talayco4b2bee62010-07-20 14:10:05 -0700797 act.nw_tos = mod_field_vals['ip_tos']
798 elif field_to_mod == 'tcp_sport':
Rich Lanecd97d3d2013-01-07 18:50:06 -0800799 act = of10.action.action_set_tp_src()
Dan Talayco4b2bee62010-07-20 14:10:05 -0700800 act.tp_port = mod_field_vals['tcp_sport']
801 elif field_to_mod == 'tcp_dport':
Rich Lanecd97d3d2013-01-07 18:50:06 -0800802 act = of10.action.action_set_tp_dst()
Dan Talayco4b2bee62010-07-20 14:10:05 -0700803 act.tp_port = mod_field_vals['tcp_dport']
Rich Lane110e0e32012-10-26 16:21:46 -0700804 elif field_to_mod == 'udp_sport':
Rich Lanecd97d3d2013-01-07 18:50:06 -0800805 act = of10.action.action_set_tp_src()
Rich Lane110e0e32012-10-26 16:21:46 -0700806 act.tp_port = mod_field_vals['udp_sport']
807 elif field_to_mod == 'udp_dport':
Rich Lanecd97d3d2013-01-07 18:50:06 -0800808 act = of10.action.action_set_tp_dst()
Rich Lane110e0e32012-10-26 16:21:46 -0700809 act.tp_port = mod_field_vals['udp_dport']
Dan Talayco4b2bee62010-07-20 14:10:05 -0700810 else:
811 parent.assertTrue(0, "Unknown field to modify: " + str(field_to_mod))
812
813 return act
814
815def pkt_action_setup(parent, start_field_vals={}, mod_field_vals={},
Rich Lane110e0e32012-10-26 16:21:46 -0700816 mod_fields=[], tp="tcp", check_test_params=False):
Dan Talayco4b2bee62010-07-20 14:10:05 -0700817 """
818 Set up the ingress and expected packet and action list for a test
819
Rich Lane2014f9b2012-10-05 15:29:40 -0700820 @param parent Must implement assertTrue
Dan Talayco4b2bee62010-07-20 14:10:05 -0700821 @param start_field_values Field values to use for ingress packet (optional)
822 @param mod_field_values Field values to use for modified packet (optional)
823 @param mod_fields The list of fields to be modified by the switch in the test.
824 @params check_test_params If True, will check the parameters vid, add_vlan
825 and strip_vlan from the command line.
826
827 Returns a triple: pkt-to-send, expected-pkt, action-list
828 """
829
830 new_actions = []
831
Dan Talayco4b2bee62010-07-20 14:10:05 -0700832 base_pkt_params = {}
833 base_pkt_params['pktlen'] = 100
834 base_pkt_params['dl_dst'] = '00:DE:F0:12:34:56'
835 base_pkt_params['dl_src'] = '00:23:45:67:89:AB'
836 base_pkt_params['dl_vlan_enable'] = False
837 base_pkt_params['dl_vlan'] = 2
838 base_pkt_params['dl_vlan_pcp'] = 0
839 base_pkt_params['ip_src'] = '192.168.0.1'
840 base_pkt_params['ip_dst'] = '192.168.0.2'
841 base_pkt_params['ip_tos'] = 0
Rich Lane110e0e32012-10-26 16:21:46 -0700842 if tp == "tcp":
843 base_pkt_params['tcp_sport'] = 1234
844 base_pkt_params['tcp_dport'] = 80
845 elif tp == "udp":
846 base_pkt_params['udp_sport'] = 1234
847 base_pkt_params['udp_dport'] = 80
Dan Talayco4b2bee62010-07-20 14:10:05 -0700848 for keyname in start_field_vals.keys():
849 base_pkt_params[keyname] = start_field_vals[keyname]
850
851 mod_pkt_params = {}
852 mod_pkt_params['pktlen'] = 100
853 mod_pkt_params['dl_dst'] = '00:21:0F:ED:CB:A9'
854 mod_pkt_params['dl_src'] = '00:ED:CB:A9:87:65'
855 mod_pkt_params['dl_vlan_enable'] = False
856 mod_pkt_params['dl_vlan'] = 3
857 mod_pkt_params['dl_vlan_pcp'] = 7
858 mod_pkt_params['ip_src'] = '10.20.30.40'
859 mod_pkt_params['ip_dst'] = '50.60.70.80'
860 mod_pkt_params['ip_tos'] = 0xf0
Rich Lane110e0e32012-10-26 16:21:46 -0700861 if tp == "tcp":
862 mod_pkt_params['tcp_sport'] = 4321
863 mod_pkt_params['tcp_dport'] = 8765
864 elif tp == "udp":
865 mod_pkt_params['udp_sport'] = 4321
866 mod_pkt_params['udp_dport'] = 8765
Dan Talayco4b2bee62010-07-20 14:10:05 -0700867 for keyname in mod_field_vals.keys():
868 mod_pkt_params[keyname] = mod_field_vals[keyname]
869
870 # Check for test param modifications
871 strip = False
872 if check_test_params:
Rich Lane2014f9b2012-10-05 15:29:40 -0700873 add_vlan = test_param_get('add_vlan')
874 strip_vlan = test_param_get('strip_vlan')
875 vid = test_param_get('vid')
Dan Talayco4b2bee62010-07-20 14:10:05 -0700876
877 if add_vlan and strip_vlan:
878 parent.assertTrue(0, "Add and strip VLAN both specified")
879
880 if vid:
881 base_pkt_params['dl_vlan_enable'] = True
882 base_pkt_params['dl_vlan'] = vid
883 if 'dl_vlan' in mod_fields:
884 mod_pkt_params['dl_vlan'] = vid + 1
885
886 if add_vlan:
887 base_pkt_params['dl_vlan_enable'] = False
888 mod_pkt_params['dl_vlan_enable'] = True
889 mod_pkt_params['pktlen'] = base_pkt_params['pktlen'] + 4
890 mod_fields.append('pktlen')
891 mod_fields.append('dl_vlan_enable')
892 if 'dl_vlan' not in mod_fields:
893 mod_fields.append('dl_vlan')
894 elif strip_vlan:
895 base_pkt_params['dl_vlan_enable'] = True
896 mod_pkt_params['dl_vlan_enable'] = False
897 mod_pkt_params['pktlen'] = base_pkt_params['pktlen'] - 4
898 mod_fields.append('dl_vlan_enable')
899 mod_fields.append('pktlen')
900
Rich Lane110e0e32012-10-26 16:21:46 -0700901 if tp == "tcp":
902 packet_builder = simple_tcp_packet
903 elif tp == "udp":
904 packet_builder = simple_udp_packet
905 else:
906 raise NotImplementedError("unknown transport protocol %s" % tp)
907
Dan Talayco4b2bee62010-07-20 14:10:05 -0700908 # Build the ingress packet
Rich Lane110e0e32012-10-26 16:21:46 -0700909 ingress_pkt = packet_builder(**base_pkt_params)
Dan Talayco4b2bee62010-07-20 14:10:05 -0700910
911 # Build the expected packet, modifying the indicated fields
912 for item in mod_fields:
913 base_pkt_params[item] = mod_pkt_params[item]
914 act = action_generate(parent, item, mod_pkt_params)
915 if act:
916 new_actions.append(act)
917
Rich Lane110e0e32012-10-26 16:21:46 -0700918 expected_pkt = packet_builder(**base_pkt_params)
Dan Talayco4b2bee62010-07-20 14:10:05 -0700919
920 return (ingress_pkt, expected_pkt, new_actions)
Dan Talayco677c0b72011-08-23 22:53:38 -0700921
922# Generate a simple "drop" flow mod
923# If in_band is true, then only drop from first test port
924def flow_mod_gen(port_map, in_band):
Rich Lanecd97d3d2013-01-07 18:50:06 -0800925 request = of10.message.flow_mod()
926 request.match.wildcards = of10.cstruct.OFPFW_ALL
Dan Talayco677c0b72011-08-23 22:53:38 -0700927 if in_band:
Rich Lanecd97d3d2013-01-07 18:50:06 -0800928 request.match.wildcards = of10.cstruct.OFPFW_ALL - of10.cstruct.OFPFW_IN_PORT
Dan Talayco677c0b72011-08-23 22:53:38 -0700929 for of_port, ifname in port_map.items(): # Grab first port
930 break
931 request.match.in_port = of_port
932 request.buffer_id = 0xffffffff
933 return request
Dan Talaycoba3745c2010-07-21 21:51:08 -0700934
935def skip_message_emit(parent, s):
936 """
937 Print out a 'skipped' message to stderr
938
939 @param s The string to print out to the log file
Dan Talaycoba3745c2010-07-21 21:51:08 -0700940 """
941 global skipped_test_count
942
943 skipped_test_count += 1
Rich Lane9a003812012-10-04 17:17:59 -0700944 logging.info("Skipping: " + s)
Rich Lanecd97d3d2013-01-07 18:50:06 -0800945 if oftest.config["dbg_level"] < logging.WARNING:
Dan Talaycoba3745c2010-07-21 21:51:08 -0700946 sys.stderr.write("(skipped) ")
947 else:
948 sys.stderr.write("(S)")
Dan Talayco677c0b72011-08-23 22:53:38 -0700949
Dan Talayco8a64e332012-03-28 14:53:20 -0700950
951def all_stats_get(parent):
952 """
953 Get the aggregate stats for all flows in the table
954 @param parent Test instance with controller connection and assert
955 @returns dict with keys flows, packets, bytes, active (flows),
956 lookups, matched
957 """
Rich Lanecd97d3d2013-01-07 18:50:06 -0800958 stat_req = of10.message.aggregate_stats_request()
959 stat_req.match = of10.cstruct.ofp_match()
960 stat_req.match.wildcards = of10.cstruct.OFPFW_ALL
Dan Talayco8a64e332012-03-28 14:53:20 -0700961 stat_req.table_id = 0xff
Rich Lanecd97d3d2013-01-07 18:50:06 -0800962 stat_req.out_port = of10.cstruct.OFPP_NONE
Dan Talayco8a64e332012-03-28 14:53:20 -0700963
964 rv = {}
965
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700966 (reply, pkt) = parent.controller.transact(stat_req)
Dan Talayco8a64e332012-03-28 14:53:20 -0700967 parent.assertTrue(len(reply.stats) == 1, "Did not receive flow stats reply")
968
969 for obj in reply.stats:
970 (rv["flows"], rv["packets"], rv["bytes"]) = (obj.flow_count,
971 obj.packet_count, obj.byte_count)
972 break
973
Rich Lanecd97d3d2013-01-07 18:50:06 -0800974 request = of10.message.table_stats_request()
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700975 (reply , pkt) = parent.controller.transact(request)
Dan Talayco8a64e332012-03-28 14:53:20 -0700976
977
978 (rv["active"], rv["lookups"], rv["matched"]) = (0,0,0)
979 for obj in reply.stats:
980 rv["active"] += obj.active_count
981 rv["lookups"] += obj.lookup_count
982 rv["matched"] += obj.matched_count
983
984 return rv
Dan Talayco2baf8b52012-03-30 09:55:42 -0700985
986FILTER=''.join([(len(repr(chr(x)))==3) and chr(x) or '.'
987 for x in range(256)])
988
989def hex_dump_buffer(src, length=16):
990 """
991 Convert src to a hex dump string and return the string
992 @param src The source buffer
993 @param length The number of bytes shown in each line
994 @returns A string showing the hex dump
995 """
Dan Talaycoc516fa02012-04-12 22:28:43 -0700996 result = ["\n"]
Dan Talayco2baf8b52012-03-30 09:55:42 -0700997 for i in xrange(0, len(src), length):
998 chars = src[i:i+length]
999 hex = ' '.join(["%02x" % ord(x) for x in chars])
1000 printable = ''.join(["%s" % ((ord(x) <= 127 and
1001 FILTER[ord(x)]) or '.') for x in chars])
1002 result.append("%04x %-*s %s\n" % (i, length*3, hex, printable))
1003 return ''.join(result)
1004
1005def format_packet(pkt):
1006 return "Packet length %d \n%s" % (len(str(pkt)),
1007 hex_dump_buffer(str(pkt)))
Rich Lane5d7e89a2012-10-26 16:43:13 -07001008
1009def inspect_packet(pkt):
1010 """
1011 Wrapper around scapy's show() method.
1012 @returns A string showing the dissected packet.
1013 """
1014 from cStringIO import StringIO
1015 out = None
1016 backup = sys.stdout
1017 try:
1018 sys.stdout = StringIO()
1019 pkt.show2()
1020 out = sys.stdout.getvalue()
1021 sys.stdout.close()
1022 finally:
1023 sys.stdout = backup
1024 return out
Rich Lane0a4f6372013-01-02 14:40:22 -08001025
1026def nonstandard(cls):
1027 """
Rich Lanecc45b8e2013-01-02 15:55:02 -08001028 Testcase decorator that marks the test as being non-standard.
1029 These tests are not automatically added to the "standard" group.
Rich Lane0a4f6372013-01-02 14:40:22 -08001030 """
Rich Lanecc45b8e2013-01-02 15:55:02 -08001031 cls._nonstandard = True
Rich Lane0a4f6372013-01-02 14:40:22 -08001032 return cls
1033
1034def disabled(cls):
1035 """
Rich Lanecc45b8e2013-01-02 15:55:02 -08001036 Testcase decorator that marks the test as being disabled.
1037 These tests are not automatically added to the "standard" group or
1038 their module's group.
Rich Lane0a4f6372013-01-02 14:40:22 -08001039 """
Rich Lanecc45b8e2013-01-02 15:55:02 -08001040 cls._disabled = True
Rich Lane0a4f6372013-01-02 14:40:22 -08001041 return cls
Rich Lane97e99652013-01-02 17:23:20 -08001042
1043def group(name):
1044 """
1045 Testcase decorator that adds the test to a group.
1046 """
1047 def fn(cls):
1048 if not hasattr(cls, "_groups"):
1049 cls._groups = []
1050 cls._groups.append(name)
1051 return cls
1052 return fn