blob: e7c09e12d287f4fe9b39157f69c9f9222837f490 [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',
Tatsuya Yabe460321e2010-05-25 17:50:49 -070059 dl_vlan_enable=False,
60 dl_vlan=0,
61 dl_vlan_pcp=0,
Dan Talayco551befa2010-07-15 17:05:32 -070062 dl_vlan_cfi=0,
Dan Talayco41eae8b2010-03-10 13:57:06 -080063 ip_src='192.168.0.1',
64 ip_dst='192.168.0.2',
Tatsuya Yabe460321e2010-05-25 17:50:49 -070065 ip_tos=0,
Dan Talayco41eae8b2010-03-10 13:57:06 -080066 tcp_sport=1234,
Christian Dickmann8b59b4b2012-09-23 16:48:30 -070067 tcp_dport=80,
68 ip_ihl=None,
69 ip_options=False
Dan Talayco41eae8b2010-03-10 13:57:06 -080070 ):
71 """
72 Return a simple dataplane TCP packet
73
74 Supports a few parameters:
75 @param len Length of packet in bytes w/o CRC
76 @param dl_dst Destinatino MAC
77 @param dl_src Source MAC
Tatsuya Yabe460321e2010-05-25 17:50:49 -070078 @param dl_vlan_enable True if the packet is with vlan, False otherwise
79 @param dl_vlan VLAN ID
80 @param dl_vlan_pcp VLAN priority
Dan Talayco41eae8b2010-03-10 13:57:06 -080081 @param ip_src IP source
82 @param ip_dst IP destination
Tatsuya Yabe460321e2010-05-25 17:50:49 -070083 @param ip_tos IP ToS
Dan Talayco41eae8b2010-03-10 13:57:06 -080084 @param tcp_dport TCP destination port
85 @param ip_sport TCP source port
86
87 Generates a simple TCP request. Users
88 shouldn't assume anything about this packet other than that
89 it is a valid ethernet/IP/TCP frame.
90 """
Jeffrey Townsend5cb7ed32012-08-17 18:11:01 +000091
92 if MINSIZE > pktlen:
93 pktlen = MINSIZE
94
Dan Talayco551befa2010-07-15 17:05:32 -070095 # Note Dot1Q.id is really CFI
Tatsuya Yabe460321e2010-05-25 17:50:49 -070096 if (dl_vlan_enable):
97 pkt = scapy.Ether(dst=dl_dst, src=dl_src)/ \
Dan Talayco551befa2010-07-15 17:05:32 -070098 scapy.Dot1Q(prio=dl_vlan_pcp, id=dl_vlan_cfi, vlan=dl_vlan)/ \
Christian Dickmann8b59b4b2012-09-23 16:48:30 -070099 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ihl=ip_ihl)/ \
Tatsuya Yabe460321e2010-05-25 17:50:49 -0700100 scapy.TCP(sport=tcp_sport, dport=tcp_dport)
101 else:
Christian Dickmann8b59b4b2012-09-23 16:48:30 -0700102 if not ip_options:
103 pkt = scapy.Ether(dst=dl_dst, src=dl_src)/ \
104 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ihl=ip_ihl)/ \
105 scapy.TCP(sport=tcp_sport, dport=tcp_dport)
106 else:
107 pkt = scapy.Ether(dst=dl_dst, src=dl_src)/ \
108 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ihl=ip_ihl, options=ip_options)/ \
109 scapy.TCP(sport=tcp_sport, dport=tcp_dport)
Tatsuya Yabe460321e2010-05-25 17:50:49 -0700110
Dan Talayco41eae8b2010-03-10 13:57:06 -0800111 pkt = pkt/("D" * (pktlen - len(pkt)))
112
113 return pkt
114
Rich Lane6ee7bea2012-10-26 16:19:29 -0700115def simple_udp_packet(pktlen=100,
116 dl_dst='00:01:02:03:04:05',
117 dl_src='00:06:07:08:09:0a',
118 dl_vlan_enable=False,
119 dl_vlan=0,
120 dl_vlan_pcp=0,
121 dl_vlan_cfi=0,
122 ip_src='192.168.0.1',
123 ip_dst='192.168.0.2',
124 ip_tos=0,
125 udp_sport=1234,
126 udp_dport=80,
127 ip_ihl=None,
128 ip_options=False
129 ):
130 """
131 Return a simple dataplane UDP packet
132
133 Supports a few parameters:
134 @param len Length of packet in bytes w/o CRC
135 @param dl_dst Destination MAC
136 @param dl_src Source MAC
137 @param dl_vlan_enable True if the packet is with vlan, False otherwise
138 @param dl_vlan VLAN ID
139 @param dl_vlan_pcp VLAN priority
140 @param ip_src IP source
141 @param ip_dst IP destination
142 @param ip_tos IP ToS
143 @param udp_dport UDP destination port
144 @param udp_sport UDP source port
145
146 Generates a simple UDP packet. Users shouldn't assume anything about
147 this packet other than that it is a valid ethernet/IP/UDP frame.
148 """
149
150 if MINSIZE > pktlen:
151 pktlen = MINSIZE
152
153 # Note Dot1Q.id is really CFI
154 if (dl_vlan_enable):
155 pkt = scapy.Ether(dst=dl_dst, src=dl_src)/ \
156 scapy.Dot1Q(prio=dl_vlan_pcp, id=dl_vlan_cfi, vlan=dl_vlan)/ \
157 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ihl=ip_ihl)/ \
158 scapy.UDP(sport=udp_sport, dport=udp_dport)
159 else:
160 if not ip_options:
161 pkt = scapy.Ether(dst=dl_dst, src=dl_src)/ \
162 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ihl=ip_ihl)/ \
163 scapy.UDP(sport=udp_sport, dport=udp_dport)
164 else:
165 pkt = scapy.Ether(dst=dl_dst, src=dl_src)/ \
166 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ihl=ip_ihl, options=ip_options)/ \
167 scapy.UDP(sport=udp_sport, dport=udp_dport)
168
169 pkt = pkt/("D" * (pktlen - len(pkt)))
170
171 return pkt
172
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700173def simple_icmp_packet(pktlen=60,
174 dl_dst='00:01:02:03:04:05',
175 dl_src='00:06:07:08:09:0a',
176 dl_vlan_enable=False,
177 dl_vlan=0,
178 dl_vlan_pcp=0,
179 ip_src='192.168.0.1',
180 ip_dst='192.168.0.2',
181 ip_tos=0,
182 icmp_type=8,
183 icmp_code=0
184 ):
185 """
186 Return a simple ICMP packet
187
188 Supports a few parameters:
189 @param len Length of packet in bytes w/o CRC
190 @param dl_dst Destinatino MAC
191 @param dl_src Source MAC
192 @param dl_vlan_enable True if the packet is with vlan, False otherwise
193 @param dl_vlan VLAN ID
194 @param dl_vlan_pcp VLAN priority
195 @param ip_src IP source
196 @param ip_dst IP destination
197 @param ip_tos IP ToS
198 @param icmp_type ICMP type
199 @param icmp_code ICMP code
200
201 Generates a simple ICMP ECHO REQUEST. Users
202 shouldn't assume anything about this packet other than that
203 it is a valid ethernet/ICMP frame.
204 """
Jeffrey Townsend5cb7ed32012-08-17 18:11:01 +0000205
206 if MINSIZE > pktlen:
207 pktlen = MINSIZE
208
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700209 if (dl_vlan_enable):
210 pkt = scapy.Ether(dst=dl_dst, src=dl_src)/ \
211 scapy.Dot1Q(prio=dl_vlan_pcp, id=0, vlan=dl_vlan)/ \
212 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos)/ \
213 scapy.ICMP(type=icmp_type, code=icmp_code)
214 else:
215 pkt = scapy.Ether(dst=dl_dst, src=dl_src)/ \
216 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos)/ \
217 scapy.ICMP(type=icmp_type, code=icmp_code)
218
219 pkt = pkt/("0" * (pktlen - len(pkt)))
220
221 return pkt
222
Ed Swierk0aeff8c2012-03-23 20:27:18 -0700223def simple_eth_packet(pktlen=60,
224 dl_dst='00:01:02:03:04:05',
225 dl_src='01:80:c2:00:00:00',
226 dl_type=0x88cc):
Jeffrey Townsend5cb7ed32012-08-17 18:11:01 +0000227
228 if MINSIZE > pktlen:
229 pktlen = MINSIZE
230
Ed Swierk0aeff8c2012-03-23 20:27:18 -0700231 pkt = scapy.Ether(dst=dl_dst, src=dl_src, type=dl_type)
232
233 pkt = pkt/("0" * (pktlen - len(pkt)))
234
235 return pkt
236
Shudong Zhoub7f12462012-11-20 13:01:12 -0800237def do_barrier(ctrl, timeout=-1):
Dan Talayco0fc08bd2012-04-09 16:56:18 -0700238 """
239 Do a barrier command
240 Return 0 on success, -1 on error
241 """
Dan Talayco41eae8b2010-03-10 13:57:06 -0800242 b = message.barrier_request()
Shudong Zhoub7f12462012-11-20 13:01:12 -0800243 (resp, pkt) = ctrl.transact(b, timeout=timeout)
Dan Talaycof6b94832012-04-12 21:50:57 -0700244 # We'll trust the transaction processing in the controller that xid matched
Dan Talayco0fc08bd2012-04-09 16:56:18 -0700245 if not resp:
246 return -1
247 return 0
Dan Talayco92c99122010-06-03 13:53:18 -0700248
Rich Lane9a003812012-10-04 17:17:59 -0700249def port_config_get(controller, port_no):
Dan Talayco92c99122010-06-03 13:53:18 -0700250 """
251 Get a port's configuration
252
253 Gets the switch feature configuration and grabs one port's
254 configuration
255
256 @returns (hwaddr, config, advert) The hwaddress, configuration and
257 advertised values
258 """
259 request = message.features_request()
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700260 reply, pkt = controller.transact(request)
Rich Lane9a003812012-10-04 17:17:59 -0700261 logging.debug(reply.show())
Dan Talayco92c99122010-06-03 13:53:18 -0700262 if reply is None:
Rich Lane9a003812012-10-04 17:17:59 -0700263 logging.warn("Get feature request failed")
Dan Talayco92c99122010-06-03 13:53:18 -0700264 return None, None, None
265 for idx in range(len(reply.ports)):
266 if reply.ports[idx].port_no == port_no:
267 return (reply.ports[idx].hw_addr, reply.ports[idx].config,
268 reply.ports[idx].advertised)
269
Rich Lane9a003812012-10-04 17:17:59 -0700270 logging.warn("Did not find port number for port config")
Dan Talayco92c99122010-06-03 13:53:18 -0700271 return None, None, None
272
Rich Lane9a003812012-10-04 17:17:59 -0700273def port_config_set(controller, port_no, config, mask):
Dan Talayco92c99122010-06-03 13:53:18 -0700274 """
275 Set the port configuration according the given parameters
276
277 Gets the switch feature configuration and updates one port's
278 configuration value according to config and mask
279 """
Rich Lane9a003812012-10-04 17:17:59 -0700280 logging.info("Setting port " + str(port_no) + " to config " + str(config))
Dan Talayco92c99122010-06-03 13:53:18 -0700281 request = message.features_request()
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700282 reply, pkt = controller.transact(request)
Dan Talayco92c99122010-06-03 13:53:18 -0700283 if reply is None:
284 return -1
Rich Lane9a003812012-10-04 17:17:59 -0700285 logging.debug(reply.show())
Dan Talayco92c99122010-06-03 13:53:18 -0700286 for idx in range(len(reply.ports)):
287 if reply.ports[idx].port_no == port_no:
288 break
289 if idx >= len(reply.ports):
290 return -1
291 mod = message.port_mod()
292 mod.port_no = port_no
293 mod.hw_addr = reply.ports[idx].hw_addr
294 mod.config = config
295 mod.mask = mask
296 mod.advertise = reply.ports[idx].advertised
297 rv = controller.message_send(mod)
298 return rv
299
Rich Lane2014f9b2012-10-05 15:29:40 -0700300def receive_pkt_check(dp, pkt, yes_ports, no_ports, assert_if):
Dan Talayco92c99122010-06-03 13:53:18 -0700301 """
302 Check for proper receive packets across all ports
Ken Chiang1bf01602012-04-04 10:48:23 -0700303 @param dp The dataplane object
Dan Talayco92c99122010-06-03 13:53:18 -0700304 @param pkt Expected packet; may be None if yes_ports is empty
305 @param yes_ports Set or list of ports that should recieve packet
306 @param no_ports Set or list of ports that should not receive packet
307 @param assert_if Object that implements assertXXX
308 """
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700309 exp_pkt_arg = None
Rich Lane2014f9b2012-10-05 15:29:40 -0700310 if config["relax"]:
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700311 exp_pkt_arg = pkt
312
Dan Talayco92c99122010-06-03 13:53:18 -0700313 for ofport in yes_ports:
Rich Lane9a003812012-10-04 17:17:59 -0700314 logging.debug("Checking for pkt on port " + str(ofport))
Ken Chiang1bf01602012-04-04 10:48:23 -0700315 (rcv_port, rcv_pkt, pkt_time) = dp.poll(
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700316 port_number=ofport, exp_pkt=exp_pkt_arg)
Dan Talayco92c99122010-06-03 13:53:18 -0700317 assert_if.assertTrue(rcv_pkt is not None,
318 "Did not receive pkt on " + str(ofport))
Ken Chiang1bf01602012-04-04 10:48:23 -0700319 if not dataplane.match_exp_pkt(pkt, rcv_pkt):
Rich Lane9a003812012-10-04 17:17:59 -0700320 logging.debug("Sent %s" % format_packet(pkt))
321 logging.debug("Resp %s" % format_packet(rcv_pkt))
Ken Chiang1bf01602012-04-04 10:48:23 -0700322 assert_if.assertTrue(dataplane.match_exp_pkt(pkt, rcv_pkt),
323 "Response packet does not match send packet " +
324 "on port " + str(ofport))
Dan Talayco73f84012012-10-02 09:23:18 -0700325 if len(no_ports) > 0:
326 time.sleep(1)
Dan Talayco92c99122010-06-03 13:53:18 -0700327 for ofport in no_ports:
Rich Lane9a003812012-10-04 17:17:59 -0700328 logging.debug("Negative check for pkt on port " + str(ofport))
Ken Chiang1bf01602012-04-04 10:48:23 -0700329 (rcv_port, rcv_pkt, pkt_time) = dp.poll(
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700330 port_number=ofport, timeout=1, exp_pkt=exp_pkt_arg)
Dan Talayco92c99122010-06-03 13:53:18 -0700331 assert_if.assertTrue(rcv_pkt is None,
332 "Unexpected pkt on port " + str(ofport))
Dan Talayco551befa2010-07-15 17:05:32 -0700333
334
Dan Talaycoc948d0b2012-03-23 12:17:54 -0700335def receive_pkt_verify(parent, egr_ports, exp_pkt, ing_port):
Dan Talayco551befa2010-07-15 17:05:32 -0700336 """
337 Receive a packet and verify it matches an expected value
Dan Talaycof6e76c02012-03-23 10:56:12 -0700338 @param egr_port A single port or list of ports
Dan Talayco551befa2010-07-15 17:05:32 -0700339
340 parent must implement dataplane, assertTrue and assertEqual
341 """
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700342 exp_pkt_arg = None
Rich Lane477f4812012-10-04 22:49:00 -0700343 if config["relax"]:
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700344 exp_pkt_arg = exp_pkt
345
Dan Talaycof6e76c02012-03-23 10:56:12 -0700346 if type(egr_ports) == type([]):
347 egr_port_list = egr_ports
348 else:
349 egr_port_list = [egr_ports]
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700350
Dan Talaycof6e76c02012-03-23 10:56:12 -0700351 # Expect a packet from each port on egr port list
352 for egr_port in egr_port_list:
Dan Talaycod8ae7582012-03-23 12:24:56 -0700353 check_port = egr_port
Dan Talaycoc948d0b2012-03-23 12:17:54 -0700354 if egr_port == ofp.OFPP_IN_PORT:
Dan Talaycod8ae7582012-03-23 12:24:56 -0700355 check_port = ing_port
Dan Talaycof6e76c02012-03-23 10:56:12 -0700356 (rcv_port, rcv_pkt, pkt_time) = parent.dataplane.poll(
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700357 port_number=check_port, exp_pkt=exp_pkt_arg)
Dan Talayco551befa2010-07-15 17:05:32 -0700358
Dan Talaycof6e76c02012-03-23 10:56:12 -0700359 if rcv_pkt is None:
Rich Lane9a003812012-10-04 17:17:59 -0700360 logging.error("ERROR: No packet received from " +
Dan Talaycod8ae7582012-03-23 12:24:56 -0700361 str(check_port))
Dan Talayco551befa2010-07-15 17:05:32 -0700362
Dan Talaycof6e76c02012-03-23 10:56:12 -0700363 parent.assertTrue(rcv_pkt is not None,
Dan Talaycod8ae7582012-03-23 12:24:56 -0700364 "Did not receive packet port " + str(check_port))
Rich Lane9a003812012-10-04 17:17:59 -0700365 logging.debug("Packet len " + str(len(rcv_pkt)) + " in on " +
Dan Talaycof6e76c02012-03-23 10:56:12 -0700366 str(rcv_port))
367
368 if str(exp_pkt) != str(rcv_pkt):
Rich Lane9a003812012-10-04 17:17:59 -0700369 logging.error("ERROR: Packet match failed.")
370 logging.debug("Expected len " + str(len(exp_pkt)) + ": "
Dan Talaycof6e76c02012-03-23 10:56:12 -0700371 + str(exp_pkt).encode('hex'))
Rich Lane9a003812012-10-04 17:17:59 -0700372 logging.debug("Received len " + str(len(rcv_pkt)) + ": "
Dan Talaycof6e76c02012-03-23 10:56:12 -0700373 + str(rcv_pkt).encode('hex'))
Rich Lane5d7e89a2012-10-26 16:43:13 -0700374 logging.debug("Expected packet: " + inspect_packet(scapy.Ether(str(exp_pkt))))
375 logging.debug("Received packet: " + inspect_packet(scapy.Ether(str(rcv_pkt))))
Dan Talaycof6e76c02012-03-23 10:56:12 -0700376 parent.assertEqual(str(exp_pkt), str(rcv_pkt),
Dan Talaycod8ae7582012-03-23 12:24:56 -0700377 "Packet match error on port " + str(check_port))
Dan Talaycof6e76c02012-03-23 10:56:12 -0700378
Dan Talayco551befa2010-07-15 17:05:32 -0700379def match_verify(parent, req_match, res_match):
380 """
381 Verify flow matches agree; if they disagree, report where
382
383 parent must implement assertEqual
384 Use str() to ensure content is compared and not pointers
385 """
386
387 parent.assertEqual(req_match.wildcards, res_match.wildcards,
388 'Match failed: wildcards: ' + hex(req_match.wildcards) +
389 " != " + hex(res_match.wildcards))
390 parent.assertEqual(req_match.in_port, res_match.in_port,
391 'Match failed: in_port: ' + str(req_match.in_port) +
392 " != " + str(res_match.in_port))
393 parent.assertEqual(str(req_match.dl_src), str(res_match.dl_src),
394 'Match failed: dl_src: ' + str(req_match.dl_src) +
395 " != " + str(res_match.dl_src))
396 parent.assertEqual(str(req_match.dl_dst), str(res_match.dl_dst),
397 'Match failed: dl_dst: ' + str(req_match.dl_dst) +
398 " != " + str(res_match.dl_dst))
399 parent.assertEqual(req_match.dl_vlan, res_match.dl_vlan,
400 'Match failed: dl_vlan: ' + str(req_match.dl_vlan) +
401 " != " + str(res_match.dl_vlan))
402 parent.assertEqual(req_match.dl_vlan_pcp, res_match.dl_vlan_pcp,
403 'Match failed: dl_vlan_pcp: ' +
404 str(req_match.dl_vlan_pcp) + " != " +
405 str(res_match.dl_vlan_pcp))
406 parent.assertEqual(req_match.dl_type, res_match.dl_type,
407 'Match failed: dl_type: ' + str(req_match.dl_type) +
408 " != " + str(res_match.dl_type))
409
410 if (not(req_match.wildcards & ofp.OFPFW_DL_TYPE)
411 and (req_match.dl_type == IP_ETHERTYPE)):
412 parent.assertEqual(req_match.nw_tos, res_match.nw_tos,
413 'Match failed: nw_tos: ' + str(req_match.nw_tos) +
414 " != " + str(res_match.nw_tos))
415 parent.assertEqual(req_match.nw_proto, res_match.nw_proto,
416 'Match failed: nw_proto: ' + str(req_match.nw_proto) +
417 " != " + str(res_match.nw_proto))
418 parent.assertEqual(req_match.nw_src, res_match.nw_src,
419 'Match failed: nw_src: ' + str(req_match.nw_src) +
420 " != " + str(res_match.nw_src))
421 parent.assertEqual(req_match.nw_dst, res_match.nw_dst,
422 'Match failed: nw_dst: ' + str(req_match.nw_dst) +
423 " != " + str(res_match.nw_dst))
424
425 if (not(req_match.wildcards & ofp.OFPFW_NW_PROTO)
426 and ((req_match.nw_proto == TCP_PROTOCOL)
427 or (req_match.nw_proto == UDP_PROTOCOL))):
428 parent.assertEqual(req_match.tp_src, res_match.tp_src,
429 'Match failed: tp_src: ' +
430 str(req_match.tp_src) +
431 " != " + str(res_match.tp_src))
432 parent.assertEqual(req_match.tp_dst, res_match.tp_dst,
433 'Match failed: tp_dst: ' +
434 str(req_match.tp_dst) +
435 " != " + str(res_match.tp_dst))
436
Ed Swierk99a74de2012-08-22 06:40:54 -0700437def packet_to_flow_match(parent, packet):
438 match = parse.packet_to_flow_match(packet)
439 match.wildcards |= required_wildcards(parent)
440 return match
441
442def flow_msg_create(parent, pkt, ing_port=None, action_list=None, wildcards=None,
Dan Talaycof6e76c02012-03-23 10:56:12 -0700443 egr_ports=None, egr_queue=None, check_expire=False, in_band=False):
Dan Talayco551befa2010-07-15 17:05:32 -0700444 """
445 Create a flow message
446
447 Match on packet with given wildcards.
448 See flow_match_test for other parameter descriptoins
449 @param egr_queue if not None, make the output an enqueue action
Dan Talayco677c0b72011-08-23 22:53:38 -0700450 @param in_band if True, do not wildcard ingress port
Dan Talaycof6e76c02012-03-23 10:56:12 -0700451 @param egr_ports None (drop), single port or list of ports
Dan Talayco551befa2010-07-15 17:05:32 -0700452 """
453 match = parse.packet_to_flow_match(pkt)
454 parent.assertTrue(match is not None, "Flow match from pkt failed")
Ed Swierk99a74de2012-08-22 06:40:54 -0700455 if wildcards is None:
456 wildcards = required_wildcards(parent)
Dan Talayco677c0b72011-08-23 22:53:38 -0700457 if in_band:
458 wildcards &= ~ofp.OFPFW_IN_PORT
Dan Talayco551befa2010-07-15 17:05:32 -0700459 match.wildcards = wildcards
460 match.in_port = ing_port
461
Dan Talaycof6e76c02012-03-23 10:56:12 -0700462 if type(egr_ports) == type([]):
463 egr_port_list = egr_ports
464 else:
465 egr_port_list = [egr_ports]
466
Dan Talayco551befa2010-07-15 17:05:32 -0700467 request = message.flow_mod()
468 request.match = match
469 request.buffer_id = 0xffffffff
470 if check_expire:
471 request.flags |= ofp.OFPFF_SEND_FLOW_REM
472 request.hard_timeout = 1
473
474 if action_list is not None:
475 for act in action_list:
Rich Lane9a003812012-10-04 17:17:59 -0700476 logging.debug("Adding action " + act.show())
Dan Talayco551befa2010-07-15 17:05:32 -0700477 rv = request.actions.add(act)
478 parent.assertTrue(rv, "Could not add action" + act.show())
479
480 # Set up output/enqueue action if directed
481 if egr_queue is not None:
Dan Talaycof6e76c02012-03-23 10:56:12 -0700482 parent.assertTrue(egr_ports is not None, "Egress port not set")
Dan Talayco551befa2010-07-15 17:05:32 -0700483 act = action.action_enqueue()
Dan Talaycof6e76c02012-03-23 10:56:12 -0700484 for egr_port in egr_port_list:
485 act.port = egr_port
486 act.queue_id = egr_queue
487 rv = request.actions.add(act)
488 parent.assertTrue(rv, "Could not add enqueue action " +
489 str(egr_port) + " Q: " + str(egr_queue))
490 elif egr_ports is not None:
491 for egr_port in egr_port_list:
492 act = action.action_output()
493 act.port = egr_port
494 rv = request.actions.add(act)
495 parent.assertTrue(rv, "Could not add output action " +
496 str(egr_port))
Dan Talayco551befa2010-07-15 17:05:32 -0700497
Rich Lane9a003812012-10-04 17:17:59 -0700498 logging.debug(request.show())
Dan Talayco551befa2010-07-15 17:05:32 -0700499
500 return request
501
Jeffrey Townsendf3eae9c2012-03-28 18:23:21 -0700502def flow_msg_install(parent, request, clear_table_override=None):
Dan Talayco551befa2010-07-15 17:05:32 -0700503 """
504 Install a flow mod message in the switch
505
506 @param parent Must implement controller, assertEqual, assertTrue
507 @param request The request, all set to go
508 @param clear_table If true, clear the flow table before installing
509 """
Dan Talayco8a64e332012-03-28 14:53:20 -0700510
Rich Lane2014f9b2012-10-05 15:29:40 -0700511 clear_table = test_param_get('clear_table', default=True)
Jeffrey Townsendf3eae9c2012-03-28 18:23:21 -0700512 if(clear_table_override != None):
513 clear_table = clear_table_override
514
515 if clear_table:
Rich Lane9a003812012-10-04 17:17:59 -0700516 logging.debug("Clear flow table")
517 rc = delete_all_flows(parent.controller)
Dan Talayco551befa2010-07-15 17:05:32 -0700518 parent.assertEqual(rc, 0, "Failed to delete all flows")
Dan Talayco0fc08bd2012-04-09 16:56:18 -0700519 parent.assertEqual(do_barrier(parent.controller), 0, "Barrier failed")
Dan Talayco551befa2010-07-15 17:05:32 -0700520
Rich Lane9a003812012-10-04 17:17:59 -0700521 logging.debug("Insert flow")
Dan Talayco551befa2010-07-15 17:05:32 -0700522 rv = parent.controller.message_send(request)
523 parent.assertTrue(rv != -1, "Error installing flow mod")
Dan Talayco0fc08bd2012-04-09 16:56:18 -0700524 parent.assertEqual(do_barrier(parent.controller), 0, "Barrier failed")
Dan Talayco551befa2010-07-15 17:05:32 -0700525
Ed Swierk99a74de2012-08-22 06:40:54 -0700526def flow_match_test_port_pair(parent, ing_port, egr_ports, wildcards=None,
Dan Talayco551befa2010-07-15 17:05:32 -0700527 dl_vlan=-1, pkt=None, exp_pkt=None,
Rich Lanee5779d32012-10-05 17:56:04 -0700528 action_list=None):
Dan Talayco551befa2010-07-15 17:05:32 -0700529 """
530 Flow match test on single TCP packet
Dan Talaycof6e76c02012-03-23 10:56:12 -0700531 @param egr_ports A single port or list of ports
Dan Talayco551befa2010-07-15 17:05:32 -0700532
533 Run test with packet through switch from ing_port to egr_port
534 See flow_match_test for parameter descriptions
535 """
536
Ed Swierk99a74de2012-08-22 06:40:54 -0700537 if wildcards is None:
538 wildcards = required_wildcards(parent)
Rich Lane9a003812012-10-04 17:17:59 -0700539 logging.info("Pkt match test: " + str(ing_port) + " to " +
Dan Talaycof6e76c02012-03-23 10:56:12 -0700540 str(egr_ports))
Rich Lanee5779d32012-10-05 17:56:04 -0700541 logging.debug(" WC: " + hex(wildcards) + " vlan: " + str(dl_vlan))
Dan Talayco551befa2010-07-15 17:05:32 -0700542 if pkt is None:
543 pkt = simple_tcp_packet(dl_vlan_enable=(dl_vlan >= 0), dl_vlan=dl_vlan)
544
545 request = flow_msg_create(parent, pkt, ing_port=ing_port,
Dan Talaycof6e76c02012-03-23 10:56:12 -0700546 wildcards=wildcards, egr_ports=egr_ports,
Dan Talayco551befa2010-07-15 17:05:32 -0700547 action_list=action_list)
548
549 flow_msg_install(parent, request)
550
Rich Lane9a003812012-10-04 17:17:59 -0700551 logging.debug("Send packet: " + str(ing_port) + " to " +
Dan Talaycof6e76c02012-03-23 10:56:12 -0700552 str(egr_ports))
Dan Talayco551befa2010-07-15 17:05:32 -0700553 parent.dataplane.send(ing_port, str(pkt))
554
555 if exp_pkt is None:
556 exp_pkt = pkt
Dan Talaycoc948d0b2012-03-23 12:17:54 -0700557 receive_pkt_verify(parent, egr_ports, exp_pkt, ing_port)
Dan Talayco551befa2010-07-15 17:05:32 -0700558
Dan Talaycof6e76c02012-03-23 10:56:12 -0700559def get_egr_list(parent, of_ports, how_many, exclude_list=[]):
560 """
561 Generate a list of ports avoiding those in the exclude list
Rich Lane9a003812012-10-04 17:17:59 -0700562 @param parent Supplies logging
Dan Talaycof6e76c02012-03-23 10:56:12 -0700563 @param of_ports List of OF port numbers
564 @param how_many Number of ports to be added to the list
565 @param exclude_list List of ports not to be used
566 @returns An empty list if unable to find enough ports
567 """
568
Dan Talaycoc948d0b2012-03-23 12:17:54 -0700569 if how_many == 0:
570 return []
571
Dan Talaycof6e76c02012-03-23 10:56:12 -0700572 count = 0
573 egr_ports = []
574 for egr_idx in range(len(of_ports)):
575 if of_ports[egr_idx] not in exclude_list:
576 egr_ports.append(of_ports[egr_idx])
577 count += 1
578 if count >= how_many:
579 return egr_ports
Rich Lane9a003812012-10-04 17:17:59 -0700580 logging.debug("Could not generate enough egress ports for test")
Dan Talaycof6e76c02012-03-23 10:56:12 -0700581 return []
582
Ed Swierk99a74de2012-08-22 06:40:54 -0700583def flow_match_test(parent, port_map, wildcards=None, dl_vlan=-1, pkt=None,
Rich Lanee5779d32012-10-05 17:56:04 -0700584 exp_pkt=None, action_list=None,
Dan Talaycoc948d0b2012-03-23 12:17:54 -0700585 max_test=0, egr_count=1, ing_port=False):
Dan Talayco551befa2010-07-15 17:05:32 -0700586 """
587 Run flow_match_test_port_pair on all port pairs
588
589 @param max_test If > 0 no more than this number of tests are executed.
590 @param parent Must implement controller, dataplane, assertTrue, assertEqual
Rich Lane9a003812012-10-04 17:17:59 -0700591 and logging
Dan Talayco551befa2010-07-15 17:05:32 -0700592 @param pkt If not None, use this packet for ingress
593 @param wildcards For flow match entry
Dan Talayco79184222010-11-01 12:24:29 -0700594 @param dl_vlan If not -1, and pkt is None, create a pkt w/ VLAN tag
Dan Talayco551befa2010-07-15 17:05:32 -0700595 @param exp_pkt If not None, use this as the expected output pkt; els use pkt
596 @param action_list Additional actions to add to flow mod
Dan Talaycocfa172f2012-03-23 12:03:00 -0700597 @param egr_count Number of egress ports; -1 means get from config w/ dflt 2
Dan Talayco551befa2010-07-15 17:05:32 -0700598 """
Ed Swierk99a74de2012-08-22 06:40:54 -0700599 if wildcards is None:
600 wildcards = required_wildcards(parent)
Dan Talayco551befa2010-07-15 17:05:32 -0700601 of_ports = port_map.keys()
602 of_ports.sort()
603 parent.assertTrue(len(of_ports) > 1, "Not enough ports for test")
604 test_count = 0
605
Dan Talaycocfa172f2012-03-23 12:03:00 -0700606 if egr_count == -1:
Rich Lane2014f9b2012-10-05 15:29:40 -0700607 egr_count = test_param_get('egr_count', default=2)
Dan Talaycocfa172f2012-03-23 12:03:00 -0700608
Dan Talayco551befa2010-07-15 17:05:32 -0700609 for ing_idx in range(len(of_ports)):
610 ingress_port = of_ports[ing_idx]
Dan Talaycof6e76c02012-03-23 10:56:12 -0700611 egr_ports = get_egr_list(parent, of_ports, egr_count,
612 exclude_list=[ingress_port])
Dan Talaycoc948d0b2012-03-23 12:17:54 -0700613 if ing_port:
614 egr_ports.append(ofp.OFPP_IN_PORT)
Dan Talaycof6e76c02012-03-23 10:56:12 -0700615 if len(egr_ports) == 0:
616 parent.assertTrue(0, "Failed to generate egress port list")
617
618 flow_match_test_port_pair(parent, ingress_port, egr_ports,
619 wildcards=wildcards, dl_vlan=dl_vlan,
620 pkt=pkt, exp_pkt=exp_pkt,
Rich Lanee5779d32012-10-05 17:56:04 -0700621 action_list=action_list)
Dan Talaycof6e76c02012-03-23 10:56:12 -0700622 test_count += 1
623 if (max_test > 0) and (test_count > max_test):
Rich Lane9a003812012-10-04 17:17:59 -0700624 logging.info("Ran " + str(test_count) + " tests; exiting")
Dan Talaycof6e76c02012-03-23 10:56:12 -0700625 return
Dan Talayco551befa2010-07-15 17:05:32 -0700626
Rich Lane2014f9b2012-10-05 15:29:40 -0700627def test_param_get(key, default=None):
Dan Talayco4b2bee62010-07-20 14:10:05 -0700628 """
629 Return value passed via test-params if present
630
Dan Talayco4b2bee62010-07-20 14:10:05 -0700631 @param key The lookup key
632 @param default Default value to use if not found
633
634 If the pair 'key=val' appeared in the string passed to --test-params
635 on the command line, return val (as interpreted by exec). Otherwise
636 return default value.
Dan Talaycof6e76c02012-03-23 10:56:12 -0700637
638 WARNING: TEST PARAMETERS MUST BE PYTHON IDENTIFIERS;
639 eg egr_count, not egr-count.
Dan Talayco4b2bee62010-07-20 14:10:05 -0700640 """
641 try:
642 exec config["test_params"]
643 except:
644 return default
645
646 s = "val = " + str(key)
647 try:
648 exec s
649 return val
650 except:
651 return default
652
653def action_generate(parent, field_to_mod, mod_field_vals):
654 """
655 Create an action to modify the field indicated in field_to_mod
656
657 @param parent Must implement, assertTrue
658 @param field_to_mod The field to modify as a string name
659 @param mod_field_vals Hash of values to use for modified values
660 """
661
662 act = None
663
664 if field_to_mod in ['pktlen']:
665 return None
666
667 if field_to_mod == 'dl_dst':
668 act = action.action_set_dl_dst()
669 act.dl_addr = parse.parse_mac(mod_field_vals['dl_dst'])
670 elif field_to_mod == 'dl_src':
671 act = action.action_set_dl_src()
672 act.dl_addr = parse.parse_mac(mod_field_vals['dl_src'])
673 elif field_to_mod == 'dl_vlan_enable':
674 if not mod_field_vals['dl_vlan_enable']: # Strip VLAN tag
675 act = action.action_strip_vlan()
676 # Add VLAN tag is handled by dl_vlan field
677 # Will return None in this case
678 elif field_to_mod == 'dl_vlan':
679 act = action.action_set_vlan_vid()
680 act.vlan_vid = mod_field_vals['dl_vlan']
681 elif field_to_mod == 'dl_vlan_pcp':
682 act = action.action_set_vlan_pcp()
683 act.vlan_pcp = mod_field_vals['dl_vlan_pcp']
684 elif field_to_mod == 'ip_src':
685 act = action.action_set_nw_src()
686 act.nw_addr = parse.parse_ip(mod_field_vals['ip_src'])
687 elif field_to_mod == 'ip_dst':
688 act = action.action_set_nw_dst()
689 act.nw_addr = parse.parse_ip(mod_field_vals['ip_dst'])
690 elif field_to_mod == 'ip_tos':
691 act = action.action_set_nw_tos()
692 act.nw_tos = mod_field_vals['ip_tos']
693 elif field_to_mod == 'tcp_sport':
694 act = action.action_set_tp_src()
695 act.tp_port = mod_field_vals['tcp_sport']
696 elif field_to_mod == 'tcp_dport':
697 act = action.action_set_tp_dst()
698 act.tp_port = mod_field_vals['tcp_dport']
Rich Lane110e0e32012-10-26 16:21:46 -0700699 elif field_to_mod == 'udp_sport':
700 act = action.action_set_tp_src()
701 act.tp_port = mod_field_vals['udp_sport']
702 elif field_to_mod == 'udp_dport':
703 act = action.action_set_tp_dst()
704 act.tp_port = mod_field_vals['udp_dport']
Dan Talayco4b2bee62010-07-20 14:10:05 -0700705 else:
706 parent.assertTrue(0, "Unknown field to modify: " + str(field_to_mod))
707
708 return act
709
710def pkt_action_setup(parent, start_field_vals={}, mod_field_vals={},
Rich Lane110e0e32012-10-26 16:21:46 -0700711 mod_fields=[], tp="tcp", check_test_params=False):
Dan Talayco4b2bee62010-07-20 14:10:05 -0700712 """
713 Set up the ingress and expected packet and action list for a test
714
Rich Lane2014f9b2012-10-05 15:29:40 -0700715 @param parent Must implement assertTrue
Dan Talayco4b2bee62010-07-20 14:10:05 -0700716 @param start_field_values Field values to use for ingress packet (optional)
717 @param mod_field_values Field values to use for modified packet (optional)
718 @param mod_fields The list of fields to be modified by the switch in the test.
719 @params check_test_params If True, will check the parameters vid, add_vlan
720 and strip_vlan from the command line.
721
722 Returns a triple: pkt-to-send, expected-pkt, action-list
723 """
724
725 new_actions = []
726
Dan Talayco4b2bee62010-07-20 14:10:05 -0700727 base_pkt_params = {}
728 base_pkt_params['pktlen'] = 100
729 base_pkt_params['dl_dst'] = '00:DE:F0:12:34:56'
730 base_pkt_params['dl_src'] = '00:23:45:67:89:AB'
731 base_pkt_params['dl_vlan_enable'] = False
732 base_pkt_params['dl_vlan'] = 2
733 base_pkt_params['dl_vlan_pcp'] = 0
734 base_pkt_params['ip_src'] = '192.168.0.1'
735 base_pkt_params['ip_dst'] = '192.168.0.2'
736 base_pkt_params['ip_tos'] = 0
Rich Lane110e0e32012-10-26 16:21:46 -0700737 if tp == "tcp":
738 base_pkt_params['tcp_sport'] = 1234
739 base_pkt_params['tcp_dport'] = 80
740 elif tp == "udp":
741 base_pkt_params['udp_sport'] = 1234
742 base_pkt_params['udp_dport'] = 80
Dan Talayco4b2bee62010-07-20 14:10:05 -0700743 for keyname in start_field_vals.keys():
744 base_pkt_params[keyname] = start_field_vals[keyname]
745
746 mod_pkt_params = {}
747 mod_pkt_params['pktlen'] = 100
748 mod_pkt_params['dl_dst'] = '00:21:0F:ED:CB:A9'
749 mod_pkt_params['dl_src'] = '00:ED:CB:A9:87:65'
750 mod_pkt_params['dl_vlan_enable'] = False
751 mod_pkt_params['dl_vlan'] = 3
752 mod_pkt_params['dl_vlan_pcp'] = 7
753 mod_pkt_params['ip_src'] = '10.20.30.40'
754 mod_pkt_params['ip_dst'] = '50.60.70.80'
755 mod_pkt_params['ip_tos'] = 0xf0
Rich Lane110e0e32012-10-26 16:21:46 -0700756 if tp == "tcp":
757 mod_pkt_params['tcp_sport'] = 4321
758 mod_pkt_params['tcp_dport'] = 8765
759 elif tp == "udp":
760 mod_pkt_params['udp_sport'] = 4321
761 mod_pkt_params['udp_dport'] = 8765
Dan Talayco4b2bee62010-07-20 14:10:05 -0700762 for keyname in mod_field_vals.keys():
763 mod_pkt_params[keyname] = mod_field_vals[keyname]
764
765 # Check for test param modifications
766 strip = False
767 if check_test_params:
Rich Lane2014f9b2012-10-05 15:29:40 -0700768 add_vlan = test_param_get('add_vlan')
769 strip_vlan = test_param_get('strip_vlan')
770 vid = test_param_get('vid')
Dan Talayco4b2bee62010-07-20 14:10:05 -0700771
772 if add_vlan and strip_vlan:
773 parent.assertTrue(0, "Add and strip VLAN both specified")
774
775 if vid:
776 base_pkt_params['dl_vlan_enable'] = True
777 base_pkt_params['dl_vlan'] = vid
778 if 'dl_vlan' in mod_fields:
779 mod_pkt_params['dl_vlan'] = vid + 1
780
781 if add_vlan:
782 base_pkt_params['dl_vlan_enable'] = False
783 mod_pkt_params['dl_vlan_enable'] = True
784 mod_pkt_params['pktlen'] = base_pkt_params['pktlen'] + 4
785 mod_fields.append('pktlen')
786 mod_fields.append('dl_vlan_enable')
787 if 'dl_vlan' not in mod_fields:
788 mod_fields.append('dl_vlan')
789 elif strip_vlan:
790 base_pkt_params['dl_vlan_enable'] = True
791 mod_pkt_params['dl_vlan_enable'] = False
792 mod_pkt_params['pktlen'] = base_pkt_params['pktlen'] - 4
793 mod_fields.append('dl_vlan_enable')
794 mod_fields.append('pktlen')
795
Rich Lane110e0e32012-10-26 16:21:46 -0700796 if tp == "tcp":
797 packet_builder = simple_tcp_packet
798 elif tp == "udp":
799 packet_builder = simple_udp_packet
800 else:
801 raise NotImplementedError("unknown transport protocol %s" % tp)
802
Dan Talayco4b2bee62010-07-20 14:10:05 -0700803 # Build the ingress packet
Rich Lane110e0e32012-10-26 16:21:46 -0700804 ingress_pkt = packet_builder(**base_pkt_params)
Dan Talayco4b2bee62010-07-20 14:10:05 -0700805
806 # Build the expected packet, modifying the indicated fields
807 for item in mod_fields:
808 base_pkt_params[item] = mod_pkt_params[item]
809 act = action_generate(parent, item, mod_pkt_params)
810 if act:
811 new_actions.append(act)
812
Rich Lane110e0e32012-10-26 16:21:46 -0700813 expected_pkt = packet_builder(**base_pkt_params)
Dan Talayco4b2bee62010-07-20 14:10:05 -0700814
815 return (ingress_pkt, expected_pkt, new_actions)
Dan Talayco677c0b72011-08-23 22:53:38 -0700816
817# Generate a simple "drop" flow mod
818# If in_band is true, then only drop from first test port
819def flow_mod_gen(port_map, in_band):
820 request = message.flow_mod()
821 request.match.wildcards = ofp.OFPFW_ALL
822 if in_band:
823 request.match.wildcards = ofp.OFPFW_ALL - ofp.OFPFW_IN_PORT
824 for of_port, ifname in port_map.items(): # Grab first port
825 break
826 request.match.in_port = of_port
827 request.buffer_id = 0xffffffff
828 return request
Dan Talaycoba3745c2010-07-21 21:51:08 -0700829
830def skip_message_emit(parent, s):
831 """
832 Print out a 'skipped' message to stderr
833
834 @param s The string to print out to the log file
Rich Lane9a003812012-10-04 17:17:59 -0700835 @param parent Must implement config object
Dan Talaycoba3745c2010-07-21 21:51:08 -0700836 """
837 global skipped_test_count
838
839 skipped_test_count += 1
Rich Lane9a003812012-10-04 17:17:59 -0700840 logging.info("Skipping: " + s)
Rich Lane477f4812012-10-04 22:49:00 -0700841 if config["dbg_level"] < logging.WARNING:
Dan Talaycoba3745c2010-07-21 21:51:08 -0700842 sys.stderr.write("(skipped) ")
843 else:
844 sys.stderr.write("(S)")
Dan Talayco677c0b72011-08-23 22:53:38 -0700845
Dan Talayco8a64e332012-03-28 14:53:20 -0700846
847def all_stats_get(parent):
848 """
849 Get the aggregate stats for all flows in the table
850 @param parent Test instance with controller connection and assert
851 @returns dict with keys flows, packets, bytes, active (flows),
852 lookups, matched
853 """
854 stat_req = message.aggregate_stats_request()
855 stat_req.match = ofp.ofp_match()
856 stat_req.match.wildcards = ofp.OFPFW_ALL
857 stat_req.table_id = 0xff
858 stat_req.out_port = ofp.OFPP_NONE
859
860 rv = {}
861
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700862 (reply, pkt) = parent.controller.transact(stat_req)
Dan Talayco8a64e332012-03-28 14:53:20 -0700863 parent.assertTrue(len(reply.stats) == 1, "Did not receive flow stats reply")
864
865 for obj in reply.stats:
866 (rv["flows"], rv["packets"], rv["bytes"]) = (obj.flow_count,
867 obj.packet_count, obj.byte_count)
868 break
869
870 request = message.table_stats_request()
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700871 (reply , pkt) = parent.controller.transact(request)
Dan Talayco8a64e332012-03-28 14:53:20 -0700872
873
874 (rv["active"], rv["lookups"], rv["matched"]) = (0,0,0)
875 for obj in reply.stats:
876 rv["active"] += obj.active_count
877 rv["lookups"] += obj.lookup_count
878 rv["matched"] += obj.matched_count
879
880 return rv
Dan Talayco2baf8b52012-03-30 09:55:42 -0700881
882FILTER=''.join([(len(repr(chr(x)))==3) and chr(x) or '.'
883 for x in range(256)])
884
885def hex_dump_buffer(src, length=16):
886 """
887 Convert src to a hex dump string and return the string
888 @param src The source buffer
889 @param length The number of bytes shown in each line
890 @returns A string showing the hex dump
891 """
Dan Talaycoc516fa02012-04-12 22:28:43 -0700892 result = ["\n"]
Dan Talayco2baf8b52012-03-30 09:55:42 -0700893 for i in xrange(0, len(src), length):
894 chars = src[i:i+length]
895 hex = ' '.join(["%02x" % ord(x) for x in chars])
896 printable = ''.join(["%s" % ((ord(x) <= 127 and
897 FILTER[ord(x)]) or '.') for x in chars])
898 result.append("%04x %-*s %s\n" % (i, length*3, hex, printable))
899 return ''.join(result)
900
901def format_packet(pkt):
902 return "Packet length %d \n%s" % (len(str(pkt)),
903 hex_dump_buffer(str(pkt)))
Rich Lane5d7e89a2012-10-26 16:43:13 -0700904
905def inspect_packet(pkt):
906 """
907 Wrapper around scapy's show() method.
908 @returns A string showing the dissected packet.
909 """
910 from cStringIO import StringIO
911 out = None
912 backup = sys.stdout
913 try:
914 sys.stdout = StringIO()
915 pkt.show2()
916 out = sys.stdout.getvalue()
917 sys.stdout.close()
918 finally:
919 sys.stdout = backup
920 return out