All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH bpf-next 0/8] tools: bpftool: add probes for system and device
@ 2018-12-13 12:19 Quentin Monnet
  2018-12-13 12:19 ` [PATCH bpf-next 1/8] tools: bpftool: add basic probe capability, probe syscall and kversion Quentin Monnet
                   ` (10 more replies)
  0 siblings, 11 replies; 41+ messages in thread
From: Quentin Monnet @ 2018-12-13 12:19 UTC (permalink / raw)
  To: Alexei Starovoitov, Daniel Borkmann
  Cc: netdev, oss-drivers, Quentin Monnet, Arnaldo Carvalho de Melo,
	Jesper Dangaard Brouer, Stanislav Fomichev

Hi,
This set add a new command to bpftool in order to dump a list of
eBPF-related parameters for the system (or for a specific network
device) to the console. Once again, this is based on a suggestion from
Daniel.

At this time, output includes:

    - Availability of bpf() system call
    - Availability of bpf() system call for unprivileged users
    - JIT status (enabled or not, with or without debugging traces)
    - JIT hardening status
    - JIT kallsyms exports status
    - Status of kernel compilation options related to BPF features
    - Release number of the running kernel
    - Availability of known eBPF program types
    - Availability of known eBPF map types
    - Availability of known eBPF helper functions

There are three different ways to dump this information at this time:

    - Plain output dumps probe results in plain text. It is the most
      flexible options for providing descriptive output to the user, but
      should not be relied upon for parsing the output.
    - JSON output is supported.
    - A third mode, available through the "macros" keyword appended to
      the command line, dumps the parameters as a series of "#define"
      directives, that can be included into a C header file for example.

If the user does not have root privileges (or more precisely, the
CAP_SYS_ADMIN capability) detection will be erroneous for most
parameters. Therefore, forbid non-root users to run the command.

Cc: Arnaldo Carvalho de Melo <acme@kernel.org>
Cc: Jesper Dangaard Brouer <brouer@redhat.com>
Cc: Stanislav Fomichev <sdf@google.com>

Quentin Monnet (8):
  tools: bpftool: add basic probe capability, probe syscall and kversion
  tools: bpftool: add probes for /proc/ eBPF parameters
  tools: bpftool: add probes for kernel configuration options
  tools: bpftool: add probes for eBPF program types
  tools: bpftool: add probes for eBPF map types
  tools: bpftool: add probes for eBPF helper functions
  tools: bpftool: add probes for a network device
  tools: bpftool: add bash completion for bpftool probes

 .../bpftool/Documentation/bpftool-cgroup.rst  |    1 +
 .../bpftool/Documentation/bpftool-feature.rst |   85 ++
 .../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/bash-completion/bpftool     |   19 +
 tools/bpf/bpftool/common.c                    |    2 +-
 tools/bpf/bpftool/feature.c                   | 1012 +++++++++++++++++
 tools/bpf/bpftool/main.c                      |    3 +-
 tools/bpf/bpftool/main.h                      |    5 +
 tools/bpf/bpftool/map.c                       |    4 +-
 13 files changed, 1133 insertions(+), 3 deletions(-)
 create mode 100644 tools/bpf/bpftool/Documentation/bpftool-feature.rst
 create mode 100644 tools/bpf/bpftool/feature.c

-- 
2.17.1

^ permalink raw reply	[flat|nested] 41+ messages in thread

* [PATCH bpf-next 1/8] tools: bpftool: add basic probe capability, probe syscall and kversion
  2018-12-13 12:19 [PATCH bpf-next 0/8] tools: bpftool: add probes for system and device Quentin Monnet
@ 2018-12-13 12:19 ` Quentin Monnet
  2018-12-14  2:50   ` Stanislav Fomichev
  2018-12-14 23:35   ` Daniel Borkmann
  2018-12-13 12:19 ` [PATCH bpf-next 2/8] tools: bpftool: add probes for /proc/ eBPF parameters Quentin Monnet
                   ` (9 subsequent siblings)
  10 siblings, 2 replies; 41+ messages in thread
From: Quentin Monnet @ 2018-12-13 12:19 UTC (permalink / raw)
  To: Alexei Starovoitov, Daniel Borkmann
  Cc: netdev, oss-drivers, Quentin Monnet, Arnaldo Carvalho de Melo,
	Jesper Dangaard Brouer, Stanislav Fomichev

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@netronome.com>
Reviewed-by: Jakub Kicinski <jakub.kicinski@netronome.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);
+	else
+		printf("%s is %savailable\n", plain_name, res ? "" : "NOT ");
+}
+
+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

^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [PATCH bpf-next 2/8] tools: bpftool: add probes for /proc/ eBPF parameters
  2018-12-13 12:19 [PATCH bpf-next 0/8] tools: bpftool: add probes for system and device Quentin Monnet
  2018-12-13 12:19 ` [PATCH bpf-next 1/8] tools: bpftool: add basic probe capability, probe syscall and kversion Quentin Monnet
@ 2018-12-13 12:19 ` Quentin Monnet
  2018-12-14  2:58   ` Stanislav Fomichev
  2018-12-14 23:40   ` Daniel Borkmann
  2018-12-13 12:19 ` [PATCH bpf-next 3/8] tools: bpftool: add probes for kernel configuration options Quentin Monnet
                   ` (8 subsequent siblings)
  10 siblings, 2 replies; 41+ messages in thread
From: Quentin Monnet @ 2018-12-13 12:19 UTC (permalink / raw)
  To: Alexei Starovoitov, Daniel Borkmann
  Cc: netdev, oss-drivers, Quentin Monnet, Arnaldo Carvalho de Melo,
	Jesper Dangaard Brouer, Stanislav Fomichev

Add a set of probes to dump the eBPF-related parameters available from
/proc/: availability of bpf() syscall for unprivileged users,
JIT compiler status and hardening status, kallsyms exports status.

Sample output:

    # bpftool feature probe kernel
    Scanning system configuration...
    bpf() syscall for unprivileged users is enabled
    JIT compiler is disabled
    JIT compiler hardening is disabled
    JIT compiler kallsyms exports are disabled
    ...

    # bpftool --json --pretty feature probe kernel
    {
        "system_config": {
            "unprivileged_bpf_disabled": 0,
            "bpf_jit_enable": 0,
            "bpf_jit_harden": 0,
            "bpf_jit_kallsyms": 0
        },
        ...
    }

    # bpftool feature probe kernel macros prefix BPFTOOL_
    #define UNPRIVILEGED_BPF_DISABLED UNPRIVILEGED_BPF_DISABLED_OFF
    #define  UNPRIVILEGED_BPF_DISABLED_OFF 0
    #define  UNPRIVILEGED_BPF_DISABLED_ON 1
    #define  UNPRIVILEGED_BPF_DISABLED_UNKNOWN -1
    #define JIT_COMPILER_ENABLE JIT_COMPILER_ENABLE_OFF
    #define  JIT_COMPILER_ENABLE_OFF 0
    #define  JIT_COMPILER_ENABLE_ON 1
    #define  JIT_COMPILER_ENABLE_ON_WITH_DEBUG 2
    #define  JIT_COMPILER_ENABLE_UNKNOWN -1
    #define JIT_COMPILER_HARDEN JIT_COMPILER_HARDEN_OFF
    #define  JIT_COMPILER_HARDEN_OFF 0
    #define  JIT_COMPILER_HARDEN_FOR_UNPRIVILEGED 1
    #define  JIT_COMPILER_HARDEN_FOR_ALL_USERS 2
    #define  JIT_COMPILER_HARDEN_UNKNOWN -1
    #define JIT_COMPILER_KALLSYMS JIT_COMPILER_KALLSYMS_OFF
    #define  JIT_COMPILER_KALLSYMS_OFF 0
    #define  JIT_COMPILER_KALLSYMS_FOR_ROOT 1
    #define  JIT_COMPILER_KALLSYMS_UNKNOWN -1
    ...

These probes are skipped if procfs is not mounted.

Signed-off-by: Quentin Monnet <quentin.monnet@netronome.com>
Reviewed-by: Jakub Kicinski <jakub.kicinski@netronome.com>
---
 tools/bpf/bpftool/feature.c | 271 ++++++++++++++++++++++++++++++++++++
 1 file changed, 271 insertions(+)

diff --git a/tools/bpf/bpftool/feature.c b/tools/bpf/bpftool/feature.c
index e1784611575d..9fa7016c7d21 100644
--- a/tools/bpf/bpftool/feature.c
+++ b/tools/bpf/bpftool/feature.c
@@ -5,6 +5,7 @@
 #include <string.h>
 #include <unistd.h>
 #include <sys/utsname.h>
+#include <sys/vfs.h>
 
 #include <linux/filter.h>
 #include <linux/limits.h>
@@ -13,11 +14,29 @@
 
 #include "main.h"
 
+#ifndef PROC_SUPER_MAGIC
+# define PROC_SUPER_MAGIC	0x9fa0
+#endif
+
 enum probe_component {
 	COMPONENT_UNSPEC,
 	COMPONENT_KERNEL,
 };
 
+/* Miscellaneous utility functions */
+
+static bool check_procfs(void)
+{
+	struct statfs st_fs;
+
+	if (statfs("/proc", &st_fs) < 0)
+		return false;
+	if ((unsigned long)st_fs.f_type != PROC_SUPER_MAGIC)
+		return false;
+
+	return true;
+}
+
 /* Printing utility functions */
 
 static void
@@ -49,6 +68,236 @@ print_start_section(const char *json_title, const char *define_comment,
 
 /* Probing functions */
 
+static int read_procfs(const char *path)
+{
+	char *endptr, *line = NULL;
+	size_t len = 0;
+	FILE *fd;
+	int res;
+
+	fd = fopen(path, "r");
+	if (!fd)
+		return -1;
+
+	res = getline(&line, &len, fd);
+	fclose(fd);
+	if (res < 0)
+		return -1;
+
+	errno = 0;
+	res = strtol(line, &endptr, 10);
+	if (errno || *line == '\0' || *endptr != '\n')
+		res = -1;
+	free(line);
+
+	return res;
+}
+
+static void probe_unprivileged_disabled(const char *define_prefix)
+{
+	int res;
+
+	res = read_procfs("/proc/sys/kernel/unprivileged_bpf_disabled");
+	if (json_output) {
+		jsonw_int_field(json_wtr, "unprivileged_bpf_disabled", res);
+	} else if (define_prefix) {
+		printf("#define %sUNPRIVILEGED_BPF_DISABLED ", define_prefix);
+		switch (res) {
+		case 0:
+			printf("%sUNPRIVILEGED_BPF_DISABLED_OFF\n",
+			       define_prefix);
+			break;
+		case 1:
+			printf("%sUNPRIVILEGED_BPF_DISABLED_ON\n",
+			       define_prefix);
+			break;
+		case -1:
+			printf("%sUNPRIVILEGED_BPF_DISABLED_UNKNOWN\n",
+			       define_prefix);
+			break;
+		default:
+			printf("%d\n", res);
+		}
+		printf("#define  %sUNPRIVILEGED_BPF_DISABLED_OFF 0\n",
+		       define_prefix);
+		printf("#define  %sUNPRIVILEGED_BPF_DISABLED_ON 1\n",
+		       define_prefix);
+		printf("#define  %sUNPRIVILEGED_BPF_DISABLED_UNKNOWN -1\n",
+		       define_prefix);
+	} else {
+		switch (res) {
+		case 0:
+			printf("bpf() syscall for unprivileged users is enabled\n");
+			break;
+		case 1:
+			printf("bpf() syscall restricted to privileged users\n");
+			break;
+		case -1:
+			printf("Unable to retrieve required privileges for bpf() syscall\n");
+			break;
+		default:
+			printf("bpf() syscall restriction has unknown value %d\n", res);
+		}
+	}
+}
+
+static void probe_jit_enable(const char *define_prefix)
+{
+	int res;
+
+	res = read_procfs("/proc/sys/net/core/bpf_jit_enable");
+	if (json_output) {
+		jsonw_int_field(json_wtr, "bpf_jit_enable", res);
+	} else if (define_prefix) {
+		printf("#define %sJIT_COMPILER_ENABLE ", define_prefix);
+		switch (res) {
+		case 0:
+			printf("%sJIT_COMPILER_ENABLE_OFF\n", define_prefix);
+			break;
+		case 1:
+			printf("%sJIT_COMPILER_ENABLE_ON\n", define_prefix);
+			break;
+		case 2:
+			printf("%sJIT_COMPILER_ENABLE_ON_WITH_DEBUG\n",
+			       define_prefix);
+			break;
+		case -1:
+			printf("%sJIT_COMPILER_ENABLE_UNKNOWN\n",
+			       define_prefix);
+			break;
+		default:
+			printf("%d\n", res);
+		}
+		printf("#define  %sJIT_COMPILER_ENABLE_OFF 0\n", define_prefix);
+		printf("#define  %sJIT_COMPILER_ENABLE_ON 1\n", define_prefix);
+		printf("#define  %sJIT_COMPILER_ENABLE_ON_WITH_DEBUG 2\n",
+		       define_prefix);
+		printf("#define  %sJIT_COMPILER_ENABLE_UNKNOWN -1\n",
+		       define_prefix);
+	} else {
+		switch (res) {
+		case 0:
+			printf("JIT compiler is disabled\n");
+			break;
+		case 1:
+			printf("JIT compiler is enabled\n");
+			break;
+		case 2:
+			printf("JIT compiler is enabled with debugging traces in kernel logs\n");
+			break;
+		case -1:
+			printf("Unable to retrieve JIT-compiler status\n");
+			break;
+		default:
+			printf("JIT-compiler status has unknown value %d\n",
+			       res);
+		}
+	}
+}
+
+static void probe_jit_harden(const char *define_prefix)
+{
+	int res;
+
+	res = read_procfs("/proc/sys/net/core/bpf_jit_harden");
+	if (json_output) {
+		jsonw_int_field(json_wtr, "bpf_jit_harden", res);
+	} else if (define_prefix) {
+		printf("#define %sJIT_COMPILER_HARDEN ", define_prefix);
+		switch (res) {
+		case 0:
+			printf("%sJIT_COMPILER_HARDEN_OFF\n", define_prefix);
+			break;
+		case 1:
+			printf("%sJIT_COMPILER_HARDEN_FOR_UNPRIVILEGED\n",
+			       define_prefix);
+			break;
+		case 2:
+			printf("%sJIT_COMPILER_HARDEN_FOR_ALL_USERS\n",
+			       define_prefix);
+			break;
+		case -1:
+			printf("%sJIT_COMPILER_HARDEN_UNKNOWN\n",
+			       define_prefix);
+			break;
+		default:
+			printf("%d\n", res);
+		}
+		printf("#define  %sJIT_COMPILER_HARDEN_OFF 0\n", define_prefix);
+		printf("#define  %sJIT_COMPILER_HARDEN_FOR_UNPRIVILEGED 1\n",
+		       define_prefix);
+		printf("#define  %sJIT_COMPILER_HARDEN_FOR_ALL_USERS 2\n",
+		       define_prefix);
+		printf("#define  %sJIT_COMPILER_HARDEN_UNKNOWN -1\n",
+		       define_prefix);
+	} else {
+		switch (res) {
+		case 0:
+			printf("JIT compiler hardening is disabled\n");
+			break;
+		case 1:
+			printf("JIT compiler hardening is enabled for unprivileged users\n");
+			break;
+		case 2:
+			printf("JIT compiler hardening is enabled for all users\n");
+			break;
+		case -1:
+			printf("Unable to retrieve JIT hardening status\n");
+			break;
+		default:
+			printf("JIT hardening status has unknown value %d\n",
+			       res);
+		}
+	}
+}
+
+static void probe_jit_kallsyms(const char *define_prefix)
+{
+	int res;
+
+	res = read_procfs("/proc/sys/net/core/bpf_jit_kallsyms");
+	if (json_output) {
+		jsonw_int_field(json_wtr, "bpf_jit_kallsyms", res);
+	} else if (define_prefix) {
+		printf("#define %sJIT_COMPILER_KALLSYMS ", define_prefix);
+		switch (res) {
+		case 0:
+			printf("%sJIT_COMPILER_KALLSYMS_OFF\n", define_prefix);
+			break;
+		case 1:
+			printf("%sJIT_COMPILER_KALLSYMS_FOR_ROOT\n",
+			       define_prefix);
+			break;
+		case -1:
+			printf("%sJIT_COMPILER_KALLSYMS_UNKNOWN\n",
+			       define_prefix);
+			break;
+		default:
+			printf("%d\n", res);
+		}
+		printf("#define  %sJIT_COMPILER_KALLSYMS_OFF 0\n",
+		       define_prefix);
+		printf("#define  %sJIT_COMPILER_KALLSYMS_FOR_ROOT 1\n",
+		       define_prefix);
+		printf("#define  %sJIT_COMPILER_KALLSYMS_UNKNOWN -1\n",
+		       define_prefix);
+	} else {
+		switch (res) {
+		case 0:
+			printf("JIT compiler kallsyms exports are disabled\n");
+			break;
+		case 1:
+			printf("JIT compiler kallsyms exports are enabled for root\n");
+			break;
+		case -1:
+			printf("Unable to retrieve JIT kallsyms export status\n");
+			break;
+		default:
+			printf("JIT kallsyms exports status has unknown value %d\n", res);
+		}
+	}
+}
+
 static int probe_kernel_version(const char *define_prefix)
 {
 	int version, subversion, patchlevel, code = 0;
@@ -138,6 +387,28 @@ static int do_probe(int argc, char **argv)
 	if (json_output)
 		jsonw_start_object(json_wtr);
 
+	switch (target) {
+	case COMPONENT_KERNEL:
+	case COMPONENT_UNSPEC:
+		print_start_section("system_config",
+				    "/*** System configuration ***/",
+				    "Scanning system configuration...",
+				    define_prefix);
+		if (check_procfs()) {
+			probe_unprivileged_disabled(define_prefix);
+			probe_jit_enable(define_prefix);
+			probe_jit_harden(define_prefix);
+			probe_jit_kallsyms(define_prefix);
+		} else {
+			p_info("/* procfs not mounted, skipping related probes */");
+		}
+		if (json_output)
+			jsonw_end_object(json_wtr);
+		else
+			printf("\n");
+		break;
+	}
+
 	print_start_section("syscall_config",
 			    "/*** System call and kernel version ***/",
 			    "Scanning system call and kernel version...",
-- 
2.17.1

^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [PATCH bpf-next 3/8] tools: bpftool: add probes for kernel configuration options
  2018-12-13 12:19 [PATCH bpf-next 0/8] tools: bpftool: add probes for system and device Quentin Monnet
  2018-12-13 12:19 ` [PATCH bpf-next 1/8] tools: bpftool: add basic probe capability, probe syscall and kversion Quentin Monnet
  2018-12-13 12:19 ` [PATCH bpf-next 2/8] tools: bpftool: add probes for /proc/ eBPF parameters Quentin Monnet
@ 2018-12-13 12:19 ` Quentin Monnet
  2018-12-14 23:56   ` Daniel Borkmann
  2018-12-13 12:19 ` [PATCH bpf-next 4/8] tools: bpftool: add probes for eBPF program types Quentin Monnet
                   ` (7 subsequent siblings)
  10 siblings, 1 reply; 41+ messages in thread
From: Quentin Monnet @ 2018-12-13 12:19 UTC (permalink / raw)
  To: Alexei Starovoitov, Daniel Borkmann
  Cc: netdev, oss-drivers, Quentin Monnet, Arnaldo Carvalho de Melo,
	Jesper Dangaard Brouer, Stanislav Fomichev

Add probes to dump a number of options set (or not set) for compiling
the kernel image. These parameters provide information about what BPF
components should be available on the system. A number of them are not
directly related to eBPF, but are in fact used in the kernel as
conditions on which to compile, or not to compile, some of the eBPF
helper functions.

Sample output:

    # bpftool feature probe kernel
    Scanning system configuration...
    ...
    CONFIG_BPF is set to y
    CONFIG_BPF_SYSCALL is set to y
    CONFIG_HAVE_EBPF_JIT is set to y
    ...

    # bpftool --pretty --json feature probe kernel
    {
        "system_config": {
            ...
            "CONFIG_BPF": "y",
            "CONFIG_BPF_SYSCALL": "y",
            "CONFIG_HAVE_EBPF_JIT": "y",
            ...
        }
    }

    # bpftool feature probe kernel macros prefix BPFTOOL_
    /*** System configuration ***/
    ...
    #define BPFTOOL_CONFIG_BPF y
    #define BPFTOOL_CONFIG_BPF_SYSCALL y
    #define BPFTOOL_CONFIG_HAVE_EBPF_JIT y
    ...

Signed-off-by: Quentin Monnet <quentin.monnet@netronome.com>
Reviewed-by: Jakub Kicinski <jakub.kicinski@netronome.com>
---
 tools/bpf/bpftool/feature.c | 144 ++++++++++++++++++++++++++++++++++++
 1 file changed, 144 insertions(+)

diff --git a/tools/bpf/bpftool/feature.c b/tools/bpf/bpftool/feature.c
index 9fa7016c7d21..4a3a45f44162 100644
--- a/tools/bpf/bpftool/feature.c
+++ b/tools/bpf/bpftool/feature.c
@@ -52,6 +52,37 @@ print_bool_feature(const char *feat_name, const char *define_name,
 		printf("%s is %savailable\n", plain_name, res ? "" : "NOT ");
 }
 
+static void
+print_kernel_option(const char *name, const char *value,
+		    const char *define_prefix)
+{
+	char *endptr;
+	int res;
+
+	if (json_output) {
+		if (!value) {
+			jsonw_null_field(json_wtr, name);
+			return;
+		}
+		errno = 0;
+		res = strtol(value, &endptr, 0);
+		if (!errno && *endptr == '\n')
+			jsonw_int_field(json_wtr, name, res);
+		else
+			jsonw_string_field(json_wtr, name, value);
+	} else if (define_prefix) {
+		if (value)
+			printf("#define %s%s %s\n", define_prefix, name, value);
+		else
+			printf("#define %sNO_%s\n", define_prefix, name);
+	} else {
+		if (value)
+			printf("%s is set to %s\n", name, value);
+		else
+			printf("%s is not set\n", name);
+	}
+}
+
 static void
 print_start_section(const char *json_title, const char *define_comment,
 		    const char *plain_title, const char *define_prefix)
@@ -298,6 +329,118 @@ static void probe_jit_kallsyms(const char *define_prefix)
 	}
 }
 
+static char *get_kernel_config_option(FILE *fd, const char *option)
+{
+	size_t line_n = 0, optlen = strlen(option);
+	char *res, *strval, *line = NULL;
+	ssize_t n;
+
+	rewind(fd);
+	while ((n = getline(&line, &line_n, fd)) > 0) {
+		if (strncmp(line, option, optlen))
+			continue;
+		/* Check we have at least '=', value, and '\n' */
+		if (strlen(line) < optlen + 3)
+			continue;
+		if (*(line + optlen) != '=')
+			continue;
+
+		/* Trim ending '\n' */
+		line[strlen(line) - 1] = '\0';
+
+		/* Copy and return config option value */
+		strval = line + optlen + 1;
+		res = strdup(strval);
+		free(line);
+		return res;
+	}
+	free(line);
+
+	return NULL;
+}
+
+static void probe_kernel_image_config(const char *define_prefix)
+{
+	const char * const options[] = {
+		"CONFIG_BPF",
+		"CONFIG_BPF_SYSCALL",
+		"CONFIG_HAVE_EBPF_JIT",
+		"CONFIG_BPF_JIT",
+		"CONFIG_BPF_JIT_ALWAYS_ON",
+		"CONFIG_NET",
+		"CONFIG_XDP_SOCKETS",
+		"CONFIG_CGROUPS",
+		"CONFIG_CGROUP_BPF",
+		"CONFIG_CGROUP_NET_CLASSID",
+		"CONFIG_BPF_EVENTS",
+		"CONFIG_LWTUNNEL_BPF",
+		"CONFIG_NET_ACT_BPF",
+		"CONFIG_NET_CLS_ACT",
+		"CONFIG_NET_CLS_BPF",
+		"CONFIG_NET_SCH_INGRESS",
+		"CONFIG_XFRM",
+		"CONFIG_SOCK_CGROUP_DATA",
+		"CONFIG_IP_ROUTE_CLASSID",
+		"CONFIG_IPV6_SEG6_BPF",
+		"CONFIG_FUNCTION_ERROR_INJECTION",
+		"CONFIG_BPF_KPROBE_OVERRIDE",
+		"CONFIG_BPF_LIRC_MODE2",
+		"CONFIG_NETFILTER_XT_MATCH_BPF",
+		"CONFIG_TEST_BPF",
+		"CONFIG_BPFILTER",
+		"CONFIG_BPFILTER_UMH",
+		"CONFIG_BPF_STREAM_PARSER",
+	};
+	char *value, *buf = NULL;
+	struct utsname utsn;
+	char path[PATH_MAX];
+	size_t i, n;
+	ssize_t ret;
+	FILE *fd;
+
+	if (uname(&utsn))
+		goto no_config;
+
+	snprintf(path, sizeof(path), "/boot/config-%s", utsn.release);
+
+	fd = fopen(path, "r");
+	if (!fd && errno == ENOENT) {
+		/* Sometimes config is at /proc/config */
+		fd = fopen("/proc/config", "r");
+	}
+	if (!fd) {
+		p_err("can't open kernel config file: %s", strerror(errno));
+		goto no_config;
+	}
+	/* Sanity checks */
+	ret = getline(&buf, &n, fd);
+	ret = getline(&buf, &n, fd);
+	if (!buf || !ret) {
+		p_err("can't read from kernel config file: %s",
+		      strerror(errno));
+		free(buf);
+		goto no_config;
+	}
+	if (strcmp(buf, "# Automatically generated file; DO NOT EDIT.\n")) {
+		p_err("can't find correct kernel config file");
+		free(buf);
+		goto no_config;
+	}
+	free(buf);
+
+	for (i = 0; i < ARRAY_SIZE(options); i++) {
+		value = get_kernel_config_option(fd, options[i]);
+		print_kernel_option(options[i], value, define_prefix);
+		free(value);
+	}
+	fclose(fd);
+	return;
+
+no_config:
+	for (i = 0; i < ARRAY_SIZE(options); i++)
+		print_kernel_option(options[i], NULL, define_prefix);
+}
+
 static int probe_kernel_version(const char *define_prefix)
 {
 	int version, subversion, patchlevel, code = 0;
@@ -402,6 +545,7 @@ static int do_probe(int argc, char **argv)
 		} else {
 			p_info("/* procfs not mounted, skipping related probes */");
 		}
+		probe_kernel_image_config(define_prefix);
 		if (json_output)
 			jsonw_end_object(json_wtr);
 		else
-- 
2.17.1

^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [PATCH bpf-next 4/8] tools: bpftool: add probes for eBPF program types
  2018-12-13 12:19 [PATCH bpf-next 0/8] tools: bpftool: add probes for system and device Quentin Monnet
                   ` (2 preceding siblings ...)
  2018-12-13 12:19 ` [PATCH bpf-next 3/8] tools: bpftool: add probes for kernel configuration options Quentin Monnet
@ 2018-12-13 12:19 ` Quentin Monnet
  2018-12-13 12:19 ` [PATCH bpf-next 5/8] tools: bpftool: add probes for eBPF map types Quentin Monnet
                   ` (6 subsequent siblings)
  10 siblings, 0 replies; 41+ messages in thread
From: Quentin Monnet @ 2018-12-13 12:19 UTC (permalink / raw)
  To: Alexei Starovoitov, Daniel Borkmann
  Cc: netdev, oss-drivers, Quentin Monnet, Arnaldo Carvalho de Melo,
	Jesper Dangaard Brouer, Stanislav Fomichev

Add new probes to test what eBPF program types are available on the
system. For each type, try loading a very simple program of that type
and see if the verifier complains.

Sample output:

    # bpftool feature probe kernel
    ...
    Scanning eBPF program types...
    eBPF program_type socket_filter is available
    eBPF program_type kprobe is available
    eBPF program_type sched_cls is available
    ...

    # bpftool --json --pretty feature probe kernel
    {
        ...
        "program_types": {
            "have_socket_filter_prog_type": true,
            "have_kprobe_prog_type": true,
            "have_sched_cls_prog_type": true,
            ...
        }
    }

    # bpftool feature probe kernel macros prefix BPFTOOL_
    ...
    /*** eBPF program types ***/
    #define BPFTOOL_SOCKET_FILTER_PROG_TYPE
    #define BPFTOOL_KPROBE_PROG_TYPE
    #define BPFTOOL_SCHED_CLS_PROG_TYPE
    ...

Signed-off-by: Quentin Monnet <quentin.monnet@netronome.com>
Reviewed-by: Jakub Kicinski <jakub.kicinski@netronome.com>
---
 tools/bpf/bpftool/feature.c | 102 +++++++++++++++++++++++++++++++++++-
 1 file changed, 100 insertions(+), 2 deletions(-)

diff --git a/tools/bpf/bpftool/feature.c b/tools/bpf/bpftool/feature.c
index 4a3a45f44162..4910c9c325d6 100644
--- a/tools/bpf/bpftool/feature.c
+++ b/tools/bpf/bpftool/feature.c
@@ -1,6 +1,7 @@
 // SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
 /* Copyright (c) 2018 Netronome Systems, Inc. */
 
+#include <ctype.h>
 #include <errno.h>
 #include <string.h>
 #include <unistd.h>
@@ -37,6 +38,14 @@ static bool check_procfs(void)
 	return true;
 }
 
+static void uppercase(char *str, size_t len)
+{
+	size_t i;
+
+	for (i = 0; i < len && str[i] != '\0'; i++)
+		str[i] = toupper(str[i]);
+}
+
 /* Printing utility functions */
 
 static void
@@ -97,6 +106,19 @@ print_start_section(const char *json_title, const char *define_comment,
 	}
 }
 
+static void
+print_end_then_start_section(const char *json_title, const char *define_title,
+			     const char *plain_title, const char *define_prefix)
+{
+	if (json_output)
+		jsonw_end_object(json_wtr);
+	else
+		printf("\n");
+
+	print_start_section(json_title, define_title, plain_title,
+			    define_prefix);
+}
+
 /* Probing functions */
 
 static int read_procfs(const char *path)
@@ -480,10 +502,73 @@ static bool probe_bpf_syscall(const char *define_prefix)
 	return res;
 }
 
