blob: 9558bcbb1a5aba435792c6bce399f04fb9ce10a1 [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 """
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700319 exp_pkt_arg = None
Rich Lane2014f9b2012-10-05 15:29:40 -0700320 if config["relax"]:
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700321 exp_pkt_arg = pkt
322
Dan Talayco92c99122010-06-03 13:53:18 -0700323 for ofport in yes_ports:
Rich Lane9a003812012-10-04 17:17:59 -0700324 logging.debug("Checking for pkt on port " + str(ofport))
Ken Chiang1bf01602012-04-04 10:48:23 -0700325 (rcv_port, rcv_pkt, pkt_time) = dp.poll(
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700326 port_number=ofport, exp_pkt=exp_pkt_arg)
Dan Talayco92c99122010-06-03 13:53:18 -0700327 assert_if.assertTrue(rcv_pkt is not None,
328 "Did not receive pkt on " + str(ofport))
Ken Chiang1bf01602012-04-04 10:48:23 -0700329 if not dataplane.match_exp_pkt(pkt, rcv_pkt):
Rich Lane9a003812012-10-04 17:17:59 -0700330 logging.debug("Sent %s" % format_packet(pkt))
331 logging.debug("Resp %s" % format_packet(rcv_pkt))
Ken Chiang1bf01602012-04-04 10:48:23 -0700332 assert_if.assertTrue(dataplane.match_exp_pkt(pkt, rcv_pkt),
333 "Response packet does not match send packet " +
334 "on port " + str(ofport))
Dan Talayco73f84012012-10-02 09:23:18 -0700335 if len(no_ports) > 0:
336 time.sleep(1)
Dan Talayco92c99122010-06-03 13:53:18 -0700337 for ofport in no_ports:
Rich Lane9a003812012-10-04 17:17:59 -0700338 logging.debug("Negative check for pkt on port " + str(ofport))
Ken Chiang1bf01602012-04-04 10:48:23 -0700339 (rcv_port, rcv_pkt, pkt_time) = dp.poll(
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700340 port_number=ofport, timeout=1, exp_pkt=exp_pkt_arg)
Dan Talayco92c99122010-06-03 13:53:18 -0700341 assert_if.assertTrue(rcv_pkt is None,
342 "Unexpected pkt on port " + str(ofport))
Dan Talayco551befa2010-07-15 17:05:32 -0700343
344
Dan Talaycoc948d0b2012-03-23 12:17:54 -0700345def receive_pkt_verify(parent, egr_ports, exp_pkt, ing_port):
Dan Talayco551befa2010-07-15 17:05:32 -0700346 """
347 Receive a packet and verify it matches an expected value
Dan Talaycof6e76c02012-03-23 10:56:12 -0700348 @param egr_port A single port or list of ports
Dan Talayco551befa2010-07-15 17:05:32 -0700349
350 parent must implement dataplane, assertTrue and assertEqual
351 """
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700352 exp_pkt_arg = None
Rich Lane477f4812012-10-04 22:49:00 -0700353 if config["relax"]:
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700354 exp_pkt_arg = exp_pkt
355
Dan Talaycof6e76c02012-03-23 10:56:12 -0700356 if type(egr_ports) == type([]):
357 egr_port_list = egr_ports
358 else:
359 egr_port_list = [egr_ports]
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700360
Dan Talaycof6e76c02012-03-23 10:56:12 -0700361 # Expect a packet from each port on egr port list
362 for egr_port in egr_port_list:
Dan Talaycod8ae7582012-03-23 12:24:56 -0700363 check_port = egr_port
Dan Talaycoc948d0b2012-03-23 12:17:54 -0700364 if egr_port == ofp.OFPP_IN_PORT:
Dan Talaycod8ae7582012-03-23 12:24:56 -0700365 check_port = ing_port
Dan Talaycof6e76c02012-03-23 10:56:12 -0700366 (rcv_port, rcv_pkt, pkt_time) = parent.dataplane.poll(
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700367 port_number=check_port, exp_pkt=exp_pkt_arg)
Dan Talayco551befa2010-07-15 17:05:32 -0700368
Dan Talaycof6e76c02012-03-23 10:56:12 -0700369 if rcv_pkt is None:
Rich Lane9a003812012-10-04 17:17:59 -0700370 logging.error("ERROR: No packet received from " +
Dan Talaycod8ae7582012-03-23 12:24:56 -0700371 str(check_port))
Dan Talayco551befa2010-07-15 17:05:32 -0700372
Dan Talaycof6e76c02012-03-23 10:56:12 -0700373 parent.assertTrue(rcv_pkt is not None,
Dan Talaycod8ae7582012-03-23 12:24:56 -0700374 "Did not receive packet port " + str(check_port))
Rich Lane9a003812012-10-04 17:17:59 -0700375 logging.debug("Packet len " + str(len(rcv_pkt)) + " in on " +
Dan Talaycof6e76c02012-03-23 10:56:12 -0700376 str(rcv_port))
377
378 if str(exp_pkt) != str(rcv_pkt):
Rich Lane9a003812012-10-04 17:17:59 -0700379 logging.error("ERROR: Packet match failed.")
380 logging.debug("Expected len " + str(len(exp_pkt)) + ": "
Dan Talaycof6e76c02012-03-23 10:56:12 -0700381 + str(exp_pkt).encode('hex'))
Rich Lane9a003812012-10-04 17:17:59 -0700382 logging.debug("Received len " + str(len(rcv_pkt)) + ": "
Dan Talaycof6e76c02012-03-23 10:56:12 -0700383 + str(rcv_pkt).encode('hex'))
Rich Lane5d7e89a2012-10-26 16:43:13 -0700384 logging.debug("Expected packet: " + inspect_packet(scapy.Ether(str(exp_pkt))))
385 logging.debug("Received packet: " + inspect_packet(scapy.Ether(str(rcv_pkt))))
Dan Talaycof6e76c02012-03-23 10:56:12 -0700386 parent.assertEqual(str(exp_pkt), str(rcv_pkt),
Dan Talaycod8ae7582012-03-23 12:24:56 -0700387 "Packet match error on port " + str(check_port))
Dan Talaycof6e76c02012-03-23 10:56:12 -0700388
Dan Talayco551befa2010-07-15 17:05:32 -0700389def match_verify(parent, req_match, res_match):
390 """
391 Verify flow matches agree; if they disagree, report where
392
393 parent must implement assertEqual
394 Use str() to ensure content is compared and not pointers
395 """
396
397 parent.assertEqual(req_match.wildcards, res_match.wildcards,
398 'Match failed: wildcards: ' + hex(req_match.wildcards) +
399 " != " + hex(res_match.wildcards))
400 parent.assertEqual(req_match.in_port, res_match.in_port,
401 'Match failed: in_port: ' + str(req_match.in_port) +
402 " != " + str(res_match.in_port))
403 parent.assertEqual(str(req_match.dl_src), str(res_match.dl_src),
404 'Match failed: dl_src: ' + str(req_match.dl_src) +
405 " != " + str(res_match.dl_src))
406 parent.assertEqual(str(req_match.dl_dst), str(res_match.dl_dst),
407 'Match failed: dl_dst: ' + str(req_match.dl_dst) +
408 " != " + str(res_match.dl_dst))
409 parent.assertEqual(req_match.dl_vlan, res_match.dl_vlan,
410 'Match failed: dl_vlan: ' + str(req_match.dl_vlan) +
411 " != " + str(res_match.dl_vlan))
412 parent.assertEqual(req_match.dl_vlan_pcp, res_match.dl_vlan_pcp,
413 'Match failed: dl_vlan_pcp: ' +
414 str(req_match.dl_vlan_pcp) + " != " +
415 str(res_match.dl_vlan_pcp))
416 parent.assertEqual(req_match.dl_type, res_match.dl_type,
417 'Match failed: dl_type: ' + str(req_match.dl_type) +
418 " != " + str(res_match.dl_type))
419
420 if (not(req_match.wildcards & ofp.OFPFW_DL_TYPE)
421 and (req_match.dl_type == IP_ETHERTYPE)):
422 parent.assertEqual(req_match.nw_tos, res_match.nw_tos,
423 'Match failed: nw_tos: ' + str(req_match.nw_tos) +
424 " != " + str(res_match.nw_tos))
425 parent.assertEqual(req_match.nw_proto, res_match.nw_proto,
426 'Match failed: nw_proto: ' + str(req_match.nw_proto) +
427 " != " + str(res_match.nw_proto))
428 parent.assertEqual(req_match.nw_src, res_match.nw_src,
429 'Match failed: nw_src: ' + str(req_match.nw_src) +
430 " != " + str(res_match.nw_src))
431 parent.assertEqual(req_match.nw_dst, res_match.nw_dst,
432 'Match failed: nw_dst: ' + str(req_match.nw_dst) +
433 " != " + str(res_match.nw_dst))
434
435 if (not(req_match.wildcards & ofp.OFPFW_NW_PROTO)
436 and ((req_match.nw_proto == TCP_PROTOCOL)
437 or (req_match.nw_proto == UDP_PROTOCOL))):
438 parent.assertEqual(req_match.tp_src, res_match.tp_src,
439 'Match failed: tp_src: ' +
440 str(req_match.tp_src) +
441 " != " + str(res_match.tp_src))
442 parent.assertEqual(req_match.tp_dst, res_match.tp_dst,
443 'Match failed: tp_dst: ' +
444 str(req_match.tp_dst) +
445 " != " + str(res_match.tp_dst))
446
Ed Swierk99a74de2012-08-22 06:40:54 -0700447def packet_to_flow_match(parent, packet):
448 match = parse.packet_to_flow_match(packet)
449 match.wildcards |= required_wildcards(parent)
450 return match
451
452def flow_msg_create(parent, pkt, ing_port=None, action_list=None, wildcards=None,
Dan Talaycof6e76c02012-03-23 10:56:12 -0700453 egr_ports=None, egr_queue=None, check_expire=False, in_band=False):
Dan Talayco551befa2010-07-15 17:05:32 -0700454 """
455 Create a flow message
456
457 Match on packet with given wildcards.
458 See flow_match_test for other parameter descriptoins
459 @param egr_queue if not None, make the output an enqueue action
Dan Talayco677c0b72011-08-23 22:53:38 -0700460 @param in_band if True, do not wildcard ingress port
Dan Talaycof6e76c02012-03-23 10:56:12 -0700461 @param egr_ports None (drop), single port or list of ports
Dan Talayco551befa2010-07-15 17:05:32 -0700462 """
463 match = parse.packet_to_flow_match(pkt)
464 parent.assertTrue(match is not None, "Flow match from pkt failed")
Ed Swierk99a74de2012-08-22 06:40:54 -0700465 if wildcards is None:
466 wildcards = required_wildcards(parent)
Dan Talayco677c0b72011-08-23 22:53:38 -0700467 if in_band:
468 wildcards &= ~ofp.OFPFW_IN_PORT
Dan Talayco551befa2010-07-15 17:05:32 -0700469 match.wildcards = wildcards
470 match.in_port = ing_port
471
Dan Talaycof6e76c02012-03-23 10:56:12 -0700472 if type(egr_ports) == type([]):
473 egr_port_list = egr_ports
474 else:
475 egr_port_list = [egr_ports]
476
Dan Talayco551befa2010-07-15 17:05:32 -0700477 request = message.flow_mod()
478 request.match = match
479 request.buffer_id = 0xffffffff
480 if check_expire:
481 request.flags |= ofp.OFPFF_SEND_FLOW_REM
482 request.hard_timeout = 1
483
484 if action_list is not None:
485 for act in action_list:
Rich Lane9a003812012-10-04 17:17:59 -0700486 logging.debug("Adding action " + act.show())
Dan Talayco551befa2010-07-15 17:05:32 -0700487 rv = request.actions.add(act)
488 parent.assertTrue(rv, "Could not add action" + act.show())
489
490 # Set up output/enqueue action if directed
491 if egr_queue is not None:
Dan Talaycof6e76c02012-03-23 10:56:12 -0700492 parent.assertTrue(egr_ports is not None, "Egress port not set")
Dan Talayco551befa2010-07-15 17:05:32 -0700493 act = action.action_enqueue()
Dan Talaycof6e76c02012-03-23 10:56:12 -0700494 for egr_port in egr_port_list:
495 act.port = egr_port
496 act.queue_id = egr_queue
497 rv = request.actions.add(act)
498 parent.assertTrue(rv, "Could not add enqueue action " +
499 str(egr_port) + " Q: " + str(egr_queue))
500 elif egr_ports is not None:
501 for egr_port in egr_port_list:
502 act = action.action_output()
503 act.port = egr_port
504 rv = request.actions.add(act)
505 parent.assertTrue(rv, "Could not add output action " +
506 str(egr_port))
Dan Talayco551befa2010-07-15 17:05:32 -0700507
Rich Lane9a003812012-10-04 17:17:59 -0700508 logging.debug(request.show())
Dan Talayco551befa2010-07-15 17:05:32 -0700509
510 return request
511
Jeffrey Townsendf3eae9c2012-03-28 18:23:21 -0700512def flow_msg_install(parent, request, clear_table_override=None):
Dan Talayco551befa2010-07-15 17:05:32 -0700513 """
514 Install a flow mod message in the switch
515
516 @param parent Must implement controller, assertEqual, assertTrue
517 @param request The request, all set to go
518 @param clear_table If true, clear the flow table before installing
519 """
Dan Talayco8a64e332012-03-28 14:53:20 -0700520
Rich Lane2014f9b2012-10-05 15:29:40 -0700521 clear_table = test_param_get('clear_table', default=True)
Jeffrey Townsendf3eae9c2012-03-28 18:23:21 -0700522 if(clear_table_override != None):
523 clear_table = clear_table_override
524
525 if clear_table:
Rich Lane9a003812012-10-04 17:17:59 -0700526 logging.debug("Clear flow table")
527 rc = delete_all_flows(parent.controller)
Dan Talayco551befa2010-07-15 17:05:32 -0700528 parent.assertEqual(rc, 0, "Failed to delete all flows")
Dan Talayco0fc08bd2012-04-09 16:56:18 -0700529 parent.assertEqual(do_barrier(parent.controller), 0, "Barrier failed")
Dan Talayco551befa2010-07-15 17:05:32 -0700530
Rich Lane9a003812012-10-04 17:17:59 -0700531 logging.debug("Insert flow")
Dan Talayco551befa2010-07-15 17:05:32 -0700532 rv = parent.controller.message_send(request)
533 parent.assertTrue(rv != -1, "Error installing flow mod")
Dan Talayco0fc08bd2012-04-09 16:56:18 -0700534 parent.assertEqual(do_barrier(parent.controller), 0, "Barrier failed")
Dan Talayco551befa2010-07-15 17:05:32 -0700535
Ed Swierk99a74de2012-08-22 06:40:54 -0700536def flow_match_test_port_pair(parent, ing_port, egr_ports, wildcards=None,
Dan Talayco551befa2010-07-15 17:05:32 -0700537 dl_vlan=-1, pkt=None, exp_pkt=None,
Rich Lanee5779d32012-10-05 17:56:04 -0700538 action_list=None):
Dan Talayco551befa2010-07-15 17:05:32 -0700539 """
540 Flow match test on single TCP packet
Dan Talaycof6e76c02012-03-23 10:56:12 -0700541 @param egr_ports A single port or list of ports
Dan Talayco551befa2010-07-15 17:05:32 -0700542
543 Run test with packet through switch from ing_port to egr_port
544 See flow_match_test for parameter descriptions
545 """
546
Ed Swierk99a74de2012-08-22 06:40:54 -0700547 if wildcards is None:
548 wildcards = required_wildcards(parent)
Rich Lane9a003812012-10-04 17:17:59 -0700549 logging.info("Pkt match test: " + str(ing_port) + " to " +
Dan Talaycof6e76c02012-03-23 10:56:12 -0700550 str(egr_ports))
Rich Lanee5779d32012-10-05 17:56:04 -0700551 logging.debug(" WC: " + hex(wildcards) + " vlan: " + str(dl_vlan))
Dan Talayco551befa2010-07-15 17:05:32 -0700552 if pkt is None:
553 pkt = simple_tcp_packet(dl_vlan_enable=(dl_vlan >= 0), dl_vlan=dl_vlan)
554
555 request = flow_msg_create(parent, pkt, ing_port=ing_port,
Dan Talaycof6e76c02012-03-23 10:56:12 -0700556 wildcards=wildcards, egr_ports=egr_ports,
Dan Talayco551befa2010-07-15 17:05:32 -0700557 action_list=action_list)
558
559 flow_msg_install(parent, request)
560
Rich Lane9a003812012-10-04 17:17:59 -0700561 logging.debug("Send packet: " + str(ing_port) + " to " +
Dan Talaycof6e76c02012-03-23 10:56:12 -0700562 str(egr_ports))
Dan Talayco551befa2010-07-15 17:05:32 -0700563 parent.dataplane.send(ing_port, str(pkt))
564
565 if exp_pkt is None:
566 exp_pkt = pkt
Dan Talaycoc948d0b2012-03-23 12:17:54 -0700567 receive_pkt_verify(parent, egr_ports, exp_pkt, ing_port)
Dan Talayco551befa2010-07-15 17:05:32 -0700568
Rich Lane89725bb2012-12-03 16:23:27 -0800569def flow_match_test_pktout(parent, ing_port, egr_ports,
570 dl_vlan=-1, pkt=None, exp_pkt=None,
571 action_list=None):
572 """
573 Packet-out test on single TCP packet
574 @param egr_ports A single port or list of ports
575
576 Run test sending packet-out to egr_ports. The goal is to test the actions
577 taken on the packet, not the matching which is of course irrelevant.
578 See flow_match_test for parameter descriptions
579 """
580
581 if pkt is None:
582 pkt = simple_tcp_packet(dl_vlan_enable=(dl_vlan >= 0), dl_vlan=dl_vlan)
583
584 msg = message.packet_out()
585 msg.in_port = ing_port
586 msg.data = str(pkt)
587 if action_list is not None:
588 for act in action_list:
589 assert(msg.actions.add(act))
590
591 # Set up output action
592 if egr_ports is not None:
593 for egr_port in egr_ports:
594 act = action.action_output()
595 act.port = egr_port
596 assert(msg.actions.add(act))
597
598 logging.debug(msg.show())
599 rv = parent.controller.message_send(msg)
600 parent.assertTrue(rv == 0, "Error sending out message")
601
602 if exp_pkt is None:
603 exp_pkt = pkt
604 receive_pkt_verify(parent, egr_ports, exp_pkt, ing_port)
605
Dan Talaycof6e76c02012-03-23 10:56:12 -0700606def get_egr_list(parent, of_ports, how_many, exclude_list=[]):
607 """
608 Generate a list of ports avoiding those in the exclude list
Rich Lane9a003812012-10-04 17:17:59 -0700609 @param parent Supplies logging
Dan Talaycof6e76c02012-03-23 10:56:12 -0700610 @param of_ports List of OF port numbers
611 @param how_many Number of ports to be added to the list
612 @param exclude_list List of ports not to be used
613 @returns An empty list if unable to find enough ports
614 """
615
Dan Talaycoc948d0b2012-03-23 12:17:54 -0700616 if how_many == 0:
617 return []
618
Dan Talaycof6e76c02012-03-23 10:56:12 -0700619 count = 0
620 egr_ports = []
621 for egr_idx in range(len(of_ports)):
622 if of_ports[egr_idx] not in exclude_list:
623 egr_ports.append(of_ports[egr_idx])
624 count += 1
625 if count >= how_many:
626 return egr_ports
Rich Lane9a003812012-10-04 17:17:59 -0700627 logging.debug("Could not generate enough egress ports for test")
Dan Talaycof6e76c02012-03-23 10:56:12 -0700628 return []
629
Ed Swierk99a74de2012-08-22 06:40:54 -0700630def flow_match_test(parent, port_map, wildcards=None, dl_vlan=-1, pkt=None,
Rich Lanee5779d32012-10-05 17:56:04 -0700631 exp_pkt=None, action_list=None,
Dan Talaycoc948d0b2012-03-23 12:17:54 -0700632 max_test=0, egr_count=1, ing_port=False):
Dan Talayco551befa2010-07-15 17:05:32 -0700633 """
Rich Lane89725bb2012-12-03 16:23:27 -0800634 Run flow_match_test_port_pair on all port pairs and packet-out
Dan Talayco551befa2010-07-15 17:05:32 -0700635
636 @param max_test If > 0 no more than this number of tests are executed.
637 @param parent Must implement controller, dataplane, assertTrue, assertEqual
Rich Lane9a003812012-10-04 17:17:59 -0700638 and logging
Dan Talayco551befa2010-07-15 17:05:32 -0700639 @param pkt If not None, use this packet for ingress
640 @param wildcards For flow match entry
Dan Talayco79184222010-11-01 12:24:29 -0700641 @param dl_vlan If not -1, and pkt is None, create a pkt w/ VLAN tag
Dan Talayco551befa2010-07-15 17:05:32 -0700642 @param exp_pkt If not None, use this as the expected output pkt; els use pkt
643 @param action_list Additional actions to add to flow mod
Dan Talaycocfa172f2012-03-23 12:03:00 -0700644 @param egr_count Number of egress ports; -1 means get from config w/ dflt 2
Dan Talayco551befa2010-07-15 17:05:32 -0700645 """
Ed Swierk99a74de2012-08-22 06:40:54 -0700646 if wildcards is None:
647 wildcards = required_wildcards(parent)
Dan Talayco551befa2010-07-15 17:05:32 -0700648 of_ports = port_map.keys()
649 of_ports.sort()
650 parent.assertTrue(len(of_ports) > 1, "Not enough ports for test")
651 test_count = 0
652
Dan Talaycocfa172f2012-03-23 12:03:00 -0700653 if egr_count == -1:
Rich Lane2014f9b2012-10-05 15:29:40 -0700654 egr_count = test_param_get('egr_count', default=2)
Dan Talaycocfa172f2012-03-23 12:03:00 -0700655
Dan Talayco551befa2010-07-15 17:05:32 -0700656 for ing_idx in range(len(of_ports)):
657 ingress_port = of_ports[ing_idx]
Dan Talaycof6e76c02012-03-23 10:56:12 -0700658 egr_ports = get_egr_list(parent, of_ports, egr_count,
659 exclude_list=[ingress_port])
Dan Talaycoc948d0b2012-03-23 12:17:54 -0700660 if ing_port:
661 egr_ports.append(ofp.OFPP_IN_PORT)
Dan Talaycof6e76c02012-03-23 10:56:12 -0700662 if len(egr_ports) == 0:
663 parent.assertTrue(0, "Failed to generate egress port list")
664
665 flow_match_test_port_pair(parent, ingress_port, egr_ports,
666 wildcards=wildcards, dl_vlan=dl_vlan,
667 pkt=pkt, exp_pkt=exp_pkt,
Rich Lanee5779d32012-10-05 17:56:04 -0700668 action_list=action_list)
Dan Talaycof6e76c02012-03-23 10:56:12 -0700669 test_count += 1
670 if (max_test > 0) and (test_count > max_test):
Rich Lane9a003812012-10-04 17:17:59 -0700671 logging.info("Ran " + str(test_count) + " tests; exiting")
Rich Lane89725bb2012-12-03 16:23:27 -0800672 break
673
674
675 ingress_port = of_ports[0]
676 egr_ports = get_egr_list(parent, of_ports, egr_count,
677 exclude_list=[ingress_port])
678 if ing_port:
679 egr_ports.append(ofp.OFPP_IN_PORT)
680 flow_match_test_pktout(parent, ingress_port, egr_ports,
681 dl_vlan=dl_vlan,
682 pkt=pkt, exp_pkt=exp_pkt,
683 action_list=action_list)
Dan Talayco551befa2010-07-15 17:05:32 -0700684
Rich Lane2014f9b2012-10-05 15:29:40 -0700685def test_param_get(key, default=None):
Dan Talayco4b2bee62010-07-20 14:10:05 -0700686 """
687 Return value passed via test-params if present
688
Dan Talayco4b2bee62010-07-20 14:10:05 -0700689 @param key The lookup key
690 @param default Default value to use if not found
691
692 If the pair 'key=val' appeared in the string passed to --test-params
693 on the command line, return val (as interpreted by exec). Otherwise
694 return default value.
Dan Talaycof6e76c02012-03-23 10:56:12 -0700695
696 WARNING: TEST PARAMETERS MUST BE PYTHON IDENTIFIERS;
697 eg egr_count, not egr-count.
Dan Talayco4b2bee62010-07-20 14:10:05 -0700698 """
699 try:
700 exec config["test_params"]
701 except:
702 return default
703
704 s = "val = " + str(key)
705 try:
706 exec s
707 return val
708 except:
709 return default
710
711def action_generate(parent, field_to_mod, mod_field_vals):
712 """
713 Create an action to modify the field indicated in field_to_mod
714
715 @param parent Must implement, assertTrue
716 @param field_to_mod The field to modify as a string name
717 @param mod_field_vals Hash of values to use for modified values
718 """
719
720 act = None
721
722 if field_to_mod in ['pktlen']:
723 return None
724
725 if field_to_mod == 'dl_dst':
726 act = action.action_set_dl_dst()
727 act.dl_addr = parse.parse_mac(mod_field_vals['dl_dst'])
728 elif field_to_mod == 'dl_src':
729 act = action.action_set_dl_src()
730 act.dl_addr = parse.parse_mac(mod_field_vals['dl_src'])
731 elif field_to_mod == 'dl_vlan_enable':
732 if not mod_field_vals['dl_vlan_enable']: # Strip VLAN tag
733 act = action.action_strip_vlan()
734 # Add VLAN tag is handled by dl_vlan field
735 # Will return None in this case
736 elif field_to_mod == 'dl_vlan':
737 act = action.action_set_vlan_vid()
738 act.vlan_vid = mod_field_vals['dl_vlan']
739 elif field_to_mod == 'dl_vlan_pcp':
740 act = action.action_set_vlan_pcp()
741 act.vlan_pcp = mod_field_vals['dl_vlan_pcp']
742 elif field_to_mod == 'ip_src':
743 act = action.action_set_nw_src()
744 act.nw_addr = parse.parse_ip(mod_field_vals['ip_src'])
745 elif field_to_mod == 'ip_dst':
746 act = action.action_set_nw_dst()
747 act.nw_addr = parse.parse_ip(mod_field_vals['ip_dst'])
748 elif field_to_mod == 'ip_tos':
749 act = action.action_set_nw_tos()
750 act.nw_tos = mod_field_vals['ip_tos']
751 elif field_to_mod == 'tcp_sport':
752 act = action.action_set_tp_src()
753 act.tp_port = mod_field_vals['tcp_sport']
754 elif field_to_mod == 'tcp_dport':
755 act = action.action_set_tp_dst()
756 act.tp_port = mod_field_vals['tcp_dport']
Rich Lane110e0e32012-10-26 16:21:46 -0700757 elif field_to_mod == 'udp_sport':
758 act = action.action_set_tp_src()
759 act.tp_port = mod_field_vals['udp_sport']
760 elif field_to_mod == 'udp_dport':
761 act = action.action_set_tp_dst()
762 act.tp_port = mod_field_vals['udp_dport']
Dan Talayco4b2bee62010-07-20 14:10:05 -0700763 else:
764 parent.assertTrue(0, "Unknown field to modify: " + str(field_to_mod))
765
766 return act
767
768def pkt_action_setup(parent, start_field_vals={}, mod_field_vals={},
Rich Lane110e0e32012-10-26 16:21:46 -0700769 mod_fields=[], tp="tcp", check_test_params=False):
Dan Talayco4b2bee62010-07-20 14:10:05 -0700770 """
771 Set up the ingress and expected packet and action list for a test
772
Rich Lane2014f9b2012-10-05 15:29:40 -0700773 @param parent Must implement assertTrue
Dan Talayco4b2bee62010-07-20 14:10:05 -0700774 @param start_field_values Field values to use for ingress packet (optional)
775 @param mod_field_values Field values to use for modified packet (optional)
776 @param mod_fields The list of fields to be modified by the switch in the test.
777 @params check_test_params If True, will check the parameters vid, add_vlan
778 and strip_vlan from the command line.
779
780 Returns a triple: pkt-to-send, expected-pkt, action-list
781 """
782
783 new_actions = []
784
Dan Talayco4b2bee62010-07-20 14:10:05 -0700785 base_pkt_params = {}
786 base_pkt_params['pktlen'] = 100
787 base_pkt_params['dl_dst'] = '00:DE:F0:12:34:56'
788 base_pkt_params['dl_src'] = '00:23:45:67:89:AB'
789 base_pkt_params['dl_vlan_enable'] = False
790 base_pkt_params['dl_vlan'] = 2
791 base_pkt_params['dl_vlan_pcp'] = 0
792 base_pkt_params['ip_src'] = '192.168.0.1'
793 base_pkt_params['ip_dst'] = '192.168.0.2'
794 base_pkt_params['ip_tos'] = 0
Rich Lane110e0e32012-10-26 16:21:46 -0700795 if tp == "tcp":
796 base_pkt_params['tcp_sport'] = 1234
797 base_pkt_params['tcp_dport'] = 80
798 elif tp == "udp":
799 base_pkt_params['udp_sport'] = 1234
800 base_pkt_params['udp_dport'] = 80
Dan Talayco4b2bee62010-07-20 14:10:05 -0700801 for keyname in start_field_vals.keys():
802 base_pkt_params[keyname] = start_field_vals[keyname]
803
804 mod_pkt_params = {}
805 mod_pkt_params['pktlen'] = 100
806 mod_pkt_params['dl_dst'] = '00:21:0F:ED:CB:A9'
807 mod_pkt_params['dl_src'] = '00:ED:CB:A9:87:65'
808 mod_pkt_params['dl_vlan_enable'] = False
809 mod_pkt_params['dl_vlan'] = 3
810 mod_pkt_params['dl_vlan_pcp'] = 7
811 mod_pkt_params['ip_src'] = '10.20.30.40'
812 mod_pkt_params['ip_dst'] = '50.60.70.80'
813 mod_pkt_params['ip_tos'] = 0xf0
Rich Lane110e0e32012-10-26 16:21:46 -0700814 if tp == "tcp":
815 mod_pkt_params['tcp_sport'] = 4321
816 mod_pkt_params['tcp_dport'] = 8765
817 elif tp == "udp":
818 mod_pkt_params['udp_sport'] = 4321
819 mod_pkt_params['udp_dport'] = 8765
Dan Talayco4b2bee62010-07-20 14:10:05 -0700820 for keyname in mod_field_vals.keys():
821 mod_pkt_params[keyname] = mod_field_vals[keyname]
822
823 # Check for test param modifications
824 strip = False
825 if check_test_params:
Rich Lane2014f9b2012-10-05 15:29:40 -0700826 add_vlan = test_param_get('add_vlan')
827 strip_vlan = test_param_get('strip_vlan')
828 vid = test_param_get('vid')
Dan Talayco4b2bee62010-07-20 14:10:05 -0700829
830 if add_vlan and strip_vlan:
831 parent.assertTrue(0, "Add and strip VLAN both specified")
832
833 if vid:
834 base_pkt_params['dl_vlan_enable'] = True
835 base_pkt_params['dl_vlan'] = vid
836 if 'dl_vlan' in mod_fields:
837 mod_pkt_params['dl_vlan'] = vid + 1
838
839 if add_vlan:
840 base_pkt_params['dl_vlan_enable'] = False
841 mod_pkt_params['dl_vlan_enable'] = True
842 mod_pkt_params['pktlen'] = base_pkt_params['pktlen'] + 4
843 mod_fields.append('pktlen')
844 mod_fields.append('dl_vlan_enable')
845 if 'dl_vlan' not in mod_fields:
846 mod_fields.append('dl_vlan')
847 elif strip_vlan:
848 base_pkt_params['dl_vlan_enable'] = True
849 mod_pkt_params['dl_vlan_enable'] = False
850 mod_pkt_params['pktlen'] = base_pkt_params['pktlen'] - 4
851 mod_fields.append('dl_vlan_enable')
852 mod_fields.append('pktlen')
853
Rich Lane110e0e32012-10-26 16:21:46 -0700854 if tp == "tcp":
855 packet_builder = simple_tcp_packet
856 elif tp == "udp":
857 packet_builder = simple_udp_packet
858 else:
859 raise NotImplementedError("unknown transport protocol %s" % tp)
860
Dan Talayco4b2bee62010-07-20 14:10:05 -0700861 # Build the ingress packet
Rich Lane110e0e32012-10-26 16:21:46 -0700862 ingress_pkt = packet_builder(**base_pkt_params)
Dan Talayco4b2bee62010-07-20 14:10:05 -0700863
864 # Build the expected packet, modifying the indicated fields
865 for item in mod_fields:
866 base_pkt_params[item] = mod_pkt_params[item]
867 act = action_generate(parent, item, mod_pkt_params)
868 if act:
869 new_actions.append(act)
870
Rich Lane110e0e32012-10-26 16:21:46 -0700871 expected_pkt = packet_builder(**base_pkt_params)
Dan Talayco4b2bee62010-07-20 14:10:05 -0700872
873 return (ingress_pkt, expected_pkt, new_actions)
Dan Talayco677c0b72011-08-23 22:53:38 -0700874
875# Generate a simple "drop" flow mod
876# If in_band is true, then only drop from first test port
877def flow_mod_gen(port_map, in_band):
878 request = message.flow_mod()
879 request.match.wildcards = ofp.OFPFW_ALL
880 if in_band:
881 request.match.wildcards = ofp.OFPFW_ALL - ofp.OFPFW_IN_PORT
882 for of_port, ifname in port_map.items(): # Grab first port
883 break
884 request.match.in_port = of_port
885 request.buffer_id = 0xffffffff
886 return request
Dan Talaycoba3745c2010-07-21 21:51:08 -0700887
888def skip_message_emit(parent, s):
889 """
890 Print out a 'skipped' message to stderr
891
892 @param s The string to print out to the log file
Rich Lane9a003812012-10-04 17:17:59 -0700893 @param parent Must implement config object
Dan Talaycoba3745c2010-07-21 21:51:08 -0700894 """
895 global skipped_test_count
896
897 skipped_test_count += 1
Rich Lane9a003812012-10-04 17:17:59 -0700898 logging.info("Skipping: " + s)
Rich Lane477f4812012-10-04 22:49:00 -0700899 if config["dbg_level"] < logging.WARNING:
Dan Talaycoba3745c2010-07-21 21:51:08 -0700900 sys.stderr.write("(skipped) ")
901 else:
902 sys.stderr.write("(S)")
Dan Talayco677c0b72011-08-23 22:53:38 -0700903
Dan Talayco8a64e332012-03-28 14:53:20 -0700904
905def all_stats_get(parent):
906 """
907 Get the aggregate stats for all flows in the table
908 @param parent Test instance with controller connection and assert
909 @returns dict with keys flows, packets, bytes, active (flows),
910 lookups, matched
911 """
912 stat_req = message.aggregate_stats_request()
913 stat_req.match = ofp.ofp_match()
914 stat_req.match.wildcards = ofp.OFPFW_ALL
915 stat_req.table_id = 0xff
916 stat_req.out_port = ofp.OFPP_NONE
917
918 rv = {}
919
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700920 (reply, pkt) = parent.controller.transact(stat_req)
Dan Talayco8a64e332012-03-28 14:53:20 -0700921 parent.assertTrue(len(reply.stats) == 1, "Did not receive flow stats reply")
922
923 for obj in reply.stats:
924 (rv["flows"], rv["packets"], rv["bytes"]) = (obj.flow_count,
925 obj.packet_count, obj.byte_count)
926 break
927
928 request = message.table_stats_request()
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700929 (reply , pkt) = parent.controller.transact(request)
Dan Talayco8a64e332012-03-28 14:53:20 -0700930
931
932 (rv["active"], rv["lookups"], rv["matched"]) = (0,0,0)
933 for obj in reply.stats:
934 rv["active"] += obj.active_count
935 rv["lookups"] += obj.lookup_count
936 rv["matched"] += obj.matched_count
937
938 return rv
Dan Talayco2baf8b52012-03-30 09:55:42 -0700939
940FILTER=''.join([(len(repr(chr(x)))==3) and chr(x) or '.'
941 for x in range(256)])
942
943def hex_dump_buffer(src, length=16):
944 """
945 Convert src to a hex dump string and return the string
946 @param src The source buffer
947 @param length The number of bytes shown in each line
948 @returns A string showing the hex dump
949 """
Dan Talaycoc516fa02012-04-12 22:28:43 -0700950 result = ["\n"]
Dan Talayco2baf8b52012-03-30 09:55:42 -0700951 for i in xrange(0, len(src), length):
952 chars = src[i:i+length]
953 hex = ' '.join(["%02x" % ord(x) for x in chars])
954 printable = ''.join(["%s" % ((ord(x) <= 127 and
955 FILTER[ord(x)]) or '.') for x in chars])
956 result.append("%04x %-*s %s\n" % (i, length*3, hex, printable))
957 return ''.join(result)
958
959def format_packet(pkt):
960 return "Packet length %d \n%s" % (len(str(pkt)),
961 hex_dump_buffer(str(pkt)))
Rich Lane5d7e89a2012-10-26 16:43:13 -0700962
963def inspect_packet(pkt):
964 """
965 Wrapper around scapy's show() method.
966 @returns A string showing the dissected packet.
967 """
968 from cStringIO import StringIO
969 out = None
970 backup = sys.stdout
971 try:
972 sys.stdout = StringIO()
973 pkt.show2()
974 out = sys.stdout.getvalue()
975 sys.stdout.close()
976 finally:
977 sys.stdout = backup
978 return out