[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20181214025056.GC31012@mini-arch.hsd1.ca.comcast.net>
Date: Thu, 13 Dec 2018 18:50:56 -0800
From: Stanislav Fomichev <sdf@...ichev.me>
To: Quentin Monnet <quentin.monnet@...ronome.com>
Cc: Alexei Starovoitov <ast@...nel.org>,
Daniel Borkmann <daniel@...earbox.net>, netdev@...r.kernel.org,
oss-drivers@...ronome.com,
Arnaldo Carvalho de Melo <acme@...nel.org>,
Jesper Dangaard Brouer <brouer@...hat.com>,
Stanislav Fomichev <sdf@...gle.com>
Subject: Re: [PATCH bpf-next 1/8] tools: bpftool: add basic probe capability,
probe syscall and kversion
On 12/13, Quentin Monnet wrote:
> Add a new component and command for bpftool, in order to probe the
> system to dump a set of eBPF-related parameters so that users can know
> what features are available on the system.
>
> Parameters are dumped in plain or JSON output (with -j/-p options).
> Additionally, a specific keyword can be used to provide a third possible
> output so that the parameters are dumped as #define-d macros, ready to
> be saved to a header file and included in an eBPF-based project.
>
> The current patch introduces probing of two simple parameters:
> availability of the bpf() system call, and kernel version. Later commits
> will add other probes.
>
> Sample output:
>
> # bpftool feature probe kernel
> Scanning system call and kernel version...
> Kernel release is 4.19.0
> bpf() syscall is available
>
> # bpftool --json --pretty feature probe kernel
> {
> "syscall_config": {
> "kernel_version_code": 267008,
> "have_bpf_syscall": true
> }
> }
>
> # bpftool feature probe kernel macros prefix BPFTOOL_
> /*** System call and kernel version ***/
> #define BPFTOOL_LINUX_VERSION_CODE 267008
> #define BPFTOOL_BPF_SYSCALL
>
> The optional "kernel" keyword enforces probing of the current system,
> which is the only possible behaviour at this stage. It can be safely
> omitted.
>
> The feature comes with the relevant man page, but bash completion will
> come in a dedicated commit.
>
> Signed-off-by: Quentin Monnet <quentin.monnet@...ronome.com>
> Reviewed-by: Jakub Kicinski <jakub.kicinski@...ronome.com>
> ---
> .../bpftool/Documentation/bpftool-cgroup.rst | 1 +
> .../bpftool/Documentation/bpftool-feature.rst | 69 +++++++
> .../bpf/bpftool/Documentation/bpftool-map.rst | 1 +
> .../bpf/bpftool/Documentation/bpftool-net.rst | 1 +
> .../bpftool/Documentation/bpftool-perf.rst | 1 +
> .../bpftool/Documentation/bpftool-prog.rst | 1 +
> tools/bpf/bpftool/Documentation/bpftool.rst | 1 +
> tools/bpf/bpftool/feature.c | 184 ++++++++++++++++++
> tools/bpf/bpftool/main.c | 3 +-
> tools/bpf/bpftool/main.h | 1 +
> 10 files changed, 262 insertions(+), 1 deletion(-)
> create mode 100644 tools/bpf/bpftool/Documentation/bpftool-feature.rst
> create mode 100644 tools/bpf/bpftool/feature.c
>
> diff --git a/tools/bpf/bpftool/Documentation/bpftool-cgroup.rst b/tools/bpf/bpftool/Documentation/bpftool-cgroup.rst
> index d07ccf8a23f7..d43fce568ef7 100644
> --- a/tools/bpf/bpftool/Documentation/bpftool-cgroup.rst
> +++ b/tools/bpf/bpftool/Documentation/bpftool-cgroup.rst
> @@ -142,5 +142,6 @@ SEE ALSO
> **bpftool**\ (8),
> **bpftool-prog**\ (8),
> **bpftool-map**\ (8),
> + **bpftool-feature**\ (8),
> **bpftool-net**\ (8),
> **bpftool-perf**\ (8)
> diff --git a/tools/bpf/bpftool/Documentation/bpftool-feature.rst b/tools/bpf/bpftool/Documentation/bpftool-feature.rst
> new file mode 100644
> index 000000000000..23920a7490e9
> --- /dev/null
> +++ b/tools/bpf/bpftool/Documentation/bpftool-feature.rst
> @@ -0,0 +1,69 @@
> +===============
> +bpftool-feature
> +===============
> +-------------------------------------------------------------------------------
> +tool for inspection of eBPF-related parameters for Linux kernel or net device
> +-------------------------------------------------------------------------------
> +
> +:Manual section: 8
> +
> +SYNOPSIS
> +========
> +
> + **bpftool** [*OPTIONS*] **feature** *COMMAND*
> +
> + *OPTIONS* := { { **-j** | **--json** } [{ **-p** | **--pretty** }] }
> +
> + *COMMANDS* := { **probe** | **help** }
> +
> +MAP COMMANDS
> +=============
> +
> +| **bpftool** **feature probe** [**kernel**] [**macros** [**prefix** *PREFIX*]]
> +| **bpftool** **feature help**
> +
> +DESCRIPTION
> +===========
> + **bpftool feature probe** [**kernel**] [**macros** [**prefix** *PREFIX*]]
> + Probe the running kernel and dump a number of eBPF-related
> + parameters, such as availability of the **bpf()** system call.
> +
> + Keyword **kernel** can be omitted.
> +
> + If the **macros** keyword (but not the **-j** option) is
> + passed, output is dumped as a list of **#define** macros that
> + are ready to be included in a C header file, for example.
> + If, additionally, **prefix** is used to define a *PREFIX*,
> + the provided string will be used as a prefix to the names of
> + the macros: this can be used to avoid conflicts on macro
> + names when including the output of this command as a header
> + file.
> +
> + **bpftool feature help**
> + Print short help message.
> +
> +OPTIONS
> +=======
> + -h, --help
> + Print short generic help message (similar to **bpftool help**).
> +
> + -v, --version
> + Print version number (similar to **bpftool version**).
> +
> + -j, --json
> + Generate JSON output. For commands that cannot produce JSON, this
> + option has no effect.
> +
> + -p, --pretty
> + Generate human-readable JSON output. Implies **-j**.
> +
> +SEE ALSO
> +========
> + **bpf**\ (2),
> + **bpf-helpers**\ (7),
> + **bpftool**\ (8),
> + **bpftool-prog**\ (8),
> + **bpftool-map**\ (8),
> + **bpftool-cgroup**\ (8),
> + **bpftool-net**\ (8),
> + **bpftool-perf**\ (8)
> diff --git a/tools/bpf/bpftool/Documentation/bpftool-map.rst b/tools/bpf/bpftool/Documentation/bpftool-map.rst
> index 5318dcb2085e..b432c5cc20c8 100644
> --- a/tools/bpf/bpftool/Documentation/bpftool-map.rst
> +++ b/tools/bpf/bpftool/Documentation/bpftool-map.rst
> @@ -177,5 +177,6 @@ SEE ALSO
> **bpftool**\ (8),
> **bpftool-prog**\ (8),
> **bpftool-cgroup**\ (8),
> + **bpftool-feature**\ (8),
> **bpftool-net**\ (8),
> **bpftool-perf**\ (8)
> diff --git a/tools/bpf/bpftool/Documentation/bpftool-net.rst b/tools/bpf/bpftool/Documentation/bpftool-net.rst
> index ed87c9b619ad..779dab3650ee 100644
> --- a/tools/bpf/bpftool/Documentation/bpftool-net.rst
> +++ b/tools/bpf/bpftool/Documentation/bpftool-net.rst
> @@ -142,4 +142,5 @@ SEE ALSO
> **bpftool-prog**\ (8),
> **bpftool-map**\ (8),
> **bpftool-cgroup**\ (8),
> + **bpftool-feature**\ (8),
> **bpftool-perf**\ (8)
> diff --git a/tools/bpf/bpftool/Documentation/bpftool-perf.rst b/tools/bpf/bpftool/Documentation/bpftool-perf.rst
> index f4c5e5538bb8..bca5590a80d0 100644
> --- a/tools/bpf/bpftool/Documentation/bpftool-perf.rst
> +++ b/tools/bpf/bpftool/Documentation/bpftool-perf.rst
> @@ -84,4 +84,5 @@ SEE ALSO
> **bpftool-prog**\ (8),
> **bpftool-map**\ (8),
> **bpftool-cgroup**\ (8),
> + **bpftool-feature**\ (8),
> **bpftool-net**\ (8)
> diff --git a/tools/bpf/bpftool/Documentation/bpftool-prog.rst b/tools/bpf/bpftool/Documentation/bpftool-prog.rst
> index bb1aeb98b6da..595b4538c0d7 100644
> --- a/tools/bpf/bpftool/Documentation/bpftool-prog.rst
> +++ b/tools/bpf/bpftool/Documentation/bpftool-prog.rst
> @@ -243,5 +243,6 @@ SEE ALSO
> **bpftool**\ (8),
> **bpftool-map**\ (8),
> **bpftool-cgroup**\ (8),
> + **bpftool-feature**\ (8),
> **bpftool-net**\ (8),
> **bpftool-perf**\ (8)
> diff --git a/tools/bpf/bpftool/Documentation/bpftool.rst b/tools/bpf/bpftool/Documentation/bpftool.rst
> index 129b7a9c0f9b..f6526b657677 100644
> --- a/tools/bpf/bpftool/Documentation/bpftool.rst
> +++ b/tools/bpf/bpftool/Documentation/bpftool.rst
> @@ -68,5 +68,6 @@ SEE ALSO
> **bpftool-prog**\ (8),
> **bpftool-map**\ (8),
> **bpftool-cgroup**\ (8),
> + **bpftool-feature**\ (8),
> **bpftool-net**\ (8),
> **bpftool-perf**\ (8)
> diff --git a/tools/bpf/bpftool/feature.c b/tools/bpf/bpftool/feature.c
> new file mode 100644
> index 000000000000..e1784611575d
> --- /dev/null
> +++ b/tools/bpf/bpftool/feature.c
> @@ -0,0 +1,184 @@
> +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +/* Copyright (c) 2018 Netronome Systems, Inc. */
> +
> +#include <errno.h>
> +#include <string.h>
> +#include <unistd.h>
> +#include <sys/utsname.h>
> +
> +#include <linux/filter.h>
> +#include <linux/limits.h>
> +
> +#include <bpf.h>
> +
> +#include "main.h"
> +
> +enum probe_component {
> + COMPONENT_UNSPEC,
> + COMPONENT_KERNEL,
> +};
> +
> +/* Printing utility functions */
> +
> +static void
> +print_bool_feature(const char *feat_name, const char *define_name,
> + const char *plain_name, bool res, const char *define_prefix)
> +{
> + if (json_output)
> + jsonw_bool_field(json_wtr, feat_name, res);
> + else if (define_prefix)
[..]
> + printf("#define %s%s%s\n", define_prefix,
> + res ? "" : "NO_", define_name);
Should we keep it autoconf style and do:
#define XYZ 1 - in case of supported feature
/* #undef XYZ */ - in case of unsupported feature
?
> + else
> + printf("%s is %savailable\n", plain_name, res ? "" : "NOT ");
Why not do printf("%s %s\n", feat_name, res ? "yes" : "no") instead?
And not complicate (drop) the output with human readability. One
possible (dis)advantage - scripts can use this.
> +}
> +
> +static void
> +print_start_section(const char *json_title, const char *define_comment,
> + const char *plain_title, const char *define_prefix)
> +{
> + if (json_output) {
> + jsonw_name(json_wtr, json_title);
> + jsonw_start_object(json_wtr);
> + } else if (define_prefix) {
> + printf("%s\n", define_comment);
> + } else {
> + printf("%s\n", plain_title);
> + }
> +}
> +
> +/* Probing functions */
> +
> +static int probe_kernel_version(const char *define_prefix)
> +{
> + int version, subversion, patchlevel, code = 0;
> + struct utsname utsn;
> +
> + if (!uname(&utsn))
> + if (sscanf(utsn.release, "%d.%d.%d",
> + &version, &subversion, &patchlevel) == 3)
> + code = (version << 16) + (subversion << 8) + patchlevel;
> +
> + if (json_output)
> + jsonw_uint_field(json_wtr, "kernel_version_code", code);
> + else if (define_prefix)
> + printf("#define %sLINUX_VERSION_CODE %d\n",
> + define_prefix, code);
> + else if (code)
> + printf("Kernel release is %d.%d.%d\n",
> + version, subversion, patchlevel);
> + else
> + printf("Unable to parse kernel release number\n");
> +
> + return code;
> +}
> +
> +static bool probe_bpf_syscall(const char *define_prefix)
> +{
> + bool res;
> +
> + bpf_load_program(BPF_PROG_TYPE_UNSPEC, NULL, 0, NULL, 0, NULL, 0);
> + res = (errno != ENOSYS);
> +
> + print_bool_feature("have_bpf_syscall",
> + "BPF_SYSCALL",
> + "bpf() syscall",
> + res, define_prefix);
> +
> + return res;
> +}
> +
> +static int do_probe(int argc, char **argv)
> +{
> + enum probe_component target = COMPONENT_UNSPEC;
> + const char *define_prefix = NULL;
> +
> + /* Detection assumes user has sufficient privileges (CAP_SYS_ADMIN).
> + * Let's approximate, and restrict usage to root user only.
> + */
> + if (geteuid()) {
> + p_err("please run this command as root user");
> + return -1;
> + }
> +
> + set_max_rlimit();
> +
> + while (argc) {
> + if (is_prefix(*argv, "kernel")) {
> + if (target != COMPONENT_UNSPEC) {
> + p_err("component to probe already specified");
> + return -1;
> + }
> + target = COMPONENT_KERNEL;
> + NEXT_ARG();
> + } else if (is_prefix(*argv, "macros") && !define_prefix) {
> + define_prefix = "";
> + NEXT_ARG();
> + } else if (is_prefix(*argv, "prefix")) {
> + if (!define_prefix) {
> + p_err("'prefix' argument can only be use after 'macros'");
> + return -1;
> + }
> + if (strcmp(define_prefix, "")) {
> + p_err("'prefix' already defined");
> + return -1;
> + }
> + NEXT_ARG();
> +
> + if (!REQ_ARGS(1))
> + return -1;
> + define_prefix = GET_ARG();
> + } else {
> + p_err("expected no more arguments, 'kernel', 'macros' or 'prefix', got: '%s'?",
> + *argv);
> + return -1;
> + }
> + }
> +
> + if (json_output)
> + jsonw_start_object(json_wtr);
> +
> + print_start_section("syscall_config",
> + "/*** System call and kernel version ***/",
> + "Scanning system call and kernel version...",
> + define_prefix);
> +
> + probe_kernel_version(define_prefix);
> + probe_bpf_syscall(define_prefix);
> +
> + if (json_output) {
> + /* End current "section" of probes */
> + jsonw_end_object(json_wtr);
> + /* End root object */
> + jsonw_end_object(json_wtr);
> + }
> +
> + return 0;
> +}
> +
> +static int do_help(int argc, char **argv)
> +{
> + if (json_output) {
> + jsonw_null(json_wtr);
> + return 0;
> + }
> +
> + fprintf(stderr,
> + "Usage: %s %s probe [kernel] [macros [prefix PREFIX]]\n"
> + " %s %s help\n"
> + "",
> + bin_name, argv[-2], bin_name, argv[-2]);
> +
> + return 0;
> +}
> +
> +static const struct cmd cmds[] = {
> + { "help", do_help },
> + { "probe", do_probe },
> + { 0 }
> +};
> +
> +int do_feature(int argc, char **argv)
> +{
> + return cmd_select(cmds, argc, argv, do_help);
> +}
> diff --git a/tools/bpf/bpftool/main.c b/tools/bpf/bpftool/main.c
> index 9e657e7d5172..baf07f8be737 100644
> --- a/tools/bpf/bpftool/main.c
> +++ b/tools/bpf/bpftool/main.c
> @@ -55,7 +55,7 @@ static int do_help(int argc, char **argv)
> " %s batch file FILE\n"
> " %s version\n"
> "\n"
> - " OBJECT := { prog | map | cgroup | perf | net }\n"
> + " OBJECT := { prog | map | cgroup | perf | net | feature }\n"
> " " HELP_SPEC_OPTIONS "\n"
> "",
> bin_name, bin_name, bin_name);
> @@ -186,6 +186,7 @@ static const struct cmd cmds[] = {
> { "cgroup", do_cgroup },
> { "perf", do_perf },
> { "net", do_net },
> + { "feature", do_feature },
> { "version", do_version },
> { 0 }
> };
> diff --git a/tools/bpf/bpftool/main.h b/tools/bpf/bpftool/main.h
> index d2beb88f0e2e..2acd8c08e8b6 100644
> --- a/tools/bpf/bpftool/main.h
> +++ b/tools/bpf/bpftool/main.h
> @@ -141,6 +141,7 @@ int do_cgroup(int argc, char **arg);
> int do_perf(int argc, char **arg);
> int do_net(int argc, char **arg);
> int do_tracelog(int argc, char **arg);
> +int do_feature(int argc, char **argv);
>
> int parse_u32_arg(int *argc, char ***argv, __u32 *val, const char *what);
> int prog_parse_fd(int *argc, char ***argv);
> --
> 2.17.1
>
Powered by blists - more mailing lists