• Andrii Nakryiko's avatar
    libbpf: implement __arg_ctx fallback logic · 2f38fe68
    Andrii Nakryiko authored
    Out of all special global func arg tag annotations, __arg_ctx is
    practically is the most immediately useful and most critical to have
    working across multitude kernel version, if possible. This would allow
    end users to write much simpler code if __arg_ctx semantics worked for
    older kernels that don't natively understand btf_decl_tag("arg:ctx") in
    verifier logic.
    
    Luckily, it is possible to ensure __arg_ctx works on old kernels through
    a bit of extra work done by libbpf, at least in a lot of common cases.
    
    To explain the overall idea, we need to go back at how context argument
    was supported in global funcs before __arg_ctx support was added. This
    was done based on special struct name checks in kernel. E.g., for
    BPF_PROG_TYPE_PERF_EVENT the expectation is that argument type `struct
    bpf_perf_event_data *` mark that argument as PTR_TO_CTX. This is all
    good as long as global function is used from the same BPF program types
    only, which is often not the case. If the same subprog has to be called
    from, say, kprobe and perf_event program types, there is no single
    definition that would satisfy BPF verifier. Subprog will have context
    argument either for kprobe (if using bpf_user_pt_regs_t struct name) or
    perf_event (with bpf_perf_event_data struct name), but not both.
    
    This limitation was the reason to add btf_decl_tag("arg:ctx"), making
    the actual argument type not important, so that user can just define
    "generic" signature:
    
      __noinline int global_subprog(void *ctx __arg_ctx) { ... }
    
    I won't belabor how libbpf is implementing subprograms, see a huge
    comment next to bpf_object_relocate_calls() function. The idea is that
    each main/entry BPF program gets its own copy of global_subprog's code
    appended.
    
    This per-program copy of global subprog code *and* associated func_info
    .BTF.ext information, pointing to FUNC -> FUNC_PROTO BTF type chain
    allows libbpf to simulate __arg_ctx behavior transparently, even if the
    kernel doesn't yet support __arg_ctx annotation natively.
    
    The idea is straightforward: each time we append global subprog's code
    and func_info information, we adjust its FUNC -> FUNC_PROTO type
    information, if necessary (that is, libbpf can detect the presence of
    btf_decl_tag("arg:ctx") just like BPF verifier would do it).
    
    The rest is just mechanical and somewhat painful BTF manipulation code.
    It's painful because we need to clone FUNC -> FUNC_PROTO, instead of
    reusing it, as same FUNC -> FUNC_PROTO chain might be used by another
    main BPF program within the same BPF object, so we can't just modify it
    in-place (and cloning BTF types within the same struct btf object is
    painful due to constant memory invalidation, see comments in code).
    Uploaded BPF object's BTF information has to work for all BPF
    programs at the same time.
    
    Once we have FUNC -> FUNC_PROTO clones, we make sure that instead of
    using some `void *ctx` parameter definition, we have an expected `struct
    bpf_perf_event_data *ctx` definition (as far as BPF verifier and kernel
    is concerned), which will mark it as context for BPF verifier. Same
    global subprog relocated and copied into another main BPF program will
    get different type information according to main program's type. It all
    works out in the end in a completely transparent way for end user.
    
    Libbpf maintains internal program type -> expected context struct name
    mapping internally. Note, not all BPF program types have named context
    struct, so this approach won't work for such programs (just like it
    didn't before __arg_ctx). So native __arg_ctx is still important to have
    in kernel to have generic context support across all BPF program types.
    Acked-by: default avatarJiri Olsa <jolsa@kernel.org>
    Signed-off-by: default avatarAndrii Nakryiko <andrii@kernel.org>
    Link: https://lore.kernel.org/r/20240104013847.3875810-8-andrii@kernel.orgSigned-off-by: default avatarAlexei Starovoitov <ast@kernel.org>
    2f38fe68
libbpf.c 365 KB