Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 64 additions & 0 deletions tools/lib/bpf/libbpf.c
Original file line number Diff line number Diff line change
Expand Up @@ -9802,6 +9802,70 @@ __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_prog_load_opts *pattr = &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);

/* Copy caller opts, fall back to prog/object defaults */
OPTS_SET(pattr, expected_attach_type,
OPTS_GET(opts, expected_attach_type, 0) ?: prog->expected_attach_type);
OPTS_SET(pattr, attach_btf_id, OPTS_GET(opts, attach_btf_id, 0) ?: prog->attach_btf_id);
OPTS_SET(pattr, attach_btf_obj_fd,
OPTS_GET(opts, attach_btf_obj_fd, 0) ?: prog->attach_btf_obj_fd);
OPTS_SET(pattr, attach_prog_fd, OPTS_GET(opts, attach_prog_fd, 0) ?: prog->attach_prog_fd);
OPTS_SET(pattr, prog_flags, OPTS_GET(opts, prog_flags, 0) ?: prog->prog_flags);
OPTS_SET(pattr, prog_ifindex, OPTS_GET(opts, prog_ifindex, 0) ?: prog->prog_ifindex);
OPTS_SET(pattr, kern_version, OPTS_GET(opts, kern_version, 0) ?: obj->kern_version);
OPTS_SET(pattr, fd_array, OPTS_GET(opts, fd_array, NULL) ?: obj->fd_array);
OPTS_SET(pattr, 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) {
OPTS_SET(pattr, prog_btf_fd, OPTS_GET(opts, prog_btf_fd, 0) ?: btf__fd(obj->btf));
OPTS_SET(pattr, func_info, OPTS_GET(opts, func_info, NULL) ?: prog->func_info);
OPTS_SET(pattr, func_info_cnt,
OPTS_GET(opts, func_info_cnt, 0) ?: prog->func_info_cnt);
OPTS_SET(pattr, func_info_rec_size,
OPTS_GET(opts, func_info_rec_size, 0) ?: prog->func_info_rec_size);
OPTS_SET(pattr, line_info, OPTS_GET(opts, line_info, NULL) ?: prog->line_info);
OPTS_SET(pattr, line_info_cnt,
OPTS_GET(opts, line_info_cnt, 0) ?: prog->line_info_cnt);
OPTS_SET(pattr, line_info_rec_size,
OPTS_GET(opts, line_info_rec_size, 0) ?: prog->line_info_rec_size);
}

OPTS_SET(pattr, log_buf, OPTS_GET(opts, log_buf, NULL));
OPTS_SET(pattr, log_size, OPTS_GET(opts, log_size, 0));
OPTS_SET(pattr, log_level, OPTS_GET(opts, log_level, 0));

/* Resolve BTF attach targets, set sleepable/XDP flags, etc. */
if (prog->sec_def && prog->sec_def->prog_prepare_load_fn) {
err = prog->sec_def->prog_prepare_load_fn(prog, pattr, prog->sec_def->cookie);
if (err)
return libbpf_err(err);
}

fd = bpf_prog_load(prog->type, prog->name, obj->license, prog->insns, prog->insns_cnt,
pattr);

return libbpf_err(fd);
}

#define SEC_DEF(sec_pfx, ptype, atype, flags, ...) { \
.sec = (char *)sec_pfx, \
.prog_type = BPF_PROG_TYPE_##ptype, \
Expand Down
17 changes: 17 additions & 0 deletions tools/lib/bpf/libbpf.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions tools/lib/bpf/libbpf.map
Original file line number Diff line number Diff line change
Expand Up @@ -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;
104 changes: 44 additions & 60 deletions tools/testing/selftests/bpf/veristat.c
Original file line number Diff line number Diff line change
Expand Up @@ -1236,7 +1236,7 @@ static void mask_unrelated_struct_ops_progs(struct bpf_object *obj,
}
}

static void fixup_obj(struct bpf_object *obj, struct bpf_program *prog, const char *filename)
static void fixup_obj_maps(struct bpf_object *obj)
{
struct bpf_map *map;

Expand All @@ -1251,15 +1251,23 @@ static void fixup_obj(struct bpf_object *obj, struct bpf_program *prog, const ch
case BPF_MAP_TYPE_INODE_STORAGE:
case BPF_MAP_TYPE_CGROUP_STORAGE:
case BPF_MAP_TYPE_CGRP_STORAGE:
break;
case BPF_MAP_TYPE_STRUCT_OPS:
mask_unrelated_struct_ops_progs(obj, map, prog);
break;
default:
if (bpf_map__max_entries(map) == 0)
bpf_map__set_max_entries(map, 1);
}
}
}

