netdev.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [RFC bpf-next v3 0/9] tools: bpftool: add probes for system and device
@ 2019-01-03 14:02 Quentin Monnet
  2019-01-03 14:02 ` [RFC bpf-next v3 1/9] tools: bpftool: add basic probe capability, probe syscall availability Quentin Monnet
                   ` (8 more replies)
  0 siblings, 9 replies; 18+ messages in thread
From: Quentin Monnet @ 2019-01-03 14:02 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 adds 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 some of those parameters (not all) as a series of
      "#define" directives, that can be included into a C header file for
      example.

Probes for supported program and map types, and supported helpers, are
directly added to libbpf, so that other applications (or selftests) can
reuse them as necessary.

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.

v3
- Do not probe kernel version in bpftool (just retrieve it to probe support
  for kprobes in libbpf).
- Change the way results for helper support is displayed: now one list of
  compatible helpers for each program type (and C-style output gets a
  HAVE_PROG_TYPE_HELPER(prog_type, helper) macro to help with tests. See
  patches 6, 7.
- Address other comments from feedback from v2 (please refer to individual
  patches' history).

v2 (please also refer to individual patches' history):
- Move probes for prog/map types, helpers, from bpftool to libbpf.
- Move C-style output as a separate patch, and restrict it to a subset of
  collected information (bpf() availability, prog/map types, helpers).
- Now probe helpers with all supported program types, and display a list of
  compatible program types (as supported on the system) for each helper.
- NOT addressed: grouping compilation options for kernel into subsections
  (patch 3) (I don't see an easy way of grouping them at the moment, please
  see also the discussion on v1 thread).

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

Quentin Monnet (9):
  tools: bpftool: add basic probe capability, probe syscall availability
  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 C-style "#define" output for probes
  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/feature.c                   | 701 ++++++++++++++++++
 tools/bpf/bpftool/main.c                      |   3 +-
 tools/bpf/bpftool/main.h                      |   4 +
 tools/bpf/bpftool/map.c                       |   4 +-
 tools/lib/bpf/Build                           |   2 +-
 tools/lib/bpf/libbpf.h                        |  14 +
 tools/lib/bpf/libbpf.map                      |   3 +
 tools/lib/bpf/libbpf_probes.c                 | 241 ++++++
 16 files changed, 1079 insertions(+), 3 deletions(-)
 create mode 100644 tools/bpf/bpftool/Documentation/bpftool-feature.rst
 create mode 100644 tools/bpf/bpftool/feature.c
 create mode 100644 tools/lib/bpf/libbpf_probes.c

-- 
2.17.1

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

* [RFC bpf-next v3 1/9] tools: bpftool: add basic probe capability, probe syscall availability
  2019-01-03 14:02 [RFC bpf-next v3 0/9] tools: bpftool: add probes for system and device Quentin Monnet
@ 2019-01-03 14:02 ` Quentin Monnet
  2019-01-03 14:02 ` [RFC bpf-next v3 2/9] tools: bpftool: add probes for /proc/ eBPF parameters Quentin Monnet
                   ` (7 subsequent siblings)
  8 siblings, 0 replies; 18+ messages in thread
From: Quentin Monnet @ 2019-01-03 14:02 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).

The current patch introduces probing of one simple parameter:
availability of the bpf() system call. Later commits
will add other probes.

Sample output:

    # bpftool feature probe kernel
    Scanning system call availability...
    bpf() syscall is available

    # bpftool --json --pretty feature probe kernel
    {
        "syscall_config": {
            "have_bpf_syscall": true
        }
    }

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.

v3:
- Do not probe kernel version. Contrarily to what is written below for
  v2, we can have the kernel version retrieved in libbpf instead of
  bpftool (in the patch adding probing for program types).

v2:
- Remove C-style macros output from this patch.
- Even though kernel version is no longer needed for testing kprobes
  availability, note that we still collect it in this patch so that
  bpftool gets able to probe (in next patches) older kernels as well.

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 |  60 ++++++++
 .../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                   | 131 ++++++++++++++++++
 tools/bpf/bpftool/main.c                      |   3 +-
 tools/bpf/bpftool/main.h                      |   1 +
 10 files changed, 200 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..40ac13c0b782
--- /dev/null
+++ b/tools/bpf/bpftool/Documentation/bpftool-feature.rst
@@ -0,0 +1,60 @@
+===============
+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**]
+|	**bpftool** **feature help**
+
+DESCRIPTION
+===========
+	**bpftool feature probe** [**kernel**]
+		  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.
+
+	**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 64b001b4f777..eafdc9f76694 100644
--- a/tools/bpf/bpftool/Documentation/bpftool-map.rst
+++ b/tools/bpf/bpftool/Documentation/bpftool-map.rst
@@ -236,5 +236,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 58c8369b77dd..13b56102f528 100644
--- a/tools/bpf/bpftool/Documentation/bpftool-prog.rst
+++ b/tools/bpf/bpftool/Documentation/bpftool-prog.rst
@@ -258,5 +258,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 e1677e81ed59..27153bb816ac 100644
--- a/tools/bpf/bpftool/Documentation/bpftool.rst
+++ b/tools/bpf/bpftool/Documentation/bpftool.rst
@@ -72,5 +72,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..954fb12a5228
--- /dev/null
+++ b/tools/bpf/bpftool/feature.c
@@ -0,0 +1,131 @@
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+/* Copyright (c) 2019 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 *plain_name, bool res)
+{
+	if (json_output)
+		jsonw_bool_field(json_wtr, feat_name, res);
+	else
+		printf("%s is %savailable\n", plain_name, res ? "" : "NOT ");
+}
+
+static void
+print_start_section(const char *json_title, const char *plain_title)
+{
+	if (json_output) {
+		jsonw_name(json_wtr, json_title);
+		jsonw_start_object(json_wtr);
+	} else {
+		printf("%s\n", plain_title);
+	}
+}
+
+/* Probing functions */
+
+static bool probe_bpf_syscall(void)
+{
+	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",
+			   res);
+
+	return res;
+}
+
+static int do_probe(int argc, char **argv)
+{
+	enum probe_component target = COMPONENT_UNSPEC;
+
+	/* 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 {
+			p_err("expected no more arguments, 'kernel', got: '%s'?",
+			      *argv);
+			return -1;
+		}
+	}
+
+	if (json_output)
+		jsonw_start_object(json_wtr);
+
+	print_start_section("syscall_config",
+			    "Scanning system call availability...");
+
+	probe_bpf_syscall();
+
+	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]\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 f44a1c2c4ea0..a9d5e9e6a732 100644
--- a/tools/bpf/bpftool/main.c
+++ b/tools/bpf/bpftool/main.c
@@ -56,7 +56,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);
@@ -187,6 +187,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 052c91d4dc55..5cfc6601de9b 100644
--- a/tools/bpf/bpftool/main.h
+++ b/tools/bpf/bpftool/main.h
@@ -145,6 +145,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] 18+ messages in thread

* [RFC bpf-next v3 2/9] tools: bpftool: add probes for /proc/ eBPF parameters
  2019-01-03 14:02 [RFC bpf-next v3 0/9] tools: bpftool: add probes for system and device Quentin Monnet
  2019-01-03 14:02 ` [RFC bpf-next v3 1/9] tools: bpftool: add basic probe capability, probe syscall availability Quentin Monnet
@ 2019-01-03 14:02 ` Quentin Monnet
  2019-01-04  6:32   ` Y Song
  2019-01-03 14:02 ` [RFC bpf-next v3 3/9] tools: bpftool: add probes for kernel configuration options Quentin Monnet
                   ` (6 subsequent siblings)
  8 siblings, 1 reply; 18+ messages in thread
From: Quentin Monnet @ 2019-01-03 14:02 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
        },
        ...
    }

These probes are skipped if procfs is not mounted.

v2:
- Remove C-style macros output from this patch.

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

diff --git a/tools/bpf/bpftool/feature.c b/tools/bpf/bpftool/feature.c
index 954fb12a5228..37fe79f59015 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
@@ -42,6 +61,135 @@ print_start_section(const char *json_title, const char *plain_title)
 
 /* 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(void)
+{
+	int res;
+
+	res = read_procfs("/proc/sys/kernel/unprivileged_bpf_disabled");
+	if (json_output) {
+		jsonw_int_field(json_wtr, "unprivileged_bpf_disabled", res);
+	} 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(void)
+{
+	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 {
+		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(void)
+{
+	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 {
+		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(void)
+{
+	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 {
+		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 bool probe_bpf_syscall(void)
 {
 	bool res;
@@ -88,6 +236,26 @@ 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",
+				    "Scanning system configuration...");
+		if (check_procfs()) {
+			probe_unprivileged_disabled();
+			probe_jit_enable();
+			probe_jit_harden();
+			probe_jit_kallsyms();
+		} 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",
 			    "Scanning system call availability...");
 
-- 
2.17.1

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

* [RFC bpf-next v3 3/9] tools: bpftool: add probes for kernel configuration options
  2019-01-03 14:02 [RFC bpf-next v3 0/9] tools: bpftool: add probes for system and device Quentin Monnet
  2019-01-03 14:02 ` [RFC bpf-next v3 1/9] tools: bpftool: add basic probe capability, probe syscall availability Quentin Monnet
  2019-01-03 14:02 ` [RFC bpf-next v3 2/9] tools: bpftool: add probes for /proc/ eBPF parameters Quentin Monnet
@ 2019-01-03 14:02 ` Quentin Monnet
  2019-01-04  6:35   ` Y Song
  2019-01-03 14:02 ` [RFC bpf-next v3 4/9] tools: bpftool: add probes for eBPF program types Quentin Monnet
                   ` (5 subsequent siblings)
  8 siblings, 1 reply; 18+ messages in thread
From: Quentin Monnet @ 2019-01-03 14:02 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",
            ...
        }
    }

v3:
- Add a comment about /proc/config.gz not being supported as a path for
  the config file at this time.
- Use p_info() instead of p_err() on failure to get options from config
  file, as bpftool keeps probing other parameters and that would
  possibly create duplicate "error" entries for JSON.

v2:
- Remove C-style macros output from this patch.
- NOT addressed: grouping of those config options into subsections
  (I don't see an easy way of grouping them at the moment, please see
  also the discussion on v1 thread).

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

diff --git a/tools/bpf/bpftool/feature.c b/tools/bpf/bpftool/feature.c
index 37fe79f59015..05c16fe67005 100644
--- a/tools/bpf/bpftool/feature.c
+++ b/tools/bpf/bpftool/feature.c
@@ -48,6 +48,30 @@ print_bool_feature(const char *feat_name, const char *plain_name, bool res)
 		printf("%s is %savailable\n", plain_name, res ? "" : "NOT ");
 }
 
+static void print_kernel_option(const char *name, const char *value)
+{
+	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 (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 *plain_title)
 {
@@ -190,6 +214,123 @@ static void probe_jit_kallsyms(void)
 	}
 }
 
+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(void)
+{
+	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) {
+		/* Some distributions put the config file at /proc/config, give
+		 * it a try.
+		 * Sometimes it is also at /proc/config.gz but we do not try
+		 * this one for now, it would require linking against libz.
+		 */
+		fd = fopen("/proc/config", "r");
+	}
+	if (!fd) {
+		p_info("skipping kernel config, can't open file: %s",
+		       strerror(errno));
+		goto no_config;
+	}
+	/* Sanity checks */
+	ret = getline(&buf, &n, fd);
+	ret = getline(&buf, &n, fd);
+	if (!buf || !ret) {
+		p_info("skipping kernel config, can't read from file: %s",
+		       strerror(errno));
+		free(buf);
+		goto no_config;
+	}
+	if (strcmp(buf, "# Automatically generated file; DO NOT EDIT.\n")) {
+		p_info("skipping kernel config, can't find correct 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);
+		free(value);
+	}
+	fclose(fd);
+	return;
+
+no_config:
+	for (i = 0; i < ARRAY_SIZE(options); i++)
+		print_kernel_option(options[i], NULL);
+}
+
 static bool probe_bpf_syscall(void)
 {
 	bool res;
@@ -249,6 +390,7 @@ static int do_probe(int argc, char **argv)
 		} else {
 			p_info("/* procfs not mounted, skipping related probes */");
 		}
+		probe_kernel_image_config();
 		if (json_output)
 			jsonw_end_object(json_wtr);
 		else
-- 
2.17.1

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

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