+static void
+prog_load(enum bpf_prog_type prog_type, const struct bpf_insn *insns,
+	  size_t insns_cnt, int kernel_version, char *buf, size_t buf_len)
+{
+	struct bpf_load_program_attr xattr = {};
+	int fd;
+
+	switch (prog_type) {
+	case BPF_PROG_TYPE_CGROUP_SOCK_ADDR:
+		xattr.expected_attach_type = BPF_CGROUP_INET4_CONNECT;
+		break;
+	default:
+		break;
+	}
+
+	xattr.prog_type = prog_type;
+	xattr.insns = insns;
+	xattr.insns_cnt = insns_cnt;
+	xattr.license = "GPL";
+	xattr.kern_version = kernel_version;
+
+	fd = bpf_load_program_xattr(&xattr, buf, buf_len);
+	if (fd >= 0)
+		close(fd);
+}
+
+static void
+probe_prog_type(enum bpf_prog_type prog_type, int kernel_version,
+		bool *supported_types, const char *define_prefix)
+{
+	char buf[4096], feat_name[128], define_name[128], plain_desc[128];
+	const char *plain_comment = "eBPF program_type ";
+	struct bpf_insn insns[2] = {
+		BPF_MOV64_IMM(BPF_REG_0, 0),
+		BPF_EXIT_INSN()
+	};
+	size_t maxlen;
+	bool res;
+
+	errno = 0;
+	prog_load(prog_type, insns, ARRAY_SIZE(insns), kernel_version,
+		  buf, sizeof(buf));
+	res = (errno != EINVAL && errno != EOPNOTSUPP);
+
+	supported_types[prog_type] |= res;
+
+	maxlen = sizeof(plain_desc) - strlen(plain_comment) - 1;
+	if (strlen(prog_type_name[prog_type]) > maxlen) {
+		p_info("program type name too long");
+		return;
+	}
+
+	sprintf(feat_name, "have_%s_prog_type", prog_type_name[prog_type]);
+	sprintf(define_name, "%s_prog_type", prog_type_name[prog_type]);
+	uppercase(define_name, sizeof(define_name));
+	sprintf(plain_desc, "%s%s", plain_comment, prog_type_name[prog_type]);
+	print_bool_feature(feat_name, define_name, plain_desc, res,
+			   define_prefix);
+}
+
 static int do_probe(int argc, char **argv)
 {
 	enum probe_component target = COMPONENT_UNSPEC;
 	const char *define_prefix = NULL;
+	bool supported_types[128] = {};
+	int kernel_version;
+	unsigned int i;
 
 	/* Detection assumes user has sufficient privileges (CAP_SYS_ADMIN).
 	 * Let's approximate, and restrict usage to root user only.
@@ -558,9 +643,22 @@ static int do_probe(int argc, char **argv)
 			    "Scanning system call and kernel version...",
 			    define_prefix);
 
-	probe_kernel_version(define_prefix);
-	probe_bpf_syscall(define_prefix);
+	kernel_version = probe_kernel_version(define_prefix);
+	if (!probe_bpf_syscall(define_prefix))
+		/* bpf() syscall unavailable, don't probe other BPF features */
+		goto exit_close_json;
+
+	print_end_then_start_section("program_types",
+				     "/*** eBPF program types ***/",
+				     "Scanning eBPF program types...",
+				     define_prefix);
+
+	for (i = BPF_PROG_TYPE_SOCKET_FILTER;
+	     i < ARRAY_SIZE(prog_type_name); i++)
+		probe_prog_type(i, kernel_version, supported_types,
+				define_prefix);
 
+exit_close_json:
 	if (json_output) {
 		/* End current "section" of probes */
 		jsonw_end_object(json_wtr);
-- 
2.17.1

^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [PATCH bpf-next 5/8] tools: bpftool: add probes for eBPF map types
  2018-12-13 12:19 [PATCH bpf-next 0/8] tools: bpftool: add probes for system and device Quentin Monnet
                   ` (3 preceding siblings ...)
  2018-12-13 12:19 ` [PATCH bpf-next 4/8] tools: bpftool: add probes for eBPF program types Quentin Monnet
@ 2018-12-13 12:19 ` Quentin Monnet
  2018-12-13 12:19 ` [PATCH bpf-next 6/8] tools: bpftool: add probes for eBPF helper functions Quentin Monnet
                   ` (5 subsequent siblings)
  10 siblings, 0 replies; 41+ messages in thread
From: Quentin Monnet @ 2018-12-13 12:19 UTC (permalink / raw)
  To: Alexei Starovoitov, Daniel Borkmann
  Cc: netdev, oss-drivers, Quentin Monnet, Arnaldo Carvalho de Melo,
	Jesper Dangaard Brouer, Stanislav Fomichev

Add new probes for eBPF map types, to detect what are the ones available
on the system. Try creating one map of each type, and see if the kernel
complains.

Sample output:

    # bpftool feature probe kernel
    ...
    Scanning eBPF map types...
    eBPF map_type hash is available
    eBPF map_type array is available
    eBPF map_type prog_array is available
    ...

    # bpftool --json --pretty feature probe kernel
    {
        ...
        "map_types": {
            "have_hash_map_type": true,
            "have_array_map_type": true,
            "have_prog_array_map_type": true,
            ...
        }
    }

    # bpftool feature probe kernel macros prefix BPFTOOL_
    ...
    /*** eBPF map types ***/
    #define BPFTOOL_HASH_MAP_TYPE
    #define BPFTOOL_ARRAY_MAP_TYPE
    #define BPFTOOL_PROG_ARRAY_MAP_TYPE
    ...

Signed-off-by: Quentin Monnet <quentin.monnet@netronome.com>
Reviewed-by: Jakub Kicinski <jakub.kicinski@netronome.com>
---
 tools/bpf/bpftool/feature.c | 88 +++++++++++++++++++++++++++++++++++++
 tools/bpf/bpftool/main.h    |  3 ++
 tools/bpf/bpftool/map.c     |  4 +-
 3 files changed, 94 insertions(+), 1 deletion(-)

diff --git a/tools/bpf/bpftool/feature.c b/tools/bpf/bpftool/feature.c
index 4910c9c325d6..85928f172413 100644
--- a/tools/bpf/bpftool/feature.c
+++ b/tools/bpf/bpftool/feature.c
@@ -562,6 +562,86 @@ probe_prog_type(enum bpf_prog_type prog_type, int kernel_version,
 			   define_prefix);
 }
 
+static void
+probe_map_type(enum bpf_map_type map_type, const char *define_prefix)
+{
+	char feat_name[128], define_name[128], plain_desc[128];
+	int key_size, value_size, max_entries, map_flags;
+	const char *plain_comment = "eBPF map_type ";
+	struct bpf_create_map_attr attr = {};
+	int fd = -1, fd_inner;
+	size_t maxlen;
+	bool res;
+
+	key_size = sizeof(__u32);
+	value_size = sizeof(__u32);
+	max_entries = 1;
+	map_flags = 0;
+
+	switch (map_type) {
+	case BPF_MAP_TYPE_LPM_TRIE:
+		key_size = sizeof(__u64);
+		value_size = sizeof(__u64);
+		map_flags = BPF_F_NO_PREALLOC;
+		break;
+	case BPF_MAP_TYPE_STACK_TRACE:
+		value_size = sizeof(__u64);
+		break;
+	case BPF_MAP_TYPE_CGROUP_STORAGE:
+	case BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE:
+		key_size = sizeof(struct bpf_cgroup_storage_key);
+		value_size = sizeof(__u64);
+		max_entries = 0;
+		break;
+	case BPF_MAP_TYPE_QUEUE:
+	case BPF_MAP_TYPE_STACK:
+		key_size = 0;
+		break;
+	default:
+		break;
+	}
+
+	switch (map_type) {
+	case BPF_MAP_TYPE_ARRAY_OF_MAPS:
+	case BPF_MAP_TYPE_HASH_OF_MAPS:
+		fd_inner = bpf_create_map(BPF_MAP_TYPE_HASH,
+					  sizeof(__u32), sizeof(__u32), 1, 0);
+		if (fd_inner < 0)
+			break;
+		fd = bpf_create_map_in_map(map_type, "", sizeof(__u32),
+					   fd_inner, 1, 0);
+		close(fd_inner);
+		break;
+	default:
+		/* Note: No other restriction on map type probes for offload */
+		attr.map_type = map_type;
+		attr.key_size = key_size;
+		attr.value_size = value_size;
+		attr.max_entries = max_entries;
+		attr.map_flags = map_flags;
+
+		fd = bpf_create_map_xattr(&attr);
+		break;
+	}
+	if (fd >= 0)
+		close(fd);
+
+	res = fd >= 0;
+
+	maxlen = sizeof(plain_desc) - strlen(plain_comment) - 1;
+	if (strlen(map_type_name[map_type]) > maxlen) {
+		p_info("map type name too long");
+		return;
+	}
+
+	sprintf(feat_name, "have_%s_map_type", map_type_name[map_type]);
+	sprintf(define_name, "%s_map_type", map_type_name[map_type]);
+	uppercase(define_name, sizeof(define_name));
+	sprintf(plain_desc, "%s%s", plain_comment, map_type_name[map_type]);
+	print_bool_feature(feat_name, define_name, plain_desc, res,
+			   define_prefix);
+}
+
 static int do_probe(int argc, char **argv)
 {
 	enum probe_component target = COMPONENT_UNSPEC;
@@ -658,6 +738,14 @@ static int do_probe(int argc, char **argv)
 		probe_prog_type(i, kernel_version, supported_types,
 				define_prefix);
 
+	print_end_then_start_section("map_types",
+				     "/*** eBPF map types ***/",
+				     "Scanning eBPF map types...",
+				     define_prefix);
+
+	for (i = BPF_MAP_TYPE_HASH; i < map_type_name_size; i++)
+		probe_map_type(i, define_prefix);
+
 exit_close_json:
 	if (json_output) {
 		/* End current "section" of probes */
diff --git a/tools/bpf/bpftool/main.h b/tools/bpf/bpftool/main.h
index 2acd8c08e8b6..d9a2b1eafae7 100644
--- a/tools/bpf/bpftool/main.h
+++ b/tools/bpf/bpftool/main.h
@@ -74,6 +74,9 @@ static const char * const prog_type_name[] = {
 	[BPF_PROG_TYPE_FLOW_DISSECTOR]		= "flow_dissector",
 };
 
+extern const char * const map_type_name[];
+extern const size_t map_type_name_size;
+
 enum bpf_obj_type {
 	BPF_OBJ_UNKNOWN,
 	BPF_OBJ_PROG,
diff --git a/tools/bpf/bpftool/map.c b/tools/bpf/bpftool/map.c
index 2037e3dc864b..b73985589929 100644
--- a/tools/bpf/bpftool/map.c
+++ b/tools/bpf/bpftool/map.c
@@ -21,7 +21,7 @@
 #include "json_writer.h"
 #include "main.h"
 
-static const char * const map_type_name[] = {
+const char * const map_type_name[] = {
 	[BPF_MAP_TYPE_UNSPEC]			= "unspec",
 	[BPF_MAP_TYPE_HASH]			= "hash",
 	[BPF_MAP_TYPE_ARRAY]			= "array",
@@ -48,6 +48,8 @@ static const char * const map_type_name[] = {
 	[BPF_MAP_TYPE_STACK]			= "stack",
 };
 
+const size_t map_type_name_size = ARRAY_SIZE(map_type_name);
+
 static bool map_is_per_cpu(__u32 type)
 {
 	return type == BPF_MAP_TYPE_PERCPU_HASH ||
-- 
2.17.1

^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [PATCH bpf-next 6/8] tools: bpftool: add probes for eBPF helper functions
  2018-12-13 12:19 [PATCH bpf-next 0/8] tools: bpftool: add probes for system and device Quentin Monnet
                   ` (4 preceding siblings ...)
  2018-12-13 12:19 ` [PATCH bpf-next 5/8] tools: bpftool: add probes for eBPF map types Quentin Monnet
@ 2018-12-13 12:19 ` Quentin Monnet
  2018-12-15  0:08   ` Daniel Borkmann
  2018-12-13 12:19 ` [PATCH bpf-next 7/8] tools: bpftool: add probes for a network device Quentin Monnet
                   ` (4 subsequent siblings)
  10 siblings, 1 reply; 41+ messages in thread
From: Quentin Monnet @ 2018-12-13 12:19 UTC (permalink / raw)
  To: Alexei Starovoitov, Daniel Borkmann
  Cc: netdev, oss-drivers, Quentin Monnet, Arnaldo Carvalho de Melo,
	Jesper Dangaard Brouer, Stanislav Fomichev

Similarly to what was done for program types and map types, add a set of
probes to test the availability of the different eBPF helper functions
on the current system.

Sample output:

    # bpftool feature probe kernel
    ...
    Scanning eBPF helper functions...
    eBPF helper bpf_map_lookup_elem is available
    eBPF helper bpf_map_update_elem is available
    eBPF helper bpf_map_delete_elem is available
    ...

    # bpftool --json --pretty feature probe kernel
    {
        ...
        "helpers": {
            "have_bpf_map_lookup_elem_helper": true,
            "have_bpf_map_update_elem_helper": true,
            "have_bpf_map_delete_elem_helper": true,
            ...
        }
    }

    # bpftool feature probe kernel macros prefix BPFTOOL_
    ...
    /*** eBPF helper functions ***/
    #define BPFTOOL_BPF_MAP_LOOKUP_ELEM_HELPER
    #define BPFTOOL_BPF_MAP_UPDATE_ELEM_HELPER
    #define BPFTOOL_BPF_MAP_DELETE_ELEM_HELPER
    ...

Signed-off-by: Quentin Monnet <quentin.monnet@netronome.com>
Reviewed-by: Jakub Kicinski <jakub.kicinski@netronome.com>
---
 .../bpftool/Documentation/bpftool-feature.rst |   4 +
 tools/bpf/bpftool/feature.c                   | 152 ++++++++++++++++++
 2 files changed, 156 insertions(+)

diff --git a/tools/bpf/bpftool/Documentation/bpftool-feature.rst b/tools/bpf/bpftool/Documentation/bpftool-feature.rst
index 23920a7490e9..083d30510cce 100644
--- a/tools/bpf/bpftool/Documentation/bpftool-feature.rst
+++ b/tools/bpf/bpftool/Documentation/bpftool-feature.rst
@@ -39,6 +39,10 @@ DESCRIPTION
 		  names when including the output of this command as a header
 		  file.
 
+		  Note that when probed, some eBPF helpers (e.g.
+		  **bpf_trace_printk**\ () or **bpf_probe_write_user**\ ()) may
+		  print warnings to kernel logs.
+
 	**bpftool feature help**
 		  Print short help message.
 
diff --git a/tools/bpf/bpftool/feature.c b/tools/bpf/bpftool/feature.c
index 85928f172413..77221fff6ba9 100644
--- a/tools/bpf/bpftool/feature.c
+++ b/tools/bpf/bpftool/feature.c
@@ -24,6 +24,113 @@ enum probe_component {
 	COMPONENT_KERNEL,
 };
 
+#define MAX_HELPER_NAME_LEN 32
+struct helper_param {
+	enum bpf_prog_type progtype;
+	const char name[MAX_HELPER_NAME_LEN];
+};
+
+/* helper_progtype_and_name[index] associates to the BPF helper function of id
+ * "index" a name and a program type to run this helper with. In order to probe
+ * helper availability for programs offloaded to a network device, use
+ * offload-compatible types (e.g. XDP) everywhere we can. Caveats: helper
+ * probing may fail currently if only TC (but not XDP) is supported for
+ * offload.
+ */
+static const struct helper_param helper_progtype_and_name[] = {
+	{ BPF_PROG_TYPE_XDP,		"no_helper_with_id_0" },
+	{ BPF_PROG_TYPE_XDP,		"bpf_map_lookup_elem" },
+	{ BPF_PROG_TYPE_XDP,		"bpf_map_update_elem" },
+	{ BPF_PROG_TYPE_XDP,		"bpf_map_delete_elem" },
+	{ BPF_PROG_TYPE_KPROBE,		"bpf_probe_read" },
+	{ BPF_PROG_TYPE_XDP,		"bpf_ktime_get_ns" },
+	{ BPF_PROG_TYPE_XDP,		"bpf_trace_printk" },
+	{ BPF_PROG_TYPE_XDP,		"bpf_get_prandom_u32" },
+	{ BPF_PROG_TYPE_XDP,		"bpf_get_smp_processor_id" },
+	{ BPF_PROG_TYPE_SCHED_CLS,	"bpf_skb_store_bytes" },
+	{ BPF_PROG_TYPE_SCHED_CLS,	"bpf_l3_csum_replace" },
+	{ BPF_PROG_TYPE_SCHED_CLS,	"bpf_l4_csum_replace" },
+	{ BPF_PROG_TYPE_XDP,		"bpf_tail_call" },
+	{ BPF_PROG_TYPE_SCHED_CLS,	"bpf_clone_redirect" },
+	{ BPF_PROG_TYPE_KPROBE,		"bpf_get_current_pid_tgid" },
+	{ BPF_PROG_TYPE_KPROBE,		"bpf_get_current_uid_gid" },
+	{ BPF_PROG_TYPE_KPROBE,		"bpf_get_current_comm" },
+	{ BPF_PROG_TYPE_SCHED_CLS,	"bpf_get_cgroup_classid" },
+	{ BPF_PROG_TYPE_SCHED_CLS,	"bpf_skb_vlan_push" },
+	{ BPF_PROG_TYPE_SCHED_CLS,	"bpf_skb_vlan_pop" },
+	{ BPF_PROG_TYPE_SCHED_CLS,	"bpf_skb_get_tunnel_key" },
+	{ BPF_PROG_TYPE_SCHED_CLS,	"bpf_skb_set_tunnel_key" },
+	{ BPF_PROG_TYPE_KPROBE,		"bpf_perf_event_read" },
+	{ BPF_PROG_TYPE_XDP,		"bpf_redirect" },
+	{ BPF_PROG_TYPE_SCHED_CLS,	"bpf_get_route_realm" },
+	{ BPF_PROG_TYPE_XDP,		"bpf_perf_event_output" },
+	{ BPF_PROG_TYPE_SCHED_CLS,	"bpf_skb_load_bytes" },
+	{ BPF_PROG_TYPE_KPROBE,		"bpf_get_stackid" },
+	{ BPF_PROG_TYPE_XDP,		"bpf_csum_diff" },
+	{ BPF_PROG_TYPE_SCHED_CLS,	"bpf_skb_get_tunnel_opt" },
+	{ BPF_PROG_TYPE_SCHED_CLS,	"bpf_skb_set_tunnel_opt" },
+	{ BPF_PROG_TYPE_SCHED_CLS,	"bpf_skb_change_proto" },
+	{ BPF_PROG_TYPE_SCHED_CLS,	"bpf_skb_change_type" },
+	{ BPF_PROG_TYPE_SCHED_CLS,	"bpf_skb_under_cgroup" },
+	{ BPF_PROG_TYPE_SCHED_CLS,	"bpf_get_hash_recalc" },
+	{ BPF_PROG_TYPE_KPROBE,		"bpf_get_current_task" },
+	{ BPF_PROG_TYPE_KPROBE,		"bpf_probe_write_user" },
+	{ BPF_PROG_TYPE_KPROBE,		"bpf_current_task_under_cgroup" },
+	{ BPF_PROG_TYPE_SCHED_CLS,	"bpf_skb_change_tail" },
+	{ BPF_PROG_TYPE_SCHED_CLS,	"bpf_skb_pull_data" },
+	{ BPF_PROG_TYPE_SCHED_CLS,	"bpf_csum_update" },
+	{ BPF_PROG_TYPE_SCHED_CLS,	"bpf_set_hash_invalid" },
+	{ BPF_PROG_TYPE_XDP,		"bpf_get_numa_node_id" },
+	{ BPF_PROG_TYPE_SK_SKB,		"bpf_skb_change_head" },
+	{ BPF_PROG_TYPE_XDP,		"bpf_xdp_adjust_head" },
+	{ BPF_PROG_TYPE_KPROBE,		"bpf_probe_read_str" },
+	{ BPF_PROG_TYPE_SCHED_CLS,	"bpf_get_socket_cookie" },
+	{ BPF_PROG_TYPE_SCHED_CLS,	"bpf_get_socket_uid" },
+	{ BPF_PROG_TYPE_SCHED_CLS,	"bpf_set_hash" },
+	{ BPF_PROG_TYPE_SOCK_OPS,	"bpf_setsockopt" },
+	{ BPF_PROG_TYPE_SCHED_CLS,	"bpf_skb_adjust_room" },
+	{ BPF_PROG_TYPE_XDP,		"bpf_redirect_map" },
+	{ BPF_PROG_TYPE_SK_SKB,		"bpf_sk_redirect_map" },
+	{ BPF_PROG_TYPE_SOCK_OPS,	"bpf_sock_map_update" },
+	{ BPF_PROG_TYPE_XDP,		"bpf_xdp_adjust_meta" },
+	{ BPF_PROG_TYPE_KPROBE,		"bpf_perf_event_read_value" },
+	{ BPF_PROG_TYPE_PERF_EVENT,	"bpf_perf_prog_read_value" },
+	{ BPF_PROG_TYPE_SOCK_OPS,	"bpf_getsockopt" },
+	{ BPF_PROG_TYPE_KPROBE,		"bpf_override_return" },
+	{ BPF_PROG_TYPE_SOCK_OPS,	"bpf_sock_ops_cb_flags_set" },
+	{ BPF_PROG_TYPE_SK_MSG,		"bpf_msg_redirect_map" },
+	{ BPF_PROG_TYPE_SK_MSG,		"bpf_msg_apply_bytes" },
+	{ BPF_PROG_TYPE_SK_MSG,		"bpf_msg_cork_bytes" },
+	{ BPF_PROG_TYPE_SK_MSG,		"bpf_msg_pull_data" },
+	{ BPF_PROG_TYPE_CGROUP_SOCK_ADDR,	"bpf_bind" },
+	{ BPF_PROG_TYPE_XDP,		"bpf_xdp_adjust_tail" },
+	{ BPF_PROG_TYPE_SCHED_CLS,	"bpf_skb_get_xfrm_state" },
+	{ BPF_PROG_TYPE_KPROBE,		"bpf_get_stack" },
+	{ BPF_PROG_TYPE_SCHED_CLS,	"bpf_skb_load_bytes_relative" },
+	{ BPF_PROG_TYPE_SCHED_CLS,	"bpf_fib_lookup" },
+	{ BPF_PROG_TYPE_SOCK_OPS,	"bpf_sock_hash_update" },
+	{ BPF_PROG_TYPE_SK_MSG,		"bpf_msg_redirect_hash" },
+	{ BPF_PROG_TYPE_SK_SKB,		"bpf_sk_redirect_hash" },
+	{ BPF_PROG_TYPE_LWT_IN,		"bpf_lwt_push_encap" },
+	{ BPF_PROG_TYPE_LWT_SEG6LOCAL,	"bpf_lwt_seg6_store_bytes" },
+	{ BPF_PROG_TYPE_LWT_SEG6LOCAL,	"bpf_lwt_seg6_adjust_srh" },
+	{ BPF_PROG_TYPE_LWT_SEG6LOCAL,	"bpf_lwt_seg6_action" },
+	{ BPF_PROG_TYPE_LIRC_MODE2,	"bpf_rc_repeat" },
+	{ BPF_PROG_TYPE_LIRC_MODE2,	"bpf_rc_keydown" },
+	{ BPF_PROG_TYPE_SCHED_CLS,	"bpf_skb_cgroup_id" },
+	{ BPF_PROG_TYPE_KPROBE,		"bpf_get_current_cgroup_id" },
+	{ BPF_PROG_TYPE_CGROUP_SKB,	"bpf_get_local_storage" },
+	{ BPF_PROG_TYPE_SK_REUSEPORT,	"bpf_sk_select_reuseport" },
+	{ BPF_PROG_TYPE_SCHED_CLS,	"bpf_skb_ancestor_cgroup_id" },
+	{ BPF_PROG_TYPE_SK_SKB,		"bpf_sk_lookup_tcp" },
+	{ BPF_PROG_TYPE_SK_SKB,		"bpf_sk_lookup_udp" },
+	{ BPF_PROG_TYPE_SK_SKB,		"bpf_sk_release" },
+	{ BPF_PROG_TYPE_XDP,		"bpf_map_push_elem" },
+	{ BPF_PROG_TYPE_XDP,		"bpf_map_pop_elem" },
+	{ BPF_PROG_TYPE_XDP,		"bpf_map_peek_elem" },
+	{ BPF_PROG_TYPE_SK_MSG,		"bpf_msg_push_data" },
+};
+
 /* Miscellaneous utility functions */
 
 static bool check_procfs(void)
@@ -46,6 +153,11 @@ static void uppercase(char *str, size_t len)
 		str[i] = toupper(str[i]);
 }
 
+static bool grep(const char *buffer, const char *pattern)
+{
+	return !!strstr(buffer, pattern);
+}
+
 /* Printing utility functions */
 
 static void
@@ -642,6 +754,36 @@ probe_map_type(enum bpf_map_type map_type, const char *define_prefix)
 			   define_prefix);
 }
 
+static void
+probe_helper(__u32 id, enum bpf_prog_type prog_type, const char *name,
+	     int kernel_version, bool *supported_types,
+	     const char *define_prefix)
+{
+	char buf[4096], feat_name[128], define_name[128], plain_desc[128];
+	struct bpf_insn insns[2] = {
+		BPF_EMIT_CALL(id),
+		BPF_EXIT_INSN()
+	};
+	bool res = false;
+
+	if (!supported_types[prog_type])
+		goto do_print;
+
+	/* Reset buffer in case no debug info was written at previous probe */
+	*buf = '\0';
+	prog_load(prog_type, insns, ARRAY_SIZE(insns), kernel_version,
+		  buf, sizeof(buf));
+	res = !grep(buf, "invalid func ") && !grep(buf, "unknown func ");
+
+do_print:
+	sprintf(feat_name, "have_%s_helper", name);
+	sprintf(define_name, "%s_helper", name);
+	uppercase(define_name, sizeof(define_name));
+	sprintf(plain_desc, "eBPF helper %s", name);
+	print_bool_feature(feat_name, define_name, plain_desc, res,
+			   define_prefix);
+}
+
 static int do_probe(int argc, char **argv)
 {
 	enum probe_component target = COMPONENT_UNSPEC;
@@ -746,6 +888,16 @@ static int do_probe(int argc, char **argv)
 	for (i = BPF_MAP_TYPE_HASH; i < map_type_name_size; i++)
 		probe_map_type(i, define_prefix);
 
+	print_end_then_start_section("helpers",
+				     "/*** eBPF helper functions ***/",
+				     "Scanning eBPF helper functions...",
+				     define_prefix);
+
+	for (i = 1; i < ARRAY_SIZE(helper_progtype_and_name); i++)
+		probe_helper(i, helper_progtype_and_name[i].progtype,
+			     helper_progtype_and_name[i].name,
+			     kernel_version, supported_types, define_prefix);
+
 exit_close_json:
 	if (json_output) {
 		/* End current "section" of probes */
-- 
2.17.1

^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [PATCH bpf-next 7/8] tools: bpftool: add probes for a network device
  2018-12-13 12:19 [PATCH bpf-next 0/8] tools: bpftool: add probes for system and device Quentin Monnet
                   ` (5 preceding siblings ...)
  2018-12-13 12:19 ` [PATCH bpf-next 6/8] tools: bpftool: add probes for eBPF helper functions Quentin Monnet
@ 2018-12-13 12:19 ` Quentin Monnet
  2018-12-13 12:19 ` [PATCH bpf-next 8/8] tools: bpftool: add bash completion for bpftool probes Quentin Monnet
                   ` (3 subsequent siblings)
  10 siblings, 0 replies; 41+ messages in thread
From: Quentin Monnet @ 2018-12-13 12:19 UTC (permalink / raw)
  To: Alexei Starovoitov, Daniel Borkmann
  Cc: netdev, oss-drivers, Quentin Monnet, Arnaldo Carvalho de Melo,
	Jesper Dangaard Brouer, Stanislav Fomichev

bpftool gained support for probing the current system in order to see
what program and map types, and what helpers are available on that
system. This patch adds the possibility to pass an interface index to
the kernel when trying to load the programs or to create the maps, in
order to see what items a given network device can support.

A new keyword "dev <ifname>" can be used as an alternative to "kernel"
to indicate that the given device should be tested. If no target ("dev"
or "kernel") is specified bpftool defaults to probing the kernel.

Sample output:

    # bpftool -p feature probe dev lo
    {
        "syscall_config": {
            "kernel_version_code": 267008,
            "have_bpf_syscall": true
        },
        "program_types": {
            "have_sched_cls_prog_type": false,
            "have_xdp_prog_type": false
        },
        ...
    }

As the target is a network device, /proc/ parameters and kernel
configuration are NOT dumped. Availability of the bpf() syscall and
kernel version are still probed, as they are necessary for the remaining
probes.

Among the program types, only the ones that can be offloaded are
probed. Among the helpers, only the ones that can work with the latter
program types are probed. All map types are probed, as there is no
specific rule telling which one could or could not be supported by a
device in the future.

Caveat: as bpftool does not attempt to attach programs to the device at
the moment, probes do not entirely reflect what the device accepts:
typically, for Netronome's nfp, results will announce that TC cls
offload is available even if support has been deactivated (with e.g.
ethtool -K eth1 hw-tc-offload off).

Signed-off-by: Quentin Monnet <quentin.monnet@netronome.com>
Reviewed-by: Jakub Kicinski <jakub.kicinski@netronome.com>
---
 .../bpftool/Documentation/bpftool-feature.rst | 18 +++-
 tools/bpf/bpftool/common.c                    |  2 +-
 tools/bpf/bpftool/feature.c                   | 97 ++++++++++++++++---
 tools/bpf/bpftool/main.h                      |  1 +
 4 files changed, 103 insertions(+), 15 deletions(-)

diff --git a/tools/bpf/bpftool/Documentation/bpftool-feature.rst b/tools/bpf/bpftool/Documentation/bpftool-feature.rst
index 083d30510cce..9f366461fb72 100644
--- a/tools/bpf/bpftool/Documentation/bpftool-feature.rst
+++ b/tools/bpf/bpftool/Documentation/bpftool-feature.rst
@@ -19,16 +19,21 @@ SYNOPSIS
 MAP COMMANDS
 =============
 
-|	**bpftool** **feature probe** [**kernel**] [**macros** [**prefix** *PREFIX*]]
+|	**bpftool** **feature probe** [*COMPONENT*] [**macros** [**prefix** *PREFIX*]]
 |	**bpftool** **feature help**
+|
+|	*COMPONENT* := { **kernel** | **dev** *NAME* }
 
 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.
+		  parameters, such as availability of the **bpf()** system call,
+		  JIT status, eBPF program types availability, eBPF helper
+		  functions availability, and more.
 
-		  Keyword **kernel** can be omitted.
+		  Keyword **kernel** can be omitted. If no probe target is
+		  specified, probing the kernel is the default behaviour.
 
 		  If the **macros** keyword (but not the **-j** option) is
 		  passed, output is dumped as a list of **#define** macros that
@@ -43,6 +48,13 @@ DESCRIPTION
 		  **bpf_trace_printk**\ () or **bpf_probe_write_user**\ ()) may
 		  print warnings to kernel logs.
 
+	**bpftool feature probe dev** *NAME* [**macros** [**prefix** *PREFIX*]]
+		  Probe network device for supported eBPF features and dump
+		  results to the console.
+
+		  The two keywords **macros** and **prefix** have the same
+		  role as when probing the kernel.
+
 	**bpftool feature help**
 		  Print short help message.
 
diff --git a/tools/bpf/bpftool/common.c b/tools/bpf/bpftool/common.c
index 99e4027dde75..9cd5b24e4778 100644
--- a/tools/bpf/bpftool/common.c
+++ b/tools/bpf/bpftool/common.c
@@ -521,7 +521,7 @@ static int read_sysfs_hex_int(char *path)
 	return strtol(vendor_id_buf, NULL, 0);
 }
 
