diff options
-rw-r--r-- | tools/bpf/bpftool/Documentation/bpftool-feature.rst | 4 | ||||
-rw-r--r-- | tools/bpf/bpftool/feature.c | 51 | ||||
-rw-r--r-- | tools/lib/bpf/libbpf.h | 2 | ||||
-rw-r--r-- | tools/lib/bpf/libbpf.map | 1 | ||||
-rw-r--r-- | tools/lib/bpf/libbpf_probes.c | 63 |
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 | ||
29 | static 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 | ||
30 | static bool check_procfs(void) | 37 | static 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 | ||
468 | static void | ||
469 | probe_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 | |||
461 | static int do_probe(int argc, char **argv) | 506 | static 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 | |||
536 | exit_close_json: | 587 | exit_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, | |||
366 | LIBBPF_API bool bpf_probe_prog_type(enum bpf_prog_type prog_type, | 366 | LIBBPF_API bool bpf_probe_prog_type(enum bpf_prog_type prog_type, |
367 | __u32 ifindex); | 367 | __u32 ifindex); |
368 | LIBBPF_API bool bpf_probe_map_type(enum bpf_map_type map_type, __u32 ifindex); | 368 | LIBBPF_API bool bpf_probe_map_type(enum bpf_map_type map_type, __u32 ifindex); |
369 | LIBBPF_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 | ||
128 | LIBBPF_0.0.2 { | 128 | LIBBPF_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 | ||
18 | static bool grep(const char *buffer, const char *pattern) | ||
19 | { | ||
20 | return !!strstr(buffer, pattern); | ||
21 | } | ||
22 | |||
23 | static 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 | |||
14 | static int get_kernel_version(void) | 49 | static 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 | |||
216 | bool 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 | } | ||