This commit adds a basic packet metadata macro to the already existing
macros in ovs_gdb.py, ovs_dump_packets will print out information about
one or more packets. Currently, it will only extract some basic L2-4
information from Ethernet frames. However, it could easily be extended
as needed for future tasks.
Example usage:
(gdb) break fast_path_processing
(gdb) commands
>ovs_dump_packets packets_
>continue
>end
(gdb) continue
Thread 1 "ovs-vswitchd" hit Breakpoint 1, fast_path_processing ...
9e:11:bb:29:f3:1b -> 5a:e3:39:9b:b7:e0 ARP: Who has 10.1.1.2, tell
9e:11:bb:29:f3:1b
Thread 1 "ovs-vswitchd" hit Breakpoint 1, fast_path_processing ...
5a:e3:39:9b:b7:e0 -> 9e:11:bb:29:f3:1b ARP: 10.1.1.2 is at
5a:e3:39:9b:b7:e0
Signed-off-by: Mike Pattrick <[email protected]>
---
utilities/gdb/ovs_gdb.py | 161 +++++++++++++++++++++++++++++++++++++++
1 file changed, 161 insertions(+)
diff --git a/utilities/gdb/ovs_gdb.py b/utilities/gdb/ovs_gdb.py
index 0b2ecb81b..9e3c59f0e 100644
--- a/utilities/gdb/ovs_gdb.py
+++ b/utilities/gdb/ovs_gdb.py
@@ -34,6 +34,7 @@
# - ovs_dump_udpif_keys {<udpif_name>|<udpif_address>} {short}
# - ovs_show_fdb {[<bridge_name>] {dbg} {hash}}
# - ovs_show_upcall {dbg}
+# - ovs_dump_dp_packet <struct dp_packet_batch|struct dp_packet>
#
# Example:
# $ gdb $(which ovs-vswitchd) $(pidof ovs-vswitchd)
@@ -58,6 +59,8 @@
import gdb
import sys
import uuid
+import socket
+import struct
#
@@ -151,6 +154,29 @@ def eth_addr_to_string(eth_addr):
int(eth_addr['ea'][5]))
+def ipv4_to_string(ip):
+ return socket.inet_ntop(
+ socket.AF_INET,
+ struct.pack(
+ "I",
+ ip.cast(gdb.lookup_type('uint32_t'))
+ )
+ )
+
+
+def ipv6_to_string(ip):
+ ip_array = ip.cast( gdb.lookup_type('uint64_t').array(1) )
+
+ return socket.inet_ntop(
+ socket.AF_INET6,
+ struct.pack(
+ "QQ",
+ ip_array[0],
+ ip_array[1]
+ )
+ )
+
+
#
# Simple class to print a spinner on the console
#
@@ -1306,6 +1332,140 @@ class CmdDumpOfpacts(gdb.Command):
print("(struct ofpact *) {}: {}".format(node, node.dereference()))
+#
+# Implements the GDB "ovs_dump_packets" command
+#
+class CmdDumpPackets(gdb.Command):
+ """Dump metadata about dp_packets
+ Usage: ovs_dump_packets <struct dp_packet_batch|struct dp_packet>
+
+ This command can take either a dp_packet_batch struct and print out
metadata
+ about all packets in this batch, or a single dp_packet struct and print out
+ metadata about a single packet.
+
+ (gdb) ovs_dump_packets packets_
+ 9e:11:bb:29:f3:1b -> ff:ff:ff:ff:ff:ff ARP: Who has 00:00:00:00:00:00,
tell 9e:11:bb:29:f3:1b
+ """
+ def __init__(self):
+ super().__init__("ovs_dump_packets", gdb.COMMAND_DATA)
+
+ def invoke(self, arg, from_tty):
+ arg_list = gdb.string_to_argv(arg)
+ if len(arg_list) != 1:
+ print("Usage: ovs_dump_packets <dp_packet_struct>")
+
+ val = gdb.parse_and_eval(arg_list[0])
+ while val.type.code == gdb.TYPE_CODE_PTR:
+ val = val.dereference()
+
+ if str(val.type).startswith("struct dp_packet_batch"):
+ for idx in range(val['count']):
+ pkt = val['packets'][idx].dereference()
+ parsed = self.fmt_pkt(pkt)
+ if parsed is not None:
+ print(parsed['format'] % parsed)
+ elif str(val.type) == "struct dp_packet":
+ parsed = self.fmt_pkt(val)
+ if parsed is not None:
+ print(parsed['format'] % parsed)
+ else:
+ print("Unhandled type", str(val.type))
+
+ def fmt_pkt(self, pkt):
+ eth = gdb.parse_and_eval('dp_packet_eth(%s)' % pkt.address)
+ # todo, check for is NULL
+ if eth == 0:
+ return None
+
+ res_d = {
+ "e_src": None,
+ "e_dst": None,
+ "e_proto": None,
+ "i_src": None,
+ "i_dst": None,
+ "i_proto": None,
+ "t_src": "",
+ "t_dst": "",
+ "proto_msg": None,
+ "format": "Can not parse ethernet protocol %(e_proto)s"
+ }
+
+ eth_hdr = eth.cast(gdb.lookup_type('struct
eth_header').pointer()).dereference()
+ res_d['e_dst'] = eth_addr_to_string(eth_hdr['eth_dst'])
+ res_d['e_src'] = eth_addr_to_string(eth_hdr['eth_src'])
+ eth_type = socket.ntohs(eth_hdr['eth_type'])
+ res_d['e_proto'] = eth_type
+
+ l3 = gdb.parse_and_eval('dp_packet_l3(%s)' % pkt.address)
+ if eth_type == 0x0806:
+ res_d['e_proto'] = "ARP"
+
+ arp_pkt = l3.cast(gdb.lookup_type('struct
arp_eth_header').pointer()).dereference()
+ ar_op = socket.ntohs(arp_pkt['ar_op'])
+ if ar_op == 1:
+ res_d['proto_msg'] = "Who has %s, tell %s" % (
+ ipv4_to_string(arp_pkt['ar_tpa']),
+ eth_addr_to_string(arp_pkt['ar_sha']),
+ )
+ elif ar_op == 2:
+ res_d['proto_msg'] = "%s is at %s" % (
+ ipv4_to_string(arp_pkt['ar_spa']),
+ eth_addr_to_string(arp_pkt['ar_sha']),
+ )
+
+ res_d['format'] = "%(e_src)s -> %(e_dst)s ARP: %(proto_msg)s"
+
+ elif eth_type == 0x0800:
+ ip_pkt = l3.cast(gdb.lookup_type('struct
ip_header').pointer()).dereference()
+ res_d['e_proto'] = "IP"
+ res_d['i_src'] = ipv4_to_string(ip_pkt['ip_src'])
+ res_d['i_dst'] = ipv4_to_string(ip_pkt['ip_dst'])
+
+ ip_proto = ip_pkt['ip_proto']
+ l4 = gdb.parse_and_eval('dp_packet_l4(%s)' % pkt.address)
+ self.parse_l4(ip_proto, l4, res_d)
+ if res_d['t_dst']:
+ res_d['format'] = "%(e_src)s -> %(e_dst)s IP/%(i_proto)s:
%(i_src)s:%(t_src)s -> %(i_dst)s:%(t_dst)s"
+ else:
+ res_d['format'] = "%(e_src)s -> %(e_dst)s IP/%(i_proto)s:
%(i_src)s -> %(i_dst)s"
+
+ elif eth_type == 0x86dd:
+ res_d['e_proto'] = "IPv6"
+
+ ip_pkt = l3.cast(gdb.lookup_type('struct
ovs_16aligned_ip6_hdr').pointer()).dereference()
+ res_d['i_src'] = ipv6_to_string(ip_pkt['ip6_src'])
+ res_d['i_dst'] = ipv6_to_string(ip_pkt['ip6_dst'])
+
+ l4 = gdb.parse_and_eval('dp_packet_l4(%s)' % pkt.address)
+ ip_proto = ip_pkt['ip6_ctlun']['ip6_un1']['ip6_un1_nxt']
+ self.parse_l4(ip_proto, l4, res_d)
+ if res_d['t_dst']:
+ res_d['format'] = "%(e_src)s -> %(e_dst)s IP6/%(i_proto)s:
[%(i_src)s]:%(t_src)s -> [%(i_dst)s]:%(t_dst)s"
+ else:
+ res_d['format'] = "%(e_src)s -> %(e_dst)s IP6/%(i_proto)s:
[%(i_src)s] -> [%(i_dst)s]"
+
+ return res_d
+
+ @staticmethod
+ def parse_l4(ip_proto, l4, res_d):
+ uh = l4.cast(gdb.lookup_type('struct
udp_header').pointer()).dereference()
+ th = l4.cast(gdb.lookup_type('struct
tcp_header').pointer()).dereference()
+ if ip_proto == 58:
+ res_d['i_proto'] = "ICMPv6"
+ elif ip_proto == 11:
+ res_d['i_proto'] = "UDP"
+ res_d['t_src'] = socket.ntohs(th['udp_src'])
+ res_d['t_dst'] = socket.ntohs(th['udp_dst'])
+ elif ip_proto == 6:
+ res_d['i_proto'] = "TCP"
+ res_d['t_src'] = socket.ntohs(th['tcp_src'])
+ res_d['t_dst'] = socket.ntohs(th['tcp_dst'])
+ elif ip_proto == 1:
+ res_d['i_proto'] = "ICMP"
+ else:
+ res_d['i_proto'] = str(ip_proto)
+
+
#
# Initialize all GDB commands
#
@@ -1324,3 +1484,4 @@ CmdDumpSmap()
CmdDumpUdpifKeys()
CmdShowFDB()
CmdShowUpcall()
+CmdDumpPackets()
--
2.30.2
_______________________________________________
dev mailing list
[email protected]
https://mail.openvswitch.org/mailman/listinfo/ovs-dev