All of lore.kernel.org
 help / color / mirror / Atom feed
From: "Emil Tsalapatis" <emil@etsalapatis.com>
To: "Mykyta Yatsenko" <mykyta.yatsenko5@gmail.com>,
	<bpf@vger.kernel.org>, <ast@kernel.org>, <andrii@kernel.org>,
	<daniel@iogearbox.net>, <kafai@meta.com>, <kernel-team@meta.com>,
	<eddyz87@gmail.com>
Cc: "Mykyta Yatsenko" <yatsenko@meta.com>
Subject: Re: [PATCH bpf-next v4 1/3] libbpf: Introduce bpf_program__clone()
Date: Tue, 17 Mar 2026 15:40:52 -0400	[thread overview]
Message-ID: <DH5B9WYNX00J.8R01FVFXM4YR@etsalapatis.com> (raw)
In-Reply-To: <20260317-veristat_prepare-v4-1-74193d4cc9d9@meta.com>

On Tue Mar 17, 2026 at 1:39 PM EDT, Mykyta Yatsenko wrote:
> From: Mykyta Yatsenko <yatsenko@meta.com>
>
> Add bpf_program__clone() API that loads a single BPF program from a
> prepared BPF object into the kernel, returning a file descriptor owned
> by the caller.
>
> After bpf_object__prepare(), callers can use bpf_program__clone() to
> load individual programs with custom bpf_prog_load_opts, instead of
> loading all programs at once via bpf_object__load(). Non-zero fields in
> opts override the defaults derived from the program and object
> internals; passing NULL opts populates everything automatically.
>
> Signed-off-by: Mykyta Yatsenko <yatsenko@meta.com>

Reviewed-by: Emil Tsalapatis <emil@etsalapatis.com>

Overriding the prepare_load_fn() callback's results with user-provided
ones is a valid choice design-wise.

