[ovs-dev] [PATCH v2] utilities: Add another GDB macro for ovs-vswitchd

Eelco Chaudron echaudro at redhat.com
Fri Nov 12 10:27:47 UTC 2021


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 at 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 at openvswitch.org
> https://mail.openvswitch.org/mailman/listinfo/ovs-dev



More information about the dev mailing list