blob: d7e5e9df74ee4ac700d657022dc946fa2b2dda81 [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 clear_switch(parent, port_list):
Dan Talayco98fada92010-07-17 00:36:21 -070035 """
36 Clear the switch configuration
37
38 @param parent Object implementing controller and assert equal
Dan Talayco98fada92010-07-17 00:36:21 -070039 """
40 for port in port_list:
Rich Lane9a003812012-10-04 17:17:59 -070041 clear_port_config(parent, port)
42 delete_all_flows(parent.controller)
Dan Talayco98fada92010-07-17 00:36:21 -070043
Rich Lane9a003812012-10-04 17:17:59 -070044def delete_all_flows(ctrl):
Dan Talayco41eae8b2010-03-10 13:57:06 -080045 """
46 Delete all flows on the switch
47 @param ctrl The controller object for the test
Dan Talayco41eae8b2010-03-10 13:57:06 -080048 """
49
Rich Lane9a003812012-10-04 17:17:59 -070050 logging.info("Deleting all flows")
Dan Talaycoc901f4d2010-03-07 21:55:45 -080051 msg = message.flow_mod()
52 msg.match.wildcards = ofp.OFPFW_ALL
Dan Talayco41eae8b2010-03-10 13:57:06 -080053 msg.out_port = ofp.OFPP_NONE
Dan Talaycoc901f4d2010-03-07 21:55:45 -080054 msg.command = ofp.OFPFC_DELETE
55 msg.buffer_id = 0xffffffff
Dan Talayco41eae8b2010-03-10 13:57:06 -080056 return ctrl.message_send(msg)
57
Rich Lane9a003812012-10-04 17:17:59 -070058def clear_port_config(parent, port):
Dan Talayco98fada92010-07-17 00:36:21 -070059 """
60 Clear the port configuration (currently only no flood setting)
61
62 @param parent Object implementing controller and assert equal
Dan Talayco98fada92010-07-17 00:36:21 -070063 """
64 rv = port_config_set(parent.controller, port,
Rich Lane9a003812012-10-04 17:17:59 -070065 0, ofp.OFPPC_NO_FLOOD)
Dan Talayco98fada92010-07-17 00:36:21 -070066 self.assertEqual(rv, 0, "Failed to reset port config")
67
Ed Swierk99a74de2012-08-22 06:40:54 -070068def required_wildcards(parent):
Rich Lane477f4812012-10-04 22:49:00 -070069 w = test_param_get(config, 'required_wildcards', default='default')
Ed Swierk99a74de2012-08-22 06:40:54 -070070 if w == 'l3-l4':
71 return (ofp.OFPFW_NW_SRC_ALL | ofp.OFPFW_NW_DST_ALL | ofp.OFPFW_NW_TOS
72 | ofp.OFPFW_NW_PROTO | ofp.OFPFW_TP_SRC | ofp.OFPFW_TP_DST)
73 else:
74 return 0
75
Dan Talayco41eae8b2010-03-10 13:57:06 -080076def simple_tcp_packet(pktlen=100,
77 dl_dst='00:01:02:03:04:05',
78 dl_src='00:06:07:08:09:0a',
Tatsuya Yabe460321e2010-05-25 17:50:49 -070079 dl_vlan_enable=False,
80 dl_vlan=0,
81 dl_vlan_pcp=0,
Dan Talayco551befa2010-07-15 17:05:32 -070082 dl_vlan_cfi=0,
Dan Talayco41eae8b2010-03-10 13:57:06 -080083 ip_src='192.168.0.1',
84 ip_dst='192.168.0.2',
Tatsuya Yabe460321e2010-05-25 17:50:49 -070085 ip_tos=0,
Dan Talayco41eae8b2010-03-10 13:57:06 -080086 tcp_sport=1234,
87 tcp_dport=80
88 ):
89 """
90 Return a simple dataplane TCP packet
91
92 Supports a few parameters:
93 @param len Length of packet in bytes w/o CRC
94 @param dl_dst Destinatino MAC
95 @param dl_src Source MAC
Tatsuya Yabe460321e2010-05-25 17:50:49 -070096 @param dl_vlan_enable True if the packet is with vlan, False otherwise
97 @param dl_vlan VLAN ID
98 @param dl_vlan_pcp VLAN priority
Dan Talayco41eae8b2010-03-10 13:57:06 -080099 @param ip_src IP source
100 @param ip_dst IP destination
Tatsuya Yabe460321e2010-05-25 17:50:49 -0700101 @param ip_tos IP ToS
Dan Talayco41eae8b2010-03-10 13:57:06 -0800102 @param tcp_dport TCP destination port
103 @param ip_sport TCP source port
104
105 Generates a simple TCP request. Users
106 shouldn't assume anything about this packet other than that
107 it is a valid ethernet/IP/TCP frame.
108 """
Jeffrey Townsend5cb7ed32012-08-17 18:11:01 +0000109
110 if MINSIZE > pktlen:
111 pktlen = MINSIZE
112
Dan Talayco551befa2010-07-15 17:05:32 -0700113 # Note Dot1Q.id is really CFI
Tatsuya Yabe460321e2010-05-25 17:50:49 -0700114 if (dl_vlan_enable):
115 pkt = scapy.Ether(dst=dl_dst, src=dl_src)/ \
Dan Talayco551befa2010-07-15 17:05:32 -0700116 scapy.Dot1Q(prio=dl_vlan_pcp, id=dl_vlan_cfi, vlan=dl_vlan)/ \
Tatsuya Yabe460321e2010-05-25 17:50:49 -0700117 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos)/ \
118 scapy.TCP(sport=tcp_sport, dport=tcp_dport)
119 else:
120 pkt = scapy.Ether(dst=dl_dst, src=dl_src)/ \
121 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos)/ \
122 scapy.TCP(sport=tcp_sport, dport=tcp_dport)
123
Dan Talayco41eae8b2010-03-10 13:57:06 -0800124 pkt = pkt/("D" * (pktlen - len(pkt)))
125
126 return pkt
127
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700128def simple_icmp_packet(pktlen=60,
129 dl_dst='00:01:02:03:04:05',
130 dl_src='00:06:07:08:09:0a',
131 dl_vlan_enable=False,
132 dl_vlan=0,
133 dl_vlan_pcp=0,
134 ip_src='192.168.0.1',
135 ip_dst='192.168.0.2',
136 ip_tos=0,
137 icmp_type=8,
138 icmp_code=0
139 ):
140 """
141 Return a simple ICMP packet
142
143 Supports a few parameters:
144 @param len Length of packet in bytes w/o CRC
145 @param dl_dst Destinatino 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 icmp_type ICMP type
154 @param icmp_code ICMP code
155
156 Generates a simple ICMP ECHO REQUEST. Users
157 shouldn't assume anything about this packet other than that
158 it is a valid ethernet/ICMP frame.
159 """
Jeffrey Townsend5cb7ed32012-08-17 18:11:01 +0000160
161 if MINSIZE > pktlen:
162 pktlen = MINSIZE
163
Tatsuya Yabeb8fb3c32010-06-14 15:48:36 -0700164 if (dl_vlan_enable):
165 pkt = scapy.Ether(dst=dl_dst, src=dl_src)/ \
166 scapy.Dot1Q(prio=dl_vlan_pcp, id=0, vlan=dl_vlan)/ \
167 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos)/ \
168 scapy.ICMP(type=icmp_type, code=icmp_code)
169 else:
170 pkt = scapy.Ether(dst=dl_dst, src=dl_src)/ \
171 scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos)/ \
172 scapy.ICMP(type=icmp_type, code=icmp_code)
173
174 pkt = pkt/("0" * (pktlen - len(pkt)))
175
176 return pkt
177
Ed Swierk0aeff8c2012-03-23 20:27:18 -0700178def simple_eth_packet(pktlen=60,
179 dl_dst='00:01:02:03:04:05',
180 dl_src='01:80:c2:00:00:00',
181 dl_type=0x88cc):
Jeffrey Townsend5cb7ed32012-08-17 18:11:01 +0000182
183 if MINSIZE > pktlen:
184 pktlen = MINSIZE
185
Ed Swierk0aeff8c2012-03-23 20:27:18 -0700186 pkt = scapy.Ether(dst=dl_dst, src=dl_src, type=dl_type)
187
188 pkt = pkt/("0" * (pktlen - len(pkt)))
189
190 return pkt
191
Dan Talayco41eae8b2010-03-10 13:57:06 -0800192def do_barrier(ctrl):
Dan Talayco0fc08bd2012-04-09 16:56:18 -0700193 """
194 Do a barrier command
195 Return 0 on success, -1 on error
196 """
Dan Talayco41eae8b2010-03-10 13:57:06 -0800197 b = message.barrier_request()
Dan Talaycof6b94832012-04-12 21:50:57 -0700198 (resp, pkt) = ctrl.transact(b)
199 # We'll trust the transaction processing in the controller that xid matched
Dan Talayco0fc08bd2012-04-09 16:56:18 -0700200 if not resp:
201 return -1
202 return 0
Dan Talayco92c99122010-06-03 13:53:18 -0700203
Rich Lane9a003812012-10-04 17:17:59 -0700204def port_config_get(controller, port_no):
Dan Talayco92c99122010-06-03 13:53:18 -0700205 """
206 Get a port's configuration
207
208 Gets the switch feature configuration and grabs one port's
209 configuration
210
211 @returns (hwaddr, config, advert) The hwaddress, configuration and
212 advertised values
213 """
214 request = message.features_request()
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700215 reply, pkt = controller.transact(request)
Rich Lane9a003812012-10-04 17:17:59 -0700216 logging.debug(reply.show())
Dan Talayco92c99122010-06-03 13:53:18 -0700217 if reply is None:
Rich Lane9a003812012-10-04 17:17:59 -0700218 logging.warn("Get feature request failed")
Dan Talayco92c99122010-06-03 13:53:18 -0700219 return None, None, None
220 for idx in range(len(reply.ports)):
221 if reply.ports[idx].port_no == port_no:
222 return (reply.ports[idx].hw_addr, reply.ports[idx].config,
223 reply.ports[idx].advertised)
224
Rich Lane9a003812012-10-04 17:17:59 -0700225 logging.warn("Did not find port number for port config")
Dan Talayco92c99122010-06-03 13:53:18 -0700226 return None, None, None
227
Rich Lane9a003812012-10-04 17:17:59 -0700228def port_config_set(controller, port_no, config, mask):
Dan Talayco92c99122010-06-03 13:53:18 -0700229 """
230 Set the port configuration according the given parameters
231
232 Gets the switch feature configuration and updates one port's
233 configuration value according to config and mask
234 """
Rich Lane9a003812012-10-04 17:17:59 -0700235 logging.info("Setting port " + str(port_no) + " to config " + str(config))
Dan Talayco92c99122010-06-03 13:53:18 -0700236 request = message.features_request()
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700237 reply, pkt = controller.transact(request)
Dan Talayco92c99122010-06-03 13:53:18 -0700238 if reply is None:
239 return -1
Rich Lane9a003812012-10-04 17:17:59 -0700240 logging.debug(reply.show())
Dan Talayco92c99122010-06-03 13:53:18 -0700241 for idx in range(len(reply.ports)):
242 if reply.ports[idx].port_no == port_no:
243 break
244 if idx >= len(reply.ports):
245 return -1
246 mod = message.port_mod()
247 mod.port_no = port_no
248 mod.hw_addr = reply.ports[idx].hw_addr
249 mod.config = config
250 mod.mask = mask
251 mod.advertise = reply.ports[idx].advertised
252 rv = controller.message_send(mod)
253 return rv
254
Rich Lane9a003812012-10-04 17:17:59 -0700255def receive_pkt_check(dp, pkt, yes_ports, no_ports, assert_if, config):
Dan Talayco92c99122010-06-03 13:53:18 -0700256 """
257 Check for proper receive packets across all ports
Ken Chiang1bf01602012-04-04 10:48:23 -0700258 @param dp The dataplane object
Dan Talayco92c99122010-06-03 13:53:18 -0700259 @param pkt Expected packet; may be None if yes_ports is empty
260 @param yes_ports Set or list of ports that should recieve packet
261 @param no_ports Set or list of ports that should not receive packet
262 @param assert_if Object that implements assertXXX
263 """
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700264 exp_pkt_arg = None
265 if config and config["relax"]:
266 exp_pkt_arg = pkt
267
Dan Talayco92c99122010-06-03 13:53:18 -0700268 for ofport in yes_ports:
Rich Lane9a003812012-10-04 17:17:59 -0700269 logging.debug("Checking for pkt on port " + str(ofport))
Ken Chiang1bf01602012-04-04 10:48:23 -0700270 (rcv_port, rcv_pkt, pkt_time) = dp.poll(
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700271 port_number=ofport, exp_pkt=exp_pkt_arg)
Dan Talayco92c99122010-06-03 13:53:18 -0700272 assert_if.assertTrue(rcv_pkt is not None,
273 "Did not receive pkt on " + str(ofport))
Ken Chiang1bf01602012-04-04 10:48:23 -0700274 if not dataplane.match_exp_pkt(pkt, rcv_pkt):
Rich Lane9a003812012-10-04 17:17:59 -0700275 logging.debug("Sent %s" % format_packet(pkt))
276 logging.debug("Resp %s" % format_packet(rcv_pkt))
Ken Chiang1bf01602012-04-04 10:48:23 -0700277 assert_if.assertTrue(dataplane.match_exp_pkt(pkt, rcv_pkt),
278 "Response packet does not match send packet " +
279 "on port " + str(ofport))
Dan Talayco73f84012012-10-02 09:23:18 -0700280 if len(no_ports) > 0:
281 time.sleep(1)
Dan Talayco92c99122010-06-03 13:53:18 -0700282 for ofport in no_ports:
Rich Lane9a003812012-10-04 17:17:59 -0700283 logging.debug("Negative check for pkt on port " + str(ofport))
Ken Chiang1bf01602012-04-04 10:48:23 -0700284 (rcv_port, rcv_pkt, pkt_time) = dp.poll(
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700285 port_number=ofport, timeout=1, exp_pkt=exp_pkt_arg)
Dan Talayco92c99122010-06-03 13:53:18 -0700286 assert_if.assertTrue(rcv_pkt is None,
287 "Unexpected pkt on port " + str(ofport))
Dan Talayco551befa2010-07-15 17:05:32 -0700288
289
Dan Talaycoc948d0b2012-03-23 12:17:54 -0700290def receive_pkt_verify(parent, egr_ports, exp_pkt, ing_port):
Dan Talayco551befa2010-07-15 17:05:32 -0700291 """
292 Receive a packet and verify it matches an expected value
Dan Talaycof6e76c02012-03-23 10:56:12 -0700293 @param egr_port A single port or list of ports
Dan Talayco551befa2010-07-15 17:05:32 -0700294
295 parent must implement dataplane, assertTrue and assertEqual
296 """
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700297 exp_pkt_arg = None
Rich Lane477f4812012-10-04 22:49:00 -0700298 if config["relax"]:
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700299 exp_pkt_arg = exp_pkt
300
Dan Talaycof6e76c02012-03-23 10:56:12 -0700301 if type(egr_ports) == type([]):
302 egr_port_list = egr_ports
303 else:
304 egr_port_list = [egr_ports]
Dan Talaycocf26b7a2011-08-05 10:15:35 -0700305
Dan Talaycof6e76c02012-03-23 10:56:12 -0700306 # Expect a packet from each port on egr port list
307 for egr_port in egr_port_list:
Dan Talaycod8ae7582012-03-23 12:24:56 -0700308 check_port = egr_port
Dan Talaycoc948d0b2012-03-23 12:17:54 -0700309 if egr_port == ofp.OFPP_IN_PORT:
Dan Talaycod8ae7582012-03-23 12:24:56 -0700310 check_port = ing_port
Dan Talaycof6e76c02012-03-23 10:56:12 -0700311 (rcv_port, rcv_pkt, pkt_time) = parent.dataplane.poll(
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700312 port_number=check_port, exp_pkt=exp_pkt_arg)
Dan Talayco551befa2010-07-15 17:05:32 -0700313
Dan Talaycof6e76c02012-03-23 10:56:12 -0700314 if rcv_pkt is None:
Rich Lane9a003812012-10-04 17:17:59 -0700315 logging.error("ERROR: No packet received from " +
Dan Talaycod8ae7582012-03-23 12:24:56 -0700316 str(check_port))
Dan Talayco551befa2010-07-15 17:05:32 -0700317
Dan Talaycof6e76c02012-03-23 10:56:12 -0700318 parent.assertTrue(rcv_pkt is not None,
Dan Talaycod8ae7582012-03-23 12:24:56 -0700319 "Did not receive packet port " + str(check_port))
Rich Lane9a003812012-10-04 17:17:59 -0700320 logging.debug("Packet len " + str(len(rcv_pkt)) + " in on " +
Dan Talaycof6e76c02012-03-23 10:56:12 -0700321 str(rcv_port))
322
323 if str(exp_pkt) != str(rcv_pkt):
Rich Lane9a003812012-10-04 17:17:59 -0700324 logging.error("ERROR: Packet match failed.")
325 logging.debug("Expected len " + str(len(exp_pkt)) + ": "
Dan Talaycof6e76c02012-03-23 10:56:12 -0700326 + str(exp_pkt).encode('hex'))
Rich Lane9a003812012-10-04 17:17:59 -0700327 logging.debug("Received len " + str(len(rcv_pkt)) + ": "
Dan Talaycof6e76c02012-03-23 10:56:12 -0700328 + str(rcv_pkt).encode('hex'))
329 parent.assertEqual(str(exp_pkt), str(rcv_pkt),
Dan Talaycod8ae7582012-03-23 12:24:56 -0700330 "Packet match error on port " + str(check_port))
Dan Talaycof6e76c02012-03-23 10:56:12 -0700331
Dan Talayco551befa2010-07-15 17:05:32 -0700332def match_verify(parent, req_match, res_match):
333 """
334 Verify flow matches agree; if they disagree, report where
335
336 parent must implement assertEqual
337 Use str() to ensure content is compared and not pointers
338 """
339
340 parent.assertEqual(req_match.wildcards, res_match.wildcards,
341 'Match failed: wildcards: ' + hex(req_match.wildcards) +
342 " != " + hex(res_match.wildcards))
343 parent.assertEqual(req_match.in_port, res_match.in_port,
344 'Match failed: in_port: ' + str(req_match.in_port) +
345 " != " + str(res_match.in_port))
346 parent.assertEqual(str(req_match.dl_src), str(res_match.dl_src),
347 'Match failed: dl_src: ' + str(req_match.dl_src) +
348 " != " + str(res_match.dl_src))
349 parent.assertEqual(str(req_match.dl_dst), str(res_match.dl_dst),
350 'Match failed: dl_dst: ' + str(req_match.dl_dst) +
351 " != " + str(res_match.dl_dst))
352 parent.assertEqual(req_match.dl_vlan, res_match.dl_vlan,
353 'Match failed: dl_vlan: ' + str(req_match.dl_vlan) +
354 " != " + str(res_match.dl_vlan))
355 parent.assertEqual(req_match.dl_vlan_pcp, res_match.dl_vlan_pcp,
356 'Match failed: dl_vlan_pcp: ' +
357 str(req_match.dl_vlan_pcp) + " != " +
358 str(res_match.dl_vlan_pcp))
359 parent.assertEqual(req_match.dl_type, res_match.dl_type,
360 'Match failed: dl_type: ' + str(req_match.dl_type) +
361 " != " + str(res_match.dl_type))
362
363 if (not(req_match.wildcards & ofp.OFPFW_DL_TYPE)
364 and (req_match.dl_type == IP_ETHERTYPE)):
365 parent.assertEqual(req_match.nw_tos, res_match.nw_tos,
366 'Match failed: nw_tos: ' + str(req_match.nw_tos) +
367 " != " + str(res_match.nw_tos))
368 parent.assertEqual(req_match.nw_proto, res_match.nw_proto,
369 'Match failed: nw_proto: ' + str(req_match.nw_proto) +
370 " != " + str(res_match.nw_proto))
371 parent.assertEqual(req_match.nw_src, res_match.nw_src,
372 'Match failed: nw_src: ' + str(req_match.nw_src) +
373 " != " + str(res_match.nw_src))
374 parent.assertEqual(req_match.nw_dst, res_match.nw_dst,
375 'Match failed: nw_dst: ' + str(req_match.nw_dst) +
376 " != " + str(res_match.nw_dst))
377
378 if (not(req_match.wildcards & ofp.OFPFW_NW_PROTO)
379 and ((req_match.nw_proto == TCP_PROTOCOL)
380 or (req_match.nw_proto == UDP_PROTOCOL))):
381 parent.assertEqual(req_match.tp_src, res_match.tp_src,
382 'Match failed: tp_src: ' +
383 str(req_match.tp_src) +
384 " != " + str(res_match.tp_src))
385 parent.assertEqual(req_match.tp_dst, res_match.tp_dst,
386 'Match failed: tp_dst: ' +
387 str(req_match.tp_dst) +
388 " != " + str(res_match.tp_dst))
389
390def flow_removed_verify(parent, request=None, pkt_count=-1, byte_count=-1):
391 """
392 Receive a flow removed msg and verify it matches expected
393
394 @params parent Must implement controller, assertEqual
395 @param pkt_count If >= 0, verify packet count
396 @param byte_count If >= 0, verify byte count
397 """
398 (response, raw) = parent.controller.poll(ofp.OFPT_FLOW_REMOVED, 2)
399 parent.assertTrue(response is not None, 'No flow removed message received')
400
401 if request is None:
402 return
403
404 parent.assertEqual(request.cookie, response.cookie,
405 "Flow removed cookie error: " +
406 hex(request.cookie) + " != " + hex(response.cookie))
407
408 req_match = request.match
409 res_match = response.match
410 verifyMatchField(req_match, res_match)
411
412 if (req_match.wildcards != 0):
413 parent.assertEqual(request.priority, response.priority,
414 'Flow remove prio mismatch: ' +
415 str(request,priority) + " != " +
416 str(response.priority))
417 parent.assertEqual(response.reason, ofp.OFPRR_HARD_TIMEOUT,
418 'Flow remove reason is not HARD TIMEOUT:' +
419 str(response.reason))
420 if pkt_count >= 0:
421 parent.assertEqual(response.packet_count, pkt_count,
422 'Flow removed failed, packet count: ' +
423 str(response.packet_count) + " != " +
424 str(pkt_count))
425 if byte_count >= 0:
426 parent.assertEqual(response.byte_count, byte_count,
427 'Flow removed failed, byte count: ' +
428 str(response.byte_count) + " != " +
429 str(byte_count))
430
Ed Swierk99a74de2012-08-22 06:40:54 -0700431def packet_to_flow_match(parent, packet):
432 match = parse.packet_to_flow_match(packet)
433 match.wildcards |= required_wildcards(parent)
434 return match
435
436def flow_msg_create(parent, pkt, ing_port=None, action_list=None, wildcards=None,
Dan Talaycof6e76c02012-03-23 10:56:12 -0700437 egr_ports=None, egr_queue=None, check_expire=False, in_band=False):
Dan Talayco551befa2010-07-15 17:05:32 -0700438 """
439 Create a flow message
440
441 Match on packet with given wildcards.
442 See flow_match_test for other parameter descriptoins
443 @param egr_queue if not None, make the output an enqueue action
Dan Talayco677c0b72011-08-23 22:53:38 -0700444 @param in_band if True, do not wildcard ingress port
Dan Talaycof6e76c02012-03-23 10:56:12 -0700445 @param egr_ports None (drop), single port or list of ports
Dan Talayco551befa2010-07-15 17:05:32 -0700446 """
447 match = parse.packet_to_flow_match(pkt)
448 parent.assertTrue(match is not None, "Flow match from pkt failed")
Ed Swierk99a74de2012-08-22 06:40:54 -0700449 if wildcards is None:
450 wildcards = required_wildcards(parent)
Dan Talayco677c0b72011-08-23 22:53:38 -0700451 if in_band:
452 wildcards &= ~ofp.OFPFW_IN_PORT
Dan Talayco551befa2010-07-15 17:05:32 -0700453 match.wildcards = wildcards
454 match.in_port = ing_port
455
Dan Talaycof6e76c02012-03-23 10:56:12 -0700456 if type(egr_ports) == type([]):
457 egr_port_list = egr_ports
458 else:
459 egr_port_list = [egr_ports]
460
Dan Talayco551befa2010-07-15 17:05:32 -0700461 request = message.flow_mod()
462 request.match = match
463 request.buffer_id = 0xffffffff
464 if check_expire:
465 request.flags |= ofp.OFPFF_SEND_FLOW_REM
466 request.hard_timeout = 1
467
468 if action_list is not None:
469 for act in action_list:
Rich Lane9a003812012-10-04 17:17:59 -0700470 logging.debug("Adding action " + act.show())
Dan Talayco551befa2010-07-15 17:05:32 -0700471 rv = request.actions.add(act)
472 parent.assertTrue(rv, "Could not add action" + act.show())
473
474 # Set up output/enqueue action if directed
475 if egr_queue is not None:
Dan Talaycof6e76c02012-03-23 10:56:12 -0700476 parent.assertTrue(egr_ports is not None, "Egress port not set")
Dan Talayco551befa2010-07-15 17:05:32 -0700477 act = action.action_enqueue()
Dan Talaycof6e76c02012-03-23 10:56:12 -0700478 for egr_port in egr_port_list:
479 act.port = egr_port
480 act.queue_id = egr_queue
481 rv = request.actions.add(act)
482 parent.assertTrue(rv, "Could not add enqueue action " +
483 str(egr_port) + " Q: " + str(egr_queue))
484 elif egr_ports is not None:
485 for egr_port in egr_port_list:
486 act = action.action_output()
487 act.port = egr_port
488 rv = request.actions.add(act)
489 parent.assertTrue(rv, "Could not add output action " +
490 str(egr_port))
Dan Talayco551befa2010-07-15 17:05:32 -0700491
Rich Lane9a003812012-10-04 17:17:59 -0700492 logging.debug(request.show())
Dan Talayco551befa2010-07-15 17:05:32 -0700493
494 return request
495
Jeffrey Townsendf3eae9c2012-03-28 18:23:21 -0700496def flow_msg_install(parent, request, clear_table_override=None):
Dan Talayco551befa2010-07-15 17:05:32 -0700497 """
498 Install a flow mod message in the switch
499
500 @param parent Must implement controller, assertEqual, assertTrue
501 @param request The request, all set to go
502 @param clear_table If true, clear the flow table before installing
503 """
Dan Talayco8a64e332012-03-28 14:53:20 -0700504
Rich Lane477f4812012-10-04 22:49:00 -0700505 clear_table = test_param_get(config, 'clear_table', default=True)
Jeffrey Townsendf3eae9c2012-03-28 18:23:21 -0700506 if(clear_table_override != None):
507 clear_table = clear_table_override
508
509 if clear_table:
Rich Lane9a003812012-10-04 17:17:59 -0700510 logging.debug("Clear flow table")
511 rc = delete_all_flows(parent.controller)
Dan Talayco551befa2010-07-15 17:05:32 -0700512 parent.assertEqual(rc, 0, "Failed to delete all flows")
Dan Talayco0fc08bd2012-04-09 16:56:18 -0700513 parent.assertEqual(do_barrier(parent.controller), 0, "Barrier failed")
Dan Talayco551befa2010-07-15 17:05:32 -0700514
Rich Lane9a003812012-10-04 17:17:59 -0700515 logging.debug("Insert flow")
Dan Talayco551befa2010-07-15 17:05:32 -0700516 rv = parent.controller.message_send(request)
517 parent.assertTrue(rv != -1, "Error installing flow mod")
Dan Talayco0fc08bd2012-04-09 16:56:18 -0700518 parent.assertEqual(do_barrier(parent.controller), 0, "Barrier failed")
Dan Talayco551befa2010-07-15 17:05:32 -0700519
Ed Swierk99a74de2012-08-22 06:40:54 -0700520def flow_match_test_port_pair(parent, ing_port, egr_ports, wildcards=None,
Dan Talayco551befa2010-07-15 17:05:32 -0700521 dl_vlan=-1, pkt=None, exp_pkt=None,
522 action_list=None, check_expire=False):
523 """
524 Flow match test on single TCP packet
Dan Talaycof6e76c02012-03-23 10:56:12 -0700525 @param egr_ports A single port or list of ports
Dan Talayco551befa2010-07-15 17:05:32 -0700526
527 Run test with packet through switch from ing_port to egr_port
528 See flow_match_test for parameter descriptions
529 """
530
Ed Swierk99a74de2012-08-22 06:40:54 -0700531 if wildcards is None:
532 wildcards = required_wildcards(parent)
Rich Lane9a003812012-10-04 17:17:59 -0700533 logging.info("Pkt match test: " + str(ing_port) + " to " +
Dan Talaycof6e76c02012-03-23 10:56:12 -0700534 str(egr_ports))
Rich Lane9a003812012-10-04 17:17:59 -0700535 logging.debug(" WC: " + hex(wildcards) + " vlan: " + str(dl_vlan) +
Dan Talayco98fada92010-07-17 00:36:21 -0700536 " expire: " + str(check_expire))
Dan Talayco551befa2010-07-15 17:05:32 -0700537 if pkt is None:
538 pkt = simple_tcp_packet(dl_vlan_enable=(dl_vlan >= 0), dl_vlan=dl_vlan)
539
540 request = flow_msg_create(parent, pkt, ing_port=ing_port,
Dan Talaycof6e76c02012-03-23 10:56:12 -0700541 wildcards=wildcards, egr_ports=egr_ports,
Dan Talayco551befa2010-07-15 17:05:32 -0700542 action_list=action_list)
543
544 flow_msg_install(parent, request)
545
Rich Lane9a003812012-10-04 17:17:59 -0700546 logging.debug("Send packet: " + str(ing_port) + " to " +
Dan Talaycof6e76c02012-03-23 10:56:12 -0700547 str(egr_ports))
Dan Talayco551befa2010-07-15 17:05:32 -0700548 parent.dataplane.send(ing_port, str(pkt))
549
550 if exp_pkt is None:
551 exp_pkt = pkt
Dan Talaycoc948d0b2012-03-23 12:17:54 -0700552 receive_pkt_verify(parent, egr_ports, exp_pkt, ing_port)
Dan Talayco551befa2010-07-15 17:05:32 -0700553
554 if check_expire:
555 #@todo Not all HW supports both pkt and byte counters
556 flow_removed_verify(parent, request, pkt_count=1, byte_count=len(pkt))
557
Dan Talaycof6e76c02012-03-23 10:56:12 -0700558def get_egr_list(parent, of_ports, how_many, exclude_list=[]):
559 """
560 Generate a list of ports avoiding those in the exclude list
Rich Lane9a003812012-10-04 17:17:59 -0700561 @param parent Supplies logging
Dan Talaycof6e76c02012-03-23 10:56:12 -0700562 @param of_ports List of OF port numbers
563 @param how_many Number of ports to be added to the list
564 @param exclude_list List of ports not to be used
565 @returns An empty list if unable to find enough ports
566 """
567
Dan Talaycoc948d0b2012-03-23 12:17:54 -0700568 if how_many == 0:
569 return []
570
Dan Talaycof6e76c02012-03-23 10:56:12 -0700571 count = 0
572 egr_ports = []
573 for egr_idx in range(len(of_ports)):
574 if of_ports[egr_idx] not in exclude_list:
575 egr_ports.append(of_ports[egr_idx])
576 count += 1
577 if count >= how_many:
578 return egr_ports
Rich Lane9a003812012-10-04 17:17:59 -0700579 logging.debug("Could not generate enough egress ports for test")
Dan Talaycof6e76c02012-03-23 10:56:12 -0700580 return []
581
Ed Swierk99a74de2012-08-22 06:40:54 -0700582def flow_match_test(parent, port_map, wildcards=None, dl_vlan=-1, pkt=None,
Dan Talayco551befa2010-07-15 17:05:32 -0700583 exp_pkt=None, action_list=None, check_expire=False,
Dan Talaycoc948d0b2012-03-23 12:17:54 -0700584 max_test=0, egr_count=1, ing_port=False):
Dan Talayco551befa2010-07-15 17:05:32 -0700585 """
586 Run flow_match_test_port_pair on all port pairs
587
588 @param max_test If > 0 no more than this number of tests are executed.
589 @param parent Must implement controller, dataplane, assertTrue, assertEqual
Rich Lane9a003812012-10-04 17:17:59 -0700590 and logging
Dan Talayco551befa2010-07-15 17:05:32 -0700591 @param pkt If not None, use this packet for ingress
592 @param wildcards For flow match entry
Dan Talayco79184222010-11-01 12:24:29 -0700593 @param dl_vlan If not -1, and pkt is None, create a pkt w/ VLAN tag
Dan Talayco551befa2010-07-15 17:05:32 -0700594 @param exp_pkt If not None, use this as the expected output pkt; els use pkt
595 @param action_list Additional actions to add to flow mod
596 @param check_expire Check for flow expiration message
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 Lane477f4812012-10-04 22:49:00 -0700607 egr_count = test_param_get(config, '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,
621 action_list=action_list,
622 check_expire=check_expire)
623 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
Dan Talayco4b2bee62010-07-20 14:10:05 -0700628def test_param_get(config, key, default=None):
629 """
630 Return value passed via test-params if present
631
632 @param config The configuration structure for OFTest
633 @param key The lookup key
634 @param default Default value to use if not found
635
636 If the pair 'key=val' appeared in the string passed to --test-params
637 on the command line, return val (as interpreted by exec). Otherwise
638 return default value.
Dan Talaycof6e76c02012-03-23 10:56:12 -0700639
640 WARNING: TEST PARAMETERS MUST BE PYTHON IDENTIFIERS;
641 eg egr_count, not egr-count.
Dan Talayco4b2bee62010-07-20 14:10:05 -0700642 """
643 try:
644 exec config["test_params"]
645 except:
646 return default
647
648 s = "val = " + str(key)
649 try:
650 exec s
651 return val
652 except:
653 return default
654
655def action_generate(parent, field_to_mod, mod_field_vals):
656 """
657 Create an action to modify the field indicated in field_to_mod
658
659 @param parent Must implement, assertTrue
660 @param field_to_mod The field to modify as a string name
661 @param mod_field_vals Hash of values to use for modified values
662 """
663
664 act = None
665
666 if field_to_mod in ['pktlen']:
667 return None
668
669 if field_to_mod == 'dl_dst':
670 act = action.action_set_dl_dst()
671 act.dl_addr = parse.parse_mac(mod_field_vals['dl_dst'])
672 elif field_to_mod == 'dl_src':
673 act = action.action_set_dl_src()
674 act.dl_addr = parse.parse_mac(mod_field_vals['dl_src'])
675 elif field_to_mod == 'dl_vlan_enable':
676 if not mod_field_vals['dl_vlan_enable']: # Strip VLAN tag
677 act = action.action_strip_vlan()
678 # Add VLAN tag is handled by dl_vlan field
679 # Will return None in this case
680 elif field_to_mod == 'dl_vlan':
681 act = action.action_set_vlan_vid()
682 act.vlan_vid = mod_field_vals['dl_vlan']
683 elif field_to_mod == 'dl_vlan_pcp':
684 act = action.action_set_vlan_pcp()
685 act.vlan_pcp = mod_field_vals['dl_vlan_pcp']
686 elif field_to_mod == 'ip_src':
687 act = action.action_set_nw_src()
688 act.nw_addr = parse.parse_ip(mod_field_vals['ip_src'])
689 elif field_to_mod == 'ip_dst':
690 act = action.action_set_nw_dst()
691 act.nw_addr = parse.parse_ip(mod_field_vals['ip_dst'])
692 elif field_to_mod == 'ip_tos':
693 act = action.action_set_nw_tos()
694 act.nw_tos = mod_field_vals['ip_tos']
695 elif field_to_mod == 'tcp_sport':
696 act = action.action_set_tp_src()
697 act.tp_port = mod_field_vals['tcp_sport']
698 elif field_to_mod == 'tcp_dport':
699 act = action.action_set_tp_dst()
700 act.tp_port = mod_field_vals['tcp_dport']
701 else:
702 parent.assertTrue(0, "Unknown field to modify: " + str(field_to_mod))
703
704 return act
705
706def pkt_action_setup(parent, start_field_vals={}, mod_field_vals={},
707 mod_fields={}, check_test_params=False):
708 """
709 Set up the ingress and expected packet and action list for a test
710
Rich Lane9a003812012-10-04 17:17:59 -0700711 @param parent Must implement, assertTrue, and config hash
Dan Talayco4b2bee62010-07-20 14:10:05 -0700712 @param start_field_values Field values to use for ingress packet (optional)
713 @param mod_field_values Field values to use for modified packet (optional)
714 @param mod_fields The list of fields to be modified by the switch in the test.
715 @params check_test_params If True, will check the parameters vid, add_vlan
716 and strip_vlan from the command line.
717
718 Returns a triple: pkt-to-send, expected-pkt, action-list
719 """
720
721 new_actions = []
722
Dan Talayco4b2bee62010-07-20 14:10:05 -0700723 base_pkt_params = {}
724 base_pkt_params['pktlen'] = 100
725 base_pkt_params['dl_dst'] = '00:DE:F0:12:34:56'
726 base_pkt_params['dl_src'] = '00:23:45:67:89:AB'
727 base_pkt_params['dl_vlan_enable'] = False
728 base_pkt_params['dl_vlan'] = 2
729 base_pkt_params['dl_vlan_pcp'] = 0
730 base_pkt_params['ip_src'] = '192.168.0.1'
731 base_pkt_params['ip_dst'] = '192.168.0.2'
732 base_pkt_params['ip_tos'] = 0
733 base_pkt_params['tcp_sport'] = 1234
734 base_pkt_params['tcp_dport'] = 80
735 for keyname in start_field_vals.keys():
736 base_pkt_params[keyname] = start_field_vals[keyname]
737
738 mod_pkt_params = {}
739 mod_pkt_params['pktlen'] = 100
740 mod_pkt_params['dl_dst'] = '00:21:0F:ED:CB:A9'
741 mod_pkt_params['dl_src'] = '00:ED:CB:A9:87:65'
742 mod_pkt_params['dl_vlan_enable'] = False
743 mod_pkt_params['dl_vlan'] = 3
744 mod_pkt_params['dl_vlan_pcp'] = 7
745 mod_pkt_params['ip_src'] = '10.20.30.40'
746 mod_pkt_params['ip_dst'] = '50.60.70.80'
747 mod_pkt_params['ip_tos'] = 0xf0
748 mod_pkt_params['tcp_sport'] = 4321
749 mod_pkt_params['tcp_dport'] = 8765
750 for keyname in mod_field_vals.keys():
751 mod_pkt_params[keyname] = mod_field_vals[keyname]
752
753 # Check for test param modifications
754 strip = False
755 if check_test_params:
Rich Lane477f4812012-10-04 22:49:00 -0700756 add_vlan = test_param_get(config, 'add_vlan')
757 strip_vlan = test_param_get(config, 'strip_vlan')
758 vid = test_param_get(config, 'vid')
Dan Talayco4b2bee62010-07-20 14:10:05 -0700759
760 if add_vlan and strip_vlan:
761 parent.assertTrue(0, "Add and strip VLAN both specified")
762
763 if vid:
764 base_pkt_params['dl_vlan_enable'] = True
765 base_pkt_params['dl_vlan'] = vid
766 if 'dl_vlan' in mod_fields:
767 mod_pkt_params['dl_vlan'] = vid + 1
768
769 if add_vlan:
770 base_pkt_params['dl_vlan_enable'] = False
771 mod_pkt_params['dl_vlan_enable'] = True
772 mod_pkt_params['pktlen'] = base_pkt_params['pktlen'] + 4
773 mod_fields.append('pktlen')
774 mod_fields.append('dl_vlan_enable')
775 if 'dl_vlan' not in mod_fields:
776 mod_fields.append('dl_vlan')
777 elif strip_vlan:
778 base_pkt_params['dl_vlan_enable'] = True
779 mod_pkt_params['dl_vlan_enable'] = False
780 mod_pkt_params['pktlen'] = base_pkt_params['pktlen'] - 4
781 mod_fields.append('dl_vlan_enable')
782 mod_fields.append('pktlen')
783
784 # Build the ingress packet
785 ingress_pkt = simple_tcp_packet(**base_pkt_params)
786
787 # Build the expected packet, modifying the indicated fields
788 for item in mod_fields:
789 base_pkt_params[item] = mod_pkt_params[item]
790 act = action_generate(parent, item, mod_pkt_params)
791 if act:
792 new_actions.append(act)
793
794 expected_pkt = simple_tcp_packet(**base_pkt_params)
795
796 return (ingress_pkt, expected_pkt, new_actions)
Dan Talayco677c0b72011-08-23 22:53:38 -0700797
798# Generate a simple "drop" flow mod
799# If in_band is true, then only drop from first test port
800def flow_mod_gen(port_map, in_band):
801 request = message.flow_mod()
802 request.match.wildcards = ofp.OFPFW_ALL
803 if in_band:
804 request.match.wildcards = ofp.OFPFW_ALL - ofp.OFPFW_IN_PORT
805 for of_port, ifname in port_map.items(): # Grab first port
806 break
807 request.match.in_port = of_port
808 request.buffer_id = 0xffffffff
809 return request
Dan Talaycoba3745c2010-07-21 21:51:08 -0700810
811def skip_message_emit(parent, s):
812 """
813 Print out a 'skipped' message to stderr
814
815 @param s The string to print out to the log file
Rich Lane9a003812012-10-04 17:17:59 -0700816 @param parent Must implement config object
Dan Talaycoba3745c2010-07-21 21:51:08 -0700817 """
818 global skipped_test_count
819
820 skipped_test_count += 1
Rich Lane9a003812012-10-04 17:17:59 -0700821 logging.info("Skipping: " + s)
Rich Lane477f4812012-10-04 22:49:00 -0700822 if config["dbg_level"] < logging.WARNING:
Dan Talaycoba3745c2010-07-21 21:51:08 -0700823 sys.stderr.write("(skipped) ")
824 else:
825 sys.stderr.write("(S)")
Dan Talayco677c0b72011-08-23 22:53:38 -0700826
Dan Talayco8a64e332012-03-28 14:53:20 -0700827
828def all_stats_get(parent):
829 """
830 Get the aggregate stats for all flows in the table
831 @param parent Test instance with controller connection and assert
832 @returns dict with keys flows, packets, bytes, active (flows),
833 lookups, matched
834 """
835 stat_req = message.aggregate_stats_request()
836 stat_req.match = ofp.ofp_match()
837 stat_req.match.wildcards = ofp.OFPFW_ALL
838 stat_req.table_id = 0xff
839 stat_req.out_port = ofp.OFPP_NONE
840
841 rv = {}
842
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700843 (reply, pkt) = parent.controller.transact(stat_req)
Dan Talayco8a64e332012-03-28 14:53:20 -0700844 parent.assertTrue(len(reply.stats) == 1, "Did not receive flow stats reply")
845
846 for obj in reply.stats:
847 (rv["flows"], rv["packets"], rv["bytes"]) = (obj.flow_count,
848 obj.packet_count, obj.byte_count)
849 break
850
851 request = message.table_stats_request()
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700852 (reply , pkt) = parent.controller.transact(request)
Dan Talayco8a64e332012-03-28 14:53:20 -0700853
854
855 (rv["active"], rv["lookups"], rv["matched"]) = (0,0,0)
856 for obj in reply.stats:
857 rv["active"] += obj.active_count
858 rv["lookups"] += obj.lookup_count
859 rv["matched"] += obj.matched_count
860
861 return rv
Dan Talayco2baf8b52012-03-30 09:55:42 -0700862
863FILTER=''.join([(len(repr(chr(x)))==3) and chr(x) or '.'
864 for x in range(256)])
865
866def hex_dump_buffer(src, length=16):
867 """
868 Convert src to a hex dump string and return the string
869 @param src The source buffer
870 @param length The number of bytes shown in each line
871 @returns A string showing the hex dump
872 """
Dan Talaycoc516fa02012-04-12 22:28:43 -0700873 result = ["\n"]
Dan Talayco2baf8b52012-03-30 09:55:42 -0700874 for i in xrange(0, len(src), length):
875 chars = src[i:i+length]
876 hex = ' '.join(["%02x" % ord(x) for x in chars])
877 printable = ''.join(["%s" % ((ord(x) <= 127 and
878 FILTER[ord(x)]) or '.') for x in chars])
879 result.append("%04x %-*s %s\n" % (i, length*3, hex, printable))
880 return ''.join(result)
881
882def format_packet(pkt):
883 return "Packet length %d \n%s" % (len(str(pkt)),
884 hex_dump_buffer(str(pkt)))