> ---
>  tools/lib/bpf/libbpf.c   | 78 ++++++++++++++++++++++++++++++++++++++++++++++++
>  tools/lib/bpf/libbpf.h   | 17 +++++++++++
>  tools/lib/bpf/libbpf.map |  1 +
>  3 files changed, 96 insertions(+)
>
> diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c
> index 0662d72bad20..1eaa7527d4da 100644
> --- a/tools/lib/bpf/libbpf.c
> +++ b/tools/lib/bpf/libbpf.c
> @@ -9802,6 +9802,84 @@ __u32 bpf_program__line_info_cnt(const struct bpf_program *prog)
>  	return prog->line_info_cnt;
>  }
>  
> +int bpf_program__clone(struct bpf_program *prog, const struct bpf_prog_load_opts *opts)
> +{
> +	LIBBPF_OPTS(bpf_prog_load_opts, attr);
> +	struct bpf_object *obj;
> +	int err, fd;
> +
> +	if (!prog)
> +		return libbpf_err(-EINVAL);
> +
> +	if (!OPTS_VALID(opts, bpf_prog_load_opts))
> +		return libbpf_err(-EINVAL);
> +
> +	obj = prog->obj;
> +	if (obj->state < OBJ_PREPARED)
> +		return libbpf_err(-EINVAL);
> +
> +	/*
> +	 * Caller-provided opts take priority; fall back to
> +	 * prog/object defaults when the caller leaves them zero.
> +	 */
> +	attr.attach_prog_fd = OPTS_GET(opts, attach_prog_fd, 0) ?: prog->attach_prog_fd;
> +	attr.prog_flags = OPTS_GET(opts, prog_flags, 0) ?: prog->prog_flags;
> +	attr.prog_ifindex = OPTS_GET(opts, prog_ifindex, 0) ?: prog->prog_ifindex;
> +	attr.kern_version = OPTS_GET(opts, kern_version, 0) ?: obj->kern_version;
> +	attr.fd_array = OPTS_GET(opts, fd_array, NULL) ?: obj->fd_array;
> +	attr.fd_array_cnt = OPTS_GET(opts, fd_array_cnt, 0) ?: obj->fd_array_cnt;
> +	attr.token_fd = OPTS_GET(opts, token_fd, 0) ?: obj->token_fd;
> +	if (attr.token_fd)
> +		attr.prog_flags |= BPF_F_TOKEN_FD;
> +
> +	/* BTF func/line info */
> +	if (obj->btf && btf__fd(obj->btf) >= 0) {
> +		attr.prog_btf_fd = OPTS_GET(opts, prog_btf_fd, 0) ?: btf__fd(obj->btf);
> +		attr.func_info = OPTS_GET(opts, func_info, NULL) ?: prog->func_info;
> +		attr.func_info_cnt = OPTS_GET(opts, func_info_cnt, 0) ?: prog->func_info_cnt;
> +		attr.func_info_rec_size =
> +			OPTS_GET(opts, func_info_rec_size, 0) ?: prog->func_info_rec_size;
> +		attr.line_info = OPTS_GET(opts, line_info, NULL) ?: prog->line_info;
> +		attr.line_info_cnt = OPTS_GET(opts, line_info_cnt, 0) ?: prog->line_info_cnt;
> +		attr.line_info_rec_size =
> +			OPTS_GET(opts, line_info_rec_size, 0) ?: prog->line_info_rec_size;
> +	}
> +
> +	attr.log_buf = OPTS_GET(opts, log_buf, NULL);
> +	attr.log_size = OPTS_GET(opts, log_size, 0);
> +	attr.log_level = OPTS_GET(opts, log_level, 0);
> +
> +	/*
> +	 * Fields below may be mutated by prog_prepare_load_fn:
> +	 * Seed them from prog/obj defaults here;
> +	 * Later override with caller-provided opts.
> +	 */
> +	attr.expected_attach_type = prog->expected_attach_type;
> +	attr.attach_btf_id = prog->attach_btf_id;
> +	attr.attach_btf_obj_fd = prog->attach_btf_obj_fd;
> +
> +	if (prog->sec_def && prog->sec_def->prog_prepare_load_fn) {
> +		err = prog->sec_def->prog_prepare_load_fn(prog, &attr, prog->sec_def->cookie);
> +		if (err)
> +			return libbpf_err(err);
> +	}
> +
> +	/* Re-apply caller overrides for output fields */
> +	if (OPTS_GET(opts, expected_attach_type, 0))
> +		attr.expected_attach_type =
> +			OPTS_GET(opts, expected_attach_type, 0);
> +	if (OPTS_GET(opts, attach_btf_id, 0))
> +		attr.attach_btf_id = OPTS_GET(opts, attach_btf_id, 0);
> +	if (OPTS_GET(opts, attach_btf_obj_fd, 0))
> +		attr.attach_btf_obj_fd =
> +			OPTS_GET(opts, attach_btf_obj_fd, 0);
> +
> +	fd = bpf_prog_load(prog->type, prog->name, obj->license, prog->insns, prog->insns_cnt,
> +			   &attr);
> +
> +	return libbpf_err(fd);
> +}
> +
>  #define SEC_DEF(sec_pfx, ptype, atype, flags, ...) {			    \
>  	.sec = (char *)sec_pfx,						    \
>  	.prog_type = BPF_PROG_TYPE_##ptype,				    \
> diff --git a/tools/lib/bpf/libbpf.h b/tools/lib/bpf/libbpf.h
> index dfc37a615578..0be34852350f 100644
> --- a/tools/lib/bpf/libbpf.h
> +++ b/tools/lib/bpf/libbpf.h
> @@ -2021,6 +2021,23 @@ LIBBPF_API int libbpf_register_prog_handler(const char *sec,
>   */
>  LIBBPF_API int libbpf_unregister_prog_handler(int handler_id);
>  
> +/**
> + * @brief **bpf_program__clone()** loads a single BPF program from a prepared
> + * BPF object into the kernel, returning its file descriptor.
> + *
> + * The BPF object must have been previously prepared with
> + * **bpf_object__prepare()**. If @opts is provided, any non-zero field
> + * overrides the defaults derived from the program/object internals.
> + * If @opts is NULL, all fields are populated automatically.
> + *
> + * The returned FD is owned by the caller and must be closed with close().
> + *
> + * @param prog BPF program from a prepared object
> + * @param opts Optional load options; non-zero fields override defaults
> + * @return program FD (>= 0) on success; negative error code on failure
> + */
> +LIBBPF_API int bpf_program__clone(struct bpf_program *prog, const struct bpf_prog_load_opts *opts);
> +
>  #ifdef __cplusplus
>  } /* extern "C" */
>  #endif
> diff --git a/tools/lib/bpf/libbpf.map b/tools/lib/bpf/libbpf.map
> index d18fbcea7578..e727a54e373a 100644
> --- a/tools/lib/bpf/libbpf.map
> +++ b/tools/lib/bpf/libbpf.map
> @@ -452,6 +452,7 @@ LIBBPF_1.7.0 {
>  		bpf_map__set_exclusive_program;
>  		bpf_map__exclusive_program;
>  		bpf_prog_assoc_struct_ops;
> +		bpf_program__clone;
>  		bpf_program__assoc_struct_ops;
>  		btf__permute;
>  } LIBBPF_1.6.0;


  reply	other threads:[~2026-03-17 19:40 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-03-17 17:39 [PATCH bpf-next v4 0/3] libbpf: Add bpf_program__clone() for individual program loading Mykyta Yatsenko
2026-03-17 17:39 ` [PATCH bpf-next v4 1/3] libbpf: Introduce bpf_program__clone() Mykyta Yatsenko
2026-03-17 19:40   ` Emil Tsalapatis [this message]
2026-03-17 17:39 ` [PATCH bpf-next v4 2/3] selftests/bpf: Use bpf_program__clone() in veristat Mykyta Yatsenko
2026-03-17 17:39 ` [PATCH bpf-next v4 3/3] selftests/bpf: Test bpf_program__clone() attach_btf_id override Mykyta Yatsenko
2026-03-17 19:50   ` Emil Tsalapatis
2026-03-21 20:20 ` [PATCH bpf-next v4 0/3] libbpf: Add bpf_program__clone() for individual program loading patchwork-bot+netdevbpf

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=DH5B9WYNX00J.8R01FVFXM4YR@etsalapatis.com \
    --to=emil@etsalapatis.com \
    --cc=andrii@kernel.org \
    --cc=ast@kernel.org \
    --cc=bpf@vger.kernel.org \
    --cc=daniel@iogearbox.net \
    --cc=eddyz87@gmail.com \
    --cc=kafai@meta.com \
    --cc=kernel-team@meta.com \
    --cc=mykyta.yatsenko5@gmail.com \
    --cc=yatsenko@meta.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.