Repository navigation
libxdp: Synthesise BTF for component programs supplied as instructions - #592
Closed
simonmorley wants to merge 1 commit into
Closed
simonmorley wants to merge 1 commit into
simonmorley wants to merge 1 commit into
Conversation
A dispatcher component has to be loaded as BPF_PROG_TYPE_EXT, and the kernel only accepts an EXT program that carries BTF describing its own function signature: check_attach_btf_id() compares the replacement's prototype against the target function's via btf_check_func_type_match(). A program's BTF is fixed at BPF_PROG_LOAD time, so a caller holding an already-loaded BTF-less program cannot add it afterwards, and xdp_multiprog__link_prog() correctly refuses such a program. This excludes any project that emits BPF bytecode directly instead of compiling it with clang. Such a program can only take the whole interface, which in turn locks every libxdp user out of that interface. Every XDP component has the same int (struct xdp_md *) signature, so the BTF is fully determined and libxdp can generate it. Add insns/insns_cnt to struct xdp_program_opts and synthesise a minimal ELF object - the instructions, a license section, the BTF, and a .BTF.ext func_info record - which is then opened with bpf_object__open_mem() and handled like any other object. Wrapping the instructions in an ELF rather than loading them directly means the attach, EXT conversion and chain linking paths need no special case. Two details worth noting. The struct xdp_md in the generated BTF is deliberately opaque: btf_check_func_type_match() compares the struct name and never its members, so a component need not agree with the kernel on the layout, which keeps the BTF small and version-independent. And libelf references the image rather than copying it, so the buffer is owned by the xdp_program and freed in xdp_program__close(), after bpf_object__close() has stopped reading it. Add a test that creates a program from a raw instruction stream and checks that it attaches as a component of a real dispatcher rather than falling back to a legacy single-program attach. Signed-off-by: Simon Morley <simon@nullrabbit.ai>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #591.
A dispatcher component has to be loaded as
BPF_PROG_TYPE_EXT, and the kernel only accepts anEXTprogram that carries BTF describing its own function signature —check_attach_btf_id()compares the replacement's prototype against the target function's viabtf_check_func_type_match(). Since a program's BTF is fixed atBPF_PROG_LOADtime, a caller holding an already-loaded BTF-less program cannot add it afterwards, andxdp_multiprog__link_prog()correctly refuses it.That excludes any project emitting BPF bytecode directly rather than compiling it with clang. Such a program can only take the whole interface, which in turn locks every libxdp user out of that interface.
Every XDP component has the same
int (struct xdp_md *)signature, so the BTF is fully determined and libxdp can generate it. This addsinsns/insns_cnttostruct xdp_program_opts:Approach
xdp_elfgen.csynthesises a minimal ELF object — the instructions, a license section, the BTF, and a.BTF.extfunc_info record — which is then opened withbpf_object__open_mem(). Wrapping the instructions in an ELF rather than loading them directly means the result is an ordinarystruct bpf_object, so the attach, EXT conversion and chain linking paths need no special case at all.Two details worth flagging for review:
struct xdp_mdin the generated BTF is deliberately opaque (vlen = 0).btf_check_func_type_match()compares the struct name and never its members, so a component need not agree with the kernel on the layout. That keeps the BTF at ~127 bytes and independent of kernel version.xdp_programand freed inxdp_program__close(), afterbpf_object__close()has stopped reading it.No new exported symbol, so
libxdp.mapis unchanged —xdp_program__create()has been exported sinceLIBXDP_1.3.0and the opts struct is extended through the existingszmechanism.Testing
New
test_synth_insnscreates a program from a raw instruction stream and checks it attaches as a component of a real dispatcher, rather than falling back to a legacy single-program attach. Full suite on 6.12.107, x86-64:libxdp.3was updated by hand rather than regenerated, as emacs was not available here; it renders correctly under groff but is worth a check against the org export.🤖 Generated with Claude Code