-static int read_sysfs_netdev_hex_int(char *devname, const char *entry_name)
+int read_sysfs_netdev_hex_int(char *devname, const char *entry_name)
 {
 	char full_path[64];
 
diff --git a/tools/bpf/bpftool/feature.c b/tools/bpf/bpftool/feature.c
index 77221fff6ba9..0283faacf1dc 100644
--- a/tools/bpf/bpftool/feature.c
+++ b/tools/bpf/bpftool/feature.c
@@ -5,6 +5,7 @@
 #include <errno.h>
 #include <string.h>
 #include <unistd.h>
+#include <net/if.h>
 #include <sys/utsname.h>
 #include <sys/vfs.h>
 
@@ -22,6 +23,7 @@
 enum probe_component {
 	COMPONENT_UNSPEC,
 	COMPONENT_KERNEL,
+	COMPONENT_DEVICE,
 };
 
 #define MAX_HELPER_NAME_LEN 32
@@ -616,7 +618,8 @@ static bool probe_bpf_syscall(const char *define_prefix)
 
 static void
 prog_load(enum bpf_prog_type prog_type, const struct bpf_insn *insns,
-	  size_t insns_cnt, int kernel_version, char *buf, size_t buf_len)
+	  size_t insns_cnt, int kernel_version, char *buf, size_t buf_len,
+	  __u32 ifindex)
 {
 	struct bpf_load_program_attr xattr = {};
 	int fd;
@@ -634,6 +637,7 @@ prog_load(enum bpf_prog_type prog_type, const struct bpf_insn *insns,
 	xattr.insns_cnt = insns_cnt;
 	xattr.license = "GPL";
 	xattr.kern_version = kernel_version;
+	xattr.prog_ifindex = ifindex;
 
 	fd = bpf_load_program_xattr(&xattr, buf, buf_len);
 	if (fd >= 0)
@@ -642,7 +646,7 @@ prog_load(enum bpf_prog_type prog_type, const struct bpf_insn *insns,
 
 static void
 probe_prog_type(enum bpf_prog_type prog_type, int kernel_version,
-		bool *supported_types, const char *define_prefix)
+		bool *supported_types, const char *define_prefix, __u32 ifindex)
 {
 	char buf[4096], feat_name[128], define_name[128], plain_desc[128];
 	const char *plain_comment = "eBPF program_type ";
@@ -653,9 +657,22 @@ probe_prog_type(enum bpf_prog_type prog_type, int kernel_version,
 	size_t maxlen;
 	bool res;
 
+	if (ifindex)
+		/* Only test offload-able program types */
+		switch (prog_type) {
+		case BPF_PROG_TYPE_SCHED_CLS:
+			/* nfp returns -EINVAL on exit(0) with TC offload */
+			insns[0].imm = 2;
+			/* fall through */
+		case BPF_PROG_TYPE_XDP:
+			break;
+		default:
+			return;
+		}
+
 	errno = 0;
 	prog_load(prog_type, insns, ARRAY_SIZE(insns), kernel_version,
-		  buf, sizeof(buf));
+		  buf, sizeof(buf), ifindex);
 	res = (errno != EINVAL && errno != EOPNOTSUPP);
 
 	supported_types[prog_type] |= res;
@@ -675,7 +692,8 @@ probe_prog_type(enum bpf_prog_type prog_type, int kernel_version,
 }
 
 static void
-probe_map_type(enum bpf_map_type map_type, const char *define_prefix)
+probe_map_type(enum bpf_map_type map_type, const char *define_prefix,
+	       __u32 ifindex)
 {
 	char feat_name[128], define_name[128], plain_desc[128];
 	int key_size, value_size, max_entries, map_flags;
@@ -716,6 +734,12 @@ probe_map_type(enum bpf_map_type map_type, const char *define_prefix)
 	switch (map_type) {
 	case BPF_MAP_TYPE_ARRAY_OF_MAPS:
 	case BPF_MAP_TYPE_HASH_OF_MAPS:
+		/* TODO: probe for device, once libbpf has an API to create
+		 * map-in-map for offload
+		 */
+		if (ifindex)
+			break;
+
 		fd_inner = bpf_create_map(BPF_MAP_TYPE_HASH,
 					  sizeof(__u32), sizeof(__u32), 1, 0);
 		if (fd_inner < 0)
@@ -731,6 +755,7 @@ probe_map_type(enum bpf_map_type map_type, const char *define_prefix)
 		attr.value_size = value_size;
 		attr.max_entries = max_entries;
 		attr.map_flags = map_flags;
+		attr.map_ifindex = ifindex;
 
 		fd = bpf_create_map_xattr(&attr);
 		break;
@@ -757,7 +782,7 @@ probe_map_type(enum bpf_map_type map_type, const char *define_prefix)
 static void
 probe_helper(__u32 id, enum bpf_prog_type prog_type, const char *name,
 	     int kernel_version, bool *supported_types,
-	     const char *define_prefix)
+	     const char *define_prefix, __u32 ifindex, int vendor_id)
 {
 	char buf[4096], feat_name[128], define_name[128], plain_desc[128];
 	struct bpf_insn insns[2] = {
@@ -766,15 +791,35 @@ probe_helper(__u32 id, enum bpf_prog_type prog_type, const char *name,
 	};
 	bool res = false;
 
+	if (ifindex)
+		/* Only test helpers compatible with offload-able prog types */
+		switch (prog_type) {
+		case BPF_PROG_TYPE_XDP:
+		case BPF_PROG_TYPE_SCHED_CLS:
+			break;
+		default:
+			return;
+		}
+
 	if (!supported_types[prog_type])
 		goto do_print;
 
 	/* Reset buffer in case no debug info was written at previous probe */
 	*buf = '\0';
 	prog_load(prog_type, insns, ARRAY_SIZE(insns), kernel_version,
-		  buf, sizeof(buf));
+		  buf, sizeof(buf), ifindex);
 	res = !grep(buf, "invalid func ") && !grep(buf, "unknown func ");
 
+	if (ifindex)
+		switch (vendor_id) {
+		case 0x19ee: /* Netronome specific */
+			res = res && !grep(buf, "not supported by FW") &&
+				!grep(buf, "unsupported function id");
+			break;
+		default:
+			break;
+		}
+
 do_print:
 	sprintf(feat_name, "have_%s_helper", name);
 	sprintf(define_name, "%s_helper", name);
@@ -790,7 +835,10 @@ static int do_probe(int argc, char **argv)
 	const char *define_prefix = NULL;
 	bool supported_types[128] = {};
 	int kernel_version;
+	__u32 ifindex = 0;
+	int vendor_id = 0;
 	unsigned int i;
+	char *ifname;
 
 	/* Detection assumes user has sufficient privileges (CAP_SYS_ADMIN).
 	 * Let's approximate, and restrict usage to root user only.
@@ -810,6 +858,24 @@ static int do_probe(int argc, char **argv)
 			}
 			target = COMPONENT_KERNEL;
 			NEXT_ARG();
+		} else if (is_prefix(*argv, "dev")) {
+			NEXT_ARG();
+
+			if (target != COMPONENT_UNSPEC || ifindex) {
+				p_err("component to probe already specified");
+				return -1;
+			}
+			if (!REQ_ARGS(1))
+				return -1;
+
+			target = COMPONENT_DEVICE;
+			ifname = GET_ARG();
+			ifindex = if_nametoindex(ifname);
+			if (!ifindex) {
+				p_err("unrecognized netdevice '%s': %s", ifname,
+				      strerror(errno));
+				return -1;
+			}
 		} else if (is_prefix(*argv, "macros") && !define_prefix) {
 			define_prefix = "";
 			NEXT_ARG();
@@ -828,7 +894,7 @@ static int do_probe(int argc, char **argv)
 				return -1;
 			define_prefix = GET_ARG();
 		} else {
-			p_err("expected no more arguments, 'kernel', 'macros' or 'prefix', got: '%s'?",
+			p_err("expected no more arguments, 'kernel', 'dev', 'macros' or 'prefix', got: '%s'?",
 			      *argv);
 			return -1;
 		}
@@ -858,6 +924,8 @@ static int do_probe(int argc, char **argv)
 		else
 			printf("\n");
 		break;
+	default:
+		break;
 	}
 
 	print_start_section("syscall_config",
@@ -865,6 +933,7 @@ static int do_probe(int argc, char **argv)
 			    "Scanning system call and kernel version...",
 			    define_prefix);
 
+	/* Get kernel version in all cases, we need it for kprobe programs */
 	kernel_version = probe_kernel_version(define_prefix);
 	if (!probe_bpf_syscall(define_prefix))
 		/* bpf() syscall unavailable, don't probe other BPF features */
@@ -878,7 +947,7 @@ static int do_probe(int argc, char **argv)
 	for (i = BPF_PROG_TYPE_SOCKET_FILTER;
 	     i < ARRAY_SIZE(prog_type_name); i++)
 		probe_prog_type(i, kernel_version, supported_types,
-				define_prefix);
+				define_prefix, ifindex);
 
 	print_end_then_start_section("map_types",
 				     "/*** eBPF map types ***/",
@@ -886,17 +955,21 @@ static int do_probe(int argc, char **argv)
 				     define_prefix);
 
 	for (i = BPF_MAP_TYPE_HASH; i < map_type_name_size; i++)
-		probe_map_type(i, define_prefix);
+		probe_map_type(i, define_prefix, ifindex);
 
 	print_end_then_start_section("helpers",
 				     "/*** eBPF helper functions ***/",
 				     "Scanning eBPF helper functions...",
 				     define_prefix);
 
+	if (ifindex)
+		vendor_id = read_sysfs_netdev_hex_int(ifname, "vendor");
+
 	for (i = 1; i < ARRAY_SIZE(helper_progtype_and_name); i++)
 		probe_helper(i, helper_progtype_and_name[i].progtype,
 			     helper_progtype_and_name[i].name,
-			     kernel_version, supported_types, define_prefix);
+			     kernel_version, supported_types, define_prefix,
+			     ifindex, vendor_id);
 
 exit_close_json:
 	if (json_output) {
@@ -917,8 +990,10 @@ static int do_help(int argc, char **argv)
 	}
 
 	fprintf(stderr,
-		"Usage: %s %s probe [kernel] [macros [prefix PREFIX]]\n"
+		"Usage: %s %s probe [COMPONENT] [macros [prefix PREFIX]]\n"
 		"       %s %s help\n"
+		"\n"
+		"       COMPONENT := { kernel | dev NAME }\n"
 		"",
 		bin_name, argv[-2], bin_name, argv[-2]);
 
diff --git a/tools/bpf/bpftool/main.h b/tools/bpf/bpftool/main.h
index d9a2b1eafae7..f8518c7ec2cc 100644
--- a/tools/bpf/bpftool/main.h
+++ b/tools/bpf/bpftool/main.h
@@ -181,6 +181,7 @@ void print_hex_data_json(uint8_t *data, size_t len);
 
 unsigned int get_page_size(void);
 unsigned int get_possible_cpus(void);
+int read_sysfs_netdev_hex_int(char *devname, const char *entry_name);
 const char *
 ifindex_to_bfd_params(__u32 ifindex, __u64 ns_dev, __u64 ns_ino,
 		      const char **opt);
-- 
2.17.1

^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [PATCH bpf-next 8/8] tools: bpftool: add bash completion for bpftool probes
  2018-12-13 12:19 [PATCH bpf-next 0/8] tools: bpftool: add probes for system and device Quentin Monnet
                   ` (6 preceding siblings ...)
  2018-12-13 12:19 ` [PATCH bpf-next 7/8] tools: bpftool: add probes for a network device Quentin Monnet
@ 2018-12-13 12:19 ` Quentin Monnet
  2018-12-13 13:03 ` [PATCH bpf-next 0/8] tools: bpftool: add probes for system and device Arnaldo Carvalho de Melo
                   ` (2 subsequent siblings)
  10 siblings, 0 replies; 41+ messages in thread
From: Quentin Monnet @ 2018-12-13 12:19 UTC (permalink / raw)
  To: Alexei Starovoitov, Daniel Borkmann
  Cc: netdev, oss-drivers, Quentin Monnet, Arnaldo Carvalho de Melo,
	Jesper Dangaard Brouer, Stanislav Fomichev

Add the bash completion related to the newly introduced "bpftool feature
probe" command.

Signed-off-by: Quentin Monnet <quentin.monnet@netronome.com>
Reviewed-by: Jakub Kicinski <jakub.kicinski@netronome.com>
---
 tools/bpf/bpftool/bash-completion/bpftool | 19 +++++++++++++++++++
 1 file changed, 19 insertions(+)

diff --git a/tools/bpf/bpftool/bash-completion/bpftool b/tools/bpf/bpftool/bash-completion/bpftool
index e4e4fab1b8c7..21d5295936ed 100644
--- a/tools/bpf/bpftool/bash-completion/bpftool
+++ b/tools/bpf/bpftool/bash-completion/bpftool
@@ -624,6 +624,25 @@ _bpftool()
                     ;;
             esac
             ;;
+        feature)
+            case $command in
+                probe)
+                    [[ $prev == "dev" ]] && _sysfs_get_netdevs && return 0
+                    [[ $prev == "prefix" ]] && return 0
+                    if _bpftool_search_list 'macros'; then
+                        COMPREPLY+=( $( compgen -W 'prefix' -- "$cur" ) )
+                    else
+                        COMPREPLY+=( $( compgen -W 'macros' -- "$cur" ) )
+                    fi
+                    _bpftool_one_of_list 'kernel dev'
+                    return 0
+                    ;;
+                *)
+                    [[ $prev == $object ]] && \
+                        COMPREPLY=( $( compgen -W 'help probe' -- "$cur" ) )
+                    ;;
+            esac
+            ;;
     esac
 } &&
 complete -F _bpftool bpftool
-- 
2.17.1

^ permalink raw reply related	[flat|nested] 41+ messages in thread

* Re: [PATCH bpf-next 0/8] tools: bpftool: add probes for system and device
  2018-12-13 12:19 [PATCH bpf-next 0/8] tools: bpftool: add probes for system and device Quentin Monnet
                   ` (7 preceding siblings ...)
  2018-12-13 12:19 ` [PATCH bpf-next 8/8] tools: bpftool: add bash completion for bpftool probes Quentin Monnet
@ 2018-12-13 13:03 ` Arnaldo Carvalho de Melo
  2018-12-13 13:49   ` Debugging eBPF was: " Arnaldo Carvalho de Melo
  2018-12-14 11:53 ` Quentin Monnet
  2018-12-14 14:00 ` Arnaldo Carvalho de Melo
  10 siblings, 1 reply; 41+ messages in thread
From: Arnaldo Carvalho de Melo @ 2018-12-13 13:03 UTC (permalink / raw)
  To: Quentin Monnet
  Cc: Alexei Starovoitov, Daniel Borkmann, netdev, oss-drivers,
	Jesper Dangaard Brouer, Stanislav Fomichev

Em Thu, Dec 13, 2018 at 12:19:14PM +0000, Quentin Monnet escreveu:
> Hi,
> This set add a new command to bpftool in order to dump a list of
> eBPF-related parameters for the system (or for a specific network
> device) to the console. Once again, this is based on a suggestion from
> Daniel.
> 
> At this time, output includes:
> 
>     - Availability of bpf() system call
>     - Availability of bpf() system call for unprivileged users
>     - JIT status (enabled or not, with or without debugging traces)
>     - JIT hardening status
>     - JIT kallsyms exports status
>     - Status of kernel compilation options related to BPF features
>     - Release number of the running kernel
>     - Availability of known eBPF program types
>     - Availability of known eBPF map types
>     - Availability of known eBPF helper functions
> 
> There are three different ways to dump this information at this time:
> 
>     - Plain output dumps probe results in plain text. It is the most
>       flexible options for providing descriptive output to the user, but
>       should not be relied upon for parsing the output.
>     - JSON output is supported.
>     - A third mode, available through the "macros" keyword appended to
>       the command line, dumps the parameters as a series of "#define"
>       directives, that can be included into a C header file for example.
> 
> If the user does not have root privileges (or more precisely, the
> CAP_SYS_ADMIN capability) detection will be erroneous for most
> parameters. Therefore, forbid non-root users to run the command.

Interesting, and helps developers to figure out what is present and help
the user to tell why some specific feature is not working.

Something else we've discussed while in LPC was to present the users
with hints about what to do when something fails, IIRC Joe Stringer
suggested to have hints pointing to the documentation about that
specific error, helping users to setup the system.

In perf we have something similar, for instance, when a !root user is
wanting to use 'perf trace'

$ perf trace
Error:	No permissions to read /sys/kernel/debug/tracing/events/raw_syscalls/sys_(enter|exit)
Hint:	Try 'sudo mount -o remount,mode=755 /sys/kernel/debug/'
$ sudo mount -o remount,mode=755 /sys/kernel/debug/
$ perf trace sleep 1
Error:	Permission denied.
Hint:	Check /proc/sys/kernel/perf_event_paranoid setting.
Hint:	For your workloads it needs to be <= 1
Hint:	For system wide tracing it needs to be set to -1.
Hint:	Try: 'sudo sh -c "echo -1 > /proc/sys/kernel/perf_event_paranoid"'
Hint:	The current value is 2.
$ sudo sh -c "echo 1 > /proc/sys/kernel/perf_event_paranoid"
$ perf trace sleep 1
     <SNIP>
     0.708 ( 0.008 ms): sleep/24196 mmap(len: 217749968, prot: READ, flags: PRIVATE, fd: 3) = 0x7fe0863b5000
     0.728 ( 0.002 ms): sleep/24196 close(fd: 3) = 0
     0.796 (1000.111 ms): sleep/24196 nanosleep(rqtp: 0x7fff78e7ff60) = 0
  1000.953 ( 0.007 ms): sleep/24196 close(fd: 1) = 0
  1000.965 ( 0.003 ms): sleep/24196 close(fd: 2) = 0
  1000.989 (         ): sleep/24196 exit_group()
$ 
$ perf trace --all-cpus
Error:	Operation not permitted.
Hint:	Check /proc/sys/kernel/perf_event_paranoid setting.
Hint:	For system wide tracing it needs to be set to -1.
Hint:	Try: 'sudo sh -c "echo -1 > /proc/sys/kernel/perf_event_paranoid"'
Hint:	The current value is 1.
$ 
$ sudo sh -c "echo -1 > /proc/sys/kernel/perf_event_paranoid"'
$ perf trace -a -e open*
     0.000 ( 0.057 ms): pulseaudio/2103 openat(dfd: CWD, filename: 0x712de930, flags: CLOEXEC) = 47
     1.658 ( 0.038 ms): alsa-sink-ALC2/2181 openat(dfd: CWD, filename: 0x5b57cfd0, flags: CLOEXEC) = 47
     1.770 ( 0.013 ms): alsa-sink-ALC2/2181 openat(dfd: CWD, filename: 0x5b57cc60, flags: CLOEXEC) = 47
     1.805 ( 0.029 ms): alsa-sink-ALC2/2181 openat(dfd: CWD, filename: 0x5b57cc40, flags: RDWR|CLOEXEC) = 47
     2.038 ( 0.021 ms): alsa-sink-ALC2/2181 openat(dfd: CWD, filename: 0x5b57d290, flags: CLOEXEC) = 47
     2.085 ( 0.014 ms): alsa-sink-ALC2/2181 openat(dfd: CWD, filename: 0x5b57d0a0, flags: RDWR|CLOEXEC) = 47
     2.119 (33.276 ms): alsa-sink-ALC2/2181 openat(dfd: CWD, filename: 0x5b57d250, flags: RDWR|CLOEXEC|NONBLOCK) = 53
    35.575 ( 0.038 ms): alsa-sink-ALC2/2181 openat(dfd: CWD, filename: 0x5b57d3d0, flags: CLOEXEC) = 47
    35.698 ( 0.006 ms): alsa-sink-ALC2/2181 openat(dfd: CWD, filename: 0x5b57cf90, flags: CLOEXEC) = 47
    35.710 ( 0.003 ms): alsa-sink-ALC2/2181 openat(dfd: CWD, filename: 0x5b57cf70, flags: RDWR|CLOEXEC) = 47
   250.421 ( 0.044 ms): DNS Res~er #41/18571 openat(dfd: CWD, filename: 0x5fc2d024, flags: CLOEXEC) = 138
   365.200 ( 0.038 ms): :17437/17437 openat(dfd: CWD, filename: 0x25211b80) = 129
   365.393 ( 0.013 ms): :17437/17437 openat(dfd: CWD, filename: 0x25211b80) = 129
   366.264 ( 0.031 ms): :17437/17437 openat(dfd: CWD, filename: 0x25211b80) = 129
   366.442 ( 0.012 ms): :17437/17437 openat(dfd: CWD, filename: 0x25211b80) = 524
   367.727 ( 0.026 ms): :17437/17437 openat(dfd: CWD, filename: 0x634a3780) = 129
   426.638 ( 0.036 ms): vim/24205 openat(dfd: CWD, filename: 0xc9504770, flags: CREAT|WRONLY, mode: IRUSR|IWUSR) = 6
^C$

Which makes me realize I have to provide hints for when a !root user tries to
load a BPF program via 'perf trace':

[acme@quaco perf]$ ls -la tools/perf/examples/bpf/augmented_raw_syscalls.o
-rw-r--r--. 1 root root 2224 Dec 12 16:45 tools/perf/examples/bpf/augmented_raw_syscalls.o
[acme@quaco perf]$ perf trace -a -e open*,tools/perf/examples/bpf/augmented_raw_syscalls.o
event syntax error: 'tools/perf/examples/bpf/augmented_raw_syscalls.o'
                     \___ Failed to load program for unknown reason

(add -v to see detail)
Run 'perf list' for a list of valid events

 Usage: perf trace [<options>] [<command>]
    or: perf trace [<options>] -- <command> [<options>]
    or: perf trace record [<options>] [<command>]
    or: perf trace record [<options>] -- <command> [<options>]

    -e, --event <event>   event/syscall selector. use 'perf list' to list available events
[acme@quaco perf]$ file tools/perf/examples/bpf/augmented_raw_syscalls.o
tools/perf/examples/bpf/augmented_raw_syscalls.o: ELF 64-bit LSB relocatable, eBPF, version 1 (SYSV), not stripped
[acme@quaco perf]

running with -v ends up with:

libbpf: failed to load object 'tools/perf/examples/bpf/augmented_raw_syscalls.o'
bpf: load objects failed: err=-4009: (Incorrect kernel version)
event syntax error: 'tools/perf/examples/bpf/augmented_raw_syscalls.o'
                     \___ Failed to load program for unknown reason

ouch, even rebuildng the .c file ends up with that error, will debug :-)

[acme@quaco perf]$ perf trace -v -a -e open*,tools/perf/examples/bpf/augmented_raw_syscalls.c
bpf: builtin compilation failed: -95, try external compiler
Kernel build dir is set to /lib/modules/4.20.0-rc5/build
set env: KBUILD_DIR=/lib/modules/4.20.0-rc5/build
unset env: KBUILD_OPTS
include option is set to  -nostdinc -isystem /usr/lib/gcc/x86_64-redhat-linux/8/include -I/home/acme/git/linux/arch/x86/include -I./arch/x86/include/generated  -I/home/acme/git/linux/include -I./include -I/home/acme/git/linux/arch/x86/include/uapi -I./arch/x86/include/generated/uapi -I/home/acme/git/linux/include/uapi -I./include/generated/uapi -include /home/acme/git/linux/include/linux/kconfig.h 
set env: NR_CPUS=8
set env: LINUX_VERSION_CODE=0x41400
set env: CLANG_EXEC=/usr/lib64/ccache/clang
unset env: CLANG_OPTIONS
set env: KERNEL_INC_OPTIONS= -nostdinc -isystem /usr/lib/gcc/x86_64-redhat-linux/8/include -I/home/acme/git/linux/arch/x86/include -I./arch/x86/include/generated  -I/home/acme/git/linux/include -I./include -I/home/acme/git/linux/arch/x86/include/uapi -I./arch/x86/include/generated/uapi -I/home/acme/git/linux/include/uapi -I./include/generated/uapi -include /home/acme/git/linux/include/linux/kconfig.h 
set env: PERF_BPF_INC_OPTIONS=-I/home/acme/lib/perf/include/bpf
set env: WORKING_DIR=/lib/modules/4.20.0-rc5/build
set env: CLANG_SOURCE=/home/acme/git/perf/tools/perf/examples/bpf/augmented_raw_syscalls.c
llvm compiling command template: $CLANG_EXEC -D__KERNEL__ -D__NR_CPUS__=$NR_CPUS -DLINUX_VERSION_CODE=$LINUX_VERSION_CODE $CLANG_OPTIONS $PERF_BPF_INC_OPTIONS $KERNEL_INC_OPTIONS -Wno-unused-value -Wno-pointer-sign -working-directory $WORKING_DIR -c "$CLANG_SOURCE" -target bpf $CLANG_EMIT_LLVM -O2 -o - $LLVM_OPTIONS_PIPE
llvm compiling command : /usr/lib64/ccache/clang -D__KERNEL__ -D__NR_CPUS__=8 -DLINUX_VERSION_CODE=0x41400  -I/home/acme/lib/perf/include/bpf  -nostdinc -isystem /usr/lib/gcc/x86_64-redhat-linux/8/include -I/home/acme/git/linux/arch/x86/include -I./arch/x86/include/generated  -I/home/acme/git/linux/include -I./include -I/home/acme/git/linux/arch/x86/include/uapi -I./arch/x86/include/generated/uapi -I/home/acme/git/linux/include/uapi -I./include/generated/uapi -include /home/acme/git/linux/include/linux/kconfig.h  -Wno-unused-value -Wno-pointer-sign -working-directory /lib/modules/4.20.0-rc5/build -c /home/acme/git/perf/tools/perf/examples/bpf/augmented_raw_syscalls.c -target bpf  -O2 -o - 
libbpf: loading object 'tools/perf/examples/bpf/augmented_raw_syscalls.c' from buffer
libbpf: section(1) .strtab, size 211, link 0, flags 0, type=3
libbpf: skip section(1) .strtab
libbpf: section(2) .text, size 0, link 0, flags 6, type=1
libbpf: skip section(2) .text
libbpf: section(3) raw_syscalls:sys_enter, size 440, link 0, flags 6, type=1
libbpf: found program raw_syscalls:sys_enter
libbpf: section(4) .relraw_syscalls:sys_enter, size 48, link 11, flags 0, type=9
libbpf: section(5) raw_syscalls:sys_exit, size 192, link 0, flags 6, type=1
libbpf: found program raw_syscalls:sys_exit
libbpf: section(6) .relraw_syscalls:sys_exit, size 32, link 11, flags 0, type=9
libbpf: section(7) maps, size 112, link 0, flags 3, type=1
libbpf: section(8) license, size 4, link 0, flags 3, type=1
libbpf: license of tools/perf/examples/bpf/augmented_raw_syscalls.c is GPL
libbpf: section(9) version, size 4, link 0, flags 3, type=1
libbpf: kernel version of tools/perf/examples/bpf/augmented_raw_syscalls.c is 41400
libbpf: section(10) .llvm_addrsig, size 8, link 11, flags 80000000, type=1879002115
libbpf: skip section(10) .llvm_addrsig
libbpf: section(11) .symtab, size 336, link 1, flags 0, type=2
libbpf: maps in tools/perf/examples/bpf/augmented_raw_syscalls.c: 4 maps in 112 bytes
libbpf: map 0 is "__augmented_syscalls__"
libbpf: map 1 is "__bpf_stdout__"
libbpf: map 2 is "pids_filtered"
libbpf: map 3 is "syscalls"
libbpf: collecting relocating info for: 'raw_syscalls:sys_enter'
libbpf: relo for 10 value 84 name 106
libbpf: relocation: insn_idx=5
libbpf: relocation: find map 3 (pids_filtered) for insn 5
libbpf: relo for 13 value 56 name 38
libbpf: relocation: insn_idx=16
libbpf: relocation: find map 2 (syscalls) for insn 16
libbpf: relo for 6 value 28 name 151
libbpf: relocation: insn_idx=48
libbpf: relocation: find map 1 (__augmented_syscalls__) for insn 48
libbpf: collecting relocating info for: 'raw_syscalls:sys_exit'
libbpf: relo for 10 value 84 name 106
libbpf: relocation: insn_idx=5
libbpf: relocation: find map 3 (pids_filtered) for insn 5
libbpf: relo for 13 value 56 name 38
libbpf: relocation: insn_idx=17
libbpf: relocation: find map 2 (syscalls) for insn 17
bpf: config program 'raw_syscalls:sys_enter'
bpf: config program 'raw_syscalls:sys_exit'
libbpf: create map __bpf_stdout__: fd=3
libbpf: create map __augmented_syscalls__: fd=4
libbpf: create map syscalls: fd=5
libbpf: create map pids_filtered: fd=6
libbpf: load bpf program failed: Operation not permitted
libbpf: failed to load program 'raw_syscalls:sys_enter'
libbpf: failed to load object 'tools/perf/examples/bpf/augmented_raw_syscalls.c'
bpf: load objects failed: err=-4009: (Incorrect kernel version)
event syntax error: 'tools/perf/examples/bpf/augmented_raw_syscalls.c'
                     \___ Failed to load program for unknown reason

(add -v to see detail)
Run 'perf list' for a list of valid events

 Usage: perf trace [<options>] [<command>]
    or: perf trace [<options>] -- <command> [<options>]
    or: perf trace record [<options>] [<command>]
    or: perf trace record [<options>] -- <command> [<options>]

    -e, --event <event>   event/syscall selector. use 'perf list' to list available events
[acme@quaco perf]$ 

Ok, out to figure this out :-)

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Debugging eBPF was: Re: [PATCH bpf-next 0/8] tools: bpftool: add probes for system and device
  2018-12-13 13:03 ` [PATCH bpf-next 0/8] tools: bpftool: add probes for system and device Arnaldo Carvalho de Melo
@ 2018-12-13 13:49   ` Arnaldo Carvalho de Melo
  2018-12-13 20:55     ` Alexei Starovoitov
  0 siblings, 1 reply; 41+ messages in thread
From: Arnaldo Carvalho de Melo @ 2018-12-13 13:49 UTC (permalink / raw)
  To: Quentin Monnet
  Cc: Alexei Starovoitov, Daniel Borkmann, netdev, oss-drivers,
	Jesper Dangaard Brouer, Stanislav Fomichev

Em Thu, Dec 13, 2018 at 10:03:59AM -0300, Arnaldo Carvalho de Melo escreveu:
> libbpf: failed to load program 'raw_syscalls:sys_enter'
> libbpf: failed to load object 'tools/perf/examples/bpf/augmented_raw_syscalls.c'
> bpf: load objects failed: err=-4009: (Incorrect kernel version)
> event syntax error: 'tools/perf/examples/bpf/augmented_raw_syscalls.c'
>                      \___ Failed to load program for unknown reason
> 
> (add -v to see detail)
> Run 'perf list' for a list of valid events
> 
>  Usage: perf trace [<options>] [<command>]
>     or: perf trace [<options>] -- <command> [<options>]
>     or: perf trace record [<options>] [<command>]
>     or: perf trace record [<options>] -- <command> [<options>]
> 
>     -e, --event <event>   event/syscall selector. use 'perf list' to list available events
> [acme@quaco perf]$ 
> 
> Ok, out to figure this out :-)

I've changed the subject to better reflect the change in discussion,
which I think is worth as it was another topic discussed at LPC, how to
debug when somthing goes awry:

So I first tried with:

$ strace -e bpf perf trace -v -a -e open*,tools/perf/examples/bpf/augmented_raw_syscalls.o
<SNIP>
bpf: config program 'raw_syscalls:sys_enter'
bpf: config program 'raw_syscalls:sys_exit'
bpf(BPF_MAP_CREATE, {map_type=BPF_MAP_TYPE_PERF_EVENT_ARRAY, key_size=4, value_size=4, max_entries=8, map_flags=0, inner_map_fd=0, map_name="__bpf_stdout__", map_ifindex=0}, 72) = 3
libbpf: create map __bpf_stdout__: fd=3
bpf(BPF_MAP_CREATE, {map_type=BPF_MAP_TYPE_PERF_EVENT_ARRAY, key_size=4, value_size=4, max_entries=8, map_flags=0, inner_map_fd=0, map_name="__augmented_sys", map_ifindex=0}, 72) = 4
libbpf: create map __augmented_syscalls__: fd=4
bpf(BPF_MAP_CREATE, {map_type=BPF_MAP_TYPE_ARRAY, key_size=4, value_size=1, max_entries=512, map_flags=0, inner_map_fd=0, map_name="syscalls", map_ifindex=0}, 72) = 5
libbpf: create map syscalls: fd=5
bpf(BPF_MAP_CREATE, {map_type=BPF_MAP_TYPE_HASH, key_size=4, value_size=1, max_entries=64, map_flags=0, inner_map_fd=0, map_name="pids_filtered", map_ifindex=0}, 72) = 6
libbpf: create map pids_filtered: fd=6
bpf(BPF_PROG_LOAD, {prog_type=BPF_PROG_TYPE_TRACEPOINT, insn_cnt=55, insns=0x11ec6e0, license="GPL", log_level=0, log_size=0, log_buf=NULL, kern_version=KERNEL_VERSION(4, 20, 0), prog_flags=0, prog_name="sys_enter", prog_ifindex=0, expected_attach_type=BPF_CGROUP_INET_INGRESS}, 72) = -1 EPERM (Operation not permitted)
bpf(BPF_PROG_LOAD, {prog_type=BPF_PROG_TYPE_TRACEPOINT, insn_cnt=55, insns=0x11ec6e0, license="GPL", log_level=1, log_size=262144, log_buf="", kern_version=KERNEL_VERSION(4, 20, 0), prog_flags=0, prog_name="sys_enter", prog_ifindex=0, expected_attach_type=BPF_CGROUP_INET_INGRESS}, 72) = -1 EPERM (Operation not permitted)
libbpf: load bpf program failed: Operation not permitted
bpf(BPF_PROG_LOAD, {prog_type=BPF_PROG_TYPE_KPROBE, insn_cnt=55, insns=0x11ec6e0, license="GPL", log_level=0, log_size=0, log_buf=NULL, kern_version=KERNEL_VERSION(4, 20, 0), prog_flags=0, prog_name="sys_enter", prog_ifindex=0, expected_attach_type=BPF_CGROUP_INET_INGRESS}, 72) = -1 EPERM (Operation not permitted)
libbpf: failed to load program 'raw_syscalls:sys_enter'
libbpf: failed to load object 'tools/perf/examples/bpf/augmented_raw_syscalls.o'
bpf: load objects failed: err=-4009: (Incorrect kernel version)
event syntax error: 'tools/perf/examples/bpf/augmented_raw_syscalls.o'
                     \___ Failed to load program for unknown reason


So it can create the maps, but not attach the programs to tracepoints,
ok, now lets switch to what is happening in the kernel side:

[acme@quaco perf]$ perf ftrace -G bpf_prog_load perf trace -v -a -e open*,tools/perf/examples/bpf/augmented_raw_syscalls.o
ftrace only works for root!
[acme@quaco perf]$

Oops, so lets try as root, doing it system wide, then start the 'perf
trace' part:

[root@quaco ~]# perf ftrace -G bpf_prog_load -a
 5)               |  bpf_prog_load() {
 5)               |    __check_object_size() {
 5)   0.110 us    |      __virt_addr_valid();
 5)   0.111 us    |      check_stack_object();
 5)   0.534 us    |    }
 5)               |    capable() {
 5)               |      ns_capable_common() {
 5)               |        security_capable() {
 5)   0.102 us    |          cap_capable();
 5)   0.336 us    |        }
 5)   0.773 us    |      }
 5)   0.989 us    |    }
 5) + 18.444 us   |  }
 5)               |  bpf_prog_load() {
 5)               |    __check_object_size() {
 5)   0.117 us    |      __virt_addr_valid();
 5)   0.116 us    |      check_stack_object();
 5)   0.575 us    |    }
 5)               |    capable() {
 5)               |      ns_capable_common() {
 5)               |        security_capable() {
 5)   0.104 us    |          cap_capable();
 5)   0.318 us    |        }
 5)   0.519 us    |      }
 5)   0.722 us    |    }
 5)   1.671 us    |  }
 5)               |  bpf_prog_load() {
 5)               |    __check_object_size() {
 5)   0.105 us    |      __virt_addr_valid();
 5)   0.103 us    |      check_stack_object();
 5)   0.527 us    |    }
 5)               |    capable() {
 5)               |      ns_capable_common() {
 5)               |        security_capable() {
 5)   0.099 us    |          cap_capable();
 5)   0.315 us    |        }
 5)   0.520 us    |      }
 5)   0.715 us    |    }
 5)   5.111 us    |  }
 
 Ok, not that helpful, but should be this one:

         if (type != BPF_PROG_TYPE_SOCKET_FILTER &&
             type != BPF_PROG_TYPE_CGROUP_SKB &&
            !capable(CAP_SYS_ADMIN))
                return -EPERM;

I'll update the error message accordingly :-/

Only root can attach eBPF programs to tracepoints.

Would be really good if we could have a more restricted program type to
attach to tracepoints, one that would be able to run only in the context
of their threads and access only the pointers in the tracepoints, that
way the 'perf trace' augmented syscalls code would be usable for
non-root users just like the other 'perf' commands are, allowing us to,
as with root, to copy the pointer arguments, like:

[root@quaco ~]# cd ~acme/git/perf/tools/perf/examples/bpf
[root@quaco bpf]# perf trace -e open*,augmented_raw_syscalls.o cat /etc/passwd > /dev/null
     0.000 ( 0.007 ms): cat/29941 openat(dfd: CWD, filename: /etc/ld.so.cache, flags: CLOEXEC           ) = 3
     0.018 ( 0.004 ms): cat/29941 openat(dfd: CWD, filename: /lib64/libc.so.6, flags: CLOEXEC           ) = 3
     0.185 ( 0.005 ms): cat/29941 openat(dfd: CWD, filename: /usr/lib/locale/locale-archive, flags: CLOEXEC) = 3
     0.223 ( 0.047 ms): cat/29941 openat(dfd: CWD, filename: /etc/passwd                                ) = 3

Without that we are back to just what is present in the tracepoints, the
pointers:

[root@quaco bpf]# perf trace -e open* cat /etc/passwd > /dev/null
     0.000 ( 0.006 ms): cat/29946 openat(dfd: CWD, filename: 0xa354e8b3, flags: CLOEXEC                 ) = 3
     0.017 ( 0.004 ms): cat/29946 openat(dfd: CWD, filename: 0xa3558d00, flags: CLOEXEC                 ) = 3
     0.217 ( 0.005 ms): cat/29946 openat(dfd: CWD, filename: 0xa34d6a20, flags: CLOEXEC                 ) = 3
     0.260 ( 0.003 ms): cat/29946 openat(dfd: CWD, filename: 0xcd70cd69                                 ) = 3
[root@quaco bpf]# file augmented_raw_syscalls.o
augmented_raw_syscalls.o: ELF 64-bit LSB relocatable, eBPF, version 1 (SYSV), not stripped
[root@quaco bpf]#

- Arnaldo

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: Debugging eBPF was: Re: [PATCH bpf-next 0/8] tools: bpftool: add probes for system and device
  2018-12-13 13:49   ` Debugging eBPF was: " Arnaldo Carvalho de Melo
@ 2018-12-13 20:55     ` Alexei Starovoitov
  2018-12-14 13:39       ` Arnaldo Carvalho de Melo
  0 siblings, 1 reply; 41+ messages in thread
From: Alexei Starovoitov @ 2018-12-13 20:55 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Quentin Monnet, Alexei Starovoitov, Daniel Borkmann, netdev,
	oss-drivers, Jesper Dangaard Brouer, Stanislav Fomichev

On Thu, Dec 13, 2018 at 10:49:09AM -0300, Arnaldo Carvalho de Melo wrote:
> 
> Only root can attach eBPF programs to tracepoints.
> 
> Would be really good if we could have a more restricted program type to
> attach to tracepoints, one that would be able to run only in the context
> of their threads and access only the pointers in the tracepoints, that
> way the 'perf trace' augmented syscalls code would be usable for
> non-root users just like the other 'perf' commands are, allowing us to,
> as with root, to copy the pointer arguments, like:

I don't think there is a clean way of doing non-root with tracepoints or syscalls.
The kernel side would need to start filtering the progs.
Like current uid == uid of loaded prog. But then there are tail_calls.
they would need to be disabled. 
tracepoints args can be pointers. _all_ of them in the kernel would need to
be annotated to make sure pointers don't leak into unpriv user space.
and so on and so forth.

I think better way forward would be to introduce something in the middle.
Between root and unpriv. Something that tracing bpf progs can use.
May be new capability?

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH bpf-next 1/8] tools: bpftool: add basic probe capability, probe syscall and kversion
  2018-12-13 12:19 ` [PATCH bpf-next 1/8] tools: bpftool: add basic probe capability, probe syscall and kversion Quentin Monnet
@ 2018-12-14  2:50   ` Stanislav Fomichev
  2018-12-14 11:27     ` Quentin Monnet
  2018-12-14 23:35   ` Daniel Borkmann
  1 sibling, 1 reply; 41+ messages in thread
From: Stanislav Fomichev @ 2018-12-14  2:50 UTC (permalink / raw)
  To: Quentin Monnet
  Cc: Alexei Starovoitov, Daniel Borkmann, netdev, oss-drivers,
	Arnaldo Carvalho de Melo, Jesper Dangaard Brouer,
	Stanislav Fomichev

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@netronome.com>
> Reviewed-by: Jakub Kicinski <jakub.kicinski@netronome.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
> 

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH bpf-next 2/8] tools: bpftool: add probes for /proc/ eBPF parameters
  2018-12-13 12:19 ` [PATCH bpf-next 2/8] tools: bpftool: add probes for /proc/ eBPF parameters Quentin Monnet
