Message ID | 8839ca84209fb4b28501af5a956b2a2d0e0ee17d.camel@redhat.com |
---|---|
State | Superseded |
Headers | show |
Series | [ovs-dev,v2] utilities: Add another GDB macro for ovs-vswitchd | expand |
Context | Check | Description |
---|---|---|
ovsrobot/apply-robot | success | apply and check: success |
ovsrobot/github-robot-_Build_and_Test | fail | github build: failed |
Some small remaining comments, rest looks good! On 5 Nov 2021, at 18:26, Mike Pattrick wrote: > 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. It feeds packets into tcpdump, and the user can > pass in tcpdump options to modify how packets are parsed or even write > out packets to a pcap file. > > Example usage: > (gdb) break fast_path_processing > (gdb) commands >> ovs_dump_packets packets_ >> continue >> end > (gdb) continue > > Thread 1 "ovs-vswitchd" hit Breakpoint 2, fast_path_processing ... > 12:01:05.962485 ARP, Ethernet (len 6), IPv4 (len 4), Request who-has 10.1.1.1 tell 10.1.1.2, length 28 > Thread 1 "ovs-vswitchd" hit Breakpoint 1, fast_path_processing ... > 12:01:05.981214 ARP, Ethernet (len 6), IPv4 (len 4), Reply 10.1.1.1 is-at a6:0f:c3:f0:5f:bd (oui Unknown), length 28 > > Signed-off-by: Mike Pattrick <mkp@redhat.com> > --- > utilities/gdb/ovs_gdb.py | 102 ++++++++++++++++++++++++++++++++++++++- > 1 file changed, 100 insertions(+), 2 deletions(-) > > diff --git a/utilities/gdb/ovs_gdb.py b/utilities/gdb/ovs_gdb.py > index 0b2ecb81b..ee9160607 100644 > --- a/utilities/gdb/ovs_gdb.py > +++ b/utilities/gdb/ovs_gdb.py > @@ -29,6 +29,7 @@ > # - ovs_dump_netdev > # - ovs_dump_netdev_provider > # - ovs_dump_ovs_list <struct ovs_list *> {[<structure>] [<member>] {dump}]} > +# - ovs_dump_packets <struct dp_packet_batch|struct dp_packet> [tcpdump options] > # - ovs_dump_simap <struct simap *> > # - ovs_dump_smap <struct smap *> > # - ovs_dump_udpif_keys {<udpif_name>|<udpif_address>} {short} > @@ -58,6 +59,9 @@ > import gdb > import sys > import uuid > +import struct Please keep imports in alphabetical order. > +from scapy.layers.l2 import Ether > +from scapy.utils import tcpdump Not everybody might have/need scapy support. Maybe we can change it to something like: try: from scapy.layers.l2 import Ether from scapy.utils import tcpdump except ModuleNotFoundError: print("WARNING: Can't find the Scapy Python module!") print(" This is required for the ovs_dump_packets command.") > > # > @@ -138,7 +142,7 @@ def get_time_msec(): > > def get_time_now(): > # See get_time_msec() above > - return int(get_global_variable("coverage_run_time"))/1000, -5 > + return int(get_global_variable("coverage_run_time")) / 1000, -5 > > > def eth_addr_to_string(eth_addr): > @@ -156,7 +160,7 @@ def eth_addr_to_string(eth_addr): > # > class ProgressIndicator(object): > def __init__(self, message=None): > - self.spinner = "/-\|" > + self.spinner = "/-\\|" > self.spinner_index = 0 > self.message = message > > @@ -1306,6 +1310,99 @@ 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> [tcpdump options] > + > + 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. > + > + Everything after the struct reference is passed into tcpdump. > + > + (gdb) ovs_dump_packets packets_ > + 12:01:05.981214 ARP, Ethernet (len 6), IPv4 (len 4), Reply 10.1.1.1 is-at a6:0f:c3:f0:5f:bd (oui Unknown), length 28 > + """ > + 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) == 0: > + print("Usage: ovs_dump_packets <struct dp_packet_batch|" > + "struct dp_packet> [tcpdump options]") Indent is not correct here. > + return > + > + symb_name = arg_list[0] > + tcpdump_args = arg_list[1:] > + > + val = gdb.parse_and_eval(symb_name) > + while val.type.code == gdb.TYPE_CODE_PTR: > + val = val.dereference() > + > + pkt_list = [] > + if str(val.type).startswith("struct dp_packet_batch"): > + for idx in range(val['count']): > + pkt_struct = val['packets'][idx].dereference() > + pkt = self.extract_pkt(pkt_struct) > + if pkt is None: > + continue > + pkt_list.append(pkt) > + elif str(val.type) == "struct dp_packet": > + pkt = self.extract_pkt(val) > + if pkt is None: > + return > + pkt_list.append(pkt) > + else: > + print("Error, unsupported argument type:", str(val.type)) All errors are in the format print(“ERROR: unsupported argument type: {}”.format(str(val.type)) > + return > + > + tcpdump(pkt_list, args=tcpdump_args) Wondering if we should supply the “-n” option if no options are given to speed up the actual display. But I’ll leave it up to you. > + > + def extract_pkt(self, pkt): > + pkt_fields = pkt.type.keys() > + if pkt['packet_type'] != 0: > + return > + if pkt['l3_ofs'] == 0xFFFF: > + return > + > + if "mbuf" in pkt_fields: > + if pkt['mbuf']['data_off'] == 0xFFFF: > + return > + eth_ptr = pkt['mbuf']['buf_addr'] > + eth_off = int(pkt['mbuf']['data_off']) > + eth_len = int(pkt['mbuf']['pkt_len']) > + else: > + if pkt['data_ofs'] == 0xFFFF: > + return > + eth_ptr = pkt['base_'] > + eth_off = int(pkt['data_ofs']) > + eth_len = int(pkt['size_']) > + Thanks for doing the above, so it will also work with core dumps! > + if eth_ptr == 0 or eth_len < 1: > + return > + > + # Extract packet > + pkt_ptr = eth_ptr.cast( > + gdb.lookup_type('uint8_t').pointer() > + ) > + pkt_ptr += eth_off > + > + pkt_data = [] > + for idx in range(eth_len): > + pkt_data.append(int(pkt_ptr[idx])) > + > + pkt_data = struct.pack("{}B".format(eth_len), *pkt_data) > + > + packet = Ether(pkt_data) > + packet.len = int(eth_len) > + > + return packet > + > + > # > # Initialize all GDB commands > # > @@ -1319,6 +1416,7 @@ CmdDumpNetdev() > CmdDumpNetdevProvider() > CmdDumpOfpacts() > CmdDumpOvsList() > +CmdDumpPackets() > CmdDumpSimap() > CmdDumpSmap() > CmdDumpUdpifKeys() > -- > 2.30.2 > > > _______________________________________________ > dev mailing list > dev@openvswitch.org > https://mail.openvswitch.org/mailman/listinfo/ovs-dev
diff --git a/utilities/gdb/ovs_gdb.py b/utilities/gdb/ovs_gdb.py index 0b2ecb81b..ee9160607 100644 --- a/utilities/gdb/ovs_gdb.py +++ b/utilities/gdb/ovs_gdb.py @@ -29,6 +29,7 @@ # - ovs_dump_netdev # - ovs_dump_netdev_provider # - ovs_dump_ovs_list <struct ovs_list *> {[<structure>] [<member>] {dump}]} +# - ovs_dump_packets <struct dp_packet_batch|struct dp_packet> [tcpdump options] # - ovs_dump_simap <struct simap *> # - ovs_dump_smap <struct smap *> # - ovs_dump_udpif_keys {<udpif_name>|<udpif_address>} {short} @@ -58,6 +59,9 @@ import gdb import sys import uuid +import struct +from scapy.layers.l2 import Ether +from scapy.utils import tcpdump # @@ -138,7 +142,7 @@ def get_time_msec(): def get_time_now(): # See get_time_msec() above - return int(get_global_variable("coverage_run_time"))/1000, -5 + return int(get_global_variable("coverage_run_time")) / 1000, -5 def eth_addr_to_string(eth_addr): @@ -156,7 +160,7 @@ def eth_addr_to_string(eth_addr): # class ProgressIndicator(object): def __init__(self, message=None): - self.spinner = "/-\|" + self.spinner = "/-\\|" self.spinner_index = 0 self.message = message @@ -1306,6 +1310,99 @@ 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> [tcpdump options] + + 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. + + Everything after the struct reference is passed into tcpdump. + + (gdb) ovs_dump_packets packets_ + 12:01:05.981214 ARP, Ethernet (len 6), IPv4 (len 4), Reply 10.1.1.1 is-at a6:0f:c3:f0:5f:bd (oui Unknown), length 28 + """ + 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) == 0: + print("Usage: ovs_dump_packets <struct dp_packet_batch|" + "struct dp_packet> [tcpdump options]") + return + + symb_name = arg_list[0] + tcpdump_args = arg_list[1:] + + val = gdb.parse_and_eval(symb_name) + while val.type.code == gdb.TYPE_CODE_PTR: + val = val.dereference() + + pkt_list = [] + if str(val.type).startswith("struct dp_packet_batch"): + for idx in range(val['count']): + pkt_struct = val['packets'][idx].dereference() + pkt = self.extract_pkt(pkt_struct) + if pkt is None: + continue + pkt_list.append(pkt) + elif str(val.type) == "struct dp_packet": + pkt = self.extract_pkt(val) + if pkt is None: + return + pkt_list.append(pkt) + else: + print("Error, unsupported argument type:", str(val.type)) + return + + tcpdump(pkt_list, args=tcpdump_args) + + def extract_pkt(self, pkt): + pkt_fields = pkt.type.keys() + if pkt['packet_type'] != 0: + return + if pkt['l3_ofs'] == 0xFFFF: + return + + if "mbuf" in pkt_fields: + if pkt['mbuf']['data_off'] == 0xFFFF: + return + eth_ptr = pkt['mbuf']['buf_addr'] + eth_off = int(pkt['mbuf']['data_off']) + eth_len = int(pkt['mbuf']['pkt_len']) + else: + if pkt['data_ofs'] == 0xFFFF: + return + eth_ptr = pkt['base_'] + eth_off = int(pkt['data_ofs']) + eth_len = int(pkt['size_']) + + if eth_ptr == 0 or eth_len < 1: + return + + # Extract packet + pkt_ptr = eth_ptr.cast( + gdb.lookup_type('uint8_t').pointer() + ) + pkt_ptr += eth_off + + pkt_data = [] + for idx in range(eth_len): + pkt_data.append(int(pkt_ptr[idx])) + + pkt_data = struct.pack("{}B".format(eth_len), *pkt_data) + + packet = Ether(pkt_data) + packet.len = int(eth_len) + + return packet + + # # Initialize all GDB commands # @@ -1319,6 +1416,7 @@ CmdDumpNetdev() CmdDumpNetdevProvider() CmdDumpOfpacts() CmdDumpOvsList() +CmdDumpPackets() CmdDumpSimap() CmdDumpSmap() CmdDumpUdpifKeys()