Re: [PATCH bpf-next v2 5/6] libbpf: Add bpf_link_create_log API

From: Andrii Nakryiko

Date: Tue Oct 20 2026 - 19:26:22 EST


On Mon, Oct 19, 2026 at 8:37 AM Leon Hwang <leon.hwang@xxxxxxxxx> wrote:
>
> Add a new API to accept the log opts, instead of extending the existing
> struct bpf_link_create_opts.
>
> Appending log_opts to struct bpf_link_create_opts would place them after
> attach-type-specific fields of varying sizes, making it difficult to
> extend the struct while preserving forward compatibility.
>
> For example, adding log_opts would prevent extending uprobe_multi
> directly with a new build_id field. Instead, a separate union would
> be needed:
>
> struct bpf_link_create_opts {
> /* ... */
> union {
> /* ... */
> struct {
> /* ... */
> __u32 path_fd;
> } uprobe_multi;
> };
> struct bpf_log_opts *log_opts;
> union {
> struct {
> __u64 build_id;
> } uprobe_multi_ext;
> };
> size_t :0;
> };
>
> Without log_opts, build_id could be added directly to uprobe_multi:
>
> struct bpf_link_create_opts {
> /* ... */
> union {
> /* ... */
> struct {
> /* ... */
> __u32 path_fd;
> __u64 build_id;
> } uprobe_multi;
> };
> size_t :0;
> };
>
> Introduce bpf_link_create_log() to accept struct bpf_log_opts separately,
> preserving the forward compatibility of struct bpf_link_create_opts.
>
> Signed-off-by: Leon Hwang <leon.hwang@xxxxxxxxx>
> ---
> tools/lib/bpf/bpf.c | 28 ++++++++++++++++++++++++----
> tools/lib/bpf/bpf.h | 5 +++++
> tools/lib/bpf/libbpf.map | 2 ++
> 3 files changed, 31 insertions(+), 4 deletions(-)
>
> diff --git a/tools/lib/bpf/bpf.c b/tools/lib/bpf/bpf.c
> index 9a2107d4f6d8..263a1d516a02 100644
> --- a/tools/lib/bpf/bpf.c
> +++ b/tools/lib/bpf/bpf.c
> @@ -788,9 +788,10 @@ int bpf_prog_detach2(int prog_fd, int target_fd, enum bpf_attach_type type)
> return bpf_prog_detach_opts(prog_fd, target_fd, type, NULL);
> }
>
> -int bpf_link_create(int prog_fd, int target_fd,
> - enum bpf_attach_type attach_type,
> - const struct bpf_link_create_opts *opts)
> +static int __bpf_link_create(int prog_fd, int target_fd,
> + enum bpf_attach_type attach_type,
> + const struct bpf_link_create_opts *opts,
> + struct bpf_log_opts *log_opts)
> {
> const size_t attr_sz = offsetofend(union bpf_attr, link_create);
> __u32 target_btf_id, iter_info_len, relative_id;
> @@ -965,7 +966,7 @@ int bpf_link_create(int prog_fd, int target_fd,
> break;
> }
> proceed:
> - fd = sys_bpf_fd(BPF_LINK_CREATE, &attr, attr_sz);
> + fd = __sys_bpf_fd(&attr, attr_sz, BPF_LINK_CREATE, log_opts);
> if (fd >= 0)
> return fd;
> /* we'll get EINVAL if LINK_CREATE doesn't support attaching fentry
> @@ -975,6 +976,10 @@ int bpf_link_create(int prog_fd, int target_fd,
> if (err != -EINVAL)
> return libbpf_err(err);
>
> + /* bpf_raw_tracepoint_open() does not support log_opts */
> + if (log_opts)
> + return libbpf_err(err);
> +
> /* if user used features not supported by
> * BPF_RAW_TRACEPOINT_OPEN command, then just give up immediately
> */
> @@ -999,6 +1004,21 @@ int bpf_link_create(int prog_fd, int target_fd,
> }
> }
>
> +int bpf_link_create(int prog_fd, int target_fd,
> + enum bpf_attach_type attach_type,
> + const struct bpf_link_create_opts *opts)
> +{
> + return __bpf_link_create(prog_fd, target_fd, attach_type, opts, NULL);
> +}
> +
> +int bpf_link_create_log(int prog_fd, int target_fd,
> + enum bpf_attach_type attach_type,
> + const struct bpf_link_create_opts *opts,
> + struct bpf_log_opts *log_opts)
> +{
> + return __bpf_link_create(prog_fd, target_fd, attach_type, opts, log_opts);
> +}
> +
> int bpf_link_detach(int link_fd)
> {
> const size_t attr_sz = offsetofend(union bpf_attr, link_detach);
> diff --git a/tools/lib/bpf/bpf.h b/tools/lib/bpf/bpf.h
> index 826d9cc9ab65..dedaf8086902 100644
> --- a/tools/lib/bpf/bpf.h
> +++ b/tools/lib/bpf/bpf.h
> @@ -484,6 +484,11 @@ LIBBPF_API int bpf_link_create(int prog_fd, int target_fd,
> enum bpf_attach_type attach_type,
> const struct bpf_link_create_opts *opts);
>
> +LIBBPF_API int bpf_link_create_log(int prog_fd, int target_fd,
> + enum bpf_attach_type attach_type,
> + const struct bpf_link_create_opts *opts,
> + struct bpf_log_opts *log_opts);

Leon,

how about instead of adding this new API, we try to repurpose
bpf_link_create_opts' iter_info to be used as log opts? we have this
right now:

union bpf_iter_link_info; /* defined in up-to-date linux/bpf.h */
struct bpf_link_create_opts {
size_t sz; /* size of this struct for forward/backward compatibility */
__u32 flags;
union bpf_iter_link_info *iter_info;
__u32 iter_info_len;
__u32 target_btf_id;
union {


that iter_info/iter_info_len is a bit of a legacy before we had
per-attach type union, what if we add iter section into the union,
wrap iter_info with union and put log_opts there, mark iter_info
deprecated or something.

I'm not sure anyone is actually using iter_info (I didn't find any
uses in Meta code base, for instance), but we can detect its use by
checking iter_info_len: if it's non-zero, then iter_info must be a
real bpf_iter_link_info. so we should be able to detect this just
fine, the only downside is that you can't use log_opts and iter_info
simultaneously, but I think that's fine: you can update your code to
use new iter.info fields instead, if you need log_opts + iter_info.

WDYT?


> +
> LIBBPF_API int bpf_link_detach(int link_fd);
>
> struct bpf_link_update_opts {
> diff --git a/tools/lib/bpf/libbpf.map b/tools/lib/bpf/libbpf.map
> index eeba4072a5da..f6eb57151f7d 100644
> --- a/tools/lib/bpf/libbpf.map
> +++ b/tools/lib/bpf/libbpf.map
> @@ -475,4 +475,6 @@ LIBBPF_1.8.0 {
> } LIBBPF_1.7.0;
>
> LIBBPF_1.9.0 {
> + global:
> + bpf_link_create_log;
> } LIBBPF_1.8.0;
> --
> 2.55.0
>