@ 2018-12-14  2:58   ` Stanislav Fomichev
  2018-12-14 11:27     ` Quentin Monnet
  2018-12-14 23:40   ` Daniel Borkmann
  1 sibling, 1 reply; 41+ messages in thread
From: Stanislav Fomichev @ 2018-12-14  2:58 UTC (permalink / raw)
  To: Quentin Monnet
  Cc: Alexei Starovoitov, Daniel Borkmann, netdev, oss-drivers,
	Arnaldo Carvalho de Melo, Jesper Dangaard Brouer,
	Stanislav Fomichev

On 12/13, Quentin Monnet wrote:
> Add a set of probes to dump the eBPF-related parameters available from
> /proc/: availability of bpf() syscall for unprivileged users,
> JIT compiler status and hardening status, kallsyms exports status.
> 
> Sample output:
> 
>     # bpftool feature probe kernel
>     Scanning system configuration...
>     bpf() syscall for unprivileged users is enabled
>     JIT compiler is disabled
>     JIT compiler hardening is disabled
>     JIT compiler kallsyms exports are disabled
>     ...
> 
>     # bpftool --json --pretty feature probe kernel
>     {
>         "system_config": {
>             "unprivileged_bpf_disabled": 0,
>             "bpf_jit_enable": 0,
>             "bpf_jit_harden": 0,
>             "bpf_jit_kallsyms": 0
>         },
>         ...
>     }
> 

[..]

>     # bpftool feature probe kernel macros prefix BPFTOOL_
>     #define UNPRIVILEGED_BPF_DISABLED UNPRIVILEGED_BPF_DISABLED_OFF
>     #define  UNPRIVILEGED_BPF_DISABLED_OFF 0
>     #define  UNPRIVILEGED_BPF_DISABLED_ON 1
>     #define  UNPRIVILEGED_BPF_DISABLED_UNKNOWN -1
This looks a bit complicated. For example, why not simply define:

#define UNPRIVILEGED_BPF_DISABLED 1 /* when it's explicitly disabled */
#define UNPRIVILEGED_BPF_ENABLED  1 /* when it's explicitly enabled */
#define UNPRIVILEGED_BPF_UNKNOWN  1 /* when unknown - maybe even skip
this altogether and treat unknown == disabled (worst case) */

Then, I, as a potential user, can do:

#if defined(UNPRIVILEGED_BPF_ENABLED)
/* do something useful */
#elif defined(UNPRIVILEGED_BPF_DISABLED)
/* print an error asking to use root */
#else
/* try anyway, fallback to error ? */
#endif

IMO, if don't want to do stuff like:

#if UNPRIVILEGED_BPF_DISABLED == UNPRIVILEGED_BPF_DISABLED_OFF
#elif UNPRIVILEGED_BPF_DISABLED == UNPRIVILEGED_BPF_DISABLED_ON
#else
#endif

I live in my mental model if ifdefs, not complicated cpp #if
comparisons.

Just a suggestion, I feel like we can keep it simple.

>     #define JIT_COMPILER_ENABLE JIT_COMPILER_ENABLE_OFF
>     #define  JIT_COMPILER_ENABLE_OFF 0
>     #define  JIT_COMPILER_ENABLE_ON 1
>     #define  JIT_COMPILER_ENABLE_ON_WITH_DEBUG 2
>     #define  JIT_COMPILER_ENABLE_UNKNOWN -1
Same here:
JIT_COMPILER_ENABLED
JIT_COMPILER_ENABLED_WITH_DEBUG
JIT_COMPILER_DISABLED
JIT_COMPILER_UNKNOWN

And so on...
>     #define JIT_COMPILER_HARDEN JIT_COMPILER_HARDEN_OFF
>     #define  JIT_COMPILER_HARDEN_OFF 0
>     #define  JIT_COMPILER_HARDEN_FOR_UNPRIVILEGED 1
>     #define  JIT_COMPILER_HARDEN_FOR_ALL_USERS 2
>     #define  JIT_COMPILER_HARDEN_UNKNOWN -1
>     #define JIT_COMPILER_KALLSYMS JIT_COMPILER_KALLSYMS_OFF
>     #define  JIT_COMPILER_KALLSYMS_OFF 0
>     #define  JIT_COMPILER_KALLSYMS_FOR_ROOT 1
>     #define  JIT_COMPILER_KALLSYMS_UNKNOWN -1
>     ...
> 
> These probes are skipped if procfs is not mounted.
> 
> Signed-off-by: Quentin Monnet <quentin.monnet@netronome.com>
> Reviewed-by: Jakub Kicinski <jakub.kicinski@netronome.com>
> ---
>  tools/bpf/bpftool/feature.c | 271 ++++++++++++++++++++++++++++++++++++
>  1 file changed, 271 insertions(+)
> 
> diff --git a/tools/bpf/bpftool/feature.c b/tools/bpf/bpftool/feature.c
> index e1784611575d..9fa7016c7d21 100644
> --- a/tools/bpf/bpftool/feature.c
> +++ b/tools/bpf/bpftool/feature.c
> @@ -5,6 +5,7 @@
>  #include <string.h>
>  #include <unistd.h>
>  #include <sys/utsname.h>
> +#include <sys/vfs.h>
>  
>  #include <linux/filter.h>
>  #include <linux/limits.h>
> @@ -13,11 +14,29 @@
>  
>  #include "main.h"
>  
> +#ifndef PROC_SUPER_MAGIC
> +# define PROC_SUPER_MAGIC	0x9fa0
> +#endif
> +
>  enum probe_component {
>  	COMPONENT_UNSPEC,
>  	COMPONENT_KERNEL,
>  };
>  
> +/* Miscellaneous utility functions */
> +
> +static bool check_procfs(void)
> +{
> +	struct statfs st_fs;
> +
> +	if (statfs("/proc", &st_fs) < 0)
> +		return false;
> +	if ((unsigned long)st_fs.f_type != PROC_SUPER_MAGIC)
> +		return false;
> +
> +	return true;
> +}
> +
>  /* Printing utility functions */
>  
>  static void
> @@ -49,6 +68,236 @@ print_start_section(const char *json_title, const char *define_comment,
>  
>  /* Probing functions */
>  
> +static int read_procfs(const char *path)
> +{
> +	char *endptr, *line = NULL;
> +	size_t len = 0;
> +	FILE *fd;
> +	int res;
> +
> +	fd = fopen(path, "r");
> +	if (!fd)
> +		return -1;
> +
> +	res = getline(&line, &len, fd);
> +	fclose(fd);
> +	if (res < 0)
> +		return -1;
> +
> +	errno = 0;
> +	res = strtol(line, &endptr, 10);
> +	if (errno || *line == '\0' || *endptr != '\n')
> +		res = -1;
> +	free(line);
> +
> +	return res;
> +}
> +
> +static void probe_unprivileged_disabled(const char *define_prefix)
> +{
> +	int res;
> +
> +	res = read_procfs("/proc/sys/kernel/unprivileged_bpf_disabled");
> +	if (json_output) {
> +		jsonw_int_field(json_wtr, "unprivileged_bpf_disabled", res);
> +	} else if (define_prefix) {
> +		printf("#define %sUNPRIVILEGED_BPF_DISABLED ", define_prefix);
> +		switch (res) {
> +		case 0:
> +			printf("%sUNPRIVILEGED_BPF_DISABLED_OFF\n",
> +			       define_prefix);
> +			break;
> +		case 1:
> +			printf("%sUNPRIVILEGED_BPF_DISABLED_ON\n",
> +			       define_prefix);
> +			break;
> +		case -1:
> +			printf("%sUNPRIVILEGED_BPF_DISABLED_UNKNOWN\n",
> +			       define_prefix);
> +			break;
> +		default:
> +			printf("%d\n", res);
> +		}
> +		printf("#define  %sUNPRIVILEGED_BPF_DISABLED_OFF 0\n",
> +		       define_prefix);
> +		printf("#define  %sUNPRIVILEGED_BPF_DISABLED_ON 1\n",
> +		       define_prefix);
> +		printf("#define  %sUNPRIVILEGED_BPF_DISABLED_UNKNOWN -1\n",
> +		       define_prefix);
> +	} else {
> +		switch (res) {
> +		case 0:
> +			printf("bpf() syscall for unprivileged users is enabled\n");
> +			break;
> +		case 1:
> +			printf("bpf() syscall restricted to privileged users\n");
> +			break;
> +		case -1:
> +			printf("Unable to retrieve required privileges for bpf() syscall\n");
> +			break;
> +		default:
> +			printf("bpf() syscall restriction has unknown value %d\n", res);
> +		}
> +	}
> +}
> +
> +static void probe_jit_enable(const char *define_prefix)
> +{
> +	int res;
> +
> +	res = read_procfs("/proc/sys/net/core/bpf_jit_enable");
> +	if (json_output) {
> +		jsonw_int_field(json_wtr, "bpf_jit_enable", res);
> +	} else if (define_prefix) {
> +		printf("#define %sJIT_COMPILER_ENABLE ", define_prefix);
> +		switch (res) {
> +		case 0:
> +			printf("%sJIT_COMPILER_ENABLE_OFF\n", define_prefix);
> +			break;
> +		case 1:
> +			printf("%sJIT_COMPILER_ENABLE_ON\n", define_prefix);
> +			break;
> +		case 2:
> +			printf("%sJIT_COMPILER_ENABLE_ON_WITH_DEBUG\n",
> +			       define_prefix);
> +			break;
> +		case -1:
> +			printf("%sJIT_COMPILER_ENABLE_UNKNOWN\n",
> +			       define_prefix);
> +			break;
> +		default:
> +			printf("%d\n", res);
> +		}
> +		printf("#define  %sJIT_COMPILER_ENABLE_OFF 0\n", define_prefix);
> +		printf("#define  %sJIT_COMPILER_ENABLE_ON 1\n", define_prefix);
> +		printf("#define  %sJIT_COMPILER_ENABLE_ON_WITH_DEBUG 2\n",
> +		       define_prefix);
> +		printf("#define  %sJIT_COMPILER_ENABLE_UNKNOWN -1\n",
> +		       define_prefix);
> +	} else {
> +		switch (res) {
> +		case 0:
> +			printf("JIT compiler is disabled\n");
> +			break;
> +		case 1:
> +			printf("JIT compiler is enabled\n");
> +			break;
> +		case 2:
> +			printf("JIT compiler is enabled with debugging traces in kernel logs\n");
> +			break;
> +		case -1:
> +			printf("Unable to retrieve JIT-compiler status\n");
> +			break;
> +		default:
> +			printf("JIT-compiler status has unknown value %d\n",
> +			       res);
> +		}
> +	}
> +}
> +
> +static void probe_jit_harden(const char *define_prefix)
> +{
> +	int res;
> +
> +	res = read_procfs("/proc/sys/net/core/bpf_jit_harden");
> +	if (json_output) {
> +		jsonw_int_field(json_wtr, "bpf_jit_harden", res);
> +	} else if (define_prefix) {
> +		printf("#define %sJIT_COMPILER_HARDEN ", define_prefix);
> +		switch (res) {
> +		case 0:
> +			printf("%sJIT_COMPILER_HARDEN_OFF\n", define_prefix);
> +			break;
> +		case 1:
> +			printf("%sJIT_COMPILER_HARDEN_FOR_UNPRIVILEGED\n",
> +			       define_prefix);
> +			break;
> +		case 2:
> +			printf("%sJIT_COMPILER_HARDEN_FOR_ALL_USERS\n",
> +			       define_prefix);
> +			break;
> +		case -1:
> +			printf("%sJIT_COMPILER_HARDEN_UNKNOWN\n",
> +			       define_prefix);
> +			break;
> +		default:
> +			printf("%d\n", res);
> +		}
> +		printf("#define  %sJIT_COMPILER_HARDEN_OFF 0\n", define_prefix);
> +		printf("#define  %sJIT_COMPILER_HARDEN_FOR_UNPRIVILEGED 1\n",
> +		       define_prefix);
> +		printf("#define  %sJIT_COMPILER_HARDEN_FOR_ALL_USERS 2\n",
> +		       define_prefix);
> +		printf("#define  %sJIT_COMPILER_HARDEN_UNKNOWN -1\n",
> +		       define_prefix);
> +	} else {
> +		switch (res) {
> +		case 0:
> +			printf("JIT compiler hardening is disabled\n");
> +			break;
> +		case 1:
> +			printf("JIT compiler hardening is enabled for unprivileged users\n");
> +			break;
> +		case 2:
> +			printf("JIT compiler hardening is enabled for all users\n");
> +			break;
> +		case -1:
> +			printf("Unable to retrieve JIT hardening status\n");
> +			break;
> +		default:
> +			printf("JIT hardening status has unknown value %d\n",
> +			       res);
> +		}
> +	}
> +}
> +
> +static void probe_jit_kallsyms(const char *define_prefix)
> +{
> +	int res;
> +
> +	res = read_procfs("/proc/sys/net/core/bpf_jit_kallsyms");
> +	if (json_output) {
> +		jsonw_int_field(json_wtr, "bpf_jit_kallsyms", res);
> +	} else if (define_prefix) {
> +		printf("#define %sJIT_COMPILER_KALLSYMS ", define_prefix);
> +		switch (res) {
> +		case 0:
> +			printf("%sJIT_COMPILER_KALLSYMS_OFF\n", define_prefix);
> +			break;
> +		case 1:
> +			printf("%sJIT_COMPILER_KALLSYMS_FOR_ROOT\n",
> +			       define_prefix);
> +			break;
> +		case -1:
> +			printf("%sJIT_COMPILER_KALLSYMS_UNKNOWN\n",
> +			       define_prefix);
> +			break;
> +		default:
> +			printf("%d\n", res);
> +		}
> +		printf("#define  %sJIT_COMPILER_KALLSYMS_OFF 0\n",
> +		       define_prefix);
> +		printf("#define  %sJIT_COMPILER_KALLSYMS_FOR_ROOT 1\n",
> +		       define_prefix);
> +		printf("#define  %sJIT_COMPILER_KALLSYMS_UNKNOWN -1\n",
> +		       define_prefix);
> +	} else {
> +		switch (res) {
> +		case 0:
> +			printf("JIT compiler kallsyms exports are disabled\n");
> +			break;
> +		case 1:
> +			printf("JIT compiler kallsyms exports are enabled for root\n");
> +			break;
> +		case -1:
> +			printf("Unable to retrieve JIT kallsyms export status\n");
> +			break;
> +		default:
> +			printf("JIT kallsyms exports status has unknown value %d\n", res);
> +		}
> +	}
> +}
> +
>  static int probe_kernel_version(const char *define_prefix)
>  {
>  	int version, subversion, patchlevel, code = 0;
> @@ -138,6 +387,28 @@ static int do_probe(int argc, char **argv)
>  	if (json_output)
>  		jsonw_start_object(json_wtr);
>  
> +	switch (target) {
> +	case COMPONENT_KERNEL:
> +	case COMPONENT_UNSPEC:
> +		print_start_section("system_config",
> +				    "/*** System configuration ***/",
> +				    "Scanning system configuration...",
> +				    define_prefix);
> +		if (check_procfs()) {
> +			probe_unprivileged_disabled(define_prefix);
> +			probe_jit_enable(define_prefix);
> +			probe_jit_harden(define_prefix);
> +			probe_jit_kallsyms(define_prefix);
> +		} else {
> +			p_info("/* procfs not mounted, skipping related probes */");
> +		}
> +		if (json_output)
> +			jsonw_end_object(json_wtr);
> +		else
> +			printf("\n");
> +		break;
> +	}
> +
>  	print_start_section("syscall_config",
>  			    "/*** System call and kernel version ***/",
>  			    "Scanning system call and kernel version...",
> -- 
> 2.17.1
> 

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH bpf-next 1/8] tools: bpftool: add basic probe capability, probe syscall and kversion
  2018-12-14  2:50   ` Stanislav Fomichev
@ 2018-12-14 11:27     ` Quentin Monnet
  2018-12-14 18:45       ` Stanislav Fomichev
  0 siblings, 1 reply; 41+ messages in thread
From: Quentin Monnet @ 2018-12-14 11:27 UTC (permalink / raw)
  To: Stanislav Fomichev
  Cc: Alexei Starovoitov, Daniel Borkmann, netdev, oss-drivers,
	Arnaldo Carvalho de Melo, Jesper Dangaard Brouer,
	Stanislav Fomichev

2018-12-13 18:50 UTC-0800 ~ Stanislav Fomichev <sdf@fomichev.me>
> 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@netronome.com>
>> Reviewed-by: Jakub Kicinski <jakub.kicinski@netronome.com>
>> ---

> 
> [..]
> 
>> +		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
> 
> ?

But then if you include this as a header, you have no way to distinguish
the case when the feature is not supported from when bpftool did not
attempt to run the probe at all?

>> +	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.

I've been pondering about the interest of keeping human-readable output.
I think it helps users understand the output, especially for the procfs
parameters for example.

As for scripts, they can and should stick to JSON. Plain output from
bpftool is not meant to be reliable for scripting.

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH bpf-next 2/8] tools: bpftool: add probes for /proc/ eBPF parameters
  2018-12-14  2:58   ` Stanislav Fomichev
@ 2018-12-14 11:27     ` Quentin Monnet
  0 siblings, 0 replies; 41+ messages in thread
From: Quentin Monnet @ 2018-12-14 11:27 UTC (permalink / raw)
  To: Stanislav Fomichev
  Cc: Alexei Starovoitov, Daniel Borkmann, netdev, oss-drivers,
	Arnaldo Carvalho de Melo, Jesper Dangaard Brouer,
	Stanislav Fomichev

2018-12-13 18:58 UTC-0800 ~ Stanislav Fomichev <sdf@fomichev.me>
> On 12/13, Quentin Monnet wrote:
>> Add a set of probes to dump the eBPF-related parameters available from
>> /proc/: availability of bpf() syscall for unprivileged users,
>> JIT compiler status and hardening status, kallsyms exports status.
>>
>> Sample output:
>>
>>     # bpftool feature probe kernel
>>     Scanning system configuration...
>>     bpf() syscall for unprivileged users is enabled
>>     JIT compiler is disabled
>>     JIT compiler hardening is disabled
>>     JIT compiler kallsyms exports are disabled
>>     ...
>>
>>     # bpftool --json --pretty feature probe kernel
>>     {
>>         "system_config": {
>>             "unprivileged_bpf_disabled": 0,
>>             "bpf_jit_enable": 0,
>>             "bpf_jit_harden": 0,
>>             "bpf_jit_kallsyms": 0
>>         },
>>         ...
>>     }
>>
> 
> [..]
> 
>>     # bpftool feature probe kernel macros prefix BPFTOOL_
>>     #define UNPRIVILEGED_BPF_DISABLED UNPRIVILEGED_BPF_DISABLED_OFF
>>     #define  UNPRIVILEGED_BPF_DISABLED_OFF 0
>>     #define  UNPRIVILEGED_BPF_DISABLED_ON 1
>>     #define  UNPRIVILEGED_BPF_DISABLED_UNKNOWN -1
> This looks a bit complicated. For example, why not simply define:
> 
> #define UNPRIVILEGED_BPF_DISABLED 1 /* when it's explicitly disabled */
> #define UNPRIVILEGED_BPF_ENABLED  1 /* when it's explicitly enabled */
> #define UNPRIVILEGED_BPF_UNKNOWN  1 /* when unknown - maybe even skip
> this altogether and treat unknown == disabled (worst case) */
> 
> Then, I, as a potential user, can do:
> 
> #if defined(UNPRIVILEGED_BPF_ENABLED)
> /* do something useful */
> #elif defined(UNPRIVILEGED_BPF_DISABLED)
> /* print an error asking to use root */
> #else
> /* try anyway, fallback to error ? */
> #endif
> 
> IMO, if don't want to do stuff like:
> 
> #if UNPRIVILEGED_BPF_DISABLED == UNPRIVILEGED_BPF_DISABLED_OFF
> #elif UNPRIVILEGED_BPF_DISABLED == UNPRIVILEGED_BPF_DISABLED_ON
> #else
> #endif
> 
> I live in my mental model if ifdefs, not complicated cpp #if
> comparisons.
> 
> Just a suggestion, I feel like we can keep it simple.

It's true that it make things look simpler. We loose the direct
correspondence between macro name and procfs file name, but I suppose we
can live with it.

I'm more concerned about the loss of information for the "unknown" case,
however. If we successfully retrieved a value from the procfs, I find it
harsh not to give it to the user, even if we cannot interpret it :/. And
I don't see a way of doing that without having a UNPRIVILEGED_BPF_VALUE
macro of some kind.

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH bpf-next 0/8] tools: bpftool: add probes for system and device
  2018-12-13 12:19 [PATCH bpf-next 0/8] tools: bpftool: add probes for system and device Quentin Monnet
                   ` (8 preceding siblings ...)
  2018-12-13 13:03 ` [PATCH bpf-next 0/8] tools: bpftool: add probes for system and device Arnaldo Carvalho de Melo
@ 2018-12-14 11:53 ` Quentin Monnet
  2018-12-14 18:21   ` Stanislav Fomichev
  2018-12-14 14:00 ` Arnaldo Carvalho de Melo
  10 siblings, 1 reply; 41+ messages in thread
From: Quentin Monnet @ 2018-12-14 11:53 UTC (permalink / raw)
  To: Alexei Starovoitov, Daniel Borkmann
  Cc: netdev, oss-drivers, Arnaldo Carvalho de Melo,
	Jesper Dangaard Brouer, Stanislav Fomichev

2018-12-13 12:19 UTC+0000 ~ Quentin Monnet <quentin.monnet@netronome.com>
> Hi,
> This set add a new command to bpftool in order to dump a list of
> eBPF-related parameters for the system (or for a specific network
> device) to the console. Once again, this is based on a suggestion from
> Daniel.
> 
> At this time, output includes:
> 

So as a reminder this one comes from an actual probe with the syscall...

>     - Availability of bpf() system call

... those 4 are read from procfs...

>     - Availability of bpf() system call for unprivileged users
>     - JIT status (enabled or not, with or without debugging traces)
>     - JIT hardening status
>     - JIT kallsyms exports status

... these are read from /boot/config-$(uname -r)...

>     - Status of kernel compilation options related to BPF features

... this from uname()...

>     - Release number of the running kernel

... and the remaining ones are probed with minimal BPF programs.

>     - Availability of known eBPF program types
>     - Availability of known eBPF map types
>     - Availability of known eBPF helper functions

As discussed with Stanislav and Daniel, some of the probing should
probably be moved to libbpf instead for the next version of this set. As
I see it, I could move probing to libbpf for:

- BPF prog and map types
- BPF helper functions
- bpf() syscall availability

I do not think kernel compile options, or kernel release number, should
go to libbpf, they're probably better in bpftool. I'm unsure about the
procfs parameters, I'm considering leaving them in bpftool for now. Do
others have an opinion about this?

Quentin

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: Debugging eBPF was: Re: [PATCH bpf-next 0/8] tools: bpftool: add probes for system and device
  2018-12-13 20:55     ` Alexei Starovoitov
@ 2018-12-14 13:39       ` Arnaldo Carvalho de Melo
  0 siblings, 0 replies; 41+ messages in thread
From: Arnaldo Carvalho de Melo @ 2018-12-14 13:39 UTC (permalink / raw)
  To: Alexei Starovoitov
  Cc: Quentin Monnet, Alexei Starovoitov, Daniel Borkmann, netdev,
	oss-drivers, Jesper Dangaard Brouer, Stanislav Fomichev

Em Thu, Dec 13, 2018 at 12:55:10PM -0800, Alexei Starovoitov escreveu:
> On Thu, Dec 13, 2018 at 10:49:09AM -0300, Arnaldo Carvalho de Melo wrote:
> > Only root can attach eBPF programs to tracepoints.

> > Would be really good if we could have a more restricted program type to
> > attach to tracepoints, one that would be able to run only in the context
> > of their threads and access only the pointers in the tracepoints, that
> > way the 'perf trace' augmented syscalls code would be usable for
> > non-root users just like the other 'perf' commands are, allowing us to,
> > as with root, to copy the pointer arguments, like:
 
> I don't think there is a clean way of doing non-root with tracepoints or syscalls.
> The kernel side would need to start filtering the progs.
> Like current uid == uid of loaded prog. But then there are tail_calls.

Yeah, that program would run only for threads owned by the prog owner.

> they would need to be disabled. 

I think if that is not possible, then would be an acceptable limitation
in a first implementation. I.e. my understanding is that eBPF started
with some limited scope, then as it goes maturing, more features were
added as its security/performance implications were understood.

> tracepoints args can be pointers. _all_ of them in the kernel would need to
> be annotated to make sure pointers don't leak into unpriv user space.
> and so on and so forth.

Yes, I thought about heavily restricting them, i.e. points would be
allowed just for some very special cases, like the arguments to
raw_syscalls.sys_{sys_enter,sys_exit}, as a starting point.
 
> I think better way forward would be to introduce something in the middle.
> Between root and unpriv. Something that tracing bpf progs can use.
> May be new capability?

Well, that would be interesting too, I think, would make go a bit
forward, for a class of applications where trusting the tracer is
possible.

- Arnaldo

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH bpf-next 0/8] tools: bpftool: add probes for system and device
  2018-12-13 12:19 [PATCH bpf-next 0/8] tools: bpftool: add probes for system and device Quentin Monnet
                   ` (9 preceding siblings ...)
  2018-12-14 11:53 ` Quentin Monnet
@ 2018-12-14 14:00 ` Arnaldo Carvalho de Melo
  2018-12-14 14:56   ` Quentin Monnet
  10 siblings, 1 reply; 41+ messages in thread
From: Arnaldo Carvalho de Melo @ 2018-12-14 14:00 UTC (permalink / raw)
  To: Quentin Monnet
  Cc: Alexei Starovoitov, Daniel Borkmann, netdev, oss-drivers,
	Jesper Dangaard Brouer, Stanislav Fomichev

Em Thu, Dec 13, 2018 at 12:19:14PM +0000, Quentin Monnet escreveu:
> Hi,
> This set add a new command to bpftool in order to dump a list of
> eBPF-related parameters for the system (or for a specific network
> device) to the console. Once again, this is based on a suggestion from
> Daniel.
> 
> At this time, output includes:
> 
>     - Availability of bpf() system call
>     - Availability of bpf() system call for unprivileged users
>     - JIT status (enabled or not, with or without debugging traces)
>     - JIT hardening status
>     - JIT kallsyms exports status
>     - Status of kernel compilation options related to BPF features
>     - Release number of the running kernel
>     - Availability of known eBPF program types
>     - Availability of known eBPF map types
>     - Availability of known eBPF helper functions
> 
> There are three different ways to dump this information at this time:
> 
>     - Plain output dumps probe results in plain text. It is the most
>       flexible options for providing descriptive output to the user, but
>       should not be relied upon for parsing the output.
>     - JSON output is supported.
>     - A third mode, available through the "macros" keyword appended to
>       the command line, dumps the parameters as a series of "#define"
>       directives, that can be included into a C header file for example.
> 
> If the user does not have root privileges (or more precisely, the
> CAP_SYS_ADMIN capability) detection will be erroneous for most
> parameters. Therefore, forbid non-root users to run the command.

One other thing I noticed is that this has lots of goodies that are not
bpftool specific, like the json writer, the procfs reading routines,
etc.

perf has these and some were even moved to tools/lib/api/, things like
finding the procfs, debugfs, sysfs mount points, routines to mount then
automatically when the user can do it, etc.

Have you considered using them? If so, what prevented you from doing it?
Licensing?

Sharing these non-tool specific routines in tools/lib/ is a good thing
and we should work out details on what prevents that from happening.

Another thing that came to mind is that the bpf loaded in perf has
routines for figuring out the kbuild directory, kernel version, etc.

Please take a look at tools/perf/util/llvm-utils.c and
tools/perf/util/bpf-loader.c. If we could reuse what is there, working
out licensing details with Wang, etc, that would be awesome.

- Arnaldo

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH bpf-next 0/8] tools: bpftool: add probes for system and device
  2018-12-14 14:00 ` Arnaldo Carvalho de Melo
@ 2018-12-14 14:56   ` Quentin Monnet
  2018-12-14 17:26     ` Arnaldo Carvalho de Melo
  0 siblings, 1 reply; 41+ messages in thread
From: Quentin Monnet @ 2018-12-14 14:56 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Alexei Starovoitov, Daniel Borkmann, netdev, oss-drivers,
	Jesper Dangaard Brouer, Stanislav Fomichev

Hi Arnaldo,

2018-12-14 11:00 UTC-0300 ~ Arnaldo Carvalho de Melo <acme@kernel.org>
> Em Thu, Dec 13, 2018 at 12:19:14PM +0000, Quentin Monnet escreveu:
>> Hi,
>> This set add a new command to bpftool in order to dump a list of
>> eBPF-related parameters for the system (or for a specific network
>> device) to the console. Once again, this is based on a suggestion from
>> Daniel.
>>
>> At this time, output includes:
>>
>>     - Availability of bpf() system call
>>     - Availability of bpf() system call for unprivileged users
>>     - JIT status (enabled or not, with or without debugging traces)
>>     - JIT hardening status
>>     - JIT kallsyms exports status
>>     - Status of kernel compilation options related to BPF features
>>     - Release number of the running kernel
>>     - Availability of known eBPF program types
>>     - Availability of known eBPF map types
>>     - Availability of known eBPF helper functions
>>
>> There are three different ways to dump this information at this time:
>>
>>     - Plain output dumps probe results in plain text. It is the most
>>       flexible options for providing descriptive output to the user, but
>>       should not be relied upon for parsing the output.
>>     - JSON output is supported.
>>     - A third mode, available through the "macros" keyword appended to
>>       the command line, dumps the parameters as a series of "#define"
>>       directives, that can be included into a C header file for example.
>>
>> If the user does not have root privileges (or more precisely, the
>> CAP_SYS_ADMIN capability) detection will be erroneous for most
>> parameters. Therefore, forbid non-root users to run the command.
> 
> One other thing I noticed is that this has lots of goodies that are not
> bpftool specific, like the json writer, the procfs reading routines,
> etc.
> 
> perf has these and some were even moved to tools/lib/api/, things like
> finding the procfs, debugfs, sysfs mount points, routines to mount then
> automatically when the user can do it, etc.
> 
> Have you considered using them? If so, what prevented you from doing it?
> Licensing?

Some of it is not necessarily relevant. For JSON, for example, it seems
that related parts in perf provide JSON parsing. bpftool does not parse
any JSON, it only needs to print JSON, and I didn't find that in perf.
This being said making both JSON parsing and printing available under
e.g. tools/lib/api (providing licensing details allow it) would make
sense to me, so that it can be shared if e.g. bpftool had to parse JSON
one day (or if other tools were added).

As for BPF, most of the low-level object management directly comes from
libbpf. I see perf uses it as well, but it doesn't really look like the
code of the two tools could be merged easily now.

Regarding procfs, debugfs, sysfs, it's true that there are things that
we could maybe reuse. Here I don't have any argument - mostly I didn't
notice these functions were available here when working on bpftool (I
mostly looked at iproute2 instead).

> Sharing these non-tool specific routines in tools/lib/ is a good thing
> and we should work out details on what prevents that from happening.
> 
> Another thing that came to mind is that the bpf loaded in perf has
> routines for figuring out the kbuild directory, kernel version, etc.
> 
> Please take a look at tools/perf/util/llvm-utils.c and
> tools/perf/util/bpf-loader.c. If we could reuse what is there, working
> out licensing details with Wang, etc, that would be awesome.

At the moment bpftool does not use LLVM stuff. My opinion is that for
loading programs, improvements that could benefit to multiple projects
should probably go to libbpf. For things such as retrieving the kernel
version, we can maybe do something.

Overall I agree it would be nice to share more code between the two,
providing licensing allows it. I'm not sure there's much to share about
BPF itself, but JSON or other FS-related things could maybe be reused.
I'll try to look at it in more details when I have some time, and keep
it in mind for future bpftool work. Thanks!

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH bpf-next 0/8] tools: bpftool: add probes for system and device
  2018-12-14 14:56   ` Quentin Monnet
@ 2018-12-14 17:26     ` Arnaldo Carvalho de Melo
  0 siblings, 0 replies; 41+ messages in thread
From: Arnaldo Carvalho de Melo @ 2018-12-14 17:26 UTC (permalink / raw)
  To: Quentin Monnet
  Cc: Alexei Starovoitov, Daniel Borkmann, netdev, oss-drivers,
	Jesper Dangaard Brouer, Stanislav Fomichev

Em Fri, Dec 14, 2018 at 02:56:06PM +0000, Quentin Monnet escreveu:
> 2018-12-14 11:00 UTC-0300 ~ Arnaldo Carvalho de Melo <acme@kernel.org>
> > One other thing I noticed is that this has lots of goodies that are not
> > bpftool specific, like the json writer, the procfs reading routines,
> > etc.

> > perf has these and some were even moved to tools/lib/api/, things like
> > finding the procfs, debugfs, sysfs mount points, routines to mount then
> > automatically when the user can do it, etc.

> > Have you considered using them? If so, what prevented you from doing it?
> > Licensing?
 
> Some of it is not necessarily relevant. For JSON, for example, it seems
> that related parts in perf provide JSON parsing. bpftool does not parse
> any JSON, it only needs to print JSON, and I didn't find that in perf.

Right, perf reads, bpftool writes, so we have a complete JSON library,
having it in one place would expose it for further reuse.

For instance, I want to output in JSON the information in a perf.data
file:

[root@quaco ~]# perf report --header-only
# ========
# captured on    : Fri Dec 14 14:00:33 2018
# header version : 1
# data offset    : 488
# data size      : 22784
# feat offset    : 23272
# hostname : quaco
# os release : 4.20.0-rc5
# perf version : 4.20.rc3.g4ef9231
# arch : x86_64
# nrcpus online : 8
# nrcpus avail : 8
# cpudesc : Intel(R) Core(TM) i7-8650U CPU @ 1.90GHz
# cpuid : GenuineIntel,6,142,10
# total memory : 24555788 kB
# cmdline : /home/acme/bin/perf record -e /home/acme/git/perf/tools/perf/examples/bpf/augmented_raw_syscalls.c sleep 0.00001 
# event : name = raw_syscalls:sys_exit, , id = { 3708326, 3708327, 3708328, 3708329, 3708330, 3708331, 3708332, 3708333 }, type = 2, size = 112, >
# event : name = raw_syscalls:sys_enter, , id = { 3708334, 3708335, 3708336, 3708337, 3708338, 3708339, 3708340, 3708341 }, type = 2, size = 112,>
# CPU_TOPOLOGY info available, use -I to display
# NUMA_TOPOLOGY info available, use -I to display
# pmu mappings: intel_pt = 8, software = 1, power = 11, uprobe = 7, uncore_imc = 12, cpu = 4, cstate_core = 18, uncore_cbox_2 = 15, breakpoint = >
# CACHE info available, use -I to display
# time of first sample : 0.000000
# time of last sample : 0.000000
# sample duration :      0.000 ms
# MEM_TOPOLOGY info available, use -I to display
# missing features: BRANCH_STACK GROUP_DESC AUXTRACE STAT CLOCKID 
# ========
#
[root@quaco ~]#

For consumption by scripts.

> This being said making both JSON parsing and printing available under
> e.g. tools/lib/api (providing licensing details allow it) would make
> sense to me, so that it can be shared if e.g. bpftool had to parse JSON
> one day (or if other tools were added).

Right, I'd suggest tools/lib/json/ instead.
 
> As for BPF, most of the low-level object management directly comes from
> libbpf. I see perf uses it as well, but it doesn't really look like the
> code of the two tools could be merged easily now.

Right, perf was its first user, so since day one the idea was for
everything bpf related to go to tools/lib/bpf/ for reuse by other tools,
but what I was alluding to was some more stuff that comes before having
a BPF object for loading, and involves calling an external compiler, and
that involves finding the kbuild environment, etc.

That file name "llvm-utils.c" is kinda misleading, as it doesn't have
only thing exclusively related to llvm, for instance:

int llvm__get_nr_cpus(void)
{
        static int nr_cpus_avail = 0;
        char serr[STRERR_BUFSIZE];

        if (nr_cpus_avail > 0)
                return nr_cpus_avail;

        nr_cpus_avail = sysconf(_SC_NPROCESSORS_CONF);
        if (nr_cpus_avail <= 0) {
                pr_err(
"WARNING:\tunable to get available CPUs in this system: %s\n"
"        \tUse 128 instead.\n", str_error_r(errno, serr, sizeof(serr)));
                nr_cpus_avail = 128;
        }
        return nr_cpus_avail;
}

void llvm__get_kbuild_opts(char **kbuild_dir, char **kbuild_include_opts)

That calls things like:

static int detect_kbuild_dir(char **kbuild_dir)

int
fetch_kernel_version(unsigned int *puint, char *str,
                     size_t str_size)

That handles artifacts such as:

        if (access("/proc/version_signature", R_OK) == 0)
                if (!fetch_ubuntu_kernel_version(puint))
                        int_ver_ready = true;

Introduced in:

commit d18acd15c6dfb669f0463afa31ac5343594d2fe2
Author: Wang Nan <wangnan0@huawei.com>
Date:   Tue Nov 15 04:05:44 2016 +0000

    perf tools: Fix kernel version error in ubuntu

    On ubuntu the internal kernel version code is different from what can
    be retrived from uname:
 
> Regarding procfs, debugfs, sysfs, it's true that there are things that
> we could maybe reuse. Here I don't have any argument - mostly I didn't
> notice these functions were available here when working on bpftool (I
> mostly looked at iproute2 instead).

Ok
 
> > Sharing these non-tool specific routines in tools/lib/ is a good thing
> > and we should work out details on what prevents that from happening.
> > 
> > Another thing that came to mind is that the bpf loaded in perf has
> > routines for figuring out the kbuild directory, kernel version, etc.
> > 
> > Please take a look at tools/perf/util/llvm-utils.c and
> > tools/perf/util/bpf-loader.c. If we could reuse what is there, working
> > out licensing details with Wang, etc, that would be awesome.
> 
> At the moment bpftool does not use LLVM stuff. My opinion is that for
> loading programs, improvements that could benefit to multiple projects
> should probably go to libbpf. For things such as retrieving the kernel
> version, we can maybe do something.

See above about the "llvm" routines, which are there because we need it
to call llvm but are not llvm specific and maybe interesting for other
purposes.
 
> Overall I agree it would be nice to share more code between the two,
> providing licensing allows it. I'm not sure there's much to share about
> BPF itself, but JSON or other FS-related things could maybe be reused.
> I'll try to look at it in more details when I have some time, and keep
> it in mind for future bpftool work. Thanks!

Ok!

- Arnaldo

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH bpf-next 0/8] tools: bpftool: add probes for system and device
  2018-12-14 11:53 ` Quentin Monnet
@ 2018-12-14 18:21   ` Stanislav Fomichev
  2018-12-14 18:41     ` [oss-drivers] " Quentin Monnet
  0 siblings, 1 reply; 41+ messages in thread
From: Stanislav Fomichev @ 2018-12-14 18:21 UTC (permalink / raw)
  To: Quentin Monnet
  Cc: Alexei Starovoitov, Daniel Borkmann, netdev, oss-drivers,
	Arnaldo Carvalho de Melo, Jesper Dangaard Brouer,
	Stanislav Fomichev

On 12/14, Quentin Monnet wrote:
> 2018-12-13 12:19 UTC+0000 ~ Quentin Monnet <quentin.monnet@netronome.com>
> > Hi,
> > This set add a new command to bpftool in order to dump a list of
> > eBPF-related parameters for the system (or for a specific network
> > device) to the console. Once again, this is based on a suggestion from
> > Daniel.
> > 
> > At this time, output includes:
> > 
> 
> So as a reminder this one comes from an actual probe with the syscall...
> 
> >     - Availability of bpf() system call
> 
> ... those 4 are read from procfs...
> 
> >     - Availability of bpf() system call for unprivileged users
> >     - JIT status (enabled or not, with or without debugging traces)
> >     - JIT hardening status
> >     - JIT kallsyms exports status
> 
> ... these are read from /boot/config-$(uname -r)...
> 
> >     - Status of kernel compilation options related to BPF features
> 
> ... this from uname()...
> 
> >     - Release number of the running kernel
> 
> ... and the remaining ones are probed with minimal BPF programs.
> 
> >     - Availability of known eBPF program types
> >     - Availability of known eBPF map types
> >     - Availability of known eBPF helper functions
> 
> As discussed with Stanislav and Daniel, some of the probing should
> probably be moved to libbpf instead for the next version of this set. As
> I see it, I could move probing to libbpf for:
> 
> - BPF prog and map types
> - BPF helper functions
> - bpf() syscall availability
> 
> I do not think kernel compile options, or kernel release number, should
> go to libbpf, they're probably better in bpftool. I'm unsure about the
+1
Kernel + /proc stuff can probably live in bpftool.

> procfs parameters, I'm considering leaving them in bpftool for now. Do
> others have an opinion about this?
Maybe start with adding prog/map/helpers probes to the libbpf
(+ifindex)?

> 
> Quentin

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [oss-drivers] Re: [PATCH bpf-next 0/8] tools: bpftool: add probes for system and device
  2018-12-14 18:21   ` Stanislav Fomichev
@ 2018-12-14 18:41     ` Quentin Monnet
  0 siblings, 0 replies; 41+ messages in thread
From: Quentin Monnet @ 2018-12-14 18:41 UTC (permalink / raw)
  To: Stanislav Fomichev
  Cc: Alexei Starovoitov, Daniel Borkmann, netdev, oss-drivers,
	Arnaldo Carvalho de Melo, Jesper Dangaard Brouer,
	Stanislav Fomichev

2018-12-14 10:21 UTC-0800 ~ Stanislav Fomichev <sdf@fomichev.me>
> On 12/14, Quentin Monnet wrote:
>> 2018-12-13 12:19 UTC+0000 ~ Quentin Monnet <quentin.monnet@netronome.com>
>>> Hi,
>>> This set add a new command to bpftool in order to dump a list of
>>> eBPF-related parameters for the system (or for a specific network
>>> device) to the console. Once again, this is based on a suggestion from
>>> Daniel.
>>>
>>> At this time, output includes:
>>>
>>
>> So as a reminder this one comes from an actual probe with the syscall...
>>
>>>     - Availability of bpf() system call
>>
>> ... those 4 are read from procfs...
>>
>>>     - Availability of bpf() system call for unprivileged users
>>>     - JIT status (enabled or not, with or without debugging traces)
>>>     - JIT hardening status
>>>     - JIT kallsyms exports status
>>
>> ... these are read from /boot/config-$(uname -r)...
>>
>>>     - Status of kernel compilation options related to BPF features
>>
>> ... this from uname()...
>>
>>>     - Release number of the running kernel
>>
>> ... and the remaining ones are probed with minimal BPF programs.
>>
>>>     - Availability of known eBPF program types
>>>     - Availability of known eBPF map types
>>>     - Availability of known eBPF helper functions
>>
>> As discussed with Stanislav and Daniel, some of the probing should
>> probably be moved to libbpf instead for the next version of this set. As
>> I see it, I could move probing to libbpf for:
>>
>> - BPF prog and map types
>> - BPF helper functions
>> - bpf() syscall availability
>>
>> I do not think kernel compile options, or kernel release number, should
>> go to libbpf, they're probably better in bpftool. I'm unsure about the
> +1
> Kernel + /proc stuff can probably live in bpftool.
> 
>> procfs parameters, I'm considering leaving them in bpftool for now. Do
>> others have an opinion about this?
> Maybe start with adding prog/map/helpers probes to the libbpf
> (+ifindex)?

Agree with it, I'll work on a new version for next week. Thanks!

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH bpf-next 1/8] tools: bpftool: add basic probe capability, probe syscall and kversion
  2018-12-14 11:27     ` Quentin Monnet
@ 2018-12-14 18:45       ` Stanislav Fomichev
  2018-12-15  3:31         ` Quentin Monnet
  0 siblings, 1 reply; 41+ messages in thread
From: Stanislav Fomichev @ 2018-12-14 18:45 UTC (permalink / raw)
  To: Quentin Monnet
  Cc: Alexei Starovoitov, Daniel Borkmann, netdev, oss-drivers,
	Arnaldo Carvalho de Melo, Jesper Dangaard Brouer,
	Stanislav Fomichev

On 12/14, Quentin Monnet wrote:
> 2018-12-13 18:50 UTC-0800 ~ Stanislav Fomichev <sdf@fomichev.me>
> > 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@netronome.com>
> >> Reviewed-by: Jakub Kicinski <jakub.kicinski@netronome.com>
> >> ---
> 
> > 
> > [..]
> > 
> >> +		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
> > 
> > ?
> 
> But then if you include this as a header, you have no way to distinguish
> the case when the feature is not supported from when bpftool did not
> attempt to run the probe at all?
How do you expect to exercise that knowledge? Something like the following?

#ifdef FEAT_X
/* we know X is present, use it */
#else
# ifdef NO_FEAT_X
/* we know X is not there, fall back to something else or let the user
 * know we depend on it
 */
