blob: 50316b7cc5d6a60db4daca32083fa29abe8e93bb [file] [log] [blame]
Dan Talaycoc901f4d2010-03-07 21:55:45 -08001
Dan Talaycod2ca1032010-03-10 14:40:26 -08002import sys
Dan Talayco92c99122010-06-03 13:53:18 -07003import copy
Dan Talaycod2ca1032010-03-10 14:40:26 -08004
5try:
6 import scapy.all as scapy
7except:
8 try:
9 import scapy as scapy
10 except:
11 sys.exit("Need to install scapy for packet parsing")
Dan Talayco41eae8b2010-03-10 13:57:06 -080012
Rich Lane477f4812012-10-04 22:49:00 -070013from oftest import config
Dan Talaycoc901f4d2010-03-07 21:55:45 -080014import oftest.controller as controller
15import oftest.cstruct as ofp
16import oftest.message as message
17import oftest.dataplane as dataplane
18import oftest.action as action
Dan Talayco41eae8b2010-03-10 13:57:06 -080019import oftest.parse as parse
Dan Talaycoc901f4d2010-03-07 21:55:45 -080020import logging
Dan Talayco4b2bee62010-07-20 14:10:05 -070021import types
Dan Talayco73f84012012-10-02 09:23:18 -070022import time
Dan Talaycoc901f4d2010-03-07 21:55:45 -080023
Dan Talaycoba3745c2010-07-21 21:51:08 -070024global skipped_test_count
25skipped_test_count = 0
26
Dan Talayco551befa2010-07-15 17:05:32 -070027# Some useful defines
28IP_ETHERTYPE = 0x800
29TCP_PROTOCOL = 0x6
30UDP_PROTOCOL = 0x11
31
Jeffrey Townsend5cb7ed32012-08-17 18:11:01 +000032MINSIZE = 0
33
Rich Lane9a003812012-10-04 17:17:59 -070034def delete_all_flows(ctrl):
Dan Talayco41eae8b2010-03-10 13:57:06 -080035 """
36 Delete all flows on the switch
37 @param ctrl The controller object for the test
Dan Talayco41eae8b2010-03-10 13:57:06 -080038 """
39
Rich Lane9a003812012-10-04 17:17:59 -070040 logging.info("Deleting all flows")
Dan Talaycoc901f4d2010-03-07 21:55:45 -080041 msg = message.flow_mod()
42 msg.match.wildcards = ofp.OFPFW_ALL
Dan Talayco41eae8b2010-03-10 13:57:06 -080043 msg.out_port = ofp.OFPP_NONE
Dan Talaycoc901f4d2010-03-07 21:55:45 -080044 msg.command = ofp.OFPFC_DELETE
45 msg.buffer_id = 0xffffffff
Dan Talayco41eae8b2010-03-10 13:57:06 -080046 return ctrl.message_send(msg)
47
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':
51 return (ofp.OFPFW_NW_SRC_ALL | ofp.OFPFW_NW_DST_ALL | ofp.OFPFW_NW_TOS
52 | ofp.OFPFW_NW_PROTO | ofp.OFPFW_TP_SRC | ofp.OFPFW_TP_DST)
53 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',
Shudong Zhoub10ebd62012-11-27 01:42:51 -080059 dl_qinq_enable=False,
60 dl_vlan_outer=20,
Tatsuya Yabe460321e2010-05-25 17:50:49 -070061 dl_vlan_enable=False,
62 dl_vlan=0,
63 dl_vlan_pcp=0,
Dan Talayco551befa2010-07-15 17:05:32 -070064 dl_vlan_cfi=0,
Dan Talayco41eae8b2010-03-10 13:57:06 -080065 ip_src='192.168.0.1',
66 ip_dst='192.168.0.2',
Tatsuya Yabe460321e2010-05-25 17:50:49 -070067 ip_tos=0,
Dan Talayco41eae8b2010-03-10 13:57:06 -080068 tcp_sport=1234,
Christian Dickmann8b59b4b2012-09-23 16:48:30 -070069 tcp_dport=80,
70 ip_ihl=None,
71 ip_options=False
Dan Talayco41eae8b2010-03-10 13:57:06 -080072 ):
73 """
74 Return a simple dataplane TCP packet
75
76 Supports a few parameters:
77 @param len Length of packet in bytes w/o CRC
78 @param dl_dst Destinatino MAC
79 @param dl_src Source MAC
Shudong Zhoub10ebd62012-11-27 01:42:51 -080080 @param dl_qinq_enable True if the packet is double vlan tags
81 @param dl_vlan_outer Outer VLAN ID
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
Dan Talayco41eae8b2010-03-10 13:57:06 -080088 @param tcp_dport TCP destination port
89 @param ip_sport TCP source port
90
91 Generates a simple TCP request. Users
92 shouldn't assume anything about this packet other than that
93 it is a valid ethernet/IP/TCP frame.
94 """
Jeffrey Townsend5cb7ed32012-08-17 18:11:01 +000095
96 if MINSIZE > pktlen:
97 pktlen = MINSIZE
98
Dan Talayco551befa2010-07-15 17:05:32 -070099 # Note Dot1Q.id is really CFI
Shudong Zhoub10ebd62012-11-27 01:42:51 -0800100 if (dl_qinq_enable):
101 pkt = scapy.Ether(dst=dl_dst, src=dl_src)/ \
102 scapy.Dot1Q(prio=0, id=0, vlan=dl_vlan_outer)/ \
103 scapy.Dot1Q(prio=dl_vlan_pcp, id=dl_vlan_cfi, vlan=dl_vlan)/ \
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 elif (dl_vlan_enable):
Tatsuya Yabe460321e2010-05-25 17:50:49 -0700107 pkt = scapy.Ether(dst=dl_dst, src=dl_src)/ \
Dan Talayco551befa2010-07-15 17:05:32 -0700108 scapy.Dot1Q(prio=dl_vlan_pcp, id=dl_vlan_cfi, vlan=dl_vlan)/ \
Christian Dickmann8b59b4b2012-09-23 16:48:30 -0700109 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ihl=ip_ihl)/ \
Tatsuya Yabe460321e2010-05-25 17:50:49 -0700110 scapy.TCP(sport=tcp_sport, dport=tcp_dport)
111 else:
Christian Dickmann8b59b4b2012-09-23 16:48:30 -0700112 if not ip_options:
113 pkt = scapy.Ether(dst=dl_dst, src=dl_src)/ \
114 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ihl=ip_ihl)/ \
115 scapy.TCP(sport=tcp_sport, dport=tcp_dport)
116 else:
117 pkt = scapy.Ether(dst=dl_dst, src=dl_src)/ \
118 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ihl=ip_ihl, options=ip_options)/ \
119 scapy.TCP(sport=tcp_sport, dport=tcp_dport)
Tatsuya Yabe460321e2010-05-25 17:50:49 -0700120
Dan Talayco41eae8b2010-03-10 13:57:06 -0800121 pkt = pkt/("D" * (pktlen - len(pkt)))
122
123 return pkt
124
Rich Lane6ee7bea2012-10-26 16:19:29 -0700125def simple_udp_packet(pktlen=100,
126 dl_dst='00:01:02:03:04:05',
127 dl_src='00:06:07:08:09:0a',
128 dl_vlan_enable=False,
129 dl_vlan=0,
130 dl_vlan_pcp=0,
131 dl_vlan_cfi=0,
132 ip_src='192.168.0.1',
133 ip_dst='192.168.0.2',
134 ip_tos=0,
135 udp_sport=1234,
136 udp_dport=80,
137 ip_ihl=None,
138 ip_options=False
139 ):
140 """
141 Return a simple dataplane UDP packet
142
143 Supports a few parameters:
144 @param len Length of packet in bytes w/o CRC
145 @param dl_dst Destination MAC
146 @param dl_src Source MAC
147 @param dl_vlan_enable True if the packet is with vlan, False otherwise
148 @param dl_vlan VLAN ID
149 @param dl_vlan_pcp VLAN priority
150 @param ip_src IP source
151 @param ip_dst IP destination
152 @param ip_tos IP ToS
153 @param udp_dport UDP destination port
154 @param udp_sport UDP source port
155
156 Generates a simple UDP packet. Users shouldn't assume anything about
157 this packet other than that it is a valid ethernet/IP/UDP frame.
158 """
159
160 if MINSIZE > pktlen:
161 pktlen = MINSIZE
162
163 # Note Dot1Q.id is really CFI
164 if (dl_vlan_enable):
165 pkt = scapy.Ether(dst=dl_dst, src=dl_src)/ \
166 scapy.Dot1Q(prio=dl_vlan_pcp, id=dl_vlan_cfi, vlan=dl_vlan)/ \
167 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ihl=ip_ihl)/ \
168 scapy.UDP(sport=udp_sport, dport=udp_dport)
169 else:
170 if not ip_options:
171 pkt = scapy.Ether(dst=dl_dst, src=dl_src)/ \
172 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ihl=ip_ihl)/ \
173 scapy.UDP(sport=udp_sport, dport=udp_dport)
174 else:
175 pkt = scapy.Ether(dst=dl_dst, src=dl_src)/ \
176 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ihl=ip_ihl, options=ip_options)/ \
177 scapy.UDP(sport=udp_sport, dport=udp_dport)
178
179 pkt = pkt/("D" * (pktlen - len(pkt)))
180
181 return pkt
182
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700183def simple_icmp_packet(pktlen=60,
184 dl_dst='00:01:02:03:04:05',
185 dl_src='00:06:07:08:09:0a',
186 dl_vlan_enable=False,
187 dl_vlan=0,
188 dl_vlan_pcp=0,
189 ip_src='192.168.0.1',
190 ip_dst='192.168.0.2',
191 ip_tos=0,
192 icmp_type=8,
193 icmp_code=0
194 ):
195 """
196 Return a simple ICMP packet
197
198 Supports a few parameters:
199 @param len Length of packet in bytes w/o CRC
200 @param dl_dst Destinatino MAC
201 @param dl_src Source MAC
202 @param dl_vlan_enable True if the packet is with vlan, False otherwise
203 @param dl_vlan VLAN ID
204 @param dl_vlan_pcp VLAN priority
205 @param ip_src IP source
206 @param ip_dst IP destination
207 @param ip_tos IP ToS
208 @param icmp_type ICMP type
209 @param icmp_code ICMP code
210
211 Generates a simple ICMP ECHO REQUEST. Users
212 shouldn't assume anything about this packet other than that
213 it is a valid ethernet/ICMP frame.
214 """
Jeffrey Townsend5cb7ed32012-08-17 18:11:01 +0000215
216 if MINSIZE > pktlen:
217 pktlen = MINSIZE
218
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700219 if (dl_vlan_enable):
220 pkt = scapy.Ether(dst=dl_dst, src=dl_src)/ \
221 scapy.Dot1Q(prio=dl_vlan_pcp, id=0, vlan=dl_vlan)/ \
222 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos)/ \
223 scapy.ICMP(type=icmp_type, code=icmp_code)
224 else:
225 pkt = scapy.Ether(dst=dl_dst, src=dl_src)/ \
226 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos)/ \
227 scapy.ICMP(type=icmp_type, code=icmp_code)
228
229 pkt = pkt/("0" * (pktlen - len(pkt)))
230
231 return pkt
232
Ed Swierk0aeff8c2012-03-23 20:27:18 -0700233def simple_eth_packet(pktlen=60,
234 dl_dst='00:01:02:03:04:05',
235 dl_src='01:80:c2:00:00:00',
236 dl_type=0x88cc):
Jeffrey Townsend5cb7ed32012-08-17 18:11:01 +0000237
238 if MINSIZE > pktlen:
239 pktlen = MINSIZE
240
Ed Swierk0aeff8c2012-03-23 20:27:18 -0700241 pkt = scapy.Ether(dst=dl_dst, src=dl_src, type=dl_type)
242
243 pkt = pkt/("0" * (pktlen - len(pkt)))
244
245 return pkt
246
Shudong Zhoub7f12462012-11-20 13:01:12 -0800247def do_barrier(ctrl, timeout=-1):
Dan Talayco0fc08bd2012-04-09 16:56:18 -0700248 """
249 Do a barrier command
250 Return 0 on success, -1 on error
251 """
Dan Talayco41eae8b2010-03-10 13:57:06 -0800252 b = message.barrier_request()
Shudong Zhoub7f12462012-11-20 13:01:12 -0800253 (resp, pkt) = ctrl.transact(b, timeout=timeout)
Dan Talaycof6b94832012-04-12 21:50:57 -0700254 # We'll trust the transaction processing in the controller that xid matched
Dan Talayco0fc08bd2012-04-09 16:56:18 -0700255 if not resp:
256 return -1
257 return 0
Dan Talayco92c99122010-06-03 13:53:18 -0700258
Rich Lane9a003812012-10-04 17:17:59 -0700259def port_config_get(controller, port_no):
Dan Talayco92c99122010-06-03 13:53:18 -0700260 """
261 Get a port's configuration
262
263 Gets the switch feature configuration and grabs one port's
264 configuration
265
266 @returns (hwaddr, config, advert) The hwaddress, configuration and
267 advertised values
268 """
269 request = message.features_request()
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700270 reply, pkt = controller.transact(request)
Rich Lane9a003812012-10-04 17:17:59 -0700271 logging.debug(reply.show())
Dan Talayco92c99122010-06-03 13:53:18 -0700272 if reply is None:
Rich Lane9a003812012-10-04 17:17:59 -0700273 logging.warn("Get feature request failed")
Dan Talayco92c99122010-06-03 13:53:18 -0700274 return None, None, None
275 for idx in range(len(reply.ports)):
276 if reply.ports[idx].port_no == port_no:
277 return (reply.ports[idx].hw_addr, reply.ports[idx].config,
278 reply.ports[idx].advertised)
279
Rich Lane9a003812012-10-04 17:17:59 -0700280 logging.warn("Did not find port number for port config")
Dan Talayco92c99122010-06-03 13:53:18 -0700281 return None, None, None
282
Rich Lane9a003812012-10-04 17:17:59 -0700283def port_config_set(controller, port_no, config, mask):
Dan Talayco92c99122010-06-03 13:53:18 -0700284 """
285 Set the port configuration according the given parameters
286
287 Gets the switch feature configuration and updates one port's
288 configuration value according to config and mask
289 """
Rich Lane9a003812012-10-04 17:17:59 -0700290 logging.info("Setting port " + str(port_no) + " to config " + str(config))
Dan Talayco92c99122010-06-03 13:53:18 -0700291 request = message.features_request()
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700292 reply, pkt = controller.transact(request)
Dan Talayco92c99122010-06-03 13:53:18 -0700293 if reply is None:
294 return -1
Rich Lane9a003812012-10-04 17:17:59 -0700295 logging.debug(reply.show())
Dan Talayco92c99122010-06-03 13:53:18 -0700296 for idx in range(len(reply.ports)):
297 if reply.ports[idx].port_no == port_no:
298 break
299 if idx >= len(reply.ports):
300 return -1
301 mod = message.port_mod()
302 mod.port_no = port_no
303 mod.hw_addr = reply.ports[idx].hw_addr
304 mod.config = config
305 mod.mask = mask
306 mod.advertise = reply.ports[idx].advertised
307 rv = controller.message_send(mod)
308 return rv
309
Rich Lane2014f9b2012-10-05 15:29:40 -0700310def receive_pkt_check(dp, pkt, yes_ports, no_ports, assert_if):
Dan Talayco92c99122010-06-03 13:53:18 -0700311 """
312 Check for proper receive packets across all ports
Ken Chiang1bf01602012-04-04 10:48:23 -0700313 @param dp The dataplane object
Dan Talayco92c99122010-06-03 13:53:18 -0700314 @param pkt Expected packet; may be None if yes_ports is empty
315 @param yes_ports Set or list of ports that should recieve packet
316 @param no_ports Set or list of ports that should not receive packet
317 @param assert_if Object that implements assertXXX
318 """
Rich Lane91765672012-12-06 16:33:04 -0800319
320 # Wait this long for packets that we don't expect to receive.
321 # 100ms is (rarely) too short for positive tests on slow
322 # switches but is definitely not too short for a negative test.
323 negative_timeout = 0.1
324
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700325 exp_pkt_arg = None
Rich Lane2014f9b2012-10-05 15:29:40 -0700326 if config["relax"]:
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700327 exp_pkt_arg = pkt
328
Dan Talayco92c99122010-06-03 13:53:18 -0700329 for ofport in yes_ports:
Rich Lane9a003812012-10-04 17:17:59 -0700330 logging.debug("Checking for pkt on port " + str(ofport))
Ken Chiang1bf01602012-04-04 10:48:23 -0700331 (rcv_port, rcv_pkt, pkt_time) = dp.poll(
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700332 port_number=ofport, exp_pkt=exp_pkt_arg)
Dan Talayco92c99122010-06-03 13:53:18 -0700333 assert_if.assertTrue(rcv_pkt is not None,
334 "Did not receive pkt on " + str(ofport))
Ken Chiang1bf01602012-04-04 10:48:23 -0700335 if not dataplane.match_exp_pkt(pkt, rcv_pkt):
Rich Lane9a003812012-10-04 17:17:59 -0700336 logging.debug("Sent %s" % format_packet(pkt))
337 logging.debug("Resp %s" % format_packet(rcv_pkt))
Ken Chiang1bf01602012-04-04 10:48:23 -0700338 assert_if.assertTrue(dataplane.match_exp_pkt(pkt, rcv_pkt),
339 "Response packet does not match send packet " +
340 "on port " + str(ofport))
Dan Talayco73f84012012-10-02 09:23:18 -0700341 if len(no_ports) > 0:
Rich Lane91765672012-12-06 16:33:04 -0800342 time.sleep(negative_timeout)
Dan Talayco92c99122010-06-03 13:53:18 -0700343 for ofport in no_ports:
Rich Lane9a003812012-10-04 17:17:59 -0700344 logging.debug("Negative check for pkt on port " + str(ofport))
Ken Chiang1bf01602012-04-04 10:48:23 -0700345 (rcv_port, rcv_pkt, pkt_time) = dp.poll(
Rich Lane91765672012-12-06 16:33:04 -0800346 port_number=ofport, timeout=0, exp_pkt=exp_pkt_arg)
Dan Talayco92c99122010-06-03 13:53:18 -0700347 assert_if.assertTrue(rcv_pkt is None,
348 "Unexpected pkt on port " + str(ofport))
Dan Talayco551befa2010-07-15 17:05:32 -0700349
350
Dan Talaycoc948d0b2012-03-23 12:17:54 -0700351def receive_pkt_verify(parent, egr_ports, exp_pkt, ing_port):
Dan Talayco551befa2010-07-15 17:05:32 -0700352 """
353 Receive a packet and verify it matches an expected value
Dan Talaycof6e76c02012-03-23 10:56:12 -0700354 @param egr_port A single port or list of ports
Dan Talayco551befa2010-07-15 17:05:32 -0700355
356 parent must implement dataplane, assertTrue and assertEqual
357 """
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700358 exp_pkt_arg = None
Rich Lane477f4812012-10-04 22:49:00 -0700359 if config["relax"]:
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700360 exp_pkt_arg = exp_pkt
361
Dan Talaycof6e76c02012-03-23 10:56:12 -0700362 if type(egr_ports) == type([]):
363 egr_port_list = egr_ports
364 else:
365 egr_port_list = [egr_ports]
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700366
Dan Talaycof6e76c02012-03-23 10:56:12 -0700367 # Expect a packet from each port on egr port list
368 for egr_port in egr_port_list:
Dan Talaycod8ae7582012-03-23 12:24:56 -0700369 check_port = egr_port
Dan Talaycoc948d0b2012-03-23 12:17:54 -0700370 if egr_port == ofp.OFPP_IN_PORT:
Dan Talaycod8ae7582012-03-23 12:24:56 -0700371 check_port = ing_port
Dan Talaycof6e76c02012-03-23 10:56:12 -0700372 (rcv_port, rcv_pkt, pkt_time) = parent.dataplane.poll(
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700373 port_number=check_port, exp_pkt=exp_pkt_arg)
Dan Talayco551befa2010-07-15 17:05:32 -0700374
Dan Talaycof6e76c02012-03-23 10:56:12 -0700375 if rcv_pkt is None:
Rich Lane9a003812012-10-04 17:17:59 -0700376 logging.error("ERROR: No packet received from " +
Dan Talaycod8ae7582012-03-23 12:24:56 -0700377 str(check_port))
Dan Talayco551befa2010-07-15 17:05:32 -0700378
Dan Talaycof6e76c02012-03-23 10:56:12 -0700379 parent.assertTrue(rcv_pkt is not None,
Dan Talaycod8ae7582012-03-23 12:24:56 -0700380 "Did not receive packet port " + str(check_port))
Rich Lane9a003812012-10-04 17:17:59 -0700381 logging.debug("Packet len " + str(len(rcv_pkt)) + " in on " +
Dan Talaycof6e76c02012-03-23 10:56:12 -0700382 str(rcv_port))
383
384 if str(exp_pkt) != str(rcv_pkt):
Rich Lane9a003812012-10-04 17:17:59 -0700385 logging.error("ERROR: Packet match failed.")
386 logging.debug("Expected len " + str(len(exp_pkt)) + ": "
Dan Talaycof6e76c02012-03-23 10:56:12 -0700387 + str(exp_pkt).encode('hex'))
Rich Lane9a003812012-10-04 17:17:59 -0700388 logging.debug("Received len " + str(len(rcv_pkt)) + ": "
Dan Talaycof6e76c02012-03-23 10:56:12 -0700389 + str(rcv_pkt).encode('hex'))
Rich Lane5d7e89a2012-10-26 16:43:13 -0700390 logging.debug("Expected packet: " + inspect_packet(scapy.Ether(str(exp_pkt))))
391 logging.debug("Received packet: " + inspect_packet(scapy.Ether(str(rcv_pkt))))
Dan Talaycof6e76c02012-03-23 10:56:12 -0700392 parent.assertEqual(str(exp_pkt), str(rcv_pkt),
Dan Talaycod8ae7582012-03-23 12:24:56 -0700393 "Packet match error on port " + str(check_port))
Dan Talaycof6e76c02012-03-23 10:56:12 -0700394
Dan Talayco551befa2010-07-15 17:05:32 -0700395def match_verify(parent, req_match, res_match):
396 """
397 Verify flow matches agree; if they disagree, report where
398
399 parent must implement assertEqual
400 Use str() to ensure content is compared and not pointers
401 """
402
403 parent.assertEqual(req_match.wildcards, res_match.wildcards,
404 'Match failed: wildcards: ' + hex(req_match.wildcards) +
405 " != " + hex(res_match.wildcards))
406 parent.assertEqual(req_match.in_port, res_match.in_port,
407 'Match failed: in_port: ' + str(req_match.in_port) +
408 " != " + str(res_match.in_port))
409 parent.assertEqual(str(req_match.dl_src), str(res_match.dl_src),
410 'Match failed: dl_src: ' + str(req_match.dl_src) +
411 " != " + str(res_match.dl_src))
412 parent.assertEqual(str(req_match.dl_dst), str(res_match.dl_dst),
413 'Match failed: dl_dst: ' + str(req_match.dl_dst) +
414 " != " + str(res_match.dl_dst))
415 parent.assertEqual(req_match.dl_vlan, res_match.dl_vlan,
416 'Match failed: dl_vlan: ' + str(req_match.dl_vlan) +
417 " != " + str(res_match.dl_vlan))
418 parent.assertEqual(req_match.dl_vlan_pcp, res_match.dl_vlan_pcp,
419 'Match failed: dl_vlan_pcp: ' +
420 str(req_match.dl_vlan_pcp) + " != " +
421 str(res_match.dl_vlan_pcp))
422 parent.assertEqual(req_match.dl_type, res_match.dl_type,
423 'Match failed: dl_type: ' + str(req_match.dl_type) +
424 " != " + str(res_match.dl_type))
425
426 if (not(req_match.wildcards & ofp.OFPFW_DL_TYPE)
427 and (req_match.dl_type == IP_ETHERTYPE)):
428 parent.assertEqual(req_match.nw_tos, res_match.nw_tos,
429 'Match failed: nw_tos: ' + str(req_match.nw_tos) +
430 " != " + str(res_match.nw_tos))
431 parent.assertEqual(req_match.nw_proto, res_match.nw_proto,
432 'Match failed: nw_proto: ' + str(req_match.nw_proto) +
433 " != " + str(res_match.nw_proto))
434 parent.assertEqual(req_match.nw_src, res_match.nw_src,
435 'Match failed: nw_src: ' + str(req_match.nw_src) +
436 " != " + str(res_match.nw_src))
437 parent.assertEqual(req_match.nw_dst, res_match.nw_dst,
438 'Match failed: nw_dst: ' + str(req_match.nw_dst) +
439 " != " + str(res_match.nw_dst))
440
441 if (not(req_match.wildcards & ofp.OFPFW_NW_PROTO)
442 and ((req_match.nw_proto == TCP_PROTOCOL)
443 or (req_match.nw_proto == UDP_PROTOCOL))):
444 parent.assertEqual(req_match.tp_src, res_match.tp_src,
445 'Match failed: tp_src: ' +
446 str(req_match.tp_src) +
447 " != " + str(res_match.tp_src))
448 parent.assertEqual(req_match.tp_dst, res_match.tp_dst,
449 'Match failed: tp_dst: ' +
450 str(req_match.tp_dst) +
451 " != " + str(res_match.tp_dst))
452
Ed Swierk99a74de2012-08-22 06:40:54 -0700453def packet_to_flow_match(parent, packet):
454 match = parse.packet_to_flow_match(packet)
455 match.wildcards |= required_wildcards(parent)
456 return match
457
458def flow_msg_create(parent, pkt, ing_port=None, action_list=None, wildcards=None,
Dan Talaycof6e76c02012-03-23 10:56:12 -0700459 egr_ports=None, egr_queue=None, check_expire=False, in_band=False):
Dan Talayco551befa2010-07-15 17:05:32 -0700460 """
461 Create a flow message
462
463 Match on packet with given wildcards.
464 See flow_match_test for other parameter descriptoins
465 @param egr_queue if not None, make the output an enqueue action
Dan Talayco677c0b72011-08-23 22:53:38 -0700466 @param in_band if True, do not wildcard ingress port
Dan Talaycof6e76c02012-03-23 10:56:12 -0700467 @param egr_ports None (drop), single port or list of ports
Dan Talayco551befa2010-07-15 17:05:32 -0700468 """
469 match = parse.packet_to_flow_match(pkt)
470 parent.assertTrue(match is not None, "Flow match from pkt failed")
Ed Swierk99a74de2012-08-22 06:40:54 -0700471 if wildcards is None:
472 wildcards = required_wildcards(parent)
Dan Talayco677c0b72011-08-23 22:53:38 -0700473 if in_band:
474 wildcards &= ~ofp.OFPFW_IN_PORT
Dan Talayco551befa2010-07-15 17:05:32 -0700475 match.wildcards = wildcards
476 match.in_port = ing_port
477
Dan Talaycof6e76c02012-03-23 10:56:12 -0700478 if type(egr_ports) == type([]):
479 egr_port_list = egr_ports
480 else:
481 egr_port_list = [egr_ports]
482
Dan Talayco551befa2010-07-15 17:05:32 -0700483 request = message.flow_mod()
484 request.match = match
485 request.buffer_id = 0xffffffff
486 if check_expire:
487 request.flags |= ofp.OFPFF_SEND_FLOW_REM
488 request.hard_timeout = 1
489
490 if action_list is not None:
491 for act in action_list:
Rich Lane9a003812012-10-04 17:17:59 -0700492 logging.debug("Adding action " + act.show())
Dan Talayco551befa2010-07-15 17:05:32 -0700493 rv = request.actions.add(act)
494 parent.assertTrue(rv, "Could not add action" + act.show())
495
496 # Set up output/enqueue action if directed
497 if egr_queue is not None:
Dan Talaycof6e76c02012-03-23 10:56:12 -0700498 parent.assertTrue(egr_ports is not None, "Egress port not set")
Dan Talayco551befa2010-07-15 17:05:32 -0700499 act = action.action_enqueue()
Dan Talaycof6e76c02012-03-23 10:56:12 -0700500 for egr_port in egr_port_list:
501 act.port = egr_port
502 act.queue_id = egr_queue
503 rv = request.actions.add(act)
504 parent.assertTrue(rv, "Could not add enqueue action " +
505 str(egr_port) + " Q: " + str(egr_queue))
506 elif egr_ports is not None:
507 for egr_port in egr_port_list:
508 act = action.action_output()
509 act.port = egr_port
510 rv = request.actions.add(act)
511 parent.assertTrue(rv, "Could not add output action " +
512 str(egr_port))
Dan Talayco551befa2010-07-15 17:05:32 -0700513
Rich Lane9a003812012-10-04 17:17:59 -0700514 logging.debug(request.show())
Dan Talayco551befa2010-07-15 17:05:32 -0700515
516 return request
517
Jeffrey Townsendf3eae9c2012-03-28 18:23:21 -0700518def flow_msg_install(parent, request, clear_table_override=None):
Dan Talayco551befa2010-07-15 17:05:32 -0700519 """
520 Install a flow mod message in the switch
521
522 @param parent Must implement controller, assertEqual, assertTrue
523 @param request The request, all set to go
524 @param clear_table If true, clear the flow table before installing
525 """
Dan Talayco8a64e332012-03-28 14:53:20 -0700526
Rich Lane2014f9b2012-10-05 15:29:40 -0700527 clear_table = test_param_get('clear_table', default=True)
Jeffrey Townsendf3eae9c2012-03-28 18:23:21 -0700528 if(clear_table_override != None):
529 clear_table = clear_table_override
530
531 if clear_table:
Rich Lane9a003812012-10-04 17:17:59 -0700532 logging.debug("Clear flow table")
533 rc = delete_all_flows(parent.controller)
Dan Talayco551befa2010-07-15 17:05:32 -0700534 parent.assertEqual(rc, 0, "Failed to delete all flows")
Dan Talayco0fc08bd2012-04-09 16:56:18 -0700535 parent.assertEqual(do_barrier(parent.controller), 0, "Barrier failed")
Dan Talayco551befa2010-07-15 17:05:32 -0700536
Rich Lane9a003812012-10-04 17:17:59 -0700537 logging.debug("Insert flow")
Dan Talayco551befa2010-07-15 17:05:32 -0700538 rv = parent.controller.message_send(request)
539 parent.assertTrue(rv != -1, "Error installing flow mod")
Dan Talayco0fc08bd2012-04-09 16:56:18 -0700540 parent.assertEqual(do_barrier(parent.controller), 0, "Barrier failed")
Dan Talayco551befa2010-07-15 17:05:32 -0700541
Ed Swierk99a74de2012-08-22 06:40:54 -0700542def flow_match_test_port_pair(parent, ing_port, egr_ports, wildcards=None,
Dan Talayco551befa2010-07-15 17:05:32 -0700543 dl_vlan=-1, pkt=None, exp_pkt=None,
Rich Lanee5779d32012-10-05 17:56:04 -0700544 action_list=None):
Dan Talayco551befa2010-07-15 17:05:32 -0700545 """
546 Flow match test on single TCP packet
Dan Talaycof6e76c02012-03-23 10:56:12 -0700547 @param egr_ports A single port or list of ports
Dan Talayco551befa2010-07-15 17:05:32 -0700548
549 Run test with packet through switch from ing_port to egr_port
550 See flow_match_test for parameter descriptions
551 """
552
Ed Swierk99a74de2012-08-22 06:40:54 -0700553 if wildcards is None:
554 wildcards = required_wildcards(parent)
Rich Lane9a003812012-10-04 17:17:59 -0700555 logging.info("Pkt match test: " + str(ing_port) + " to " +
Dan Talaycof6e76c02012-03-23 10:56:12 -0700556 str(egr_ports))
Rich Lanee5779d32012-10-05 17:56:04 -0700557 logging.debug(" WC: " + hex(wildcards) + " vlan: " + str(dl_vlan))
Dan Talayco551befa2010-07-15 17:05:32 -0700558 if pkt is None:
559 pkt = simple_tcp_packet(dl_vlan_enable=(dl_vlan >= 0), dl_vlan=dl_vlan)
560
561 request = flow_msg_create(parent, pkt, ing_port=ing_port,
Dan Talaycof6e76c02012-03-23 10:56:12 -0700562 wildcards=wildcards, egr_ports=egr_ports,
Dan Talayco551befa2010-07-15 17:05:32 -0700563 action_list=action_list)
564
565 flow_msg_install(parent, request)
566
Rich Lane9a003812012-10-04 17:17:59 -0700567 logging.debug("Send packet: " + str(ing_port) + " to " +
Dan Talaycof6e76c02012-03-23 10:56:12 -0700568 str(egr_ports))
Dan Talayco551befa2010-07-15 17:05:32 -0700569 parent.dataplane.send(ing_port, str(pkt))
570
571 if exp_pkt is None:
572 exp_pkt = pkt
Dan Talaycoc948d0b2012-03-23 12:17:54 -0700573 receive_pkt_verify(parent, egr_ports, exp_pkt, ing_port)
Dan Talayco551befa2010-07-15 17:05:32 -0700574
Rich Lane89725bb2012-12-03 16:23:27 -0800575def flow_match_test_pktout(parent, ing_port, egr_ports,
576 dl_vlan=-1, pkt=None, exp_pkt=None,
577 action_list=None):
578 """
579 Packet-out test on single TCP packet
580 @param egr_ports A single port or list of ports
581
582 Run test sending packet-out to egr_ports. The goal is to test the actions
583 taken on the packet, not the matching which is of course irrelevant.
584 See flow_match_test for parameter descriptions
585 """
586
587 if pkt is None:
588 pkt = simple_tcp_packet(dl_vlan_enable=(dl_vlan >= 0), dl_vlan=dl_vlan)
589
590 msg = message.packet_out()
591 msg.in_port = ing_port
592 msg.data = str(pkt)
593 if action_list is not None:
594 for act in action_list:
595 assert(msg.actions.add(act))
596
597 # Set up output action
598 if egr_ports is not None:
599 for egr_port in egr_ports:
600 act = action.action_output()
601 act.port = egr_port
602 assert(msg.actions.add(act))
603
604 logging.debug(msg.show())
605 rv = parent.controller.message_send(msg)
606 parent.assertTrue(rv == 0, "Error sending out message")
607
608 if exp_pkt is None:
609 exp_pkt = pkt
610 receive_pkt_verify(parent, egr_ports, exp_pkt, ing_port)
611
Dan Talaycof6e76c02012-03-23 10:56:12 -0700612def get_egr_list(parent, of_ports, how_many, exclude_list=[]):
613 """
614 Generate a list of ports avoiding those in the exclude list
Rich Lane9a003812012-10-04 17:17:59 -0700615 @param parent Supplies logging
Dan Talaycof6e76c02012-03-23 10:56:12 -0700616 @param of_ports List of OF port numbers
617 @param how_many Number of ports to be added to the list
618 @param exclude_list List of ports not to be used
619 @returns An empty list if unable to find enough ports
620 """
621
Dan Talaycoc948d0b2012-03-23 12:17:54 -0700622 if how_many == 0:
623 return []
624
Dan Talaycof6e76c02012-03-23 10:56:12 -0700625 count = 0
626 egr_ports = []
627 for egr_idx in range(len(of_ports)):
628 if of_ports[egr_idx] not in exclude_list:
629 egr_ports.append(of_ports[egr_idx])
630 count += 1
631 if count >= how_many:
632 return egr_ports
Rich Lane9a003812012-10-04 17:17:59 -0700633 logging.debug("Could not generate enough egress ports for test")
Dan Talaycof6e76c02012-03-23 10:56:12 -0700634 return []
635
Ed Swierk99a74de2012-08-22 06:40:54 -0700636def flow_match_test(parent, port_map, wildcards=None, dl_vlan=-1, pkt=None,
Rich Lanee5779d32012-10-05 17:56:04 -0700637 exp_pkt=None, action_list=None,
Dan Talaycoc948d0b2012-03-23 12:17:54 -0700638 max_test=0, egr_count=1, ing_port=False):
Dan Talayco551befa2010-07-15 17:05:32 -0700639 """
Rich Lane89725bb2012-12-03 16:23:27 -0800640 Run flow_match_test_port_pair on all port pairs and packet-out
Dan Talayco551befa2010-07-15 17:05:32 -0700641
642 @param max_test If > 0 no more than this number of tests are executed.
643 @param parent Must implement controller, dataplane, assertTrue, assertEqual
Rich Lane9a003812012-10-04 17:17:59 -0700644 and logging
Dan Talayco551befa2010-07-15 17:05:32 -0700645 @param pkt If not None, use this packet for ingress
646 @param wildcards For flow match entry
Dan Talayco79184222010-11-01 12:24:29 -0700647 @param dl_vlan If not -1, and pkt is None, create a pkt w/ VLAN tag
Dan Talayco551befa2010-07-15 17:05:32 -0700648 @param exp_pkt If not None, use this as the expected output pkt; els use pkt
649 @param action_list Additional actions to add to flow mod
Dan Talaycocfa172f2012-03-23 12:03:00 -0700650 @param egr_count Number of egress ports; -1 means get from config w/ dflt 2
Dan Talayco551befa2010-07-15 17:05:32 -0700651 """
Ed Swierk99a74de2012-08-22 06:40:54 -0700652 if wildcards is None:
653 wildcards = required_wildcards(parent)
Dan Talayco551befa2010-07-15 17:05:32 -0700654 of_ports = port_map.keys()
655 of_ports.sort()
656 parent.assertTrue(len(of_ports) > 1, "Not enough ports for test")
657 test_count = 0
658
Dan Talaycocfa172f2012-03-23 12:03:00 -0700659 if egr_count == -1:
Rich Lane2014f9b2012-10-05 15:29:40 -0700660 egr_count = test_param_get('egr_count', default=2)
Dan Talaycocfa172f2012-03-23 12:03:00 -0700661
Dan Talayco551befa2010-07-15 17:05:32 -0700662 for ing_idx in range(len(of_ports)):
663 ingress_port = of_ports[ing_idx]
Dan Talaycof6e76c02012-03-23 10:56:12 -0700664 egr_ports = get_egr_list(parent, of_ports, egr_count,
665 exclude_list=[ingress_port])
Dan Talaycoc948d0b2012-03-23 12:17:54 -0700666 if ing_port:
667 egr_ports.append(ofp.OFPP_IN_PORT)
Dan Talaycof6e76c02012-03-23 10:56:12 -0700668 if len(egr_ports) == 0:
669 parent.assertTrue(0, "Failed to generate egress port list")
670
671 flow_match_test_port_pair(parent, ingress_port, egr_ports,
672 wildcards=wildcards, dl_vlan=dl_vlan,
673 pkt=pkt, exp_pkt=exp_pkt,
Rich Lanee5779d32012-10-05 17:56:04 -0700674 action_list=action_list)
Dan Talaycof6e76c02012-03-23 10:56:12 -0700675 test_count += 1
676 if (max_test > 0) and (test_count > max_test):
Rich Lane9a003812012-10-04 17:17:59 -0700677 logging.info("Ran " + str(test_count) + " tests; exiting")
Rich Lane89725bb2012-12-03 16:23:27 -0800678 break
679
680
681 ingress_port = of_ports[0]
682 egr_ports = get_egr_list(parent, of_ports, egr_count,
683 exclude_list=[ingress_port])
684 if ing_port:
685 egr_ports.append(ofp.OFPP_IN_PORT)
686 flow_match_test_pktout(parent, ingress_port, egr_ports,
687 dl_vlan=dl_vlan,
688 pkt=pkt, exp_pkt=exp_pkt,
689 action_list=action_list)
Dan Talayco551befa2010-07-15 17:05:32 -0700690
Rich Lane2014f9b2012-10-05 15:29:40 -0700691def test_param_get(key, default=None):
Dan Talayco4b2bee62010-07-20 14:10:05 -0700692 """
693 Return value passed via test-params if present
694
Dan Talayco4b2bee62010-07-20 14:10:05 -0700695 @param key The lookup key
696 @param default Default value to use if not found
697
698 If the pair 'key=val' appeared in the string passed to --test-params
699 on the command line, return val (as interpreted by exec). Otherwise
700 return default value.
Dan Talaycof6e76c02012-03-23 10:56:12 -0700701
702 WARNING: TEST PARAMETERS MUST BE PYTHON IDENTIFIERS;
703 eg egr_count, not egr-count.
Dan Talayco4b2bee62010-07-20 14:10:05 -0700704 """
705 try:
706 exec config["test_params"]
707 except:
708 return default
709
710 s = "val = " + str(key)
711 try:
712 exec s
713 return val
714 except:
715 return default
716
717def action_generate(parent, field_to_mod, mod_field_vals):
718 """
719 Create an action to modify the field indicated in field_to_mod
720
721 @param parent Must implement, assertTrue
722 @param field_to_mod The field to modify as a string name
723 @param mod_field_vals Hash of values to use for modified values
724 """
725
726 act = None
727
728 if field_to_mod in ['pktlen']:
729 return None
730
731 if field_to_mod == 'dl_dst':
732 act = action.action_set_dl_dst()
733 act.dl_addr = parse.parse_mac(mod_field_vals['dl_dst'])
734 elif field_to_mod == 'dl_src':
735 act = action.action_set_dl_src()
736 act.dl_addr = parse.parse_mac(mod_field_vals['dl_src'])
737 elif field_to_mod == 'dl_vlan_enable':
738 if not mod_field_vals['dl_vlan_enable']: # Strip VLAN tag
739 act = action.action_strip_vlan()
740 # Add VLAN tag is handled by dl_vlan field
741 # Will return None in this case
742 elif field_to_mod == 'dl_vlan':
743 act = action.action_set_vlan_vid()
744 act.vlan_vid = mod_field_vals['dl_vlan']
745 elif field_to_mod == 'dl_vlan_pcp':
746 act = action.action_set_vlan_pcp()
747 act.vlan_pcp = mod_field_vals['dl_vlan_pcp']
748 elif field_to_mod == 'ip_src':
749 act = action.action_set_nw_src()
750 act.nw_addr = parse.parse_ip(mod_field_vals['ip_src'])
751 elif field_to_mod == 'ip_dst':
752 act = action.action_set_nw_dst()
753 act.nw_addr = parse.parse_ip(mod_field_vals['ip_dst'])
754 elif field_to_mod == 'ip_tos':
755 act = action.action_set_nw_tos()
756 act.nw_tos = mod_field_vals['ip_tos']
757 elif field_to_mod == 'tcp_sport':
758 act = action.action_set_tp_src()
759 act.tp_port = mod_field_vals['tcp_sport']
760 elif field_to_mod == 'tcp_dport':
761 act = action.action_set_tp_dst()
762 act.tp_port = mod_field_vals['tcp_dport']
Rich Lane110e0e32012-10-26 16:21:46 -0700763 elif field_to_mod == 'udp_sport':
764 act = action.action_set_tp_src()
765 act.tp_port = mod_field_vals['udp_sport']
766 elif field_to_mod == 'udp_dport':
767 act = action.action_set_tp_dst()
768 act.tp_port = mod_field_vals['udp_dport']
Dan Talayco4b2bee62010-07-20 14:10:05 -0700769 else:
770 parent.assertTrue(0, "Unknown field to modify: " + str(field_to_mod))
771
772 return act
773
774def pkt_action_setup(parent, start_field_vals={}, mod_field_vals={},
Rich Lane110e0e32012-10-26 16:21:46 -0700775 mod_fields=[], tp="tcp", check_test_params=False):
Dan Talayco4b2bee62010-07-20 14:10:05 -0700776 """
777 Set up the ingress and expected packet and action list for a test
778
Rich Lane2014f9b2012-10-05 15:29:40 -0700779 @param parent Must implement assertTrue
Dan Talayco4b2bee62010-07-20 14:10:05 -0700780 @param start_field_values Field values to use for ingress packet (optional)
781 @param mod_field_values Field values to use for modified packet (optional)
782 @param mod_fields The list of fields to be modified by the switch in the test.
783 @params check_test_params If True, will check the parameters vid, add_vlan
784 and strip_vlan from the command line.
785
786 Returns a triple: pkt-to-send, expected-pkt, action-list
787 """
788
789 new_actions = []
790
Dan Talayco4b2bee62010-07-20 14:10:05 -0700791 base_pkt_params = {}
792 base_pkt_params['pktlen'] = 100
793 base_pkt_params['dl_dst'] = '00:DE:F0:12:34:56'
794 base_pkt_params['dl_src'] = '00:23:45:67:89:AB'
795 base_pkt_params['dl_vlan_enable'] = False
796 base_pkt_params['dl_vlan'] = 2
797 base_pkt_params['dl_vlan_pcp'] = 0
798 base_pkt_params['ip_src'] = '192.168.0.1'
799 base_pkt_params['ip_dst'] = '192.168.0.2'
800 base_pkt_params['ip_tos'] = 0
Rich Lane110e0e32012-10-26 16:21:46 -0700801 if tp == "tcp":
802 base_pkt_params['tcp_sport'] = 1234
803 base_pkt_params['tcp_dport'] = 80
804 elif tp == "udp":
805 base_pkt_params['udp_sport'] = 1234
806 base_pkt_params['udp_dport'] = 80
Dan Talayco4b2bee62010-07-20 14:10:05 -0700807 for keyname in start_field_vals.keys():
808 base_pkt_params[keyname] = start_field_vals[keyname]
809
810 mod_pkt_params = {}
811 mod_pkt_params['pktlen'] = 100
812 mod_pkt_params['dl_dst'] = '00:21:0F:ED:CB:A9'
813 mod_pkt_params['dl_src'] = '00:ED:CB:A9:87:65'
814 mod_pkt_params['dl_vlan_enable'] = False
815 mod_pkt_params['dl_vlan'] = 3
816 mod_pkt_params['dl_vlan_pcp'] = 7
817 mod_pkt_params['ip_src'] = '10.20.30.40'
818 mod_pkt_params['ip_dst'] = '50.60.70.80'
819 mod_pkt_params['ip_tos'] = 0xf0
Rich Lane110e0e32012-10-26 16:21:46 -0700820 if tp == "tcp":
821 mod_pkt_params['tcp_sport'] = 4321
822 mod_pkt_params['tcp_dport'] = 8765
823 elif tp == "udp":
824 mod_pkt_params['udp_sport'] = 4321
825 mod_pkt_params['udp_dport'] = 8765
Dan Talayco4b2bee62010-07-20 14:10:05 -0700826 for keyname in mod_field_vals.keys():
827 mod_pkt_params[keyname] = mod_field_vals[keyname]
828
829 # Check for test param modifications
830 strip = False
831 if check_test_params:
Rich Lane2014f9b2012-10-05 15:29:40 -0700832 add_vlan = test_param_get('add_vlan')
833 strip_vlan = test_param_get('strip_vlan')
834 vid = test_param_get('vid')
Dan Talayco4b2bee62010-07-20 14:10:05 -0700835
836 if add_vlan and strip_vlan:
837 parent.assertTrue(0, "Add and strip VLAN both specified")
838
839 if vid:
840 base_pkt_params['dl_vlan_enable'] = True
841 base_pkt_params['dl_vlan'] = vid
842 if 'dl_vlan' in mod_fields:
843 mod_pkt_params['dl_vlan'] = vid + 1
844
845 if add_vlan:
846 base_pkt_params['dl_vlan_enable'] = False
847 mod_pkt_params['dl_vlan_enable'] = True
848 mod_pkt_params['pktlen'] = base_pkt_params['pktlen'] + 4
849 mod_fields.append('pktlen')
850 mod_fields.append('dl_vlan_enable')
851 if 'dl_vlan' not in mod_fields:
852 mod_fields.append('dl_vlan')
853 elif strip_vlan:
854 base_pkt_params['dl_vlan_enable'] = True
855 mod_pkt_params['dl_vlan_enable'] = False
856 mod_pkt_params['pktlen'] = base_pkt_params['pktlen'] - 4
857 mod_fields.append('dl_vlan_enable')
858 mod_fields.append('pktlen')
859
Rich Lane110e0e32012-10-26 16:21:46 -0700860 if tp == "tcp":
861 packet_builder = simple_tcp_packet
862 elif tp == "udp":
863 packet_builder = simple_udp_packet
864 else:
865 raise NotImplementedError("unknown transport protocol %s" % tp)
866
Dan Talayco4b2bee62010-07-20 14:10:05 -0700867 # Build the ingress packet
Rich Lane110e0e32012-10-26 16:21:46 -0700868 ingress_pkt = packet_builder(**base_pkt_params)
Dan Talayco4b2bee62010-07-20 14:10:05 -0700869
870 # Build the expected packet, modifying the indicated fields
871 for item in mod_fields:
872 base_pkt_params[item] = mod_pkt_params[item]
873 act = action_generate(parent, item, mod_pkt_params)
874 if act:
875 new_actions.append(act)
876
Rich Lane110e0e32012-10-26 16:21:46 -0700877 expected_pkt = packet_builder(**base_pkt_params)
Dan Talayco4b2bee62010-07-20 14:10:05 -0700878
879 return (ingress_pkt, expected_pkt, new_actions)
Dan Talayco677c0b72011-08-23 22:53:38 -0700880
881# Generate a simple "drop" flow mod
882# If in_band is true, then only drop from first test port
883def flow_mod_gen(port_map, in_band):
884 request = message.flow_mod()
885 request.match.wildcards = ofp.OFPFW_ALL
886 if in_band:
887 request.match.wildcards = ofp.OFPFW_ALL - ofp.OFPFW_IN_PORT
888 for of_port, ifname in port_map.items(): # Grab first port
889 break
890 request.match.in_port = of_port
891 request.buffer_id = 0xffffffff
892 return request
Dan Talaycoba3745c2010-07-21 21:51:08 -0700893
894def skip_message_emit(parent, s):
895 """
896 Print out a 'skipped' message to stderr
897
898 @param s The string to print out to the log file
Rich Lane9a003812012-10-04 17:17:59 -0700899 @param parent Must implement config object
Dan Talaycoba3745c2010-07-21 21:51:08 -0700900 """
901 global skipped_test_count
902
903 skipped_test_count += 1
Rich Lane9a003812012-10-04 17:17:59 -0700904 logging.info("Skipping: " + s)
Rich Lane477f4812012-10-04 22:49:00 -0700905 if config["dbg_level"] < logging.WARNING:
Dan Talaycoba3745c2010-07-21 21:51:08 -0700906 sys.stderr.write("(skipped) ")
907 else:
908 sys.stderr.write("(S)")
Dan Talayco677c0b72011-08-23 22:53:38 -0700909
Dan Talayco8a64e332012-03-28 14:53:20 -0700910
911def all_stats_get(parent):
912 """
913 Get the aggregate stats for all flows in the table
914 @param parent Test instance with controller connection and assert
915 @returns dict with keys flows, packets, bytes, active (flows),
916 lookups, matched
917 """
918 stat_req = message.aggregate_stats_request()
919 stat_req.match = ofp.ofp_match()
920 stat_req.match.wildcards = ofp.OFPFW_ALL
921 stat_req.table_id = 0xff
922 stat_req.out_port = ofp.OFPP_NONE
923
924 rv = {}
925
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700926 (reply, pkt) = parent.controller.transact(stat_req)
Dan Talayco8a64e332012-03-28 14:53:20 -0700927 parent.assertTrue(len(reply.stats) == 1, "Did not receive flow stats reply")
928
929 for obj in reply.stats:
930 (rv["flows"], rv["packets"], rv["bytes"]) = (obj.flow_count,
931 obj.packet_count, obj.byte_count)
932 break
933
934 request = message.table_stats_request()
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700935 (reply , pkt) = parent.controller.transact(request)
Dan Talayco8a64e332012-03-28 14:53:20 -0700936
937
938 (rv["active"], rv["lookups"], rv["matched"]) = (0,0,0)
939 for obj in reply.stats:
940 rv["active"] += obj.active_count
941 rv["lookups"] += obj.lookup_count
942 rv["matched"] += obj.matched_count
943
944 return rv
Dan Talayco2baf8b52012-03-30 09:55:42 -0700945
946FILTER=''.join([(len(repr(chr(x)))==3) and chr(x) or '.'
947 for x in range(256)])
948
949def hex_dump_buffer(src, length=16):
950 """
951 Convert src to a hex dump string and return the string
952 @param src The source buffer
953 @param length The number of bytes shown in each line
954 @returns A string showing the hex dump
955 """
Dan Talaycoc516fa02012-04-12 22:28:43 -0700956 result = ["\n"]
Dan Talayco2baf8b52012-03-30 09:55:42 -0700957 for i in xrange(0, len(src), length):
958 chars = src[i:i+length]
959 hex = ' '.join(["%02x" % ord(x) for x in chars])
960 printable = ''.join(["%s" % ((ord(x) <= 127 and
961 FILTER[ord(x)]) or '.') for x in chars])
962 result.append("%04x %-*s %s\n" % (i, length*3, hex, printable))
963 return ''.join(result)
964
965def format_packet(pkt):
966 return "Packet length %d \n%s" % (len(str(pkt)),
967 hex_dump_buffer(str(pkt)))
Rich Lane5d7e89a2012-10-26 16:43:13 -0700968
969def inspect_packet(pkt):
970 """
971 Wrapper around scapy's show() method.
972 @returns A string showing the dissected packet.
973 """
974 from cStringIO import StringIO
975 out = None
976 backup = sys.stdout
977 try:
978 sys.stdout = StringIO()
979 pkt.show2()
980 out = sys.stdout.getvalue()
981 sys.stdout.close()
982 finally:
983 sys.stdout = backup
984 return out