Merge branch 'libbpf: Streamline internal BPF program sections handling'

Andrii Nakryiko says:

====================

This small patch set performs internal refactorings around libbpf BPF program
ELF section definitions' handling. This is preparatory changes for further
changes around making libbpf BPF program section handling more strict but also
pluggable and customizable, as part of the libbpf 1.0 effort. See individual
patches for details.
====================

Signed-off-by: Alexei Starovoitov <ast@kernel.org>
This commit is contained in:
Alexei Starovoitov 2021-09-14 15:49:24 -07:00
commit 67dfac47da
2 changed files with 95 additions and 117 deletions

View file

@ -218,8 +218,7 @@ struct reloc_desc {
struct bpf_sec_def; struct bpf_sec_def;
typedef struct bpf_link *(*attach_fn_t)(const struct bpf_sec_def *sec, typedef struct bpf_link *(*attach_fn_t)(struct bpf_program *prog);
struct bpf_program *prog);
struct bpf_sec_def { struct bpf_sec_def {
const char *sec; const char *sec;
@ -6373,12 +6372,37 @@ bpf_object__load_progs(struct bpf_object *obj, int log_level)
static const struct bpf_sec_def *find_sec_def(const char *sec_name); static const struct bpf_sec_def *find_sec_def(const char *sec_name);
static int bpf_object_init_progs(struct bpf_object *obj, const struct bpf_object_open_opts *opts)
{
struct bpf_program *prog;
bpf_object__for_each_program(prog, obj) {
prog->sec_def = find_sec_def(prog->sec_name);
if (!prog->sec_def) {
/* couldn't guess, but user might manually specify */
pr_debug("prog '%s': unrecognized ELF section name '%s'\n",
prog->name, prog->sec_name);
continue;
}
if (prog->sec_def->is_sleepable)
prog->prog_flags |= BPF_F_SLEEPABLE;
bpf_program__set_type(prog, prog->sec_def->prog_type);
bpf_program__set_expected_attach_type(prog, prog->sec_def->expected_attach_type);
if (prog->sec_def->prog_type == BPF_PROG_TYPE_TRACING ||
prog->sec_def->prog_type == BPF_PROG_TYPE_EXT)
prog->attach_prog_fd = OPTS_GET(opts, attach_prog_fd, 0);
}
return 0;
}
static struct bpf_object * static struct bpf_object *
__bpf_object__open(const char *path, const void *obj_buf, size_t obj_buf_sz, __bpf_object__open(const char *path, const void *obj_buf, size_t obj_buf_sz,
const struct bpf_object_open_opts *opts) const struct bpf_object_open_opts *opts)
{ {
const char *obj_name, *kconfig, *btf_tmp_path; const char *obj_name, *kconfig, *btf_tmp_path;
struct bpf_program *prog;
struct bpf_object *obj; struct bpf_object *obj;
char tmp_name[64]; char tmp_name[64];
int err; int err;
@ -6436,31 +6460,13 @@ __bpf_object__open(const char *path, const void *obj_buf, size_t obj_buf_sz,
err = err ? : bpf_object__collect_externs(obj); err = err ? : bpf_object__collect_externs(obj);
err = err ? : bpf_object__finalize_btf(obj); err = err ? : bpf_object__finalize_btf(obj);
err = err ? : bpf_object__init_maps(obj, opts); err = err ? : bpf_object__init_maps(obj, opts);
err = err ? : bpf_object_init_progs(obj, opts);
err = err ? : bpf_object__collect_relos(obj); err = err ? : bpf_object__collect_relos(obj);
if (err) if (err)
goto out; goto out;
bpf_object__elf_finish(obj); bpf_object__elf_finish(obj);
bpf_object__for_each_program(prog, obj) {
prog->sec_def = find_sec_def(prog->sec_name);
if (!prog->sec_def) {
/* couldn't guess, but user might manually specify */
pr_debug("prog '%s': unrecognized ELF section name '%s'\n",
prog->name, prog->sec_name);
continue;
}
if (prog->sec_def->is_sleepable)
prog->prog_flags |= BPF_F_SLEEPABLE;
bpf_program__set_type(prog, prog->sec_def->prog_type);
bpf_program__set_expected_attach_type(prog,
prog->sec_def->expected_attach_type);
if (prog->sec_def->prog_type == BPF_PROG_TYPE_TRACING ||
prog->sec_def->prog_type == BPF_PROG_TYPE_EXT)
prog->attach_prog_fd = OPTS_GET(opts, attach_prog_fd, 0);
}
return obj; return obj;
out: out:
bpf_object__close(obj); bpf_object__close(obj);
@ -7913,18 +7919,12 @@ void bpf_program__set_expected_attach_type(struct bpf_program *prog,
__VA_ARGS__ \ __VA_ARGS__ \
} }
static struct bpf_link *attach_kprobe(const struct bpf_sec_def *sec, static struct bpf_link *attach_kprobe(struct bpf_program *prog);
struct bpf_program *prog); static struct bpf_link *attach_tp(struct bpf_program *prog);
static struct bpf_link *attach_tp(const struct bpf_sec_def *sec, static struct bpf_link *attach_raw_tp(struct bpf_program *prog);
struct bpf_program *prog); static struct bpf_link *attach_trace(struct bpf_program *prog);
static struct bpf_link *attach_raw_tp(const struct bpf_sec_def *sec, static struct bpf_link *attach_lsm(struct bpf_program *prog);
struct bpf_program *prog); static struct bpf_link *attach_iter(struct bpf_program *prog);
static struct bpf_link *attach_trace(const struct bpf_sec_def *sec,
struct bpf_program *prog);
static struct bpf_link *attach_lsm(const struct bpf_sec_def *sec,
struct bpf_program *prog);
static struct bpf_link *attach_iter(const struct bpf_sec_def *sec,
struct bpf_program *prog);
static const struct bpf_sec_def section_defs[] = { static const struct bpf_sec_def section_defs[] = {
BPF_PROG_SEC("socket", BPF_PROG_TYPE_SOCKET_FILTER), BPF_PROG_SEC("socket", BPF_PROG_TYPE_SOCKET_FILTER),
@ -8250,35 +8250,37 @@ static int bpf_object__collect_st_ops_relos(struct bpf_object *obj,
return -EINVAL; return -EINVAL;
} }
if (prog->type == BPF_PROG_TYPE_UNSPEC) { /* prevent the use of BPF prog with invalid type */
const struct bpf_sec_def *sec_def; if (prog->type != BPF_PROG_TYPE_STRUCT_OPS) {
pr_warn("struct_ops reloc %s: prog %s is not struct_ops BPF program\n",
map->name, prog->name);
return -EINVAL;
}
sec_def = find_sec_def(prog->sec_name); /* if we haven't yet processed this BPF program, record proper
if (sec_def && * attach_btf_id and member_idx
sec_def->prog_type != BPF_PROG_TYPE_STRUCT_OPS) { */
/* for pr_warn */ if (!prog->attach_btf_id) {
prog->type = sec_def->prog_type;
goto invalid_prog;
}
prog->type = BPF_PROG_TYPE_STRUCT_OPS;
prog->attach_btf_id = st_ops->type_id; prog->attach_btf_id = st_ops->type_id;
prog->expected_attach_type = member_idx; prog->expected_attach_type = member_idx;
} else if (prog->type != BPF_PROG_TYPE_STRUCT_OPS ||
prog->attach_btf_id != st_ops->type_id ||
prog->expected_attach_type != member_idx) {
goto invalid_prog;
} }
/* struct_ops BPF prog can be re-used between multiple
* .struct_ops as long as it's the same struct_ops struct
* definition and the same function pointer field
*/
if (prog->attach_btf_id != st_ops->type_id ||
prog->expected_attach_type != member_idx) {
pr_warn("struct_ops reloc %s: cannot use prog %s in sec %s with type %u attach_btf_id %u expected_attach_type %u for func ptr %s\n",
map->name, prog->name, prog->sec_name, prog->type,
prog->attach_btf_id, prog->expected_attach_type, name);
return -EINVAL;
}
st_ops->progs[member_idx] = prog; st_ops->progs[member_idx] = prog;
} }
return 0; return 0;
invalid_prog:
pr_warn("struct_ops reloc %s: cannot use prog %s in sec %s with type %u attach_btf_id %u expected_attach_type %u for func ptr %s\n",
map->name, prog->name, prog->sec_name, prog->type,
prog->attach_btf_id, prog->expected_attach_type, name);
return -EINVAL;
} }
#define BTF_TRACE_PREFIX "btf_trace_" #define BTF_TRACE_PREFIX "btf_trace_"
@ -8436,22 +8438,13 @@ static int libbpf_find_attach_btf_id(struct bpf_program *prog, int *btf_obj_fd,
__u32 attach_prog_fd = prog->attach_prog_fd; __u32 attach_prog_fd = prog->attach_prog_fd;
const char *name = prog->sec_name, *attach_name; const char *name = prog->sec_name, *attach_name;
const struct bpf_sec_def *sec = NULL; const struct bpf_sec_def *sec = NULL;
int i, err = 0; int err = 0;
if (!name) if (!name)
return -EINVAL; return -EINVAL;
for (i = 0; i < ARRAY_SIZE(section_defs); i++) { sec = find_sec_def(name);
if (!section_defs[i].is_attach_btf) if (!sec || !sec->is_attach_btf) {
continue;
if (strncmp(name, section_defs[i].sec, section_defs[i].len))
continue;
sec = &section_defs[i];
break;
}
if (!sec) {
pr_warn("failed to identify BTF ID based on ELF section name '%s'\n", name); pr_warn("failed to identify BTF ID based on ELF section name '%s'\n", name);
return -ESRCH; return -ESRCH;
} }
@ -8489,27 +8482,28 @@ int libbpf_attach_type_by_name(const char *name,
enum bpf_attach_type *attach_type) enum bpf_attach_type *attach_type)
{ {
char *type_names; char *type_names;
int i; const struct bpf_sec_def *sec_def;
if (!name) if (!name)
return libbpf_err(-EINVAL); return libbpf_err(-EINVAL);
for (i = 0; i < ARRAY_SIZE(section_defs); i++) { sec_def = find_sec_def(name);
if (strncmp(name, section_defs[i].sec, section_defs[i].len)) if (!sec_def) {
continue; pr_debug("failed to guess attach type based on ELF section name '%s'\n", name);
if (!section_defs[i].is_attachable) type_names = libbpf_get_type_names(true);
return libbpf_err(-EINVAL); if (type_names != NULL) {
*attach_type = section_defs[i].expected_attach_type; pr_debug("attachable section(type) names are:%s\n", type_names);
return 0; free(type_names);
} }
pr_debug("failed to guess attach type based on ELF section name '%s'\n", name);
type_names = libbpf_get_type_names(true); return libbpf_err(-EINVAL);
if (type_names != NULL) {
pr_debug("attachable section(type) names are:%s\n", type_names);
free(type_names);
} }
return libbpf_err(-EINVAL); if (!sec_def->is_attachable)
return libbpf_err(-EINVAL);
*attach_type = sec_def->expected_attach_type;
return 0;
} }
int bpf_map__fd(const struct bpf_map *map) int bpf_map__fd(const struct bpf_map *map)
@ -9382,8 +9376,7 @@ struct bpf_link *bpf_program__attach_kprobe(struct bpf_program *prog,
return bpf_program__attach_kprobe_opts(prog, func_name, &opts); return bpf_program__attach_kprobe_opts(prog, func_name, &opts);
} }
static struct bpf_link *attach_kprobe(const struct bpf_sec_def *sec, static struct bpf_link *attach_kprobe(struct bpf_program *prog)
struct bpf_program *prog)
{ {
DECLARE_LIBBPF_OPTS(bpf_kprobe_opts, opts); DECLARE_LIBBPF_OPTS(bpf_kprobe_opts, opts);
unsigned long offset = 0; unsigned long offset = 0;
@ -9392,8 +9385,8 @@ static struct bpf_link *attach_kprobe(const struct bpf_sec_def *sec,
char *func; char *func;
int n, err; int n, err;
func_name = prog->sec_name + sec->len; func_name = prog->sec_name + prog->sec_def->len;
opts.retprobe = strcmp(sec->sec, "kretprobe/") == 0; opts.retprobe = strcmp(prog->sec_def->sec, "kretprobe/") == 0;
n = sscanf(func_name, "%m[a-zA-Z0-9_.]+%li", &func, &offset); n = sscanf(func_name, "%m[a-zA-Z0-9_.]+%li", &func, &offset);
if (n < 1) { if (n < 1) {
@ -9556,8 +9549,7 @@ struct bpf_link *bpf_program__attach_tracepoint(struct bpf_program *prog,
return bpf_program__attach_tracepoint_opts(prog, tp_category, tp_name, NULL); return bpf_program__attach_tracepoint_opts(prog, tp_category, tp_name, NULL);
} }
static struct bpf_link *attach_tp(const struct bpf_sec_def *sec, static struct bpf_link *attach_tp(struct bpf_program *prog)
struct bpf_program *prog)
{ {
char *sec_name, *tp_cat, *tp_name; char *sec_name, *tp_cat, *tp_name;
struct bpf_link *link; struct bpf_link *link;
@ -9567,7 +9559,7 @@ static struct bpf_link *attach_tp(const struct bpf_sec_def *sec,
return libbpf_err_ptr(-ENOMEM); return libbpf_err_ptr(-ENOMEM);
/* extract "tp/<category>/<name>" */ /* extract "tp/<category>/<name>" */
tp_cat = sec_name + sec->len; tp_cat = sec_name + prog->sec_def->len;
tp_name = strchr(tp_cat, '/'); tp_name = strchr(tp_cat, '/');
if (!tp_name) { if (!tp_name) {
free(sec_name); free(sec_name);
@ -9611,10 +9603,9 @@ struct bpf_link *bpf_program__attach_raw_tracepoint(struct bpf_program *prog,
return link; return link;
} }
static struct bpf_link *attach_raw_tp(const struct bpf_sec_def *sec, static struct bpf_link *attach_raw_tp(struct bpf_program *prog)
struct bpf_program *prog)
{ {
const char *tp_name = prog->sec_name + sec->len; const char *tp_name = prog->sec_name + prog->sec_def->len;
return bpf_program__attach_raw_tracepoint(prog, tp_name); return bpf_program__attach_raw_tracepoint(prog, tp_name);
} }
@ -9659,14 +9650,12 @@ struct bpf_link *bpf_program__attach_lsm(struct bpf_program *prog)
return bpf_program__attach_btf_id(prog); return bpf_program__attach_btf_id(prog);
} }
static struct bpf_link *attach_trace(const struct bpf_sec_def *sec, static struct bpf_link *attach_trace(struct bpf_program *prog)
struct bpf_program *prog)
{ {
return bpf_program__attach_trace(prog); return bpf_program__attach_trace(prog);
} }
static struct bpf_link *attach_lsm(const struct bpf_sec_def *sec, static struct bpf_link *attach_lsm(struct bpf_program *prog)
struct bpf_program *prog)
{ {
return bpf_program__attach_lsm(prog); return bpf_program__attach_lsm(prog);
} }
@ -9797,21 +9786,17 @@ bpf_program__attach_iter(struct bpf_program *prog,
return link; return link;
} }
static struct bpf_link *attach_iter(const struct bpf_sec_def *sec, static struct bpf_link *attach_iter(struct bpf_program *prog)
struct bpf_program *prog)
{ {
return bpf_program__attach_iter(prog, NULL); return bpf_program__attach_iter(prog, NULL);
} }
struct bpf_link *bpf_program__attach(struct bpf_program *prog) struct bpf_link *bpf_program__attach(struct bpf_program *prog)
{ {
const struct bpf_sec_def *sec_def; if (!prog->sec_def || !prog->sec_def->attach_fn)
sec_def = find_sec_def(prog->sec_name);
if (!sec_def || !sec_def->attach_fn)
return libbpf_err_ptr(-ESRCH); return libbpf_err_ptr(-ESRCH);
return sec_def->attach_fn(sec_def, prog); return prog->sec_def->attach_fn(prog);
} }
static int bpf_link__detach_struct_ops(struct bpf_link *link) static int bpf_link__detach_struct_ops(struct bpf_link *link)
@ -10890,16 +10875,15 @@ int bpf_object__attach_skeleton(struct bpf_object_skeleton *s)
for (i = 0; i < s->prog_cnt; i++) { for (i = 0; i < s->prog_cnt; i++) {
struct bpf_program *prog = *s->progs[i].prog; struct bpf_program *prog = *s->progs[i].prog;
struct bpf_link **link = s->progs[i].link; struct bpf_link **link = s->progs[i].link;
const struct bpf_sec_def *sec_def;
if (!prog->load) if (!prog->load)
continue; continue;
sec_def = find_sec_def(prog->sec_name); /* auto-attaching not supported for this program */
if (!sec_def || !sec_def->attach_fn) if (!prog->sec_def || !prog->sec_def->attach_fn)
continue; continue;
*link = sec_def->attach_fn(sec_def, prog); *link = prog->sec_def->attach_fn(prog);
err = libbpf_get_error(*link); err = libbpf_get_error(*link);
if (err) { if (err) {
pr_warn("failed to auto-attach program '%s': %d\n", pr_warn("failed to auto-attach program '%s': %d\n",

View file

@ -169,11 +169,7 @@ static __always_inline void bictcp_hystart_reset(struct sock *sk)
ca->sample_cnt = 0; ca->sample_cnt = 0;
} }
/* "struct_ops/" prefix is not a requirement /* "struct_ops/" prefix is a requirement */
* It will be recognized as BPF_PROG_TYPE_STRUCT_OPS
* as long as it is used in one of the func ptr
* under SEC(".struct_ops").
*/
SEC("struct_ops/bpf_cubic_init") SEC("struct_ops/bpf_cubic_init")
void BPF_PROG(bpf_cubic_init, struct sock *sk) void BPF_PROG(bpf_cubic_init, struct sock *sk)
{ {
@ -188,10 +184,8 @@ void BPF_PROG(bpf_cubic_init, struct sock *sk)
tcp_sk(sk)->snd_ssthresh = initial_ssthresh; tcp_sk(sk)->snd_ssthresh = initial_ssthresh;
} }
/* No prefix in SEC will also work. /* "struct_ops" prefix is a requirement */
* The remaining tcp-cubic functions have an easier way. SEC("struct_ops/bpf_cubic_cwnd_event")
*/
SEC("no-sec-prefix-bictcp_cwnd_event")
void BPF_PROG(bpf_cubic_cwnd_event, struct sock *sk, enum tcp_ca_event event) void BPF_PROG(bpf_cubic_cwnd_event, struct sock *sk, enum tcp_ca_event event)
{ {
if (event == CA_EVENT_TX_START) { if (event == CA_EVENT_TX_START) {