Skip to content

Commit 477bb4c

Browse files
committed
Merge branch 'libbpf: Implement BTFGen'
Mauricio Vásquez <[email protected]> says: ==================== CO-RE requires to have BTF information describing the kernel types in order to perform the relocations. This is usually provided by the kernel itself when it's configured with CONFIG_DEBUG_INFO_BTF. However, this configuration is not enabled in all the distributions and it's not available on kernels before 5.12. It's possible to use CO-RE in kernels without CONFIG_DEBUG_INFO_BTF support by providing the BTF information from an external source. BTFHub[0] contains BTF files to each released kernel not supporting BTF, for the most popular distributions. Providing this BTF file for a given kernel has some challenges: 1. Each BTF file is a few MBs big, then it's not possible to ship the eBPF program with all the BTF files needed to run in different kernels. (The BTF files will be in the order of GBs if you want to support a high number of kernels) 2. Downloading the BTF file for the current kernel at runtime delays the start of the program and it's not always possible to reach an external host to download such a file. Providing the BTF file with the information about all the data types of the kernel for running an eBPF program is an overkill in many of the cases. Usually the eBPF programs access only some kernel fields. This series implements BTFGen support in bpftool. This idea was discussed during the "Towards truly portable eBPF"[1] presentation at Linux Plumbers 2021. There is a good example[2] on how to use BTFGen and BTFHub together to generate multiple BTF files, to each existing/supported kernel, tailored to one application. For example: a complex bpf object might support nearly 400 kernels by having BTF files summing only 1.5 MB. [0]: https://github.com/aquasecurity/btfhub/ [1]: https://www.youtube.com/watch?v=igJLKyP1lFk&t=2418s [2]: https://github.com/aquasecurity/btfhub/tree/main/tools Changelog: v6 > v7: - use array instead of hashmap to store ids - use btf__add_{struct,union}() instead of memcpy() - don't use fixed path for testing BTF file - update example to use DECLARE_LIBBPF_OPTS() v5 > v6: - use BTF structure to store used member/types instead of hashmaps - remove support for input/output folders - remove bpf_core_{created,free}_cand_cache() - reorganize commits to avoid having unused static functions - remove usage of libbpf_get_error() - fix some errno propagation issues - do not record full types for type-based relocations - add support for BTF_KIND_FUNC_PROTO - implement tests based on core_reloc ones v4 > v5: - move some checks before invoking prog->obj->gen_loader - use p_info() instead of printf() - improve command output - fix issue with record_relo_core() - implement bash completion - write man page - implement some tests v3 > v4: - parse BTF and BTF.ext sections in bpftool and use bpf_core_calc_relo_insn() directly - expose less internal details from libbpf to bpftool - implement support for enum-based relocations - split commits in a more granular way v2 > v3: - expose internal libbpf APIs to bpftool instead - implement btfgen in bpftool - drop btf__raw_data() from libbpf v1 > v2: - introduce bpf_object__prepare() and ‘record_core_relos’ to expose CO-RE relocations instead of bpf_object__reloc_info_gen() - rename btf__save_to_file() to btf__raw_data() v1: https://lore.kernel.org/bpf/[email protected]/ v2: https://lore.kernel.org/bpf/[email protected]/ v3: https://lore.kernel.org/bpf/[email protected]/ v4: https://lore.kernel.org/bpf/[email protected]/ v5: https://lore.kernel.org/bpf/[email protected]/ v6: https://lore.kernel.org/bpf/[email protected]/ Mauricio Vásquez (6): libbpf: split bpf_core_apply_relo() libbpf: Expose bpf_core_{add,free}_cands() to bpftool bpftool: Add gen min_core_btf command bpftool: Implement "gen min_core_btf" logic bpftool: Implement btfgen_get_btf() selftests/bpf: Test "bpftool gen min_core_btf" ==================== Signed-off-by: Andrii Nakryiko <[email protected]>
2 parents 8cbf062 + 704c91e commit 477bb4c

File tree

10 files changed

+863
-113
lines changed

10 files changed

+863
-113
lines changed

