netdev.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Stanislav Fomichev <sdf@fomichev.me>
To: Quentin Monnet <quentin.monnet@netronome.com>
Cc: Alexei Starovoitov <ast@kernel.org>,
	Daniel Borkmann <daniel@iogearbox.net>,
	netdev@vger.kernel.org, oss-drivers@netronome.com,
	Arnaldo Carvalho de Melo <acme@kernel.org>,
	Jesper Dangaard Brouer <brouer@redhat.com>,
	Stanislav Fomichev <sdf@google.com>
Subject: Re: [RFC PATCH bpf-next v2 6/9] tools: bpftool: add probes for eBPF helper functions
Date: Thu, 20 Dec 2018 09:53:01 -0800	[thread overview]
Message-ID: <20181220175301.GO20955@mini-arch.hsd1.ca.comcast.net> (raw)
In-Reply-To: <20181220122432.27511-7-quentin.monnet@netronome.com>

On 12/20, Quentin Monnet wrote:
> Similarly to what was done for program types and map types, add a set of
> probes to test the availability of the different eBPF helper functions
> on the current system.
> 
> Each known helper is tested with all program types supported by the
> system, in order to establish a compatibility matrix. Output is provided
> as a list of compatible program types, for each helper.
> 
> Sample output:
> 
>     # bpftool feature probe kernel
>     ...
>     Scanning eBPF helper functions...
>     ...
>     eBPF helper bpf_skb_change_head supported for program types: \
>             lwt_xmit sk_skb
>     eBPF helper bpf_xdp_adjust_head supported for program types: xdp
>     eBPF helper bpf_probe_read_str supported for program types: \
>             kprobe tracepoint perf_event raw_tracepoint
>     ...
> 
>     # bpftool --json --pretty feature probe kernel
>     {
>         ...
>         "helpers": {
>             ...
>             "bpf_skb_change_head_compat_list": ["lwt_xmit","sk_skb"
>             ],
>             "bpf_xdp_adjust_head_compat_list": ["xdp"
>             ],
>             "bpf_probe_read_str_compat_list": ["kprobe","tracepoint", \
>                     "perf_event","raw_tracepoint"
>             ],
>             ...
>         }
>     }
> 
> 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                   | 51 +++++++++++++++
>  tools/lib/bpf/libbpf.h                        |  2 +
>  tools/lib/bpf/libbpf.map                      |  1 +
>  tools/lib/bpf/libbpf_probes.c                 | 63 +++++++++++++++++++
>  5 files changed, 121 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 3c44953ded5a..bc483823014b 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)
> @@ -418,6 +423,45 @@ static void probe_map_type(enum bpf_map_type map_type)
>  	print_bool_feature(feat_name, plain_desc, res);
>  }
>  
> +static void
> +probe_helper(__u32 id, const char *name, int kernel_version,
> +	     bool *supported_types)
> +{
> +	char feat_name[128], plain_desc[128];
> +	unsigned int i;
> +
> +	sprintf(feat_name, "%s_compat_list", name);
> +	sprintf(plain_desc,
> +		"eBPF helper %s supported for program types:",
> +		name);
> +
> +	if (json_output) {
> +		jsonw_name(json_wtr, feat_name);
> +		jsonw_start_array(json_wtr);
> +	} else {
> +		printf("%s", plain_desc);
> +	}
> +
> +	for (i = BPF_PROG_TYPE_UNSPEC + 1;
> +	     i < ARRAY_SIZE(prog_type_name); i++) {
> +		if (!supported_types[i])
> +			continue;
> +
> +		if (!bpf_probe_helper(id, i, kernel_version, 0))
> +			continue;
> +
> +		if (json_output)
> +			jsonw_string(json_wtr, prog_type_name[i]);
> +		else
> +			printf(" %s", prog_type_name[i]);
> +	}
> +
> +	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;
> @@ -494,6 +538,13 @@ 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 = 1; i < ARRAY_SIZE(helper_name); i++)
> +		probe_helper(i, helper_name[i], kernel_version,
> +			     supported_types);
> +
>  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 202c1ee5c579..ab5b40af5fae 100644
> --- a/tools/lib/bpf/libbpf.h
> +++ b/tools/lib/bpf/libbpf.h
> @@ -361,6 +361,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,
>  				    int kernel_version, __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,
> +				 int kernel_version, __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 796fe1e66169..19aa062f33b5 100644
> --- a/tools/lib/bpf/libbpf_probes.c
> +++ b/tools/lib/bpf/libbpf_probes.c
> @@ -3,7 +3,11 @@
>  /* Copyright (c) 2018 Netronome Systems, Inc. */
>  
>  #include <errno.h>
> +#include <fcntl.h>
> +#include <string.h>
> +#include <stdlib.h>
>  #include <unistd.h>
> +#include <net/if.h>
>  
>  #include <linux/filter.h>
>  #include <linux/kernel.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 void
>  prog_load(enum bpf_prog_type prog_type, const struct bpf_insn *insns,
>  	  size_t insns_cnt, int kernel_version, char *buf, size_t buf_len,
> @@ -112,3 +147,31 @@ 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,
> +		      int kernel_version, __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), kernel_version,
> +		  buf, sizeof(buf), ifindex);
> +	res = !grep(buf, "invalid func ") && !grep(buf, "unknown func ");
Why not look at errno directly?
> +
> +	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
> 

  reply	other threads:[~2018-12-20 17:53 UTC|newest]