Introduce probes for supported BPF program types in libbpf, and call it
from bpftool to test what types are available on the system. The probe
simply consists in loading a very basic program of that type and see if
the verifier complains or not.

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,
            ...
        }
    }

v3:
- Get kernel version for checking kprobes availability from libbpf
  instead of from bpftool. Do not pass kernel_version as an argument
  when calling libbpf probes.
- Use a switch with all enum values for setting specific program
  parameters just before probing, so that gcc complains at compile time
  (-Wswitch-enum) if new prog types were added to the kernel but libbpf
  was not updated.
- Add a comment in libbpf.h about setrlimit() usage to allow many
  consecutive probe attempts.

v2:
- Move probes from bpftool to libbpf.
- Remove C-style macros output from this patch.

Signed-off-by: Quentin Monnet <quentin.monnet@netronome.com>
---
 tools/bpf/bpftool/feature.c   | 48 +++++++++++++++++-
 tools/lib/bpf/Build           |  2 +-
 tools/lib/bpf/libbpf.h        | 11 ++++
 tools/lib/bpf/libbpf.map      |  1 +
 tools/lib/bpf/libbpf_probes.c | 95 +++++++++++++++++++++++++++++++++++
 5 files changed, 155 insertions(+), 2 deletions(-)
 create mode 100644 tools/lib/bpf/libbpf_probes.c

diff --git a/tools/bpf/bpftool/feature.c b/tools/bpf/bpftool/feature.c
index 05c16fe67005..8b9e00867000 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) 2019 Netronome Systems, Inc. */
 
+#include <ctype.h>
 #include <errno.h>
 #include <string.h>
 #include <unistd.h>
@@ -11,6 +12,7 @@
 #include <linux/limits.h>
 
 #include <bpf.h>
+#include <libbpf.h>
 
 #include "main.h"
 
@@ -83,6 +85,17 @@ print_start_section(const char *json_title, const char *plain_title)
 	}
 }
 
+static void
+print_end_then_start_section(const char *json_title, const char *plain_title)
+{
+	if (json_output)
+		jsonw_end_object(json_wtr);
+	else
+		printf("\n");
+
+	print_start_section(json_title, plain_title);
+}
+
 /* Probing functions */
 
 static int read_procfs(const char *path)
@@ -345,9 +358,33 @@ static bool probe_bpf_syscall(void)
 	return res;
 }
 