static void fixup_obj(struct bpf_object *obj, struct bpf_program *prog, const char *filename)
{
struct bpf_map *map;

bpf_object__for_each_map(map, obj) {
if (bpf_map__type(map) == BPF_MAP_TYPE_STRUCT_OPS)
mask_unrelated_struct_ops_progs(obj, map, prog);
}

/* SEC(freplace) programs can't be loaded with veristat as is,
* but we can try guessing their target program's expected type by
Expand Down Expand Up @@ -1608,6 +1616,7 @@ static int process_prog(const char *filename, struct bpf_object *obj, struct bpf
const char *base_filename = basename(strdupa(filename));
const char *prog_name = bpf_program__name(prog);
long mem_peak_a, mem_peak_b, mem_peak = -1;
LIBBPF_OPTS(bpf_prog_load_opts, opts);
char *buf;
int buf_sz, log_level;
struct verif_stats *stats;
Expand Down Expand Up @@ -1647,9 +1656,6 @@ static int process_prog(const char *filename, struct bpf_object *obj, struct bpf
}
verif_log_buf[0] = '\0';

bpf_program__set_log_buf(prog, buf, buf_sz);
bpf_program__set_log_level(prog, log_level);

/* increase chances of successful BPF object loading */
fixup_obj(obj, prog, base_filename);

Expand All @@ -1658,15 +1664,21 @@ static int process_prog(const char *filename, struct bpf_object *obj, struct bpf
if (env.force_reg_invariants)
bpf_program__set_flags(prog, bpf_program__flags(prog) | BPF_F_TEST_REG_INVARIANTS);

err = bpf_object__prepare(obj);
if (!err) {
cgroup_err = reset_stat_cgroup();
mem_peak_a = cgroup_memory_peak();
err = bpf_object__load(obj);
mem_peak_b = cgroup_memory_peak();
if (!cgroup_err && mem_peak_a >= 0 && mem_peak_b >= 0)
mem_peak = mem_peak_b - mem_peak_a;
opts.log_buf = buf;
opts.log_size = buf_sz;
opts.log_level = log_level;

cgroup_err = reset_stat_cgroup();
mem_peak_a = cgroup_memory_peak();
fd = bpf_program__clone(prog, &opts);
if (fd < 0) {
err = fd;
fprintf(stderr, "Failed to load program %s %d\n", prog_name, err);
}
mem_peak_b = cgroup_memory_peak();
if (!cgroup_err && mem_peak_a >= 0 && mem_peak_b >= 0)
mem_peak = mem_peak_b - mem_peak_a;

env.progs_processed++;

stats->file_name = strdup(base_filename);
Expand All @@ -1678,7 +1690,6 @@ static int process_prog(const char *filename, struct bpf_object *obj, struct bpf
stats->stats[MEMORY_PEAK] = mem_peak < 0 ? -1 : mem_peak / (1024 * 1024);

memset(&info, 0, info_len);
fd = bpf_program__fd(prog);
if (fd > 0 && bpf_prog_get_info_by_fd(fd, &info, &info_len) == 0) {
stats->stats[JITED_SIZE] = info.jited_prog_len;
if (env.dump_mode & DUMP_JITED)
Expand All @@ -1699,7 +1710,8 @@ static int process_prog(const char *filename, struct bpf_object *obj, struct bpf

if (verif_log_buf != buf)
free(buf);

if (fd > 0)
close(fd);
return 0;
}

Expand Down Expand Up @@ -2182,8 +2194,8 @@ static int set_global_vars(struct bpf_object *obj, struct var_preset *presets, i
static int process_obj(const char *filename)
{
const char *base_filename = basename(strdupa(filename));
struct bpf_object *obj = NULL, *tobj;
struct bpf_program *prog, *tprog, *lprog;
struct bpf_object *obj = NULL;
struct bpf_program *prog;
libbpf_print_fn_t old_libbpf_print_fn;
LIBBPF_OPTS(bpf_object_open_opts, opts);
int err = 0, prog_cnt = 0;
Expand Down Expand Up @@ -2222,51 +2234,26 @@ static int process_obj(const char *filename)
env.files_processed++;

bpf_object__for_each_program(prog, obj) {
bpf_program__set_autoload(prog, true);
prog_cnt++;
}

if (prog_cnt == 1) {
prog = bpf_object__next_program(obj, NULL);
bpf_program__set_autoload(prog, true);
err = set_global_vars(obj, env.presets, env.npresets);
if (err) {
fprintf(stderr, "Failed to set global variables %d\n", err);
goto cleanup;
}
process_prog(filename, obj, prog);
fixup_obj_maps(obj);

err = set_global_vars(obj, env.presets, env.npresets);
if (err) {
fprintf(stderr, "Failed to set global variables %d\n", err);
goto cleanup;
}

bpf_object__for_each_program(prog, obj) {
const char *prog_name = bpf_program__name(prog);

tobj = bpf_object__open_file(filename, &opts);
if (!tobj) {
err = -errno;
fprintf(stderr, "Failed to open '%s': %d\n", filename, err);
goto cleanup;
}

err = set_global_vars(tobj, env.presets, env.npresets);
if (err) {
fprintf(stderr, "Failed to set global variables %d\n", err);
goto cleanup;
}

lprog = NULL;
bpf_object__for_each_program(tprog, tobj) {
const char *tprog_name = bpf_program__name(tprog);

if (strcmp(prog_name, tprog_name) == 0) {
bpf_program__set_autoload(tprog, true);
lprog = tprog;
} else {
bpf_program__set_autoload(tprog, false);
}
}
err = bpf_object__prepare(obj);
if (err) {
fprintf(stderr, "Failed to prepare BPF object for loading %d\n", err);
goto cleanup;
}

process_prog(filename, tobj, lprog);
bpf_object__close(tobj);
bpf_object__for_each_program(prog, obj) {
process_prog(filename, obj, prog);
}

cleanup:
Expand Down Expand Up @@ -3264,17 +3251,14 @@ static int handle_verif_mode(void)
create_stat_cgroup();
for (i = 0; i < env.filename_cnt; i++) {
err = process_obj(env.filenames[i]);
if (err) {
if (err)
fprintf(stderr, "Failed to process '%s': %d\n", env.filenames[i], err);
goto out;
}
}

qsort(env.prog_stats, env.prog_stat_cnt, sizeof(*env.prog_stats), cmp_prog_stats);

output_prog_stats();

out:
destroy_stat_cgroup();
return err;
}
Expand Down
Loading