lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <20181220122432.27511-9-quentin.monnet@netronome.com>
Date:   Thu, 20 Dec 2018 12:24:31 +0000
From:   Quentin Monnet <quentin.monnet@...ronome.com>
To:     Alexei Starovoitov <ast@...nel.org>,
        Daniel Borkmann <daniel@...earbox.net>
Cc:     netdev@...r.kernel.org, oss-drivers@...ronome.com,
        Quentin Monnet <quentin.monnet@...ronome.com>,
        Arnaldo Carvalho de Melo <acme@...nel.org>,
        Jesper Dangaard Brouer <brouer@...hat.com>,
        Stanislav Fomichev <sdf@...gle.com>
Subject: [RFC PATCH bpf-next v2 8/9] tools: bpftool: add probes for a network device

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": {
            "kernel_version_code": 267008,
            "have_bpf_syscall": true
        },
        "program_types": {
            "have_sched_cls_prog_type": false,
            "have_xdp_prog_type": false
        },
        ...
    }

As the target is a network device, /proc/ parameters and kernel
configuration are NOT dumped. Availability of the bpf() syscall and
kernel version are still probed, as they are necessary for the remaining
probes (although kernel version is no longer needed on the latest
kernels, it is required for probing availability of kprobes on older
kernels).

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 as well, for all supported 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@...ronome.com>
Reviewed-by: Jakub Kicinski <jakub.kicinski@...ronome.com>
---
 .../bpftool/Documentation/bpftool-feature.rst | 18 +++++-
 tools/bpf/bpftool/common.c                    |  2 +-
 tools/bpf/bpftool/feature.c                   | 58 +++++++++++++++----
 tools/bpf/bpftool/main.h                      |  1 +
 4 files changed, 65 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/common.c b/tools/bpf/bpftool/common.c
index 897483457bf0..cf454e8eca52 100644
--- a/tools/bpf/bpftool/common.c
+++ b/tools/bpf/bpftool/common.c
@@ -542,7 +542,7 @@ static int read_sysfs_hex_int(char *path)
 	return strtol(vendor_id_buf, NULL, 0);
 }
 
-static int read_sysfs_netdev_hex_int(char *devname, const char *entry_name)
+int read_sysfs_netdev_hex_int(char *devname, const char *entry_name)
 {
 	char full_path[64];
 
diff --git a/tools/bpf/bpftool/feature.c b/tools/bpf/bpftool/feature.c
index cd84617312dc..f1ccd91c1f9f 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
@@ -414,14 +416,24 @@ static bool probe_bpf_syscall(const char *define_prefix)
 
 static void
 probe_prog_type(enum bpf_prog_type prog_type, int kernel_version,
-		bool *supported_types, const char *define_prefix)
+		bool *supported_types, const char *define_prefix, __u32 ifindex)
 {
 	char 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, kernel_version, 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, kernel_version, ifindex);
 
 	supported_types[prog_type] |= res;
 
@@ -440,14 +452,15 @@ probe_prog_type(enum bpf_prog_type prog_type, int kernel_version,
 }
 
 static void
-probe_map_type(enum bpf_map_type map_type, const char *define_prefix)
+probe_map_type(enum bpf_map_type map_type, const char *define_prefix,
+	       __u32 ifindex)
 {
 	char feat_name[128], 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) {
@@ -465,7 +478,7 @@ probe_map_type(enum bpf_map_type map_type, const char *define_prefix)
 
 static void
 probe_helper(__u32 id, const char *name, int kernel_version,
-	     bool *supported_types, const char *define_prefix)
+	     bool *supported_types, const char *define_prefix, __u32 ifindex)
 {
 	char feat_name[128], plain_desc[128], define_name[128];
 	unsigned int i;
@@ -514,7 +527,9 @@ static int do_probe(int argc, char **argv)
 	const char *define_prefix = NULL;
 	bool supported_types[128] = {};
 	int kernel_version;
+	__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.
@@ -534,6 +549,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();
@@ -552,7 +585,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;
 		}
@@ -587,6 +620,8 @@ static int do_probe(int argc, char **argv)
 		else
 			printf("\n");
 		break;
+	default:
+		break;
 	}
 
 	print_start_section("syscall_config",
@@ -594,6 +629,7 @@ static int do_probe(int argc, char **argv)
 			    "/*** System call availability ***/",
 			    define_prefix);
 
+	/* Get kernel version in all cases, we need it for kprobe programs */
 	kernel_version = probe_kernel_version(define_prefix);
 	if (!probe_bpf_syscall(define_prefix))
 		/* bpf() syscall unavailable, don't probe other BPF features */
@@ -606,7 +642,7 @@ 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, kernel_version, supported_types,
-				define_prefix);
+				define_prefix, ifindex);
 
 	print_end_then_start_section("map_types",
 				     "Scanning eBPF map types...",
@@ -614,7 +650,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...",
@@ -623,7 +659,7 @@ static int do_probe(int argc, char **argv)
 
 	for (i = 1; i < ARRAY_SIZE(helper_name); i++)
 		probe_helper(i, helper_name[i], kernel_version,
-			     supported_types, define_prefix);
+			     supported_types, define_prefix, ifindex);
 
 exit_close_json:
 	if (json_output) {
@@ -644,8 +680,10 @@ static int do_help(int argc, char **argv)
 	}
 
 	fprintf(stderr,
-		"Usage: %s %s probe [kernel] [macros [prefix PREFIX]]\n"
+		"Usage: %s %s probe [COMPONENT] [macros [prefix PREFIX]]\n"
 		"       %s %s help\n"
+		"\n"
+		"       COMPONENT := { kernel | dev NAME }\n"
 		"",
 		bin_name, argv[-2], bin_name, argv[-2]);
 
diff --git a/tools/bpf/bpftool/main.h b/tools/bpf/bpftool/main.h
index d7dd84d3c660..5caea42d1618 100644
--- a/tools/bpf/bpftool/main.h
+++ b/tools/bpf/bpftool/main.h
@@ -185,6 +185,7 @@ void print_hex_data_json(uint8_t *data, size_t len);
 
 unsigned int get_page_size(void);
 unsigned int get_possible_cpus(void);
+int read_sysfs_netdev_hex_int(char *devname, const char *entry_name);
 const char *
 ifindex_to_bfd_params(__u32 ifindex, __u64 ns_dev, __u64 ns_ino,
 		      const char **opt);
-- 
2.17.1

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