+static void probe_prog_type(enum bpf_prog_type prog_type, bool *supported_types)
+{
+	const char *plain_comment = "eBPF program_type ";
+	char feat_name[128], plain_desc[128];
+	size_t maxlen;
+	bool res;
+
+	res = bpf_probe_prog_type(prog_type, 0);
+
+	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(plain_desc, "%s%s", plain_comment, prog_type_name[prog_type]);
+	print_bool_feature(feat_name, plain_desc, res);
+}
+
 static int do_probe(int argc, char **argv)
 {
 	enum probe_component target = COMPONENT_UNSPEC;
+	bool supported_types[128] = {};
+	unsigned int i;
 
 	/* Detection assumes user has sufficient privileges (CAP_SYS_ADMIN).
 	 * Let's approximate, and restrict usage to root user only.
@@ -401,8 +438,17 @@ static int do_probe(int argc, char **argv)
 	print_start_section("syscall_config",
 			    "Scanning system call availability...");
 
-	probe_bpf_syscall();
+	if (!probe_bpf_syscall())
+		/* bpf() syscall unavailable, don't probe other BPF features */
+		goto exit_close_json;
+
+	print_end_then_start_section("program_types",
+				     "Scanning eBPF program types...");
+
+	for (i = BPF_PROG_TYPE_UNSPEC + 1; i < ARRAY_SIZE(prog_type_name); i++)
+		probe_prog_type(i, supported_types);
 
+exit_close_json:
 	if (json_output) {
 		/* End current "section" of probes */
 		jsonw_end_object(json_wtr);
diff --git a/tools/lib/bpf/Build b/tools/lib/bpf/Build
index 197b40f5b5c6..bfd9bfc82c3b 100644
--- a/tools/lib/bpf/Build
+++ b/tools/lib/bpf/Build
@@ -1 +1 @@
-libbpf-y := libbpf.o bpf.o nlattr.o btf.o libbpf_errno.o str_error.o netlink.o bpf_prog_linfo.o
+libbpf-y := libbpf.o bpf.o nlattr.o btf.o libbpf_errno.o str_error.o netlink.o bpf_prog_linfo.o libbpf_probes.o
diff --git a/tools/lib/bpf/libbpf.h b/tools/lib/bpf/libbpf.h
index 5f68d7b75215..8e63821109ab 100644
--- a/tools/lib/bpf/libbpf.h
+++ b/tools/lib/bpf/libbpf.h
@@ -355,6 +355,17 @@ LIBBPF_API const struct bpf_line_info *
 bpf_prog_linfo__lfind(const struct bpf_prog_linfo *prog_linfo,
 		      __u32 insn_off, __u32 nr_skip);
 
+/*
+ * Probe for supported system features
+ *
+ * Note that running many of these probes in a short amount of time can cause
+ * the kernel to reach the maximal size of lockable memory allowed for the
+ * user, causing subsequent probes to fail. In this case, the caller may want
+ * to adjust that limit with setrlimit().
+ */
+LIBBPF_API bool bpf_probe_prog_type(enum bpf_prog_type prog_type,
+				    __u32 ifindex);
+
 #ifdef __cplusplus
 } /* extern "C" */
 #endif
diff --git a/tools/lib/bpf/libbpf.map b/tools/lib/bpf/libbpf.map
index cd02cd4e2cc3..6355e4c80a86 100644
--- a/tools/lib/bpf/libbpf.map
+++ b/tools/lib/bpf/libbpf.map
@@ -56,6 +56,7 @@ LIBBPF_0.0.1 {
 		bpf_object__unpin_maps;
 		bpf_object__unpin_programs;
 		bpf_perf_event_read_simple;
+		bpf_probe_prog_type;
 		bpf_prog_attach;
 		bpf_prog_detach;
 		bpf_prog_detach2;
diff --git a/tools/lib/bpf/libbpf_probes.c b/tools/lib/bpf/libbpf_probes.c
new file mode 100644
index 000000000000..f08c33fa8dc9
--- /dev/null
+++ b/tools/lib/bpf/libbpf_probes.c
@@ -0,0 +1,95 @@
+// SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause)
+/* Copyright (c) 2019 Netronome Systems, Inc. */
+
+#include <errno.h>
+#include <unistd.h>
+#include <sys/utsname.h>
+
+#include <linux/filter.h>
+#include <linux/kernel.h>
+
+#include "bpf.h"
+#include "libbpf.h"
+
+static int get_kernel_version(void)
+{
+	int version, subversion, patchlevel;
+	struct utsname utsn;
+
+	/* Return 0 on failure, and attempt to probe with empty kversion */
+	if (uname(&utsn))
+		return 0;
+
+	if (sscanf(utsn.release, "%d.%d.%d",
+		   &version, &subversion, &patchlevel) != 3)
+		return 0;
+
+	return (version << 16) + (subversion << 8) + patchlevel;
+}
+
+static void
+prog_load(enum bpf_prog_type prog_type, const struct bpf_insn *insns,
+	  size_t insns_cnt, char *buf, size_t buf_len, __u32 ifindex)
+{
+	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;
+	case BPF_PROG_TYPE_KPROBE:
+		xattr.kern_version = get_kernel_version();
+		break;
+	case BPF_PROG_TYPE_UNSPEC:
+	case BPF_PROG_TYPE_SOCKET_FILTER:
+	case BPF_PROG_TYPE_SCHED_CLS:
+	case BPF_PROG_TYPE_SCHED_ACT:
+	case BPF_PROG_TYPE_TRACEPOINT:
+	case BPF_PROG_TYPE_XDP:
+	case BPF_PROG_TYPE_PERF_EVENT:
+	case BPF_PROG_TYPE_CGROUP_SKB:
+	case BPF_PROG_TYPE_CGROUP_SOCK:
+	case BPF_PROG_TYPE_LWT_IN:
+	case BPF_PROG_TYPE_LWT_OUT:
+	case BPF_PROG_TYPE_LWT_XMIT:
+	case BPF_PROG_TYPE_SOCK_OPS:
+	case BPF_PROG_TYPE_SK_SKB:
+	case BPF_PROG_TYPE_CGROUP_DEVICE:
+	case BPF_PROG_TYPE_SK_MSG:
+	case BPF_PROG_TYPE_RAW_TRACEPOINT:
+	case BPF_PROG_TYPE_LWT_SEG6LOCAL:
+	case BPF_PROG_TYPE_LIRC_MODE2:
+	case BPF_PROG_TYPE_SK_REUSEPORT:
+	case BPF_PROG_TYPE_FLOW_DISSECTOR:
+	default:
+		break;
+	}
+
+	xattr.prog_type = prog_type;
+	xattr.insns = insns;
+	xattr.insns_cnt = insns_cnt;
+	xattr.license = "GPL";
+	xattr.prog_ifindex = ifindex;
+
+	fd = bpf_load_program_xattr(&xattr, buf, buf_len);
+	if (fd >= 0)
+		close(fd);
+}
+
+bool bpf_probe_prog_type(enum bpf_prog_type prog_type, __u32 ifindex)
+{
+	struct bpf_insn insns[2] = {
+		BPF_MOV64_IMM(BPF_REG_0, 0),
+		BPF_EXIT_INSN()
+	};
+
+	if (ifindex && prog_type == BPF_PROG_TYPE_SCHED_CLS)
+		/* nfp returns -EINVAL on exit(0) with TC offload */
+		insns[0].imm = 2;
+
+	errno = 0;
+	prog_load(prog_type, insns, ARRAY_SIZE(insns), NULL, 0, ifindex);
+
+	return errno != EINVAL && errno != EOPNOTSUPP;
+}
-- 
2.17.1

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

* [RFC bpf-next v3 5/9] tools: bpftool: add probes for eBPF map types
  2019-01-03 14:02 [RFC bpf-next v3 0/9] tools: bpftool: add probes for system and device Quentin Monnet
                   ` (3 preceding siblings ...)
  2019-01-03 14:02 ` [RFC bpf-next v3 4/9] tools: bpftool: add probes for eBPF program types Quentin Monnet
@ 2019-01-03 14:02 ` Quentin Monnet
  2019-01-03 14:02 ` [RFC bpf-next v3 6/9] tools: bpftool: add probes for eBPF helper functions Quentin Monnet
                   ` (3 subsequent siblings)
  8 siblings, 0 replies; 18+ messages in thread
From: Quentin Monnet @ 2019-01-03 14:02 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,
            ...
        }
    }

v3:
- Use a switch with all enum values for setting specific map parameters,
  so that gcc complains at compile time (-Wswitch-enum) if new map types
  were added to the kernel but libbpf was not updated.

v2:
- Move probes from bpftool to libbpf.
- Remove C-style macros output from this patch.

Signed-off-by: Quentin Monnet <quentin.monnet@netronome.com>
---
 tools/bpf/bpftool/feature.c   | 26 +++++++++++
 tools/bpf/bpftool/main.h      |  3 ++
 tools/bpf/bpftool/map.c       |  4 +-
 tools/lib/bpf/libbpf.h        |  1 +
 tools/lib/bpf/libbpf.map      |  1 +
 tools/lib/bpf/libbpf_probes.c | 84 +++++++++++++++++++++++++++++++++++
 6 files changed, 118 insertions(+), 1 deletion(-)

diff --git a/tools/bpf/bpftool/feature.c b/tools/bpf/bpftool/feature.c
index 8b9e00867000..6a4ff402854c 100644
--- a/tools/bpf/bpftool/feature.c
+++ b/tools/bpf/bpftool/feature.c
@@ -380,6 +380,26 @@ static void probe_prog_type(enum bpf_prog_type prog_type, bool *supported_types)
 	print_bool_feature(feat_name, plain_desc, res);
 }
 
+static void probe_map_type(enum bpf_map_type map_type)
+{
+	const char *plain_comment = "eBPF map_type ";
+	char feat_name[128], plain_desc[128];
+	size_t maxlen;
+	bool res;
+
+	res = bpf_probe_map_type(map_type, 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(plain_desc, "%s%s", plain_comment, map_type_name[map_type]);
+	print_bool_feature(feat_name, plain_desc, res);
+}
+
 static int do_probe(int argc, char **argv)
 {
 	enum probe_component target = COMPONENT_UNSPEC;
@@ -448,6 +468,12 @@ static int do_probe(int argc, char **argv)
 	for (i = BPF_PROG_TYPE_UNSPEC + 1; i < ARRAY_SIZE(prog_type_name); i++)
 		probe_prog_type(i, supported_types);
 
+	print_end_then_start_section("map_types",
+				     "Scanning eBPF map types...");
+
+	for (i = BPF_MAP_TYPE_UNSPEC + 1; i < map_type_name_size; i++)
+		probe_map_type(i);
+
 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 5cfc6601de9b..d7dd84d3c660 100644
--- a/tools/bpf/bpftool/main.h
+++ b/tools/bpf/bpftool/main.h
@@ -75,6 +75,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 ||
diff --git a/tools/lib/bpf/libbpf.h b/tools/lib/bpf/libbpf.h
index 8e63821109ab..72385f6f9415 100644
--- a/tools/lib/bpf/libbpf.h
+++ b/tools/lib/bpf/libbpf.h
@@ -365,6 +365,7 @@ bpf_prog_linfo__lfind(const struct bpf_prog_linfo *prog_linfo,
  */
 LIBBPF_API bool bpf_probe_prog_type(enum bpf_prog_type prog_type,
 				    __u32 ifindex);
+LIBBPF_API bool bpf_probe_map_type(enum bpf_map_type map_type, __u32 ifindex);
 
 #ifdef __cplusplus
 } /* extern "C" */
diff --git a/tools/lib/bpf/libbpf.map b/tools/lib/bpf/libbpf.map
index 6355e4c80a86..c08f4c726e8e 100644
--- a/tools/lib/bpf/libbpf.map
+++ b/tools/lib/bpf/libbpf.map
@@ -56,6 +56,7 @@ LIBBPF_0.0.1 {
 		bpf_object__unpin_maps;
 		bpf_object__unpin_programs;
 		bpf_perf_event_read_simple;
+		bpf_probe_map_type;
 		bpf_probe_prog_type;
 		bpf_prog_attach;
 		bpf_prog_detach;
diff --git a/tools/lib/bpf/libbpf_probes.c b/tools/lib/bpf/libbpf_probes.c
index f08c33fa8dc9..e3d57632a975 100644
--- a/tools/lib/bpf/libbpf_probes.c
+++ b/tools/lib/bpf/libbpf_probes.c
@@ -93,3 +93,87 @@ bool bpf_probe_prog_type(enum bpf_prog_type prog_type, __u32 ifindex)
 
 	return errno != EINVAL && errno != EOPNOTSUPP;
 }
+
+bool bpf_probe_map_type(enum bpf_map_type map_type, __u32 ifindex)
+{
+	int key_size, value_size, max_entries, map_flags;
+	struct bpf_create_map_attr attr = {};
+	int fd = -1, fd_inner;
+
+	key_size	= sizeof(__u32);
+	value_size	= sizeof(__u32);
+	max_entries	= 1;
+	map_flags	= 0;
+
+	switch (map_type) {
+	case BPF_MAP_TYPE_STACK_TRACE:
+		value_size	= sizeof(__u64);
+		break;
+	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_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;
+	case BPF_MAP_TYPE_UNSPEC:
+	case BPF_MAP_TYPE_HASH:
+	case BPF_MAP_TYPE_ARRAY:
+	case BPF_MAP_TYPE_PROG_ARRAY:
+	case BPF_MAP_TYPE_PERF_EVENT_ARRAY:
+	case BPF_MAP_TYPE_PERCPU_HASH:
+	case BPF_MAP_TYPE_PERCPU_ARRAY:
+	case BPF_MAP_TYPE_CGROUP_ARRAY:
+	case BPF_MAP_TYPE_LRU_HASH:
+	case BPF_MAP_TYPE_LRU_PERCPU_HASH:
+	case BPF_MAP_TYPE_ARRAY_OF_MAPS:
+	case BPF_MAP_TYPE_HASH_OF_MAPS:
+	case BPF_MAP_TYPE_DEVMAP:
+	case BPF_MAP_TYPE_SOCKMAP:
+	case BPF_MAP_TYPE_CPUMAP:
+	case BPF_MAP_TYPE_XSKMAP:
+	case BPF_MAP_TYPE_SOCKHASH:
+	case BPF_MAP_TYPE_REUSEPORT_SOCKARRAY:
+	default:
+		break;
+	}
+
+	if (map_type == BPF_MAP_TYPE_ARRAY_OF_MAPS ||
+	    map_type == BPF_MAP_TYPE_HASH_OF_MAPS) {
+		/* TODO: probe for device, once libbpf has a function to create
+		 * map-in-map for offload
+		 */
+		if (ifindex)
+			return false;
+
+		fd_inner = bpf_create_map(BPF_MAP_TYPE_HASH,
+					  sizeof(__u32), sizeof(__u32), 1, 0);
+		if (fd_inner < 0)
+			return false;
+		fd = bpf_create_map_in_map(map_type, NULL, sizeof(__u32),
+					   fd_inner, 1, 0);
+		close(fd_inner);
+	} else {
+		/* 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;
+		attr.map_ifindex = ifindex;
+
+		fd = bpf_create_map_xattr(&attr);
+	}
+	if (fd >= 0)
+		close(fd);
+
+	return fd >= 0;
+}
-- 
2.17.1

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

* [RFC bpf-next v3 6/9] tools: bpftool: add probes for eBPF helper functions
  2019-01-03 14:02 [RFC bpf-next v3 0/9] tools: bpftool: add probes for system and device Quentin Monnet
                   ` (4 preceding siblings ...)
  2019-01-03 14:02 ` [RFC bpf-next v3 5/9] tools: bpftool: add probes for eBPF map types Quentin Monnet
@ 2019-01-03 14:02 ` Quentin Monnet
  2019-01-03 17:15   ` Stanislav Fomichev
  2019-01-03 14:02 ` [RFC bpf-next v3 7/9] tools: bpftool: add C-style "#define" output for probes Quentin Monnet
                   ` (2 subsequent siblings)
  8 siblings, 1 reply; 18+ messages in thread
From: Quentin Monnet @ 2019-01-03 14:02 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.

For each known program type, all known helpers are tested, in order to
establish a compatibility matrix. Output is provided as a set of lists
of available helpers, one per program type.

Sample output:

    # bpftool feature probe kernel
    ...
    Scanning eBPF helper functions...
    eBPF helpers supported for program type socket_filter:
            - bpf_map_lookup_elem
            - bpf_map_update_elem
            - bpf_map_delete_elem
    ...
    eBPF helpers supported for program type kprobe:
            - bpf_map_lookup_elem
            - bpf_map_update_elem
            - bpf_map_delete_elem
    ...

    # bpftool --json --pretty feature probe kernel
    {
        ...
        "helpers": {
            "socket_filter_available_helpers": ["bpf_map_lookup_elem", \
                    "bpf_map_update_elem","bpf_map_delete_elem", ...
            ],
            "kprobe_available_helpers": ["bpf_map_lookup_elem", \
                    "bpf_map_update_elem","bpf_map_delete_elem", ...
            ],
            ...
        }
    }

v3:
- Do not pass kernel version from bpftool to libbpf probes (kernel
  version for testing program with kprobes is retrieved directly from
  libbpf).
- Dump one list of available helpers per program type (instead of one
  list of compatible program types per helper).

v2:
- Move probes from bpftool to libbpf.
- Test all program types for each helper, print a list of working prog
  types for each helper.
- Fall back on include/uapi/linux/bpf.h for names and ids of helpers.
- Remove C-style macros output from this patch.

Signed-off-by: Quentin Monnet <quentin.monnet@netronome.com>
---
 .../bpftool/Documentation/bpftool-feature.rst |  4 ++
 tools/bpf/bpftool/feature.c                   | 49 +++++++++++++++
 tools/lib/bpf/libbpf.h                        |  2 +
 tools/lib/bpf/libbpf.map                      |  1 +
 tools/lib/bpf/libbpf_probes.c                 | 62 +++++++++++++++++++
 5 files changed, 118 insertions(+)

diff --git a/tools/bpf/bpftool/Documentation/bpftool-feature.rst b/tools/bpf/bpftool/Documentation/bpftool-feature.rst
index 40ac13c0b782..255e3b3629a0 100644
--- a/tools/bpf/bpftool/Documentation/bpftool-feature.rst
+++ b/tools/bpf/bpftool/Documentation/bpftool-feature.rst
@@ -30,6 +30,10 @@ DESCRIPTION
 
 		  Keyword **kernel** can be omitted.
 
+		  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 6a4ff402854c..133cdfda00d4 100644
--- a/tools/bpf/bpftool/feature.c
+++ b/tools/bpf/bpftool/feature.c
@@ -25,6 +25,11 @@ enum probe_component {
 	COMPONENT_KERNEL,
 };
 
+#define BPF_HELPER_MAKE_ENTRY(name)	[BPF_FUNC_ ## name] = "bpf_" # name
+static const char * const helper_name[] = {
+	__BPF_FUNC_MAPPER(BPF_HELPER_MAKE_ENTRY)
+};
+
 /* Miscellaneous utility functions */
 
 static bool check_procfs(void)
@@ -400,6 +405,44 @@ static void probe_map_type(enum bpf_map_type map_type)
 	print_bool_feature(feat_name, plain_desc, res);
 }
 
+static void
+probe_helpers_for_progtype(enum bpf_prog_type prog_type, bool supported_type)
+{
+	const char *ptype_name = prog_type_name[prog_type];
+	char feat_name[128];
+	unsigned int id;
+	bool res;
+
+	if (json_output) {
+		sprintf(feat_name, "%s_available_helpers", ptype_name);
+		jsonw_name(json_wtr, feat_name);
+		jsonw_start_array(json_wtr);
+	} else {
+		printf("eBPF helpers supported for program type %s:",
+		       ptype_name);
+	}
+
+	for (id = 1; id < ARRAY_SIZE(helper_name); id++) {
+		if (!supported_type)
+			res = false;
+		else
+			res = bpf_probe_helper(id, prog_type, 0);
+
+		if (json_output) {
+			if (res)
+				jsonw_string(json_wtr, helper_name[id]);
+		} else {
+			if (res)
+				printf("\n\t- %s", helper_name[id]);
+		}
+	}
+
+	if (json_output)
+		jsonw_end_array(json_wtr);
+	else
+		printf("\n");
+}
+
 static int do_probe(int argc, char **argv)
 {
 	enum probe_component target = COMPONENT_UNSPEC;
@@ -474,6 +517,12 @@ static int do_probe(int argc, char **argv)
 	for (i = BPF_MAP_TYPE_UNSPEC + 1; i < map_type_name_size; i++)
 		probe_map_type(i);
 
+	print_end_then_start_section("helpers",
+				     "Scanning eBPF helper functions...");
+
+	for (i = BPF_PROG_TYPE_UNSPEC + 1; i < ARRAY_SIZE(prog_type_name); i++)
+		probe_helpers_for_progtype(i, supported_types[i]);
+
 exit_close_json:
 	if (json_output) {
 		/* End current "section" of probes */
diff --git a/tools/lib/bpf/libbpf.h b/tools/lib/bpf/libbpf.h
index 72385f6f9415..6ab275933d2e 100644
--- a/tools/lib/bpf/libbpf.h
+++ b/tools/lib/bpf/libbpf.h
@@ -366,6 +366,8 @@ bpf_prog_linfo__lfind(const struct bpf_prog_linfo *prog_linfo,
 LIBBPF_API bool bpf_probe_prog_type(enum bpf_prog_type prog_type,
 				    __u32 ifindex);
 LIBBPF_API bool bpf_probe_map_type(enum bpf_map_type map_type, __u32 ifindex);
+LIBBPF_API bool bpf_probe_helper(__u32 id, enum bpf_prog_type prog_type,
+				 __u32 ifindex);
 
 #ifdef __cplusplus
 } /* extern "C" */
diff --git a/tools/lib/bpf/libbpf.map b/tools/lib/bpf/libbpf.map
index c08f4c726e8e..67e51b2becec 100644
--- a/tools/lib/bpf/libbpf.map
+++ b/tools/lib/bpf/libbpf.map
@@ -56,6 +56,7 @@ LIBBPF_0.0.1 {
 		bpf_object__unpin_maps;
 		bpf_object__unpin_programs;
 		bpf_perf_event_read_simple;
+		bpf_probe_helper;
 		bpf_probe_map_type;
 		bpf_probe_prog_type;
 		bpf_prog_attach;
diff --git a/tools/lib/bpf/libbpf_probes.c b/tools/lib/bpf/libbpf_probes.c
index e3d57632a975..1b325142bca4 100644
--- a/tools/lib/bpf/libbpf_probes.c
+++ b/tools/lib/bpf/libbpf_probes.c
@@ -2,7 +2,11 @@
 /* Copyright (c) 2019 Netronome Systems, Inc. */
 
 #include <errno.h>
+#include <fcntl.h>
+#include <string.h>
+#include <stdlib.h>
 #include <unistd.h>
+#include <net/if.h>
 #include <sys/utsname.h>
 
 #include <linux/filter.h>
@@ -11,6 +15,37 @@
 #include "bpf.h"
 #include "libbpf.h"
 
+static bool grep(const char *buffer, const char *pattern)
+{
+	return !!strstr(buffer, pattern);
+}
+
+static int get_vendor_id(int ifindex)
+{
+	char ifname[IF_NAMESIZE], path[64], buf[8];
+	ssize_t len;
+	int fd;
+
+	if (!if_indextoname(ifindex, ifname))
+		return -1;
+
+	snprintf(path, sizeof(path), "/sys/class/net/%s/device/vendor", ifname);
+
+	fd = open(path, O_RDONLY);
+	if (fd < 0)
+		return -1;
+
+	len = read(fd, buf, sizeof(buf));
+	close(fd);
+	if (len < 0)
+		return -1;
+	if (len >= (ssize_t)sizeof(buf))
+		return -1;
+	buf[len] = '\0';
+
+	return strtol(buf, NULL, 0);
+}
+
 static int get_kernel_version(void)
 {
 	int version, subversion, patchlevel;
@@ -177,3 +212,30 @@ bool bpf_probe_map_type(enum bpf_map_type map_type, __u32 ifindex)
 
 	return fd >= 0;
 }
+
+bool bpf_probe_helper(__u32 id, enum bpf_prog_type prog_type, __u32 ifindex)
+{
+	struct bpf_insn insns[2] = {
+		BPF_EMIT_CALL(id),
+		BPF_EXIT_INSN()
+	};
+	char buf[4096] = {};
+	bool res;
+
+	prog_load(prog_type, insns, ARRAY_SIZE(insns), buf, sizeof(buf),
+		  ifindex);
+	res = !grep(buf, "invalid func ") && !grep(buf, "unknown func ");
+
+	if (ifindex) {
+		switch (get_vendor_id(ifindex)) {
+		case 0x19ee: /* Netronome specific */
+			res = res && !grep(buf, "not supported by FW") &&
+				!grep(buf, "unsupported function id");
+			break;
+		default:
+			break;
+		}
+	}
+
+	return res;
+}
-- 
2.17.1

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

* [RFC bpf-next v3 7/9] tools: bpftool: add C-style "#define" output for probes
  2019-01-03 14:02 [RFC bpf-next v3 0/9] tools: bpftool: add probes for system and device Quentin Monnet
                   ` (5 preceding siblings ...)
  2019-01-03 14:02 ` [RFC bpf-next v3 6/9] tools: bpftool: add probes for eBPF helper functions Quentin Monnet
@ 2019-01-03 14:02 ` Quentin Monnet
  2019-01-03 14:02 ` [RFC bpf-next v3 8/9] tools: bpftool: add probes for a network device Quentin Monnet
  2019-01-03 14:02 ` [RFC bpf-next v3 9/9] tools: bpftool: add bash completion for bpftool probes Quentin Monnet
  8 siblings, 0 replies; 18+ messages in thread
From: Quentin Monnet @ 2019-01-03 14:02 UTC (permalink / raw)
  To: Alexei Starovoitov, Daniel Borkmann
  Cc: netdev, oss-drivers, Quentin Monnet, Arnaldo Carvalho de Melo,
	Jesper Dangaard Brouer, Stanislav Fomichev

Make bpftool able to dump a subset of the parameters collected by
probing the system as a listing of C-style #define macros, so that
external projects can reuse the result of this probing and build
BPF-based project in accordance with the features available on the
system.

The new "macros" keyword is used to select this output. An additional
"prefix" keyword is added so that users can select a custom prefix for
macro names, in order to avoid any namespace conflict.

Sample output:

    # bpftool feature probe kernel macros prefix FOO_
    /*** System call availability ***/
    #define FOO_HAVE_BPF_SYSCALL

    /*** eBPF program types ***/
    #define FOO_HAVE_SOCKET_FILTER_PROG_TYPE
    #define FOO_HAVE_KPROBE_PROG_TYPE
    #define FOO_HAVE_SCHED_CLS_PROG_TYPE
    ...

    /*** eBPF map types ***/
    #define FOO_HAVE_HASH_MAP_TYPE
    #define FOO_HAVE_ARRAY_MAP_TYPE
    #define FOO_HAVE_PROG_ARRAY_MAP_TYPE
    ...

    /*** eBPF helper functions ***/
    /*
     * Use FOO_HAVE_PROG_TYPE_HELPER(prog_type_name, helper_name)
     * to determine if <helper_name> is available for <prog_type_name>,
     * e.g.
     *      #if FOO_HAVE_PROG_TYPE_HELPER(xdp, bpf_redirect)
     *              // do stuff with this helper
     *      #elif
     *              // use a workaround
     *      #endif
     */
    #define FOO_HAVE_PROG_TYPE_HELPER(prog_type, helper)        \
            FOO_BPF__PROG_TYPE_ ## prog_type ## __HELPER_ ## helper
    ...
    #define FOO_BPF__PROG_TYPE_socket_filter__HELPER_bpf_probe_read 0
    #define FOO_BPF__PROG_TYPE_socket_filter__HELPER_bpf_ktime_get_ns 1
    #define FOO_BPF__PROG_TYPE_socket_filter__HELPER_bpf_trace_printk 1
    ...

v3:
- Change output for helpers again: add a
  HAVE_PROG_TYPE_HELPER(type, helper) macro that can be used to tell
  if <helper> is available for program <type>.

v2:
- #define-based output added as a distinct patch.
- "HAVE_" prefix appended to macro names.
- Output limited to bpf() syscall availability, BPF prog and map types,
  helper functions. In this version kernel config options, procfs
  parameter or kernel version are intentionally left aside.
- Following the change on helper probes, format for helper probes in
  this output style has changed (now a list of compatible program
  types).

Signed-off-by: Quentin Monnet <quentin.monnet@netronome.com>
---
 .../bpftool/Documentation/bpftool-feature.rst |  13 +-
 tools/bpf/bpftool/feature.c                   | 148 ++++++++++++++----
 2 files changed, 131 insertions(+), 30 deletions(-)

diff --git a/tools/bpf/bpftool/Documentation/bpftool-feature.rst b/tools/bpf/bpftool/Documentation/bpftool-feature.rst
index 255e3b3629a0..53092995f46b 100644
--- a/tools/bpf/bpftool/Documentation/bpftool-feature.rst
+++ b/tools/bpf/bpftool/Documentation/bpftool-feature.rst
@@ -19,15 +19,24 @@ SYNOPSIS
 MAP COMMANDS
 =============
 
-|	**bpftool** **feature probe** [**kernel**]
+|	**bpftool** **feature probe** [**kernel**] [**macros** [**prefix** *PREFIX*]]
 |	**bpftool** **feature help**
 
 DESCRIPTION
 ===========
-	**bpftool feature probe** [**kernel**]
+	**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.
 
+		  If the **macros** keyword (but not the **-j** option) is
+		  passed, a subset of the 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.
+
 		  Keyword **kernel** can be omitted.
 
 		  Note that when probed, some eBPF helpers (e.g.
diff --git a/tools/bpf/bpftool/feature.c b/tools/bpf/bpftool/feature.c
index 133cdfda00d4..a97913b0df6c 100644
--- a/tools/bpf/bpftool/feature.c
+++ b/tools/bpf/bpftool/feature.c
@@ -44,13 +44,25 @@ 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
-print_bool_feature(const char *feat_name, const char *plain_name, bool res)
+print_bool_feature(const char *feat_name, const char *plain_name,
+		   const char *define_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%sHAVE_%s\n", define_prefix,
+		       res ? "" : "NO_", define_name);
 	else
 		printf("%s is %savailable\n", plain_name, res ? "" : "NOT ");
 }
@@ -60,6 +72,8 @@ static void print_kernel_option(const char *name, const char *value)
 	char *endptr;
 	int res;
 
+	/* No support for C-style ouptut */
+
 	if (json_output) {
 		if (!value) {
 			jsonw_null_field(json_wtr, name);
@@ -80,25 +94,31 @@ static void print_kernel_option(const char *name, const char *value)
 }
 
 static void
-print_start_section(const char *json_title, const char *plain_title)
+print_start_section(const char *json_title, const char *plain_title,
+		    const char *define_comment, 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);
 	}
 }
 
 static void
