root/tools/bpf/bpftool/feature.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. check_procfs
  2. uppercase
  3. print_bool_feature
  4. print_kernel_option
  5. print_start_section
  6. print_end_then_start_section
  7. read_procfs
  8. probe_unprivileged_disabled
  9. probe_jit_enable
  10. probe_jit_harden
  11. probe_jit_kallsyms
  12. probe_jit_limit
  13. read_next_kernel_config_option
  14. probe_kernel_image_config
  15. probe_bpf_syscall
  16. probe_prog_type
  17. probe_map_type
  18. probe_helpers_for_progtype
  19. do_probe
  20. do_help
  21. do_feature

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

/* [<][>][^][v][top][bottom][index][help] */