Re: [PATCH RFC bpf-next 0/7] bpf: Support struct_ops in light skeletons

From: Ihor Solodrai

Date: Mon Nov 09 2026 - 14:47:48 EST


On 11/6/26 1:19 PM, Siddharth Nayyar wrote:
> BPF light skeletons (bpftool gen skeleton -L) compile BPF object loading
> into a self-contained BPF_PROG_TYPE_SYSCALL loader program (gen_loader)
> embedded in a C header, removing any runtime dependency on libbpf or
> userspace BTF parsing. Currently, light skeletons do not support
> BPF_MAP_TYPE_STRUCT_OPS maps or BPF_PROG_TYPE_STRUCT_OPS programs
> because preparing a struct_ops map normally relies on libbpf parsing the
> target vmlinux or kernel module BTF in userspace to resolve type IDs,
> struct sizes, member byte offsets, and member indices.
>
> This series adds BPF_MAP_TYPE_STRUCT_OPS support for link-based
> (SEC(".struct_ops.link")) maps in light skeletons across both vmlinux
> and kernel module BTF targets:
>
> - Patch 1 adds a new bpf_btf_get_struct_member_info() helper for
> BPF_PROG_TYPE_SYSCALL programs to query a struct's byte size (when the
> member name is NULL) or a named member's byte offset and member index
> from vmlinux or module BTF at load time.
> - Patches 2-5 wire up struct_ops initialization, map creation, program
> loading, and map update in libbpf's gen_loader. At runtime, the loader
> program resolves the kernel wrapper type bpf_struct_ops_<name> and
> target <name> struct BTF IDs (and module BTF FDs) via
> bpf_btf_find_by_name_kind(), queries struct sizes and member
> offsets/indices via bpf_btf_get_struct_member_info(), constructs the
> kernel vdata buffer in the loader data blob, passes the resolved BTF
> metadata to BPF_MAP_CREATE and BPF_PROG_LOAD, and populates the
> callback program FDs before issuing BPF_MAP_UPDATE_ELEM.
> - Patch 6 teaches bpftool to generate per-map skel_link_create() attach
> functions and skel__attach() / skel__detach() plumbing for BPF_F_LINK
> struct_ops maps in light skeletons, skips gen_st_ops_shadow() so the
> light skeleton ctx layout is preserved, and rejects non-link
> struct_ops maps.
> - Patch 7 adds light skeleton struct_ops selftests covering both vmlinux
> (tcp_congestion_ops) and bpf_testmod (bpf_testmod_ops, including a
> subset struct with reordered members, scalar fields, detach, and
> re-attachment).
>
> Adding a new BPF helper and alternative kfunc approach
> ======================================================
> I am aware that BPF helpers have been frozen for several years in favor
> of kfuncs. I propose adding bpf_btf_get_struct_member_info() as a BPF
> helper (restricted exclusively to BPF_PROG_TYPE_SYSCALL loader programs,
> alongside bpf_btf_find_by_name_kind()) because, to my knowledge, there
> is no better way to enable struct_ops support in light skeletons.
>
> Before settling on a BPF helper, I explored an alternative approach
> using a kfunc, which hit a roadblock. Calling a kfunc directly from the
> light skeleton loader program is not possible because kfunc calls
> (BPF_PSEUDO_KFUNC_CALL) require the target kfunc's BTF ID in insn->imm
> when the loader program itself is loaded, whereas light skeletons ship
> pre-generated loader bytecode without userspace BTF resolution.

Hi Siddharth,

I don't think a new helper is going to fly.
It's a legacy baggage we are carrying because we can't easily get rid
of it, we don't want to make it heavier.

IIUC the problem is that the BPF instructions of the loader are
supposed to be frozen (signed?), therefore it's not an option to patch
them at load time, as libbpf normally does with kfuncs.

I think the way around this may be teaching the kernel to resolve
kfuncs itself, similar to how it resolves CO-RE relocations?

The call instruction (or a new bpf_core_relo kind) would refer to the
kfunc in the *program* BTF instead of a kernel BTF ID. Early in
bpf_check(), the verifier would look the name up in vmlinux and module
BTF, check prototype compatibility against the local FUNC, and patch
imm/off. The rest of the verifier would see a regular kfunc call.

The loader could then call kfuncs, so your member info query could be
a kfunc, and the programs it loads would resolve kfuncs the same way
libbpf does.

One concern with this may be that we are moving libbpf functionality
into the kernel, which may not be desirable for reasons I haven't
thought of. Not sure.

Andrii, Alexei, wdyt? Any other ideas?



> [...]