]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
libbpf: Introduce bpf_program__clone()
authorMykyta Yatsenko <yatsenko@meta.com>
Tue, 17 Mar 2026 17:39:21 +0000 (10:39 -0700)
committerAlexei Starovoitov <ast@kernel.org>
Sat, 21 Mar 2026 20:17:13 +0000 (13:17 -0700)
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>
Link: https://lore.kernel.org/r/20260317-veristat_prepare-v4-1-74193d4cc9d9@meta.com
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
tools/lib/bpf/libbpf.c
tools/lib/bpf/libbpf.h
tools/lib/bpf/libbpf.map

index 0662d72bad207f97a023c4a08c653d488b3b1a8c..1eaa7527d4dabb6e558b49c5f566b8f71e163669 100644 (file)
@@ -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,                                 \
index dfc37a6155786f325935aaac1508eed679151f0d..0be34852350ffe512dee22f7328b215bbfe3a553 100644 (file)
@@ -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
index 3526c937bdbe695cf85f5845bdbe35c74d30bb2f..5828040f178a8959b1ef4901db3f357dcc1b6731 100644 (file)
@@ -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;