-print_end_then_start_section(const char *json_title, const char *plain_title)
+print_end_then_start_section(const char *json_title, const char *plain_title,
+			     const char *define_comment,
+			     const char *define_prefix)
 {
 	if (json_output)
 		jsonw_end_object(json_wtr);
 	else
 		printf("\n");
 
-	print_start_section(json_title, plain_title);
+	print_start_section(json_title, plain_title, define_comment,
+			    define_prefix);
 }
 
 /* Probing functions */
@@ -132,6 +152,8 @@ static void probe_unprivileged_disabled(void)
 {
 	int res;
 
+	/* No support for C-style ouptut */
+
 	res = read_procfs("/proc/sys/kernel/unprivileged_bpf_disabled");
 	if (json_output) {
 		jsonw_int_field(json_wtr, "unprivileged_bpf_disabled", res);
@@ -156,6 +178,8 @@ static void probe_jit_enable(void)
 {
 	int res;
 
+	/* No support for C-style ouptut */
+
 	res = read_procfs("/proc/sys/net/core/bpf_jit_enable");
 	if (json_output) {
 		jsonw_int_field(json_wtr, "bpf_jit_enable", res);
@@ -184,6 +208,8 @@ static void probe_jit_harden(void)
 {
 	int res;
 
+	/* No support for C-style ouptut */
+
 	res = read_procfs("/proc/sys/net/core/bpf_jit_harden");
 	if (json_output) {
 		jsonw_int_field(json_wtr, "bpf_jit_harden", res);
@@ -212,6 +238,8 @@ static void probe_jit_kallsyms(void)
 {
 	int res;
 
+	/* No support for C-style ouptut */
+
 	res = read_procfs("/proc/sys/net/core/bpf_jit_kallsyms");
 	if (json_output) {
 		jsonw_int_field(json_wtr, "bpf_jit_kallsyms", res);
@@ -349,7 +377,7 @@ static void probe_kernel_image_config(void)
 		print_kernel_option(options[i], NULL);
 }
 
-static bool probe_bpf_syscall(void)
+static bool probe_bpf_syscall(const char *define_prefix)
 {
 	bool res;
 
@@ -358,15 +386,18 @@ static bool probe_bpf_syscall(void)
 
 	print_bool_feature("have_bpf_syscall",
 			   "bpf() syscall",
-			   res);
+			   "BPF_SYSCALL",
+			   res, define_prefix);
 
 	return res;
 }
 
-static void probe_prog_type(enum bpf_prog_type prog_type, bool *supported_types)
+static void
+probe_prog_type(enum bpf_prog_type prog_type, bool *supported_types,
+		const char *define_prefix)
 {
+	char feat_name[128], plain_desc[128], define_name[128];
 	const char *plain_comment = "eBPF program_type ";
-	char feat_name[128], plain_desc[128];
 	size_t maxlen;
 	bool res;
 
@@ -381,14 +412,18 @@ static void probe_prog_type(enum bpf_prog_type prog_type, bool *supported_types)
 	}
 
 	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, plain_desc, res);
+	print_bool_feature(feat_name, plain_desc, define_name, res,
+			   define_prefix);
 }
 
-static void probe_map_type(enum bpf_map_type map_type)
+static void
+probe_map_type(enum bpf_map_type map_type, const char *define_prefix)
 {
+	char feat_name[128], plain_desc[128], define_name[128];
 	const char *plain_comment = "eBPF map_type ";
-	char feat_name[128], plain_desc[128];
 	size_t maxlen;
 	bool res;
 
@@ -401,12 +436,16 @@ static void probe_map_type(enum bpf_map_type map_type)
 	}
 
 	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, plain_desc, res);
+	print_bool_feature(feat_name, plain_desc, define_name, res,
+			   define_prefix);
 }
 
 static void
-probe_helpers_for_progtype(enum bpf_prog_type prog_type, bool supported_type)
+probe_helpers_for_progtype(enum bpf_prog_type prog_type, bool supported_type,
+			   const char *define_prefix)
 {
 	const char *ptype_name = prog_type_name[prog_type];
 	char feat_name[128];
@@ -417,7 +456,7 @@ probe_helpers_for_progtype(enum bpf_prog_type prog_type, bool supported_type)
 		sprintf(feat_name, "%s_available_helpers", ptype_name);
 		jsonw_name(json_wtr, feat_name);
 		jsonw_start_array(json_wtr);
-	} else {
+	} else if (!define_prefix) {
 		printf("eBPF helpers supported for program type %s:",
 		       ptype_name);
 	}
@@ -431,6 +470,10 @@ probe_helpers_for_progtype(enum bpf_prog_type prog_type, bool supported_type)
 		if (json_output) {
 			if (res)
 				jsonw_string(json_wtr, helper_name[id]);
+		} else if (define_prefix) {
+			printf("#define %sBPF__PROG_TYPE_%s__HELPER_%s %s\n",
+			       define_prefix, ptype_name, helper_name[id],
+			       res ? "1" : "0");
 		} else {
 			if (res)
 				printf("\n\t- %s", helper_name[id]);
@@ -439,13 +482,14 @@ probe_helpers_for_progtype(enum bpf_prog_type prog_type, bool supported_type)
 
 	if (json_output)
 		jsonw_end_array(json_wtr);
-	else
+	else if (!define_prefix)
 		printf("\n");
 }
 
 static int do_probe(int argc, char **argv)
 {
 	enum probe_component target = COMPONENT_UNSPEC;
+	const char *define_prefix = NULL;
 	bool supported_types[128] = {};
 	unsigned int i;
 
@@ -467,21 +511,45 @@ static int do_probe(int argc, char **argv)
 			}
 			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', got: '%s'?",
+			p_err("expected no more arguments, 'kernel', 'macros' or 'prefix', got: '%s'?",
 			      *argv);
 			return -1;
 		}
 	}
 