Thread overview: 29+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-12-20 12:24 [RFC PATCH bpf-next v2 0/9] tools: bpftool: add probes for system and device Quentin Monnet
2018-12-20 12:24 ` [RFC PATCH bpf-next v2 1/9] tools: bpftool: add basic probe capability, probe syscall and kversion Quentin Monnet
2018-12-20 12:24 ` [RFC PATCH bpf-next v2 2/9] tools: bpftool: add probes for /proc/ eBPF parameters Quentin Monnet
2018-12-20 12:24 ` [RFC PATCH bpf-next v2 3/9] tools: bpftool: add probes for kernel configuration options Quentin Monnet
2018-12-20 17:40   ` Stanislav Fomichev
2018-12-20 18:02     ` Quentin Monnet
2018-12-20 18:14       ` Stanislav Fomichev
2018-12-20 12:24 ` [RFC PATCH bpf-next v2 4/9] tools: bpftool: add probes for eBPF program types Quentin Monnet
2018-12-20 17:45   ` Stanislav Fomichev
2018-12-20 18:06     ` [oss-drivers] " Quentin Monnet
2018-12-20 18:17       ` Stanislav Fomichev
2018-12-20 18:21         ` Quentin Monnet
2018-12-20 18:29           ` Stanislav Fomichev
2018-12-20 12:24 ` [RFC PATCH bpf-next v2 5/9] tools: bpftool: add probes for eBPF map types Quentin Monnet
2018-12-20 17:47   ` Stanislav Fomichev
2018-12-20 18:10     ` Quentin Monnet
2018-12-20 18:18       ` Stanislav Fomichev
2018-12-20 18:27         ` Quentin Monnet
2018-12-20 18:42           ` Stanislav Fomichev
2018-12-20 18:45             ` Quentin Monnet
2018-12-20 12:24 ` [RFC PATCH bpf-next v2 6/9] tools: bpftool: add probes for eBPF helper functions Quentin Monnet
2018-12-20 17:53   ` Stanislav Fomichev [this message]
2018-12-20 18:14     ` Quentin Monnet
2018-12-20 12:24 ` [RFC PATCH bpf-next v2 7/9] tools: bpftool: add C-style "#define" output for probes Quentin Monnet
2018-12-20 17:25   ` Daniel Borkmann
2018-12-20 20:05     ` Quentin Monnet
2018-12-20 22:29       ` Daniel Borkmann
2018-12-20 12:24 ` [RFC PATCH bpf-next v2 8/9] tools: bpftool: add probes for a network device Quentin Monnet
2018-12-20 12:24 ` [RFC PATCH bpf-next v2 9/9] tools: bpftool: add bash completion for bpftool probes Quentin Monnet

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20181220175301.GO20955@mini-arch.hsd1.ca.comcast.net \
    --to=sdf@fomichev.me \
    --cc=acme@kernel.org \
    --cc=ast@kernel.org \
    --cc=brouer@redhat.com \
    --cc=daniel@iogearbox.net \
    --cc=netdev@vger.kernel.org \
    --cc=oss-drivers@netronome.com \
    --cc=quentin.monnet@netronome.com \
    --cc=sdf@google.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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).