# else
/* we don't know whether the feature is there or not,
 * what are we supposed to do?
 *
 * isn't it essentially the same as 'ifdef FEAT_X'?
 * we try to use the feature anyway here, I suppose?
 */
# endif
#endif

My thinking of using that was something like the following (in a simple
autoconf like fashion):
#ifndef FEAT_X
  /* error or fallback to something else */
#endif
/* use feature (or whatever fallback we've set up in the previous ifdef)
 */

My worry is that we just export too much and it's hard to use.

> 
> >> +	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.
> 
> I've been pondering about the interest of keeping human-readable output.
> I think it helps users understand the output, especially for the procfs
> parameters for example.
> 
> As for scripts, they can and should stick to JSON. Plain output from
> bpftool is not meant to be reliable for scripting.
Makes sense, if you think that it provides more info than just rephrased
json field name, then go for it :-)

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH bpf-next 1/8] tools: bpftool: add basic probe capability, probe syscall and kversion
  2018-12-13 12:19 ` [PATCH bpf-next 1/8] tools: bpftool: add basic probe capability, probe syscall and kversion Quentin Monnet
  2018-12-14  2:50   ` Stanislav Fomichev
@ 2018-12-14 23:35   ` Daniel Borkmann
  2018-12-15  3:31     ` Quentin Monnet
  1 sibling, 1 reply; 41+ messages in thread
From: Daniel Borkmann @ 2018-12-14 23:35 UTC (permalink / raw)
  To: Quentin Monnet, Alexei Starovoitov
  Cc: netdev, oss-drivers, Arnaldo Carvalho de Melo,
	Jesper Dangaard Brouer, Stanislav Fomichev

On 12/13/2018 01:19 PM, 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@netronome.com>
> Reviewed-by: Jakub Kicinski <jakub.kicinski@netronome.com>

First of all, thanks a lot for working on this infra!
Few comments below.

[...]
> +/* 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;
> +}

What would be the use-case to try to fetch the kernel version? My main
worry is that this doesn't tell much to the user e.g. in kernels where
features are mainly backported like RHEL. (Is it for the kprobes version
requirement?)

> +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;
> +}

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH bpf-next 2/8] tools: bpftool: add probes for /proc/ eBPF parameters
  2018-12-13 12:19 ` [PATCH bpf-next 2/8] tools: bpftool: add probes for /proc/ eBPF parameters Quentin Monnet
  2018-12-14  2:58   ` Stanislav Fomichev
@ 2018-12-14 23:40   ` Daniel Borkmann
  2018-12-15  3:31     ` Quentin Monnet
  1 sibling, 1 reply; 41+ messages in thread
From: Daniel Borkmann @ 2018-12-14 23:40 UTC (permalink / raw)
  To: Quentin Monnet, Alexei Starovoitov
  Cc: netdev, oss-drivers, Arnaldo Carvalho de Melo,
	Jesper Dangaard Brouer, Stanislav Fomichev

On 12/13/2018 01:19 PM, Quentin Monnet wrote:
> Add a set of probes to dump the eBPF-related parameters available from
> /proc/: availability of bpf() syscall for unprivileged users,
> JIT compiler status and hardening status, kallsyms exports status.
> 
> Sample output:
> 
>     # bpftool feature probe kernel
>     Scanning system configuration...
>     bpf() syscall for unprivileged users is enabled
>     JIT compiler is disabled
>     JIT compiler hardening is disabled
>     JIT compiler kallsyms exports are disabled
>     ...
> 
>     # bpftool --json --pretty feature probe kernel
>     {
>         "system_config": {
>             "unprivileged_bpf_disabled": 0,
>             "bpf_jit_enable": 0,
>             "bpf_jit_harden": 0,
>             "bpf_jit_kallsyms": 0
>         },
>         ...
>     }
> 
>     # bpftool feature probe kernel macros prefix BPFTOOL_
>     #define UNPRIVILEGED_BPF_DISABLED UNPRIVILEGED_BPF_DISABLED_OFF
>     #define  UNPRIVILEGED_BPF_DISABLED_OFF 0
>     #define  UNPRIVILEGED_BPF_DISABLED_ON 1
>     #define  UNPRIVILEGED_BPF_DISABLED_UNKNOWN -1
>     #define JIT_COMPILER_ENABLE JIT_COMPILER_ENABLE_OFF
>     #define  JIT_COMPILER_ENABLE_OFF 0
>     #define  JIT_COMPILER_ENABLE_ON 1
>     #define  JIT_COMPILER_ENABLE_ON_WITH_DEBUG 2
>     #define  JIT_COMPILER_ENABLE_UNKNOWN -1
>     #define JIT_COMPILER_HARDEN JIT_COMPILER_HARDEN_OFF
>     #define  JIT_COMPILER_HARDEN_OFF 0
>     #define  JIT_COMPILER_HARDEN_FOR_UNPRIVILEGED 1
>     #define  JIT_COMPILER_HARDEN_FOR_ALL_USERS 2
>     #define  JIT_COMPILER_HARDEN_UNKNOWN -1
>     #define JIT_COMPILER_KALLSYMS JIT_COMPILER_KALLSYMS_OFF
>     #define  JIT_COMPILER_KALLSYMS_OFF 0
>     #define  JIT_COMPILER_KALLSYMS_FOR_ROOT 1
>     #define  JIT_COMPILER_KALLSYMS_UNKNOWN -1
>     ...

Hm, given these knobs may change at any point in time, what would
be a use case in an application for these if they cannot be relied
upon? (At least the jit_enable and jit_harden are transparent to
the user.)

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH bpf-next 3/8] tools: bpftool: add probes for kernel configuration options
  2018-12-13 12:19 ` [PATCH bpf-next 3/8] tools: bpftool: add probes for kernel configuration options Quentin Monnet
@ 2018-12-14 23:56   ` Daniel Borkmann
  2018-12-15  3:32     ` Quentin Monnet
  0 siblings, 1 reply; 41+ messages in thread
From: Daniel Borkmann @ 2018-12-14 23:56 UTC (permalink / raw)
  To: Quentin Monnet, Alexei Starovoitov
  Cc: netdev, oss-drivers, Arnaldo Carvalho de Melo,
	Jesper Dangaard Brouer, Stanislav Fomichev

On 12/13/2018 01:19 PM, Quentin Monnet wrote:
> Add probes to dump a number of options set (or not set) for compiling
> the kernel image. These parameters provide information about what BPF
> components should be available on the system. A number of them are not
> directly related to eBPF, but are in fact used in the kernel as
> conditions on which to compile, or not to compile, some of the eBPF
> helper functions.
> 
> Sample output:
> 
>     # bpftool feature probe kernel
>     Scanning system configuration...
>     ...
>     CONFIG_BPF is set to y
>     CONFIG_BPF_SYSCALL is set to y
>     CONFIG_HAVE_EBPF_JIT is set to y
>     ...
> 
>     # bpftool --pretty --json feature probe kernel
>     {
>         "system_config": {
>             ...
>             "CONFIG_BPF": "y",
>             "CONFIG_BPF_SYSCALL": "y",
>             "CONFIG_HAVE_EBPF_JIT": "y",
>             ...
>         }
>     }
> 
>     # bpftool feature probe kernel macros prefix BPFTOOL_
>     /*** System configuration ***/
>     ...
>     #define BPFTOOL_CONFIG_BPF y
>     #define BPFTOOL_CONFIG_BPF_SYSCALL y
>     #define BPFTOOL_CONFIG_HAVE_EBPF_JIT y
>     ...

Looks reasonable. I think as a user next question that would
follow-up from it would be whether this set of config means
that e.g. requirements for XDP, cgroups bpf, tracing or xyz is
fulfilled. Perhaps it makes sense to split the options[] into
base_options[], bpf_trace_options[], bpf_tc_options[] etc such
that it might become obvious that base_options[] + bpf_tc_options[]
are supported and thus cls_bpf could be used. I'd see this part
here in general more as giving a hint to the user in that some
basic assumptions could be made and providing some info on the
misc ones on what might potentially be missing. Though more
concrete info would come from the actual helper / map / prog
type probing.

> Signed-off-by: Quentin Monnet <quentin.monnet@netronome.com>
> Reviewed-by: Jakub Kicinski <jakub.kicinski@netronome.com>
> ---
>  tools/bpf/bpftool/feature.c | 144 ++++++++++++++++++++++++++++++++++++
>  1 file changed, 144 insertions(+)
> 
> diff --git a/tools/bpf/bpftool/feature.c b/tools/bpf/bpftool/feature.c
> index 9fa7016c7d21..4a3a45f44162 100644
> --- a/tools/bpf/bpftool/feature.c
> +++ b/tools/bpf/bpftool/feature.c
> @@ -52,6 +52,37 @@ print_bool_feature(const char *feat_name, const char *define_name,
>  		printf("%s is %savailable\n", plain_name, res ? "" : "NOT ");
>  }
>  
> +static void
> +print_kernel_option(const char *name, const char *value,
> +		    const char *define_prefix)
> +{
> +	char *endptr;
> +	int res;
> +
> +	if (json_output) {
> +		if (!value) {
> +			jsonw_null_field(json_wtr, name);
> +			return;
> +		}
> +		errno = 0;
> +		res = strtol(value, &endptr, 0);
> +		if (!errno && *endptr == '\n')
> +			jsonw_int_field(json_wtr, name, res);
> +		else
> +			jsonw_string_field(json_wtr, name, value);
> +	} else if (define_prefix) {
> +		if (value)
> +			printf("#define %s%s %s\n", define_prefix, name, value);
> +		else
> +			printf("#define %sNO_%s\n", define_prefix, name);
> +	} else {
> +		if (value)
> +			printf("%s is set to %s\n", name, value);
> +		else
> +			printf("%s is not set\n", name);
> +	}
> +}
> +
>  static void
>  print_start_section(const char *json_title, const char *define_comment,
>  		    const char *plain_title, const char *define_prefix)
> @@ -298,6 +329,118 @@ static void probe_jit_kallsyms(const char *define_prefix)
>  	}
>  }
>  
> +static char *get_kernel_config_option(FILE *fd, const char *option)
> +{
> +	size_t line_n = 0, optlen = strlen(option);
> +	char *res, *strval, *line = NULL;
> +	ssize_t n;
> +
> +	rewind(fd);
> +	while ((n = getline(&line, &line_n, fd)) > 0) {
> +		if (strncmp(line, option, optlen))
> +			continue;
> +		/* Check we have at least '=', value, and '\n' */
> +		if (strlen(line) < optlen + 3)
> +			continue;
> +		if (*(line + optlen) != '=')
> +			continue;
> +
> +		/* Trim ending '\n' */
> +		line[strlen(line) - 1] = '\0';
> +
> +		/* Copy and return config option value */
> +		strval = line + optlen + 1;
> +		res = strdup(strval);
> +		free(line);
> +		return res;
> +	}
> +	free(line);
> +
> +	return NULL;
> +}
> +
> +static void probe_kernel_image_config(const char *define_prefix)
> +{
> +	const char * const options[] = {
> +		"CONFIG_BPF",
> +		"CONFIG_BPF_SYSCALL",
> +		"CONFIG_HAVE_EBPF_JIT",
> +		"CONFIG_BPF_JIT",
> +		"CONFIG_BPF_JIT_ALWAYS_ON",
> +		"CONFIG_NET",
> +		"CONFIG_XDP_SOCKETS",
> +		"CONFIG_CGROUPS",
> +		"CONFIG_CGROUP_BPF",
> +		"CONFIG_CGROUP_NET_CLASSID",
> +		"CONFIG_BPF_EVENTS",
> +		"CONFIG_LWTUNNEL_BPF",
> +		"CONFIG_NET_ACT_BPF",
> +		"CONFIG_NET_CLS_ACT",
> +		"CONFIG_NET_CLS_BPF",
> +		"CONFIG_NET_SCH_INGRESS",
> +		"CONFIG_XFRM",
> +		"CONFIG_SOCK_CGROUP_DATA",
> +		"CONFIG_IP_ROUTE_CLASSID",
> +		"CONFIG_IPV6_SEG6_BPF",
> +		"CONFIG_FUNCTION_ERROR_INJECTION",
> +		"CONFIG_BPF_KPROBE_OVERRIDE",
> +		"CONFIG_BPF_LIRC_MODE2",
> +		"CONFIG_NETFILTER_XT_MATCH_BPF",
> +		"CONFIG_TEST_BPF",
> +		"CONFIG_BPFILTER",
> +		"CONFIG_BPFILTER_UMH",
> +		"CONFIG_BPF_STREAM_PARSER",
> +	};
> +	char *value, *buf = NULL;
> +	struct utsname utsn;
> +	char path[PATH_MAX];
> +	size_t i, n;
> +	ssize_t ret;
> +	FILE *fd;
> +
> +	if (uname(&utsn))
> +		goto no_config;
> +
> +	snprintf(path, sizeof(path), "/boot/config-%s", utsn.release);
> +
> +	fd = fopen(path, "r");
> +	if (!fd && errno == ENOENT) {
> +		/* Sometimes config is at /proc/config */
> +		fd = fopen("/proc/config", "r");
> +	}
> +	if (!fd) {
> +		p_err("can't open kernel config file: %s", strerror(errno));
> +		goto no_config;
> +	}
> +	/* Sanity checks */
> +	ret = getline(&buf, &n, fd);
> +	ret = getline(&buf, &n, fd);
> +	if (!buf || !ret) {
> +		p_err("can't read from kernel config file: %s",
> +		      strerror(errno));
> +		free(buf);
> +		goto no_config;
> +	}
> +	if (strcmp(buf, "# Automatically generated file; DO NOT EDIT.\n")) {
> +		p_err("can't find correct kernel config file");
> +		free(buf);
> +		goto no_config;
> +	}
> +	free(buf);
> +
> +	for (i = 0; i < ARRAY_SIZE(options); i++) {
> +		value = get_kernel_config_option(fd, options[i]);
> +		print_kernel_option(options[i], value, define_prefix);
> +		free(value);
> +	}
> +	fclose(fd);
> +	return;
> +
> +no_config:
> +	for (i = 0; i < ARRAY_SIZE(options); i++)
> +		print_kernel_option(options[i], NULL, define_prefix);
> +}
> +
>  static int probe_kernel_version(const char *define_prefix)
>  {
>  	int version, subversion, patchlevel, code = 0;
> @@ -402,6 +545,7 @@ static int do_probe(int argc, char **argv)
>  		} else {
>  			p_info("/* procfs not mounted, skipping related probes */");
>  		}
> +		probe_kernel_image_config(define_prefix);
>  		if (json_output)
>  			jsonw_end_object(json_wtr);
>  		else
> 

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH bpf-next 6/8] tools: bpftool: add probes for eBPF helper functions
  2018-12-13 12:19 ` [PATCH bpf-next 6/8] tools: bpftool: add probes for eBPF helper functions Quentin Monnet
@ 2018-12-15  0:08   ` Daniel Borkmann
  2018-12-15  3:32     ` Quentin Monnet
  0 siblings, 1 reply; 41+ messages in thread
From: Daniel Borkmann @ 2018-12-15  0:08 UTC (permalink / raw)
  To: Quentin Monnet, Alexei Starovoitov
  Cc: netdev, oss-drivers, Arnaldo Carvalho de Melo,
	Jesper Dangaard Brouer, Stanislav Fomichev

On 12/13/2018 01:19 PM, Quentin Monnet wrote:
> Similarly to what was done for program types and map types, add a set of
> probes to test the availability of the different eBPF helper functions
> on the current system.
> 
> Sample output:
> 
>     # bpftool feature probe kernel
>     ...
>     Scanning eBPF helper functions...
>     eBPF helper bpf_map_lookup_elem is available
>     eBPF helper bpf_map_update_elem is available
>     eBPF helper bpf_map_delete_elem is available
>     ...
> 
>     # bpftool --json --pretty feature probe kernel
>     {
>         ...
>         "helpers": {
>             "have_bpf_map_lookup_elem_helper": true,
>             "have_bpf_map_update_elem_helper": true,
>             "have_bpf_map_delete_elem_helper": true,
>             ...
>         }
>     }
> 
>     # bpftool feature probe kernel macros prefix BPFTOOL_
>     ...
>     /*** eBPF helper functions ***/
>     #define BPFTOOL_BPF_MAP_LOOKUP_ELEM_HELPER
>     #define BPFTOOL_BPF_MAP_UPDATE_ELEM_HELPER
>     #define BPFTOOL_BPF_MAP_DELETE_ELEM_HELPER

Small nit: instead of BPFTOOL_ prefix, would it make sense
to generally use Have_ prefix (similar to json output). The
former seems somewhat bpftool related though it solely probes
the underlying kernel.

>     ...
> 
> Signed-off-by: Quentin Monnet <quentin.monnet@netronome.com>
> Reviewed-by: Jakub Kicinski <jakub.kicinski@netronome.com>
> ---
>  .../bpftool/Documentation/bpftool-feature.rst |   4 +
>  tools/bpf/bpftool/feature.c                   | 152 ++++++++++++++++++
>  2 files changed, 156 insertions(+)
> 
> diff --git a/tools/bpf/bpftool/Documentation/bpftool-feature.rst b/tools/bpf/bpftool/Documentation/bpftool-feature.rst
> index 23920a7490e9..083d30510cce 100644
> --- a/tools/bpf/bpftool/Documentation/bpftool-feature.rst
> +++ b/tools/bpf/bpftool/Documentation/bpftool-feature.rst
> @@ -39,6 +39,10 @@ DESCRIPTION
>  		  names when including the output of this command as a header
>  		  file.
>  
> +		  Note that when probed, some eBPF helpers (e.g.
> +		  **bpf_trace_printk**\ () or **bpf_probe_write_user**\ ()) may
> +		  print warnings to kernel logs.
> +
>  	**bpftool feature help**
>  		  Print short help message.
>  
> diff --git a/tools/bpf/bpftool/feature.c b/tools/bpf/bpftool/feature.c
> index 85928f172413..77221fff6ba9 100644
> --- a/tools/bpf/bpftool/feature.c
> +++ b/tools/bpf/bpftool/feature.c
> @@ -24,6 +24,113 @@ enum probe_component {
>  	COMPONENT_KERNEL,
>  };
>  
> +#define MAX_HELPER_NAME_LEN 32
> +struct helper_param {
> +	enum bpf_prog_type progtype;
> +	const char name[MAX_HELPER_NAME_LEN];
> +};
> +
> +/* helper_progtype_and_name[index] associates to the BPF helper function of id
> + * "index" a name and a program type to run this helper with. In order to probe
> + * helper availability for programs offloaded to a network device, use
> + * offload-compatible types (e.g. XDP) everywhere we can. Caveats: helper
> + * probing may fail currently if only TC (but not XDP) is supported for
> + * offload.
> + */
> +static const struct helper_param helper_progtype_and_name[] = {
> +	{ BPF_PROG_TYPE_XDP,		"no_helper_with_id_0" },
> +	{ BPF_PROG_TYPE_XDP,		"bpf_map_lookup_elem" },
> +	{ BPF_PROG_TYPE_XDP,		"bpf_map_update_elem" },
> +	{ BPF_PROG_TYPE_XDP,		"bpf_map_delete_elem" },
> +	{ BPF_PROG_TYPE_KPROBE,		"bpf_probe_read" },
> +	{ BPF_PROG_TYPE_XDP,		"bpf_ktime_get_ns" },
> +	{ BPF_PROG_TYPE_XDP,		"bpf_trace_printk" },
> +	{ BPF_PROG_TYPE_XDP,		"bpf_get_prandom_u32" },
> +	{ BPF_PROG_TYPE_XDP,		"bpf_get_smp_processor_id" },
> +	{ BPF_PROG_TYPE_SCHED_CLS,	"bpf_skb_store_bytes" },
> +	{ BPF_PROG_TYPE_SCHED_CLS,	"bpf_l3_csum_replace" },
> +	{ BPF_PROG_TYPE_SCHED_CLS,	"bpf_l4_csum_replace" },
> +	{ BPF_PROG_TYPE_XDP,		"bpf_tail_call" },
> +	{ BPF_PROG_TYPE_SCHED_CLS,	"bpf_clone_redirect" },
> +	{ BPF_PROG_TYPE_KPROBE,		"bpf_get_current_pid_tgid" },
> +	{ BPF_PROG_TYPE_KPROBE,		"bpf_get_current_uid_gid" },
> +	{ BPF_PROG_TYPE_KPROBE,		"bpf_get_current_comm" },
> +	{ BPF_PROG_TYPE_SCHED_CLS,	"bpf_get_cgroup_classid" },
> +	{ BPF_PROG_TYPE_SCHED_CLS,	"bpf_skb_vlan_push" },
> +	{ BPF_PROG_TYPE_SCHED_CLS,	"bpf_skb_vlan_pop" },
> +	{ BPF_PROG_TYPE_SCHED_CLS,	"bpf_skb_get_tunnel_key" },
> +	{ BPF_PROG_TYPE_SCHED_CLS,	"bpf_skb_set_tunnel_key" },
> +	{ BPF_PROG_TYPE_KPROBE,		"bpf_perf_event_read" },
> +	{ BPF_PROG_TYPE_XDP,		"bpf_redirect" },
> +	{ BPF_PROG_TYPE_SCHED_CLS,	"bpf_get_route_realm" },
> +	{ BPF_PROG_TYPE_XDP,		"bpf_perf_event_output" },
> +	{ BPF_PROG_TYPE_SCHED_CLS,	"bpf_skb_load_bytes" },
> +	{ BPF_PROG_TYPE_KPROBE,		"bpf_get_stackid" },
> +	{ BPF_PROG_TYPE_XDP,		"bpf_csum_diff" },
> +	{ BPF_PROG_TYPE_SCHED_CLS,	"bpf_skb_get_tunnel_opt" },
> +	{ BPF_PROG_TYPE_SCHED_CLS,	"bpf_skb_set_tunnel_opt" },
> +	{ BPF_PROG_TYPE_SCHED_CLS,	"bpf_skb_change_proto" },
> +	{ BPF_PROG_TYPE_SCHED_CLS,	"bpf_skb_change_type" },
> +	{ BPF_PROG_TYPE_SCHED_CLS,	"bpf_skb_under_cgroup" },
> +	{ BPF_PROG_TYPE_SCHED_CLS,	"bpf_get_hash_recalc" },
> +	{ BPF_PROG_TYPE_KPROBE,		"bpf_get_current_task" },
> +	{ BPF_PROG_TYPE_KPROBE,		"bpf_probe_write_user" },
> +	{ BPF_PROG_TYPE_KPROBE,		"bpf_current_task_under_cgroup" },
> +	{ BPF_PROG_TYPE_SCHED_CLS,	"bpf_skb_change_tail" },
> +	{ BPF_PROG_TYPE_SCHED_CLS,	"bpf_skb_pull_data" },
> +	{ BPF_PROG_TYPE_SCHED_CLS,	"bpf_csum_update" },
> +	{ BPF_PROG_TYPE_SCHED_CLS,	"bpf_set_hash_invalid" },
> +	{ BPF_PROG_TYPE_XDP,		"bpf_get_numa_node_id" },
> +	{ BPF_PROG_TYPE_SK_SKB,		"bpf_skb_change_head" },
> +	{ BPF_PROG_TYPE_XDP,		"bpf_xdp_adjust_head" },
> +	{ BPF_PROG_TYPE_KPROBE,		"bpf_probe_read_str" },
> +	{ BPF_PROG_TYPE_SCHED_CLS,	"bpf_get_socket_cookie" },
> +	{ BPF_PROG_TYPE_SCHED_CLS,	"bpf_get_socket_uid" },
> +	{ BPF_PROG_TYPE_SCHED_CLS,	"bpf_set_hash" },
> +	{ BPF_PROG_TYPE_SOCK_OPS,	"bpf_setsockopt" },
> +	{ BPF_PROG_TYPE_SCHED_CLS,	"bpf_skb_adjust_room" },
> +	{ BPF_PROG_TYPE_XDP,		"bpf_redirect_map" },
> +	{ BPF_PROG_TYPE_SK_SKB,		"bpf_sk_redirect_map" },
> +	{ BPF_PROG_TYPE_SOCK_OPS,	"bpf_sock_map_update" },
> +	{ BPF_PROG_TYPE_XDP,		"bpf_xdp_adjust_meta" },
> +	{ BPF_PROG_TYPE_KPROBE,		"bpf_perf_event_read_value" },
> +	{ BPF_PROG_TYPE_PERF_EVENT,	"bpf_perf_prog_read_value" },
> +	{ BPF_PROG_TYPE_SOCK_OPS,	"bpf_getsockopt" },
> +	{ BPF_PROG_TYPE_KPROBE,		"bpf_override_return" },
> +	{ BPF_PROG_TYPE_SOCK_OPS,	"bpf_sock_ops_cb_flags_set" },
> +	{ BPF_PROG_TYPE_SK_MSG,		"bpf_msg_redirect_map" },
> +	{ BPF_PROG_TYPE_SK_MSG,		"bpf_msg_apply_bytes" },
> +	{ BPF_PROG_TYPE_SK_MSG,		"bpf_msg_cork_bytes" },
> +	{ BPF_PROG_TYPE_SK_MSG,		"bpf_msg_pull_data" },
> +	{ BPF_PROG_TYPE_CGROUP_SOCK_ADDR,	"bpf_bind" },
> +	{ BPF_PROG_TYPE_XDP,		"bpf_xdp_adjust_tail" },
> +	{ BPF_PROG_TYPE_SCHED_CLS,	"bpf_skb_get_xfrm_state" },
> +	{ BPF_PROG_TYPE_KPROBE,		"bpf_get_stack" },
> +	{ BPF_PROG_TYPE_SCHED_CLS,	"bpf_skb_load_bytes_relative" },
> +	{ BPF_PROG_TYPE_SCHED_CLS,	"bpf_fib_lookup" },
> +	{ BPF_PROG_TYPE_SOCK_OPS,	"bpf_sock_hash_update" },
> +	{ BPF_PROG_TYPE_SK_MSG,		"bpf_msg_redirect_hash" },
> +	{ BPF_PROG_TYPE_SK_SKB,		"bpf_sk_redirect_hash" },
> +	{ BPF_PROG_TYPE_LWT_IN,		"bpf_lwt_push_encap" },
> +	{ BPF_PROG_TYPE_LWT_SEG6LOCAL,	"bpf_lwt_seg6_store_bytes" },
> +	{ BPF_PROG_TYPE_LWT_SEG6LOCAL,	"bpf_lwt_seg6_adjust_srh" },
> +	{ BPF_PROG_TYPE_LWT_SEG6LOCAL,	"bpf_lwt_seg6_action" },
> +	{ BPF_PROG_TYPE_LIRC_MODE2,	"bpf_rc_repeat" },
> +	{ BPF_PROG_TYPE_LIRC_MODE2,	"bpf_rc_keydown" },
> +	{ BPF_PROG_TYPE_SCHED_CLS,	"bpf_skb_cgroup_id" },
> +	{ BPF_PROG_TYPE_KPROBE,		"bpf_get_current_cgroup_id" },
> +	{ BPF_PROG_TYPE_CGROUP_SKB,	"bpf_get_local_storage" },
> +	{ BPF_PROG_TYPE_SK_REUSEPORT,	"bpf_sk_select_reuseport" },
> +	{ BPF_PROG_TYPE_SCHED_CLS,	"bpf_skb_ancestor_cgroup_id" },
> +	{ BPF_PROG_TYPE_SK_SKB,		"bpf_sk_lookup_tcp" },
> +	{ BPF_PROG_TYPE_SK_SKB,		"bpf_sk_lookup_udp" },
> +	{ BPF_PROG_TYPE_SK_SKB,		"bpf_sk_release" },
> +	{ BPF_PROG_TYPE_XDP,		"bpf_map_push_elem" },
> +	{ BPF_PROG_TYPE_XDP,		"bpf_map_pop_elem" },
> +	{ BPF_PROG_TYPE_XDP,		"bpf_map_peek_elem" },
> +	{ BPF_PROG_TYPE_SK_MSG,		"bpf_msg_push_data" },

Some of these helpers like bpf_perf_event_output are available on
multiple types; should they all be tested in case the one probed
prog type would not be available on the underlying kernel?

Thanks,
Daniel

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH bpf-next 1/8] tools: bpftool: add basic probe capability, probe syscall and kversion
  2018-12-14 18:45       ` Stanislav Fomichev
@ 2018-12-15  3:31         ` Quentin Monnet
  0 siblings, 0 replies; 41+ messages in thread
From: Quentin Monnet @ 2018-12-15  3:31 UTC (permalink / raw)
  To: Stanislav Fomichev
  Cc: Alexei Starovoitov, Daniel Borkmann, netdev, oss-drivers,
	Arnaldo Carvalho de Melo, Jesper Dangaard Brouer,
	Stanislav Fomichev

2018-12-14 10:45 UTC-0800 ~ Stanislav Fomichev <sdf@fomichev.me>
> On 12/14, Quentin Monnet wrote:
>> 2018-12-13 18:50 UTC-0800 ~ Stanislav Fomichev <sdf@fomichev.me>
>>> 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@netronome.com>
>>>> Reviewed-by: Jakub Kicinski <jakub.kicinski@netronome.com>
>>>> ---
>>
>>>
>>> [..]
>>>
>>>> +		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
>>>
>>> ?
>>
>> But then if you include this as a header, you have no way to distinguish
>> the case when the feature is not supported from when bpftool did not
>> attempt to run the probe at all?
> How do you expect to exercise that knowledge? Something like the following?
> 
> #ifdef FEAT_X
> /* we know X is present, use it */
> #else
> # ifdef NO_FEAT_X
> /* we know X is not there, fall back to something else or let the user
>  * know we depend on it
>  */
> # else
> /* we don't know whether the feature is there or not,
>  * what are we supposed to do?
>  *
>  * isn't it essentially the same as 'ifdef FEAT_X'?
>  * we try to use the feature anyway here, I suppose?
>  */
> # endif
> #endif
> 
> My thinking of using that was something like the following (in a simple
> autoconf like fashion):
> #ifndef FEAT_X
>   /* error or fallback to something else */
> #endif
> /* use feature (or whatever fallback we've set up in the previous ifdef)
>  */

But then with autoconf you're supposed to probe everything that you need
to know to compile your program, right? I don't believe there would be a
case where some random features are not tested at all by the script...

In your above example, the "#ifndef FEAT_X /* error */ #endif", you do
return an error if the feature has not been probed instead of trying
anyway to see if it's there, as you mentioned above that... Did I miss
something? Did you mean something like "#ifdef FEAT_NO_X /* error */
#endif"? I believe the fact we reliably found that the feature is not
present _is_ an important information.

> 
> My worry is that we just export too much and it's hard to use.

I understand and I'm not opposed to changing my output. I'd like to
avoid loosing information (and keep the same amount of info in JSON and
#define outputs).

> 
>>
>>>> +	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.
>>
>> I've been pondering about the interest of keeping human-readable output.
>> I think it helps users understand the output, especially for the procfs
>> parameters for example.
>>
>> As for scripts, they can and should stick to JSON. Plain output from
>> bpftool is not meant to be reliable for scripting.
> Makes sense, if you think that it provides more info than just rephrased
> json field name, then go for it :-)

Currently, a bit more descriptive info for the procfs parameters. And
the kernel version is in human-readable form (ok we don't care much).
But it's true it does not bring much. Mostly I thought of it as a nicer
output for someone who wants to probe the system just to have a quick
look at what's supported, it feels easier to interpret than JSON or
#defines.

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH bpf-next 1/8] tools: bpftool: add basic probe capability, probe syscall and kversion
  2018-12-14 23:35   ` Daniel Borkmann
@ 2018-12-15  3:31     ` Quentin Monnet
  0 siblings, 0 replies; 41+ messages in thread
From: Quentin Monnet @ 2018-12-15  3:31 UTC (permalink / raw)
  To: Daniel Borkmann, Alexei Starovoitov
  Cc: netdev, oss-drivers, Arnaldo Carvalho de Melo,
	Jesper Dangaard Brouer, Stanislav Fomichev

2018-12-15 00:35 UTC+0100 ~ Daniel Borkmann <daniel@iogearbox.net>
> On 12/13/2018 01:19 PM, 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@netronome.com>
>> Reviewed-by: Jakub Kicinski <jakub.kicinski@netronome.com>
> 
> First of all, thanks a lot for working on this infra!
> Few comments below.
> 
> [...]
>> +/* 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;
>> +}
> 
> What would be the use-case to try to fetch the kernel version? My main
> worry is that this doesn't tell much to the user e.g. in kernels where
> features are mainly backported like RHEL. (Is it for the kprobes version
> requirement?)

Yes, I retrieved the kernel version number for testing the kprobes. And
since I had it, I thought I could as well present it to the user. It's
not supposed to tell what features are supported exactly, but I was
thinking that depending on the context, it can help debug things.

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH bpf-next 2/8] tools: bpftool: add probes for /proc/ eBPF parameters
  2018-12-14 23:40   ` Daniel Borkmann
@ 2018-12-15  3:31     ` Quentin Monnet
  2018-12-16  0:14       ` Daniel Borkmann
  0 siblings, 1 reply; 41+ messages in thread
From: Quentin Monnet @ 2018-12-15  3:31 UTC (permalink / raw)
  To: Daniel Borkmann, Alexei Starovoitov
  Cc: netdev, oss-drivers, Arnaldo Carvalho de Melo,
	Jesper Dangaard Brouer, Stanislav Fomichev

2018-12-15 00:40 UTC+0100 ~ Daniel Borkmann <daniel@iogearbox.net>
> On 12/13/2018 01:19 PM, Quentin Monnet wrote:
>> Add a set of probes to dump the eBPF-related parameters available from
>> /proc/: availability of bpf() syscall for unprivileged users,
>> JIT compiler status and hardening status, kallsyms exports status.
>>
>> Sample output:
>>
>>     # bpftool feature probe kernel
>>     Scanning system configuration...
>>     bpf() syscall for unprivileged users is enabled
>>     JIT compiler is disabled
>>     JIT compiler hardening is disabled
>>     JIT compiler kallsyms exports are disabled
>>     ...
>>
>>     # bpftool --json --pretty feature probe kernel
>>     {
>>         "system_config": {
>>             "unprivileged_bpf_disabled": 0,
>>             "bpf_jit_enable": 0,
>>             "bpf_jit_harden": 0,
>>             "bpf_jit_kallsyms": 0
>>         },
>>         ...
>>     }
>>
>>     # bpftool feature probe kernel macros prefix BPFTOOL_
>>     #define UNPRIVILEGED_BPF_DISABLED UNPRIVILEGED_BPF_DISABLED_OFF
>>     #define  UNPRIVILEGED_BPF_DISABLED_OFF 0
>>     #define  UNPRIVILEGED_BPF_DISABLED_ON 1
>>     #define  UNPRIVILEGED_BPF_DISABLED_UNKNOWN -1
>>     #define JIT_COMPILER_ENABLE JIT_COMPILER_ENABLE_OFF
>>     #define  JIT_COMPILER_ENABLE_OFF 0
>>     #define  JIT_COMPILER_ENABLE_ON 1
>>     #define  JIT_COMPILER_ENABLE_ON_WITH_DEBUG 2
>>     #define  JIT_COMPILER_ENABLE_UNKNOWN -1
>>     #define JIT_COMPILER_HARDEN JIT_COMPILER_HARDEN_OFF
>>     #define  JIT_COMPILER_HARDEN_OFF 0
>>     #define  JIT_COMPILER_HARDEN_FOR_UNPRIVILEGED 1
>>     #define  JIT_COMPILER_HARDEN_FOR_ALL_USERS 2
>>     #define  JIT_COMPILER_HARDEN_UNKNOWN -1
>>     #define JIT_COMPILER_KALLSYMS JIT_COMPILER_KALLSYMS_OFF
>>     #define  JIT_COMPILER_KALLSYMS_OFF 0
>>     #define  JIT_COMPILER_KALLSYMS_FOR_ROOT 1
>>     #define  JIT_COMPILER_KALLSYMS_UNKNOWN -1
>>     ...
> 
> Hm, given these knobs may change at any point in time, what would
> be a use case in an application for these if they cannot be relied
> upon? (At least the jit_enable and jit_harden are transparent to
> the user.)
> 