-	if (json_output)
+	if (json_output) {
+		define_prefix = NULL;
 		jsonw_start_object(json_wtr);
+	}
 
 	switch (target) {
 	case COMPONENT_KERNEL:
 	case COMPONENT_UNSPEC:
+		if (define_prefix)
+			break;
+
 		print_start_section("system_config",
-				    "Scanning system configuration...");
+				    "Scanning system configuration...",
+				    NULL, /* define_comment never used here */
+				    NULL); /* define_prefix always NULL here */
 		if (check_procfs()) {
 			probe_unprivileged_disabled();
 			probe_jit_enable();
@@ -499,29 +567,53 @@ static int do_probe(int argc, char **argv)
 	}
 
 	print_start_section("syscall_config",
-			    "Scanning system call availability...");
+			    "Scanning system call availability...",
+			    "/*** System call availability ***/",
+			    define_prefix);
 
-	if (!probe_bpf_syscall())
+	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",
-				     "Scanning eBPF program types...");
+				     "Scanning eBPF program types...",
+				     "/*** eBPF program types ***/",
+				     define_prefix);
 
 	for (i = BPF_PROG_TYPE_UNSPEC + 1; i < ARRAY_SIZE(prog_type_name); i++)
-		probe_prog_type(i, supported_types);
+		probe_prog_type(i, supported_types, define_prefix);
 
 	print_end_then_start_section("map_types",
-				     "Scanning eBPF map types...");
+				     "Scanning eBPF map types...",
+				     "/*** eBPF map types ***/",
+				     define_prefix);
 
 	for (i = BPF_MAP_TYPE_UNSPEC + 1; i < map_type_name_size; i++)
-		probe_map_type(i);
+		probe_map_type(i, define_prefix);
 
 	print_end_then_start_section("helpers",
-				     "Scanning eBPF helper functions...");
-
+				     "Scanning eBPF helper functions...",
+				     "/*** eBPF helper functions ***/",
+				     define_prefix);
+
+	if (define_prefix)
+		printf("/*\n"
+		       " * Use %sHAVE_PROG_TYPE_HELPER(prog_type_name, helper_name)\n"
+		       " * to determine if <helper_name> is available for <prog_type_name>,\n"
+		       " * e.g.\n"
+		       " *	#if %sHAVE_PROG_TYPE_HELPER(xdp, bpf_redirect)\n"
+		       " *		// do stuff with this helper\n"
+		       " *	#elif\n"
+		       " *		// use a workaround\n"
+		       " *	#endif\n"
+		       " */\n"
+		       "#define %sHAVE_PROG_TYPE_HELPER(prog_type, helper)	\\\n"
+		       "	%sBPF__PROG_TYPE_ ## prog_type ## __HELPER_ ## helper\n",
+		       define_prefix, define_prefix, define_prefix,
+		       define_prefix);
 	for (i = BPF_PROG_TYPE_UNSPEC + 1; i < ARRAY_SIZE(prog_type_name); i++)
-		probe_helpers_for_progtype(i, supported_types[i]);
+		probe_helpers_for_progtype(i, supported_types[i],
+					   define_prefix);
 
 exit_close_json:
 	if (json_output) {
@@ -542,7 +634,7 @@ static int do_help(int argc, char **argv)
 	}
 
 	fprintf(stderr,
-		"Usage: %s %s probe [kernel]\n"
+		"Usage: %s %s probe [kernel] [macros [prefix PREFIX]]\n"
 		"       %s %s help\n"
 		"",
 		bin_name, argv[-2], bin_name, argv[-2]);
-- 
2.17.1

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

* [RFC bpf-next v3 8/9] tools: bpftool: add probes for a network device
  2019-01-03 14:02 [RFC bpf-next v3 0/9] tools: bpftool: add probes for system and device Quentin Monnet
                   ` (6 preceding siblings ...)
  2019-01-03 14:02 ` [RFC bpf-next v3 7/9] tools: bpftool: add C-style "#define" output for probes Quentin Monnet
@ 2019-01-03 14:02 ` Quentin Monnet
  2019-01-03 14:02 ` [RFC bpf-next v3 9/9] tools: bpftool: add bash completion for bpftool probes Quentin Monnet
  8 siblings, 0 replies; 18+ messages in thread
From: Quentin Monnet @ 2019-01-03 14:02 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
libbpf (and hence 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": {
            "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 is
still probed, so we can return early if that syscall is not usable
(since there is no point in attempting the remaining probes in this
case).

Among the program types, only the ones that can be offloaded 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. All helpers
are probed (but only for offload-able program types).

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

v2:
- All helpers are probed, whereas previous version would only probe the
  ones compatible with an offload-able program type. This is because we
  do not keep a default compatible program type for each helper anymore.

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/feature.c                   | 69 ++++++++++++++++---
 2 files changed, 73 insertions(+), 14 deletions(-)

diff --git a/tools/bpf/bpftool/Documentation/bpftool-feature.rst b/tools/bpf/bpftool/Documentation/bpftool-feature.rst
index 53092995f46b..8d489a26e3c9 100644
--- a/tools/bpf/bpftool/Documentation/bpftool-feature.rst
+++ b/tools/bpf/bpftool/Documentation/bpftool-feature.rst
@@ -19,14 +19,18 @@ 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.
 
 		  If the **macros** keyword (but not the **-j** option) is
 		  passed, a subset of the output is dumped as a list of
@@ -37,12 +41,20 @@ DESCRIPTION
 		  avoid conflicts on macro names when including the output of
 		  this command as a header file.
 
-		  Keyword **kernel** can be omitted.
+		  Keyword **kernel** can be omitted. If no probe target is
+		  specified, probing the kernel is the default behaviour.
 
 		  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 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/feature.c b/tools/bpf/bpftool/feature.c
index a97913b0df6c..c1bba37287a3 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>
 
@@ -23,6 +24,7 @@
 enum probe_component {
 	COMPONENT_UNSPEC,
 	COMPONENT_KERNEL,
+	COMPONENT_DEVICE,
 };
 
 #define BPF_HELPER_MAKE_ENTRY(name)	[BPF_FUNC_ ## name] = "bpf_" # name
@@ -394,14 +396,24 @@ static bool probe_bpf_syscall(const char *define_prefix)
 
 static void
 probe_prog_type(enum bpf_prog_type prog_type, bool *supported_types,
-		const char *define_prefix)
+		const char *define_prefix, __u32 ifindex)
 {
 	char feat_name[128], plain_desc[128], define_name[128];
 	const char *plain_comment = "eBPF program_type ";
 	size_t maxlen;
 	bool res;
 
-	res = bpf_probe_prog_type(prog_type, 0);
+	if (ifindex)
+		/* Only test offload-able program types */
+		switch (prog_type) {
+		case BPF_PROG_TYPE_SCHED_CLS:
+		case BPF_PROG_TYPE_XDP:
+			break;
+		default:
+			return;
+		}
+
+	res = bpf_probe_prog_type(prog_type, ifindex);
 
 	supported_types[prog_type] |= res;
 
@@ -420,14 +432,15 @@ probe_prog_type(enum bpf_prog_type prog_type, bool *supported_types,
 }
 
 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], plain_desc[128], define_name[128];
 	const char *plain_comment = "eBPF map_type ";
 	size_t maxlen;
 	bool res;
 
-	res = bpf_probe_map_type(map_type, 0);
+	res = bpf_probe_map_type(map_type, ifindex);
 
 	maxlen = sizeof(plain_desc) - strlen(plain_comment) - 1;
 	if (strlen(map_type_name[map_type]) > maxlen) {
@@ -445,13 +458,23 @@ probe_map_type(enum bpf_map_type map_type, const char *define_prefix)
 
 static void
 probe_helpers_for_progtype(enum bpf_prog_type prog_type, bool supported_type,
-			   const char *define_prefix)
+			   const char *define_prefix, __u32 ifindex)
 {
 	const char *ptype_name = prog_type_name[prog_type];
 	char feat_name[128];
 	unsigned int id;
 	bool res;
 
+	if (ifindex)
+		/* Only test helpers for offload-able program types */
+		switch (prog_type) {
+		case BPF_PROG_TYPE_SCHED_CLS:
+		case BPF_PROG_TYPE_XDP:
+			break;
+		default:
+			return;
+		}
+
 	if (json_output) {
 		sprintf(feat_name, "%s_available_helpers", ptype_name);
 		jsonw_name(json_wtr, feat_name);
@@ -465,7 +488,7 @@ probe_helpers_for_progtype(enum bpf_prog_type prog_type, bool supported_type,
 		if (!supported_type)
 			res = false;
 		else
-			res = bpf_probe_helper(id, prog_type, 0);
+			res = bpf_probe_helper(id, prog_type, ifindex);
 
 		if (json_output) {
 			if (res)
@@ -491,7 +514,9 @@ static int do_probe(int argc, char **argv)
 	enum probe_component target = COMPONENT_UNSPEC;
 	const char *define_prefix = NULL;
 	bool supported_types[128] = {};
+	__u32 ifindex = 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.
@@ -511,6 +536,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();
@@ -529,7 +572,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;
 		}
@@ -564,6 +607,8 @@ static int do_probe(int argc, char **argv)
 		else
 			printf("\n");
 		break;
+	default:
+		break;
 	}
 
 	print_start_section("syscall_config",
@@ -581,7 +626,7 @@ static int do_probe(int argc, char **argv)
 				     define_prefix);
 
 	for (i = BPF_PROG_TYPE_UNSPEC + 1; i < ARRAY_SIZE(prog_type_name); i++)
-		probe_prog_type(i, supported_types, define_prefix);
+		probe_prog_type(i, supported_types, define_prefix, ifindex);
 
 	print_end_then_start_section("map_types",
 				     "Scanning eBPF map types...",
@@ -589,7 +634,7 @@ static int do_probe(int argc, char **argv)
 				     define_prefix);
 
 	for (i = BPF_MAP_TYPE_UNSPEC + 1; 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",
 				     "Scanning eBPF helper functions...",
@@ -613,7 +658,7 @@ static int do_probe(int argc, char **argv)
 		       define_prefix);
 	for (i = BPF_PROG_TYPE_UNSPEC + 1; i < ARRAY_SIZE(prog_type_name); i++)
 		probe_helpers_for_progtype(i, supported_types[i],
-					   define_prefix);
+					   define_prefix, ifindex);
 
 exit_close_json:
 	if (json_output) {
@@ -634,8 +679,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]);
 
