Commit 3c561c54 authored by Jakub Kicinski's avatar Jakub Kicinski
Browse files

selftests: drv-net: add helper/wrapper for bpftrace



bpftrace is very useful for low level driver testing. perf or trace-cmd
would also do for collecting data from tracepoints, but they require
much more post-processing.

Add a wrapper for running bpftrace and sanitizing its output.
bpftrace has JSON output, which is great, but it prints loose objects
and in a slightly inconvenient format. We have to read the objects
line by line, and while at it return them indexed by the map name.

Reviewed-by: default avatarBreno Leitao <leitao@debian.org>
Signed-off-by: default avatarBreno Leitao <leitao@debian.org>
Link: https://patch.msgid.link/20250714-netpoll_test-v7-1-c0220cfaa63e@debian.org


Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parent 6c628ed9
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -14,8 +14,8 @@ try:
    from net.lib.py import EthtoolFamily, NetdevFamily, NetshaperFamily, \
        NlError, RtnlFamily, DevlinkFamily
    from net.lib.py import CmdExitFailure
    from net.lib.py import bkg, cmd, defer, ethtool, fd_read_timeout, ip, \
        rand_port, tool, wait_port_listen, bpftool
    from net.lib.py import bkg, cmd, bpftool, bpftrace, defer, ethtool, \
        fd_read_timeout, ip, rand_port, tool, wait_port_listen
    from net.lib.py import fd_read_timeout
    from net.lib.py import KsftSkipEx, KsftFailEx, KsftXfailEx
    from net.lib.py import ksft_disruptive, ksft_exit, ksft_pr, ksft_run, \
+33 −0
Original line number Diff line number Diff line
@@ -189,6 +189,39 @@ def ethtool(args, json=None, ns=None, host=None):
    return tool('ethtool', args, json=json, ns=ns, host=host)


def bpftrace(expr, json=None, ns=None, host=None, timeout=None):
    """
    Run bpftrace and return map data (if json=True).
    The output of bpftrace is inconvenient, so the helper converts
    to a dict indexed by map name, e.g.:
     {
       "@":     { ... },
       "@map2": { ... },
     }
    """
    cmd_arr = ['bpftrace']
    # Throw in --quiet if json, otherwise the output has two objects
    if json:
        cmd_arr += ['-f', 'json', '-q']
    if timeout:
        expr += ' interval:s:' + str(timeout) + ' { exit(); }'
    cmd_arr += ['-e', expr]
    cmd_obj = cmd(cmd_arr, ns=ns, host=host, shell=False)
    if json:
        # bpftrace prints objects as lines
        ret = {}
        for l in cmd_obj.stdout.split('\n'):
            if not l.strip():
                continue
            one = _json.loads(l)
            if one.get('type') != 'map':
                continue
            for k, v in one["data"].items():
                ret[k] = v
        return ret
    return cmd_obj


def rand_port(type=socket.SOCK_STREAM):
    """
    Get a random unprivileged port.