Granted, for those parameters it's a snapshot of the system at the time
the probes are run. It can be useful, I suppose, if a server is not
expected to change them often... And the plain output might be useful to
a sysadmin who wants to have a quick look at BPF-related parameters, maybe?

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH bpf-next 3/8] tools: bpftool: add probes for kernel configuration options
  2018-12-14 23:56   ` Daniel Borkmann
@ 2018-12-15  3:32     ` Quentin Monnet
  2018-12-19 18:49       ` Quentin Monnet
  0 siblings, 1 reply; 41+ messages in thread
From: Quentin Monnet @ 2018-12-15  3:32 UTC (permalink / raw)
  To: Daniel Borkmann, Alexei Starovoitov
  Cc: netdev, oss-drivers, Arnaldo Carvalho de Melo,
	Jesper Dangaard Brouer, Stanislav Fomichev

2018-12-15 00:56 UTC+0100 ~ Daniel Borkmann <daniel@iogearbox.net>
> On 12/13/2018 01:19 PM, Quentin Monnet wrote:
>> Add probes to dump a number of options set (or not set) for compiling
>> the kernel image. These parameters provide information about what BPF
>> components should be available on the system. A number of them are not
>> directly related to eBPF, but are in fact used in the kernel as
>> conditions on which to compile, or not to compile, some of the eBPF
>> helper functions.
>>
>> Sample output:
>>
>>     # bpftool feature probe kernel
>>     Scanning system configuration...
>>     ...
>>     CONFIG_BPF is set to y
>>     CONFIG_BPF_SYSCALL is set to y
>>     CONFIG_HAVE_EBPF_JIT is set to y
>>     ...
>>
>>     # bpftool --pretty --json feature probe kernel
>>     {
>>         "system_config": {
>>             ...
>>             "CONFIG_BPF": "y",
>>             "CONFIG_BPF_SYSCALL": "y",
>>             "CONFIG_HAVE_EBPF_JIT": "y",
>>             ...
>>         }
>>     }
>>
>>     # bpftool feature probe kernel macros prefix BPFTOOL_
>>     /*** System configuration ***/
>>     ...
>>     #define BPFTOOL_CONFIG_BPF y
>>     #define BPFTOOL_CONFIG_BPF_SYSCALL y
>>     #define BPFTOOL_CONFIG_HAVE_EBPF_JIT y
>>     ...
> 
> Looks reasonable. I think as a user next question that would
> follow-up from it would be whether this set of config means
> that e.g. requirements for XDP, cgroups bpf, tracing or xyz is
> fulfilled. Perhaps it makes sense to split the options[] into
> base_options[], bpf_trace_options[], bpf_tc_options[] etc such
> that it might become obvious that base_options[] + bpf_tc_options[]
> are supported and thus cls_bpf could be used. I'd see this part
> here in general more as giving a hint to the user in that some
> basic assumptions could be made and providing some info on the
> misc ones on what might potentially be missing. Though more
> concrete info would come from the actual helper / map / prog
> type probing.

Good idea. I admit that the list of options dumped with no explanations
whatsoever is hard to interpret. I'll try to divide the list into
meaningful subsections.

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH bpf-next 6/8] tools: bpftool: add probes for eBPF helper functions
  2018-12-15  0:08   ` Daniel Borkmann
@ 2018-12-15  3:32     ` Quentin Monnet
  2018-12-15 23:57       ` Daniel Borkmann
  0 siblings, 1 reply; 41+ messages in thread
From: Quentin Monnet @ 2018-12-15  3:32 UTC (permalink / raw)
  To: Daniel Borkmann, Alexei Starovoitov
  Cc: netdev, oss-drivers, Arnaldo Carvalho de Melo,
	Jesper Dangaard Brouer, Stanislav Fomichev

2018-12-15 01:08 UTC+0100 ~ Daniel Borkmann <daniel@iogearbox.net>
> On 12/13/2018 01:19 PM, Quentin Monnet wrote:
>> Similarly to what was done for program types and map types, add a set of
>> probes to test the availability of the different eBPF helper functions
>> on the current system.
>>
>> Sample output:
>>
>>     # bpftool feature probe kernel
>>     ...
>>     Scanning eBPF helper functions...
>>     eBPF helper bpf_map_lookup_elem is available
>>     eBPF helper bpf_map_update_elem is available
>>     eBPF helper bpf_map_delete_elem is available
>>     ...
>>
>>     # bpftool --json --pretty feature probe kernel
>>     {
>>         ...
>>         "helpers": {
>>             "have_bpf_map_lookup_elem_helper": true,
>>             "have_bpf_map_update_elem_helper": true,
>>             "have_bpf_map_delete_elem_helper": true,
>>             ...
>>         }
>>     }
>>
>>     # bpftool feature probe kernel macros prefix BPFTOOL_
>>     ...
>>     /*** eBPF helper functions ***/
>>     #define BPFTOOL_BPF_MAP_LOOKUP_ELEM_HELPER
>>     #define BPFTOOL_BPF_MAP_UPDATE_ELEM_HELPER
>>     #define BPFTOOL_BPF_MAP_DELETE_ELEM_HELPER
> 
> Small nit: instead of BPFTOOL_ prefix, would it make sense
> to generally use Have_ prefix (similar to json output). The
> former seems somewhat bpftool related though it solely probes
> the underlying kernel.

"BPFTOOL_" is provided on the command line ("prefix BPFTOOL_"), and it's
here just for the example. I initially had a non-configurable "HAVE_"
prefix instead, but after discussing it with Jakub we thought it best to
leave the choice of the prefix to the users, so they can choose what
works best for them, or adapt it and avoid any potential name conflict.

>>     ...
>>
>> Signed-off-by: Quentin Monnet <quentin.monnet@netronome.com>
>> Reviewed-by: Jakub Kicinski <jakub.kicinski@netronome.com>
>> ---
>>  .../bpftool/Documentation/bpftool-feature.rst |   4 +
>>  tools/bpf/bpftool/feature.c                   | 152 ++++++++++++++++++
>>  2 files changed, 156 insertions(+)
>>
>> diff --git a/tools/bpf/bpftool/Documentation/bpftool-feature.rst b/tools/bpf/bpftool/Documentation/bpftool-feature.rst
>> index 23920a7490e9..083d30510cce 100644
>> --- a/tools/bpf/bpftool/Documentation/bpftool-feature.rst
>> +++ b/tools/bpf/bpftool/Documentation/bpftool-feature.rst
>> @@ -39,6 +39,10 @@ DESCRIPTION
>>  		  names when including the output of this command as a header
>>  		  file.
>>  
>> +		  Note that when probed, some eBPF helpers (e.g.
>> +		  **bpf_trace_printk**\ () or **bpf_probe_write_user**\ ()) may
>> +		  print warnings to kernel logs.
>> +
>>  	**bpftool feature help**
>>  		  Print short help message.
>>  
>> diff --git a/tools/bpf/bpftool/feature.c b/tools/bpf/bpftool/feature.c
>> index 85928f172413..77221fff6ba9 100644
>> --- a/tools/bpf/bpftool/feature.c
>> +++ b/tools/bpf/bpftool/feature.c
>> @@ -24,6 +24,113 @@ enum probe_component {
>>  	COMPONENT_KERNEL,
>>  };
>>  
>> +#define MAX_HELPER_NAME_LEN 32
>> +struct helper_param {
>> +	enum bpf_prog_type progtype;
>> +	const char name[MAX_HELPER_NAME_LEN];
>> +};
>> +
>> +/* helper_progtype_and_name[index] associates to the BPF helper function of id
>> + * "index" a name and a program type to run this helper with. In order to probe
>> + * helper availability for programs offloaded to a network device, use
>> + * offload-compatible types (e.g. XDP) everywhere we can. Caveats: helper
>> + * probing may fail currently if only TC (but not XDP) is supported for
>> + * offload.
>> + */
>> +static const struct helper_param helper_progtype_and_name[] = {
>> +	{ BPF_PROG_TYPE_XDP,		"no_helper_with_id_0" },
>> +	{ BPF_PROG_TYPE_XDP,		"bpf_map_lookup_elem" },
>> +	{ BPF_PROG_TYPE_XDP,		"bpf_map_update_elem" },
>> +	{ BPF_PROG_TYPE_XDP,		"bpf_map_delete_elem" },
>> +	{ BPF_PROG_TYPE_KPROBE,		"bpf_probe_read" },
>> +	{ BPF_PROG_TYPE_XDP,		"bpf_ktime_get_ns" },
>> +	{ BPF_PROG_TYPE_XDP,		"bpf_trace_printk" },
>> +	{ BPF_PROG_TYPE_XDP,		"bpf_get_prandom_u32" },
>> +	{ BPF_PROG_TYPE_XDP,		"bpf_get_smp_processor_id" },
>> +	{ BPF_PROG_TYPE_SCHED_CLS,	"bpf_skb_store_bytes" },
>> +	{ BPF_PROG_TYPE_SCHED_CLS,	"bpf_l3_csum_replace" },
>> +	{ BPF_PROG_TYPE_SCHED_CLS,	"bpf_l4_csum_replace" },
>> +	{ BPF_PROG_TYPE_XDP,		"bpf_tail_call" },
>> +	{ BPF_PROG_TYPE_SCHED_CLS,	"bpf_clone_redirect" },
>> +	{ BPF_PROG_TYPE_KPROBE,		"bpf_get_current_pid_tgid" },
>> +	{ BPF_PROG_TYPE_KPROBE,		"bpf_get_current_uid_gid" },
>> +	{ BPF_PROG_TYPE_KPROBE,		"bpf_get_current_comm" },
>> +	{ BPF_PROG_TYPE_SCHED_CLS,	"bpf_get_cgroup_classid" },
>> +	{ BPF_PROG_TYPE_SCHED_CLS,	"bpf_skb_vlan_push" },
>> +	{ BPF_PROG_TYPE_SCHED_CLS,	"bpf_skb_vlan_pop" },
>> +	{ BPF_PROG_TYPE_SCHED_CLS,	"bpf_skb_get_tunnel_key" },
>> +	{ BPF_PROG_TYPE_SCHED_CLS,	"bpf_skb_set_tunnel_key" },
>> +	{ BPF_PROG_TYPE_KPROBE,		"bpf_perf_event_read" },
>> +	{ BPF_PROG_TYPE_XDP,		"bpf_redirect" },
>> +	{ BPF_PROG_TYPE_SCHED_CLS,	"bpf_get_route_realm" },
>> +	{ BPF_PROG_TYPE_XDP,		"bpf_perf_event_output" },
>> +	{ BPF_PROG_TYPE_SCHED_CLS,	"bpf_skb_load_bytes" },
>> +	{ BPF_PROG_TYPE_KPROBE,		"bpf_get_stackid" },
>> +	{ BPF_PROG_TYPE_XDP,		"bpf_csum_diff" },
>> +	{ BPF_PROG_TYPE_SCHED_CLS,	"bpf_skb_get_tunnel_opt" },
>> +	{ BPF_PROG_TYPE_SCHED_CLS,	"bpf_skb_set_tunnel_opt" },
>> +	{ BPF_PROG_TYPE_SCHED_CLS,	"bpf_skb_change_proto" },
>> +	{ BPF_PROG_TYPE_SCHED_CLS,	"bpf_skb_change_type" },
>> +	{ BPF_PROG_TYPE_SCHED_CLS,	"bpf_skb_under_cgroup" },
>> +	{ BPF_PROG_TYPE_SCHED_CLS,	"bpf_get_hash_recalc" },
>> +	{ BPF_PROG_TYPE_KPROBE,		"bpf_get_current_task" },
>> +	{ BPF_PROG_TYPE_KPROBE,		"bpf_probe_write_user" },
>> +	{ BPF_PROG_TYPE_KPROBE,		"bpf_current_task_under_cgroup" },
>> +	{ BPF_PROG_TYPE_SCHED_CLS,	"bpf_skb_change_tail" },
>> +	{ BPF_PROG_TYPE_SCHED_CLS,	"bpf_skb_pull_data" },
>> +	{ BPF_PROG_TYPE_SCHED_CLS,	"bpf_csum_update" },
>> +	{ BPF_PROG_TYPE_SCHED_CLS,	"bpf_set_hash_invalid" },
>> +	{ BPF_PROG_TYPE_XDP,		"bpf_get_numa_node_id" },
>> +	{ BPF_PROG_TYPE_SK_SKB,		"bpf_skb_change_head" },
>> +	{ BPF_PROG_TYPE_XDP,		"bpf_xdp_adjust_head" },
>> +	{ BPF_PROG_TYPE_KPROBE,		"bpf_probe_read_str" },
>> +	{ BPF_PROG_TYPE_SCHED_CLS,	"bpf_get_socket_cookie" },
>> +	{ BPF_PROG_TYPE_SCHED_CLS,	"bpf_get_socket_uid" },
>> +	{ BPF_PROG_TYPE_SCHED_CLS,	"bpf_set_hash" },
>> +	{ BPF_PROG_TYPE_SOCK_OPS,	"bpf_setsockopt" },
>> +	{ BPF_PROG_TYPE_SCHED_CLS,	"bpf_skb_adjust_room" },
>> +	{ BPF_PROG_TYPE_XDP,		"bpf_redirect_map" },
>> +	{ BPF_PROG_TYPE_SK_SKB,		"bpf_sk_redirect_map" },
>> +	{ BPF_PROG_TYPE_SOCK_OPS,	"bpf_sock_map_update" },
>> +	{ BPF_PROG_TYPE_XDP,		"bpf_xdp_adjust_meta" },
>> +	{ BPF_PROG_TYPE_KPROBE,		"bpf_perf_event_read_value" },
>> +	{ BPF_PROG_TYPE_PERF_EVENT,	"bpf_perf_prog_read_value" },
>> +	{ BPF_PROG_TYPE_SOCK_OPS,	"bpf_getsockopt" },
>> +	{ BPF_PROG_TYPE_KPROBE,		"bpf_override_return" },
>> +	{ BPF_PROG_TYPE_SOCK_OPS,	"bpf_sock_ops_cb_flags_set" },
>> +	{ BPF_PROG_TYPE_SK_MSG,		"bpf_msg_redirect_map" },
>> +	{ BPF_PROG_TYPE_SK_MSG,		"bpf_msg_apply_bytes" },
>> +	{ BPF_PROG_TYPE_SK_MSG,		"bpf_msg_cork_bytes" },
>> +	{ BPF_PROG_TYPE_SK_MSG,		"bpf_msg_pull_data" },
>> +	{ BPF_PROG_TYPE_CGROUP_SOCK_ADDR,	"bpf_bind" },
>> +	{ BPF_PROG_TYPE_XDP,		"bpf_xdp_adjust_tail" },
>> +	{ BPF_PROG_TYPE_SCHED_CLS,	"bpf_skb_get_xfrm_state" },
>> +	{ BPF_PROG_TYPE_KPROBE,		"bpf_get_stack" },
>> +	{ BPF_PROG_TYPE_SCHED_CLS,	"bpf_skb_load_bytes_relative" },
>> +	{ BPF_PROG_TYPE_SCHED_CLS,	"bpf_fib_lookup" },
>> +	{ BPF_PROG_TYPE_SOCK_OPS,	"bpf_sock_hash_update" },
>> +	{ BPF_PROG_TYPE_SK_MSG,		"bpf_msg_redirect_hash" },
>> +	{ BPF_PROG_TYPE_SK_SKB,		"bpf_sk_redirect_hash" },
>> +	{ BPF_PROG_TYPE_LWT_IN,		"bpf_lwt_push_encap" },
>> +	{ BPF_PROG_TYPE_LWT_SEG6LOCAL,	"bpf_lwt_seg6_store_bytes" },
>> +	{ BPF_PROG_TYPE_LWT_SEG6LOCAL,	"bpf_lwt_seg6_adjust_srh" },
>> +	{ BPF_PROG_TYPE_LWT_SEG6LOCAL,	"bpf_lwt_seg6_action" },
>> +	{ BPF_PROG_TYPE_LIRC_MODE2,	"bpf_rc_repeat" },
>> +	{ BPF_PROG_TYPE_LIRC_MODE2,	"bpf_rc_keydown" },
>> +	{ BPF_PROG_TYPE_SCHED_CLS,	"bpf_skb_cgroup_id" },
>> +	{ BPF_PROG_TYPE_KPROBE,		"bpf_get_current_cgroup_id" },
>> +	{ BPF_PROG_TYPE_CGROUP_SKB,	"bpf_get_local_storage" },
>> +	{ BPF_PROG_TYPE_SK_REUSEPORT,	"bpf_sk_select_reuseport" },
>> +	{ BPF_PROG_TYPE_SCHED_CLS,	"bpf_skb_ancestor_cgroup_id" },
>> +	{ BPF_PROG_TYPE_SK_SKB,		"bpf_sk_lookup_tcp" },
>> +	{ BPF_PROG_TYPE_SK_SKB,		"bpf_sk_lookup_udp" },
>> +	{ BPF_PROG_TYPE_SK_SKB,		"bpf_sk_release" },
>> +	{ BPF_PROG_TYPE_XDP,		"bpf_map_push_elem" },
>> +	{ BPF_PROG_TYPE_XDP,		"bpf_map_pop_elem" },
>> +	{ BPF_PROG_TYPE_XDP,		"bpf_map_peek_elem" },
>> +	{ BPF_PROG_TYPE_SK_MSG,		"bpf_msg_push_data" },
> 
> Some of these helpers like bpf_perf_event_output are available on
> multiple types; should they all be tested in case the one probed
> prog type would not be available on the underlying kernel?
> 
> Thanks,
> Daniel

That's a good point, but it will make things more complicated. We would
need a list of compatible program types for each helper, and then try
them all until one works. I can do that, but I fear this will get huge
and hard to maintain.

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH bpf-next 6/8] tools: bpftool: add probes for eBPF helper functions
  2018-12-15  3:32     ` Quentin Monnet
@ 2018-12-15 23:57       ` Daniel Borkmann
  2018-12-17 10:18         ` Quentin Monnet
  0 siblings, 1 reply; 41+ messages in thread
From: Daniel Borkmann @ 2018-12-15 23:57 UTC (permalink / raw)
  To: Quentin Monnet, Alexei Starovoitov
  Cc: netdev, oss-drivers, Arnaldo Carvalho de Melo,
	Jesper Dangaard Brouer, Stanislav Fomichev

On 12/15/2018 04:32 AM, Quentin Monnet wrote:
> 2018-12-15 01:08 UTC+0100 ~ Daniel Borkmann <daniel@iogearbox.net>
>> On 12/13/2018 01:19 PM, Quentin Monnet wrote:
>>> Similarly to what was done for program types and map types, add a set of
>>> probes to test the availability of the different eBPF helper functions
>>> on the current system.
>>>
>>> Sample output:
>>>
>>>     # bpftool feature probe kernel
>>>     ...
>>>     Scanning eBPF helper functions...
>>>     eBPF helper bpf_map_lookup_elem is available
>>>     eBPF helper bpf_map_update_elem is available
>>>     eBPF helper bpf_map_delete_elem is available
>>>     ...
>>>
>>>     # bpftool --json --pretty feature probe kernel
>>>     {
>>>         ...
>>>         "helpers": {
>>>             "have_bpf_map_lookup_elem_helper": true,
>>>             "have_bpf_map_update_elem_helper": true,
>>>             "have_bpf_map_delete_elem_helper": true,
>>>             ...
>>>         }
>>>     }
>>>
>>>     # bpftool feature probe kernel macros prefix BPFTOOL_
>>>     ...
>>>     /*** eBPF helper functions ***/
>>>     #define BPFTOOL_BPF_MAP_LOOKUP_ELEM_HELPER
>>>     #define BPFTOOL_BPF_MAP_UPDATE_ELEM_HELPER
>>>     #define BPFTOOL_BPF_MAP_DELETE_ELEM_HELPER
>>
>> Small nit: instead of BPFTOOL_ prefix, would it make sense
>> to generally use Have_ prefix (similar to json output). The
>> former seems somewhat bpftool related though it solely probes
>> the underlying kernel.
> 
> "BPFTOOL_" is provided on the command line ("prefix BPFTOOL_"), and it's
> here just for the example. I initially had a non-configurable "HAVE_"
> prefix instead, but after discussing it with Jakub we thought it best to
> leave the choice of the prefix to the users, so they can choose what
> works best for them, or adapt it and avoid any potential name conflict.

Ah, good point, makes sense then. As default you have no prefix? Perhaps
there it could be "HAVE_" prefix.

>>> Signed-off-by: Quentin Monnet <quentin.monnet@netronome.com>
>>> Reviewed-by: Jakub Kicinski <jakub.kicinski@netronome.com>
>>> ---
>>>  .../bpftool/Documentation/bpftool-feature.rst |   4 +
>>>  tools/bpf/bpftool/feature.c                   | 152 ++++++++++++++++++
>>>  2 files changed, 156 insertions(+)
>>>
>>> diff --git a/tools/bpf/bpftool/Documentation/bpftool-feature.rst b/tools/bpf/bpftool/Documentation/bpftool-feature.rst
>>> index 23920a7490e9..083d30510cce 100644
>>> --- a/tools/bpf/bpftool/Documentation/bpftool-feature.rst
>>> +++ b/tools/bpf/bpftool/Documentation/bpftool-feature.rst
>>> @@ -39,6 +39,10 @@ DESCRIPTION
>>>  		  names when including the output of this command as a header
>>>  		  file.
>>>  
>>> +		  Note that when probed, some eBPF helpers (e.g.
>>> +		  **bpf_trace_printk**\ () or **bpf_probe_write_user**\ ()) may
>>> +		  print warnings to kernel logs.
>>> +
>>>  	**bpftool feature help**
>>>  		  Print short help message.
>>>  
>>> diff --git a/tools/bpf/bpftool/feature.c b/tools/bpf/bpftool/feature.c
>>> index 85928f172413..77221fff6ba9 100644
>>> --- a/tools/bpf/bpftool/feature.c
>>> +++ b/tools/bpf/bpftool/feature.c
>>> @@ -24,6 +24,113 @@ enum probe_component {
>>>  	COMPONENT_KERNEL,
>>>  };
>>>  
>>> +#define MAX_HELPER_NAME_LEN 32
>>> +struct helper_param {
>>> +	enum bpf_prog_type progtype;
>>> +	const char name[MAX_HELPER_NAME_LEN];
>>> +};
>>> +
>>> +/* helper_progtype_and_name[index] associates to the BPF helper function of id
>>> + * "index" a name and a program type to run this helper with. In order to probe
>>> + * helper availability for programs offloaded to a network device, use
>>> + * offload-compatible types (e.g. XDP) everywhere we can. Caveats: helper
>>> + * probing may fail currently if only TC (but not XDP) is supported for
>>> + * offload.
>>> + */
>>> +static const struct helper_param helper_progtype_and_name[] = {
>>> +	{ BPF_PROG_TYPE_XDP,		"no_helper_with_id_0" },
>>> +	{ BPF_PROG_TYPE_XDP,		"bpf_map_lookup_elem" },
>>> +	{ BPF_PROG_TYPE_XDP,		"bpf_map_update_elem" },
>>> +	{ BPF_PROG_TYPE_XDP,		"bpf_map_delete_elem" },
>>> +	{ BPF_PROG_TYPE_KPROBE,		"bpf_probe_read" },
>>> +	{ BPF_PROG_TYPE_XDP,		"bpf_ktime_get_ns" },
>>> +	{ BPF_PROG_TYPE_XDP,		"bpf_trace_printk" },
>>> +	{ BPF_PROG_TYPE_XDP,		"bpf_get_prandom_u32" },
>>> +	{ BPF_PROG_TYPE_XDP,		"bpf_get_smp_processor_id" },
>>> +	{ BPF_PROG_TYPE_SCHED_CLS,	"bpf_skb_store_bytes" },
>>> +	{ BPF_PROG_TYPE_SCHED_CLS,	"bpf_l3_csum_replace" },
>>> +	{ BPF_PROG_TYPE_SCHED_CLS,	"bpf_l4_csum_replace" },
>>> +	{ BPF_PROG_TYPE_XDP,		"bpf_tail_call" },
>>> +	{ BPF_PROG_TYPE_SCHED_CLS,	"bpf_clone_redirect" },
>>> +	{ BPF_PROG_TYPE_KPROBE,		"bpf_get_current_pid_tgid" },
>>> +	{ BPF_PROG_TYPE_KPROBE,		"bpf_get_current_uid_gid" },
>>> +	{ BPF_PROG_TYPE_KPROBE,		"bpf_get_current_comm" },
>>> +	{ BPF_PROG_TYPE_SCHED_CLS,	"bpf_get_cgroup_classid" },
>>> +	{ BPF_PROG_TYPE_SCHED_CLS,	"bpf_skb_vlan_push" },
>>> +	{ BPF_PROG_TYPE_SCHED_CLS,	"bpf_skb_vlan_pop" },
>>> +	{ BPF_PROG_TYPE_SCHED_CLS,	"bpf_skb_get_tunnel_key" },
>>> +	{ BPF_PROG_TYPE_SCHED_CLS,	"bpf_skb_set_tunnel_key" },
>>> +	{ BPF_PROG_TYPE_KPROBE,		"bpf_perf_event_read" },
>>> +	{ BPF_PROG_TYPE_XDP,		"bpf_redirect" },
>>> +	{ BPF_PROG_TYPE_SCHED_CLS,	"bpf_get_route_realm" },
>>> +	{ BPF_PROG_TYPE_XDP,		"bpf_perf_event_output" },
>>> +	{ BPF_PROG_TYPE_SCHED_CLS,	"bpf_skb_load_bytes" },
>>> +	{ BPF_PROG_TYPE_KPROBE,		"bpf_get_stackid" },
>>> +	{ BPF_PROG_TYPE_XDP,		"bpf_csum_diff" },
>>> +	{ BPF_PROG_TYPE_SCHED_CLS,	"bpf_skb_get_tunnel_opt" },
>>> +	{ BPF_PROG_TYPE_SCHED_CLS,	"bpf_skb_set_tunnel_opt" },
>>> +	{ BPF_PROG_TYPE_SCHED_CLS,	"bpf_skb_change_proto" },
>>> +	{ BPF_PROG_TYPE_SCHED_CLS,	"bpf_skb_change_type" },
>>> +	{ BPF_PROG_TYPE_SCHED_CLS,	"bpf_skb_under_cgroup" },
>>> +	{ BPF_PROG_TYPE_SCHED_CLS,	"bpf_get_hash_recalc" },
>>> +	{ BPF_PROG_TYPE_KPROBE,		"bpf_get_current_task" },
>>> +	{ BPF_PROG_TYPE_KPROBE,		"bpf_probe_write_user" },
>>> +	{ BPF_PROG_TYPE_KPROBE,		"bpf_current_task_under_cgroup" },
>>> +	{ BPF_PROG_TYPE_SCHED_CLS,	"bpf_skb_change_tail" },
>>> +	{ BPF_PROG_TYPE_SCHED_CLS,	"bpf_skb_pull_data" },
>>> +	{ BPF_PROG_TYPE_SCHED_CLS,	"bpf_csum_update" },
>>> +	{ BPF_PROG_TYPE_SCHED_CLS,	"bpf_set_hash_invalid" },
>>> +	{ BPF_PROG_TYPE_XDP,		"bpf_get_numa_node_id" },
>>> +	{ BPF_PROG_TYPE_SK_SKB,		"bpf_skb_change_head" },
>>> +	{ BPF_PROG_TYPE_XDP,		"bpf_xdp_adjust_head" },
>>> +	{ BPF_PROG_TYPE_KPROBE,		"bpf_probe_read_str" },
>>> +	{ BPF_PROG_TYPE_SCHED_CLS,	"bpf_get_socket_cookie" },
>>> +	{ BPF_PROG_TYPE_SCHED_CLS,	"bpf_get_socket_uid" },
>>> +	{ BPF_PROG_TYPE_SCHED_CLS,	"bpf_set_hash" },
>>> +	{ BPF_PROG_TYPE_SOCK_OPS,	"bpf_setsockopt" },
>>> +	{ BPF_PROG_TYPE_SCHED_CLS,	"bpf_skb_adjust_room" },
>>> +	{ BPF_PROG_TYPE_XDP,		"bpf_redirect_map" },
>>> +	{ BPF_PROG_TYPE_SK_SKB,		"bpf_sk_redirect_map" },
>>> +	{ BPF_PROG_TYPE_SOCK_OPS,	"bpf_sock_map_update" },
>>> +	{ BPF_PROG_TYPE_XDP,		"bpf_xdp_adjust_meta" },
>>> +	{ BPF_PROG_TYPE_KPROBE,		"bpf_perf_event_read_value" },
>>> +	{ BPF_PROG_TYPE_PERF_EVENT,	"bpf_perf_prog_read_value" },
>>> +	{ BPF_PROG_TYPE_SOCK_OPS,	"bpf_getsockopt" },
>>> +	{ BPF_PROG_TYPE_KPROBE,		"bpf_override_return" },
>>> +	{ BPF_PROG_TYPE_SOCK_OPS,	"bpf_sock_ops_cb_flags_set" },
>>> +	{ BPF_PROG_TYPE_SK_MSG,		"bpf_msg_redirect_map" },
>>> +	{ BPF_PROG_TYPE_SK_MSG,		"bpf_msg_apply_bytes" },
>>> +	{ BPF_PROG_TYPE_SK_MSG,		"bpf_msg_cork_bytes" },
>>> +	{ BPF_PROG_TYPE_SK_MSG,		"bpf_msg_pull_data" },
>>> +	{ BPF_PROG_TYPE_CGROUP_SOCK_ADDR,	"bpf_bind" },
>>> +	{ BPF_PROG_TYPE_XDP,		"bpf_xdp_adjust_tail" },
>>> +	{ BPF_PROG_TYPE_SCHED_CLS,	"bpf_skb_get_xfrm_state" },
>>> +	{ BPF_PROG_TYPE_KPROBE,		"bpf_get_stack" },
>>> +	{ BPF_PROG_TYPE_SCHED_CLS,	"bpf_skb_load_bytes_relative" },
>>> +	{ BPF_PROG_TYPE_SCHED_CLS,	"bpf_fib_lookup" },
>>> +	{ BPF_PROG_TYPE_SOCK_OPS,	"bpf_sock_hash_update" },
>>> +	{ BPF_PROG_TYPE_SK_MSG,		"bpf_msg_redirect_hash" },
>>> +	{ BPF_PROG_TYPE_SK_SKB,		"bpf_sk_redirect_hash" },
>>> +	{ BPF_PROG_TYPE_LWT_IN,		"bpf_lwt_push_encap" },
>>> +	{ BPF_PROG_TYPE_LWT_SEG6LOCAL,	"bpf_lwt_seg6_store_bytes" },
>>> +	{ BPF_PROG_TYPE_LWT_SEG6LOCAL,	"bpf_lwt_seg6_adjust_srh" },
>>> +	{ BPF_PROG_TYPE_LWT_SEG6LOCAL,	"bpf_lwt_seg6_action" },
>>> +	{ BPF_PROG_TYPE_LIRC_MODE2,	"bpf_rc_repeat" },
>>> +	{ BPF_PROG_TYPE_LIRC_MODE2,	"bpf_rc_keydown" },
>>> +	{ BPF_PROG_TYPE_SCHED_CLS,	"bpf_skb_cgroup_id" },
>>> +	{ BPF_PROG_TYPE_KPROBE,		"bpf_get_current_cgroup_id" },
>>> +	{ BPF_PROG_TYPE_CGROUP_SKB,	"bpf_get_local_storage" },
>>> +	{ BPF_PROG_TYPE_SK_REUSEPORT,	"bpf_sk_select_reuseport" },
>>> +	{ BPF_PROG_TYPE_SCHED_CLS,	"bpf_skb_ancestor_cgroup_id" },
>>> +	{ BPF_PROG_TYPE_SK_SKB,		"bpf_sk_lookup_tcp" },
>>> +	{ BPF_PROG_TYPE_SK_SKB,		"bpf_sk_lookup_udp" },
>>> +	{ BPF_PROG_TYPE_SK_SKB,		"bpf_sk_release" },
>>> +	{ BPF_PROG_TYPE_XDP,		"bpf_map_push_elem" },
>>> +	{ BPF_PROG_TYPE_XDP,		"bpf_map_pop_elem" },
>>> +	{ BPF_PROG_TYPE_XDP,		"bpf_map_peek_elem" },
>>> +	{ BPF_PROG_TYPE_SK_MSG,		"bpf_msg_push_data" },
>>
>> Some of these helpers like bpf_perf_event_output are available on
>> multiple types; should they all be tested in case the one probed
>> prog type would not be available on the underlying kernel?
>>
>> Thanks,
>> Daniel
> 
> That's a good point, but it will make things more complicated. We would
> need a list of compatible program types for each helper, and then try
> them all until one works. I can do that, but I fear this will get huge
> and hard to maintain.

Hmm, true, one way to overcome this maintenance burden would be to try to
brute-force all helpers over all prog types but obviously from verifier
side it's more expensive. Perhaps worth testing whether this overhead would
be acceptable. On the upside you'd have a listing of all supported helpers
for each prog type.

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH bpf-next 2/8] tools: bpftool: add probes for /proc/ eBPF parameters
  2018-12-15  3:31     ` Quentin Monnet
@ 2018-12-16  0:14       ` Daniel Borkmann
  2018-12-17 10:44         ` Quentin Monnet
  0 siblings, 1 reply; 41+ messages in thread
From: Daniel Borkmann @ 2018-12-16  0:14 UTC (permalink / raw)
  To: Quentin Monnet, Alexei Starovoitov
  Cc: netdev, oss-drivers, Arnaldo Carvalho de Melo,
	Jesper Dangaard Brouer, Stanislav Fomichev

On 12/15/2018 04:31 AM, Quentin Monnet wrote:
> 2018-12-15 00:40 UTC+0100 ~ Daniel Borkmann <daniel@iogearbox.net>
>> On 12/13/2018 01:19 PM, Quentin Monnet wrote:
>>> Add a set of probes to dump the eBPF-related parameters available from
>>> /proc/: availability of bpf() syscall for unprivileged users,
>>> JIT compiler status and hardening status, kallsyms exports status.
>>>
>>> Sample output:
>>>
>>>     # bpftool feature probe kernel
>>>     Scanning system configuration...
>>>     bpf() syscall for unprivileged users is enabled
>>>     JIT compiler is disabled
>>>     JIT compiler hardening is disabled
>>>     JIT compiler kallsyms exports are disabled
>>>     ...
>>>
>>>     # bpftool --json --pretty feature probe kernel
>>>     {
>>>         "system_config": {
>>>             "unprivileged_bpf_disabled": 0,
>>>             "bpf_jit_enable": 0,
>>>             "bpf_jit_harden": 0,
>>>             "bpf_jit_kallsyms": 0
>>>         },
>>>         ...
>>>     }
>>>
>>>     # bpftool feature probe kernel macros prefix BPFTOOL_
>>>     #define UNPRIVILEGED_BPF_DISABLED UNPRIVILEGED_BPF_DISABLED_OFF
>>>     #define  UNPRIVILEGED_BPF_DISABLED_OFF 0
>>>     #define  UNPRIVILEGED_BPF_DISABLED_ON 1
>>>     #define  UNPRIVILEGED_BPF_DISABLED_UNKNOWN -1
>>>     #define JIT_COMPILER_ENABLE JIT_COMPILER_ENABLE_OFF
>>>     #define  JIT_COMPILER_ENABLE_OFF 0
>>>     #define  JIT_COMPILER_ENABLE_ON 1
>>>     #define  JIT_COMPILER_ENABLE_ON_WITH_DEBUG 2
>>>     #define  JIT_COMPILER_ENABLE_UNKNOWN -1
>>>     #define JIT_COMPILER_HARDEN JIT_COMPILER_HARDEN_OFF
>>>     #define  JIT_COMPILER_HARDEN_OFF 0
>>>     #define  JIT_COMPILER_HARDEN_FOR_UNPRIVILEGED 1
>>>     #define  JIT_COMPILER_HARDEN_FOR_ALL_USERS 2
>>>     #define  JIT_COMPILER_HARDEN_UNKNOWN -1
>>>     #define JIT_COMPILER_KALLSYMS JIT_COMPILER_KALLSYMS_OFF
>>>     #define  JIT_COMPILER_KALLSYMS_OFF 0
>>>     #define  JIT_COMPILER_KALLSYMS_FOR_ROOT 1
>>>     #define  JIT_COMPILER_KALLSYMS_UNKNOWN -1
>>>     ...
>>
>> Hm, given these knobs may change at any point in time, what would
>> be a use case in an application for these if they cannot be relied
>> upon? (At least the jit_enable and jit_harden are transparent to
>> the user.)
> 
> Granted, for those parameters it's a snapshot of the system at the time
> the probes are run. It can be useful, I suppose, if a server is not
> expected to change them often... And the plain output might be useful to
> a sysadmin who wants to have a quick look at BPF-related parameters, maybe?

Hmm, but wouldn't the main purpose of this header file be to include it
into a BPF program to selectively enable / disable features (e.g. LPM
map vs hashtab when kernel does not support LPM type as one example)?
What would a use-case be for the above defines used inside such BPF prog?
(Similarly for the kernel config defines in the other patch, how would
a BPF prog use them?)

I think perhaps the 'issue' is that the C-style header generation and json
dump are dumping the /exact/ same information. Is this a requirement?
Wouldn't it be better to evolve the two /independently/?

E.g. the system_config bits from the json dump and BPF-related kernel
config, perhaps also a listing of available maps, progs with supported
helpers for a prog would be useful for the json dump for an admin or
orchestration daemon to adapt to the underlying kernel where it could
just parse the json and doesn't have to do the queries by itself.

