Skip to content

Commit

Permalink
libbpf: Find correct module BTFs for struct_ops maps and progs.
Browse files Browse the repository at this point in the history
Locate the module BTFs for struct_ops maps and progs and pass them to the
kernel. This ensures that the kernel correctly resolves type IDs from the
appropriate module BTFs.

For the map of a struct_ops object, mod_btf is added to bpf_map to keep a
reference to the module BTF. The FD of the module BTF is passed to the
kernel as mod_btf_fd when the struct_ops object is loaded.

For a bpf_struct_ops prog, attach_btf_obj_fd of bpf_prog is the FD of a
module BTF in the kernel.

Signed-off-by: Kui-Feng Lee <[email protected]>
  • Loading branch information
ThinkerYzu1 authored and d-e-s-o committed Oct 16, 2023
1 parent 34719c7 commit b937492
Show file tree
Hide file tree
Showing 3 changed files with 51 additions and 26 deletions.
4 changes: 3 additions & 1 deletion tools/lib/bpf/bpf.c
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,8 @@ int bpf_map_create(enum bpf_map_type map_type,
__u32 max_entries,
const struct bpf_map_create_opts *opts)
{
const size_t attr_sz = offsetofend(union bpf_attr, map_extra);
const size_t attr_sz = offsetofend(union bpf_attr,
value_type_btf_obj_fd);
union bpf_attr attr;
int fd;

Expand All @@ -191,6 +192,7 @@ int bpf_map_create(enum bpf_map_type map_type,
attr.btf_key_type_id = OPTS_GET(opts, btf_key_type_id, 0);
attr.btf_value_type_id = OPTS_GET(opts, btf_value_type_id, 0);
attr.btf_vmlinux_value_type_id = OPTS_GET(opts, btf_vmlinux_value_type_id, 0);
attr.value_type_btf_obj_fd = OPTS_GET(opts, value_type_btf_obj_fd, 0);

attr.inner_map_fd = OPTS_GET(opts, inner_map_fd, 0);
attr.map_flags = OPTS_GET(opts, map_flags, 0);
Expand Down
5 changes: 4 additions & 1 deletion tools/lib/bpf/bpf.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,11 @@ struct bpf_map_create_opts {

__u32 numa_node;
__u32 map_ifindex;

__u32 value_type_btf_obj_fd;
size_t:0;
};
#define bpf_map_create_opts__last_field map_ifindex
#define bpf_map_create_opts__last_field value_type_btf_obj_fd

LIBBPF_API int bpf_map_create(enum bpf_map_type map_type,
const char *map_name,
Expand Down
68 changes: 44 additions & 24 deletions tools/lib/bpf/libbpf.c
Original file line number Diff line number Diff line change
Expand Up @@ -524,6 +524,7 @@ struct bpf_map {
struct bpf_map_def def;
__u32 numa_node;
__u32 btf_var_idx;
int mod_btf_fd;
__u32 btf_key_type_id;
__u32 btf_value_type_id;
__u32 btf_vmlinux_value_type_id;
Expand Down Expand Up @@ -898,6 +899,8 @@ bpf_object__add_programs(struct bpf_object *obj, Elf_Data *sec_data,
return 0;
}

static int load_module_btfs(struct bpf_object *obj);

static const struct btf_member *
find_member_by_offset(const struct btf_type *t, __u32 bit_offset)
{
Expand Down Expand Up @@ -927,22 +930,29 @@ find_member_by_name(const struct btf *btf, const struct btf_type *t,
return NULL;
}

static int find_module_btf_id(struct bpf_object *obj, const char *kern_name,
__u16 kind, struct btf **res_btf,
struct module_btf **res_mod_btf);

#define STRUCT_OPS_VALUE_PREFIX "bpf_struct_ops_"
static int find_btf_by_prefix_kind(const struct btf *btf, const char *prefix,
const char *name, __u32 kind);

static int
find_struct_ops_kern_types(const struct btf *btf, const char *tname,
find_struct_ops_kern_types(struct bpf_object *obj, const char *tname,
struct module_btf **mod_btf,
const struct btf_type **type, __u32 *type_id,
const struct btf_type **vtype, __u32 *vtype_id,
const struct btf_member **data_member)
{
const struct btf_type *kern_type, *kern_vtype;
const struct btf_member *kern_data_member;
struct btf *btf;
__s32 kern_vtype_id, kern_type_id;
__u32 i;

kern_type_id = btf__find_by_name_kind(btf, tname, BTF_KIND_STRUCT);
kern_type_id = find_module_btf_id(obj, tname, BTF_KIND_STRUCT,
&btf, mod_btf);
if (kern_type_id < 0) {
pr_warn("struct_ops init_kern: struct %s is not found in kernel BTF\n",
tname);
Expand Down Expand Up @@ -996,31 +1006,36 @@ static bool bpf_map__is_struct_ops(const struct bpf_map *map)
}

/* Init the map's fields that depend on kern_btf */
static int bpf_map__init_kern_struct_ops(struct bpf_map *map,
const struct btf *btf,
const struct btf *kern_btf)
static int bpf_map__init_kern_struct_ops(struct bpf_map *map)
{
const struct btf_member *member, *kern_member, *kern_data_member;
const struct btf_type *type, *kern_type, *kern_vtype;
__u32 i, kern_type_id, kern_vtype_id, kern_data_off;
struct bpf_object *obj = map->obj;
const struct btf *btf = obj->btf;
struct bpf_struct_ops *st_ops;
const struct btf *kern_btf;
struct module_btf *mod_btf;
void *data, *kern_data;
const char *tname;
int err;

st_ops = map->st_ops;
type = st_ops->type;
tname = st_ops->tname;
err = find_struct_ops_kern_types(kern_btf, tname,
err = find_struct_ops_kern_types(obj, tname, &mod_btf,
&kern_type, &kern_type_id,
&kern_vtype, &kern_vtype_id,
&kern_data_member);
if (err)
return err;

kern_btf = mod_btf ? mod_btf->btf : obj->btf_vmlinux;

pr_debug("struct_ops init_kern %s: type_id:%u kern_type_id:%u kern_vtype_id:%u\n",
map->name, st_ops->type_id, kern_type_id, kern_vtype_id);

map->mod_btf_fd = mod_btf ? mod_btf->fd : 0;
map->def.value_size = kern_vtype->size;
map->btf_vmlinux_value_type_id = kern_vtype_id;

Expand Down Expand Up @@ -1096,6 +1111,8 @@ static int bpf_map__init_kern_struct_ops(struct bpf_map *map,
return -ENOTSUP;
}

if (mod_btf)
prog->attach_btf_obj_fd = mod_btf->fd;
prog->attach_btf_id = kern_type_id;
prog->expected_attach_type = kern_member_idx;

Expand Down Expand Up @@ -1138,8 +1155,7 @@ static int bpf_object__init_kern_struct_ops_maps(struct bpf_object *obj)
if (!bpf_map__is_struct_ops(map))
continue;

err = bpf_map__init_kern_struct_ops(map, obj->btf,
obj->btf_vmlinux);
err = bpf_map__init_kern_struct_ops(map);
if (err)
return err;
}
Expand Down Expand Up @@ -5198,8 +5214,10 @@ static int bpf_object__create_map(struct bpf_object *obj, struct bpf_map *map, b
create_attr.numa_node = map->numa_node;
create_attr.map_extra = map->map_extra;

if (bpf_map__is_struct_ops(map))
if (bpf_map__is_struct_ops(map)) {
create_attr.btf_vmlinux_value_type_id = map->btf_vmlinux_value_type_id;
create_attr.value_type_btf_obj_fd = map->mod_btf_fd;
}

if (obj->btf && btf__fd(obj->btf) >= 0) {
create_attr.btf_fd = btf__fd(obj->btf);
Expand Down Expand Up @@ -7705,17 +7723,17 @@ static int bpf_object__read_kallsyms_file(struct bpf_object *obj)
return libbpf_kallsyms_parse(kallsyms_cb, obj);
}

static int find_ksym_btf_id(struct bpf_object *obj, const char *ksym_name,
__u16 kind, struct btf **res_btf,
struct module_btf **res_mod_btf)
static int find_module_btf_id(struct bpf_object *obj, const char *kern_name,
__u16 kind, struct btf **res_btf,
struct module_btf **res_mod_btf)
{
struct module_btf *mod_btf;
struct btf *btf;
int i, id, err;

btf = obj->btf_vmlinux;
mod_btf = NULL;
id = btf__find_by_name_kind(btf, ksym_name, kind);
id = btf__find_by_name_kind(btf, kern_name, kind);

if (id == -ENOENT) {
err = load_module_btfs(obj);
Expand All @@ -7726,7 +7744,7 @@ static int find_ksym_btf_id(struct bpf_object *obj, const char *ksym_name,
/* we assume module_btf's BTF FD is always >0 */
mod_btf = &obj->btf_modules[i];
btf = mod_btf->btf;
id = btf__find_by_name_kind_own(btf, ksym_name, kind);
id = btf__find_by_name_kind_own(btf, kern_name, kind);
if (id != -ENOENT)
break;
}
Expand All @@ -7749,7 +7767,7 @@ static int bpf_object__resolve_ksym_var_btf_id(struct bpf_object *obj,
struct btf *btf = NULL;
int id, err;

id = find_ksym_btf_id(obj, ext->name, BTF_KIND_VAR, &btf, &mod_btf);
id = find_module_btf_id(obj, ext->name, BTF_KIND_VAR, &btf, &mod_btf);
if (id < 0) {
if (id == -ESRCH && ext->is_weak)
return 0;
Expand Down Expand Up @@ -7803,8 +7821,8 @@ static int bpf_object__resolve_ksym_func_btf_id(struct bpf_object *obj,

local_func_proto_id = ext->ksym.type_id;

kfunc_id = find_ksym_btf_id(obj, ext->essent_name ?: ext->name, BTF_KIND_FUNC, &kern_btf,
&mod_btf);
kfunc_id = find_module_btf_id(obj, ext->essent_name ?: ext->name, BTF_KIND_FUNC, &kern_btf,
&mod_btf);
if (kfunc_id < 0) {
if (kfunc_id == -ESRCH && ext->is_weak)
return 0;
Expand Down Expand Up @@ -9474,9 +9492,9 @@ static int libbpf_find_prog_btf_id(const char *name, __u32 attach_prog_fd)
return err;
}

static int find_kernel_btf_id(struct bpf_object *obj, const char *attach_name,
enum bpf_attach_type attach_type,
int *btf_obj_fd, int *btf_type_id)
static int find_kernel_attach_btf_id(struct bpf_object *obj, const char *attach_name,
enum bpf_attach_type attach_type,
int *btf_obj_fd, int *btf_type_id)
{
int ret, i;

Expand Down Expand Up @@ -9541,7 +9559,9 @@ static int libbpf_find_attach_btf_id(struct bpf_program *prog, const char *attac
*btf_obj_fd = 0;
*btf_type_id = 1;
} else {
err = find_kernel_btf_id(prog->obj, attach_name, attach_type, btf_obj_fd, btf_type_id);
err = find_kernel_attach_btf_id(prog->obj, attach_name,
attach_type, btf_obj_fd,
btf_type_id);
}
if (err) {
pr_warn("prog '%s': failed to find kernel BTF type ID of '%s': %d\n",
Expand Down Expand Up @@ -12965,9 +12985,9 @@ int bpf_program__set_attach_target(struct bpf_program *prog,
err = bpf_object__load_vmlinux_btf(prog->obj, true);
if (err)
return libbpf_err(err);
err = find_kernel_btf_id(prog->obj, attach_func_name,
prog->expected_attach_type,
&btf_obj_fd, &btf_id);
err = find_kernel_attach_btf_id(prog->obj, attach_func_name,
prog->expected_attach_type,
&btf_obj_fd, &btf_id);
if (err)
return libbpf_err(err);
}
Expand Down

0 comments on commit b937492

Please sign in to comment.