Skip to content

Commit b6b466a

Browse files
author
Alexei Starovoitov
committed
Merge branch 'libbpf: split BTF support'
Andrii Nakryiko says: ==================== This patch set adds support for generating and deduplicating split BTF. This is an enhancement to the BTF, which allows to designate one BTF as the "base BTF" (e.g., vmlinux BTF), and one or more other BTFs as "split BTF" (e.g., kernel module BTF), which are building upon and extending base BTF with extra types and strings. Once loaded, split BTF appears as a single unified BTF superset of base BTF, with continuous and transparent numbering scheme. This allows all the existing users of BTF to work correctly and stay agnostic to the base/split BTFs composition. The only difference is in how to instantiate split BTF: it requires base BTF to be alread instantiated and passed to btf__new_xxx_split() or btf__parse_xxx_split() "constructors" explicitly. This split approach is necessary if we are to have a reasonably-sized kernel module BTFs. By deduping each kernel module's BTF individually, resulting module BTFs contain copies of a lot of kernel types that are already present in vmlinux BTF. Even those single copies result in a big BTF size bloat. On my kernel configuration with 700 modules built, non-split BTF approach results in 115MBs of BTFs across all modules. With split BTF deduplication approach, total size is down to 5.2MBs total, which is on part with vmlinux BTF (at around 4MBs). This seems reasonable and practical. As to why we'd need kernel module BTFs, that should be pretty obvious to anyone using BPF at this point, as it allows all the BTF-powered features to be used with kernel modules: tp_btf, fentry/fexit/fmod_ret, lsm, bpf_iter, etc. This patch set is a pre-requisite to adding split BTF support to pahole, which is a prerequisite to integrating split BTF into the Linux kernel build setup to generate BTF for kernel modules. The latter will come as a follow-up patch series once this series makes it to the libbpf and pahole makes use of it. Patch #4 introduces necessary basic support for split BTF into libbpf APIs. Patch #8 implements minimal changes to BTF dedup algorithm to allow deduplicating split BTFs. Patch #11 adds extra -B flag to bpftool to allow to specify the path to base BTF for cases when one wants to dump or inspect split BTF. All the rest are refactorings, clean ups, bug fixes and selftests. v1->v2: - addressed Song's feedback. ==================== Signed-off-by: Alexei Starovoitov <[email protected]>
2 parents d0b3d2d + 75fa177 commit b6b466a

File tree

14 files changed

+1292
-355
lines changed

14 files changed

+1292
-355
lines changed

tools/bpf/bpftool/btf.c

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -358,8 +358,12 @@ static int dump_btf_raw(const struct btf *btf,
358358
}
359359
} else {
360360
int cnt = btf__get_nr_types(btf);
361+
int start_id = 1;
361362

362-
for (i = 1; i <= cnt; i++) {
363+
if (base_btf)
364+
start_id = btf__get_nr_types(base_btf) + 1;
365+
366+
for (i = start_id; i <= cnt; i++) {
363367
t = btf__type_by_id(btf, i);
364368
dump_btf_type(btf, i, t);
365369
}
@@ -438,7 +442,6 @@ static int do_dump(int argc, char **argv)
438442
return -1;
439443
}
440444
src = GET_ARG();
441-
442445
if (is_prefix(src, "map")) {
443446
struct bpf_map_info info = {};
444447
__u32 len = sizeof(info);
@@ -499,7 +502,7 @@ static int do_dump(int argc, char **argv)
499502
}
500503
NEXT_ARG();
501504
} else if (is_prefix(src, "file")) {
502-
btf = btf__parse(*argv, NULL);
505+
btf = btf__parse_split(*argv, base_btf);
503506
if (IS_ERR(btf)) {
504507
err = -PTR_ERR(btf);
505508
btf = NULL;

tools/bpf/bpftool/main.c

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
#include <bpf/bpf.h>
1313
#include <bpf/libbpf.h>
14+
#include <bpf/btf.h>
1415

1516
#include "main.h"
1617

@@ -28,6 +29,7 @@ bool show_pinned;
2829
bool block_mount;
2930
bool verifier_logs;
3031
bool relaxed_maps;
32+
struct btf *base_btf;
3133
struct pinned_obj_table prog_table;
3234
struct pinned_obj_table map_table;
3335
struct pinned_obj_table link_table;
@@ -391,6 +393,7 @@ int main(int argc, char **argv)
391393
{ "mapcompat", no_argument, NULL, 'm' },
392394
{ "nomount", no_argument, NULL, 'n' },
393395
{ "debug", no_argument, NULL, 'd' },
396+
{ "base-btf", required_argument, NULL, 'B' },
394397
{ 0 }
395398
};
396399
int opt, ret;
@@ -407,7 +410,7 @@ int main(int argc, char **argv)
407410
hash_init(link_table.table);
408411

409412
opterr = 0;
410-
while ((opt = getopt_long(argc, argv, "Vhpjfmnd",
413+
while ((opt = getopt_long(argc, argv, "VhpjfmndB:",
411414
options, NULL)) >= 0) {
412415
switch (opt) {
413416
case 'V':
@@ -441,6 +444,15 @@ int main(int argc, char **argv)
441444
libbpf_set_print(print_all_levels);
442445
verifier_logs = true;
443446
break;
447+
case 'B':
448+
base_btf = btf__parse(optarg, NULL);
449+
if (libbpf_get_error(base_btf)) {
450+
p_err("failed to parse base BTF at '%s': %ld\n",
451+
optarg, libbpf_get_error(base_btf));
452+
base_btf = NULL;
453+
return -1;
454+
}
455+
break;
444456
default:
445457
p_err("unrecognized option '%s'", argv[optind - 1]);
446458
if (json_output)
@@ -465,6 +477,7 @@ int main(int argc, char **argv)
465477
delete_pinned_obj_table(&map_table);
466478
delete_pinned_obj_table(&link_table);
467479
}
480+
btf__free(base_btf);
468481

469482
return ret;
470483
}

tools/bpf/bpftool/main.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ extern bool show_pids;
9090
extern bool block_mount;
9191
extern bool verifier_logs;
9292
extern bool relaxed_maps;
93+
extern struct btf *base_btf;
9394
extern struct pinned_obj_table prog_table;
9495
extern struct pinned_obj_table map_table;
9596
extern struct pinned_obj_table link_table;

0 commit comments

Comments
 (0)