But for the header generation, I would only place defines in there that
are strictly relevant for the BPF program author. Available maps, progs
and helpers is a good start there, later we could also put others in there
such as [0] and similar specifics or quirks to verifier behavior that
would be relevant in terms of work-arounds for supporting different kernel
versions; but on a case by case basis. There things might potentially be
less interesting for a json dump (though the json dump could overall be
a superset of the info from the header file).

  [0] https://github.com/cilium/cilium/blob/master/bpf/probes/raw_mark_map_val.t

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH bpf-next 6/8] tools: bpftool: add probes for eBPF helper functions
  2018-12-15 23:57       ` Daniel Borkmann
@ 2018-12-17 10:18         ` Quentin Monnet
  2018-12-18  0:42           ` Daniel Borkmann
  0 siblings, 1 reply; 41+ messages in thread
From: Quentin Monnet @ 2018-12-17 10:18 UTC (permalink / raw)
  To: Daniel Borkmann, Alexei Starovoitov
  Cc: netdev, oss-drivers, Arnaldo Carvalho de Melo,
	Jesper Dangaard Brouer, Stanislav Fomichev

2018-12-16 00:57 UTC+0100 ~ Daniel Borkmann <daniel@iogearbox.net>
> On 12/15/2018 04:32 AM, Quentin Monnet wrote:
>> 2018-12-15 01:08 UTC+0100 ~ Daniel Borkmann <daniel@iogearbox.net>
>>> On 12/13/2018 01:19 PM, Quentin Monnet wrote:
>>>> Similarly to what was done for program types and map types, add a set of
>>>> probes to test the availability of the different eBPF helper functions
>>>> on the current system.
>>>>
>>>> Sample output:
>>>>
>>>>      # bpftool feature probe kernel
>>>>      ...
>>>>      Scanning eBPF helper functions...
>>>>      eBPF helper bpf_map_lookup_elem is available
>>>>      eBPF helper bpf_map_update_elem is available
>>>>      eBPF helper bpf_map_delete_elem is available
>>>>      ...
>>>>
>>>>      # bpftool --json --pretty feature probe kernel
>>>>      {
>>>>          ...
>>>>          "helpers": {
>>>>              "have_bpf_map_lookup_elem_helper": true,
>>>>              "have_bpf_map_update_elem_helper": true,
>>>>              "have_bpf_map_delete_elem_helper": true,
>>>>              ...
>>>>          }
>>>>      }
>>>>
>>>>      # bpftool feature probe kernel macros prefix BPFTOOL_
>>>>      ...
>>>>      /*** eBPF helper functions ***/
>>>>      #define BPFTOOL_BPF_MAP_LOOKUP_ELEM_HELPER
>>>>      #define BPFTOOL_BPF_MAP_UPDATE_ELEM_HELPER
>>>>      #define BPFTOOL_BPF_MAP_DELETE_ELEM_HELPER
>>>
>>> Small nit: instead of BPFTOOL_ prefix, would it make sense
>>> to generally use Have_ prefix (similar to json output). The
>>> former seems somewhat bpftool related though it solely probes
>>> the underlying kernel.
>>
>> "BPFTOOL_" is provided on the command line ("prefix BPFTOOL_"), and it's
>> here just for the example. I initially had a non-configurable "HAVE_"
>> prefix instead, but after discussing it with Jakub we thought it best to
>> leave the choice of the prefix to the users, so they can choose what
>> works best for them, or adapt it and avoid any potential name conflict.
> 
> Ah, good point, makes sense then. As default you have no prefix? Perhaps
> there it could be "HAVE_" prefix.

Yes, I can probably reinstate it as a default option if none was 
provided from the command line, for prog/map types and helpers.

>>>> Signed-off-by: Quentin Monnet <quentin.monnet@netronome.com>
>>>> Reviewed-by: Jakub Kicinski <jakub.kicinski@netronome.com>
>>>> ---
>>>>   .../bpftool/Documentation/bpftool-feature.rst |   4 +
>>>>   tools/bpf/bpftool/feature.c                   | 152 ++++++++++++++++++
>>>>   2 files changed, 156 insertions(+)
>>>>
>>>> diff --git a/tools/bpf/bpftool/Documentation/bpftool-feature.rst b/tools/bpf/bpftool/Documentation/bpftool-feature.rst
>>>> index 23920a7490e9..083d30510cce 100644
>>>> --- a/tools/bpf/bpftool/Documentation/bpftool-feature.rst
>>>> +++ b/tools/bpf/bpftool/Documentation/bpftool-feature.rst
>>>> @@ -39,6 +39,10 @@ DESCRIPTION
>>>>   		  names when including the output of this command as a header
>>>>   		  file.
>>>>   
>>>> +		  Note that when probed, some eBPF helpers (e.g.
>>>> +		  **bpf_trace_printk**\ () or **bpf_probe_write_user**\ ()) may
>>>> +		  print warnings to kernel logs.
>>>> +
>>>>   	**bpftool feature help**
>>>>   		  Print short help message.
>>>>   
>>>> diff --git a/tools/bpf/bpftool/feature.c b/tools/bpf/bpftool/feature.c
>>>> index 85928f172413..77221fff6ba9 100644
>>>> --- a/tools/bpf/bpftool/feature.c
>>>> +++ b/tools/bpf/bpftool/feature.c
>>>> @@ -24,6 +24,113 @@ enum probe_component {
>>>>   	COMPONENT_KERNEL,
>>>>   };
>>>>   
>>>> +#define MAX_HELPER_NAME_LEN 32
>>>> +struct helper_param {
>>>> +	enum bpf_prog_type progtype;
>>>> +	const char name[MAX_HELPER_NAME_LEN];
>>>> +};
>>>> +
>>>> +/* helper_progtype_and_name[index] associates to the BPF helper function of id
>>>> + * "index" a name and a program type to run this helper with. In order to probe
>>>> + * helper availability for programs offloaded to a network device, use
>>>> + * offload-compatible types (e.g. XDP) everywhere we can. Caveats: helper
>>>> + * probing may fail currently if only TC (but not XDP) is supported for
>>>> + * offload.
>>>> + */
>>>> +static const struct helper_param helper_progtype_and_name[] = {
>>>> +	{ BPF_PROG_TYPE_XDP,		"no_helper_with_id_0" },
>>>> +	{ BPF_PROG_TYPE_XDP,		"bpf_map_lookup_elem" },
>>>> +	{ BPF_PROG_TYPE_XDP,		"bpf_map_update_elem" },
>>>> +	{ BPF_PROG_TYPE_XDP,		"bpf_map_delete_elem" },
>>>> +	{ BPF_PROG_TYPE_KPROBE,		"bpf_probe_read" },
>>>> +	{ BPF_PROG_TYPE_XDP,		"bpf_ktime_get_ns" },
>>>> +	{ BPF_PROG_TYPE_XDP,		"bpf_trace_printk" },
>>>> +	{ BPF_PROG_TYPE_XDP,		"bpf_get_prandom_u32" },
>>>> +	{ BPF_PROG_TYPE_XDP,		"bpf_get_smp_processor_id" },
>>>> +	{ BPF_PROG_TYPE_SCHED_CLS,	"bpf_skb_store_bytes" },
>>>> +	{ BPF_PROG_TYPE_SCHED_CLS,	"bpf_l3_csum_replace" },
>>>> +	{ BPF_PROG_TYPE_SCHED_CLS,	"bpf_l4_csum_replace" },
>>>> +	{ BPF_PROG_TYPE_XDP,		"bpf_tail_call" },
>>>> +	{ BPF_PROG_TYPE_SCHED_CLS,	"bpf_clone_redirect" },
>>>> +	{ BPF_PROG_TYPE_KPROBE,		"bpf_get_current_pid_tgid" },
>>>> +	{ BPF_PROG_TYPE_KPROBE,		"bpf_get_current_uid_gid" },
>>>> +	{ BPF_PROG_TYPE_KPROBE,		"bpf_get_current_comm" },
>>>> +	{ BPF_PROG_TYPE_SCHED_CLS,	"bpf_get_cgroup_classid" },
>>>> +	{ BPF_PROG_TYPE_SCHED_CLS,	"bpf_skb_vlan_push" },
>>>> +	{ BPF_PROG_TYPE_SCHED_CLS,	"bpf_skb_vlan_pop" },
>>>> +	{ BPF_PROG_TYPE_SCHED_CLS,	"bpf_skb_get_tunnel_key" },
>>>> +	{ BPF_PROG_TYPE_SCHED_CLS,	"bpf_skb_set_tunnel_key" },
>>>> +	{ BPF_PROG_TYPE_KPROBE,		"bpf_perf_event_read" },
>>>> +	{ BPF_PROG_TYPE_XDP,		"bpf_redirect" },
>>>> +	{ BPF_PROG_TYPE_SCHED_CLS,	"bpf_get_route_realm" },
>>>> +	{ BPF_PROG_TYPE_XDP,		"bpf_perf_event_output" },
>>>> +	{ BPF_PROG_TYPE_SCHED_CLS,	"bpf_skb_load_bytes" },
>>>> +	{ BPF_PROG_TYPE_KPROBE,		"bpf_get_stackid" },
>>>> +	{ BPF_PROG_TYPE_XDP,		"bpf_csum_diff" },
>>>> +	{ BPF_PROG_TYPE_SCHED_CLS,	"bpf_skb_get_tunnel_opt" },
>>>> +	{ BPF_PROG_TYPE_SCHED_CLS,	"bpf_skb_set_tunnel_opt" },
>>>> +	{ BPF_PROG_TYPE_SCHED_CLS,	"bpf_skb_change_proto" },
>>>> +	{ BPF_PROG_TYPE_SCHED_CLS,	"bpf_skb_change_type" },
>>>> +	{ BPF_PROG_TYPE_SCHED_CLS,	"bpf_skb_under_cgroup" },
>>>> +	{ BPF_PROG_TYPE_SCHED_CLS,	"bpf_get_hash_recalc" },
>>>> +	{ BPF_PROG_TYPE_KPROBE,		"bpf_get_current_task" },
>>>> +	{ BPF_PROG_TYPE_KPROBE,		"bpf_probe_write_user" },
>>>> +	{ BPF_PROG_TYPE_KPROBE,		"bpf_current_task_under_cgroup" },
>>>> +	{ BPF_PROG_TYPE_SCHED_CLS,	"bpf_skb_change_tail" },
>>>> +	{ BPF_PROG_TYPE_SCHED_CLS,	"bpf_skb_pull_data" },
>>>> +	{ BPF_PROG_TYPE_SCHED_CLS,	"bpf_csum_update" },
>>>> +	{ BPF_PROG_TYPE_SCHED_CLS,	"bpf_set_hash_invalid" },
>>>> +	{ BPF_PROG_TYPE_XDP,		"bpf_get_numa_node_id" },
>>>> +	{ BPF_PROG_TYPE_SK_SKB,		"bpf_skb_change_head" },
>>>> +	{ BPF_PROG_TYPE_XDP,		"bpf_xdp_adjust_head" },
>>>> +	{ BPF_PROG_TYPE_KPROBE,		"bpf_probe_read_str" },
>>>> +	{ BPF_PROG_TYPE_SCHED_CLS,	"bpf_get_socket_cookie" },
>>>> +	{ BPF_PROG_TYPE_SCHED_CLS,	"bpf_get_socket_uid" },
>>>> +	{ BPF_PROG_TYPE_SCHED_CLS,	"bpf_set_hash" },
>>>> +	{ BPF_PROG_TYPE_SOCK_OPS,	"bpf_setsockopt" },
>>>> +	{ BPF_PROG_TYPE_SCHED_CLS,	"bpf_skb_adjust_room" },
>>>> +	{ BPF_PROG_TYPE_XDP,		"bpf_redirect_map" },
>>>> +	{ BPF_PROG_TYPE_SK_SKB,		"bpf_sk_redirect_map" },
>>>> +	{ BPF_PROG_TYPE_SOCK_OPS,	"bpf_sock_map_update" },
>>>> +	{ BPF_PROG_TYPE_XDP,		"bpf_xdp_adjust_meta" },
>>>> +	{ BPF_PROG_TYPE_KPROBE,		"bpf_perf_event_read_value" },
>>>> +	{ BPF_PROG_TYPE_PERF_EVENT,	"bpf_perf_prog_read_value" },
>>>> +	{ BPF_PROG_TYPE_SOCK_OPS,	"bpf_getsockopt" },
>>>> +	{ BPF_PROG_TYPE_KPROBE,		"bpf_override_return" },
>>>> +	{ BPF_PROG_TYPE_SOCK_OPS,	"bpf_sock_ops_cb_flags_set" },
>>>> +	{ BPF_PROG_TYPE_SK_MSG,		"bpf_msg_redirect_map" },
>>>> +	{ BPF_PROG_TYPE_SK_MSG,		"bpf_msg_apply_bytes" },
>>>> +	{ BPF_PROG_TYPE_SK_MSG,		"bpf_msg_cork_bytes" },
>>>> +	{ BPF_PROG_TYPE_SK_MSG,		"bpf_msg_pull_data" },
>>>> +	{ BPF_PROG_TYPE_CGROUP_SOCK_ADDR,	"bpf_bind" },
>>>> +	{ BPF_PROG_TYPE_XDP,		"bpf_xdp_adjust_tail" },
>>>> +	{ BPF_PROG_TYPE_SCHED_CLS,	"bpf_skb_get_xfrm_state" },
>>>> +	{ BPF_PROG_TYPE_KPROBE,		"bpf_get_stack" },
>>>> +	{ BPF_PROG_TYPE_SCHED_CLS,	"bpf_skb_load_bytes_relative" },
>>>> +	{ BPF_PROG_TYPE_SCHED_CLS,	"bpf_fib_lookup" },
>>>> +	{ BPF_PROG_TYPE_SOCK_OPS,	"bpf_sock_hash_update" },
>>>> +	{ BPF_PROG_TYPE_SK_MSG,		"bpf_msg_redirect_hash" },
>>>> +	{ BPF_PROG_TYPE_SK_SKB,		"bpf_sk_redirect_hash" },
>>>> +	{ BPF_PROG_TYPE_LWT_IN,		"bpf_lwt_push_encap" },
>>>> +	{ BPF_PROG_TYPE_LWT_SEG6LOCAL,	"bpf_lwt_seg6_store_bytes" },
>>>> +	{ BPF_PROG_TYPE_LWT_SEG6LOCAL,	"bpf_lwt_seg6_adjust_srh" },
>>>> +	{ BPF_PROG_TYPE_LWT_SEG6LOCAL,	"bpf_lwt_seg6_action" },
>>>> +	{ BPF_PROG_TYPE_LIRC_MODE2,	"bpf_rc_repeat" },
>>>> +	{ BPF_PROG_TYPE_LIRC_MODE2,	"bpf_rc_keydown" },
>>>> +	{ BPF_PROG_TYPE_SCHED_CLS,	"bpf_skb_cgroup_id" },
>>>> +	{ BPF_PROG_TYPE_KPROBE,		"bpf_get_current_cgroup_id" },
>>>> +	{ BPF_PROG_TYPE_CGROUP_SKB,	"bpf_get_local_storage" },
>>>> +	{ BPF_PROG_TYPE_SK_REUSEPORT,	"bpf_sk_select_reuseport" },
>>>> +	{ BPF_PROG_TYPE_SCHED_CLS,	"bpf_skb_ancestor_cgroup_id" },
>>>> +	{ BPF_PROG_TYPE_SK_SKB,		"bpf_sk_lookup_tcp" },
>>>> +	{ BPF_PROG_TYPE_SK_SKB,		"bpf_sk_lookup_udp" },
>>>> +	{ BPF_PROG_TYPE_SK_SKB,		"bpf_sk_release" },
>>>> +	{ BPF_PROG_TYPE_XDP,		"bpf_map_push_elem" },
>>>> +	{ BPF_PROG_TYPE_XDP,		"bpf_map_pop_elem" },
>>>> +	{ BPF_PROG_TYPE_XDP,		"bpf_map_peek_elem" },
>>>> +	{ BPF_PROG_TYPE_SK_MSG,		"bpf_msg_push_data" },
>>>
>>> Some of these helpers like bpf_perf_event_output are available on
>>> multiple types; should they all be tested in case the one probed
>>> prog type would not be available on the underlying kernel?
>>>
>>> Thanks,
>>> Daniel
>>
>> That's a good point, but it will make things more complicated. We would
>> need a list of compatible program types for each helper, and then try
>> them all until one works. I can do that, but I fear this will get huge
>> and hard to maintain.
> 
> Hmm, true, one way to overcome this maintenance burden would be to try to
> brute-force all helpers over all prog types but obviously from verifier
> side it's more expensive. Perhaps worth testing whether this overhead would
> be acceptable. On the upside you'd have a listing of all supported helpers
> for each prog type.

Having the listing sounds nice. My concern is that the compatibility 
list for a couple of helpers has been modified in the past (e.g. 
csum_diff added to XDP), and I fear such changes will be easy to miss.

Brute-forcing all programs might be doable (programs are only 2-insn 
long, no jumps) but seems less clean. I can have a look at it. Is there 
any particular metric I should focus on?

Naive question, just in case: I don't suppose it is desirable to make 
the list of supported helpers for each program type accessible to user 
space? (I guess it would come down to implement those probes as a new 
bpf() command, which has been rejected before if I remember correctly?)

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH bpf-next 2/8] tools: bpftool: add probes for /proc/ eBPF parameters
  2018-12-16  0:14       ` Daniel Borkmann
@ 2018-12-17 10:44         ` Quentin Monnet
  2018-12-17 11:11           ` Daniel Borkmann
  0 siblings, 1 reply; 41+ messages in thread
From: Quentin Monnet @ 2018-12-17 10:44 UTC (permalink / raw)
  To: Daniel Borkmann, Alexei Starovoitov
  Cc: netdev, oss-drivers, Arnaldo Carvalho de Melo,
	Jesper Dangaard Brouer, Stanislav Fomichev

2018-12-16 01:14 UTC+0100 ~ Daniel Borkmann <daniel@iogearbox.net>
> On 12/15/2018 04:31 AM, Quentin Monnet wrote:
>> 2018-12-15 00:40 UTC+0100 ~ Daniel Borkmann <daniel@iogearbox.net>
>>> On 12/13/2018 01:19 PM, Quentin Monnet wrote:
>>>> Add a set of probes to dump the eBPF-related parameters available from
>>>> /proc/: availability of bpf() syscall for unprivileged users,
>>>> JIT compiler status and hardening status, kallsyms exports status.
>>>>
>>>> Sample output:
>>>>
>>>>      # bpftool feature probe kernel
>>>>      Scanning system configuration...
>>>>      bpf() syscall for unprivileged users is enabled
>>>>      JIT compiler is disabled
>>>>      JIT compiler hardening is disabled
>>>>      JIT compiler kallsyms exports are disabled
>>>>      ...
>>>>
>>>>      # bpftool --json --pretty feature probe kernel
>>>>      {
>>>>          "system_config": {
>>>>              "unprivileged_bpf_disabled": 0,
>>>>              "bpf_jit_enable": 0,
>>>>              "bpf_jit_harden": 0,
>>>>              "bpf_jit_kallsyms": 0
>>>>          },
>>>>          ...
>>>>      }
>>>>
>>>>      # bpftool feature probe kernel macros prefix BPFTOOL_
>>>>      #define UNPRIVILEGED_BPF_DISABLED UNPRIVILEGED_BPF_DISABLED_OFF
>>>>      #define  UNPRIVILEGED_BPF_DISABLED_OFF 0
>>>>      #define  UNPRIVILEGED_BPF_DISABLED_ON 1
>>>>      #define  UNPRIVILEGED_BPF_DISABLED_UNKNOWN -1
>>>>      #define JIT_COMPILER_ENABLE JIT_COMPILER_ENABLE_OFF
>>>>      #define  JIT_COMPILER_ENABLE_OFF 0
>>>>      #define  JIT_COMPILER_ENABLE_ON 1
>>>>      #define  JIT_COMPILER_ENABLE_ON_WITH_DEBUG 2
>>>>      #define  JIT_COMPILER_ENABLE_UNKNOWN -1
>>>>      #define JIT_COMPILER_HARDEN JIT_COMPILER_HARDEN_OFF
>>>>      #define  JIT_COMPILER_HARDEN_OFF 0
>>>>      #define  JIT_COMPILER_HARDEN_FOR_UNPRIVILEGED 1
>>>>      #define  JIT_COMPILER_HARDEN_FOR_ALL_USERS 2
>>>>      #define  JIT_COMPILER_HARDEN_UNKNOWN -1
>>>>      #define JIT_COMPILER_KALLSYMS JIT_COMPILER_KALLSYMS_OFF
>>>>      #define  JIT_COMPILER_KALLSYMS_OFF 0
>>>>      #define  JIT_COMPILER_KALLSYMS_FOR_ROOT 1
>>>>      #define  JIT_COMPILER_KALLSYMS_UNKNOWN -1
>>>>      ...
>>>
>>> Hm, given these knobs may change at any point in time, what would
>>> be a use case in an application for these if they cannot be relied
>>> upon? (At least the jit_enable and jit_harden are transparent to
>>> the user.)
>>
>> Granted, for those parameters it's a snapshot of the system at the time
>> the probes are run. It can be useful, I suppose, if a server is not
>> expected to change them often... And the plain output might be useful to
>> a sysadmin who wants to have a quick look at BPF-related parameters, maybe?
> 
> Hmm, but wouldn't the main purpose of this header file be to include it
> into a BPF program to selectively enable / disable features (e.g. LPM
> map vs hashtab when kernel does not support LPM type as one example)?
> What would a use-case be for the above defines used inside such BPF prog?
> (Similarly for the kernel config defines in the other patch, how would
> a BPF prog use them?)
> 
> I think perhaps the 'issue' is that the C-style header generation and json
> dump are dumping the /exact/ same information. Is this a requirement?
> Wouldn't it be better to evolve the two /independently/?
> 
> E.g. the system_config bits from the json dump and BPF-related kernel
> config, perhaps also a listing of available maps, progs with supported
> helpers for a prog would be useful for the json dump for an admin or
> orchestration daemon to adapt to the underlying kernel where it could
> just parse the json and doesn't have to do the queries by itself.
> 
> But for the header generation, I would only place defines in there that
> are strictly relevant for the BPF program author. Available maps, progs
> and helpers is a good start there, later we could also put others in there
> such as [0] and similar specifics or quirks to verifier behavior that
> would be relevant in terms of work-arounds for supporting different kernel
> versions; but on a case by case basis. There things might potentially be
> less interesting for a json dump (though the json dump could overall be
> a superset of the info from the header file).
> 
>    [0] https://github.com/cilium/cilium/blob/master/bpf/probes/raw_mark_map_val.t
> 

For the use case about kernel config options, I was thinking about 
Cilium which collects some of them as well [0], but maybe it's not worth 
having it in the C-style header for now. For procfs parameters, maybe 
it's not so relevant indeed to have them at all in this output.

So you have a point, I suppose. I do not have any hard requirement about 
having the #define and the JSON similar; I argued with Stanislav that I 
didn't want to introduce small losses of information between the two, 
but if we consider them entirely different from the start it is not the 
same thing... So maybe I should just stick to the basics for the #define 
output, as you suggest.

I've seen the other probes used by Cilium, but I intentionally left the 
most specific one aside for now, there's enough to do with the current 
probes :). But yeah, it would make sense to have them added in the 
future. And for the record, I like the idea of keeping JSON a superset 
of the available information indeed.

I'll go with just prog/map types and helpers for the #define in my next 
version. This should also settle the discussion on the format of the 
macros used in this first version for the procfs parameters.

Thanks!
Quentin

[0] https://github.com/cilium/cilium/blob/master/bpf/run_probes.sh#L37

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH bpf-next 2/8] tools: bpftool: add probes for /proc/ eBPF parameters
  2018-12-17 10:44         ` Quentin Monnet
@ 2018-12-17 11:11           ` Daniel Borkmann
  0 siblings, 0 replies; 41+ messages in thread
From: Daniel Borkmann @ 2018-12-17 11:11 UTC (permalink / raw)
  To: Quentin Monnet, Alexei Starovoitov
  Cc: netdev, oss-drivers, Arnaldo Carvalho de Melo,
	Jesper Dangaard Brouer, Stanislav Fomichev

On 12/17/2018 11:44 AM, Quentin Monnet wrote:
> 2018-12-16 01:14 UTC+0100 ~ Daniel Borkmann <daniel@iogearbox.net>
>> On 12/15/2018 04:31 AM, Quentin Monnet wrote:
>>> 2018-12-15 00:40 UTC+0100 ~ Daniel Borkmann <daniel@iogearbox.net>
>>>> On 12/13/2018 01:19 PM, Quentin Monnet wrote:
>>>>> Add a set of probes to dump the eBPF-related parameters available from
>>>>> /proc/: availability of bpf() syscall for unprivileged users,
>>>>> JIT compiler status and hardening status, kallsyms exports status.
>>>>>
>>>>> Sample output:
>>>>>
>>>>>      # bpftool feature probe kernel
>>>>>      Scanning system configuration...
>>>>>      bpf() syscall for unprivileged users is enabled
>>>>>      JIT compiler is disabled
>>>>>      JIT compiler hardening is disabled
>>>>>      JIT compiler kallsyms exports are disabled
>>>>>      ...
>>>>>
>>>>>      # bpftool --json --pretty feature probe kernel
>>>>>      {
>>>>>          "system_config": {
>>>>>              "unprivileged_bpf_disabled": 0,
>>>>>              "bpf_jit_enable": 0,
>>>>>              "bpf_jit_harden": 0,
>>>>>              "bpf_jit_kallsyms": 0
>>>>>          },
>>>>>          ...
>>>>>      }
>>>>>
>>>>>      # bpftool feature probe kernel macros prefix BPFTOOL_
>>>>>      #define UNPRIVILEGED_BPF_DISABLED UNPRIVILEGED_BPF_DISABLED_OFF
>>>>>      #define  UNPRIVILEGED_BPF_DISABLED_OFF 0
>>>>>      #define  UNPRIVILEGED_BPF_DISABLED_ON 1
>>>>>      #define  UNPRIVILEGED_BPF_DISABLED_UNKNOWN -1
>>>>>      #define JIT_COMPILER_ENABLE JIT_COMPILER_ENABLE_OFF
>>>>>      #define  JIT_COMPILER_ENABLE_OFF 0
>>>>>      #define  JIT_COMPILER_ENABLE_ON 1
>>>>>      #define  JIT_COMPILER_ENABLE_ON_WITH_DEBUG 2
>>>>>      #define  JIT_COMPILER_ENABLE_UNKNOWN -1
>>>>>      #define JIT_COMPILER_HARDEN JIT_COMPILER_HARDEN_OFF
>>>>>      #define  JIT_COMPILER_HARDEN_OFF 0
>>>>>      #define  JIT_COMPILER_HARDEN_FOR_UNPRIVILEGED 1
>>>>>      #define  JIT_COMPILER_HARDEN_FOR_ALL_USERS 2
>>>>>      #define  JIT_COMPILER_HARDEN_UNKNOWN -1
>>>>>      #define JIT_COMPILER_KALLSYMS JIT_COMPILER_KALLSYMS_OFF
>>>>>      #define  JIT_COMPILER_KALLSYMS_OFF 0
>>>>>      #define  JIT_COMPILER_KALLSYMS_FOR_ROOT 1
>>>>>      #define  JIT_COMPILER_KALLSYMS_UNKNOWN -1
>>>>>      ...
>>>>
>>>> Hm, given these knobs may change at any point in time, what would
>>>> be a use case in an application for these if they cannot be relied
>>>> upon? (At least the jit_enable and jit_harden are transparent to
>>>> the user.)
>>>
>>> Granted, for those parameters it's a snapshot of the system at the time
>>> the probes are run. It can be useful, I suppose, if a server is not
>>> expected to change them often... And the plain output might be useful to
>>> a sysadmin who wants to have a quick look at BPF-related parameters, maybe?
>>
>> Hmm, but wouldn't the main purpose of this header file be to include it
>> into a BPF program to selectively enable / disable features (e.g. LPM
>> map vs hashtab when kernel does not support LPM type as one example)?
>> What would a use-case be for the above defines used inside such BPF prog?
>> (Similarly for the kernel config defines in the other patch, how would
>> a BPF prog use them?)
>>
>> I think perhaps the 'issue' is that the C-style header generation and json
>> dump are dumping the /exact/ same information. Is this a requirement?
>> Wouldn't it be better to evolve the two /independently/?
>>
>> E.g. the system_config bits from the json dump and BPF-related kernel
>> config, perhaps also a listing of available maps, progs with supported
>> helpers for a prog would be useful for the json dump for an admin or
>> orchestration daemon to adapt to the underlying kernel where it could
>> just parse the json and doesn't have to do the queries by itself.
>>
>> But for the header generation, I would only place defines in there that
>> are strictly relevant for the BPF program author. Available maps, progs
>> and helpers is a good start there, later we could also put others in there
>> such as [0] and similar specifics or quirks to verifier behavior that
>> would be relevant in terms of work-arounds for supporting different kernel
>> versions; but on a case by case basis. There things might potentially be
>> less interesting for a json dump (though the json dump could overall be
>> a superset of the info from the header file).
>>
>>    [0] https://github.com/cilium/cilium/blob/master/bpf/probes/raw_mark_map_val.t
> 
> For the use case about kernel config options, I was thinking about Cilium which collects some of them as well [0], but maybe it's not worth having it in the C-style header for now. For procfs parameters, maybe it's not so relevant indeed to have them at all in this output.
> 
> So you have a point, I suppose. I do not have any hard requirement about having the #define and the JSON similar; I argued with Stanislav that I didn't want to introduce small losses of information between the two, but if we consider them entirely different from the start it is not the same thing... So maybe I should just stick to the basics for the #define output, as you suggest.
> 
> I've seen the other probes used by Cilium, but I intentionally left the most specific one aside for now, there's enough to do with the current probes :). But yeah, it would make sense to have them added in the future. And for the record, I like the idea of keeping JSON a superset of the available information indeed.

Sounds good to me, I also think it's better to keep the json output a superset;
definitely allows for more flexibility and if there's a real world use case to
have some of that additional information also in the header output as defines,
we can add that at a later point in time.

> I'll go with just prog/map types and helpers for the #define in my next version. This should also settle the discussion on the format of the macros used in this first version for the procfs parameters.

Yes makes sense, this would be great as a start, and we can extend it as needed.

