1 // SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) 2 /* Copyright (c) 2019 Netronome Systems, Inc. */ 3 4 #include <ctype.h> 5 #include <errno.h> 6 #include <string.h> 7 #include <unistd.h> 8 #include <net/if.h> 9 #include <sys/utsname.h> 10 #include <sys/vfs.h> 11 12 #include <linux/filter.h> 13 #include <linux/limits.h> 14 15 #include <bpf/bpf.h> 16 #include <bpf/libbpf.h> 17 #include <zlib.h> 18 19 #include "main.h" 20 21 #ifndef PROC_SUPER_MAGIC 22 # define PROC_SUPER_MAGIC 0x9fa0 23 #endif 24 25 enum probe_component { 26 COMPONENT_UNSPEC, 27 COMPONENT_KERNEL, 28 COMPONENT_DEVICE, 29 }; 30 31 #define BPF_HELPER_MAKE_ENTRY(name) [BPF_FUNC_ ## name] = "bpf_" # name 32 static const char * const helper_name[] = { 33 __BPF_FUNC_MAPPER(BPF_HELPER_MAKE_ENTRY) 34 }; 35 36 #undef BPF_HELPER_MAKE_ENTRY 37 38 /* Miscellaneous utility functions */ 39 40 static bool check_procfs(void) 41 { 42 struct statfs st_fs; 43 44 if (statfs("/proc", &st_fs) < 0) 45 return false; 46 if ((unsigned long)st_fs.f_type != PROC_SUPER_MAGIC) 47 return false; 48 49 return true; 50 } 51 52 static void uppercase(char *str, size_t len) 53 { 54 size_t i; 55 56 for (i = 0; i < len && str[i] != '\0'; i++) 57 str[i] = toupper(str[i]); 58 } 59 60 /* Printing utility functions */ 61 62 static void 63 print_bool_feature(const char *feat_name, const char *plain_name, 64 const char *define_name, bool res, const char *define_prefix) 65 { 66 if (json_output) 67 jsonw_bool_field(json_wtr, feat_name, res); 68 else if (define_prefix) 69 printf("#define %s%sHAVE_%s\n", define_prefix, 70 res ? "" : "NO_", define_name); 71 else 72 printf("%s is %savailable\n", plain_name, res ? "" : "NOT "); 73 } 74 75 static void print_kernel_option(const char *name, const char *value) 76 { 77 char *endptr; 78 int res; 79 80 /* No support for C-style ouptut */ 81 82 if (json_output) { 83 if (!value) { 84 jsonw_null_field(json_wtr, name); 85 return; 86 } 87 errno = 0; 88 res = strtol(value, &endptr, 0); 89 if (!errno && *endptr == '\n') 90 jsonw_int_field(json_wtr, name, res); 91 else 92 jsonw_string_field(json_wtr, name, value); 93 } else { 94 if (value) 95 printf("%s is set to %s\n", name, value); 96 else 97 printf("%s is not set\n", name); 98 } 99 } 100 101 static void 102 print_start_section(const char *json_title, const char *plain_title, 103 const char *define_comment, const char *define_prefix) 104 { 105 if (json_output) { 106 jsonw_name(json_wtr, json_title); 107 jsonw_start_object(json_wtr); 108 } else if (define_prefix) { 109 printf("%s\n", define_comment); 110 } else { 111 printf("%s\n", plain_title); 112 } 113 } 114 115 static void print_end_section(void) 116 { 117 if (json_output) 118 jsonw_end_object(json_wtr); 119 else 120 printf("\n"); 121 } 122 123 /* Probing functions */ 124 125 static int read_procfs(const char *path) 126 { 127 char *endptr, *line = NULL; 128 size_t len = 0; 129 FILE *fd; 130 int res; 131 132 fd = fopen(path, "r"); 133 if (!fd) 134 return -1; 135 136 res = getline(&line, &len, fd); 137 fclose(fd); 138 if (res < 0) 139 return -1; 140 141 errno = 0; 142 res = strtol(line, &endptr, 10); 143 if (errno || *line == '\0' || *endptr != '\n') 144 res = -1; 145 free(line); 146 147 return res; 148 } 149 150 static void probe_unprivileged_disabled(void) 151 { 152 int res; 153 154 /* No support for C-style ouptut */ 155 156 res = read_procfs("/proc/sys/kernel/unprivileged_bpf_disabled"); 157 if (json_output) { 158 jsonw_int_field(json_wtr, "unprivileged_bpf_disabled", res); 159 } else { 160 switch (res) { 161 case 0: 162 printf("bpf() syscall for unprivileged users is enabled\n"); 163 break; 164 case 1: 165 printf("bpf() syscall restricted to privileged users\n"); 166 break; 167 case -1: 168 printf("Unable to retrieve required privileges for bpf() syscall\n"); 169 break; 170 default: 171 printf("bpf() syscall restriction has unknown value %d\n", res); 172 } 173 } 174 } 175 176 static void probe_jit_enable(void) 177 { 178 int res; 179 180 /* No support for C-style ouptut */ 181 182 res = read_procfs("/proc/sys/net/core/bpf_jit_enable"); 183 if (json_output) { 184 jsonw_int_field(json_wtr, "bpf_jit_enable", res); 185 } else { 186 switch (res) { 187 case 0: 188 printf("JIT compiler is disabled\n"); 189 break; 190 case 1: 191 printf("JIT compiler is enabled\n"); 192 break; 193 case 2: 194 printf("JIT compiler is enabled with debugging traces in kernel logs\n"); 195 break; 196 case -1: 197 printf("Unable to retrieve JIT-compiler status\n"); 198 break; 199 default: 200 printf("JIT-compiler status has unknown value %d\n", 201 res); 202 } 203 } 204 } 205 206 static void probe_jit_harden(void) 207 { 208 int res; 209 210 /* No support for C-style ouptut */ 211 212 res = read_procfs("/proc/sys/net/core/bpf_jit_harden"); 213 if (json_output) { 214 jsonw_int_field(json_wtr, "bpf_jit_harden", res); 215 } else { 216 switch (res) { 217 case 0: 218 printf("JIT compiler hardening is disabled\n"); 219 break; 220 case 1: 221 printf("JIT compiler hardening is enabled for unprivileged users\n"); 222 break; 223 case 2: 224 printf("JIT compiler hardening is enabled for all users\n"); 225 break; 226 case -1: 227 printf("Unable to retrieve JIT hardening status\n"); 228 break; 229 default: 230 printf("JIT hardening status has unknown value %d\n", 231 res); 232 } 233 } 234 } 235 236 static void probe_jit_kallsyms(void) 237 { 238 int res; 239 240 /* No support for C-style ouptut */ 241 242 res = read_procfs("/proc/sys/net/core/bpf_jit_kallsyms"); 243 if (json_output) { 244 jsonw_int_field(json_wtr, "bpf_jit_kallsyms", res); 245 } else { 246 switch (res) { 247 case 0: 248 printf("JIT compiler kallsyms exports are disabled\n"); 249 break; 250 case 1: 251 printf("JIT compiler kallsyms exports are enabled for root\n"); 252 break; 253 case -1: 254 printf("Unable to retrieve JIT kallsyms export status\n"); 255 break; 256 default: 257 printf("JIT kallsyms exports status has unknown value %d\n", res); 258 } 259 } 260 } 261 262 static void probe_jit_limit(void) 263 { 264 int res; 265 266 /* No support for C-style ouptut */ 267 268 res = read_procfs("/proc/sys/net/core/bpf_jit_limit"); 269 if (json_output) { 270 jsonw_int_field(json_wtr, "bpf_jit_limit", res); 271 } else { 272 switch (res) { 273 case -1: 274 printf("Unable to retrieve global memory limit for JIT compiler for unprivileged users\n"); 275 break; 276 default: 277 printf("Global memory limit for JIT compiler for unprivileged users is %d bytes\n", res); 278 } 279 } 280 } 281 282 static bool read_next_kernel_config_option(gzFile file, char *buf, size_t n, 283 char **value) 284 { 285 char *sep; 286 287 while (gzgets(file, buf, n)) { 288 if (strncmp(buf, "CONFIG_", 7)) 289 continue; 290 291 sep = strchr(buf, '='); 292 if (!sep) 293 continue; 294 295 /* Trim ending '\n' */ 296 buf[strlen(buf) - 1] = '\0'; 297 298 /* Split on '=' and ensure that a value is present. */ 299 *sep = '\0'; 300 if (!sep[1]) 301 continue; 302 303 *value = sep + 1; 304 return true; 305 } 306 307 return false; 308 } 309 310 static void probe_kernel_image_config(void) 311 { 312 static const char * const options[] = { 313 /* Enable BPF */ 314 "CONFIG_BPF", 315 /* Enable bpf() syscall */ 316 "CONFIG_BPF_SYSCALL", 317 /* Does selected architecture support eBPF JIT compiler */ 318 "CONFIG_HAVE_EBPF_JIT", 319 /* Compile eBPF JIT compiler */ 320 "CONFIG_BPF_JIT", 321 /* Avoid compiling eBPF interpreter (use JIT only) */ 322 "CONFIG_BPF_JIT_ALWAYS_ON", 323 324 /* cgroups */ 325 "CONFIG_CGROUPS", 326 /* BPF programs attached to cgroups */ 327 "CONFIG_CGROUP_BPF", 328 /* bpf_get_cgroup_classid() helper */ 329 "CONFIG_CGROUP_NET_CLASSID", 330 /* bpf_skb_{,ancestor_}cgroup_id() helpers */ 331 "CONFIG_SOCK_CGROUP_DATA", 332 333 /* Tracing: attach BPF to kprobes, tracepoints, etc. */ 334 "CONFIG_BPF_EVENTS", 335 /* Kprobes */ 336 "CONFIG_KPROBE_EVENTS", 337 /* Uprobes */ 338 "CONFIG_UPROBE_EVENTS", 339 /* Tracepoints */ 340 "CONFIG_TRACING", 341 /* Syscall tracepoints */ 342 "CONFIG_FTRACE_SYSCALLS", 343 /* bpf_override_return() helper support for selected arch */ 344 "CONFIG_FUNCTION_ERROR_INJECTION", 345 /* bpf_override_return() helper */ 346 "CONFIG_BPF_KPROBE_OVERRIDE", 347 348 /* Network */ 349 "CONFIG_NET", 350 /* AF_XDP sockets */ 351 "CONFIG_XDP_SOCKETS", 352 /* BPF_PROG_TYPE_LWT_* and related helpers */ 353 "CONFIG_LWTUNNEL_BPF", 354 /* BPF_PROG_TYPE_SCHED_ACT, TC (traffic control) actions */ 355 "CONFIG_NET_ACT_BPF", 356 /* BPF_PROG_TYPE_SCHED_CLS, TC filters */ 357 "CONFIG_NET_CLS_BPF", 358 /* TC clsact qdisc */ 359 "CONFIG_NET_CLS_ACT", 360 /* Ingress filtering with TC */ 361 "CONFIG_NET_SCH_INGRESS", 362 /* bpf_skb_get_xfrm_state() helper */ 363 "CONFIG_XFRM", 364 /* bpf_get_route_realm() helper */ 365 "CONFIG_IP_ROUTE_CLASSID", 366 /* BPF_PROG_TYPE_LWT_SEG6_LOCAL and related helpers */ 367 "CONFIG_IPV6_SEG6_BPF", 368 /* BPF_PROG_TYPE_LIRC_MODE2 and related helpers */ 369 "CONFIG_BPF_LIRC_MODE2", 370 /* BPF stream parser and BPF socket maps */ 371 "CONFIG_BPF_STREAM_PARSER", 372 /* xt_bpf module for passing BPF programs to netfilter */ 373 "CONFIG_NETFILTER_XT_MATCH_BPF", 374 /* bpfilter back-end for iptables */ 375 "CONFIG_BPFILTER", 376 /* bpftilter module with "user mode helper" */ 377 "CONFIG_BPFILTER_UMH", 378 379 /* test_bpf module for BPF tests */ 380 "CONFIG_TEST_BPF", 381 }; 382 char *values[ARRAY_SIZE(options)] = { }; 383 struct utsname utsn; 384 char path[PATH_MAX]; 385 gzFile file = NULL; 386 char buf[4096]; 387 char *value; 388 size_t i; 389 390 if (!uname(&utsn)) { 391 snprintf(path, sizeof(path), "/boot/config-%s", utsn.release); 392 393 /* gzopen also accepts uncompressed files. */ 394 file = gzopen(path, "r"); 395 } 396 397 if (!file) { 398 /* Some distributions build with CONFIG_IKCONFIG=y and put the 399 * config file at /proc/config.gz. 400 */ 401 file = gzopen("/proc/config.gz", "r"); 402 } 403 if (!file) { 404 p_info("skipping kernel config, can't open file: %s", 405 strerror(errno)); 406 goto end_parse; 407 } 408 /* Sanity checks */ 409 if (!gzgets(file, buf, sizeof(buf)) || 410 !gzgets(file, buf, sizeof(buf))) { 411 p_info("skipping kernel config, can't read from file: %s", 412 strerror(errno)); 413 goto end_parse; 414 } 415 if (strcmp(buf, "# Automatically generated file; DO NOT EDIT.\n")) { 416 p_info("skipping kernel config, can't find correct file"); 417 goto end_parse; 418 } 419 420 while (read_next_kernel_config_option(file, buf, sizeof(buf), &value)) { 421 for (i = 0; i < ARRAY_SIZE(options); i++) { 422 if (values[i] || strcmp(buf, options[i])) 423 continue; 424 425 values[i] = strdup(value); 426 } 427 } 428 429 end_parse: 430 if (file) 431 gzclose(file); 432 433 for (i = 0; i < ARRAY_SIZE(options); i++) { 434 print_kernel_option(options[i], values[i]); 435 free(values[i]); 436 } 437 } 438 439 static bool probe_bpf_syscall(const char *define_prefix) 440 { 441 bool res; 442 443 bpf_load_program(BPF_PROG_TYPE_UNSPEC, NULL, 0, NULL, 0, NULL, 0); 444 res = (errno != ENOSYS); 445 446 print_bool_feature("have_bpf_syscall", 447 "bpf() syscall", 448 "BPF_SYSCALL", 449 res, define_prefix); 450 451 return res; 452 } 453 454 static void 455 probe_prog_type(enum bpf_prog_type prog_type, bool *supported_types, 456 const char *define_prefix, __u32 ifindex) 457 { 458 char feat_name[128], plain_desc[128], define_name[128]; 459 const char *plain_comment = "eBPF program_type "; 460 size_t maxlen; 461 bool res; 462 463 if (ifindex) 464 /* Only test offload-able program types */ 465 switch (prog_type) { 466 case BPF_PROG_TYPE_SCHED_CLS: 467 case BPF_PROG_TYPE_XDP: 468 break; 469 default: 470 return; 471 } 472 473 res = bpf_probe_prog_type(prog_type, ifindex); 474 475 supported_types[prog_type] |= res; 476 477 maxlen = sizeof(plain_desc) - strlen(plain_comment) - 1; 478 if (strlen(prog_type_name[prog_type]) > maxlen) { 479 p_info("program type name too long"); 480 return; 481 } 482 483 sprintf(feat_name, "have_%s_prog_type", prog_type_name[prog_type]); 484 sprintf(define_name, "%s_prog_type", prog_type_name[prog_type]); 485 uppercase(define_name, sizeof(define_name)); 486 sprintf(plain_desc, "%s%s", plain_comment, prog_type_name[prog_type]); 487 print_bool_feature(feat_name, plain_desc, define_name, res, 488 define_prefix); 489 } 490 491 static void 492 probe_map_type(enum bpf_map_type map_type, const char *define_prefix, 493 __u32 ifindex) 494 { 495 char feat_name[128], plain_desc[128], define_name[128]; 496 const char *plain_comment = "eBPF map_type "; 497 size_t maxlen; 498 bool res; 499 500 res = bpf_probe_map_type(map_type, ifindex); 501 502 maxlen = sizeof(plain_desc) - strlen(plain_comment) - 1; 503 if (strlen(map_type_name[map_type]) > maxlen) { 504 p_info("map type name too long"); 505 return; 506 } 507 508 sprintf(feat_name, "have_%s_map_type", map_type_name[map_type]); 509 sprintf(define_name, "%s_map_type", map_type_name[map_type]); 510 uppercase(define_name, sizeof(define_name)); 511 sprintf(plain_desc, "%s%s", plain_comment, map_type_name[map_type]); 512 print_bool_feature(feat_name, plain_desc, define_name, res, 513 define_prefix); 514 } 515 516 static void 517 probe_helper_for_progtype(enum bpf_prog_type prog_type, bool supported_type, 518 const char *define_prefix, unsigned int id, 519 const char *ptype_name, __u32 ifindex) 520 { 521 bool res; 522 523 if (!supported_type) 524 res = false; 525 else 526 res = bpf_probe_helper(id, prog_type, ifindex); 527 528 if (json_output) { 529 if (res) 530 jsonw_string(json_wtr, helper_name[id]); 531 } else if (define_prefix) { 532 printf("#define %sBPF__PROG_TYPE_%s__HELPER_%s %s\n", 533 define_prefix, ptype_name, helper_name[id], 534 res ? "1" : "0"); 535 } else { 536 if (res) 537 printf("\n\t- %s", helper_name[id]); 538 } 539 } 540 541 static void 542 probe_helpers_for_progtype(enum bpf_prog_type prog_type, bool supported_type, 543 const char *define_prefix, bool full_mode, 544 __u32 ifindex) 545 { 546 const char *ptype_name = prog_type_name[prog_type]; 547 char feat_name[128]; 548 unsigned int id; 549 550 if (ifindex) 551 /* Only test helpers for offload-able program types */ 552 switch (prog_type) { 553 case BPF_PROG_TYPE_SCHED_CLS: 554 case BPF_PROG_TYPE_XDP: 555 break; 556 default: 557 return; 558 } 559 560 if (json_output) { 561 sprintf(feat_name, "%s_available_helpers", ptype_name); 562 jsonw_name(json_wtr, feat_name); 563 jsonw_start_array(json_wtr); 564 } else if (!define_prefix) { 565 printf("eBPF helpers supported for program type %s:", 566 ptype_name); 567 } 568 569 for (id = 1; id < ARRAY_SIZE(helper_name); id++) { 570 /* Skip helper functions which emit dmesg messages when not in 571 * the full mode. 572 */ 573 switch (id) { 574 case BPF_FUNC_trace_printk: 575 case BPF_FUNC_probe_write_user: 576 if (!full_mode) 577 continue; 578 /* fallthrough */ 579 default: 580 probe_helper_for_progtype(prog_type, supported_type, 581 define_prefix, id, ptype_name, 582 ifindex); 583 } 584 } 585 586 if (json_output) 587 jsonw_end_array(json_wtr); 588 else if (!define_prefix) 589 printf("\n"); 590 } 591 592 static void 593 probe_large_insn_limit(const char *define_prefix, __u32 ifindex) 594 { 595 bool res; 596 597 res = bpf_probe_large_insn_limit(ifindex); 598 print_bool_feature("have_large_insn_limit", 599 "Large program size limit", 600 "LARGE_INSN_LIMIT", 601 res, define_prefix); 602 } 603 604 static void 605 section_system_config(enum probe_component target, const char *define_prefix) 606 { 607 switch (target) { 608 case COMPONENT_KERNEL: 609 case COMPONENT_UNSPEC: 610 if (define_prefix) 611 break; 612 613 print_start_section("system_config", 614 "Scanning system configuration...", 615 NULL, /* define_comment never used here */ 616 NULL); /* define_prefix always NULL here */ 617 if (check_procfs()) { 618 probe_unprivileged_disabled(); 619 probe_jit_enable(); 620 probe_jit_harden(); 621 probe_jit_kallsyms(); 622 probe_jit_limit(); 623 } else { 624 p_info("/* procfs not mounted, skipping related probes */"); 625 } 626 probe_kernel_image_config(); 627 print_end_section(); 628 break; 629 default: 630 break; 631 } 632 } 633 634 static bool section_syscall_config(const char *define_prefix) 635 { 636 bool res; 637 638 print_start_section("syscall_config", 639 "Scanning system call availability...", 640 "/*** System call availability ***/", 641 define_prefix); 642 res = probe_bpf_syscall(define_prefix); 643 print_end_section(); 644 645 return res; 646 } 647 648 static void 649 section_program_types(bool *supported_types, const char *define_prefix, 650 __u32 ifindex) 651 { 652 unsigned int i; 653 654 print_start_section("program_types", 655 "Scanning eBPF program types...", 656 "/*** eBPF program types ***/", 657 define_prefix); 658 659 for (i = BPF_PROG_TYPE_UNSPEC + 1; i < ARRAY_SIZE(prog_type_name); i++) 660 probe_prog_type(i, supported_types, define_prefix, ifindex); 661 662 print_end_section(); 663 } 664 665 static void section_map_types(const char *define_prefix, __u32 ifindex) 666 { 667 unsigned int i; 668 669 print_start_section("map_types", 670 "Scanning eBPF map types...", 671 "/*** eBPF map types ***/", 672 define_prefix); 673 674 for (i = BPF_MAP_TYPE_UNSPEC + 1; i < map_type_name_size; i++) 675 probe_map_type(i, define_prefix, ifindex); 676 677 print_end_section(); 678 } 679 680 static void 681 section_helpers(bool *supported_types, const char *define_prefix, 682 bool full_mode, __u32 ifindex) 683 { 684 unsigned int i; 685 686 print_start_section("helpers", 687 "Scanning eBPF helper functions...", 688 "/*** eBPF helper functions ***/", 689 define_prefix); 690 691 if (define_prefix) 692 printf("/*\n" 693 " * Use %sHAVE_PROG_TYPE_HELPER(prog_type_name, helper_name)\n" 694 " * to determine if <helper_name> is available for <prog_type_name>,\n" 695 " * e.g.\n" 696 " * #if %sHAVE_PROG_TYPE_HELPER(xdp, bpf_redirect)\n" 697 " * // do stuff with this helper\n" 698 " * #elif\n" 699 " * // use a workaround\n" 700 " * #endif\n" 701 " */\n" 702 "#define %sHAVE_PROG_TYPE_HELPER(prog_type, helper) \\\n" 703 " %sBPF__PROG_TYPE_ ## prog_type ## __HELPER_ ## helper\n", 704 define_prefix, define_prefix, define_prefix, 705 define_prefix); 706 for (i = BPF_PROG_TYPE_UNSPEC + 1; i < ARRAY_SIZE(prog_type_name); i++) 707 probe_helpers_for_progtype(i, supported_types[i], 708 define_prefix, full_mode, ifindex); 709 710 print_end_section(); 711 } 712 713 static void section_misc(const char *define_prefix, __u32 ifindex) 714 { 715 print_start_section("misc", 716 "Scanning miscellaneous eBPF features...", 717 "/*** eBPF misc features ***/", 718 define_prefix); 719 probe_large_insn_limit(define_prefix, ifindex); 720 print_end_section(); 721 } 722 723 static int do_probe(int argc, char **argv) 724 { 725 enum probe_component target = COMPONENT_UNSPEC; 726 const char *define_prefix = NULL; 727 bool supported_types[128] = {}; 728 bool full_mode = false; 729 __u32 ifindex = 0; 730 char *ifname; 731 732 /* Detection assumes user has sufficient privileges (CAP_SYS_ADMIN). 733 * Let's approximate, and restrict usage to root user only. 734 */ 735 if (geteuid()) { 736 p_err("please run this command as root user"); 737 return -1; 738 } 739 740 set_max_rlimit(); 741 742 while (argc) { 743 if (is_prefix(*argv, "kernel")) { 744 if (target != COMPONENT_UNSPEC) { 745 p_err("component to probe already specified"); 746 return -1; 747 } 748 target = COMPONENT_KERNEL; 749 NEXT_ARG(); 750 } else if (is_prefix(*argv, "dev")) { 751 NEXT_ARG(); 752 753 if (target != COMPONENT_UNSPEC || ifindex) { 754 p_err("component to probe already specified"); 755 return -1; 756 } 757 if (!REQ_ARGS(1)) 758 return -1; 759 760 target = COMPONENT_DEVICE; 761 ifname = GET_ARG(); 762 ifindex = if_nametoindex(ifname); 763 if (!ifindex) { 764 p_err("unrecognized netdevice '%s': %s", ifname, 765 strerror(errno)); 766 return -1; 767 } 768 } else if (is_prefix(*argv, "full")) { 769 full_mode = true; 770 NEXT_ARG(); 771 } else if (is_prefix(*argv, "macros") && !define_prefix) { 772 define_prefix = ""; 773 NEXT_ARG(); 774 } else if (is_prefix(*argv, "prefix")) { 775 if (!define_prefix) { 776 p_err("'prefix' argument can only be use after 'macros'"); 777 return -1; 778 } 779 if (strcmp(define_prefix, "")) { 780 p_err("'prefix' already defined"); 781 return -1; 782 } 783 NEXT_ARG(); 784 785 if (!REQ_ARGS(1)) 786 return -1; 787 define_prefix = GET_ARG(); 788 } else { 789 p_err("expected no more arguments, 'kernel', 'dev', 'macros' or 'prefix', got: '%s'?", 790 *argv); 791 return -1; 792 } 793 } 794 795 if (json_output) { 796 define_prefix = NULL; 797 jsonw_start_object(json_wtr); 798 } 799 800 section_system_config(target, define_prefix); 801 if (!section_syscall_config(define_prefix)) 802 /* bpf() syscall unavailable, don't probe other BPF features */ 803 goto exit_close_json; 804 section_program_types(supported_types, define_prefix, ifindex); 805 section_map_types(define_prefix, ifindex); 806 section_helpers(supported_types, define_prefix, full_mode, ifindex); 807 section_misc(define_prefix, ifindex); 808 809 exit_close_json: 810 if (json_output) 811 /* End root object */ 812 jsonw_end_object(json_wtr); 813 814 return 0; 815 } 816 817 static int do_help(int argc, char **argv) 818 { 819 if (json_output) { 820 jsonw_null(json_wtr); 821 return 0; 822 } 823 824 fprintf(stderr, 825 "Usage: %s %s probe [COMPONENT] [full] [macros [prefix PREFIX]]\n" 826 " %s %s help\n" 827 "\n" 828 " COMPONENT := { kernel | dev NAME }\n" 829 "", 830 bin_name, argv[-2], bin_name, argv[-2]); 831 832 return 0; 833 } 834 835 static const struct cmd cmds[] = { 836 { "probe", do_probe }, 837 { "help", do_help }, 838 { 0 } 839 }; 840 841 int do_feature(int argc, char **argv) 842 { 843 return cmd_select(cmds, argc, argv, do_help); 844 } 845