libbpf: Find correct module BTFs for struct_ops maps and progs.
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, the FD of the module BTF is set to bpf_map to keep a reference to the module BTF. The FD is passed to the kernel as value_type_btf_obj_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 <thinker.li@gmail.com> Acked-by: Andrii Nakryiko <andrii@kernel.org> Link: https://lore.kernel.org/r/20240119225005.668602-13-thinker.li@gmail.com Signed-off-by: Martin KaFai Lau <martin.lau@kernel.org>
This commit is contained in:
parent
f6be98d199
commit
9e926acda0
4 changed files with 38 additions and 12 deletions
|
@ -169,7 +169,8 @@ int bpf_map_create(enum bpf_map_type map_type,
|
||||||
__u32 max_entries,
|
__u32 max_entries,
|
||||||
const struct bpf_map_create_opts *opts)
|
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;
|
union bpf_attr attr;
|
||||||
int fd;
|
int fd;
|
||||||
|
|
||||||
|
@ -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_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_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.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, -1);
|
||||||
|
|
||||||
attr.inner_map_fd = OPTS_GET(opts, inner_map_fd, 0);
|
attr.inner_map_fd = OPTS_GET(opts, inner_map_fd, 0);
|
||||||
attr.map_flags = OPTS_GET(opts, map_flags, 0);
|
attr.map_flags = OPTS_GET(opts, map_flags, 0);
|
||||||
|
|
|
@ -51,8 +51,10 @@ struct bpf_map_create_opts {
|
||||||
|
|
||||||
__u32 numa_node;
|
__u32 numa_node;
|
||||||
__u32 map_ifindex;
|
__u32 map_ifindex;
|
||||||
|
__s32 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,
|
LIBBPF_API int bpf_map_create(enum bpf_map_type map_type,
|
||||||
const char *map_name,
|
const char *map_name,
|
||||||
|
|
|
@ -528,6 +528,7 @@ struct bpf_map {
|
||||||
struct bpf_map_def def;
|
struct bpf_map_def def;
|
||||||
__u32 numa_node;
|
__u32 numa_node;
|
||||||
__u32 btf_var_idx;
|
__u32 btf_var_idx;
|
||||||
|
int mod_btf_fd;
|
||||||
__u32 btf_key_type_id;
|
__u32 btf_key_type_id;
|
||||||
__u32 btf_value_type_id;
|
__u32 btf_value_type_id;
|
||||||
__u32 btf_vmlinux_value_type_id;
|
__u32 btf_vmlinux_value_type_id;
|
||||||
|
@ -931,22 +932,29 @@ find_member_by_name(const struct btf *btf, const struct btf_type *t,
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
#define STRUCT_OPS_VALUE_PREFIX "bpf_struct_ops_"
|
#define STRUCT_OPS_VALUE_PREFIX "bpf_struct_ops_"
|
||||||
static int find_btf_by_prefix_kind(const struct btf *btf, const char *prefix,
|
static int find_btf_by_prefix_kind(const struct btf *btf, const char *prefix,
|
||||||
const char *name, __u32 kind);
|
const char *name, __u32 kind);
|
||||||
|
|
||||||
static int
|
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 **type, __u32 *type_id,
|
||||||
const struct btf_type **vtype, __u32 *vtype_id,
|
const struct btf_type **vtype, __u32 *vtype_id,
|
||||||
const struct btf_member **data_member)
|
const struct btf_member **data_member)
|
||||||
{
|
{
|
||||||
const struct btf_type *kern_type, *kern_vtype;
|
const struct btf_type *kern_type, *kern_vtype;
|
||||||
const struct btf_member *kern_data_member;
|
const struct btf_member *kern_data_member;
|
||||||
|
struct btf *btf;
|
||||||
__s32 kern_vtype_id, kern_type_id;
|
__s32 kern_vtype_id, kern_type_id;
|
||||||
__u32 i;
|
__u32 i;
|
||||||
|
|
||||||
kern_type_id = btf__find_by_name_kind(btf, tname, BTF_KIND_STRUCT);
|
kern_type_id = find_ksym_btf_id(obj, tname, BTF_KIND_STRUCT,
|
||||||
|
&btf, mod_btf);
|
||||||
if (kern_type_id < 0) {
|
if (kern_type_id < 0) {
|
||||||
pr_warn("struct_ops init_kern: struct %s is not found in kernel BTF\n",
|
pr_warn("struct_ops init_kern: struct %s is not found in kernel BTF\n",
|
||||||
tname);
|
tname);
|
||||||
|
@ -1000,14 +1008,16 @@ static bool bpf_map__is_struct_ops(const struct bpf_map *map)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Init the map's fields that depend on kern_btf */
|
/* Init the map's fields that depend on kern_btf */
|
||||||
static int bpf_map__init_kern_struct_ops(struct bpf_map *map,
|
static int bpf_map__init_kern_struct_ops(struct bpf_map *map)
|
||||||
const struct btf *btf,
|
|
||||||
const struct btf *kern_btf)
|
|
||||||
{
|
{
|
||||||
const struct btf_member *member, *kern_member, *kern_data_member;
|
const struct btf_member *member, *kern_member, *kern_data_member;
|
||||||
const struct btf_type *type, *kern_type, *kern_vtype;
|
const struct btf_type *type, *kern_type, *kern_vtype;
|
||||||
__u32 i, kern_type_id, kern_vtype_id, kern_data_off;
|
__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;
|
struct bpf_struct_ops *st_ops;
|
||||||
|
const struct btf *kern_btf;
|
||||||
|
struct module_btf *mod_btf;
|
||||||
void *data, *kern_data;
|
void *data, *kern_data;
|
||||||
const char *tname;
|
const char *tname;
|
||||||
int err;
|
int err;
|
||||||
|
@ -1015,16 +1025,19 @@ static int bpf_map__init_kern_struct_ops(struct bpf_map *map,
|
||||||
st_ops = map->st_ops;
|
st_ops = map->st_ops;
|
||||||
type = st_ops->type;
|
type = st_ops->type;
|
||||||
tname = st_ops->tname;
|
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_type, &kern_type_id,
|
||||||
&kern_vtype, &kern_vtype_id,
|
&kern_vtype, &kern_vtype_id,
|
||||||
&kern_data_member);
|
&kern_data_member);
|
||||||
if (err)
|
if (err)
|
||||||
return 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",
|
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->name, st_ops->type_id, kern_type_id, kern_vtype_id);
|
||||||
|
|
||||||
|
map->mod_btf_fd = mod_btf ? mod_btf->fd : -1;
|
||||||
map->def.value_size = kern_vtype->size;
|
map->def.value_size = kern_vtype->size;
|
||||||
map->btf_vmlinux_value_type_id = kern_vtype_id;
|
map->btf_vmlinux_value_type_id = kern_vtype_id;
|
||||||
|
|
||||||
|
@ -1100,6 +1113,8 @@ static int bpf_map__init_kern_struct_ops(struct bpf_map *map,
|
||||||
return -ENOTSUP;
|
return -ENOTSUP;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (mod_btf)
|
||||||
|
prog->attach_btf_obj_fd = mod_btf->fd;
|
||||||
prog->attach_btf_id = kern_type_id;
|
prog->attach_btf_id = kern_type_id;
|
||||||
prog->expected_attach_type = kern_member_idx;
|
prog->expected_attach_type = kern_member_idx;
|
||||||
|
|
||||||
|
@ -1142,8 +1157,7 @@ static int bpf_object__init_kern_struct_ops_maps(struct bpf_object *obj)
|
||||||
if (!bpf_map__is_struct_ops(map))
|
if (!bpf_map__is_struct_ops(map))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
err = bpf_map__init_kern_struct_ops(map, obj->btf,
|
err = bpf_map__init_kern_struct_ops(map);
|
||||||
obj->btf_vmlinux);
|
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
@ -5162,8 +5176,13 @@ static int bpf_object__create_map(struct bpf_object *obj, struct bpf_map *map, b
|
||||||
create_attr.numa_node = map->numa_node;
|
create_attr.numa_node = map->numa_node;
|
||||||
create_attr.map_extra = map->map_extra;
|
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.btf_vmlinux_value_type_id = map->btf_vmlinux_value_type_id;
|
||||||
|
if (map->mod_btf_fd >= 0) {
|
||||||
|
create_attr.value_type_btf_obj_fd = map->mod_btf_fd;
|
||||||
|
create_attr.map_flags |= BPF_F_VTYPE_BTF_OBJ_FD;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (obj->btf && btf__fd(obj->btf) >= 0) {
|
if (obj->btf && btf__fd(obj->btf) >= 0) {
|
||||||
create_attr.btf_fd = btf__fd(obj->btf);
|
create_attr.btf_fd = btf__fd(obj->btf);
|
||||||
|
@ -9970,7 +9989,9 @@ static int libbpf_find_attach_btf_id(struct bpf_program *prog, const char *attac
|
||||||
*btf_obj_fd = 0;
|
*btf_obj_fd = 0;
|
||||||
*btf_type_id = 1;
|
*btf_type_id = 1;
|
||||||
} else {
|
} else {
|
||||||
err = find_kernel_btf_id(prog->obj, attach_name, attach_type, btf_obj_fd, btf_type_id);
|
err = find_kernel_btf_id(prog->obj, attach_name,
|
||||||
|
attach_type, btf_obj_fd,
|
||||||
|
btf_type_id);
|
||||||
}
|
}
|
||||||
if (err) {
|
if (err) {
|
||||||
pr_warn("prog '%s': failed to find kernel BTF type ID of '%s': %d\n",
|
pr_warn("prog '%s': failed to find kernel BTF type ID of '%s': %d\n",
|
||||||
|
|
|
@ -326,6 +326,7 @@ static int probe_map_create(enum bpf_map_type map_type)
|
||||||
case BPF_MAP_TYPE_STRUCT_OPS:
|
case BPF_MAP_TYPE_STRUCT_OPS:
|
||||||
/* we'll get -ENOTSUPP for invalid BTF type ID for struct_ops */
|
/* we'll get -ENOTSUPP for invalid BTF type ID for struct_ops */
|
||||||
opts.btf_vmlinux_value_type_id = 1;
|
opts.btf_vmlinux_value_type_id = 1;
|
||||||
|
opts.value_type_btf_obj_fd = -1;
|
||||||
exp_err = -524; /* -ENOTSUPP */
|
exp_err = -524; /* -ENOTSUPP */
|
||||||
break;
|
break;
|
||||||
case BPF_MAP_TYPE_BLOOM_FILTER:
|
case BPF_MAP_TYPE_BLOOM_FILTER:
|
||||||
|
|
Loading…
Add table
Reference in a new issue