summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorQuentin Monnet <quentin.monnet@netronome.com>2019-01-17 10:27:55 -0500
committerAlexei Starovoitov <ast@kernel.org>2019-01-23 01:15:40 -0500
commit2d3ea5e85dd867712ba8747cb01c2d88376ead5c (patch)
treeab6e05e131cece6ffb425646ae1e1bfb6664a3c4
parentf99e166397f0298fe78bce24c55c6d074f9bf196 (diff)
tools: bpftool: add probes for eBPF helper functions
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", ... ], ... } } v5: - In libbpf.map, move global symbol to the new LIBBPF_0.0.2 section. v4: - Use "enum bpf_func_id" instead of "__u32" in bpf_probe_helper() declaration for the type of the argument used to pass the id of the helper to probe. - Undef BPF_HELPER_MAKE_ENTRY after using it. 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> Reviewed-by: Jakub Kicinski <jakub.kicinski@netronome.com> Reviewed-by: Stanislav Fomichev <sdf@google.com> Signed-off-by: Alexei Starovoitov <ast@kernel.org>
-rw-r--r--tools/bpf/bpftool/Documentation/bpftool-feature.rst4
-rw-r--r--tools/bpf/bpftool/feature.c51
-rw-r--r--tools/lib/bpf/libbpf.h2
-rw-r--r--tools/lib/bpf/libbpf.map1
-rw-r--r--tools/lib/bpf/libbpf_probes.c63
5 files changed, 121 insertions, 0 deletions
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
30 30
31 Keyword **kernel** can be omitted. 31 Keyword **kernel** can be omitted.
32 32
33 Note that when probed, some eBPF helpers (e.g.
34 **bpf_trace_printk**\ () or **bpf_probe_write_user**\ ()) may
35 print warnings to kernel logs.
36
33 **bpftool feature help** 37 **bpftool feature help**
34 Print short help message. 38 Print short help message.
35 39
diff --git a/tools/bpf/bpftool/feature.c b/tools/bpf/bpftool/feature.c
index cc731475c74b..55c8d215ca44 100644
--- a/tools/bpf/bpftool/feature.c
+++ b/tools/bpf/bpftool/feature.c
@@ -25,6 +25,13 @@ enum probe_component {
25 COMPONENT_KERNEL, 25 COMPONENT_KERNEL,
26}; 26};
27 27
28#define BPF_HELPER_MAKE_ENTRY(name) [BPF_FUNC_ ## name] = "bpf_" # name
29static const char * const helper_name[] = {
30 __BPF_FUNC_MAPPER(BPF_HELPER_MAKE_ENTRY)
31};
32
33#undef BPF_HELPER_MAKE_ENTRY
34
28/* Miscellaneous utility functions */ 35/* Miscellaneous utility functions */
29 36
30static bool check_procfs(void) 37static bool check_procfs(void)
@@ -458,6 +465,44 @@ static void probe_map_type(enum bpf_map_type map_type)
458 print_bool_feature(feat_name, plain_desc, res); 465 print_bool_feature(feat_name, plain_desc, res);
459} 466}
460 467
468static void
469probe_helpers_for_progtype(enum bpf_prog_type prog_type, bool supported_type)
470{
471 const char *ptype_name = prog_type_name[prog_type];
472 char feat_name[128];
473 unsigned int id;
474 bool res;
475
476 if (json_output) {
477 sprintf(feat_name, "%s_available_helpers", ptype_name);
478 jsonw_name(json_wtr, feat_name);
479 jsonw_start_array(json_wtr);
480 } else {
481 printf("eBPF helpers supported for program type %s:",
482 ptype_name);
483 }
484
485 for (id = 1; id < ARRAY_SIZE(helper_name); id++) {
486 if (!supported_type)
487 res = false;
488 else
489 res = bpf_probe_helper(id, prog_type, 0);
490
491 if (json_output) {
492 if (res)
493 jsonw_string(json_wtr, helper_name[id]);
494 } else {
495 if (res)
496 printf("\n\t- %s", helper_name[id]);
497 }
498 }
499
500 if (json_output)
501 jsonw_end_array(json_wtr);
502 else
503 printf("\n");
504}
505
461static int do_probe(int argc, char **argv) 506static int do_probe(int argc, char **argv)
462{ 507{
463 enum probe_component target = COMPONENT_UNSPEC; 508 enum probe_component target = COMPONENT_UNSPEC;
@@ -533,6 +578,12 @@ static int do_probe(int argc, char **argv)
533 for (i = BPF_MAP_TYPE_UNSPEC + 1; i < map_type_name_size; i++) 578 for (i = BPF_MAP_TYPE_UNSPEC + 1; i < map_type_name_size; i++)
534 probe_map_type(i); 579 probe_map_type(i);
535 580
581 print_end_then_start_section("helpers",
582 "Scanning eBPF helper functions...");
583
584 for (i = BPF_PROG_TYPE_UNSPEC + 1; i < ARRAY_SIZE(prog_type_name); i++)
585 probe_helpers_for_progtype(i, supported_types[i]);
586
536exit_close_json: 587exit_close_json:
537 if (json_output) { 588 if (json_output) {
538 /* End current "section" of probes */ 589 /* End current "section" of probes */
diff --git a/tools/lib/bpf/libbpf.h b/tools/lib/bpf/libbpf.h
index 72385f6f9415..62ae6cb93da1 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,
366LIBBPF_API bool bpf_probe_prog_type(enum bpf_prog_type prog_type, 366LIBBPF_API bool bpf_probe_prog_type(enum bpf_prog_type prog_type,
367 __u32 ifindex); 367 __u32 ifindex);
368LIBBPF_API bool bpf_probe_map_type(enum bpf_map_type map_type, __u32 ifindex); 368LIBBPF_API bool bpf_probe_map_type(enum bpf_map_type map_type, __u32 ifindex);
369LIBBPF_API bool bpf_probe_helper(enum bpf_func_id id,
370 enum bpf_prog_type prog_type, __u32 ifindex);
369 371
370#ifdef __cplusplus 372#ifdef __cplusplus
371} /* extern "C" */ 373} /* extern "C" */
diff --git a/tools/lib/bpf/libbpf.map b/tools/lib/bpf/libbpf.map
index bb2dfc3b2d7b..266bc95d0142 100644
--- a/tools/lib/bpf/libbpf.map
+++ b/tools/lib/bpf/libbpf.map
@@ -127,6 +127,7 @@ LIBBPF_0.0.1 {
127 127
128LIBBPF_0.0.2 { 128LIBBPF_0.0.2 {
129 global: 129 global:
130 bpf_probe_helper;
130 bpf_probe_map_type; 131 bpf_probe_map_type;
131 bpf_probe_prog_type; 132 bpf_probe_prog_type;
132} LIBBPF_0.0.1; 133} LIBBPF_0.0.1;
diff --git a/tools/lib/bpf/libbpf_probes.c b/tools/lib/bpf/libbpf_probes.c
index f511bd317b87..8c3a1c04dcb2 100644
--- a/tools/lib/bpf/libbpf_probes.c
+++ b/tools/lib/bpf/libbpf_probes.c
@@ -2,7 +2,11 @@
2/* Copyright (c) 2019 Netronome Systems, Inc. */ 2/* Copyright (c) 2019 Netronome Systems, Inc. */
3 3
4#include <errno.h> 4#include <errno.h>
5#include <fcntl.h>
6#include <string.h>
7#include <stdlib.h>
5#include <unistd.h> 8#include <unistd.h>
9#include <net/if.h>
6#include <sys/utsname.h> 10#include <sys/utsname.h>
7 11
8#include <linux/filter.h> 12#include <linux/filter.h>
@@ -11,6 +15,37 @@
11#include "bpf.h" 15#include "bpf.h"
12#include "libbpf.h" 16#include "libbpf.h"
13 17
18static bool grep(const char *buffer, const char *pattern)
19{
20 return !!strstr(buffer, pattern);
21}
22
23static int get_vendor_id(int ifindex)
24{
25 char ifname[IF_NAMESIZE], path[64], buf[8];
26 ssize_t len;
27 int fd;
28
29 if (!if_indextoname(ifindex, ifname))
30 return -1;
31
32 snprintf(path, sizeof(path), "/sys/class/net/%s/device/vendor", ifname);
33
34 fd = open(path, O_RDONLY);
35 if (fd < 0)
36 return -1;
37
38 len = read(fd, buf, sizeof(buf));
39 close(fd);
40 if (len < 0)
41 return -1;
42 if (len >= (ssize_t)sizeof(buf))
43 return -1;
44 buf[len] = '\0';
45
46 return strtol(buf, NULL, 0);
47}
48
14static int get_kernel_version(void) 49static int get_kernel_version(void)
15{ 50{
16 int version, subversion, patchlevel; 51 int version, subversion, patchlevel;
@@ -177,3 +212,31 @@ bool bpf_probe_map_type(enum bpf_map_type map_type, __u32 ifindex)
177 212
178 return fd >= 0; 213 return fd >= 0;
179} 214}
215
216bool bpf_probe_helper(enum bpf_func_id id, enum bpf_prog_type prog_type,
217 __u32 ifindex)
218{
219 struct bpf_insn insns[2] = {
220 BPF_EMIT_CALL(id),
221 BPF_EXIT_INSN()
222 };
223 char buf[4096] = {};
224 bool res;
225
226 probe_load(prog_type, insns, ARRAY_SIZE(insns), buf, sizeof(buf),
227 ifindex);
228 res = !grep(buf, "invalid func ") && !grep(buf, "unknown func ");
229
230 if (ifindex) {
231 switch (get_vendor_id(ifindex)) {
232 case 0x19ee: /* Netronome specific */
233 res = res && !grep(buf, "not supported by FW") &&
234 !grep(buf, "unsupported function id");
235 break;
236 default:
237 break;
238 }
239 }
240
241 return res;
242}