blob: 83a8b6858a2264b2634ffe88374cffdfac6a6066 [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)))
Christian Dickmann8b59b4b2012-09-23 16:48:30 -0700112
113 #print pkt.show()
114 #print scapy.Ether(str(pkt)).show()
Dan Talayco41eae8b2010-03-10 13:57:06 -0800115
116 return pkt
117
Rich Lane6ee7bea2012-10-26 16:19:29 -0700118def simple_udp_packet(pktlen=100,
119 dl_dst='00:01:02:03:04:05',
120 dl_src='00:06:07:08:09:0a',
121 dl_vlan_enable=False,
122 dl_vlan=0,
123 dl_vlan_pcp=0,
124 dl_vlan_cfi=0,
125 ip_src='192.168.0.1',
126 ip_dst='192.168.0.2',
127 ip_tos=0,
128 udp_sport=1234,
129 udp_dport=80,
130 ip_ihl=None,
131 ip_options=False
132 ):
133 """
134 Return a simple dataplane UDP packet
135
136 Supports a few parameters:
137 @param len Length of packet in bytes w/o CRC
138 @param dl_dst Destination MAC
139 @param dl_src Source MAC
140 @param dl_vlan_enable True if the packet is with vlan, False otherwise
141 @param dl_vlan VLAN ID
142 @param dl_vlan_pcp VLAN priority
143 @param ip_src IP source
144 @param ip_dst IP destination
145 @param ip_tos IP ToS
146 @param udp_dport UDP destination port
147 @param udp_sport UDP source port
148
149 Generates a simple UDP packet. Users shouldn't assume anything about
150 this packet other than that it is a valid ethernet/IP/UDP frame.
151 """
152
153 if MINSIZE > pktlen:
154 pktlen = MINSIZE
155
156 # Note Dot1Q.id is really CFI
157 if (dl_vlan_enable):
158 pkt = scapy.Ether(dst=dl_dst, src=dl_src)/ \
159 scapy.Dot1Q(prio=dl_vlan_pcp, id=dl_vlan_cfi, vlan=dl_vlan)/ \
160 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ihl=ip_ihl)/ \
161 scapy.UDP(sport=udp_sport, dport=udp_dport)
162 else:
163 if not ip_options:
164 pkt = scapy.Ether(dst=dl_dst, src=dl_src)/ \
165 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ihl=ip_ihl)/ \
166 scapy.UDP(sport=udp_sport, dport=udp_dport)
167 else:
168 pkt = scapy.Ether(dst=dl_dst, src=dl_src)/ \
169 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ihl=ip_ihl, options=ip_options)/ \
170 scapy.UDP(sport=udp_sport, dport=udp_dport)
171
172 pkt = pkt/("D" * (pktlen - len(pkt)))
173
174 return pkt
175
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700176def simple_icmp_packet(pktlen=60,
177 dl_dst='00:01:02:03:04:05',
178 dl_src='00:06:07:08:09:0a',
179 dl_vlan_enable=False,
180 dl_vlan=0,
181 dl_vlan_pcp=0,
182 ip_src='192.168.0.1',
183 ip_dst='192.168.0.2',
184 ip_tos=0,
185 icmp_type=8,
186 icmp_code=0
187 ):
188 """
189 Return a simple ICMP packet
190
191 Supports a few parameters:
192 @param len Length of packet in bytes w/o CRC
193 @param dl_dst Destinatino MAC
194 @param dl_src Source MAC
195 @param dl_vlan_enable True if the packet is with vlan, False otherwise
196 @param dl_vlan VLAN ID
197 @param dl_vlan_pcp VLAN priority
198 @param ip_src IP source
199 @param ip_dst IP destination
200 @param ip_tos IP ToS
201 @param icmp_type ICMP type
202 @param icmp_code ICMP code
203
204 Generates a simple ICMP ECHO REQUEST. Users
205 shouldn't assume anything about this packet other than that
206 it is a valid ethernet/ICMP frame.
207 """
Jeffrey Townsend5cb7ed32012-08-17 18:11:01 +0000208
209 if MINSIZE > pktlen:
210 pktlen = MINSIZE
211
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700212 if (dl_vlan_enable):
213 pkt = scapy.Ether(dst=dl_dst, src=dl_src)/ \
214 scapy.Dot1Q(prio=dl_vlan_pcp, id=0, vlan=dl_vlan)/ \
215 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos)/ \
216 scapy.ICMP(type=icmp_type, code=icmp_code)
217 else:
218 pkt = scapy.Ether(dst=dl_dst, src=dl_src)/ \
219 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos)/ \
220 scapy.ICMP(type=icmp_type, code=icmp_code)
221
222 pkt = pkt/("0" * (pktlen - len(pkt)))
223
224 return pkt
225
Ed Swierk0aeff8c2012-03-23 20:27:18 -0700226def simple_eth_packet(pktlen=60,
227 dl_dst='00:01:02:03:04:05',
228 dl_src='01:80:c2:00:00:00',
229 dl_type=0x88cc):
Jeffrey Townsend5cb7ed32012-08-17 18:11:01 +0000230
231 if MINSIZE > pktlen:
232 pktlen = MINSIZE
233
Ed Swierk0aeff8c2012-03-23 20:27:18 -0700234 pkt = scapy.Ether(dst=dl_dst, src=dl_src, type=dl_type)
235
236 pkt = pkt/("0" * (pktlen - len(pkt)))
237
238 return pkt
239
Dan Talayco41eae8b2010-03-10 13:57:06 -0800240def do_barrier(ctrl):
Dan Talayco0fc08bd2012-04-09 16:56:18 -0700241 """
242 Do a barrier command
243 Return 0 on success, -1 on error
244 """
Dan Talayco41eae8b2010-03-10 13:57:06 -0800245 b = message.barrier_request()
Dan Talaycof6b94832012-04-12 21:50:57 -0700246 (resp, pkt) = ctrl.transact(b)
247 # We'll trust the transaction processing in the controller that xid matched
Dan Talayco0fc08bd2012-04-09 16:56:18 -0700248 if not resp:
249 return -1
250 return 0
Dan Talayco92c99122010-06-03 13:53:18 -0700251
Rich Lane9a003812012-10-04 17:17:59 -0700252def port_config_get(controller, port_no):
Dan Talayco92c99122010-06-03 13:53:18 -0700253 """
254 Get a port's configuration
255
256 Gets the switch feature configuration and grabs one port's
257 configuration
258
259 @returns (hwaddr, config, advert) The hwaddress, configuration and
260 advertised values
261 """
262 request = message.features_request()
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700263 reply, pkt = controller.transact(request)
Rich Lane9a003812012-10-04 17:17:59 -0700264 logging.debug(reply.show())
Dan Talayco92c99122010-06-03 13:53:18 -0700265 if reply is None:
Rich Lane9a003812012-10-04 17:17:59 -0700266 logging.warn("Get feature request failed")
Dan Talayco92c99122010-06-03 13:53:18 -0700267 return None, None, None
268 for idx in range(len(reply.ports)):
269 if reply.ports[idx].port_no == port_no:
270 return (reply.ports[idx].hw_addr, reply.ports[idx].config,
271 reply.ports[idx].advertised)
272
Rich Lane9a003812012-10-04 17:17:59 -0700273 logging.warn("Did not find port number for port config")
Dan Talayco92c99122010-06-03 13:53:18 -0700274 return None, None, None
275
Rich Lane9a003812012-10-04 17:17:59 -0700276def port_config_set(controller, port_no, config, mask):
Dan Talayco92c99122010-06-03 13:53:18 -0700277 """
278 Set the port configuration according the given parameters
279
280 Gets the switch feature configuration and updates one port's
281 configuration value according to config and mask
282 """
Rich Lane9a003812012-10-04 17:17:59 -0700283 logging.info("Setting port " + str(port_no) + " to config " + str(config))
Dan Talayco92c99122010-06-03 13:53:18 -0700284 request = message.features_request()
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700285 reply, pkt = controller.transact(request)
Dan Talayco92c99122010-06-03 13:53:18 -0700286 if reply is None:
287 return -1
Rich Lane9a003812012-10-04 17:17:59 -0700288 logging.debug(reply.show())
Dan Talayco92c99122010-06-03 13:53:18 -0700289 for idx in range(len(reply.ports)):
290 if reply.ports[idx].port_no == port_no:
291 break
292 if idx >= len(reply.ports):
293 return -1
294 mod = message.port_mod()
295 mod.port_no = port_no
296 mod.hw_addr = reply.ports[idx].hw_addr
297 mod.config = config
298 mod.mask = mask
299 mod.advertise = reply.ports[idx].advertised
300 rv = controller.message_send(mod)
301 return rv
302
Rich Lane2014f9b2012-10-05 15:29:40 -0700303def receive_pkt_check(dp, pkt, yes_ports, no_ports, assert_if):
Dan Talayco92c99122010-06-03 13:53:18 -0700304 """
305 Check for proper receive packets across all ports
Ken Chiang1bf01602012-04-04 10:48:23 -0700306 @param dp The dataplane object
Dan Talayco92c99122010-06-03 13:53:18 -0700307 @param pkt Expected packet; may be None if yes_ports is empty
308 @param yes_ports Set or list of ports that should recieve packet
309 @param no_ports Set or list of ports that should not receive packet
310 @param assert_if Object that implements assertXXX
311 """
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700312 exp_pkt_arg = None
Rich Lane2014f9b2012-10-05 15:29:40 -0700313 if config["relax"]:
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700314 exp_pkt_arg = pkt
315
Dan Talayco92c99122010-06-03 13:53:18 -0700316 for ofport in yes_ports:
Rich Lane9a003812012-10-04 17:17:59 -0700317 logging.debug("Checking for pkt on port " + str(ofport))
Ken Chiang1bf01602012-04-04 10:48:23 -0700318 (rcv_port, rcv_pkt, pkt_time) = dp.poll(
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700319 port_number=ofport, exp_pkt=exp_pkt_arg)
Dan Talayco92c99122010-06-03 13:53:18 -0700320 assert_if.assertTrue(rcv_pkt is not None,
321 "Did not receive pkt on " + str(ofport))
Ken Chiang1bf01602012-04-04 10:48:23 -0700322 if not dataplane.match_exp_pkt(pkt, rcv_pkt):
Rich Lane9a003812012-10-04 17:17:59 -0700323 logging.debug("Sent %s" % format_packet(pkt))
324 logging.debug("Resp %s" % format_packet(rcv_pkt))
Ken Chiang1bf01602012-04-04 10:48:23 -0700325 assert_if.assertTrue(dataplane.match_exp_pkt(pkt, rcv_pkt),
326 "Response packet does not match send packet " +
327 "on port " + str(ofport))
Dan Talayco73f84012012-10-02 09:23:18 -0700328 if len(no_ports) > 0:
329 time.sleep(1)
Dan Talayco92c99122010-06-03 13:53:18 -0700330 for ofport in no_ports:
Rich Lane9a003812012-10-04 17:17:59 -0700331 logging.debug("Negative check for pkt on port " + str(ofport))
Ken Chiang1bf01602012-04-04 10:48:23 -0700332 (rcv_port, rcv_pkt, pkt_time) = dp.poll(
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700333 port_number=ofport, timeout=1, exp_pkt=exp_pkt_arg)
Dan Talayco92c99122010-06-03 13:53:18 -0700334 assert_if.assertTrue(rcv_pkt is None,
335 "Unexpected pkt on port " + str(ofport))
Dan Talayco551befa2010-07-15 17:05:32 -0700336
337
Dan Talaycoc948d0b2012-03-23 12:17:54 -0700338def receive_pkt_verify(parent, egr_ports, exp_pkt, ing_port):
Dan Talayco551befa2010-07-15 17:05:32 -0700339 """
340 Receive a packet and verify it matches an expected value
Dan Talaycof6e76c02012-03-23 10:56:12 -0700341 @param egr_port A single port or list of ports
Dan Talayco551befa2010-07-15 17:05:32 -0700342
343 parent must implement dataplane, assertTrue and assertEqual
344 """
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700345 exp_pkt_arg = None
Rich Lane477f4812012-10-04 22:49:00 -0700346 if config["relax"]:
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700347 exp_pkt_arg = exp_pkt
348
Dan Talaycof6e76c02012-03-23 10:56:12 -0700349 if type(egr_ports) == type([]):
350 egr_port_list = egr_ports
351 else:
352 egr_port_list = [egr_ports]
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700353
Dan Talaycof6e76c02012-03-23 10:56:12 -0700354 # Expect a packet from each port on egr port list
355 for egr_port in egr_port_list:
Dan Talaycod8ae7582012-03-23 12:24:56 -0700356 check_port = egr_port
Dan Talaycoc948d0b2012-03-23 12:17:54 -0700357 if egr_port == ofp.OFPP_IN_PORT:
Dan Talaycod8ae7582012-03-23 12:24:56 -0700358 check_port = ing_port
Dan Talaycof6e76c02012-03-23 10:56:12 -0700359 (rcv_port, rcv_pkt, pkt_time) = parent.dataplane.poll(
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700360 port_number=check_port, exp_pkt=exp_pkt_arg)
Dan Talayco551befa2010-07-15 17:05:32 -0700361
Dan Talaycof6e76c02012-03-23 10:56:12 -0700362 if rcv_pkt is None:
Rich Lane9a003812012-10-04 17:17:59 -0700363 logging.error("ERROR: No packet received from " +
Dan Talaycod8ae7582012-03-23 12:24:56 -0700364 str(check_port))
Dan Talayco551befa2010-07-15 17:05:32 -0700365
Dan Talaycof6e76c02012-03-23 10:56:12 -0700366 parent.assertTrue(rcv_pkt is not None,
Dan Talaycod8ae7582012-03-23 12:24:56 -0700367 "Did not receive packet port " + str(check_port))
Rich Lane9a003812012-10-04 17:17:59 -0700368 logging.debug("Packet len " + str(len(rcv_pkt)) + " in on " +
Dan Talaycof6e76c02012-03-23 10:56:12 -0700369 str(rcv_port))
370
371 if str(exp_pkt) != str(rcv_pkt):
Rich Lane9a003812012-10-04 17:17:59 -0700372 logging.error("ERROR: Packet match failed.")
373 logging.debug("Expected len " + str(len(exp_pkt)) + ": "
Dan Talaycof6e76c02012-03-23 10:56:12 -0700374 + str(exp_pkt).encode('hex'))
Rich Lane9a003812012-10-04 17:17:59 -0700375 logging.debug("Received len " + str(len(rcv_pkt)) + ": "
Dan Talaycof6e76c02012-03-23 10:56:12 -0700376 + str(rcv_pkt).encode('hex'))
377 parent.assertEqual(str(exp_pkt), str(rcv_pkt),
Dan Talaycod8ae7582012-03-23 12:24:56 -0700378 "Packet match error on port " + str(check_port))
Dan Talaycof6e76c02012-03-23 10:56:12 -0700379
Dan Talayco551befa2010-07-15 17:05:32 -0700380def match_verify(parent, req_match, res_match):
381 """
382 Verify flow matches agree; if they disagree, report where
383
384 parent must implement assertEqual
385 Use str() to ensure content is compared and not pointers
386 """
387
388 parent.assertEqual(req_match.wildcards, res_match.wildcards,
389 'Match failed: wildcards: ' + hex(req_match.wildcards) +
390 " != " + hex(res_match.wildcards))
391 parent.assertEqual(req_match.in_port, res_match.in_port,
392 'Match failed: in_port: ' + str(req_match.in_port) +
393 " != " + str(res_match.in_port))
394 parent.assertEqual(str(req_match.dl_src), str(res_match.dl_src),
395 'Match failed: dl_src: ' + str(req_match.dl_src) +
396 " != " + str(res_match.dl_src))
397 parent.assertEqual(str(req_match.dl_dst), str(res_match.dl_dst),
398 'Match failed: dl_dst: ' + str(req_match.dl_dst) +
399 " != " + str(res_match.dl_dst))
400 parent.assertEqual(req_match.dl_vlan, res_match.dl_vlan,
401 'Match failed: dl_vlan: ' + str(req_match.dl_vlan) +
402 " != " + str(res_match.dl_vlan))
403 parent.assertEqual(req_match.dl_vlan_pcp, res_match.dl_vlan_pcp,
404 'Match failed: dl_vlan_pcp: ' +
405 str(req_match.dl_vlan_pcp) + " != " +
406 str(res_match.dl_vlan_pcp))
407 parent.assertEqual(req_match.dl_type, res_match.dl_type,
408 'Match failed: dl_type: ' + str(req_match.dl_type) +
409 " != " + str(res_match.dl_type))
410
411 if (not(req_match.wildcards & ofp.OFPFW_DL_TYPE)
412 and (req_match.dl_type == IP_ETHERTYPE)):
413 parent.assertEqual(req_match.nw_tos, res_match.nw_tos,
414 'Match failed: nw_tos: ' + str(req_match.nw_tos) +
415 " != " + str(res_match.nw_tos))
416 parent.assertEqual(req_match.nw_proto, res_match.nw_proto,
417 'Match failed: nw_proto: ' + str(req_match.nw_proto) +
418 " != " + str(res_match.nw_proto))
419 parent.assertEqual(req_match.nw_src, res_match.nw_src,
420 'Match failed: nw_src: ' + str(req_match.nw_src) +
421 " != " + str(res_match.nw_src))
422 parent.assertEqual(req_match.nw_dst, res_match.nw_dst,
423 'Match failed: nw_dst: ' + str(req_match.nw_dst) +
424 " != " + str(res_match.nw_dst))
425
426 if (not(req_match.wildcards & ofp.OFPFW_NW_PROTO)
427 and ((req_match.nw_proto == TCP_PROTOCOL)
428 or (req_match.nw_proto == UDP_PROTOCOL))):
429 parent.assertEqual(req_match.tp_src, res_match.tp_src,
430 'Match failed: tp_src: ' +
431 str(req_match.tp_src) +
432 " != " + str(res_match.tp_src))
433 parent.assertEqual(req_match.tp_dst, res_match.tp_dst,
434 'Match failed: tp_dst: ' +
435 str(req_match.tp_dst) +
436 " != " + str(res_match.tp_dst))
437
Ed Swierk99a74de2012-08-22 06:40:54 -0700438def packet_to_flow_match(parent, packet):
439 match = parse.packet_to_flow_match(packet)
440 match.wildcards |= required_wildcards(parent)
441 return match
442
443def flow_msg_create(parent, pkt, ing_port=None, action_list=None, wildcards=None,
Dan Talaycof6e76c02012-03-23 10:56:12 -0700444 egr_ports=None, egr_queue=None, check_expire=False, in_band=False):
Dan Talayco551befa2010-07-15 17:05:32 -0700445 """
446 Create a flow message
447
448 Match on packet with given wildcards.
449 See flow_match_test for other parameter descriptoins
450 @param egr_queue if not None, make the output an enqueue action
Dan Talayco677c0b72011-08-23 22:53:38 -0700451 @param in_band if True, do not wildcard ingress port
Dan Talaycof6e76c02012-03-23 10:56:12 -0700452 @param egr_ports None (drop), single port or list of ports
Dan Talayco551befa2010-07-15 17:05:32 -0700453 """
454 match = parse.packet_to_flow_match(pkt)
455 parent.assertTrue(match is not None, "Flow match from pkt failed")
Ed Swierk99a74de2012-08-22 06:40:54 -0700456 if wildcards is None:
457 wildcards = required_wildcards(parent)
Dan Talayco677c0b72011-08-23 22:53:38 -0700458 if in_band:
459 wildcards &= ~ofp.OFPFW_IN_PORT
Dan Talayco551befa2010-07-15 17:05:32 -0700460 match.wildcards = wildcards
461 match.in_port = ing_port
462
Dan Talaycof6e76c02012-03-23 10:56:12 -0700463 if type(egr_ports) == type([]):
464 egr_port_list = egr_ports
465 else:
466 egr_port_list = [egr_ports]
467
Dan Talayco551befa2010-07-15 17:05:32 -0700468 request = message.flow_mod()
469 request.match = match
470 request.buffer_id = 0xffffffff
471 if check_expire:
472 request.flags |= ofp.OFPFF_SEND_FLOW_REM
473 request.hard_timeout = 1
474
475 if action_list is not None:
476 for act in action_list:
Rich Lane9a003812012-10-04 17:17:59 -0700477 logging.debug("Adding action " + act.show())
Dan Talayco551befa2010-07-15 17:05:32 -0700478 rv = request.actions.add(act)
479 parent.assertTrue(rv, "Could not add action" + act.show())
480
481 # Set up output/enqueue action if directed
482 if egr_queue is not None:
Dan Talaycof6e76c02012-03-23 10:56:12 -0700483 parent.assertTrue(egr_ports is not None, "Egress port not set")
Dan Talayco551befa2010-07-15 17:05:32 -0700484 act = action.action_enqueue()
Dan Talaycof6e76c02012-03-23 10:56:12 -0700485 for egr_port in egr_port_list:
486 act.port = egr_port
487 act.queue_id = egr_queue
488 rv = request.actions.add(act)
489 parent.assertTrue(rv, "Could not add enqueue action " +
490 str(egr_port) + " Q: " + str(egr_queue))
491 elif egr_ports is not None:
492 for egr_port in egr_port_list:
493 act = action.action_output()
494 act.port = egr_port
495 rv = request.actions.add(act)
496 parent.assertTrue(rv, "Could not add output action " +
497 str(egr_port))
Dan Talayco551befa2010-07-15 17:05:32 -0700498
Rich Lane9a003812012-10-04 17:17:59 -0700499 logging.debug(request.show())
Dan Talayco551befa2010-07-15 17:05:32 -0700500
501 return request
502
Jeffrey Townsendf3eae9c2012-03-28 18:23:21 -0700503def flow_msg_install(parent, request, clear_table_override=None):
Dan Talayco551befa2010-07-15 17:05:32 -0700504 """
505 Install a flow mod message in the switch
506
507 @param parent Must implement controller, assertEqual, assertTrue
508 @param request The request, all set to go
509 @param clear_table If true, clear the flow table before installing
510 """
Dan Talayco8a64e332012-03-28 14:53:20 -0700511
Rich Lane2014f9b2012-10-05 15:29:40 -0700512 clear_table = test_param_get('clear_table', default=True)
Jeffrey Townsendf3eae9c2012-03-28 18:23:21 -0700513 if(clear_table_override != None):
514 clear_table = clear_table_override
515
516 if clear_table:
Rich Lane9a003812012-10-04 17:17:59 -0700517 logging.debug("Clear flow table")
518 rc = delete_all_flows(parent.controller)
Dan Talayco551befa2010-07-15 17:05:32 -0700519 parent.assertEqual(rc, 0, "Failed to delete all flows")
Dan Talayco0fc08bd2012-04-09 16:56:18 -0700520 parent.assertEqual(do_barrier(parent.controller), 0, "Barrier failed")
Dan Talayco551befa2010-07-15 17:05:32 -0700521
Rich Lane9a003812012-10-04 17:17:59 -0700522 logging.debug("Insert flow")
Dan Talayco551befa2010-07-15 17:05:32 -0700523 rv = parent.controller.message_send(request)
524 parent.assertTrue(rv != -1, "Error installing flow mod")
Dan Talayco0fc08bd2012-04-09 16:56:18 -0700525 parent.assertEqual(do_barrier(parent.controller), 0, "Barrier failed")
Dan Talayco551befa2010-07-15 17:05:32 -0700526
Ed Swierk99a74de2012-08-22 06:40:54 -0700527def flow_match_test_port_pair(parent, ing_port, egr_ports, wildcards=None,
Dan Talayco551befa2010-07-15 17:05:32 -0700528 dl_vlan=-1, pkt=None, exp_pkt=None,
Rich Lanee5779d32012-10-05 17:56:04 -0700529 action_list=None):
Dan Talayco551befa2010-07-15 17:05:32 -0700530 """
531 Flow match test on single TCP packet
Dan Talaycof6e76c02012-03-23 10:56:12 -0700532 @param egr_ports A single port or list of ports
Dan Talayco551befa2010-07-15 17:05:32 -0700533
534 Run test with packet through switch from ing_port to egr_port
535 See flow_match_test for parameter descriptions
536 """
537
Ed Swierk99a74de2012-08-22 06:40:54 -0700538 if wildcards is None:
539 wildcards = required_wildcards(parent)
Rich Lane9a003812012-10-04 17:17:59 -0700540 logging.info("Pkt match test: " + str(ing_port) + " to " +
Dan Talaycof6e76c02012-03-23 10:56:12 -0700541 str(egr_ports))
Rich Lanee5779d32012-10-05 17:56:04 -0700542 logging.debug(" WC: " + hex(wildcards) + " vlan: " + str(dl_vlan))
Dan Talayco551befa2010-07-15 17:05:32 -0700543 if pkt is None:
544 pkt = simple_tcp_packet(dl_vlan_enable=(dl_vlan >= 0), dl_vlan=dl_vlan)
545
546 request = flow_msg_create(parent, pkt, ing_port=ing_port,
Dan Talaycof6e76c02012-03-23 10:56:12 -0700547 wildcards=wildcards, egr_ports=egr_ports,
Dan Talayco551befa2010-07-15 17:05:32 -0700548 action_list=action_list)
549
550 flow_msg_install(parent, request)
551
Rich Lane9a003812012-10-04 17:17:59 -0700552 logging.debug("Send packet: " + str(ing_port) + " to " +
Dan Talaycof6e76c02012-03-23 10:56:12 -0700553 str(egr_ports))
Dan Talayco551befa2010-07-15 17:05:32 -0700554 parent.dataplane.send(ing_port, str(pkt))
555
556 if exp_pkt is None:
557 exp_pkt = pkt
Dan Talaycoc948d0b2012-03-23 12:17:54 -0700558 receive_pkt_verify(parent, egr_ports, exp_pkt, ing_port)
Dan Talayco551befa2010-07-15 17:05:32 -0700559
Dan Talaycof6e76c02012-03-23 10:56:12 -0700560def get_egr_list(parent, of_ports, how_many, exclude_list=[]):
561 """
562 Generate a list of ports avoiding those in the exclude list
Rich Lane9a003812012-10-04 17:17:59 -0700563 @param parent Supplies logging
Dan Talaycof6e76c02012-03-23 10:56:12 -0700564 @param of_ports List of OF port numbers
565 @param how_many Number of ports to be added to the list
566 @param exclude_list List of ports not to be used
567 @returns An empty list if unable to find enough ports
568 """
569
Dan Talaycoc948d0b2012-03-23 12:17:54 -0700570 if how_many == 0:
571 return []
572
Dan Talaycof6e76c02012-03-23 10:56:12 -0700573 count = 0
574 egr_ports = []
575 for egr_idx in range(len(of_ports)):
576 if of_ports[egr_idx] not in exclude_list:
577 egr_ports.append(of_ports[egr_idx])
578 count += 1
579 if count >= how_many:
580 return egr_ports
Rich Lane9a003812012-10-04 17:17:59 -0700581 logging.debug("Could not generate enough egress ports for test")
Dan Talaycof6e76c02012-03-23 10:56:12 -0700582 return []
583
Ed Swierk99a74de2012-08-22 06:40:54 -0700584def flow_match_test(parent, port_map, wildcards=None, dl_vlan=-1, pkt=None,
Rich Lanee5779d32012-10-05 17:56:04 -0700585 exp_pkt=None, action_list=None,
Dan Talaycoc948d0b2012-03-23 12:17:54 -0700586 max_test=0, egr_count=1, ing_port=False):
Dan Talayco551befa2010-07-15 17:05:32 -0700587 """
588 Run flow_match_test_port_pair on all port pairs
589
590 @param max_test If > 0 no more than this number of tests are executed.
591 @param parent Must implement controller, dataplane, assertTrue, assertEqual
Rich Lane9a003812012-10-04 17:17:59 -0700592 and logging
Dan Talayco551befa2010-07-15 17:05:32 -0700593 @param pkt If not None, use this packet for ingress
594 @param wildcards For flow match entry
Dan Talayco79184222010-11-01 12:24:29 -0700595 @param dl_vlan If not -1, and pkt is None, create a pkt w/ VLAN tag
Dan Talayco551befa2010-07-15 17:05:32 -0700596 @param exp_pkt If not None, use this as the expected output pkt; els use pkt
597 @param action_list Additional actions to add to flow mod
Dan Talaycocfa172f2012-03-23 12:03:00 -0700598 @param egr_count Number of egress ports; -1 means get from config w/ dflt 2
Dan Talayco551befa2010-07-15 17:05:32 -0700599 """
Ed Swierk99a74de2012-08-22 06:40:54 -0700600 if wildcards is None:
601 wildcards = required_wildcards(parent)
Dan Talayco551befa2010-07-15 17:05:32 -0700602 of_ports = port_map.keys()
603 of_ports.sort()
604 parent.assertTrue(len(of_ports) > 1, "Not enough ports for test")
605 test_count = 0
606
Dan Talaycocfa172f2012-03-23 12:03:00 -0700607 if egr_count == -1:
Rich Lane2014f9b2012-10-05 15:29:40 -0700608 egr_count = test_param_get('egr_count', default=2)
Dan Talaycocfa172f2012-03-23 12:03:00 -0700609
Dan Talayco551befa2010-07-15 17:05:32 -0700610 for ing_idx in range(len(of_ports)):
611 ingress_port = of_ports[ing_idx]
Dan Talaycof6e76c02012-03-23 10:56:12 -0700612 egr_ports = get_egr_list(parent, of_ports, egr_count,
613 exclude_list=[ingress_port])
Dan Talaycoc948d0b2012-03-23 12:17:54 -0700614 if ing_port:
615 egr_ports.append(ofp.OFPP_IN_PORT)
Dan Talaycof6e76c02012-03-23 10:56:12 -0700616 if len(egr_ports) == 0:
617 parent.assertTrue(0, "Failed to generate egress port list")
618
619 flow_match_test_port_pair(parent, ingress_port, egr_ports,
620 wildcards=wildcards, dl_vlan=dl_vlan,
621 pkt=pkt, exp_pkt=exp_pkt,
Rich Lanee5779d32012-10-05 17:56:04 -0700622 action_list=action_list)
Dan Talaycof6e76c02012-03-23 10:56:12 -0700623 test_count += 1
624 if (max_test > 0) and (test_count > max_test):
Rich Lane9a003812012-10-04 17:17:59 -0700625 logging.info("Ran " + str(test_count) + " tests; exiting")
Dan Talaycof6e76c02012-03-23 10:56:12 -0700626 return
Dan Talayco551befa2010-07-15 17:05:32 -0700627
Rich Lane2014f9b2012-10-05 15:29:40 -0700628def test_param_get(key, default=None):
Dan Talayco4b2bee62010-07-20 14:10:05 -0700629 """
630 Return value passed via test-params if present
631
Dan Talayco4b2bee62010-07-20 14:10:05 -0700632 @param key The lookup key
633 @param default Default value to use if not found
634
635 If the pair 'key=val' appeared in the string passed to --test-params
636 on the command line, return val (as interpreted by exec). Otherwise
637 return default value.
Dan Talaycof6e76c02012-03-23 10:56:12 -0700638
639 WARNING: TEST PARAMETERS MUST BE PYTHON IDENTIFIERS;
640 eg egr_count, not egr-count.
Dan Talayco4b2bee62010-07-20 14:10:05 -0700641 """
642 try:
643 exec config["test_params"]
644 except:
645 return default
646
647 s = "val = " + str(key)
648 try:
649 exec s
650 return val
651 except:
652 return default
653
654def action_generate(parent, field_to_mod, mod_field_vals):
655 """
656 Create an action to modify the field indicated in field_to_mod
657
658 @param parent Must implement, assertTrue
659 @param field_to_mod The field to modify as a string name
660 @param mod_field_vals Hash of values to use for modified values
661 """
662
663 act = None
664
665 if field_to_mod in ['pktlen']:
666 return None
667
668 if field_to_mod == 'dl_dst':
669 act = action.action_set_dl_dst()
670 act.dl_addr = parse.parse_mac(mod_field_vals['dl_dst'])
671 elif field_to_mod == 'dl_src':
672 act = action.action_set_dl_src()
673 act.dl_addr = parse.parse_mac(mod_field_vals['dl_src'])
674 elif field_to_mod == 'dl_vlan_enable':
675 if not mod_field_vals['dl_vlan_enable']: # Strip VLAN tag
676 act = action.action_strip_vlan()
677 # Add VLAN tag is handled by dl_vlan field
678 # Will return None in this case
679 elif field_to_mod == 'dl_vlan':
680 act = action.action_set_vlan_vid()
681 act.vlan_vid = mod_field_vals['dl_vlan']
682 elif field_to_mod == 'dl_vlan_pcp':
683 act = action.action_set_vlan_pcp()
684 act.vlan_pcp = mod_field_vals['dl_vlan_pcp']
685 elif field_to_mod == 'ip_src':
686 act = action.action_set_nw_src()
687 act.nw_addr = parse.parse_ip(mod_field_vals['ip_src'])
688 elif field_to_mod == 'ip_dst':
689 act = action.action_set_nw_dst()
690 act.nw_addr = parse.parse_ip(mod_field_vals['ip_dst'])
691 elif field_to_mod == 'ip_tos':
692 act = action.action_set_nw_tos()
693 act.nw_tos = mod_field_vals['ip_tos']
694 elif field_to_mod == 'tcp_sport':
695 act = action.action_set_tp_src()
696 act.tp_port = mod_field_vals['tcp_sport']
697 elif field_to_mod == 'tcp_dport':
698 act = action.action_set_tp_dst()
699 act.tp_port = mod_field_vals['tcp_dport']
700 else:
701 parent.assertTrue(0, "Unknown field to modify: " + str(field_to_mod))
702
703 return act
704
705def pkt_action_setup(parent, start_field_vals={}, mod_field_vals={},
Rich Lanee5779d32012-10-05 17:56:04 -0700706 mod_fields=[], check_test_params=False):
Dan Talayco4b2bee62010-07-20 14:10:05 -0700707 """
708 Set up the ingress and expected packet and action list for a test
709
Rich Lane2014f9b2012-10-05 15:29:40 -0700710 @param parent Must implement assertTrue
Dan Talayco4b2bee62010-07-20 14:10:05 -0700711 @param start_field_values Field values to use for ingress packet (optional)
712 @param mod_field_values Field values to use for modified packet (optional)
713 @param mod_fields The list of fields to be modified by the switch in the test.
714 @params check_test_params If True, will check the parameters vid, add_vlan
715 and strip_vlan from the command line.
716
717 Returns a triple: pkt-to-send, expected-pkt, action-list
718 """
719
720 new_actions = []
721
Dan Talayco4b2bee62010-07-20 14:10:05 -0700722 base_pkt_params = {}
723 base_pkt_params['pktlen'] = 100
724 base_pkt_params['dl_dst'] = '00:DE:F0:12:34:56'
725 base_pkt_params['dl_src'] = '00:23:45:67:89:AB'
726 base_pkt_params['dl_vlan_enable'] = False
727 base_pkt_params['dl_vlan'] = 2
728 base_pkt_params['dl_vlan_pcp'] = 0
729 base_pkt_params['ip_src'] = '192.168.0.1'
730 base_pkt_params['ip_dst'] = '192.168.0.2'
731 base_pkt_params['ip_tos'] = 0
732 base_pkt_params['tcp_sport'] = 1234
733 base_pkt_params['tcp_dport'] = 80
734 for keyname in start_field_vals.keys():
735 base_pkt_params[keyname] = start_field_vals[keyname]
736
737 mod_pkt_params = {}
738 mod_pkt_params['pktlen'] = 100
739 mod_pkt_params['dl_dst'] = '00:21:0F:ED:CB:A9'
740 mod_pkt_params['dl_src'] = '00:ED:CB:A9:87:65'
741 mod_pkt_params['dl_vlan_enable'] = False
742 mod_pkt_params['dl_vlan'] = 3
743 mod_pkt_params['dl_vlan_pcp'] = 7
744 mod_pkt_params['ip_src'] = '10.20.30.40'
745 mod_pkt_params['ip_dst'] = '50.60.70.80'
746 mod_pkt_params['ip_tos'] = 0xf0
747 mod_pkt_params['tcp_sport'] = 4321
748 mod_pkt_params['tcp_dport'] = 8765
749 for keyname in mod_field_vals.keys():
750 mod_pkt_params[keyname] = mod_field_vals[keyname]
751
752 # Check for test param modifications
753 strip = False
754 if check_test_params:
Rich Lane2014f9b2012-10-05 15:29:40 -0700755 add_vlan = test_param_get('add_vlan')
756 strip_vlan = test_param_get('strip_vlan')
757 vid = test_param_get('vid')
Dan Talayco4b2bee62010-07-20 14:10:05 -0700758
759 if add_vlan and strip_vlan:
760 parent.assertTrue(0, "Add and strip VLAN both specified")
761
762 if vid:
763 base_pkt_params['dl_vlan_enable'] = True
764 base_pkt_params['dl_vlan'] = vid
765 if 'dl_vlan' in mod_fields:
766 mod_pkt_params['dl_vlan'] = vid + 1
767
768 if add_vlan:
769 base_pkt_params['dl_vlan_enable'] = False
770 mod_pkt_params['dl_vlan_enable'] = True
771 mod_pkt_params['pktlen'] = base_pkt_params['pktlen'] + 4
772 mod_fields.append('pktlen')
773 mod_fields.append('dl_vlan_enable')
774 if 'dl_vlan' not in mod_fields:
775 mod_fields.append('dl_vlan')
776 elif strip_vlan:
777 base_pkt_params['dl_vlan_enable'] = True
778 mod_pkt_params['dl_vlan_enable'] = False
779 mod_pkt_params['pktlen'] = base_pkt_params['pktlen'] - 4
780 mod_fields.append('dl_vlan_enable')
781 mod_fields.append('pktlen')
782
783 # Build the ingress packet
784 ingress_pkt = simple_tcp_packet(**base_pkt_params)
785
786 # Build the expected packet, modifying the indicated fields
787 for item in mod_fields:
788 base_pkt_params[item] = mod_pkt_params[item]
789 act = action_generate(parent, item, mod_pkt_params)
790 if act:
791 new_actions.append(act)
792
793 expected_pkt = simple_tcp_packet(**base_pkt_params)
794
795 return (ingress_pkt, expected_pkt, new_actions)
Dan Talayco677c0b72011-08-23 22:53:38 -0700796
797# Generate a simple "drop" flow mod
798# If in_band is true, then only drop from first test port
799def flow_mod_gen(port_map, in_band):
800 request = message.flow_mod()
801 request.match.wildcards = ofp.OFPFW_ALL
802 if in_band:
803 request.match.wildcards = ofp.OFPFW_ALL - ofp.OFPFW_IN_PORT
804 for of_port, ifname in port_map.items(): # Grab first port
805 break
806 request.match.in_port = of_port
807 request.buffer_id = 0xffffffff
808 return request
Dan Talaycoba3745c2010-07-21 21:51:08 -0700809
810def skip_message_emit(parent, s):
811 """
812 Print out a 'skipped' message to stderr
813
814 @param s The string to print out to the log file
Rich Lane9a003812012-10-04 17:17:59 -0700815 @param parent Must implement config object
Dan Talaycoba3745c2010-07-21 21:51:08 -0700816 """
817 global skipped_test_count
818
819 skipped_test_count += 1
Rich Lane9a003812012-10-04 17:17:59 -0700820 logging.info("Skipping: " + s)
Rich Lane477f4812012-10-04 22:49:00 -0700821 if config["dbg_level"] < logging.WARNING:
Dan Talaycoba3745c2010-07-21 21:51:08 -0700822 sys.stderr.write("(skipped) ")
823 else:
824 sys.stderr.write("(S)")
Dan Talayco677c0b72011-08-23 22:53:38 -0700825
Dan Talayco8a64e332012-03-28 14:53:20 -0700826
827def all_stats_get(parent):
828 """
829 Get the aggregate stats for all flows in the table
830 @param parent Test instance with controller connection and assert
831 @returns dict with keys flows, packets, bytes, active (flows),
832 lookups, matched
833 """
834 stat_req = message.aggregate_stats_request()
835 stat_req.match = ofp.ofp_match()
836 stat_req.match.wildcards = ofp.OFPFW_ALL
837 stat_req.table_id = 0xff
838 stat_req.out_port = ofp.OFPP_NONE
839
840 rv = {}
841
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700842 (reply, pkt) = parent.controller.transact(stat_req)
Dan Talayco8a64e332012-03-28 14:53:20 -0700843 parent.assertTrue(len(reply.stats) == 1, "Did not receive flow stats reply")
844
845 for obj in reply.stats:
846 (rv["flows"], rv["packets"], rv["bytes"]) = (obj.flow_count,
847 obj.packet_count, obj.byte_count)
848 break
849
850 request = message.table_stats_request()
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700851 (reply , pkt) = parent.controller.transact(request)
Dan Talayco8a64e332012-03-28 14:53:20 -0700852
853
854 (rv["active"], rv["lookups"], rv["matched"]) = (0,0,0)
855 for obj in reply.stats:
856 rv["active"] += obj.active_count
857 rv["lookups"] += obj.lookup_count
858 rv["matched"] += obj.matched_count
859
860 return rv
Dan Talayco2baf8b52012-03-30 09:55:42 -0700861
862FILTER=''.join([(len(repr(chr(x)))==3) and chr(x) or '.'
863 for x in range(256)])
864
865def hex_dump_buffer(src, length=16):
866 """
867 Convert src to a hex dump string and return the string
868 @param src The source buffer
869 @param length The number of bytes shown in each line
870 @returns A string showing the hex dump
871 """
Dan Talaycoc516fa02012-04-12 22:28:43 -0700872 result = ["\n"]
Dan Talayco2baf8b52012-03-30 09:55:42 -0700873 for i in xrange(0, len(src), length):
874 chars = src[i:i+length]
875 hex = ' '.join(["%02x" % ord(x) for x in chars])
876 printable = ''.join(["%s" % ((ord(x) <= 127 and
877 FILTER[ord(x)]) or '.') for x in chars])
878 result.append("%04x %-*s %s\n" % (i, length*3, hex, printable))
879 return ''.join(result)
880
881def format_packet(pkt):
882 return "Packet length %d \n%s" % (len(str(pkt)),
883 hex_dump_buffer(str(pkt)))