-- 
2.17.1

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

* [RFC bpf-next v3 9/9] tools: bpftool: add bash completion for bpftool probes
  2019-01-03 14:02 [RFC bpf-next v3 0/9] tools: bpftool: add probes for system and device Quentin Monnet
                   ` (7 preceding siblings ...)
  2019-01-03 14:02 ` [RFC bpf-next v3 8/9] tools: bpftool: add probes for a network device Quentin Monnet
@ 2019-01-03 14:02 ` Quentin Monnet
  8 siblings, 0 replies; 18+ messages in thread
From: Quentin Monnet @ 2019-01-03 14:02 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] 18+ messages in thread

* Re: [RFC bpf-next v3 6/9] tools: bpftool: add probes for eBPF helper functions
  2019-01-03 14:02 ` [RFC bpf-next v3 6/9] tools: bpftool: add probes for eBPF helper functions Quentin Monnet
@ 2019-01-03 17:15   ` Stanislav Fomichev
  2019-01-03 17:26     ` Quentin Monnet
  0 siblings, 1 reply; 18+ messages in thread
From: Stanislav Fomichev @ 2019-01-03 17:15 UTC (permalink / raw)
  To: Quentin Monnet
  Cc: Alexei Starovoitov, Daniel Borkmann, netdev, oss-drivers,
	Arnaldo Carvalho de Melo, Jesper Dangaard Brouer

