Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

bpftool: Enable libbpf's strict mode by default

Otherwise, attaching with bpftool doesn't work with strict section names.

Also:

- Add --legacy option to switch back to pre-1.0 behavior
- Print a warning when program fails to load in strict mode to
point to --legacy flag
- By default, don't append / to the section name; in strict
mode it's relevant only for a small subset of prog types

+ bpftool --legacy prog loadall tools/testing/selftests/bpf/test_cgroup_link.o /sys/fs/bpf/kprobe type kprobe
libbpf: failed to pin program: File exists
Error: failed to pin all programs
+ bpftool prog loadall tools/testing/selftests/bpf/test_cgroup_link.o /sys/fs/bpf/kprobe type kprobe

v1 -> v2:
- strict by default (Quentin Monnet)
- add more info to --legacy description (Quentin Monnet)
- add bash completion (Quentin Monnet)

Signed-off-by: Stanislav Fomichev <sdf@google.com>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Reviewed-by: Quentin Monnet <quentin@isovalent.com>
Link: https://lore.kernel.org/bpf/20211110192324.920934-1-sdf@google.com

authored by

Stanislav Fomichev and committed by
Daniel Borkmann
314f14ab 9faaffbe

+48 -19
+9
tools/bpf/bpftool/Documentation/common_options.rst
··· 20 20 Print all logs available, even debug-level information. This includes 21 21 logs from libbpf as well as from the verifier, when attempting to 22 22 load programs. 23 + 24 + -l, --legacy 25 + Use legacy libbpf mode which has more relaxed BPF program 26 + requirements. By default, bpftool has more strict requirements 27 + about section names, changes pinning logic and doesn't support 28 + some of the older non-BTF map declarations. 29 + 30 + See https://github.com/libbpf/libbpf/wiki/Libbpf:-the-road-to-v1.0 31 + for details.
+1 -1
tools/bpf/bpftool/bash-completion/bpftool
··· 261 261 # Deal with options 262 262 if [[ ${words[cword]} == -* ]]; then 263 263 local c='--version --json --pretty --bpffs --mapcompat --debug \ 264 - --use-loader --base-btf' 264 + --use-loader --base-btf --legacy' 265 265 COMPREPLY=( $( compgen -W "$c" -- "$cur" ) ) 266 266 return 0 267 267 fi
+12 -1
tools/bpf/bpftool/main.c
··· 31 31 bool verifier_logs; 32 32 bool relaxed_maps; 33 33 bool use_loader; 34 + bool legacy_libbpf; 34 35 struct btf *base_btf; 35 36 struct hashmap *refs_table; 36 37 ··· 397 396 { "debug", no_argument, NULL, 'd' }, 398 397 { "use-loader", no_argument, NULL, 'L' }, 399 398 { "base-btf", required_argument, NULL, 'B' }, 399 + { "legacy", no_argument, NULL, 'l' }, 400 400 { 0 } 401 401 }; 402 402 int opt, ret; ··· 410 408 bin_name = argv[0]; 411 409 412 410 opterr = 0; 413 - while ((opt = getopt_long(argc, argv, "VhpjfLmndB:", 411 + while ((opt = getopt_long(argc, argv, "VhpjfLmndB:l", 414 412 options, NULL)) >= 0) { 415 413 switch (opt) { 416 414 case 'V': ··· 456 454 case 'L': 457 455 use_loader = true; 458 456 break; 457 + case 'l': 458 + legacy_libbpf = true; 459 + break; 459 460 default: 460 461 p_err("unrecognized option '%s'", argv[optind - 1]); 461 462 if (json_output) ··· 466 461 else 467 462 usage(); 468 463 } 464 + } 465 + 466 + if (!legacy_libbpf) { 467 + ret = libbpf_set_strict_mode(LIBBPF_STRICT_ALL); 468 + if (ret) 469 + p_err("failed to enable libbpf strict mode: %d", ret); 469 470 } 470 471 471 472 argc -= optind;
+2 -1
tools/bpf/bpftool/main.h
··· 57 57 #define HELP_SPEC_PROGRAM \ 58 58 "PROG := { id PROG_ID | pinned FILE | tag PROG_TAG | name PROG_NAME }" 59 59 #define HELP_SPEC_OPTIONS \ 60 - "OPTIONS := { {-j|--json} [{-p|--pretty}] | {-d|--debug}" 60 + "OPTIONS := { {-j|--json} [{-p|--pretty}] | {-d|--debug} | {-l|--legacy}" 61 61 #define HELP_SPEC_MAP \ 62 62 "MAP := { id MAP_ID | pinned FILE | name MAP_NAME }" 63 63 #define HELP_SPEC_LINK \ ··· 90 90 extern bool verifier_logs; 91 91 extern bool relaxed_maps; 92 92 extern bool use_loader; 93 + extern bool legacy_libbpf; 93 94 extern struct btf *base_btf; 94 95 extern struct hashmap *refs_table; 95 96
+24 -16
tools/bpf/bpftool/prog.c
··· 1483 1483 1484 1484 while (argc) { 1485 1485 if (is_prefix(*argv, "type")) { 1486 - char *type; 1487 - 1488 1486 NEXT_ARG(); 1489 1487 1490 1488 if (common_prog_type != BPF_PROG_TYPE_UNSPEC) { ··· 1492 1494 if (!REQ_ARGS(1)) 1493 1495 goto err_free_reuse_maps; 1494 1496 1495 - /* Put a '/' at the end of type to appease libbpf */ 1496 - type = malloc(strlen(*argv) + 2); 1497 - if (!type) { 1498 - p_err("mem alloc failed"); 1499 - goto err_free_reuse_maps; 1500 - } 1501 - *type = 0; 1502 - strcat(type, *argv); 1503 - strcat(type, "/"); 1497 + err = libbpf_prog_type_by_name(*argv, &common_prog_type, 1498 + &expected_attach_type); 1499 + if (err < 0) { 1500 + /* Put a '/' at the end of type to appease libbpf */ 1501 + char *type = malloc(strlen(*argv) + 2); 1504 1502 1505 - err = get_prog_type_by_name(type, &common_prog_type, 1506 - &expected_attach_type); 1507 - free(type); 1508 - if (err < 0) 1509 - goto err_free_reuse_maps; 1503 + if (!type) { 1504 + p_err("mem alloc failed"); 1505 + goto err_free_reuse_maps; 1506 + } 1507 + *type = 0; 1508 + strcat(type, *argv); 1509 + strcat(type, "/"); 1510 + 1511 + err = get_prog_type_by_name(type, &common_prog_type, 1512 + &expected_attach_type); 1513 + free(type); 1514 + if (err < 0) 1515 + goto err_free_reuse_maps; 1516 + } 1510 1517 1511 1518 NEXT_ARG(); 1512 1519 } else if (is_prefix(*argv, "map")) { ··· 1734 1731 else 1735 1732 bpf_object__unpin_programs(obj, pinfile); 1736 1733 err_close_obj: 1734 + if (!legacy_libbpf) { 1735 + p_info("Warning: bpftool is now running in libbpf strict mode and has more stringent requirements about BPF programs.\n" 1736 + "If it used to work for this object file but now doesn't, see --legacy option for more details.\n"); 1737 + } 1738 + 1737 1739 bpf_object__close(obj); 1738 1740 err_free_reuse_maps: 1739 1741 for (i = 0; i < old_map_fds; i++)