blob: 0edcfb294712f1cf577ffb2c5a152406413beefc [file] [log] [blame]
Dan Talaycod2ca1032010-03-10 14:40:26 -08001import sys
Dan Talayco92c99122010-06-03 13:53:18 -07002import copy
Rich Lane6242d9f2013-01-06 17:35:39 -08003import logging
4import types
5import time
Rich Lane5a9a1922013-01-11 14:29:30 -08006import re
Dan Talaycod2ca1032010-03-10 14:40:26 -08007
8try:
9 import scapy.all as scapy
10except:
11 try:
12 import scapy as scapy
13 except:
14 sys.exit("Need to install scapy for packet parsing")
Dan Talayco41eae8b2010-03-10 13:57:06 -080015
Rich Lanecd97d3d2013-01-07 18:50:06 -080016import oftest
17import oftest.controller
18import oftest.dataplane
19import of10.cstruct
20import of10.message
21import of10.action
22import of10.parse
Dan Talaycoc901f4d2010-03-07 21:55:45 -080023
Dan Talaycoba3745c2010-07-21 21:51:08 -070024global skipped_test_count
25skipped_test_count = 0
26
Rich Lane7744e112013-01-11 17:23:57 -080027_import_blacklist = set(locals().keys())
28
Dan Talayco551befa2010-07-15 17:05:32 -070029# Some useful defines
30IP_ETHERTYPE = 0x800
31TCP_PROTOCOL = 0x6
32UDP_PROTOCOL = 0x11
33
Jeffrey Townsend5cb7ed32012-08-17 18:11:01 +000034MINSIZE = 0
35
Rich Lane9a003812012-10-04 17:17:59 -070036def delete_all_flows(ctrl):
Dan Talayco41eae8b2010-03-10 13:57:06 -080037 """
38 Delete all flows on the switch
39 @param ctrl The controller object for the test
Dan Talayco41eae8b2010-03-10 13:57:06 -080040 """
41
Rich Lane9a003812012-10-04 17:17:59 -070042 logging.info("Deleting all flows")
Rich Lanecd97d3d2013-01-07 18:50:06 -080043 msg = of10.message.flow_mod()
44 msg.match.wildcards = of10.cstruct.OFPFW_ALL
45 msg.out_port = of10.cstruct.OFPP_NONE
46 msg.command = of10.cstruct.OFPFC_DELETE
Dan Talaycoc901f4d2010-03-07 21:55:45 -080047 msg.buffer_id = 0xffffffff
Rich Lane5c3151c2013-01-03 17:15:41 -080048 ctrl.message_send(msg)
Rich Lane32bf9482013-01-03 17:26:30 -080049 return 0 # for backwards compatibility
Dan Talayco41eae8b2010-03-10 13:57:06 -080050
Ed Swierk99a74de2012-08-22 06:40:54 -070051def required_wildcards(parent):
Rich Lane2014f9b2012-10-05 15:29:40 -070052 w = test_param_get('required_wildcards', default='default')
Ed Swierk99a74de2012-08-22 06:40:54 -070053 if w == 'l3-l4':
Rich Lanecd97d3d2013-01-07 18:50:06 -080054 return (of10.cstruct.OFPFW_NW_SRC_ALL | of10.cstruct.OFPFW_NW_DST_ALL | of10.cstruct.OFPFW_NW_TOS
55 | of10.cstruct.OFPFW_NW_PROTO | of10.cstruct.OFPFW_TP_SRC | of10.cstruct.OFPFW_TP_DST)
Ed Swierk99a74de2012-08-22 06:40:54 -070056 else:
57 return 0
58
Dan Talayco41eae8b2010-03-10 13:57:06 -080059def simple_tcp_packet(pktlen=100,
60 dl_dst='00:01:02:03:04:05',
61 dl_src='00:06:07:08:09:0a',
Tatsuya Yabe460321e2010-05-25 17:50:49 -070062 dl_vlan_enable=False,
63 dl_vlan=0,
64 dl_vlan_pcp=0,
Dan Talayco551befa2010-07-15 17:05:32 -070065 dl_vlan_cfi=0,
Dan Talayco41eae8b2010-03-10 13:57:06 -080066 ip_src='192.168.0.1',
67 ip_dst='192.168.0.2',
Tatsuya Yabe460321e2010-05-25 17:50:49 -070068 ip_tos=0,
Gregor Maier9cc93342013-01-29 16:55:28 -080069 ip_ttl=64,
Dan Talayco41eae8b2010-03-10 13:57:06 -080070 tcp_sport=1234,
Christian Dickmann8b59b4b2012-09-23 16:48:30 -070071 tcp_dport=80,
72 ip_ihl=None,
73 ip_options=False
Dan Talayco41eae8b2010-03-10 13:57:06 -080074 ):
75 """
76 Return a simple dataplane TCP packet
77
78 Supports a few parameters:
79 @param len Length of packet in bytes w/o CRC
80 @param dl_dst Destinatino MAC
81 @param dl_src Source MAC
Tatsuya Yabe460321e2010-05-25 17:50:49 -070082 @param dl_vlan_enable True if the packet is with vlan, False otherwise
83 @param dl_vlan VLAN ID
84 @param dl_vlan_pcp VLAN priority
Dan Talayco41eae8b2010-03-10 13:57:06 -080085 @param ip_src IP source
86 @param ip_dst IP destination
Tatsuya Yabe460321e2010-05-25 17:50:49 -070087 @param ip_tos IP ToS
Gregor Maier9cc93342013-01-29 16:55:28 -080088 @param ip_ttl IP TTL
Dan Talayco41eae8b2010-03-10 13:57:06 -080089 @param tcp_dport TCP destination port
90 @param ip_sport TCP source port
91
92 Generates a simple TCP request. Users
93 shouldn't assume anything about this packet other than that
94 it is a valid ethernet/IP/TCP frame.
95 """
Jeffrey Townsend5cb7ed32012-08-17 18:11:01 +000096
97 if MINSIZE > pktlen:
98 pktlen = MINSIZE
99
Dan Talayco551befa2010-07-15 17:05:32 -0700100 # Note Dot1Q.id is really CFI
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800101 if (dl_vlan_enable):
Tatsuya Yabe460321e2010-05-25 17:50:49 -0700102 pkt = scapy.Ether(dst=dl_dst, src=dl_src)/ \
Dan Talayco551befa2010-07-15 17:05:32 -0700103 scapy.Dot1Q(prio=dl_vlan_pcp, id=dl_vlan_cfi, vlan=dl_vlan)/ \
Gregor Maier9cc93342013-01-29 16:55:28 -0800104 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ttl=ip_ttl, ihl=ip_ihl)/ \
Tatsuya Yabe460321e2010-05-25 17:50:49 -0700105 scapy.TCP(sport=tcp_sport, dport=tcp_dport)
106 else:
Christian Dickmann8b59b4b2012-09-23 16:48:30 -0700107 if not ip_options:
108 pkt = scapy.Ether(dst=dl_dst, src=dl_src)/ \
Gregor Maier9cc93342013-01-29 16:55:28 -0800109 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ttl=ip_ttl, ihl=ip_ihl)/ \
Christian Dickmann8b59b4b2012-09-23 16:48:30 -0700110 scapy.TCP(sport=tcp_sport, dport=tcp_dport)
111 else:
112 pkt = scapy.Ether(dst=dl_dst, src=dl_src)/ \
Gregor Maier9cc93342013-01-29 16:55:28 -0800113 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ttl=ip_ttl, ihl=ip_ihl, options=ip_options)/ \
Christian Dickmann8b59b4b2012-09-23 16:48:30 -0700114 scapy.TCP(sport=tcp_sport, dport=tcp_dport)
Tatsuya Yabe460321e2010-05-25 17:50:49 -0700115
Dan Talayco41eae8b2010-03-10 13:57:06 -0800116 pkt = pkt/("D" * (pktlen - len(pkt)))
117
118 return pkt
119
Rich Lane6ee7bea2012-10-26 16:19:29 -0700120def simple_udp_packet(pktlen=100,
121 dl_dst='00:01:02:03:04:05',
122 dl_src='00:06:07:08:09:0a',
123 dl_vlan_enable=False,
124 dl_vlan=0,
125 dl_vlan_pcp=0,
126 dl_vlan_cfi=0,
127 ip_src='192.168.0.1',
128 ip_dst='192.168.0.2',
129 ip_tos=0,
Gregor Maier9cc93342013-01-29 16:55:28 -0800130 ip_ttl=64,
Rich Lane6ee7bea2012-10-26 16:19:29 -0700131 udp_sport=1234,
132 udp_dport=80,
133 ip_ihl=None,
134 ip_options=False
135 ):
136 """
137 Return a simple dataplane UDP packet
138
139 Supports a few parameters:
140 @param len Length of packet in bytes w/o CRC
141 @param dl_dst Destination MAC
142 @param dl_src Source MAC
143 @param dl_vlan_enable True if the packet is with vlan, False otherwise
144 @param dl_vlan VLAN ID
145 @param dl_vlan_pcp VLAN priority
146 @param ip_src IP source
147 @param ip_dst IP destination
148 @param ip_tos IP ToS
Gregor Maier9cc93342013-01-29 16:55:28 -0800149 @param ip_ttl IP TTL
Rich Lane6ee7bea2012-10-26 16:19:29 -0700150 @param udp_dport UDP destination port
151 @param udp_sport UDP source port
152
153 Generates a simple UDP packet. Users shouldn't assume anything about
154 this packet other than that it is a valid ethernet/IP/UDP frame.
155 """
156
157 if MINSIZE > pktlen:
158 pktlen = MINSIZE
159
160 # Note Dot1Q.id is really CFI
161 if (dl_vlan_enable):
162 pkt = scapy.Ether(dst=dl_dst, src=dl_src)/ \
163 scapy.Dot1Q(prio=dl_vlan_pcp, id=dl_vlan_cfi, vlan=dl_vlan)/ \
Gregor Maier9cc93342013-01-29 16:55:28 -0800164 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ttl=ip_ttl, ihl=ip_ihl)/ \
Rich Lane6ee7bea2012-10-26 16:19:29 -0700165 scapy.UDP(sport=udp_sport, dport=udp_dport)
166 else:
167 if not ip_options:
168 pkt = scapy.Ether(dst=dl_dst, src=dl_src)/ \
Gregor Maier9cc93342013-01-29 16:55:28 -0800169 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ttl=ip_ttl, ihl=ip_ihl)/ \
Rich Lane6ee7bea2012-10-26 16:19:29 -0700170 scapy.UDP(sport=udp_sport, dport=udp_dport)
171 else:
172 pkt = scapy.Ether(dst=dl_dst, src=dl_src)/ \
Gregor Maier9cc93342013-01-29 16:55:28 -0800173 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ttl=ip_ttl, ihl=ip_ihl, options=ip_options)/ \
Rich Lane6ee7bea2012-10-26 16:19:29 -0700174 scapy.UDP(sport=udp_sport, dport=udp_dport)
175
176 pkt = pkt/("D" * (pktlen - len(pkt)))
177
178 return pkt
179
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700180def simple_icmp_packet(pktlen=60,
181 dl_dst='00:01:02:03:04:05',
182 dl_src='00:06:07:08:09:0a',
183 dl_vlan_enable=False,
184 dl_vlan=0,
185 dl_vlan_pcp=0,
186 ip_src='192.168.0.1',
187 ip_dst='192.168.0.2',
188 ip_tos=0,
Gregor Maier9cc93342013-01-29 16:55:28 -0800189 ip_ttl=64,
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700190 icmp_type=8,
191 icmp_code=0
192 ):
193 """
194 Return a simple ICMP packet
195
196 Supports a few parameters:
197 @param len Length of packet in bytes w/o CRC
198 @param dl_dst Destinatino MAC
199 @param dl_src Source MAC
200 @param dl_vlan_enable True if the packet is with vlan, False otherwise
201 @param dl_vlan VLAN ID
202 @param dl_vlan_pcp VLAN priority
203 @param ip_src IP source
204 @param ip_dst IP destination
205 @param ip_tos IP ToS
Gregor Maier9cc93342013-01-29 16:55:28 -0800206 @param ip_ttl IP TTL
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700207 @param icmp_type ICMP type
208 @param icmp_code ICMP code
209
210 Generates a simple ICMP ECHO REQUEST. Users
211 shouldn't assume anything about this packet other than that
212 it is a valid ethernet/ICMP frame.
213 """
Jeffrey Townsend5cb7ed32012-08-17 18:11:01 +0000214
215 if MINSIZE > pktlen:
216 pktlen = MINSIZE
217
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700218 if (dl_vlan_enable):
219 pkt = scapy.Ether(dst=dl_dst, src=dl_src)/ \
220 scapy.Dot1Q(prio=dl_vlan_pcp, id=0, vlan=dl_vlan)/ \
Gregor Maier9cc93342013-01-29 16:55:28 -0800221 scapy.IP(src=ip_src, dst=ip_dst, ttl=ip_ttl, tos=ip_tos)/ \
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700222 scapy.ICMP(type=icmp_type, code=icmp_code)
223 else:
224 pkt = scapy.Ether(dst=dl_dst, src=dl_src)/ \
Gregor Maier9cc93342013-01-29 16:55:28 -0800225 scapy.IP(src=ip_src, dst=ip_dst, ttl=ip_ttl, tos=ip_tos)/ \
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700226 scapy.ICMP(type=icmp_type, code=icmp_code)
227
228 pkt = pkt/("0" * (pktlen - len(pkt)))
229
230 return pkt
231
Shudong Zhouc7562b12013-02-06 01:12:18 -0800232def simple_arp_packet(pktlen=60,
233 dl_dst='ff:ff:ff:ff:ff:ff',
234 dl_src='00:06:07:08:09:0a',
235 arp_op=1,
236 ip_snd='192.168.0.1',
237 ip_tgt='192.168.0.2',
238 hw_snd='00:06:07:08:09:0a',
239 hw_tgt='00:00:00:00:00:00',
240 ):
241 """
242 Return a simple ARP packet
243
244 Supports a few parameters:
245 @param len Length of packet in bytes w/o CRC
246 @param dl_dst Destinatino MAC
247 @param dl_src Source MAC
248 @param arp_op Operation (1=request, 2=reply)
249 @param ip_snd Sender IP
250 @param ip_tgt Target IP
251 @param hw_snd Sender hardware address
252 @param hw_tgt Target hardware address
253
254 Generates a simple ARP REQUEST. Users
255 shouldn't assume anything about this packet other than that
256 it is a valid ethernet/ARP frame.
257 """
258
259 if MINSIZE > pktlen:
260 pktlen = MINSIZE
261
262 pkt = scapy.Ether(dst=dl_dst, src=dl_src)/ \
263 scapy.ARP(hwsrc=hw_snd, hwdst=hw_tgt, pdst=ip_tgt, psrc=ip_snd, op=arp_op)
264
265 pkt = pkt/("0" * (pktlen - len(pkt)))
266
267 return pkt
268
Ed Swierk0aeff8c2012-03-23 20:27:18 -0700269def simple_eth_packet(pktlen=60,
270 dl_dst='00:01:02:03:04:05',
271 dl_src='01:80:c2:00:00:00',
272 dl_type=0x88cc):
Jeffrey Townsend5cb7ed32012-08-17 18:11:01 +0000273
274 if MINSIZE > pktlen:
275 pktlen = MINSIZE
276
Ed Swierk0aeff8c2012-03-23 20:27:18 -0700277 pkt = scapy.Ether(dst=dl_dst, src=dl_src, type=dl_type)
278
279 pkt = pkt/("0" * (pktlen - len(pkt)))
280
281 return pkt
282
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800283def qinq_tcp_packet(pktlen=100,
284 dl_dst='00:01:02:03:04:05',
285 dl_src='00:06:07:08:09:0a',
286 dl_vlan_outer=20,
287 dl_vlan_pcp_outer=0,
288 dl_vlan_cfi_outer=0,
289 dl_vlan=10,
290 dl_vlan_pcp=0,
291 dl_vlan_cfi=0,
292 ip_src='192.168.0.1',
293 ip_dst='192.168.0.2',
294 ip_tos=0,
Gregor Maier9cc93342013-01-29 16:55:28 -0800295 ip_ttl=64,
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800296 tcp_sport=1234,
297 tcp_dport=80,
298 ip_ihl=None,
299 ip_options=False
300 ):
301 """
302 Return a doubly tagged dataplane TCP packet
303
304 Supports a few parameters:
305 @param len Length of packet in bytes w/o CRC
306 @param dl_dst Destinatino MAC
307 @param dl_src Source MAC
308 @param dl_vlan_outer Outer VLAN ID
309 @param dl_vlan_pcp_outer Outer VLAN priority
310 @param dl_vlan_cfi_outer Outer VLAN cfi bit
311 @param dl_vlan Inner VLAN ID
312 @param dl_vlan_pcp VLAN priority
313 @param dl_vlan_cfi VLAN cfi bit
314 @param ip_src IP source
315 @param ip_dst IP destination
316 @param ip_tos IP ToS
317 @param tcp_dport TCP destination port
318 @param ip_sport TCP source port
319
320 Generates a TCP request. Users
321 shouldn't assume anything about this packet other than that
322 it is a valid ethernet/IP/TCP frame.
323 """
324
325 if MINSIZE > pktlen:
326 pktlen = MINSIZE
327
328 # Note Dot1Q.id is really CFI
329 pkt = scapy.Ether(dst=dl_dst, src=dl_src)/ \
330 scapy.Dot1Q(prio=dl_vlan_pcp_outer, id=dl_vlan_cfi_outer, vlan=dl_vlan_outer)/ \
331 scapy.Dot1Q(prio=dl_vlan_pcp, id=dl_vlan_cfi, vlan=dl_vlan)/ \
Gregor Maier9cc93342013-01-29 16:55:28 -0800332 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ttl=ip_ttl, ihl=ip_ihl)/ \
Shudong Zhou43ee54c2012-12-13 15:52:37 -0800333 scapy.TCP(sport=tcp_sport, dport=tcp_dport)
334
335 pkt = pkt/("D" * (pktlen - len(pkt)))
336
337 return pkt
338
Shudong Zhoub7f12462012-11-20 13:01:12 -0800339def do_barrier(ctrl, timeout=-1):
Dan Talayco0fc08bd2012-04-09 16:56:18 -0700340 """
341 Do a barrier command
342 Return 0 on success, -1 on error
343 """
Rich Lanecd97d3d2013-01-07 18:50:06 -0800344 b = of10.message.barrier_request()
Shudong Zhoub7f12462012-11-20 13:01:12 -0800345 (resp, pkt) = ctrl.transact(b, timeout=timeout)
Rich Lane3a261d52013-01-03 17:45:08 -0800346 if resp is None:
347 raise AssertionError("barrier failed")
Dan Talaycof6b94832012-04-12 21:50:57 -0700348 # We'll trust the transaction processing in the controller that xid matched
Rich Lane3a261d52013-01-03 17:45:08 -0800349 return 0 # for backwards compatibility
Dan Talayco92c99122010-06-03 13:53:18 -0700350
Rich Lane9a003812012-10-04 17:17:59 -0700351def port_config_get(controller, port_no):
Dan Talayco92c99122010-06-03 13:53:18 -0700352 """
353 Get a port's configuration
354
355 Gets the switch feature configuration and grabs one port's
356 configuration
357
358 @returns (hwaddr, config, advert) The hwaddress, configuration and
359 advertised values
360 """
Rich Lanecd97d3d2013-01-07 18:50:06 -0800361 request = of10.message.features_request()
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700362 reply, pkt = controller.transact(request)
Rich Lane9a003812012-10-04 17:17:59 -0700363 logging.debug(reply.show())
Dan Talayco92c99122010-06-03 13:53:18 -0700364 if reply is None:
Rich Lane9a003812012-10-04 17:17:59 -0700365 logging.warn("Get feature request failed")
Dan Talayco92c99122010-06-03 13:53:18 -0700366 return None, None, None
367 for idx in range(len(reply.ports)):
368 if reply.ports[idx].port_no == port_no:
369 return (reply.ports[idx].hw_addr, reply.ports[idx].config,
370 reply.ports[idx].advertised)
371
Rich Lane9a003812012-10-04 17:17:59 -0700372 logging.warn("Did not find port number for port config")
Dan Talayco92c99122010-06-03 13:53:18 -0700373 return None, None, None
374
Rich Lane9a003812012-10-04 17:17:59 -0700375def port_config_set(controller, port_no, config, mask):
Dan Talayco92c99122010-06-03 13:53:18 -0700376 """
377 Set the port configuration according the given parameters
378
379 Gets the switch feature configuration and updates one port's
380 configuration value according to config and mask
381 """
Rich Lane9a003812012-10-04 17:17:59 -0700382 logging.info("Setting port " + str(port_no) + " to config " + str(config))
Rich Lanecd97d3d2013-01-07 18:50:06 -0800383 request = of10.message.features_request()
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700384 reply, pkt = controller.transact(request)
Dan Talayco92c99122010-06-03 13:53:18 -0700385 if reply is None:
386 return -1
Rich Lane9a003812012-10-04 17:17:59 -0700387 logging.debug(reply.show())
Ed Swierk8d84ce02012-12-27 15:36:48 -0800388 p = None
Dan Talayco92c99122010-06-03 13:53:18 -0700389 for idx in range(len(reply.ports)):
390 if reply.ports[idx].port_no == port_no:
Ed Swierk8d84ce02012-12-27 15:36:48 -0800391 p = reply.ports[idx]
Dan Talayco92c99122010-06-03 13:53:18 -0700392 break
Rich Lanecd97d3d2013-01-07 18:50:06 -0800393 mod = of10.message.port_mod()
Dan Talayco92c99122010-06-03 13:53:18 -0700394 mod.port_no = port_no
Ed Swierk8d84ce02012-12-27 15:36:48 -0800395 if p:
396 mod.hw_addr = p.hw_addr
Dan Talayco92c99122010-06-03 13:53:18 -0700397 mod.config = config
398 mod.mask = mask
Ed Swierk8d84ce02012-12-27 15:36:48 -0800399 if p:
400 mod.advertise = p.advertised
Rich Lane5c3151c2013-01-03 17:15:41 -0800401 controller.message_send(mod)
402 return 0
Dan Talayco92c99122010-06-03 13:53:18 -0700403
Rich Lane2014f9b2012-10-05 15:29:40 -0700404def receive_pkt_check(dp, pkt, yes_ports, no_ports, assert_if):
Dan Talayco92c99122010-06-03 13:53:18 -0700405 """
406 Check for proper receive packets across all ports
Ken Chiang1bf01602012-04-04 10:48:23 -0700407 @param dp The dataplane object
Dan Talayco92c99122010-06-03 13:53:18 -0700408 @param pkt Expected packet; may be None if yes_ports is empty
409 @param yes_ports Set or list of ports that should recieve packet
410 @param no_ports Set or list of ports that should not receive packet
411 @param assert_if Object that implements assertXXX
412 """
Rich Lane91765672012-12-06 16:33:04 -0800413
414 # Wait this long for packets that we don't expect to receive.
415 # 100ms is (rarely) too short for positive tests on slow
416 # switches but is definitely not too short for a negative test.
417 negative_timeout = 0.1
418
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700419 exp_pkt_arg = None
Rich Lanecd97d3d2013-01-07 18:50:06 -0800420 if oftest.config["relax"]:
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700421 exp_pkt_arg = pkt
422
Dan Talayco92c99122010-06-03 13:53:18 -0700423 for ofport in yes_ports:
Rich Lane9a003812012-10-04 17:17:59 -0700424 logging.debug("Checking for pkt on port " + str(ofport))
Ken Chiang1bf01602012-04-04 10:48:23 -0700425 (rcv_port, rcv_pkt, pkt_time) = dp.poll(
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700426 port_number=ofport, exp_pkt=exp_pkt_arg)
Dan Talayco92c99122010-06-03 13:53:18 -0700427 assert_if.assertTrue(rcv_pkt is not None,
428 "Did not receive pkt on " + str(ofport))
Rich Lanecd97d3d2013-01-07 18:50:06 -0800429 if not oftest.dataplane.match_exp_pkt(pkt, rcv_pkt):
Rich Lane3c266832013-01-29 18:29:15 -0800430 logging.debug("Expected %s" % format_packet(pkt))
431 logging.debug("Received %s" % format_packet(rcv_pkt))
Rich Lanecd97d3d2013-01-07 18:50:06 -0800432 assert_if.assertTrue(oftest.dataplane.match_exp_pkt(pkt, rcv_pkt),
Rich Lane3c266832013-01-29 18:29:15 -0800433 "Received packet does not match expected packet " +
Ken Chiang1bf01602012-04-04 10:48:23 -0700434 "on port " + str(ofport))
Dan Talayco73f84012012-10-02 09:23:18 -0700435 if len(no_ports) > 0:
Rich Lane91765672012-12-06 16:33:04 -0800436 time.sleep(negative_timeout)
Dan Talayco92c99122010-06-03 13:53:18 -0700437 for ofport in no_ports:
Rich Lane9a003812012-10-04 17:17:59 -0700438 logging.debug("Negative check for pkt on port " + str(ofport))
Ken Chiang1bf01602012-04-04 10:48:23 -0700439 (rcv_port, rcv_pkt, pkt_time) = dp.poll(
Rich Lane91765672012-12-06 16:33:04 -0800440 port_number=ofport, timeout=0, exp_pkt=exp_pkt_arg)
Dan Talayco92c99122010-06-03 13:53:18 -0700441 assert_if.assertTrue(rcv_pkt is None,
442 "Unexpected pkt on port " + str(ofport))
Dan Talayco551befa2010-07-15 17:05:32 -0700443
444
Dan Talaycoc948d0b2012-03-23 12:17:54 -0700445def receive_pkt_verify(parent, egr_ports, exp_pkt, ing_port):
Dan Talayco551befa2010-07-15 17:05:32 -0700446 """
447 Receive a packet and verify it matches an expected value
Dan Talaycof6e76c02012-03-23 10:56:12 -0700448 @param egr_port A single port or list of ports
Dan Talayco551befa2010-07-15 17:05:32 -0700449
450 parent must implement dataplane, assertTrue and assertEqual
451 """
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700452 exp_pkt_arg = None
Rich Lanecd97d3d2013-01-07 18:50:06 -0800453 if oftest.config["relax"]:
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700454 exp_pkt_arg = exp_pkt
455
Dan Talaycof6e76c02012-03-23 10:56:12 -0700456 if type(egr_ports) == type([]):
457 egr_port_list = egr_ports
458 else:
459 egr_port_list = [egr_ports]
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700460
Dan Talaycof6e76c02012-03-23 10:56:12 -0700461 # Expect a packet from each port on egr port list
462 for egr_port in egr_port_list:
Dan Talaycod8ae7582012-03-23 12:24:56 -0700463 check_port = egr_port
Rich Lanecd97d3d2013-01-07 18:50:06 -0800464 if egr_port == of10.cstruct.OFPP_IN_PORT:
Dan Talaycod8ae7582012-03-23 12:24:56 -0700465 check_port = ing_port
Dan Talaycof6e76c02012-03-23 10:56:12 -0700466 (rcv_port, rcv_pkt, pkt_time) = parent.dataplane.poll(
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700467 port_number=check_port, exp_pkt=exp_pkt_arg)
Dan Talayco551befa2010-07-15 17:05:32 -0700468
Dan Talaycof6e76c02012-03-23 10:56:12 -0700469 if rcv_pkt is None:
Rich Lane9a003812012-10-04 17:17:59 -0700470 logging.error("ERROR: No packet received from " +
Dan Talaycod8ae7582012-03-23 12:24:56 -0700471 str(check_port))
Dan Talayco551befa2010-07-15 17:05:32 -0700472
Dan Talaycof6e76c02012-03-23 10:56:12 -0700473 parent.assertTrue(rcv_pkt is not None,
Dan Talaycod8ae7582012-03-23 12:24:56 -0700474 "Did not receive packet port " + str(check_port))
Rich Lane9a003812012-10-04 17:17:59 -0700475 logging.debug("Packet len " + str(len(rcv_pkt)) + " in on " +
Dan Talaycof6e76c02012-03-23 10:56:12 -0700476 str(rcv_port))
477
478 if str(exp_pkt) != str(rcv_pkt):
Rich Lane9a003812012-10-04 17:17:59 -0700479 logging.error("ERROR: Packet match failed.")
480 logging.debug("Expected len " + str(len(exp_pkt)) + ": "
Dan Talaycof6e76c02012-03-23 10:56:12 -0700481 + str(exp_pkt).encode('hex'))
Rich Lane9a003812012-10-04 17:17:59 -0700482 logging.debug("Received len " + str(len(rcv_pkt)) + ": "
Dan Talaycof6e76c02012-03-23 10:56:12 -0700483 + str(rcv_pkt).encode('hex'))
Rich Lane5d7e89a2012-10-26 16:43:13 -0700484 logging.debug("Expected packet: " + inspect_packet(scapy.Ether(str(exp_pkt))))
485 logging.debug("Received packet: " + inspect_packet(scapy.Ether(str(rcv_pkt))))
Dan Talaycof6e76c02012-03-23 10:56:12 -0700486 parent.assertEqual(str(exp_pkt), str(rcv_pkt),
Dan Talaycod8ae7582012-03-23 12:24:56 -0700487 "Packet match error on port " + str(check_port))
Dan Talaycof6e76c02012-03-23 10:56:12 -0700488
Dan Talayco551befa2010-07-15 17:05:32 -0700489def match_verify(parent, req_match, res_match):
490 """
491 Verify flow matches agree; if they disagree, report where
492
493 parent must implement assertEqual
494 Use str() to ensure content is compared and not pointers
495 """
496
497 parent.assertEqual(req_match.wildcards, res_match.wildcards,
498 'Match failed: wildcards: ' + hex(req_match.wildcards) +
499 " != " + hex(res_match.wildcards))
500 parent.assertEqual(req_match.in_port, res_match.in_port,
501 'Match failed: in_port: ' + str(req_match.in_port) +
502 " != " + str(res_match.in_port))
503 parent.assertEqual(str(req_match.dl_src), str(res_match.dl_src),
504 'Match failed: dl_src: ' + str(req_match.dl_src) +
505 " != " + str(res_match.dl_src))
506 parent.assertEqual(str(req_match.dl_dst), str(res_match.dl_dst),
507 'Match failed: dl_dst: ' + str(req_match.dl_dst) +
508 " != " + str(res_match.dl_dst))
509 parent.assertEqual(req_match.dl_vlan, res_match.dl_vlan,
510 'Match failed: dl_vlan: ' + str(req_match.dl_vlan) +
511 " != " + str(res_match.dl_vlan))
512 parent.assertEqual(req_match.dl_vlan_pcp, res_match.dl_vlan_pcp,
513 'Match failed: dl_vlan_pcp: ' +
514 str(req_match.dl_vlan_pcp) + " != " +
515 str(res_match.dl_vlan_pcp))
516 parent.assertEqual(req_match.dl_type, res_match.dl_type,
517 'Match failed: dl_type: ' + str(req_match.dl_type) +
518 " != " + str(res_match.dl_type))
519
Rich Lanecd97d3d2013-01-07 18:50:06 -0800520 if (not(req_match.wildcards & of10.cstruct.OFPFW_DL_TYPE)
Dan Talayco551befa2010-07-15 17:05:32 -0700521 and (req_match.dl_type == IP_ETHERTYPE)):
522 parent.assertEqual(req_match.nw_tos, res_match.nw_tos,
523 'Match failed: nw_tos: ' + str(req_match.nw_tos) +
524 " != " + str(res_match.nw_tos))
525 parent.assertEqual(req_match.nw_proto, res_match.nw_proto,
526 'Match failed: nw_proto: ' + str(req_match.nw_proto) +
527 " != " + str(res_match.nw_proto))
528 parent.assertEqual(req_match.nw_src, res_match.nw_src,
529 'Match failed: nw_src: ' + str(req_match.nw_src) +
530 " != " + str(res_match.nw_src))
531 parent.assertEqual(req_match.nw_dst, res_match.nw_dst,
532 'Match failed: nw_dst: ' + str(req_match.nw_dst) +
533 " != " + str(res_match.nw_dst))
534
Rich Lanecd97d3d2013-01-07 18:50:06 -0800535 if (not(req_match.wildcards & of10.cstruct.OFPFW_NW_PROTO)
Dan Talayco551befa2010-07-15 17:05:32 -0700536 and ((req_match.nw_proto == TCP_PROTOCOL)
537 or (req_match.nw_proto == UDP_PROTOCOL))):
538 parent.assertEqual(req_match.tp_src, res_match.tp_src,
539 'Match failed: tp_src: ' +
540 str(req_match.tp_src) +
541 " != " + str(res_match.tp_src))
542 parent.assertEqual(req_match.tp_dst, res_match.tp_dst,
543 'Match failed: tp_dst: ' +
544 str(req_match.tp_dst) +
545 " != " + str(res_match.tp_dst))
546
Ed Swierk99a74de2012-08-22 06:40:54 -0700547def packet_to_flow_match(parent, packet):
Rich Lanecd97d3d2013-01-07 18:50:06 -0800548 match = of10.parse.packet_to_flow_match(packet)
Ed Swierk99a74de2012-08-22 06:40:54 -0700549 match.wildcards |= required_wildcards(parent)
550 return match
551
552def flow_msg_create(parent, pkt, ing_port=None, action_list=None, wildcards=None,
Dan Talaycof6e76c02012-03-23 10:56:12 -0700553 egr_ports=None, egr_queue=None, check_expire=False, in_band=False):
Dan Talayco551befa2010-07-15 17:05:32 -0700554 """
555 Create a flow message
556
557 Match on packet with given wildcards.
558 See flow_match_test for other parameter descriptoins
559 @param egr_queue if not None, make the output an enqueue action
Dan Talayco677c0b72011-08-23 22:53:38 -0700560 @param in_band if True, do not wildcard ingress port
Dan Talaycof6e76c02012-03-23 10:56:12 -0700561 @param egr_ports None (drop), single port or list of ports
Dan Talayco551befa2010-07-15 17:05:32 -0700562 """
Rich Lanecd97d3d2013-01-07 18:50:06 -0800563 match = of10.parse.packet_to_flow_match(pkt)
Dan Talayco551befa2010-07-15 17:05:32 -0700564 parent.assertTrue(match is not None, "Flow match from pkt failed")
Ed Swierk99a74de2012-08-22 06:40:54 -0700565 if wildcards is None:
566 wildcards = required_wildcards(parent)
Dan Talayco677c0b72011-08-23 22:53:38 -0700567 if in_band:
Rich Lanecd97d3d2013-01-07 18:50:06 -0800568 wildcards &= ~of10.cstruct.OFPFW_IN_PORT
Dan Talayco551befa2010-07-15 17:05:32 -0700569 match.wildcards = wildcards
570 match.in_port = ing_port
571
Dan Talaycof6e76c02012-03-23 10:56:12 -0700572 if type(egr_ports) == type([]):
573 egr_port_list = egr_ports
574 else:
575 egr_port_list = [egr_ports]
576
Rich Lanecd97d3d2013-01-07 18:50:06 -0800577 request = of10.message.flow_mod()
Dan Talayco551befa2010-07-15 17:05:32 -0700578 request.match = match
579 request.buffer_id = 0xffffffff
580 if check_expire:
Rich Lanecd97d3d2013-01-07 18:50:06 -0800581 request.flags |= of10.cstruct.OFPFF_SEND_FLOW_REM
Dan Talayco551befa2010-07-15 17:05:32 -0700582 request.hard_timeout = 1
583
584 if action_list is not None:
585 for act in action_list:
Rich Lane9a003812012-10-04 17:17:59 -0700586 logging.debug("Adding action " + act.show())
Rich Lanee30455b2013-01-03 16:24:44 -0800587 request.actions.add(act)
Dan Talayco551befa2010-07-15 17:05:32 -0700588
589 # Set up output/enqueue action if directed
590 if egr_queue is not None:
Dan Talaycof6e76c02012-03-23 10:56:12 -0700591 parent.assertTrue(egr_ports is not None, "Egress port not set")
Rich Lanecd97d3d2013-01-07 18:50:06 -0800592 act = of10.action.action_enqueue()
Dan Talaycof6e76c02012-03-23 10:56:12 -0700593 for egr_port in egr_port_list:
594 act.port = egr_port
595 act.queue_id = egr_queue
Rich Lanee30455b2013-01-03 16:24:44 -0800596 request.actions.add(act)
Dan Talaycof6e76c02012-03-23 10:56:12 -0700597 elif egr_ports is not None:
598 for egr_port in egr_port_list:
Rich Lanecd97d3d2013-01-07 18:50:06 -0800599 act = of10.action.action_output()
Dan Talaycof6e76c02012-03-23 10:56:12 -0700600 act.port = egr_port
Rich Lanee30455b2013-01-03 16:24:44 -0800601 request.actions.add(act)
Dan Talayco551befa2010-07-15 17:05:32 -0700602
Rich Lane9a003812012-10-04 17:17:59 -0700603 logging.debug(request.show())
Dan Talayco551befa2010-07-15 17:05:32 -0700604
605 return request
606
Jeffrey Townsendf3eae9c2012-03-28 18:23:21 -0700607def flow_msg_install(parent, request, clear_table_override=None):
Dan Talayco551befa2010-07-15 17:05:32 -0700608 """
609 Install a flow mod message in the switch
610
611 @param parent Must implement controller, assertEqual, assertTrue
612 @param request The request, all set to go
613 @param clear_table If true, clear the flow table before installing
614 """
Dan Talayco8a64e332012-03-28 14:53:20 -0700615
Rich Lane2014f9b2012-10-05 15:29:40 -0700616 clear_table = test_param_get('clear_table', default=True)
Jeffrey Townsendf3eae9c2012-03-28 18:23:21 -0700617 if(clear_table_override != None):
618 clear_table = clear_table_override
619
620 if clear_table:
Rich Lane9a003812012-10-04 17:17:59 -0700621 logging.debug("Clear flow table")
Rich Lane32bf9482013-01-03 17:26:30 -0800622 delete_all_flows(parent.controller)
Dan Talayco551befa2010-07-15 17:05:32 -0700623
Rich Lane9a003812012-10-04 17:17:59 -0700624 logging.debug("Insert flow")
Rich Lane5c3151c2013-01-03 17:15:41 -0800625 parent.controller.message_send(request)
Rich Lanee912d032012-12-22 14:28:33 -0800626
Rich Lane3a261d52013-01-03 17:45:08 -0800627 do_barrier(parent.controller)
Dan Talayco551befa2010-07-15 17:05:32 -0700628
Ed Swierk99a74de2012-08-22 06:40:54 -0700629def flow_match_test_port_pair(parent, ing_port, egr_ports, wildcards=None,
Dan Talayco551befa2010-07-15 17:05:32 -0700630 dl_vlan=-1, pkt=None, exp_pkt=None,
Rich Lanee5779d32012-10-05 17:56:04 -0700631 action_list=None):
Dan Talayco551befa2010-07-15 17:05:32 -0700632 """
633 Flow match test on single TCP packet
Dan Talaycof6e76c02012-03-23 10:56:12 -0700634 @param egr_ports A single port or list of ports
Dan Talayco551befa2010-07-15 17:05:32 -0700635
636 Run test with packet through switch from ing_port to egr_port
637 See flow_match_test for parameter descriptions
638 """
639
Ed Swierk99a74de2012-08-22 06:40:54 -0700640 if wildcards is None:
641 wildcards = required_wildcards(parent)
Rich Lane9a003812012-10-04 17:17:59 -0700642 logging.info("Pkt match test: " + str(ing_port) + " to " +
Dan Talaycof6e76c02012-03-23 10:56:12 -0700643 str(egr_ports))
Rich Lanee5779d32012-10-05 17:56:04 -0700644 logging.debug(" WC: " + hex(wildcards) + " vlan: " + str(dl_vlan))
Dan Talayco551befa2010-07-15 17:05:32 -0700645 if pkt is None:
646 pkt = simple_tcp_packet(dl_vlan_enable=(dl_vlan >= 0), dl_vlan=dl_vlan)
647
648 request = flow_msg_create(parent, pkt, ing_port=ing_port,
Dan Talaycof6e76c02012-03-23 10:56:12 -0700649 wildcards=wildcards, egr_ports=egr_ports,
Dan Talayco551befa2010-07-15 17:05:32 -0700650 action_list=action_list)
651
652 flow_msg_install(parent, request)
653
Rich Lane9a003812012-10-04 17:17:59 -0700654 logging.debug("Send packet: " + str(ing_port) + " to " +
Dan Talaycof6e76c02012-03-23 10:56:12 -0700655 str(egr_ports))
Dan Talayco551befa2010-07-15 17:05:32 -0700656 parent.dataplane.send(ing_port, str(pkt))
657
658 if exp_pkt is None:
659 exp_pkt = pkt
Dan Talaycoc948d0b2012-03-23 12:17:54 -0700660 receive_pkt_verify(parent, egr_ports, exp_pkt, ing_port)
Dan Talayco551befa2010-07-15 17:05:32 -0700661
Rich Lane89725bb2012-12-03 16:23:27 -0800662def flow_match_test_pktout(parent, ing_port, egr_ports,
663 dl_vlan=-1, pkt=None, exp_pkt=None,
664 action_list=None):
665 """
666 Packet-out test on single TCP packet
667 @param egr_ports A single port or list of ports
668
669 Run test sending packet-out to egr_ports. The goal is to test the actions
670 taken on the packet, not the matching which is of course irrelevant.
671 See flow_match_test for parameter descriptions
672 """
673
674 if pkt is None:
675 pkt = simple_tcp_packet(dl_vlan_enable=(dl_vlan >= 0), dl_vlan=dl_vlan)
676
Rich Lanecd97d3d2013-01-07 18:50:06 -0800677 msg = of10.message.packet_out()
Rich Lane89725bb2012-12-03 16:23:27 -0800678 msg.in_port = ing_port
679 msg.data = str(pkt)
680 if action_list is not None:
681 for act in action_list:
Rich Lanee30455b2013-01-03 16:24:44 -0800682 msg.actions.add(act)
Rich Lane89725bb2012-12-03 16:23:27 -0800683
684 # Set up output action
685 if egr_ports is not None:
686 for egr_port in egr_ports:
Rich Lanecd97d3d2013-01-07 18:50:06 -0800687 act = of10.action.action_output()
Rich Lane89725bb2012-12-03 16:23:27 -0800688 act.port = egr_port
Rich Lanee30455b2013-01-03 16:24:44 -0800689 msg.actions.add(act)
Rich Lane89725bb2012-12-03 16:23:27 -0800690
691 logging.debug(msg.show())
Rich Lane5c3151c2013-01-03 17:15:41 -0800692 parent.controller.message_send(msg)
Rich Lane89725bb2012-12-03 16:23:27 -0800693
694 if exp_pkt is None:
695 exp_pkt = pkt
696 receive_pkt_verify(parent, egr_ports, exp_pkt, ing_port)
697
Dan Talaycof6e76c02012-03-23 10:56:12 -0700698def get_egr_list(parent, of_ports, how_many, exclude_list=[]):
699 """
700 Generate a list of ports avoiding those in the exclude list
Rich Lane9a003812012-10-04 17:17:59 -0700701 @param parent Supplies logging
Dan Talaycof6e76c02012-03-23 10:56:12 -0700702 @param of_ports List of OF port numbers
703 @param how_many Number of ports to be added to the list
704 @param exclude_list List of ports not to be used
705 @returns An empty list if unable to find enough ports
706 """
707
Dan Talaycoc948d0b2012-03-23 12:17:54 -0700708 if how_many == 0:
709 return []
710
Dan Talaycof6e76c02012-03-23 10:56:12 -0700711 count = 0
712 egr_ports = []
713 for egr_idx in range(len(of_ports)):
714 if of_ports[egr_idx] not in exclude_list:
715 egr_ports.append(of_ports[egr_idx])
716 count += 1
717 if count >= how_many:
718 return egr_ports
Rich Lane9a003812012-10-04 17:17:59 -0700719 logging.debug("Could not generate enough egress ports for test")
Dan Talaycof6e76c02012-03-23 10:56:12 -0700720 return []
721
Ed Swierk99a74de2012-08-22 06:40:54 -0700722def flow_match_test(parent, port_map, wildcards=None, dl_vlan=-1, pkt=None,
Rich Lanee5779d32012-10-05 17:56:04 -0700723 exp_pkt=None, action_list=None,
Dan Talaycoc948d0b2012-03-23 12:17:54 -0700724 max_test=0, egr_count=1, ing_port=False):
Dan Talayco551befa2010-07-15 17:05:32 -0700725 """
Rich Lane89725bb2012-12-03 16:23:27 -0800726 Run flow_match_test_port_pair on all port pairs and packet-out
Dan Talayco551befa2010-07-15 17:05:32 -0700727
728 @param max_test If > 0 no more than this number of tests are executed.
729 @param parent Must implement controller, dataplane, assertTrue, assertEqual
Rich Lane9a003812012-10-04 17:17:59 -0700730 and logging
Dan Talayco551befa2010-07-15 17:05:32 -0700731 @param pkt If not None, use this packet for ingress
732 @param wildcards For flow match entry
Dan Talayco79184222010-11-01 12:24:29 -0700733 @param dl_vlan If not -1, and pkt is None, create a pkt w/ VLAN tag
Dan Talayco551befa2010-07-15 17:05:32 -0700734 @param exp_pkt If not None, use this as the expected output pkt; els use pkt
735 @param action_list Additional actions to add to flow mod
Dan Talaycocfa172f2012-03-23 12:03:00 -0700736 @param egr_count Number of egress ports; -1 means get from config w/ dflt 2
Dan Talayco551befa2010-07-15 17:05:32 -0700737 """
Ed Swierk99a74de2012-08-22 06:40:54 -0700738 if wildcards is None:
739 wildcards = required_wildcards(parent)
Dan Talayco551befa2010-07-15 17:05:32 -0700740 of_ports = port_map.keys()
741 of_ports.sort()
742 parent.assertTrue(len(of_ports) > 1, "Not enough ports for test")
743 test_count = 0
744
Dan Talaycocfa172f2012-03-23 12:03:00 -0700745 if egr_count == -1:
Rich Lane2014f9b2012-10-05 15:29:40 -0700746 egr_count = test_param_get('egr_count', default=2)
Dan Talaycocfa172f2012-03-23 12:03:00 -0700747
Dan Talayco551befa2010-07-15 17:05:32 -0700748 for ing_idx in range(len(of_ports)):
749 ingress_port = of_ports[ing_idx]
Dan Talaycof6e76c02012-03-23 10:56:12 -0700750 egr_ports = get_egr_list(parent, of_ports, egr_count,
751 exclude_list=[ingress_port])
Dan Talaycoc948d0b2012-03-23 12:17:54 -0700752 if ing_port:
Rich Lanecd97d3d2013-01-07 18:50:06 -0800753 egr_ports.append(of10.cstruct.OFPP_IN_PORT)
Dan Talaycof6e76c02012-03-23 10:56:12 -0700754 if len(egr_ports) == 0:
755 parent.assertTrue(0, "Failed to generate egress port list")
756
757 flow_match_test_port_pair(parent, ingress_port, egr_ports,
758 wildcards=wildcards, dl_vlan=dl_vlan,
759 pkt=pkt, exp_pkt=exp_pkt,
Rich Lanee5779d32012-10-05 17:56:04 -0700760 action_list=action_list)
Dan Talaycof6e76c02012-03-23 10:56:12 -0700761 test_count += 1
762 if (max_test > 0) and (test_count > max_test):
Rich Lane9a003812012-10-04 17:17:59 -0700763 logging.info("Ran " + str(test_count) + " tests; exiting")
Rich Lane89725bb2012-12-03 16:23:27 -0800764 break
765
Ed Swierk38eea082013-01-02 19:46:20 -0800766 if not test_param_get('pktout_actions', default=True):
767 return
Rich Lane89725bb2012-12-03 16:23:27 -0800768
769 ingress_port = of_ports[0]
770 egr_ports = get_egr_list(parent, of_ports, egr_count,
771 exclude_list=[ingress_port])
772 if ing_port:
Rich Lanecd97d3d2013-01-07 18:50:06 -0800773 egr_ports.append(of10.cstruct.OFPP_IN_PORT)
Rich Lane89725bb2012-12-03 16:23:27 -0800774 flow_match_test_pktout(parent, ingress_port, egr_ports,
775 dl_vlan=dl_vlan,
776 pkt=pkt, exp_pkt=exp_pkt,
777 action_list=action_list)
Dan Talayco551befa2010-07-15 17:05:32 -0700778
Rich Lane2014f9b2012-10-05 15:29:40 -0700779def test_param_get(key, default=None):
Dan Talayco4b2bee62010-07-20 14:10:05 -0700780 """
781 Return value passed via test-params if present
782
Dan Talayco4b2bee62010-07-20 14:10:05 -0700783 @param key The lookup key
784 @param default Default value to use if not found
785
786 If the pair 'key=val' appeared in the string passed to --test-params
787 on the command line, return val (as interpreted by exec). Otherwise
788 return default value.
Dan Talaycof6e76c02012-03-23 10:56:12 -0700789
790 WARNING: TEST PARAMETERS MUST BE PYTHON IDENTIFIERS;
791 eg egr_count, not egr-count.
Dan Talayco4b2bee62010-07-20 14:10:05 -0700792 """
793 try:
Rich Lanecd97d3d2013-01-07 18:50:06 -0800794 exec oftest.config["test_params"]
Dan Talayco4b2bee62010-07-20 14:10:05 -0700795 except:
796 return default
797
798 s = "val = " + str(key)
799 try:
800 exec s
801 return val
802 except:
803 return default
804
805def action_generate(parent, field_to_mod, mod_field_vals):
806 """
807 Create an action to modify the field indicated in field_to_mod
808
809 @param parent Must implement, assertTrue
810 @param field_to_mod The field to modify as a string name
811 @param mod_field_vals Hash of values to use for modified values
812 """
813
814 act = None
815
816 if field_to_mod in ['pktlen']:
817 return None
818
819 if field_to_mod == 'dl_dst':
Rich Lanecd97d3d2013-01-07 18:50:06 -0800820 act = of10.action.action_set_dl_dst()
821 act.dl_addr = of10.parse.parse_mac(mod_field_vals['dl_dst'])
Dan Talayco4b2bee62010-07-20 14:10:05 -0700822 elif field_to_mod == 'dl_src':
Rich Lanecd97d3d2013-01-07 18:50:06 -0800823 act = of10.action.action_set_dl_src()
824 act.dl_addr = of10.parse.parse_mac(mod_field_vals['dl_src'])
Dan Talayco4b2bee62010-07-20 14:10:05 -0700825 elif field_to_mod == 'dl_vlan_enable':
826 if not mod_field_vals['dl_vlan_enable']: # Strip VLAN tag
Rich Lanecd97d3d2013-01-07 18:50:06 -0800827 act = of10.action.action_strip_vlan()
Dan Talayco4b2bee62010-07-20 14:10:05 -0700828 # Add VLAN tag is handled by dl_vlan field
829 # Will return None in this case
830 elif field_to_mod == 'dl_vlan':
Rich Lanecd97d3d2013-01-07 18:50:06 -0800831 act = of10.action.action_set_vlan_vid()
Dan Talayco4b2bee62010-07-20 14:10:05 -0700832 act.vlan_vid = mod_field_vals['dl_vlan']
833 elif field_to_mod == 'dl_vlan_pcp':
Rich Lanecd97d3d2013-01-07 18:50:06 -0800834 act = of10.action.action_set_vlan_pcp()
Dan Talayco4b2bee62010-07-20 14:10:05 -0700835 act.vlan_pcp = mod_field_vals['dl_vlan_pcp']
836 elif field_to_mod == 'ip_src':
Rich Lanecd97d3d2013-01-07 18:50:06 -0800837 act = of10.action.action_set_nw_src()
838 act.nw_addr = of10.parse.parse_ip(mod_field_vals['ip_src'])
Dan Talayco4b2bee62010-07-20 14:10:05 -0700839 elif field_to_mod == 'ip_dst':
Rich Lanecd97d3d2013-01-07 18:50:06 -0800840 act = of10.action.action_set_nw_dst()
841 act.nw_addr = of10.parse.parse_ip(mod_field_vals['ip_dst'])
Dan Talayco4b2bee62010-07-20 14:10:05 -0700842 elif field_to_mod == 'ip_tos':
Rich Lanecd97d3d2013-01-07 18:50:06 -0800843 act = of10.action.action_set_nw_tos()
Dan Talayco4b2bee62010-07-20 14:10:05 -0700844 act.nw_tos = mod_field_vals['ip_tos']
845 elif field_to_mod == 'tcp_sport':
Rich Lanecd97d3d2013-01-07 18:50:06 -0800846 act = of10.action.action_set_tp_src()
Dan Talayco4b2bee62010-07-20 14:10:05 -0700847 act.tp_port = mod_field_vals['tcp_sport']
848 elif field_to_mod == 'tcp_dport':
Rich Lanecd97d3d2013-01-07 18:50:06 -0800849 act = of10.action.action_set_tp_dst()
Dan Talayco4b2bee62010-07-20 14:10:05 -0700850 act.tp_port = mod_field_vals['tcp_dport']
Rich Lane110e0e32012-10-26 16:21:46 -0700851 elif field_to_mod == 'udp_sport':
Rich Lanecd97d3d2013-01-07 18:50:06 -0800852 act = of10.action.action_set_tp_src()
Rich Lane110e0e32012-10-26 16:21:46 -0700853 act.tp_port = mod_field_vals['udp_sport']
854 elif field_to_mod == 'udp_dport':
Rich Lanecd97d3d2013-01-07 18:50:06 -0800855 act = of10.action.action_set_tp_dst()
Rich Lane110e0e32012-10-26 16:21:46 -0700856 act.tp_port = mod_field_vals['udp_dport']
Dan Talayco4b2bee62010-07-20 14:10:05 -0700857 else:
858 parent.assertTrue(0, "Unknown field to modify: " + str(field_to_mod))
859
860 return act
861
862def pkt_action_setup(parent, start_field_vals={}, mod_field_vals={},
Rich Lane110e0e32012-10-26 16:21:46 -0700863 mod_fields=[], tp="tcp", check_test_params=False):
Dan Talayco4b2bee62010-07-20 14:10:05 -0700864 """
865 Set up the ingress and expected packet and action list for a test
866
Rich Lane2014f9b2012-10-05 15:29:40 -0700867 @param parent Must implement assertTrue
Dan Talayco4b2bee62010-07-20 14:10:05 -0700868 @param start_field_values Field values to use for ingress packet (optional)
869 @param mod_field_values Field values to use for modified packet (optional)
870 @param mod_fields The list of fields to be modified by the switch in the test.
871 @params check_test_params If True, will check the parameters vid, add_vlan
872 and strip_vlan from the command line.
873
874 Returns a triple: pkt-to-send, expected-pkt, action-list
875 """
876
877 new_actions = []
878
Dan Talayco4b2bee62010-07-20 14:10:05 -0700879 base_pkt_params = {}
880 base_pkt_params['pktlen'] = 100
881 base_pkt_params['dl_dst'] = '00:DE:F0:12:34:56'
882 base_pkt_params['dl_src'] = '00:23:45:67:89:AB'
883 base_pkt_params['dl_vlan_enable'] = False
884 base_pkt_params['dl_vlan'] = 2
885 base_pkt_params['dl_vlan_pcp'] = 0
886 base_pkt_params['ip_src'] = '192.168.0.1'
887 base_pkt_params['ip_dst'] = '192.168.0.2'
888 base_pkt_params['ip_tos'] = 0
Rich Lane110e0e32012-10-26 16:21:46 -0700889 if tp == "tcp":
890 base_pkt_params['tcp_sport'] = 1234
891 base_pkt_params['tcp_dport'] = 80
892 elif tp == "udp":
893 base_pkt_params['udp_sport'] = 1234
894 base_pkt_params['udp_dport'] = 80
Dan Talayco4b2bee62010-07-20 14:10:05 -0700895 for keyname in start_field_vals.keys():
896 base_pkt_params[keyname] = start_field_vals[keyname]
897
898 mod_pkt_params = {}
899 mod_pkt_params['pktlen'] = 100
900 mod_pkt_params['dl_dst'] = '00:21:0F:ED:CB:A9'
901 mod_pkt_params['dl_src'] = '00:ED:CB:A9:87:65'
902 mod_pkt_params['dl_vlan_enable'] = False
903 mod_pkt_params['dl_vlan'] = 3
904 mod_pkt_params['dl_vlan_pcp'] = 7
905 mod_pkt_params['ip_src'] = '10.20.30.40'
906 mod_pkt_params['ip_dst'] = '50.60.70.80'
907 mod_pkt_params['ip_tos'] = 0xf0
Rich Lane110e0e32012-10-26 16:21:46 -0700908 if tp == "tcp":
909 mod_pkt_params['tcp_sport'] = 4321
910 mod_pkt_params['tcp_dport'] = 8765
911 elif tp == "udp":
912 mod_pkt_params['udp_sport'] = 4321
913 mod_pkt_params['udp_dport'] = 8765
Dan Talayco4b2bee62010-07-20 14:10:05 -0700914 for keyname in mod_field_vals.keys():
915 mod_pkt_params[keyname] = mod_field_vals[keyname]
916
917 # Check for test param modifications
918 strip = False
919 if check_test_params:
Rich Lane2014f9b2012-10-05 15:29:40 -0700920 add_vlan = test_param_get('add_vlan')
921 strip_vlan = test_param_get('strip_vlan')
922 vid = test_param_get('vid')
Dan Talayco4b2bee62010-07-20 14:10:05 -0700923
924 if add_vlan and strip_vlan:
925 parent.assertTrue(0, "Add and strip VLAN both specified")
926
927 if vid:
928 base_pkt_params['dl_vlan_enable'] = True
929 base_pkt_params['dl_vlan'] = vid
930 if 'dl_vlan' in mod_fields:
931 mod_pkt_params['dl_vlan'] = vid + 1
932
933 if add_vlan:
934 base_pkt_params['dl_vlan_enable'] = False
935 mod_pkt_params['dl_vlan_enable'] = True
936 mod_pkt_params['pktlen'] = base_pkt_params['pktlen'] + 4
937 mod_fields.append('pktlen')
938 mod_fields.append('dl_vlan_enable')
939 if 'dl_vlan' not in mod_fields:
940 mod_fields.append('dl_vlan')
941 elif strip_vlan:
942 base_pkt_params['dl_vlan_enable'] = True
943 mod_pkt_params['dl_vlan_enable'] = False
944 mod_pkt_params['pktlen'] = base_pkt_params['pktlen'] - 4
945 mod_fields.append('dl_vlan_enable')
946 mod_fields.append('pktlen')
947
Rich Lane110e0e32012-10-26 16:21:46 -0700948 if tp == "tcp":
949 packet_builder = simple_tcp_packet
950 elif tp == "udp":
951 packet_builder = simple_udp_packet
952 else:
953 raise NotImplementedError("unknown transport protocol %s" % tp)
954
Dan Talayco4b2bee62010-07-20 14:10:05 -0700955 # Build the ingress packet
Rich Lane110e0e32012-10-26 16:21:46 -0700956 ingress_pkt = packet_builder(**base_pkt_params)
Dan Talayco4b2bee62010-07-20 14:10:05 -0700957
958 # Build the expected packet, modifying the indicated fields
959 for item in mod_fields:
960 base_pkt_params[item] = mod_pkt_params[item]
961 act = action_generate(parent, item, mod_pkt_params)
962 if act:
963 new_actions.append(act)
964
Rich Lane110e0e32012-10-26 16:21:46 -0700965 expected_pkt = packet_builder(**base_pkt_params)
Dan Talayco4b2bee62010-07-20 14:10:05 -0700966
967 return (ingress_pkt, expected_pkt, new_actions)
Dan Talayco677c0b72011-08-23 22:53:38 -0700968
969# Generate a simple "drop" flow mod
970# If in_band is true, then only drop from first test port
971def flow_mod_gen(port_map, in_band):
Rich Lanecd97d3d2013-01-07 18:50:06 -0800972 request = of10.message.flow_mod()
973 request.match.wildcards = of10.cstruct.OFPFW_ALL
Dan Talayco677c0b72011-08-23 22:53:38 -0700974 if in_band:
Rich Lanecd97d3d2013-01-07 18:50:06 -0800975 request.match.wildcards = of10.cstruct.OFPFW_ALL - of10.cstruct.OFPFW_IN_PORT
Dan Talayco677c0b72011-08-23 22:53:38 -0700976 for of_port, ifname in port_map.items(): # Grab first port
977 break
978 request.match.in_port = of_port
979 request.buffer_id = 0xffffffff
980 return request
Dan Talaycoba3745c2010-07-21 21:51:08 -0700981
982def skip_message_emit(parent, s):
983 """
984 Print out a 'skipped' message to stderr
985
986 @param s The string to print out to the log file
Dan Talaycoba3745c2010-07-21 21:51:08 -0700987 """
988 global skipped_test_count
989
990 skipped_test_count += 1
Rich Lane9a003812012-10-04 17:17:59 -0700991 logging.info("Skipping: " + s)
Dan Talayco2940fdd2013-02-06 15:01:35 -0800992 if oftest.config["debug"] < logging.WARNING:
Dan Talaycoba3745c2010-07-21 21:51:08 -0700993 sys.stderr.write("(skipped) ")
994 else:
995 sys.stderr.write("(S)")
Dan Talayco677c0b72011-08-23 22:53:38 -0700996
Dan Talayco8a64e332012-03-28 14:53:20 -0700997
998def all_stats_get(parent):
999 """
1000 Get the aggregate stats for all flows in the table
1001 @param parent Test instance with controller connection and assert
1002 @returns dict with keys flows, packets, bytes, active (flows),
1003 lookups, matched
1004 """
Rich Lanecd97d3d2013-01-07 18:50:06 -08001005 stat_req = of10.message.aggregate_stats_request()
1006 stat_req.match = of10.cstruct.ofp_match()
1007 stat_req.match.wildcards = of10.cstruct.OFPFW_ALL
Dan Talayco8a64e332012-03-28 14:53:20 -07001008 stat_req.table_id = 0xff
Rich Lanecd97d3d2013-01-07 18:50:06 -08001009 stat_req.out_port = of10.cstruct.OFPP_NONE
Dan Talayco8a64e332012-03-28 14:53:20 -07001010
1011 rv = {}
1012
Rich Lanec8aaa3e2012-07-26 19:28:02 -07001013 (reply, pkt) = parent.controller.transact(stat_req)
Dan Talayco8a64e332012-03-28 14:53:20 -07001014 parent.assertTrue(len(reply.stats) == 1, "Did not receive flow stats reply")
1015
1016 for obj in reply.stats:
1017 (rv["flows"], rv["packets"], rv["bytes"]) = (obj.flow_count,
1018 obj.packet_count, obj.byte_count)
1019 break
1020
Rich Lanecd97d3d2013-01-07 18:50:06 -08001021 request = of10.message.table_stats_request()
Rich Lanec8aaa3e2012-07-26 19:28:02 -07001022 (reply , pkt) = parent.controller.transact(request)
Dan Talayco8a64e332012-03-28 14:53:20 -07001023
1024
1025 (rv["active"], rv["lookups"], rv["matched"]) = (0,0,0)
1026 for obj in reply.stats:
1027 rv["active"] += obj.active_count
1028 rv["lookups"] += obj.lookup_count
1029 rv["matched"] += obj.matched_count
1030
1031 return rv
Dan Talayco2baf8b52012-03-30 09:55:42 -07001032
Rich Lane7744e112013-01-11 17:23:57 -08001033_import_blacklist.add('FILTER')
Dan Talayco2baf8b52012-03-30 09:55:42 -07001034FILTER=''.join([(len(repr(chr(x)))==3) and chr(x) or '.'
1035 for x in range(256)])
1036
1037def hex_dump_buffer(src, length=16):
1038 """
1039 Convert src to a hex dump string and return the string
1040 @param src The source buffer
1041 @param length The number of bytes shown in each line
1042 @returns A string showing the hex dump
1043 """
Dan Talaycoc516fa02012-04-12 22:28:43 -07001044 result = ["\n"]
Dan Talayco2baf8b52012-03-30 09:55:42 -07001045 for i in xrange(0, len(src), length):
1046 chars = src[i:i+length]
1047 hex = ' '.join(["%02x" % ord(x) for x in chars])
1048 printable = ''.join(["%s" % ((ord(x) <= 127 and
1049 FILTER[ord(x)]) or '.') for x in chars])
1050 result.append("%04x %-*s %s\n" % (i, length*3, hex, printable))
1051 return ''.join(result)
1052
1053def format_packet(pkt):
1054 return "Packet length %d \n%s" % (len(str(pkt)),
1055 hex_dump_buffer(str(pkt)))
Rich Lane5d7e89a2012-10-26 16:43:13 -07001056
1057def inspect_packet(pkt):
1058 """
1059 Wrapper around scapy's show() method.
1060 @returns A string showing the dissected packet.
1061 """
1062 from cStringIO import StringIO
1063 out = None
1064 backup = sys.stdout
1065 try:
1066 sys.stdout = StringIO()
1067 pkt.show2()
1068 out = sys.stdout.getvalue()
1069 sys.stdout.close()
1070 finally:
1071 sys.stdout = backup
1072 return out
Rich Lane0a4f6372013-01-02 14:40:22 -08001073
1074def nonstandard(cls):
1075 """
Rich Lanecc45b8e2013-01-02 15:55:02 -08001076 Testcase decorator that marks the test as being non-standard.
1077 These tests are not automatically added to the "standard" group.
Rich Lane0a4f6372013-01-02 14:40:22 -08001078 """
Rich Lanecc45b8e2013-01-02 15:55:02 -08001079 cls._nonstandard = True
Rich Lane0a4f6372013-01-02 14:40:22 -08001080 return cls
1081
1082def disabled(cls):
1083 """
Rich Lanecc45b8e2013-01-02 15:55:02 -08001084 Testcase decorator that marks the test as being disabled.
1085 These tests are not automatically added to the "standard" group or
1086 their module's group.
Rich Lane0a4f6372013-01-02 14:40:22 -08001087 """
Rich Lanecc45b8e2013-01-02 15:55:02 -08001088 cls._disabled = True
Rich Lane0a4f6372013-01-02 14:40:22 -08001089 return cls
Rich Lane97e99652013-01-02 17:23:20 -08001090
1091def group(name):
1092 """
1093 Testcase decorator that adds the test to a group.
1094 """
1095 def fn(cls):
1096 if not hasattr(cls, "_groups"):
1097 cls._groups = []
1098 cls._groups.append(name)
1099 return cls
1100 return fn
Rich Lane5a9a1922013-01-11 14:29:30 -08001101
1102def version(ver):
1103 """
1104 Testcase decorator that specifies which versions of OpenFlow the test
1105 supports. The default is 1.0+. This decorator may only be used once.
1106
1107 Supported syntax:
1108 1.0 -> 1.0
1109 1.0,1.2,1.3 -> 1.0, 1.2, 1.3
1110 1.0+ -> 1.0, 1.1, 1.2, 1.3
1111 """
1112 versions = parse_version(ver)
1113 def fn(cls):
1114 cls._versions = versions
1115 return cls
1116 return fn
1117
1118def parse_version(ver):
1119 allowed_versions = ["1.0", "1.1", "1.2", "1.3"]
1120 if re.match("^1\.\d+$", ver):
1121 versions = set([ver])
1122 elif re.match("^(1\.\d+)\+$", ver):
1123 if not ver[:-1] in allowed_versions:
1124 raise ValueError("invalid OpenFlow version %s" % ver[:-1])
1125 versions = set()
1126 if ver != "1.1+": versions.add("1.0")
1127 if ver != "1.2+": versions.add("1.1")
1128 if ver != "1.3+": versions.add("1.2")
1129 versions.add("1.3")
1130 else:
1131 versions = set(ver.split(','))
1132
1133 for version in versions:
1134 if not version in allowed_versions:
1135 raise ValueError("invalid OpenFlow version %s" % version)
1136
1137 return versions
1138
1139assert(parse_version("1.0") == set(["1.0"]))
1140assert(parse_version("1.0,1.2,1.3") == set(["1.0", "1.2", "1.3"]))
1141assert(parse_version("1.0+") == set(["1.0", "1.1", "1.2", "1.3"]))
Rich Lane7744e112013-01-11 17:23:57 -08001142
Rich Laneae3428c2013-03-07 14:37:42 -08001143def get_stats(test, req):
1144 """
1145 Retrieve a list of stats entries. Handles OFPSF_REPLY_MORE.
1146 """
1147 stats = []
1148 reply, _ = test.controller.transact(req)
1149 test.assertTrue(reply is not None, "No response to stats request")
1150 stats.extend(reply.stats)
1151 while reply.flags & of10.OFPSF_REPLY_MORE != 0:
1152 reply, pkt = self.controller.poll(exp_msg=of10.OFPT_STATS_REPLY)
1153 test.assertTrue(reply is not None, "No response to stats request")
1154 stats.extend(reply.stats)
1155 return stats
1156
1157def get_flow_stats(test, match, table_id=0xff, out_port=of10.cstruct.OFPP_NONE):
1158 """
1159 Retrieve a list of flow stats entries.
1160 """
1161 req = of10.message.flow_stats_request(match=match,
1162 table_id=table_id,
1163 out_port=out_port)
1164 return get_stats(test, req)
1165
1166def verify_flow_stats(test, match, table_id=0xff,
1167 out_port=of10.cstruct.OFPP_NONE,
1168 initial=[],
1169 pkts=None, bytes=None):
1170 """
1171 Verify that flow stats changed as expected.
1172
1173 Optionally takes an 'initial' list of stats entries, as returned by
1174 get_flow_stats(). If 'initial' is not given the counters are assumed to
1175 begin at 0.
1176 """
1177 def accumulate(stats):
1178 pkts_acc = bytes_acc = 0
1179 for stat in stats:
1180 pkts_acc += stat.packet_count
1181 bytes_acc += stat.byte_count
1182 return (pkts_acc, bytes_acc)
1183
1184 pkts_before, bytes_before = accumulate(initial)
1185
1186 # Wait 10s for counters to update
1187 pkt_diff = byte_diff = None
1188 for i in range(0, 100):
1189 stats = get_flow_stats(test, match, table_id=table_id, out_port=out_port)
1190 pkts_after, bytes_after = accumulate(stats)
1191 pkt_diff = pkts_after - pkts_before
1192 byte_diff = bytes_after - bytes_before
1193 if (pkts == None or pkt_diff >= pkts) and \
1194 (bytes == None or byte_diff >= bytes):
1195 break
1196 sleep(0.1)
1197
1198 if pkts != None:
1199 test.assertEquals(pkt_diff, pkts, "Flow packet counter not updated properly (expected increase of %d, got increase of %d)" % (pkts, pkt_diff))
1200
1201 if bytes != None:
1202 test.assertEquals(byte_diff, bytes, "Flow byte counter not updated properly (expected increase of %d, got increase of %d)" % (bytes, byte_diff))
1203
1204
Rich Lane7744e112013-01-11 17:23:57 -08001205__all__ = list(set(locals()) - _import_blacklist)