On Thu, Jan 3, 2019 at 6:03 AM Quentin Monnet
<quentin.monnet@netronome.com> 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.
>
> For each known program type, all known helpers are tested, in order to
> establish a compatibility matrix. Output is provided as a set of lists
> of available helpers, one per program type.
>
> Sample output:
>
>     # bpftool feature probe kernel
>     ...
>     Scanning eBPF helper functions...
>     eBPF helpers supported for program type socket_filter:
>             - bpf_map_lookup_elem
>             - bpf_map_update_elem
>             - bpf_map_delete_elem
>     ...
>     eBPF helpers supported for program type kprobe:
>             - bpf_map_lookup_elem
>             - bpf_map_update_elem
>             - bpf_map_delete_elem
>     ...
>
>     # bpftool --json --pretty feature probe kernel
>     {
>         ...
>         "helpers": {
>             "socket_filter_available_helpers": ["bpf_map_lookup_elem", \
>                     "bpf_map_update_elem","bpf_map_delete_elem", ...
>             ],
>             "kprobe_available_helpers": ["bpf_map_lookup_elem", \
>                     "bpf_map_update_elem","bpf_map_delete_elem", ...
>             ],
>             ...
>         }
>     }
>
> v3:
> - Do not pass kernel version from bpftool to libbpf probes (kernel
>   version for testing program with kprobes is retrieved directly from
>   libbpf).
> - Dump one list of available helpers per program type (instead of one
>   list of compatible program types per helper).
>
> v2:
> - Move probes from bpftool to libbpf.
> - Test all program types for each helper, print a list of working prog
>   types for each helper.
> - Fall back on include/uapi/linux/bpf.h for names and ids of helpers.
> - Remove C-style macros output from this patch.
>
> Signed-off-by: Quentin Monnet <quentin.monnet@netronome.com>
> ---
>  .../bpftool/Documentation/bpftool-feature.rst |  4 ++
>  tools/bpf/bpftool/feature.c                   | 49 +++++++++++++++
>  tools/lib/bpf/libbpf.h                        |  2 +
>  tools/lib/bpf/libbpf.map                      |  1 +
>  tools/lib/bpf/libbpf_probes.c                 | 62 +++++++++++++++++++
>  5 files changed, 118 insertions(+)
>
> diff --git a/tools/bpf/bpftool/Documentation/bpftool-feature.rst b/tools/bpf/bpftool/Documentation/bpftool-feature.rst
> index 40ac13c0b782..255e3b3629a0 100644
> --- a/tools/bpf/bpftool/Documentation/bpftool-feature.rst
> +++ b/tools/bpf/bpftool/Documentation/bpftool-feature.rst
> @@ -30,6 +30,10 @@ DESCRIPTION
>
>                   Keyword **kernel** can be omitted.
>
> +                 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 6a4ff402854c..133cdfda00d4 100644
> --- a/tools/bpf/bpftool/feature.c
> +++ b/tools/bpf/bpftool/feature.c
> @@ -25,6 +25,11 @@ enum probe_component {
>         COMPONENT_KERNEL,
>  };
>
> +#define BPF_HELPER_MAKE_ENTRY(name)    [BPF_FUNC_ ## name] = "bpf_" # name
> +static const char * const helper_name[] = {
> +       __BPF_FUNC_MAPPER(BPF_HELPER_MAKE_ENTRY)
> +};
> +
>  /* Miscellaneous utility functions */
>
>  static bool check_procfs(void)
> @@ -400,6 +405,44 @@ static void probe_map_type(enum bpf_map_type map_type)
>         print_bool_feature(feat_name, plain_desc, res);
>  }
>
> +static void
> +probe_helpers_for_progtype(enum bpf_prog_type prog_type, bool supported_type)
> +{
> +       const char *ptype_name = prog_type_name[prog_type];
> +       char feat_name[128];
> +       unsigned int id;
> +       bool res;
> +
> +       if (json_output) {
> +               sprintf(feat_name, "%s_available_helpers", ptype_name);
> +               jsonw_name(json_wtr, feat_name);
> +               jsonw_start_array(json_wtr);
> +       } else {
> +               printf("eBPF helpers supported for program type %s:",
> +                      ptype_name);
> +       }
> +
> +       for (id = 1; id < ARRAY_SIZE(helper_name); id++) {
> +               if (!supported_type)
> +                       res = false;
> +               else
> +                       res = bpf_probe_helper(id, prog_type, 0);
> +
> +               if (json_output) {
> +                       if (res)
> +                               jsonw_string(json_wtr, helper_name[id]);
> +               } else {
> +                       if (res)
> +                               printf("\n\t- %s", helper_name[id]);
> +               }
> +       }
> +
> +       if (json_output)
> +               jsonw_end_array(json_wtr);
> +       else
> +               printf("\n");
> +}
> +
>  static int do_probe(int argc, char **argv)
>  {
>         enum probe_component target = COMPONENT_UNSPEC;
> @@ -474,6 +517,12 @@ static int do_probe(int argc, char **argv)
>         for (i = BPF_MAP_TYPE_UNSPEC + 1; i < map_type_name_size; i++)
>                 probe_map_type(i);
>
> +       print_end_then_start_section("helpers",
> +                                    "Scanning eBPF helper functions...");
> +
> +       for (i = BPF_PROG_TYPE_UNSPEC + 1; i < ARRAY_SIZE(prog_type_name); i++)
> +               probe_helpers_for_progtype(i, supported_types[i]);
> +
>  exit_close_json:
>         if (json_output) {
>                 /* End current "section" of probes */
> diff --git a/tools/lib/bpf/libbpf.h b/tools/lib/bpf/libbpf.h
> index 72385f6f9415..6ab275933d2e 100644
> --- a/tools/lib/bpf/libbpf.h
> +++ b/tools/lib/bpf/libbpf.h
> @@ -366,6 +366,8 @@ bpf_prog_linfo__lfind(const struct bpf_prog_linfo *prog_linfo,
>  LIBBPF_API bool bpf_probe_prog_type(enum bpf_prog_type prog_type,
>                                     __u32 ifindex);
>  LIBBPF_API bool bpf_probe_map_type(enum bpf_map_type map_type, __u32 ifindex);
> +LIBBPF_API bool bpf_probe_helper(__u32 id, enum bpf_prog_type prog_type,
Any reason not to use enum bpf_func_id as id type (instead of __u32)?

> +                                __u32 ifindex);
>
>  #ifdef __cplusplus
>  } /* extern "C" */
> diff --git a/tools/lib/bpf/libbpf.map b/tools/lib/bpf/libbpf.map
> index c08f4c726e8e..67e51b2becec 100644
> --- a/tools/lib/bpf/libbpf.map
> +++ b/tools/lib/bpf/libbpf.map
> @@ -56,6 +56,7 @@ LIBBPF_0.0.1 {
>                 bpf_object__unpin_maps;
>                 bpf_object__unpin_programs;
>                 bpf_perf_event_read_simple;
> +               bpf_probe_helper;
>                 bpf_probe_map_type;
>                 bpf_probe_prog_type;
>                 bpf_prog_attach;
> diff --git a/tools/lib/bpf/libbpf_probes.c b/tools/lib/bpf/libbpf_probes.c
> index e3d57632a975..1b325142bca4 100644
> --- a/tools/lib/bpf/libbpf_probes.c
> +++ b/tools/lib/bpf/libbpf_probes.c
> @@ -2,7 +2,11 @@
>  /* Copyright (c) 2019 Netronome Systems, Inc. */
>
>  #include <errno.h>
> +#include <fcntl.h>
> +#include <string.h>
> +#include <stdlib.h>
>  #include <unistd.h>
> +#include <net/if.h>
>  #include <sys/utsname.h>
>
>  #include <linux/filter.h>
> @@ -11,6 +15,37 @@
>  #include "bpf.h"
>  #include "libbpf.h"
>
> +static bool grep(const char *buffer, const char *pattern)
> +{
> +       return !!strstr(buffer, pattern);
> +}
> +
> +static int get_vendor_id(int ifindex)
> +{
> +       char ifname[IF_NAMESIZE], path[64], buf[8];
> +       ssize_t len;
> +       int fd;
> +
> +       if (!if_indextoname(ifindex, ifname))
> +               return -1;
> +
> +       snprintf(path, sizeof(path), "/sys/class/net/%s/device/vendor", ifname);
> +
> +       fd = open(path, O_RDONLY);
> +       if (fd < 0)
> +               return -1;
> +
> +       len = read(fd, buf, sizeof(buf));
> +       close(fd);
> +       if (len < 0)
> +               return -1;
> +       if (len >= (ssize_t)sizeof(buf))
> +               return -1;
> +       buf[len] = '\0';
> +
> +       return strtol(buf, NULL, 0);
> +}
> +
>  static int get_kernel_version(void)
>  {
>         int version, subversion, patchlevel;
> @@ -177,3 +212,30 @@ bool bpf_probe_map_type(enum bpf_map_type map_type, __u32 ifindex)
>
>         return fd >= 0;
>  }
> +
> +bool bpf_probe_helper(__u32 id, enum bpf_prog_type prog_type, __u32 ifindex)
> +{
> +       struct bpf_insn insns[2] = {
> +               BPF_EMIT_CALL(id),
> +               BPF_EXIT_INSN()
> +       };
> +       char buf[4096] = {};
> +       bool res;
> +
> +       prog_load(prog_type, insns, ARRAY_SIZE(insns), buf, sizeof(buf),
> +                 ifindex);
> +       res = !grep(buf, "invalid func ") && !grep(buf, "unknown func ");
> +
> +       if (ifindex) {
> +               switch (get_vendor_id(ifindex)) {
> +               case 0x19ee: /* Netronome specific */
> +                       res = res && !grep(buf, "not supported by FW") &&
> +                               !grep(buf, "unsupported function id");
> +                       break;
> +               default:
> +                       break;
> +               }
> +       }
> +
> +       return res;
> +}
> --
> 2.17.1
>

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

* Re: [RFC bpf-next v3 6/9] tools: bpftool: add probes for eBPF helper functions
  2019-01-03 17:15   ` Stanislav Fomichev
@ 2019-01-03 17:26     ` Quentin Monnet
  0 siblings, 0 replies; 18+ messages in thread
From: Quentin Monnet @ 2019-01-03 17:26 UTC (permalink / raw)
  To: Stanislav Fomichev
  Cc: Alexei Starovoitov, Daniel Borkmann, netdev, oss-drivers,
	Arnaldo Carvalho de Melo, Jesper Dangaard Brouer

2019-01-03 09:15 UTC-0800 ~ Stanislav Fomichev <sdf@google.com>
> On Thu, Jan 3, 2019 at 6:03 AM Quentin Monnet
> <quentin.monnet@netronome.com> 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.
>>
>> For each known program type, all known helpers are tested, in order to
>> establish a compatibility matrix. Output is provided as a set of lists
>> of available helpers, one per program type.
>>
>> Sample output:
>>
>>     # bpftool feature probe kernel
>>     ...
>>     Scanning eBPF helper functions...
>>     eBPF helpers supported for program type socket_filter:
>>             - bpf_map_lookup_elem
>>             - bpf_map_update_elem
>>             - bpf_map_delete_elem
>>     ...
>>     eBPF helpers supported for program type kprobe:
>>             - bpf_map_lookup_elem
>>             - bpf_map_update_elem
>>             - bpf_map_delete_elem
>>     ...
>>
>>     # bpftool --json --pretty feature probe kernel
>>     {
>>         ...
>>         "helpers": {
>>             "socket_filter_available_helpers": ["bpf_map_lookup_elem", \
>>                     "bpf_map_update_elem","bpf_map_delete_elem", ...
>>             ],
>>             "kprobe_available_helpers": ["bpf_map_lookup_elem", \
>>                     "bpf_map_update_elem","bpf_map_delete_elem", ...
>>             ],
>>             ...
>>         }
>>     }
>>
>> v3:
>> - Do not pass kernel version from bpftool to libbpf probes (kernel
>>   version for testing program with kprobes is retrieved directly from
>>   libbpf).
>> - Dump one list of available helpers per program type (instead of one
>>   list of compatible program types per helper).
>>
>> v2:
>> - Move probes from bpftool to libbpf.
>> - Test all program types for each helper, print a list of working prog
>>   types for each helper.
>> - Fall back on include/uapi/linux/bpf.h for names and ids of helpers.
>> - Remove C-style macros output from this patch.
>>
>> Signed-off-by: Quentin Monnet <quentin.monnet@netronome.com>
>> ---
>>  .../bpftool/Documentation/bpftool-feature.rst |  4 ++
>>  tools/bpf/bpftool/feature.c                   | 49 +++++++++++++++
>>  tools/lib/bpf/libbpf.h                        |  2 +
>>  tools/lib/bpf/libbpf.map                      |  1 +
>>  tools/lib/bpf/libbpf_probes.c                 | 62 +++++++++++++++++++
>>  5 files changed, 118 insertions(+)
>>

>> diff --git a/tools/lib/bpf/libbpf.h b/tools/lib/bpf/libbpf.h
>> index 72385f6f9415..6ab275933d2e 100644
>> --- a/tools/lib/bpf/libbpf.h
>> +++ b/tools/lib/bpf/libbpf.h
>> @@ -366,6 +366,8 @@ bpf_prog_linfo__lfind(const struct bpf_prog_linfo *prog_linfo,
>>  LIBBPF_API bool bpf_probe_prog_type(enum bpf_prog_type prog_type,
>>                                     __u32 ifindex);
>>  LIBBPF_API bool bpf_probe_map_type(enum bpf_map_type map_type, __u32 ifindex);
>> +LIBBPF_API bool bpf_probe_helper(__u32 id, enum bpf_prog_type prog_type,
> Any reason not to use enum bpf_func_id as id type (instead of __u32)?

No reason (other than me forgetting about that enum when writing the
function), I'll fix it, thanks!

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

* Re: [RFC bpf-next v3 2/9] tools: bpftool: add probes for /proc/ eBPF parameters
  2019-01-03 14:02 ` [RFC bpf-next v3 2/9] tools: bpftool: add probes for /proc/ eBPF parameters Quentin Monnet
@ 2019-01-04  6:32   ` Y Song
  2019-01-04 14:22     ` Quentin Monnet
  0 siblings, 1 reply; 18+ messages in thread
From: Y Song @ 2019-01-04  6:32 UTC (permalink / raw)
  To: Quentin Monnet
  Cc: Alexei Starovoitov, Daniel Borkmann, netdev, oss-drivers,
	Arnaldo Carvalho de Melo, Jesper Dangaard Brouer,
	Stanislav Fomichev

On Thu, Jan 3, 2019 at 9:26 AM Quentin Monnet
<quentin.monnet@netronome.com> 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

We have bpf_jit_limit as well to prevent excessive memory for
unprivileged users.
Do we want to add it here?

>         },
>         ...
>     }
>
> These probes are skipped if procfs is not mounted.
>
> v2:
> - Remove C-style macros output from this patch.
>
> Signed-off-by: Quentin Monnet <quentin.monnet@netronome.com>
> Reviewed-by: Jakub Kicinski <jakub.kicinski@netronome.com>
> ---
>  tools/bpf/bpftool/feature.c | 168 ++++++++++++++++++++++++++++++++++++
>  1 file changed, 168 insertions(+)
>
> diff --git a/tools/bpf/bpftool/feature.c b/tools/bpf/bpftool/feature.c
> index 954fb12a5228..37fe79f59015 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
> @@ -42,6 +61,135 @@ print_start_section(const char *json_title, const char *plain_title)
>
>  /* 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(void)
> +{
> +       int res;
> +
> +       res = read_procfs("/proc/sys/kernel/unprivileged_bpf_disabled");
> +       if (json_output) {
> +               jsonw_int_field(json_wtr, "unprivileged_bpf_disabled", res);
> +       } 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(void)
> +{
> +       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 {
> +               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(void)
> +{
> +       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 {
> +               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(void)
> +{
> +       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 {
> +               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 bool probe_bpf_syscall(void)
>  {
>         bool res;
> @@ -88,6 +236,26 @@ 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",
> +                                   "Scanning system configuration...");
> +               if (check_procfs()) {
> +                       probe_unprivileged_disabled();
> +                       probe_jit_enable();
> +                       probe_jit_harden();
> +                       probe_jit_kallsyms();
> +               } 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",
>                             "Scanning system call availability...");
>
> --
> 2.17.1
>

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

* Re: [RFC bpf-next v3 3/9] tools: bpftool: add probes for kernel configuration options
  2019-01-03 14:02 ` [RFC bpf-next v3 3/9] tools: bpftool: add probes for kernel configuration options Quentin Monnet
@ 2019-01-04  6:35   ` Y Song
  2019-01-04 14:27     ` Quentin Monnet
  0 siblings, 1 reply; 18+ messages in thread
From: Y Song @ 2019-01-04  6:35 UTC (permalink / raw)
  To: Quentin Monnet
  Cc: Alexei Starovoitov, Daniel Borkmann, netdev, oss-drivers,
	Arnaldo Carvalho de Melo, Jesper Dangaard Brouer,
	Stanislav Fomichev

On Thu, Jan 3, 2019 at 9:27 AM Quentin Monnet
<quentin.monnet@netronome.com> 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",
>             ...
>         }
>     }
>
> v3:
> - Add a comment about /proc/config.gz not being supported as a path for
>   the config file at this time.
> - Use p_info() instead of p_err() on failure to get options from config
>   file, as bpftool keeps probing other parameters and that would
>   possibly create duplicate "error" entries for JSON.
>
> v2:
> - Remove C-style macros output from this patch.
> - NOT addressed: grouping of those config options into subsections
>   (I don't see an easy way of grouping them at the moment, please see
>   also the discussion on v1 thread).
>
> Signed-off-by: Quentin Monnet <quentin.monnet@netronome.com>
> Reviewed-by: Jakub Kicinski <jakub.kicinski@netronome.com>
> ---
>  tools/bpf/bpftool/feature.c | 142 ++++++++++++++++++++++++++++++++++++
>  1 file changed, 142 insertions(+)
>
> diff --git a/tools/bpf/bpftool/feature.c b/tools/bpf/bpftool/feature.c
> index 37fe79f59015..05c16fe67005 100644
> --- a/tools/bpf/bpftool/feature.c
> +++ b/tools/bpf/bpftool/feature.c
> @@ -48,6 +48,30 @@ print_bool_feature(const char *feat_name, const char *plain_name, bool res)
>                 printf("%s is %savailable\n", plain_name, res ? "" : "NOT ");
>  }
>
> +static void print_kernel_option(const char *name, const char *value)
> +{
> +       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 (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 *plain_title)
>  {
> @@ -190,6 +214,123 @@ static void probe_jit_kallsyms(void)
>         }
>  }
>
> +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(void)
> +{
> +       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",

The list does not have any tracing specific configs like
CONFIG_KPROBES, CONFIG_UPROBES, etc.
Should we check those as well?

> +       };
> +       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) {
> +               /* Some distributions put the config file at /proc/config, give
> +                * it a try.
> +                * Sometimes it is also at /proc/config.gz but we do not try
> +                * this one for now, it would require linking against libz.
> +                */
> +               fd = fopen("/proc/config", "r");
> +       }
> +       if (!fd) {
> +               p_info("skipping kernel config, can't open file: %s",
> +                      strerror(errno));
> +               goto no_config;
> +       }
> +       /* Sanity checks */
> +       ret = getline(&buf, &n, fd);
> +       ret = getline(&buf, &n, fd);
> +       if (!buf || !ret) {
> +               p_info("skipping kernel config, can't read from file: %s",
> +                      strerror(errno));
> +               free(buf);
> +               goto no_config;
> +       }
> +       if (strcmp(buf, "# Automatically generated file; DO NOT EDIT.\n")) {
> +               p_info("skipping kernel config, can't find correct 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);
> +               free(value);
> +       }
> +       fclose(fd);
> +       return;
> +
> +no_config:
> +       for (i = 0; i < ARRAY_SIZE(options); i++)
> +               print_kernel_option(options[i], NULL);
> +}
> +
>  static bool probe_bpf_syscall(void)
>  {
>         bool res;
> @@ -249,6 +390,7 @@ static int do_probe(int argc, char **argv)
>                 } else {
>                         p_info("/* procfs not mounted, skipping related probes */");
>                 }
> +               probe_kernel_image_config();
>                 if (json_output)
>                         jsonw_end_object(json_wtr);
>                 else
> --
> 2.17.1
>

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

* Re: [RFC bpf-next v3 2/9] tools: bpftool: add probes for /proc/ eBPF parameters
  2019-01-04  6:32   ` Y Song
@ 2019-01-04 14:22     ` Quentin Monnet
  0 siblings, 0 replies; 18+ messages in thread
From: Quentin Monnet @ 2019-01-04 14:22 UTC (permalink / raw)
  To: Y Song
  Cc: Alexei Starovoitov, Daniel Borkmann, netdev, oss-drivers,
	Arnaldo Carvalho de Melo, Jesper Dangaard Brouer,
	Stanislav Fomichev

2019-01-03 22:32 UTC-0800 ~ Y Song <ys114321@gmail.com>
> On Thu, Jan 3, 2019 at 9:26 AM Quentin Monnet
> <quentin.monnet@netronome.com> 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
> 
> We have bpf_jit_limit as well to prevent excessive memory for
> unprivileged users.
> Do we want to add it here?

Yes, thanks!

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

* Re: [RFC bpf-next v3 3/9] tools: bpftool: add probes for kernel configuration options
  2019-01-04  6:35   ` Y Song
@ 2019-01-04 14:27     ` Quentin Monnet
  2019-01-04 17:36       ` Y Song
  0 siblings, 1 reply; 18+ messages in thread
From: Quentin Monnet @ 2019-01-04 14:27 UTC (permalink / raw)
  To: Y Song
  Cc: Alexei Starovoitov, Daniel Borkmann, netdev, oss-drivers,
	Arnaldo Carvalho de Melo, Jesper Dangaard Brouer,
	Stanislav Fomichev

2019-01-03 22:35 UTC-0800 ~ Y Song <ys114321@gmail.com>
> On Thu, Jan 3, 2019 at 9:27 AM Quentin Monnet
> <quentin.monnet@netronome.com> 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",
>>             ...
>>         }
>>     }
>>
>> v3:
>> - Add a comment about /proc/config.gz not being supported as a path for
>>   the config file at this time.
>> - Use p_info() instead of p_err() on failure to get options from config
>>   file, as bpftool keeps probing other parameters and that would
>>   possibly create duplicate "error" entries for JSON.
>>
>> v2:
>> - Remove C-style macros output from this patch.
>> - NOT addressed: grouping of those config options into subsections
>>   (I don't see an easy way of grouping them at the moment, please see
>>   also the discussion on v1 thread).
>>
>> Signed-off-by: Quentin Monnet <quentin.monnet@netronome.com>
>> Reviewed-by: Jakub Kicinski <jakub.kicinski@netronome.com>
>> ---
>>  tools/bpf/bpftool/feature.c | 142 ++++++++++++++++++++++++++++++++++++
>>  1 file changed, 142 insertions(+)
>>
>> diff --git a/tools/bpf/bpftool/feature.c b/tools/bpf/bpftool/feature.c
>> index 37fe79f59015..05c16fe67005 100644
>> --- a/tools/bpf/bpftool/feature.c
>> +++ b/tools/bpf/bpftool/feature.c
>> @@ -48,6 +48,30 @@ print_bool_feature(const char *feat_name, const char *plain_name, bool res)
>>                 printf("%s is %savailable\n", plain_name, res ? "" : "NOT ");
>>  }
>>
>> +static void print_kernel_option(const char *name, const char *value)
>> +{
>> +       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 (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 *plain_title)
>>  {
>> @@ -190,6 +214,123 @@ static void probe_jit_kallsyms(void)
>>         }
>>  }
>>
>> +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(void)
>> +{
>> +       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",
> 
> The list does not have any tracing specific configs like
> CONFIG_KPROBES, CONFIG_UPROBES, etc.
> Should we check those as well?

I didn't find any BPF items for which compiling would depend on those
options, that's why they are not in the list at the moment. But yeah,
they are definitely useful to tell if kprobe-attached programs have any
chance to work, so it would make sense I guess... What options do you
have in mind exactly? CONFIG_KPROBES and CONFIG_UPROBES, do you believe
CONFING_KPROBE_EVENTS and CONFIG_UPROBE_EVENTS would also be relevant?

Thanks,
Quentin

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

* Re: [RFC bpf-next v3 3/9] tools: bpftool: add probes for kernel configuration options
  2019-01-04 14:27     ` Quentin Monnet
@ 2019-01-04 17:36       ` Y Song
  2019-01-05 13:16         ` Quentin Monnet
  0 siblings, 1 reply; 18+ messages in thread
From: Y Song @ 2019-01-04 17:36 UTC (permalink / raw)
  To: Quentin Monnet
  Cc: Alexei Starovoitov, Daniel Borkmann, netdev, oss-drivers,
	Arnaldo Carvalho de Melo, Jesper Dangaard Brouer,
	Stanislav Fomichev

On Fri, Jan 4, 2019 at 6:27 AM Quentin Monnet
<quentin.monnet@netronome.com> wrote:
>
> 2019-01-03 22:35 UTC-0800 ~ Y Song <ys114321@gmail.com>
> > On Thu, Jan 3, 2019 at 9:27 AM Quentin Monnet
> > <quentin.monnet@netronome.com> 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",
> >>             ...
> >>         }
> >>     }
> >>
> >> v3:
> >> - Add a comment about /proc/config.gz not being supported as a path for
> >>   the config file at this time.
> >> - Use p_info() instead of p_err() on failure to get options from config
> >>   file, as bpftool keeps probing other parameters and that would
> >>   possibly create duplicate "error" entries for JSON.
> >>
> >> v2:
> >> - Remove C-style macros output from this patch.
> >> - NOT addressed: grouping of those config options into subsections
> >>   (I don't see an easy way of grouping them at the moment, please see
> >>   also the discussion on v1 thread).
> >>
> >> Signed-off-by: Quentin Monnet <quentin.monnet@netronome.com>
> >> Reviewed-by: Jakub Kicinski <jakub.kicinski@netronome.com>
> >> ---
> >>  tools/bpf/bpftool/feature.c | 142 ++++++++++++++++++++++++++++++++++++
> >>  1 file changed, 142 insertions(+)
> >>
> >> diff --git a/tools/bpf/bpftool/feature.c b/tools/bpf/bpftool/feature.c
> >> index 37fe79f59015..05c16fe67005 100644
> >> --- a/tools/bpf/bpftool/feature.c
> >> +++ b/tools/bpf/bpftool/feature.c
> >> @@ -48,6 +48,30 @@ print_bool_feature(const char *feat_name, const char *plain_name, bool res)
> >>                 printf("%s is %savailable\n", plain_name, res ? "" : "NOT ");
> >>  }
> >>
> >> +static void print_kernel_option(const char *name, const char *value)
> >> +{
> >> +       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 (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 *plain_title)
> >>  {
> >> @@ -190,6 +214,123 @@ static void probe_jit_kallsyms(void)
> >>         }
> >>  }
> >>
> >> +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(void)
> >> +{
> >> +       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",
> >
> > The list does not have any tracing specific configs like
> > CONFIG_KPROBES, CONFIG_UPROBES, etc.
> > Should we check those as well?
>
> I didn't find any BPF items for which compiling would depend on those
> options, that's why they are not in the list at the moment. But yeah,

That is true. They are kind of independent for compilations.

> they are definitely useful to tell if kprobe-attached programs have any
> chance to work, so it would make sense I guess... What options do you
> have in mind exactly? CONFIG_KPROBES and CONFIG_UPROBES, do you believe
> CONFING_KPROBE_EVENTS and CONFIG_UPROBE_EVENTS would also be relevant?

The following list should be a good start:
CONFIG_TRACING
CONFIG_KPROBE_EVENTS
CONFIG_UPROBE_EVENTS
CONFIG_BPF_EVENTS
CONFIG_FTRACE_SYSCALLS

No need for CONFIG_KPROBES and CONFIG_UPROBES which
are implied by CONFIG_KPROBE_EVENTS and CONFIG_UPROBE_EVENTS respectively,
and BPF mostly hooked to the events.

TRACING will enable tracepoint.
BPF_EVENTS depends on KPROBE_EVENTS or UPROBE_EVENTS, and PERF_EVENTS.
Having both CONFIG_KPROBE_EVENTS and CONFIG_UPROBE_EVENTS will tell
whether one of them or both are supported.
CONFIG_FTRACE_SYSCALLS needed to tell whether syscall tracepoints will
be supported or not
so bpf programs attached to these syscall tracepoints will work.

>
> Thanks,
> Quentin

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

* Re: [RFC bpf-next v3 3/9] tools: bpftool: add probes for kernel configuration options
  2019-01-04 17:36       ` Y Song
@ 2019-01-05 13:16         ` Quentin Monnet
  0 siblings, 0 replies; 18+ messages in thread
From: Quentin Monnet @ 2019-01-05 13:16 UTC (permalink / raw)
  To: Y Song
  Cc: Alexei Starovoitov, Daniel Borkmann, netdev, oss-drivers,
	Arnaldo Carvalho de Melo, Jesper Dangaard Brouer,
	Stanislav Fomichev

2019-01-04 09:36 UTC-0800 ~ Y Song <ys114321@gmail.com>
> On Fri, Jan 4, 2019 at 6:27 AM Quentin Monnet
> <quentin.monnet@netronome.com> wrote:
>>
>> 2019-01-03 22:35 UTC-0800 ~ Y Song <ys114321@gmail.com>
>>> On Thu, Jan 3, 2019 at 9:27 AM Quentin Monnet
>>> <quentin.monnet@netronome.com> 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",
>>>>              ...
>>>>          }
>>>>      }
>>>>
>>>> v3:
>>>> - Add a comment about /proc/config.gz not being supported as a path for
>>>>    the config file at this time.
>>>> - Use p_info() instead of p_err() on failure to get options from config
>>>>    file, as bpftool keeps probing other parameters and that would
>>>>    possibly create duplicate "error" entries for JSON.
>>>>
>>>> v2:
>>>> - Remove C-style macros output from this patch.
>>>> - NOT addressed: grouping of those config options into subsections
>>>>    (I don't see an easy way of grouping them at the moment, please see
>>>>    also the discussion on v1 thread).
>>>>
>>>> Signed-off-by: Quentin Monnet <quentin.monnet@netronome.com>
>>>> Reviewed-by: Jakub Kicinski <jakub.kicinski@netronome.com>
>>>> ---
>>>>   tools/bpf/bpftool/feature.c | 142 ++++++++++++++++++++++++++++++++++++
>>>>   1 file changed, 142 insertions(+)
>>>>
>>>> diff --git a/tools/bpf/bpftool/feature.c b/tools/bpf/bpftool/feature.c
>>>> index 37fe79f59015..05c16fe67005 100644
>>>> --- a/tools/bpf/bpftool/feature.c
>>>> +++ b/tools/bpf/bpftool/feature.c
>>>> @@ -48,6 +48,30 @@ print_bool_feature(const char *feat_name, const char *plain_name, bool res)
>>>>                  printf("%s is %savailable\n", plain_name, res ? "" : "NOT ");
>>>>   }
>>>>
>>>> +static void print_kernel_option(const char *name, const char *value)
>>>> +{
>>>> +       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 (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 *plain_title)
>>>>   {
>>>> @@ -190,6 +214,123 @@ static void probe_jit_kallsyms(void)
>>>>          }
>>>>   }
>>>>
>>>> +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(void)
>>>> +{
>>>> +       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",
>>>
>>> The list does not have any tracing specific configs like
>>> CONFIG_KPROBES, CONFIG_UPROBES, etc.
>>> Should we check those as well?
>>
>> I didn't find any BPF items for which compiling would depend on those
>> options, that's why they are not in the list at the moment. But yeah,
> 
> That is true. They are kind of independent for compilations.
> 
>> they are definitely useful to tell if kprobe-attached programs have any
>> chance to work, so it would make sense I guess... What options do you
>> have in mind exactly? CONFIG_KPROBES and CONFIG_UPROBES, do you believe
>> CONFING_KPROBE_EVENTS and CONFIG_UPROBE_EVENTS would also be relevant?
> 
> The following list should be a good start:
> CONFIG_TRACING
> CONFIG_KPROBE_EVENTS
> CONFIG_UPROBE_EVENTS
> CONFIG_BPF_EVENTS
> CONFIG_FTRACE_SYSCALLS
> 
> No need for CONFIG_KPROBES and CONFIG_UPROBES which
> are implied by CONFIG_KPROBE_EVENTS and CONFIG_UPROBE_EVENTS respectively,
> and BPF mostly hooked to the events.
> 
> TRACING will enable tracepoint.
> BPF_EVENTS depends on KPROBE_EVENTS or UPROBE_EVENTS, and PERF_EVENTS.
> Having both CONFIG_KPROBE_EVENTS and CONFIG_UPROBE_EVENTS will tell
> whether one of them or both are supported.
> CONFIG_FTRACE_SYSCALLS needed to tell whether syscall tracepoints will
> be supported or not
> so bpf programs attached to these syscall tracepoints will work.

Sounds good. CONFIG_BPF_EVENTS is in the list already, I'll add the 
other ones for v4 once bpf-next reopens. Thanks a lot for the details!

Quentin

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

end of thread, other threads:[~2019-01-05 13:16 UTC | newest]

Thread overview: 18+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-01-03 14:02 [RFC bpf-next v3 0/9] tools: bpftool: add probes for system and device Quentin Monnet
2019-01-03 14:02 ` [RFC bpf-next v3 1/9] tools: bpftool: add basic probe capability, probe syscall availability Quentin Monnet
2019-01-03 14:02 ` [RFC bpf-next v3 2/9] tools: bpftool: add probes for /proc/ eBPF parameters Quentin Monnet
2019-01-04  6:32   ` Y Song
2019-01-04 14:22     ` Quentin Monnet
2019-01-03 14:02 ` [RFC bpf-next v3 3/9] tools: bpftool: add probes for kernel configuration options Quentin Monnet
2019-01-04  6:35   ` Y Song
2019-01-04 14:27     ` Quentin Monnet
2019-01-04 17:36       ` Y Song
2019-01-05 13:16         ` Quentin Monnet
2019-01-03 14:02 ` [RFC bpf-next v3 4/9] tools: bpftool: add probes for eBPF program types Quentin Monnet
2019-01-03 14:02 ` [RFC bpf-next v3 5/9] tools: bpftool: add probes for eBPF map types Quentin Monnet
2019-01-03 14:02 ` [RFC bpf-next v3 6/9] tools: bpftool: add probes for eBPF helper functions Quentin Monnet
2019-01-03 17:15   ` Stanislav Fomichev
2019-01-03 17:26     ` Quentin Monnet
2019-01-03 14:02 ` [RFC bpf-next v3 7/9] tools: bpftool: add C-style "#define" output for probes Quentin Monnet
2019-01-03 14:02 ` [RFC bpf-next v3 8/9] tools: bpftool: add probes for a network device Quentin Monnet
2019-01-03 14:02 ` [RFC bpf-next v3 9/9] tools: bpftool: add bash completion for bpftool probes Quentin Monnet

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).