kernel/bpf/btf.c

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7225,6 +7225,7 @@ int bpf_core_apply(struct bpf_core_ctx *ctx, const struct bpf_core_relo *relo,
72257225
{
72267226
bool need_cands = relo->kind != BPF_CORE_TYPE_ID_LOCAL;
72277227
struct bpf_core_cand_list cands = {};
7228+
struct bpf_core_relo_res targ_res;
72287229
struct bpf_core_spec *specs;
72297230
int err;
72307231

@@ -7264,13 +7265,19 @@ int bpf_core_apply(struct bpf_core_ctx *ctx, const struct bpf_core_relo *relo,
72647265
cands.len = cc->cnt;
72657266
/* cand_cache_mutex needs to span the cache lookup and
72667267
* copy of btf pointer into bpf_core_cand_list,
7267-
* since module can be unloaded while bpf_core_apply_relo_insn
7268+
* since module can be unloaded while bpf_core_calc_relo_insn
72687269
* is working with module's btf.
72697270
*/
72707271
}
72717272

7272-
err = bpf_core_apply_relo_insn((void *)ctx->log, insn, relo->insn_off / 8,
7273-
relo, relo_idx, ctx->btf, &cands, specs);
7273+
err = bpf_core_calc_relo_insn((void *)ctx->log, relo, relo_idx, ctx->btf, &cands, specs,
7274+
&targ_res);
7275+
if (err)
7276+
goto out;
7277+
7278+
err = bpf_core_patch_insn((void *)ctx->log, insn, relo->insn_off / 8, relo, relo_idx,
7279+
&targ_res);
7280+
72747281
out:
72757282
kfree(specs);
72767283
if (need_cands) {

tools/bpf/bpftool/Documentation/bpftool-gen.rst

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ GEN COMMANDS
2525

2626
| **bpftool** **gen object** *OUTPUT_FILE* *INPUT_FILE* [*INPUT_FILE*...]
2727
| **bpftool** **gen skeleton** *FILE* [**name** *OBJECT_NAME*]
28+
| **bpftool** **gen min_core_btf** *INPUT* *OUTPUT* *OBJECT* [*OBJECT*...]
2829
| **bpftool** **gen help**
2930
3031
DESCRIPTION
@@ -149,6 +150,26 @@ DESCRIPTION
149150
(non-read-only) data from userspace, with same simplicity
150151
as for BPF side.
151152

153+
**bpftool** **gen min_core_btf** *INPUT* *OUTPUT* *OBJECT* [*OBJECT*...]
154+
Generate a minimum BTF file as *OUTPUT*, derived from a given
155+
*INPUT* BTF file, containing all needed BTF types so one, or
156+
more, given eBPF objects CO-RE relocations may be satisfied.
157+
158+
When kernels aren't compiled with CONFIG_DEBUG_INFO_BTF,
159+
libbpf, when loading an eBPF object, has to rely on external
160+
BTF files to be able to calculate CO-RE relocations.
161+
162+
Usually, an external BTF file is built from existing kernel
163+
DWARF data using pahole. It contains all the types used by
164+
its respective kernel image and, because of that, is big.
165+
166+
The min_core_btf feature builds smaller BTF files, customized
167+
to one or multiple eBPF objects, so they can be distributed
168+
together with an eBPF CO-RE based application, turning the
169+
application portable to different kernel versions.
170+
171+
Check examples bellow for more information how to use it.
172+
152173
**bpftool gen help**
153174
Print short help message.
154175

@@ -215,7 +236,9 @@ This is example BPF application with two BPF programs and a mix of BPF maps
215236
and global variables. Source code is split across two source code files.
216237

217238
**$ clang -target bpf -g example1.bpf.c -o example1.bpf.o**
239+
218240
**$ clang -target bpf -g example2.bpf.c -o example2.bpf.o**
241+
219242
**$ bpftool gen object example.bpf.o example1.bpf.o example2.bpf.o**
220243

221244
This set of commands compiles *example1.bpf.c* and *example2.bpf.c*
@@ -329,3 +352,70 @@ BPF ELF object file *example.bpf.o*.
329352
my_static_var: 7
330353

331354
This is a stripped-out version of skeleton generated for above example code.
355+
356+
min_core_btf
357+
------------
358+
359+
**$ bpftool btf dump file 5.4.0-example.btf format raw**
360+
361+
::
362+
363+
[1] INT 'long unsigned int' size=8 bits_offset=0 nr_bits=64 encoding=(none)
364+
[2] CONST '(anon)' type_id=1
365+
[3] VOLATILE '(anon)' type_id=1
366+
[4] ARRAY '(anon)' type_id=1 index_type_id=21 nr_elems=2
367+
[5] PTR '(anon)' type_id=8
368+
[6] CONST '(anon)' type_id=5
369+
[7] INT 'char' size=1 bits_offset=0 nr_bits=8 encoding=(none)
370+
[8] CONST '(anon)' type_id=7
371+
[9] INT 'unsigned int' size=4 bits_offset=0 nr_bits=32 encoding=(none)
372+
<long output>
373+
374+
**$ bpftool btf dump file one.bpf.o format raw**
375+
376+
::
377+
378+
[1] PTR '(anon)' type_id=2
379+
[2] STRUCT 'trace_event_raw_sys_enter' size=64 vlen=4
380+
'ent' type_id=3 bits_offset=0
381+
'id' type_id=7 bits_offset=64
382+
'args' type_id=9 bits_offset=128
383+
'__data' type_id=12 bits_offset=512
384+
[3] STRUCT 'trace_entry' size=8 vlen=4
385+
'type' type_id=4 bits_offset=0
386+
'flags' type_id=5 bits_offset=16
387+
'preempt_count' type_id=5 bits_offset=24
388+
<long output>
389+
390+
**$ bpftool gen min_core_btf 5.4.0-example.btf 5.4.0-smaller.btf one.bpf.o**
391+
392+
**$ bpftool btf dump file 5.4.0-smaller.btf format raw**
393+
394+
::
395+
396+
[1] TYPEDEF 'pid_t' type_id=6
397+
[2] STRUCT 'trace_event_raw_sys_enter' size=64 vlen=1
398+
'args' type_id=4 bits_offset=128
399+
[3] STRUCT 'task_struct' size=9216 vlen=2
400+
'pid' type_id=1 bits_offset=17920
401+
'real_parent' type_id=7 bits_offset=18048
402+
[4] ARRAY '(anon)' type_id=5 index_type_id=8 nr_elems=6
403+
[5] INT 'long unsigned int' size=8 bits_offset=0 nr_bits=64 encoding=(none)
404+
[6] TYPEDEF '__kernel_pid_t' type_id=8
405+
[7] PTR '(anon)' type_id=3
406+
[8] INT 'int' size=4 bits_offset=0 nr_bits=32 encoding=SIGNED
407+
<end>
408+
409+
Now, the "5.4.0-smaller.btf" file may be used by libbpf as an external BTF file
410+
when loading the "one.bpf.o" object into the "5.4.0-example" kernel. Note that
411+
the generated BTF file won't allow other eBPF objects to be loaded, just the
412+
ones given to min_core_btf.
413+
414+
::
415+
416+
LIBBPF_OPTS(bpf_object_open_opts, opts, .btf_custom_path = "5.4.0-smaller.btf");
417+
struct bpf_object *obj;
418+
419+
obj = bpf_object__open_file("one.bpf.o", &opts);
420+
421+
...

tools/bpf/bpftool/Makefile

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,10 +34,10 @@ LIBBPF_BOOTSTRAP_INCLUDE := $(LIBBPF_BOOTSTRAP_DESTDIR)/include
3434
LIBBPF_BOOTSTRAP_HDRS_DIR := $(LIBBPF_BOOTSTRAP_INCLUDE)/bpf
3535
LIBBPF_BOOTSTRAP := $(LIBBPF_BOOTSTRAP_OUTPUT)libbpf.a
3636

37-
# We need to copy hashmap.h and nlattr.h which is not otherwise exported by
38-
# libbpf, but still required by bpftool.
39-
LIBBPF_INTERNAL_HDRS := $(addprefix $(LIBBPF_HDRS_DIR)/,hashmap.h nlattr.h)
40-
LIBBPF_BOOTSTRAP_INTERNAL_HDRS := $(addprefix $(LIBBPF_BOOTSTRAP_HDRS_DIR)/,hashmap.h)
37+
# We need to copy hashmap.h, nlattr.h, relo_core.h and libbpf_internal.h
38+
# which are not otherwise exported by libbpf, but still required by bpftool.
39+
LIBBPF_INTERNAL_HDRS := $(addprefix $(LIBBPF_HDRS_DIR)/,hashmap.h nlattr.h relo_core.h libbpf_internal.h)
40+
LIBBPF_BOOTSTRAP_INTERNAL_HDRS := $(addprefix $(LIBBPF_BOOTSTRAP_HDRS_DIR)/,hashmap.h relo_core.h libbpf_internal.h)
4141

4242
$(LIBBPF_OUTPUT) $(BOOTSTRAP_OUTPUT) $(LIBBPF_BOOTSTRAP_OUTPUT) $(LIBBPF_HDRS_DIR) $(LIBBPF_BOOTSTRAP_HDRS_DIR):
4343
$(QUIET_MKDIR)mkdir -p $@

tools/bpf/bpftool/bash-completion/bpftool

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1003,9 +1003,13 @@ _bpftool()
10031003
;;
10041004
esac
10051005
;;
1006+
min_core_btf)
1007+
_filedir
1008+
return 0
1009+
;;
10061010
*)
10071011
[[ $prev == $object ]] && \
1008-
COMPREPLY=( $( compgen -W 'object skeleton help' -- "$cur" ) )
1012+
COMPREPLY=( $( compgen -W 'object skeleton help min_core_btf' -- "$cur" ) )
10091013
;;
10101014
esac
10111015
;;

0 commit comments

Comments
 (0)