Thanks,
Daniel

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH bpf-next 6/8] tools: bpftool: add probes for eBPF helper functions
  2018-12-17 10:18         ` Quentin Monnet
@ 2018-12-18  0:42           ` Daniel Borkmann
  2018-12-19 19:02             ` Quentin Monnet
  0 siblings, 1 reply; 41+ messages in thread
From: Daniel Borkmann @ 2018-12-18  0:42 UTC (permalink / raw)
  To: Quentin Monnet, Alexei Starovoitov
  Cc: netdev, oss-drivers, Arnaldo Carvalho de Melo,
	Jesper Dangaard Brouer, Stanislav Fomichev

On 12/17/2018 11:18 AM, Quentin Monnet wrote:
> 2018-12-16 00:57 UTC+0100 ~ Daniel Borkmann <daniel@iogearbox.net>
>> On 12/15/2018 04:32 AM, Quentin Monnet wrote:
>>> 2018-12-15 01:08 UTC+0100 ~ Daniel Borkmann <daniel@iogearbox.net>
>>>> On 12/13/2018 01:19 PM, Quentin Monnet wrote:
>>>>> Similarly to what was done for program types and map types, add a set of
>>>>> probes to test the availability of the different eBPF helper functions
>>>>> on the current system.
>>>>>
>>>>> Sample output:
>>>>>
>>>>>      # bpftool feature probe kernel
>>>>>      ...
>>>>>      Scanning eBPF helper functions...
>>>>>      eBPF helper bpf_map_lookup_elem is available
>>>>>      eBPF helper bpf_map_update_elem is available
>>>>>      eBPF helper bpf_map_delete_elem is available
>>>>>      ...
>>>>>
>>>>>      # bpftool --json --pretty feature probe kernel
>>>>>      {
>>>>>          ...
>>>>>          "helpers": {
>>>>>              "have_bpf_map_lookup_elem_helper": true,
>>>>>              "have_bpf_map_update_elem_helper": true,
>>>>>              "have_bpf_map_delete_elem_helper": true,
>>>>>              ...
>>>>>          }
>>>>>      }
>>>>>
>>>>>      # bpftool feature probe kernel macros prefix BPFTOOL_
>>>>>      ...
>>>>>      /*** eBPF helper functions ***/
>>>>>      #define BPFTOOL_BPF_MAP_LOOKUP_ELEM_HELPER
>>>>>      #define BPFTOOL_BPF_MAP_UPDATE_ELEM_HELPER
>>>>>      #define BPFTOOL_BPF_MAP_DELETE_ELEM_HELPER
>>>>
>>>> Small nit: instead of BPFTOOL_ prefix, would it make sense
>>>> to generally use Have_ prefix (similar to json output). The
>>>> former seems somewhat bpftool related though it solely probes
>>>> the underlying kernel.
>>>
>>> "BPFTOOL_" is provided on the command line ("prefix BPFTOOL_"), and it's
>>> here just for the example. I initially had a non-configurable "HAVE_"
>>> prefix instead, but after discussing it with Jakub we thought it best to
>>> leave the choice of the prefix to the users, so they can choose what
>>> works best for them, or adapt it and avoid any potential name conflict.
>>
>> Ah, good point, makes sense then. As default you have no prefix? Perhaps
>> there it could be "HAVE_" prefix.
> 
> Yes, I can probably reinstate it as a default option if none was provided from the command line, for prog/map types and helpers.
> 
>>>>> Signed-off-by: Quentin Monnet <quentin.monnet@netronome.com>
>>>>> Reviewed-by: Jakub Kicinski <jakub.kicinski@netronome.com>
>>>>> ---
>>>>>   .../bpftool/Documentation/bpftool-feature.rst |   4 +
>>>>>   tools/bpf/bpftool/feature.c                   | 152 ++++++++++++++++++
>>>>>   2 files changed, 156 insertions(+)
>>>>>
>>>>> diff --git a/tools/bpf/bpftool/Documentation/bpftool-feature.rst b/tools/bpf/bpftool/Documentation/bpftool-feature.rst
>>>>> index 23920a7490e9..083d30510cce 100644
>>>>> --- a/tools/bpf/bpftool/Documentation/bpftool-feature.rst
>>>>> +++ b/tools/bpf/bpftool/Documentation/bpftool-feature.rst
>>>>> @@ -39,6 +39,10 @@ DESCRIPTION
>>>>>             names when including the output of this command as a header
>>>>>             file.
>>>>>   +          Note that when probed, some eBPF helpers (e.g.
>>>>> +          **bpf_trace_printk**\ () or **bpf_probe_write_user**\ ()) may
>>>>> +          print warnings to kernel logs.
>>>>> +
>>>>>       **bpftool feature help**
>>>>>             Print short help message.
>>>>>   diff --git a/tools/bpf/bpftool/feature.c b/tools/bpf/bpftool/feature.c
>>>>> index 85928f172413..77221fff6ba9 100644
>>>>> --- a/tools/bpf/bpftool/feature.c
>>>>> +++ b/tools/bpf/bpftool/feature.c
>>>>> @@ -24,6 +24,113 @@ enum probe_component {
>>>>>       COMPONENT_KERNEL,
>>>>>   };
>>>>>   +#define MAX_HELPER_NAME_LEN 32
>>>>> +struct helper_param {
>>>>> +    enum bpf_prog_type progtype;
>>>>> +    const char name[MAX_HELPER_NAME_LEN];
>>>>> +};
>>>>> +
>>>>> +/* helper_progtype_and_name[index] associates to the BPF helper function of id
>>>>> + * "index" a name and a program type to run this helper with. In order to probe
>>>>> + * helper availability for programs offloaded to a network device, use
>>>>> + * offload-compatible types (e.g. XDP) everywhere we can. Caveats: helper
>>>>> + * probing may fail currently if only TC (but not XDP) is supported for
>>>>> + * offload.
>>>>> + */
>>>>> +static const struct helper_param helper_progtype_and_name[] = {
>>>>> +    { BPF_PROG_TYPE_XDP,        "no_helper_with_id_0" },
>>>>> +    { BPF_PROG_TYPE_XDP,        "bpf_map_lookup_elem" },
>>>>> +    { BPF_PROG_TYPE_XDP,        "bpf_map_update_elem" },
>>>>> +    { BPF_PROG_TYPE_XDP,        "bpf_map_delete_elem" },
>>>>> +    { BPF_PROG_TYPE_KPROBE,        "bpf_probe_read" },
>>>>> +    { BPF_PROG_TYPE_XDP,        "bpf_ktime_get_ns" },
>>>>> +    { BPF_PROG_TYPE_XDP,        "bpf_trace_printk" },
>>>>> +    { BPF_PROG_TYPE_XDP,        "bpf_get_prandom_u32" },
>>>>> +    { BPF_PROG_TYPE_XDP,        "bpf_get_smp_processor_id" },
>>>>> +    { BPF_PROG_TYPE_SCHED_CLS,    "bpf_skb_store_bytes" },
>>>>> +    { BPF_PROG_TYPE_SCHED_CLS,    "bpf_l3_csum_replace" },
>>>>> +    { BPF_PROG_TYPE_SCHED_CLS,    "bpf_l4_csum_replace" },
>>>>> +    { BPF_PROG_TYPE_XDP,        "bpf_tail_call" },
>>>>> +    { BPF_PROG_TYPE_SCHED_CLS,    "bpf_clone_redirect" },
>>>>> +    { BPF_PROG_TYPE_KPROBE,        "bpf_get_current_pid_tgid" },
>>>>> +    { BPF_PROG_TYPE_KPROBE,        "bpf_get_current_uid_gid" },
>>>>> +    { BPF_PROG_TYPE_KPROBE,        "bpf_get_current_comm" },
>>>>> +    { BPF_PROG_TYPE_SCHED_CLS,    "bpf_get_cgroup_classid" },
>>>>> +    { BPF_PROG_TYPE_SCHED_CLS,    "bpf_skb_vlan_push" },
>>>>> +    { BPF_PROG_TYPE_SCHED_CLS,    "bpf_skb_vlan_pop" },
>>>>> +    { BPF_PROG_TYPE_SCHED_CLS,    "bpf_skb_get_tunnel_key" },
>>>>> +    { BPF_PROG_TYPE_SCHED_CLS,    "bpf_skb_set_tunnel_key" },
>>>>> +    { BPF_PROG_TYPE_KPROBE,        "bpf_perf_event_read" },
>>>>> +    { BPF_PROG_TYPE_XDP,        "bpf_redirect" },
>>>>> +    { BPF_PROG_TYPE_SCHED_CLS,    "bpf_get_route_realm" },
>>>>> +    { BPF_PROG_TYPE_XDP,        "bpf_perf_event_output" },
>>>>> +    { BPF_PROG_TYPE_SCHED_CLS,    "bpf_skb_load_bytes" },
>>>>> +    { BPF_PROG_TYPE_KPROBE,        "bpf_get_stackid" },
>>>>> +    { BPF_PROG_TYPE_XDP,        "bpf_csum_diff" },
>>>>> +    { BPF_PROG_TYPE_SCHED_CLS,    "bpf_skb_get_tunnel_opt" },
>>>>> +    { BPF_PROG_TYPE_SCHED_CLS,    "bpf_skb_set_tunnel_opt" },
>>>>> +    { BPF_PROG_TYPE_SCHED_CLS,    "bpf_skb_change_proto" },
>>>>> +    { BPF_PROG_TYPE_SCHED_CLS,    "bpf_skb_change_type" },
>>>>> +    { BPF_PROG_TYPE_SCHED_CLS,    "bpf_skb_under_cgroup" },
>>>>> +    { BPF_PROG_TYPE_SCHED_CLS,    "bpf_get_hash_recalc" },
>>>>> +    { BPF_PROG_TYPE_KPROBE,        "bpf_get_current_task" },
>>>>> +    { BPF_PROG_TYPE_KPROBE,        "bpf_probe_write_user" },
>>>>> +    { BPF_PROG_TYPE_KPROBE,        "bpf_current_task_under_cgroup" },
>>>>> +    { BPF_PROG_TYPE_SCHED_CLS,    "bpf_skb_change_tail" },
>>>>> +    { BPF_PROG_TYPE_SCHED_CLS,    "bpf_skb_pull_data" },
>>>>> +    { BPF_PROG_TYPE_SCHED_CLS,    "bpf_csum_update" },
>>>>> +    { BPF_PROG_TYPE_SCHED_CLS,    "bpf_set_hash_invalid" },
>>>>> +    { BPF_PROG_TYPE_XDP,        "bpf_get_numa_node_id" },
>>>>> +    { BPF_PROG_TYPE_SK_SKB,        "bpf_skb_change_head" },
>>>>> +    { BPF_PROG_TYPE_XDP,        "bpf_xdp_adjust_head" },
>>>>> +    { BPF_PROG_TYPE_KPROBE,        "bpf_probe_read_str" },
>>>>> +    { BPF_PROG_TYPE_SCHED_CLS,    "bpf_get_socket_cookie" },
>>>>> +    { BPF_PROG_TYPE_SCHED_CLS,    "bpf_get_socket_uid" },
>>>>> +    { BPF_PROG_TYPE_SCHED_CLS,    "bpf_set_hash" },
>>>>> +    { BPF_PROG_TYPE_SOCK_OPS,    "bpf_setsockopt" },
>>>>> +    { BPF_PROG_TYPE_SCHED_CLS,    "bpf_skb_adjust_room" },
>>>>> +    { BPF_PROG_TYPE_XDP,        "bpf_redirect_map" },
>>>>> +    { BPF_PROG_TYPE_SK_SKB,        "bpf_sk_redirect_map" },
>>>>> +    { BPF_PROG_TYPE_SOCK_OPS,    "bpf_sock_map_update" },
>>>>> +    { BPF_PROG_TYPE_XDP,        "bpf_xdp_adjust_meta" },
>>>>> +    { BPF_PROG_TYPE_KPROBE,        "bpf_perf_event_read_value" },
>>>>> +    { BPF_PROG_TYPE_PERF_EVENT,    "bpf_perf_prog_read_value" },
>>>>> +    { BPF_PROG_TYPE_SOCK_OPS,    "bpf_getsockopt" },
>>>>> +    { BPF_PROG_TYPE_KPROBE,        "bpf_override_return" },
>>>>> +    { BPF_PROG_TYPE_SOCK_OPS,    "bpf_sock_ops_cb_flags_set" },
>>>>> +    { BPF_PROG_TYPE_SK_MSG,        "bpf_msg_redirect_map" },
>>>>> +    { BPF_PROG_TYPE_SK_MSG,        "bpf_msg_apply_bytes" },
>>>>> +    { BPF_PROG_TYPE_SK_MSG,        "bpf_msg_cork_bytes" },
>>>>> +    { BPF_PROG_TYPE_SK_MSG,        "bpf_msg_pull_data" },
>>>>> +    { BPF_PROG_TYPE_CGROUP_SOCK_ADDR,    "bpf_bind" },
>>>>> +    { BPF_PROG_TYPE_XDP,        "bpf_xdp_adjust_tail" },
>>>>> +    { BPF_PROG_TYPE_SCHED_CLS,    "bpf_skb_get_xfrm_state" },
>>>>> +    { BPF_PROG_TYPE_KPROBE,        "bpf_get_stack" },
>>>>> +    { BPF_PROG_TYPE_SCHED_CLS,    "bpf_skb_load_bytes_relative" },
>>>>> +    { BPF_PROG_TYPE_SCHED_CLS,    "bpf_fib_lookup" },
>>>>> +    { BPF_PROG_TYPE_SOCK_OPS,    "bpf_sock_hash_update" },
>>>>> +    { BPF_PROG_TYPE_SK_MSG,        "bpf_msg_redirect_hash" },
>>>>> +    { BPF_PROG_TYPE_SK_SKB,        "bpf_sk_redirect_hash" },
>>>>> +    { BPF_PROG_TYPE_LWT_IN,        "bpf_lwt_push_encap" },
>>>>> +    { BPF_PROG_TYPE_LWT_SEG6LOCAL,    "bpf_lwt_seg6_store_bytes" },
>>>>> +    { BPF_PROG_TYPE_LWT_SEG6LOCAL,    "bpf_lwt_seg6_adjust_srh" },
>>>>> +    { BPF_PROG_TYPE_LWT_SEG6LOCAL,    "bpf_lwt_seg6_action" },
>>>>> +    { BPF_PROG_TYPE_LIRC_MODE2,    "bpf_rc_repeat" },
>>>>> +    { BPF_PROG_TYPE_LIRC_MODE2,    "bpf_rc_keydown" },
>>>>> +    { BPF_PROG_TYPE_SCHED_CLS,    "bpf_skb_cgroup_id" },
>>>>> +    { BPF_PROG_TYPE_KPROBE,        "bpf_get_current_cgroup_id" },
>>>>> +    { BPF_PROG_TYPE_CGROUP_SKB,    "bpf_get_local_storage" },
>>>>> +    { BPF_PROG_TYPE_SK_REUSEPORT,    "bpf_sk_select_reuseport" },
>>>>> +    { BPF_PROG_TYPE_SCHED_CLS,    "bpf_skb_ancestor_cgroup_id" },
>>>>> +    { BPF_PROG_TYPE_SK_SKB,        "bpf_sk_lookup_tcp" },
>>>>> +    { BPF_PROG_TYPE_SK_SKB,        "bpf_sk_lookup_udp" },
>>>>> +    { BPF_PROG_TYPE_SK_SKB,        "bpf_sk_release" },
>>>>> +    { BPF_PROG_TYPE_XDP,        "bpf_map_push_elem" },
>>>>> +    { BPF_PROG_TYPE_XDP,        "bpf_map_pop_elem" },
>>>>> +    { BPF_PROG_TYPE_XDP,        "bpf_map_peek_elem" },
>>>>> +    { BPF_PROG_TYPE_SK_MSG,        "bpf_msg_push_data" },
>>>>
>>>> Some of these helpers like bpf_perf_event_output are available on
>>>> multiple types; should they all be tested in case the one probed
>>>> prog type would not be available on the underlying kernel?
>>>>
>>>> Thanks,
>>>> Daniel
>>>
>>> That's a good point, but it will make things more complicated. We would
>>> need a list of compatible program types for each helper, and then try
>>> them all until one works. I can do that, but I fear this will get huge
>>> and hard to maintain.
>>
>> Hmm, true, one way to overcome this maintenance burden would be to try to
>> brute-force all helpers over all prog types but obviously from verifier
>> side it's more expensive. Perhaps worth testing whether this overhead would
>> be acceptable. On the upside you'd have a listing of all supported helpers
>> for each prog type.
> 
> Having the listing sounds nice. My concern is that the compatibility list for a couple of helpers has been modified in the past (e.g. csum_diff added to XDP), and I fear such changes will be easy to miss.
> 
> Brute-forcing all programs might be doable (programs are only 2-insn long, no jumps) but seems less clean. I can have a look at it. Is there any particular metric I should focus on?
> 
> Naive question, just in case: I don't suppose it is desirable to make the list of supported helpers for each program type accessible to user space? (I guess it would come down to implement those probes as a new bpf() command, which has been rejected before if I remember correctly?)

Yep, because what this basically is testing is verifier behavior in general
where the helper aspect is one specific case of accept / reject, but there can
be more subtle probes on verifier behavior that would go beyond just that like
the ones that Cilium provides where we test verifier for register's map id
marking, etc. Such kind of things are not feasible to expose in uapi in long
term as "capability" but should be probed instead as you do here.

Thanks,
Daniel

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH bpf-next 3/8] tools: bpftool: add probes for kernel configuration options
  2018-12-15  3:32     ` Quentin Monnet
@ 2018-12-19 18:49       ` Quentin Monnet
  0 siblings, 0 replies; 41+ messages in thread
From: Quentin Monnet @ 2018-12-19 18:49 UTC (permalink / raw)
  To: Daniel Borkmann, Alexei Starovoitov
  Cc: netdev, oss-drivers, Arnaldo Carvalho de Melo,
	Jesper Dangaard Brouer, Stanislav Fomichev

2018-12-15 03:32 UTC+0000 ~ Quentin Monnet <quentin.monnet@netronome.com>
> 2018-12-15 00:56 UTC+0100 ~ Daniel Borkmann <daniel@iogearbox.net>
>> On 12/13/2018 01:19 PM, Quentin Monnet wrote:
>>> Add probes to dump a number of options set (or not set) for compiling
>>> the kernel image. These parameters provide information about what BPF
>>> components should be available on the system. A number of them are not
>>> directly related to eBPF, but are in fact used in the kernel as
>>> conditions on which to compile, or not to compile, some of the eBPF
>>> helper functions.
>>>
>>> Sample output:
>>>
>>>     # bpftool feature probe kernel
>>>     Scanning system configuration...
>>>     ...
>>>     CONFIG_BPF is set to y
>>>     CONFIG_BPF_SYSCALL is set to y
>>>     CONFIG_HAVE_EBPF_JIT is set to y
>>>     ...
>>>
>>>     # bpftool --pretty --json feature probe kernel
>>>     {
>>>         "system_config": {
>>>             ...
>>>             "CONFIG_BPF": "y",
>>>             "CONFIG_BPF_SYSCALL": "y",
>>>             "CONFIG_HAVE_EBPF_JIT": "y",
>>>             ...
>>>         }
>>>     }
>>>
>>>     # bpftool feature probe kernel macros prefix BPFTOOL_
>>>     /*** System configuration ***/
>>>     ...
>>>     #define BPFTOOL_CONFIG_BPF y
>>>     #define BPFTOOL_CONFIG_BPF_SYSCALL y
>>>     #define BPFTOOL_CONFIG_HAVE_EBPF_JIT y
>>>     ...
>>
>> Looks reasonable. I think as a user next question that would
>> follow-up from it would be whether this set of config means
>> that e.g. requirements for XDP, cgroups bpf, tracing or xyz is
>> fulfilled. Perhaps it makes sense to split the options[] into
>> base_options[], bpf_trace_options[], bpf_tc_options[] etc such
>> that it might become obvious that base_options[] + bpf_tc_options[]
>> are supported and thus cls_bpf could be used. I'd see this part
>> here in general more as giving a hint to the user in that some
>> basic assumptions could be made and providing some info on the
>> misc ones on what might potentially be missing. Though more
>> concrete info would come from the actual helper / map / prog
>> type probing.
> 
> Good idea. I admit that the list of options dumped with no explanations
> whatsoever is hard to interpret. I'll try to divide the list into
> meaningful subsections.

Hi Daniel, I've been looking into this and I have some trouble figuring
out how to group those options. I could think of something like the
following:

	base_options:
		CONFIG_BPF
		CONFIG_BPF_SYSCALL

	jit_options:
		CONFIG_HAVE_EBPF_JIT
		CONFIG_BPF_JIT
		CONFIG_BPF_JIT_ALWAYS_ON

	events_options:
		CONFIG_BPF_EVENTS

	net_options:
		CONFIG_NET

	tc_options:
		CONFIG_NET_ACT_BPF
		CONFIG_NET_CLS_ACT
		CONFIG_NET_CLS_BPF
		CONFIG_NET_SCH_INGRESS

	cgroup_options:
		CONFIG_CGROUPS
		CONFIG_CGROUP_BPF
		CONFIG_CGROUP_NET_CLASSID

	options for specific program types:
		CONFIG_LWTUNNEL_BPF
		CONFIG_XDP_SOCKETS
		CONFIG_BPF_LIRC_MODE2
		CONFIG_SOCK_CGROUP_DATA
		CONFIG_IPV6_SEG6_BPF
		CONFIG_BPF_STREAM_PARSER

	options related to specific helpers:
		CONFIG_IP_ROUTE_CLASSID		(or in tc_options?)
		CONFIG_XFRM
		CONFIG_BPF_KPROBE_OVERRIDE	(or in events_options?)
		CONFIG_FUNCTION_ERROR_INJECTION (idem?)

	bpf_misc:
		CONFIG_NETFILTER_XT_MATCH_BPF
		CONFIG_TEST_BPF
		CONFIG_BPFILTER
		CONFIG_BPFILTER_UMH

I'm not really sure how to group options for specific types (e.g.
CONFIG_LWTUNNEL_BPF), would they need one subsection each? What about
the options that are only required for some helpers but that do not
change the list of supported prog/map types? I could group them in
progtype_options and helper_options maybe.

Also the idea of checking base_options + net_options + tc_options does
not really provide precise information about whether tc_cls programs
should be supported (I mean on the theoretical, config-option side).
CONFIG_NET_CLS_ACT is not mandatory for example. Same thing for cgroups:
CONFIG_NET_CGROUP_NET_CLASSID is just needed for one helper, if I
remember correctly. Should I take it out of cgroup_options? I think it
would make sense keeping it in that group though, even if it makes this
kind of checks less accurate. Opinions?

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH bpf-next 6/8] tools: bpftool: add probes for eBPF helper functions
  2018-12-18  0:42           ` Daniel Borkmann
@ 2018-12-19 19:02             ` Quentin Monnet
  0 siblings, 0 replies; 41+ messages in thread
From: Quentin Monnet @ 2018-12-19 19:02 UTC (permalink / raw)
  To: Daniel Borkmann, Alexei Starovoitov
  Cc: netdev, oss-drivers, Arnaldo Carvalho de Melo,
	Jesper Dangaard Brouer, Stanislav Fomichev

2018-12-18 01:42 UTC+0100 ~ Daniel Borkmann <daniel@iogearbox.net>
> On 12/17/2018 11:18 AM, Quentin Monnet wrote:
>> 2018-12-16 00:57 UTC+0100 ~ Daniel Borkmann <daniel@iogearbox.net>
>>> On 12/15/2018 04:32 AM, Quentin Monnet wrote:
>>>> 2018-12-15 01:08 UTC+0100 ~ Daniel Borkmann <daniel@iogearbox.net>
>>>>> On 12/13/2018 01:19 PM, Quentin Monnet wrote:
>>>>>> Similarly to what was done for program types and map types, add a set of
>>>>>> probes to test the availability of the different eBPF helper functions
>>>>>> on the current system.
>>>>>>
>>>>>> Sample output:
>>>>>>
>>>>>>      # bpftool feature probe kernel
>>>>>>      ...
>>>>>>      Scanning eBPF helper functions...
>>>>>>      eBPF helper bpf_map_lookup_elem is available
>>>>>>      eBPF helper bpf_map_update_elem is available
>>>>>>      eBPF helper bpf_map_delete_elem is available
>>>>>>      ...
>>>>>>
>>>>>>      # bpftool --json --pretty feature probe kernel
>>>>>>      {
>>>>>>          ...
>>>>>>          "helpers": {
>>>>>>              "have_bpf_map_lookup_elem_helper": true,
>>>>>>              "have_bpf_map_update_elem_helper": true,
>>>>>>              "have_bpf_map_delete_elem_helper": true,
>>>>>>              ...
>>>>>>          }
>>>>>>      }
>>>>>>
>>>>>>      # bpftool feature probe kernel macros prefix BPFTOOL_
>>>>>>      ...
>>>>>>      /*** eBPF helper functions ***/
>>>>>>      #define BPFTOOL_BPF_MAP_LOOKUP_ELEM_HELPER
>>>>>>      #define BPFTOOL_BPF_MAP_UPDATE_ELEM_HELPER
>>>>>>      #define BPFTOOL_BPF_MAP_DELETE_ELEM_HELPER
>>>>>
>>>>> Small nit: instead of BPFTOOL_ prefix, would it make sense
>>>>> to generally use Have_ prefix (similar to json output). The
>>>>> former seems somewhat bpftool related though it solely probes
>>>>> the underlying kernel.
>>>>
>>>> "BPFTOOL_" is provided on the command line ("prefix BPFTOOL_"), and it's
>>>> here just for the example. I initially had a non-configurable "HAVE_"
>>>> prefix instead, but after discussing it with Jakub we thought it best to
>>>> leave the choice of the prefix to the users, so they can choose what
>>>> works best for them, or adapt it and avoid any potential name conflict.
>>>
>>> Ah, good point, makes sense then. As default you have no prefix? Perhaps
>>> there it could be "HAVE_" prefix.
>>
>> Yes, I can probably reinstate it as a default option if none was provided from the command line, for prog/map types and helpers.
>>
>>>>>> Signed-off-by: Quentin Monnet <quentin.monnet@netronome.com>
>>>>>> Reviewed-by: Jakub Kicinski <jakub.kicinski@netronome.com>
>>>>>> ---
>>>>>>   .../bpftool/Documentation/bpftool-feature.rst |   4 +
>>>>>>   tools/bpf/bpftool/feature.c                   | 152 ++++++++++++++++++
>>>>>>   2 files changed, 156 insertions(+)
>>>>>>
>>>>>> diff --git a/tools/bpf/bpftool/Documentation/bpftool-feature.rst b/tools/bpf/bpftool/Documentation/bpftool-feature.rst
>>>>>> index 23920a7490e9..083d30510cce 100644
>>>>>> --- a/tools/bpf/bpftool/Documentation/bpftool-feature.rst
>>>>>> +++ b/tools/bpf/bpftool/Documentation/bpftool-feature.rst
>>>>>> @@ -39,6 +39,10 @@ DESCRIPTION
>>>>>>             names when including the output of this command as a header
>>>>>>             file.
>>>>>>   +          Note that when probed, some eBPF helpers (e.g.
>>>>>> +          **bpf_trace_printk**\ () or **bpf_probe_write_user**\ ()) may
>>>>>> +          print warnings to kernel logs.
>>>>>> +
>>>>>>       **bpftool feature help**
>>>>>>             Print short help message.
>>>>>>   diff --git a/tools/bpf/bpftool/feature.c b/tools/bpf/bpftool/feature.c
>>>>>> index 85928f172413..77221fff6ba9 100644
>>>>>> --- a/tools/bpf/bpftool/feature.c
>>>>>> +++ b/tools/bpf/bpftool/feature.c
>>>>>> @@ -24,6 +24,113 @@ enum probe_component {
>>>>>>       COMPONENT_KERNEL,
>>>>>>   };
>>>>>>   +#define MAX_HELPER_NAME_LEN 32
>>>>>> +struct helper_param {
>>>>>> +    enum bpf_prog_type progtype;
>>>>>> +    const char name[MAX_HELPER_NAME_LEN];
>>>>>> +};
>>>>>> +
>>>>>> +/* helper_progtype_and_name[index] associates to the BPF helper function of id
>>>>>> + * "index" a name and a program type to run this helper with. In order to probe
>>>>>> + * helper availability for programs offloaded to a network device, use
>>>>>> + * offload-compatible types (e.g. XDP) everywhere we can. Caveats: helper
>>>>>> + * probing may fail currently if only TC (but not XDP) is supported for
>>>>>> + * offload.
>>>>>> + */
>>>>>> +static const struct helper_param helper_progtype_and_name[] = {
>>>>>> +    { BPF_PROG_TYPE_XDP,        "no_helper_with_id_0" },
>>>>>> +    { BPF_PROG_TYPE_XDP,        "bpf_map_lookup_elem" },
>>>>>> +    { BPF_PROG_TYPE_XDP,        "bpf_map_update_elem" },
>>>>>> +    { BPF_PROG_TYPE_XDP,        "bpf_map_delete_elem" },
>>>>>> +    { BPF_PROG_TYPE_KPROBE,        "bpf_probe_read" },
>>>>>> +    { BPF_PROG_TYPE_XDP,        "bpf_ktime_get_ns" },
>>>>>> +    { BPF_PROG_TYPE_XDP,        "bpf_trace_printk" },
>>>>>> +    { BPF_PROG_TYPE_XDP,        "bpf_get_prandom_u32" },
>>>>>> +    { BPF_PROG_TYPE_XDP,        "bpf_get_smp_processor_id" },
>>>>>> +    { BPF_PROG_TYPE_SCHED_CLS,    "bpf_skb_store_bytes" },
>>>>>> +    { BPF_PROG_TYPE_SCHED_CLS,    "bpf_l3_csum_replace" },
>>>>>> +    { BPF_PROG_TYPE_SCHED_CLS,    "bpf_l4_csum_replace" },
>>>>>> +    { BPF_PROG_TYPE_XDP,        "bpf_tail_call" },
>>>>>> +    { BPF_PROG_TYPE_SCHED_CLS,    "bpf_clone_redirect" },
>>>>>> +    { BPF_PROG_TYPE_KPROBE,        "bpf_get_current_pid_tgid" },
>>>>>> +    { BPF_PROG_TYPE_KPROBE,        "bpf_get_current_uid_gid" },
>>>>>> +    { BPF_PROG_TYPE_KPROBE,        "bpf_get_current_comm" },
>>>>>> +    { BPF_PROG_TYPE_SCHED_CLS,    "bpf_get_cgroup_classid" },
>>>>>> +    { BPF_PROG_TYPE_SCHED_CLS,    "bpf_skb_vlan_push" },
>>>>>> +    { BPF_PROG_TYPE_SCHED_CLS,    "bpf_skb_vlan_pop" },
>>>>>> +    { BPF_PROG_TYPE_SCHED_CLS,    "bpf_skb_get_tunnel_key" },
>>>>>> +    { BPF_PROG_TYPE_SCHED_CLS,    "bpf_skb_set_tunnel_key" },
>>>>>> +    { BPF_PROG_TYPE_KPROBE,        "bpf_perf_event_read" },
>>>>>> +    { BPF_PROG_TYPE_XDP,        "bpf_redirect" },
>>>>>> +    { BPF_PROG_TYPE_SCHED_CLS,    "bpf_get_route_realm" },
>>>>>> +    { BPF_PROG_TYPE_XDP,        "bpf_perf_event_output" },
>>>>>> +    { BPF_PROG_TYPE_SCHED_CLS,    "bpf_skb_load_bytes" },
>>>>>> +    { BPF_PROG_TYPE_KPROBE,        "bpf_get_stackid" },
>>>>>> +    { BPF_PROG_TYPE_XDP,        "bpf_csum_diff" },
>>>>>> +    { BPF_PROG_TYPE_SCHED_CLS,    "bpf_skb_get_tunnel_opt" },
>>>>>> +    { BPF_PROG_TYPE_SCHED_CLS,    "bpf_skb_set_tunnel_opt" },
>>>>>> +    { BPF_PROG_TYPE_SCHED_CLS,    "bpf_skb_change_proto" },
>>>>>> +    { BPF_PROG_TYPE_SCHED_CLS,    "bpf_skb_change_type" },
>>>>>> +    { BPF_PROG_TYPE_SCHED_CLS,    "bpf_skb_under_cgroup" },
>>>>>> +    { BPF_PROG_TYPE_SCHED_CLS,    "bpf_get_hash_recalc" },
>>>>>> +    { BPF_PROG_TYPE_KPROBE,        "bpf_get_current_task" },
>>>>>> +    { BPF_PROG_TYPE_KPROBE,        "bpf_probe_write_user" },
>>>>>> +    { BPF_PROG_TYPE_KPROBE,        "bpf_current_task_under_cgroup" },
>>>>>> +    { BPF_PROG_TYPE_SCHED_CLS,    "bpf_skb_change_tail" },
>>>>>> +    { BPF_PROG_TYPE_SCHED_CLS,    "bpf_skb_pull_data" },
>>>>>> +    { BPF_PROG_TYPE_SCHED_CLS,    "bpf_csum_update" },
>>>>>> +    { BPF_PROG_TYPE_SCHED_CLS,    "bpf_set_hash_invalid" },
>>>>>> +    { BPF_PROG_TYPE_XDP,        "bpf_get_numa_node_id" },
>>>>>> +    { BPF_PROG_TYPE_SK_SKB,        "bpf_skb_change_head" },
>>>>>> +    { BPF_PROG_TYPE_XDP,        "bpf_xdp_adjust_head" },
>>>>>> +    { BPF_PROG_TYPE_KPROBE,        "bpf_probe_read_str" },
>>>>>> +    { BPF_PROG_TYPE_SCHED_CLS,    "bpf_get_socket_cookie" },
>>>>>> +    { BPF_PROG_TYPE_SCHED_CLS,    "bpf_get_socket_uid" },
>>>>>> +    { BPF_PROG_TYPE_SCHED_CLS,    "bpf_set_hash" },
>>>>>> +    { BPF_PROG_TYPE_SOCK_OPS,    "bpf_setsockopt" },
>>>>>> +    { BPF_PROG_TYPE_SCHED_CLS,    "bpf_skb_adjust_room" },
>>>>>> +    { BPF_PROG_TYPE_XDP,        "bpf_redirect_map" },
>>>>>> +    { BPF_PROG_TYPE_SK_SKB,        "bpf_sk_redirect_map" },
>>>>>> +    { BPF_PROG_TYPE_SOCK_OPS,    "bpf_sock_map_update" },
>>>>>> +    { BPF_PROG_TYPE_XDP,        "bpf_xdp_adjust_meta" },
>>>>>> +    { BPF_PROG_TYPE_KPROBE,        "bpf_perf_event_read_value" },
>>>>>> +    { BPF_PROG_TYPE_PERF_EVENT,    "bpf_perf_prog_read_value" },
>>>>>> +    { BPF_PROG_TYPE_SOCK_OPS,    "bpf_getsockopt" },
>>>>>> +    { BPF_PROG_TYPE_KPROBE,        "bpf_override_return" },
>>>>>> +    { BPF_PROG_TYPE_SOCK_OPS,    "bpf_sock_ops_cb_flags_set" },
>>>>>> +    { BPF_PROG_TYPE_SK_MSG,        "bpf_msg_redirect_map" },
>>>>>> +    { BPF_PROG_TYPE_SK_MSG,        "bpf_msg_apply_bytes" },
>>>>>> +    { BPF_PROG_TYPE_SK_MSG,        "bpf_msg_cork_bytes" },
>>>>>> +    { BPF_PROG_TYPE_SK_MSG,        "bpf_msg_pull_data" },
>>>>>> +    { BPF_PROG_TYPE_CGROUP_SOCK_ADDR,    "bpf_bind" },
>>>>>> +    { BPF_PROG_TYPE_XDP,        "bpf_xdp_adjust_tail" },
>>>>>> +    { BPF_PROG_TYPE_SCHED_CLS,    "bpf_skb_get_xfrm_state" },
>>>>>> +    { BPF_PROG_TYPE_KPROBE,        "bpf_get_stack" },
>>>>>> +    { BPF_PROG_TYPE_SCHED_CLS,    "bpf_skb_load_bytes_relative" },
>>>>>> +    { BPF_PROG_TYPE_SCHED_CLS,    "bpf_fib_lookup" },
>>>>>> +    { BPF_PROG_TYPE_SOCK_OPS,    "bpf_sock_hash_update" },
>>>>>> +    { BPF_PROG_TYPE_SK_MSG,        "bpf_msg_redirect_hash" },
>>>>>> +    { BPF_PROG_TYPE_SK_SKB,        "bpf_sk_redirect_hash" },
>>>>>> +    { BPF_PROG_TYPE_LWT_IN,        "bpf_lwt_push_encap" },
>>>>>> +    { BPF_PROG_TYPE_LWT_SEG6LOCAL,    "bpf_lwt_seg6_store_bytes" },
>>>>>> +    { BPF_PROG_TYPE_LWT_SEG6LOCAL,    "bpf_lwt_seg6_adjust_srh" },
>>>>>> +    { BPF_PROG_TYPE_LWT_SEG6LOCAL,    "bpf_lwt_seg6_action" },
>>>>>> +    { BPF_PROG_TYPE_LIRC_MODE2,    "bpf_rc_repeat" },
>>>>>> +    { BPF_PROG_TYPE_LIRC_MODE2,    "bpf_rc_keydown" },
>>>>>> +    { BPF_PROG_TYPE_SCHED_CLS,    "bpf_skb_cgroup_id" },
>>>>>> +    { BPF_PROG_TYPE_KPROBE,        "bpf_get_current_cgroup_id" },
>>>>>> +    { BPF_PROG_TYPE_CGROUP_SKB,    "bpf_get_local_storage" },
>>>>>> +    { BPF_PROG_TYPE_SK_REUSEPORT,    "bpf_sk_select_reuseport" },
>>>>>> +    { BPF_PROG_TYPE_SCHED_CLS,    "bpf_skb_ancestor_cgroup_id" },
>>>>>> +    { BPF_PROG_TYPE_SK_SKB,        "bpf_sk_lookup_tcp" },
>>>>>> +    { BPF_PROG_TYPE_SK_SKB,        "bpf_sk_lookup_udp" },
>>>>>> +    { BPF_PROG_TYPE_SK_SKB,        "bpf_sk_release" },
>>>>>> +    { BPF_PROG_TYPE_XDP,        "bpf_map_push_elem" },
>>>>>> +    { BPF_PROG_TYPE_XDP,        "bpf_map_pop_elem" },
>>>>>> +    { BPF_PROG_TYPE_XDP,        "bpf_map_peek_elem" },
>>>>>> +    { BPF_PROG_TYPE_SK_MSG,        "bpf_msg_push_data" },
>>>>>
>>>>> Some of these helpers like bpf_perf_event_output are available on
>>>>> multiple types; should they all be tested in case the one probed
>>>>> prog type would not be available on the underlying kernel?
>>>>>
>>>>> Thanks,
>>>>> Daniel
>>>>
>>>> That's a good point, but it will make things more complicated. We would
>>>> need a list of compatible program types for each helper, and then try
>>>> them all until one works. I can do that, but I fear this will get huge
>>>> and hard to maintain.
>>>
>>> Hmm, true, one way to overcome this maintenance burden would be to try to
>>> brute-force all helpers over all prog types but obviously from verifier
>>> side it's more expensive. Perhaps worth testing whether this overhead would
>>> be acceptable. On the upside you'd have a listing of all supported helpers
>>> for each prog type.
>>
>> Having the listing sounds nice. My concern is that the compatibility list for a couple of helpers has been modified in the past (e.g. csum_diff added to XDP), and I fear such changes will be easy to miss.
>>
>> Brute-forcing all programs might be doable (programs are only 2-insn long, no jumps) but seems less clean. I can have a look at it. Is there any particular metric I should focus on?
>>
>> Naive question, just in case: I don't suppose it is desirable to make the list of supported helpers for each program type accessible to user space? (I guess it would come down to implement those probes as a new bpf() command, which has been rejected before if I remember correctly?)
> 
> Yep, because what this basically is testing is verifier behavior in general
> where the helper aspect is one specific case of accept / reject, but there can
> be more subtle probes on verifier behavior that would go beyond just that like
> the ones that Cilium provides where we test verifier for register's map id
> marking, etc. Such kind of things are not feasible to expose in uapi in long
> term as "capability" but should be probed instead as you do here.
> 
> Thanks,
> Daniel
> 

Thanks for the clarification.

I've been working on my set to add probing with all supported program
types for each helper. I'm considering printing a list of compatible
program types (as supported by the system) for each helper, like this:

	/*** eBPF helper functions ***/
	...
	#define BPF_SKB_CHANGE_HEAD_HELPER_COMPAT_LIST     ""      \
		"lwt_xmit "     \
		"sk_skb "
	#define BPF_XDP_ADJUST_HEAD_HELPER_COMPAT_LIST     ""      \
		"xdp "
	#define BPF_PROBE_READ_STR_HELPER_COMPAT_LIST      ""      \
		"kprobe "       \
		"tracepoint "   \
		"perf_event "   \
		"raw_tracepoint "
	...

or in JSON:

	{
	    ...
	    "helpers": {
	        ...
		"bpf_skb_change_head_compat_list": ["lwt_xmit","sk_skb"
		],
		"bpf_xdp_adjust_head_compat_list": ["xdp"
		],
		"bpf_probe_read_str_compat_list": \
	            ["kprobe","tracepoint","perf_event","raw_tracepoint"
		],
	    ...
	    }
	}

Would this be acceptable?

Thanks,
Quentin

^ permalink raw reply	[flat|nested] 41+ messages in thread

end of thread, other threads:[~2018-12-19 19:02 UTC | newest]

Thread overview: 41+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-12-13 12:19 [PATCH bpf-next 0/8] tools: bpftool: add probes for system and device Quentin Monnet
2018-12-13 12:19 ` [PATCH bpf-next 1/8] tools: bpftool: add basic probe capability, probe syscall and kversion Quentin Monnet
2018-12-14  2:50   ` Stanislav Fomichev
2018-12-14 11:27     ` Quentin Monnet
2018-12-14 18:45       ` Stanislav Fomichev
2018-12-15  3:31         ` Quentin Monnet
2018-12-14 23:35   ` Daniel Borkmann
2018-12-15  3:31     ` Quentin Monnet
2018-12-13 12:19 ` [PATCH bpf-next 2/8] tools: bpftool: add probes for /proc/ eBPF parameters Quentin Monnet
2018-12-14  2:58   ` Stanislav Fomichev
2018-12-14 11:27     ` Quentin Monnet
2018-12-14 23:40   ` Daniel Borkmann
2018-12-15  3:31     ` Quentin Monnet
2018-12-16  0:14       ` Daniel Borkmann
2018-12-17 10:44         ` Quentin Monnet
2018-12-17 11:11           ` Daniel Borkmann
2018-12-13 12:19 ` [PATCH bpf-next 3/8] tools: bpftool: add probes for kernel configuration options Quentin Monnet
2018-12-14 23:56   ` Daniel Borkmann
2018-12-15  3:32     ` Quentin Monnet
2018-12-19 18:49       ` Quentin Monnet
2018-12-13 12:19 ` [PATCH bpf-next 4/8] tools: bpftool: add probes for eBPF program types Quentin Monnet
2018-12-13 12:19 ` [PATCH bpf-next 5/8] tools: bpftool: add probes for eBPF map types Quentin Monnet
2018-12-13 12:19 ` [PATCH bpf-next 6/8] tools: bpftool: add probes for eBPF helper functions Quentin Monnet
2018-12-15  0:08   ` Daniel Borkmann
2018-12-15  3:32     ` Quentin Monnet
2018-12-15 23:57       ` Daniel Borkmann
2018-12-17 10:18         ` Quentin Monnet
2018-12-18  0:42           ` Daniel Borkmann
2018-12-19 19:02             ` Quentin Monnet
2018-12-13 12:19 ` [PATCH bpf-next 7/8] tools: bpftool: add probes for a network device Quentin Monnet
2018-12-13 12:19 ` [PATCH bpf-next 8/8] tools: bpftool: add bash completion for bpftool probes Quentin Monnet
2018-12-13 13:03 ` [PATCH bpf-next 0/8] tools: bpftool: add probes for system and device Arnaldo Carvalho de Melo
2018-12-13 13:49   ` Debugging eBPF was: " Arnaldo Carvalho de Melo
2018-12-13 20:55     ` Alexei Starovoitov
2018-12-14 13:39       ` Arnaldo Carvalho de Melo
2018-12-14 11:53 ` Quentin Monnet
2018-12-14 18:21   ` Stanislav Fomichev
2018-12-14 18:41     ` [oss-drivers] " Quentin Monnet
2018-12-14 14:00 ` Arnaldo Carvalho de Melo
2018-12-14 14:56   ` Quentin Monnet
2018-12-14 17:26     ` Arnaldo Carvalho de Melo

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.