summaryrefslogtreecommitdiffstats
path: root/tools/bpf/bpftool
diff options
context:
space:
mode:
authorQuentin Monnet <quentin.monnet@netronome.com>2019-01-17 10:27:56 -0500
committerAlexei Starovoitov <ast@kernel.org>2019-01-23 01:15:40 -0500
commitd267cff46753b0e8b2f169ff4a3f1bb40c2387a8 (patch)
tree4242dcffe79288fdbcab44bc287bdfd189db167c /tools/bpf/bpftool
parent2d3ea5e85dd867712ba8747cb01c2d88376ead5c (diff)
tools: bpftool: add C-style "#define" output for probes
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> Reviewed-by: Jakub Kicinski <jakub.kicinski@netronome.com> Reviewed-by: Stanislav Fomichev <sdf@google.com> Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Diffstat (limited to 'tools/bpf/bpftool')
-rw-r--r--tools/bpf/bpftool/Documentation/bpftool-feature.rst13
-rw-r--r--tools/bpf/bpftool/feature.c150
2 files changed, 133 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
19MAP COMMANDS 19MAP COMMANDS
20============= 20=============
21 21
22| **bpftool** **feature probe** [**kernel**] 22| **bpftool** **feature probe** [**kernel**] [**macros** [**prefix** *PREFIX*]]
23| **bpftool** **feature help** 23| **bpftool** **feature help**
24 24
25DESCRIPTION 25DESCRIPTION
26=========== 26===========
27 **bpftool feature probe** [**kernel**] 27 **bpftool feature probe** [**kernel**] [**macros** [**prefix** *PREFIX*]]
28 Probe the running kernel and dump a number of eBPF-related 28 Probe the running kernel and dump a number of eBPF-related
29 parameters, such as availability of the **bpf()** system call. 29 parameters, such as availability of the **bpf()** system call.
30 30
31 If the **macros** keyword (but not the **-j** option) is
32 passed, a subset of the output is dumped as a list of
33 **#define** macros that are ready to be included in a C
34 header file, for example. If, additionally, **prefix** is
35 used to define a *PREFIX*, the provided string will be used
36 as a prefix to the names of the macros: this can be used to
37 avoid conflicts on macro names when including the output of
38 this command as a header file.
39
31 Keyword **kernel** can be omitted. 40 Keyword **kernel** can be omitted.
32 41
33 Note that when probed, some eBPF helpers (e.g. 42 Note that when probed, some eBPF helpers (e.g.
diff --git a/tools/bpf/bpftool/feature.c b/tools/bpf/bpftool/feature.c
index 55c8d215ca44..a62e637953b7 100644
--- a/tools/bpf/bpftool/feature.c
+++ b/tools/bpf/bpftool/feature.c
@@ -46,13 +46,25 @@ static bool check_procfs(void)
46 return true; 46 return true;
47} 47}
48 48
49static void uppercase(char *str, size_t len)
50{
51 size_t i;
52
53 for (i = 0; i < len && str[i] != '\0'; i++)
54 str[i] = toupper(str[i]);
55}
56
49/* Printing utility functions */ 57/* Printing utility functions */
50 58
51static void 59static void
52print_bool_feature(const char *feat_name, const char *plain_name, bool res) 60print_bool_feature(const char *feat_name, const char *plain_name,
61 const char *define_name, bool res, const char *define_prefix)
53{ 62{
54 if (json_output) 63 if (json_output)
55 jsonw_bool_field(json_wtr, feat_name, res); 64 jsonw_bool_field(json_wtr, feat_name, res);
65 else if (define_prefix)
66 printf("#define %s%sHAVE_%s\n", define_prefix,
67 res ? "" : "NO_", define_name);
56 else 68 else
57 printf("%s is %savailable\n", plain_name, res ? "" : "NOT "); 69 printf("%s is %savailable\n", plain_name, res ? "" : "NOT ");
58} 70}
@@ -62,6 +74,8 @@ static void print_kernel_option(const char *name, const char *value)
62 char *endptr; 74 char *endptr;
63 int res; 75 int res;
64 76
77 /* No support for C-style ouptut */
78
65 if (json_output) { 79 if (json_output) {
66 if (!value) { 80 if (!value) {
67 jsonw_null_field(json_wtr, name); 81 jsonw_null_field(json_wtr, name);
@@ -82,25 +96,31 @@ static void print_kernel_option(const char *name, const char *value)
82} 96}
83 97
84static void 98static void
85print_start_section(const char *json_title, const char *plain_title) 99print_start_section(const char *json_title, const char *plain_title,
100 const char *define_comment, const char *define_prefix)
86{ 101{
87 if (json_output) { 102 if (json_output) {
88 jsonw_name(json_wtr, json_title); 103 jsonw_name(json_wtr, json_title);
89 jsonw_start_object(json_wtr); 104 jsonw_start_object(json_wtr);
105 } else if (define_prefix) {
106 printf("%s\n", define_comment);
90 } else { 107 } else {
91 printf("%s\n", plain_title); 108 printf("%s\n", plain_title);
92 } 109 }
93} 110}
94 111
95static void 112static void
96print_end_then_start_section(const char *json_title, const char *plain_title) 113print_end_then_start_section(const char *json_title, const char *plain_title,
114 const char *define_comment,
115 const char *define_prefix)
97{ 116{
98 if (json_output) 117 if (json_output)
99 jsonw_end_object(json_wtr); 118 jsonw_end_object(json_wtr);
100 else 119 else
101 printf("\n"); 120 printf("\n");
102 121
103 print_start_section(json_title, plain_title); 122 print_start_section(json_title, plain_title, define_comment,
123 define_prefix);
104} 124}
105 125
106/* Probing functions */ 126/* Probing functions */
@@ -134,6 +154,8 @@ static void probe_unprivileged_disabled(void)
134{ 154{
135 int res; 155 int res;
136 156
157 /* No support for C-style ouptut */
158
137 res = read_procfs("/proc/sys/kernel/unprivileged_bpf_disabled"); 159 res = read_procfs("/proc/sys/kernel/unprivileged_bpf_disabled");
138 if (json_output) { 160 if (json_output) {
139 jsonw_int_field(json_wtr, "unprivileged_bpf_disabled", res); 161 jsonw_int_field(json_wtr, "unprivileged_bpf_disabled", res);
@@ -158,6 +180,8 @@ static void probe_jit_enable(void)
158{ 180{
159 int res; 181 int res;
160 182
183 /* No support for C-style ouptut */
184
161 res = read_procfs("/proc/sys/net/core/bpf_jit_enable"); 185 res = read_procfs("/proc/sys/net/core/bpf_jit_enable");
162 if (json_output) { 186 if (json_output) {
163 jsonw_int_field(json_wtr, "bpf_jit_enable", res); 187 jsonw_int_field(json_wtr, "bpf_jit_enable", res);
@@ -186,6 +210,8 @@ static void probe_jit_harden(void)
186{ 210{
187 int res; 211 int res;
188 212
213 /* No support for C-style ouptut */
214
189 res = read_procfs("/proc/sys/net/core/bpf_jit_harden"); 215 res = read_procfs("/proc/sys/net/core/bpf_jit_harden");
190 if (json_output) { 216 if (json_output) {
191 jsonw_int_field(json_wtr, "bpf_jit_harden", res); 217 jsonw_int_field(json_wtr, "bpf_jit_harden", res);
@@ -214,6 +240,8 @@ static void probe_jit_kallsyms(void)
214{ 240{
215 int res; 241 int res;
216 242
243 /* No support for C-style ouptut */
244
217 res = read_procfs("/proc/sys/net/core/bpf_jit_kallsyms"); 245 res = read_procfs("/proc/sys/net/core/bpf_jit_kallsyms");
218 if (json_output) { 246 if (json_output) {
219 jsonw_int_field(json_wtr, "bpf_jit_kallsyms", res); 247 jsonw_int_field(json_wtr, "bpf_jit_kallsyms", res);
@@ -238,6 +266,8 @@ static void probe_jit_limit(void)
238{ 266{
239 int res; 267 int res;
240 268
269 /* No support for C-style ouptut */
270
241 res = read_procfs("/proc/sys/net/core/bpf_jit_limit"); 271 res = read_procfs("/proc/sys/net/core/bpf_jit_limit");
242 if (json_output) { 272 if (json_output) {
243 jsonw_int_field(json_wtr, "bpf_jit_limit", res); 273 jsonw_int_field(json_wtr, "bpf_jit_limit", res);
@@ -409,7 +439,7 @@ no_config:
409 print_kernel_option(options[i], NULL); 439 print_kernel_option(options[i], NULL);
410} 440}
411 441
412static bool probe_bpf_syscall(void) 442static bool probe_bpf_syscall(const char *define_prefix)
413{ 443{
414 bool res; 444 bool res;
415 445
@@ -418,15 +448,18 @@ static bool probe_bpf_syscall(void)
418 448
419 print_bool_feature("have_bpf_syscall", 449 print_bool_feature("have_bpf_syscall",
420 "bpf() syscall", 450 "bpf() syscall",
421 res); 451 "BPF_SYSCALL",
452 res, define_prefix);
422 453
423 return res; 454 return res;
424} 455}
425 456
426static void probe_prog_type(enum bpf_prog_type prog_type, bool *supported_types) 457static void
458probe_prog_type(enum bpf_prog_type prog_type, bool *supported_types,
459 const char *define_prefix)
427{ 460{
461 char feat_name[128], plain_desc[128], define_name[128];
428 const char *plain_comment = "eBPF program_type "; 462 const char *plain_comment = "eBPF program_type ";
429 char feat_name[128], plain_desc[128];
430 size_t maxlen; 463 size_t maxlen;
431 bool res; 464 bool res;
432 465
@@ -441,14 +474,18 @@ static void probe_prog_type(enum bpf_prog_type prog_type, bool *supported_types)
441 } 474 }
442 475
443 sprintf(feat_name, "have_%s_prog_type", prog_type_name[prog_type]); 476 sprintf(feat_name, "have_%s_prog_type", prog_type_name[prog_type]);
477 sprintf(define_name, "%s_prog_type", prog_type_name[prog_type]);
478 uppercase(define_name, sizeof(define_name));
444 sprintf(plain_desc, "%s%s", plain_comment, prog_type_name[prog_type]); 479 sprintf(plain_desc, "%s%s", plain_comment, prog_type_name[prog_type]);
445 print_bool_feature(feat_name, plain_desc, res); 480 print_bool_feature(feat_name, plain_desc, define_name, res,
481 define_prefix);
446} 482}
447 483
448static void probe_map_type(enum bpf_map_type map_type) 484static void
485probe_map_type(enum bpf_map_type map_type, const char *define_prefix)
449{ 486{
487 char feat_name[128], plain_desc[128], define_name[128];
450 const char *plain_comment = "eBPF map_type "; 488 const char *plain_comment = "eBPF map_type ";
451 char feat_name[128], plain_desc[128];
452 size_t maxlen; 489 size_t maxlen;
453 bool res; 490 bool res;
454 491
@@ -461,12 +498,16 @@ static void probe_map_type(enum bpf_map_type map_type)
461 } 498 }
462 499
463 sprintf(feat_name, "have_%s_map_type", map_type_name[map_type]); 500 sprintf(feat_name, "have_%s_map_type", map_type_name[map_type]);
501 sprintf(define_name, "%s_map_type", map_type_name[map_type]);
502 uppercase(define_name, sizeof(define_name));
464 sprintf(plain_desc, "%s%s", plain_comment, map_type_name[map_type]); 503 sprintf(plain_desc, "%s%s", plain_comment, map_type_name[map_type]);
465 print_bool_feature(feat_name, plain_desc, res); 504 print_bool_feature(feat_name, plain_desc, define_name, res,
505 define_prefix);
466} 506}
467 507
468static void 508static void
469probe_helpers_for_progtype(enum bpf_prog_type prog_type, bool supported_type) 509probe_helpers_for_progtype(enum bpf_prog_type prog_type, bool supported_type,
510 const char *define_prefix)
470{ 511{
471 const char *ptype_name = prog_type_name[prog_type]; 512 const char *ptype_name = prog_type_name[prog_type];
472 char feat_name[128]; 513 char feat_name[128];
@@ -477,7 +518,7 @@ probe_helpers_for_progtype(enum bpf_prog_type prog_type, bool supported_type)
477 sprintf(feat_name, "%s_available_helpers", ptype_name); 518 sprintf(feat_name, "%s_available_helpers", ptype_name);
478 jsonw_name(json_wtr, feat_name); 519 jsonw_name(json_wtr, feat_name);
479 jsonw_start_array(json_wtr); 520 jsonw_start_array(json_wtr);
480 } else { 521 } else if (!define_prefix) {
481 printf("eBPF helpers supported for program type %s:", 522 printf("eBPF helpers supported for program type %s:",
482 ptype_name); 523 ptype_name);
483 } 524 }
@@ -491,6 +532,10 @@ probe_helpers_for_progtype(enum bpf_prog_type prog_type, bool supported_type)
491 if (json_output) { 532 if (json_output) {
492 if (res) 533 if (res)
493 jsonw_string(json_wtr, helper_name[id]); 534 jsonw_string(json_wtr, helper_name[id]);
535 } else if (define_prefix) {
536 printf("#define %sBPF__PROG_TYPE_%s__HELPER_%s %s\n",
537 define_prefix, ptype_name, helper_name[id],
538 res ? "1" : "0");
494 } else { 539 } else {
495 if (res) 540 if (res)
496 printf("\n\t- %s", helper_name[id]); 541 printf("\n\t- %s", helper_name[id]);
@@ -499,13 +544,14 @@ probe_helpers_for_progtype(enum bpf_prog_type prog_type, bool supported_type)
499 544
500 if (json_output) 545 if (json_output)
501 jsonw_end_array(json_wtr); 546 jsonw_end_array(json_wtr);
502 else 547 else if (!define_prefix)
503 printf("\n"); 548 printf("\n");
504} 549}
505 550
506static int do_probe(int argc, char **argv) 551static int do_probe(int argc, char **argv)
507{ 552{
508 enum probe_component target = COMPONENT_UNSPEC; 553 enum probe_component target = COMPONENT_UNSPEC;
554 const char *define_prefix = NULL;
509 bool supported_types[128] = {}; 555 bool supported_types[128] = {};
510 unsigned int i; 556 unsigned int i;
511 557
@@ -527,21 +573,45 @@ static int do_probe(int argc, char **argv)
527 } 573 }
528 target = COMPONENT_KERNEL; 574 target = COMPONENT_KERNEL;
529 NEXT_ARG(); 575 NEXT_ARG();
576 } else if (is_prefix(*argv, "macros") && !define_prefix) {
577 define_prefix = "";
578 NEXT_ARG();
579 } else if (is_prefix(*argv, "prefix")) {
580 if (!define_prefix) {
581 p_err("'prefix' argument can only be use after 'macros'");
582 return -1;
583 }
584 if (strcmp(define_prefix, "")) {
585 p_err("'prefix' already defined");
586 return -1;
587 }
588 NEXT_ARG();
589
590 if (!REQ_ARGS(1))
591 return -1;
592 define_prefix = GET_ARG();
530 } else { 593 } else {
531 p_err("expected no more arguments, 'kernel', got: '%s'?", 594 p_err("expected no more arguments, 'kernel', 'macros' or 'prefix', got: '%s'?",
532 *argv); 595 *argv);
533 return -1; 596 return -1;
534 } 597 }
535 } 598 }
536 599
537 if (json_output) 600 if (json_output) {
601 define_prefix = NULL;
538 jsonw_start_object(json_wtr); 602 jsonw_start_object(json_wtr);
603 }
539 604
540 switch (target) { 605 switch (target) {
541 case COMPONENT_KERNEL: 606 case COMPONENT_KERNEL:
542 case COMPONENT_UNSPEC: 607 case COMPONENT_UNSPEC:
608 if (define_prefix)
609 break;
610
543 print_start_section("system_config", 611 print_start_section("system_config",
544 "Scanning system configuration..."); 612 "Scanning system configuration...",
613 NULL, /* define_comment never used here */
614 NULL); /* define_prefix always NULL here */
545 if (check_procfs()) { 615 if (check_procfs()) {
546 probe_unprivileged_disabled(); 616 probe_unprivileged_disabled();
547 probe_jit_enable(); 617 probe_jit_enable();
@@ -560,29 +630,53 @@ static int do_probe(int argc, char **argv)
560 } 630 }
561 631
562 print_start_section("syscall_config", 632 print_start_section("syscall_config",
563 "Scanning system call availability..."); 633 "Scanning system call availability...",
634 "/*** System call availability ***/",
635 define_prefix);
564 636
565 if (!probe_bpf_syscall()) 637 if (!probe_bpf_syscall(define_prefix))
566 /* bpf() syscall unavailable, don't probe other BPF features */ 638 /* bpf() syscall unavailable, don't probe other BPF features */
567 goto exit_close_json; 639 goto exit_close_json;
568 640
569 print_end_then_start_section("program_types", 641 print_end_then_start_section("program_types",
570 "Scanning eBPF program types..."); 642 "Scanning eBPF program types...",
643 "/*** eBPF program types ***/",
644 define_prefix);
571 645
572 for (i = BPF_PROG_TYPE_UNSPEC + 1; i < ARRAY_SIZE(prog_type_name); i++) 646 for (i = BPF_PROG_TYPE_UNSPEC + 1; i < ARRAY_SIZE(prog_type_name); i++)
573 probe_prog_type(i, supported_types); 647 probe_prog_type(i, supported_types, define_prefix);
574 648
575 print_end_then_start_section("map_types", 649 print_end_then_start_section("map_types",
576 "Scanning eBPF map types..."); 650 "Scanning eBPF map types...",
651 "/*** eBPF map types ***/",
652 define_prefix);
577 653
578 for (i = BPF_MAP_TYPE_UNSPEC + 1; i < map_type_name_size; i++) 654 for (i = BPF_MAP_TYPE_UNSPEC + 1; i < map_type_name_size; i++)
579 probe_map_type(i); 655 probe_map_type(i, define_prefix);
580 656
581 print_end_then_start_section("helpers", 657 print_end_then_start_section("helpers",
582 "Scanning eBPF helper functions..."); 658 "Scanning eBPF helper functions...",
583 659 "/*** eBPF helper functions ***/",
660 define_prefix);
661
662 if (define_prefix)
663 printf("/*\n"
664 " * Use %sHAVE_PROG_TYPE_HELPER(prog_type_name, helper_name)\n"
665 " * to determine if <helper_name> is available for <prog_type_name>,\n"
666 " * e.g.\n"
667 " * #if %sHAVE_PROG_TYPE_HELPER(xdp, bpf_redirect)\n"
668 " * // do stuff with this helper\n"
669 " * #elif\n"
670 " * // use a workaround\n"
671 " * #endif\n"
672 " */\n"
673 "#define %sHAVE_PROG_TYPE_HELPER(prog_type, helper) \\\n"
674 " %sBPF__PROG_TYPE_ ## prog_type ## __HELPER_ ## helper\n",
675 define_prefix, define_prefix, define_prefix,
676 define_prefix);
584 for (i = BPF_PROG_TYPE_UNSPEC + 1; i < ARRAY_SIZE(prog_type_name); i++) 677 for (i = BPF_PROG_TYPE_UNSPEC + 1; i < ARRAY_SIZE(prog_type_name); i++)
585 probe_helpers_for_progtype(i, supported_types[i]); 678 probe_helpers_for_progtype(i, supported_types[i],
679 define_prefix);
586 680
587exit_close_json: 681exit_close_json:
588 if (json_output) { 682 if (json_output) {
@@ -603,7 +697,7 @@ static int do_help(int argc, char **argv)
603 } 697 }
604 698
605 fprintf(stderr, 699 fprintf(stderr,
606 "Usage: %s %s probe [kernel]\n" 700 "Usage: %s %s probe [kernel] [macros [prefix PREFIX]]\n"
607 " %s %s help\n" 701 " %s %s help\n"
608 "", 702 "",
609 bin_name, argv[-2], bin_name, argv[-2]); 703 bin_name, argv[-2], bin_name, argv[-2]);