diff mbox series

[RFC,bpf-next,v3,09/11] libbpf: Find correct module BTFs for struct_ops maps and progs.

Message ID 20230920155923.151136-10-thinker.li@gmail.com (mailing list archive)
State RFC
Delegated to: BPF
Headers show
Series Registrating struct_ops types from modules | expand

Checks

Context Check Description
bpf/vmtest-bpf-next-PR pending PR summary
bpf/vmtest-bpf-next-VM_Test-0 success Logs for ShellCheck
bpf/vmtest-bpf-next-VM_Test-5 success Logs for set-matrix
bpf/vmtest-bpf-next-VM_Test-1 success Logs for build for aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-3 success Logs for build for x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-4 success Logs for build for x86_64 with llvm-16
bpf/vmtest-bpf-next-VM_Test-7 pending Logs for test_maps on s390x with gcc
bpf/vmtest-bpf-next-VM_Test-2 success Logs for build for s390x with gcc
bpf/vmtest-bpf-next-VM_Test-8 fail Logs for test_maps on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-9 fail Logs for test_maps on x86_64 with llvm-16
bpf/vmtest-bpf-next-VM_Test-10 fail Logs for test_progs on aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-12 fail Logs for test_progs on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-6 success Logs for test_maps on aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-13 fail Logs for test_progs on x86_64 with llvm-16
bpf/vmtest-bpf-next-VM_Test-14 fail Logs for test_progs_no_alu32 on aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-16 fail Logs for test_progs_no_alu32 on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-17 fail Logs for test_progs_no_alu32 on x86_64 with llvm-16
bpf/vmtest-bpf-next-VM_Test-18 success Logs for test_progs_no_alu32_parallel on aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-19 success Logs for test_progs_no_alu32_parallel on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-20 success Logs for test_progs_no_alu32_parallel on x86_64 with llvm-16
bpf/vmtest-bpf-next-VM_Test-21 success Logs for test_progs_parallel on aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-22 success Logs for test_progs_parallel on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-23 success Logs for test_progs_parallel on x86_64 with llvm-16
bpf/vmtest-bpf-next-VM_Test-24 success Logs for test_verifier on aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-25 success Logs for test_verifier on s390x with gcc
bpf/vmtest-bpf-next-VM_Test-26 success Logs for test_verifier on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-27 success Logs for test_verifier on x86_64 with llvm-16
bpf/vmtest-bpf-next-VM_Test-28 fail Logs for veristat
bpf/vmtest-bpf-next-VM_Test-15 fail Logs for test_progs_no_alu32 on s390x with gcc
bpf/vmtest-bpf-next-VM_Test-11 fail Logs for test_progs on s390x with gcc
netdev/series_format success Posting correctly formatted
netdev/tree_selection success Clearly marked for bpf-next, async
netdev/fixes_present success Fixes tag not required for -next series
netdev/header_inline success No static functions without inline keyword in header files
netdev/build_32bit fail Errors and warnings before: 26 this patch: 23
netdev/cc_maintainers warning 7 maintainers not CCed: jolsa@kernel.org haoluo@google.com daniel@iogearbox.net sdf@google.com john.fastabend@gmail.com yonghong.song@linux.dev kpsingh@kernel.org
netdev/build_clang fail Errors and warnings before: 26 this patch: 23
netdev/verify_signedoff success Signed-off-by tag matches author and committer
netdev/deprecated_api success None detected
netdev/check_selftest success No net selftest shell script
netdev/verify_fixes success No Fixes tag
netdev/build_allmodconfig_warn fail Errors and warnings before: 26 this patch: 23
netdev/checkpatch warning CHECK: Please use a blank line after function/struct/union/enum declarations WARNING: line length of 110 exceeds 80 columns WARNING: line length of 85 exceeds 80 columns WARNING: line length of 97 exceeds 80 columns
netdev/kdoc success Errors and warnings before: 22 this patch: 22
netdev/source_inline success Was 0 now: 0

Commit Message

Kui-Feng Lee Sept. 20, 2023, 3:59 p.m. UTC
From: Kui-Feng Lee <thinker.li@gmail.com>

Find module BTFs for struct_ops maps and progs and pass them to the kernel.
It ensures the kernel resolve type IDs from correct 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. It's FD is passed to the kernel as mod_btf_fd
when it is created.

For a prog attaching to a struct_ops object, attach_btf_obj_fd of bpf_prog
is the FD pointing to a module BTF in the kernel.

Signed-off-by: Kui-Feng Lee <thinker.li@gmail.com>
---
 tools/lib/bpf/bpf.c    |   3 +-
 tools/lib/bpf/bpf.h    |   4 +-
 tools/lib/bpf/libbpf.c | 121 ++++++++++++++++++++++++-----------------
 3 files changed, 75 insertions(+), 53 deletions(-)

Comments

Andrii Nakryiko Sept. 25, 2023, 11:09 p.m. UTC | #1
On Wed, Sep 20, 2023 at 9:00 AM <thinker.li@gmail.com> wrote:
>
> From: Kui-Feng Lee <thinker.li@gmail.com>
>
> Find module BTFs for struct_ops maps and progs and pass them to the kernel.
> It ensures the kernel resolve type IDs from correct 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. It's FD is passed to the kernel as mod_btf_fd
> when it is created.
>
> For a prog attaching to a struct_ops object, attach_btf_obj_fd of bpf_prog
> is the FD pointing to a module BTF in the kernel.
>
> Signed-off-by: Kui-Feng Lee <thinker.li@gmail.com>
> ---
>  tools/lib/bpf/bpf.c    |   3 +-
>  tools/lib/bpf/bpf.h    |   4 +-
>  tools/lib/bpf/libbpf.c | 121 ++++++++++++++++++++++++-----------------
>  3 files changed, 75 insertions(+), 53 deletions(-)
>
> diff --git a/tools/lib/bpf/bpf.c b/tools/lib/bpf/bpf.c
> index b0f1913763a3..df4b7570ad92 100644
> --- a/tools/lib/bpf/bpf.c
> +++ b/tools/lib/bpf/bpf.c
> @@ -169,7 +169,7 @@ 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, mod_btf_fd);
>         union bpf_attr attr;
>         int fd;
>
> @@ -191,6 +191,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.mod_btf_fd = OPTS_GET(opts, mod_btf_fd, 0);
>
>         attr.inner_map_fd = OPTS_GET(opts, inner_map_fd, 0);
>         attr.map_flags = OPTS_GET(opts, map_flags, 0);
> diff --git a/tools/lib/bpf/bpf.h b/tools/lib/bpf/bpf.h
> index 74c2887cfd24..d18f75b0ccc9 100644
> --- a/tools/lib/bpf/bpf.h
> +++ b/tools/lib/bpf/bpf.h
> @@ -51,8 +51,10 @@ struct bpf_map_create_opts {
>
>         __u32 numa_node;
>         __u32 map_ifindex;
> +
> +       __u32 mod_btf_fd;

please add `size_t :0;` at the end to avoid compiler leaving garbage
in added padding at the end of opts struct

>  };
> -#define bpf_map_create_opts__last_field map_ifindex
> +#define bpf_map_create_opts__last_field mod_btf_fd
>
>  LIBBPF_API int bpf_map_create(enum bpf_map_type map_type,
>                               const char *map_name,
> diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c
> index 3a6108e3238b..df6ba5494adb 100644
> --- a/tools/lib/bpf/libbpf.c
> +++ b/tools/lib/bpf/libbpf.c
> @@ -519,6 +519,7 @@ struct bpf_map {
>         struct bpf_map_def def;
>         __u32 numa_node;
>         __u32 btf_var_idx;
> +       struct module_btf *mod_btf;

It would be simpler to just store btf_fd instead of entire struct
module_btf pointer. You only need this to set btf_obj_fd on map
creation and program loading, right?

>         __u32 btf_key_type_id;
>         __u32 btf_value_type_id;
>         __u32 btf_vmlinux_value_type_id;
> @@ -893,6 +894,42 @@ bpf_object__add_programs(struct bpf_object *obj, Elf_Data *sec_data,
>         return 0;
>  }
>
> +static int load_module_btfs(struct bpf_object *obj);
> +
> +static int find_kern_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, kern_name, kind);
> +
> +       if (id == -ENOENT) {
> +               err = load_module_btfs(obj);
> +               if (err)
> +                       return err;
> +
> +               for (i = 0; i < obj->btf_module_cnt; i++) {
> +                       /* 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, kern_name, kind);
> +                       if (id != -ENOENT)
> +                               break;
> +               }
> +       }
> +       if (id <= 0)
> +               return -ESRCH;
> +
> +       *res_btf = btf;
> +       *res_mod_btf = mod_btf;
> +       return id;
> +}
> +

there is no need to move the entire function body here, just add a
forward declaration. It will also make it easier to see what actually
changed about the function (if at all)

>  static const struct btf_member *
>  find_member_by_offset(const struct btf_type *t, __u32 bit_offset)
>  {
> @@ -927,17 +964,23 @@ 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);
> +       /* XXX: should search module BTFs as well. We need module name here
> +        * to locate a correct BTF type.
> +        */

aren't we searching module BTFs? Is this comment still relevant?

> +       kern_type_id = find_kern_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);
> @@ -992,13 +1035,15 @@ 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)
> +                                        struct bpf_object *obj)

no need to pass obj separately, you can get it through `map->obj`

>  {
>         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_struct_ops *st_ops;
> +       const struct btf *kern_btf;
> +       struct module_btf *mod_btf;
> +       const struct btf *btf = obj->btf;
>         void *data, *kern_data;
>         const char *tname;
>         int err;
> @@ -1006,16 +1051,19 @@ static int bpf_map__init_kern_struct_ops(struct bpf_map *map,
>         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 = mod_btf;
>         map->def.value_size = kern_vtype->size;
>         map->btf_vmlinux_value_type_id = kern_vtype_id;
>
> @@ -1091,6 +1139,9 @@ static int bpf_map__init_kern_struct_ops(struct bpf_map *map,
>                                 return -ENOTSUP;
>                         }
>
> +                       /* XXX: attach_btf_obj_fd is needed as well */

seems like all these XXX comments are outdated and the code is already
doing all that, is that right? If so, please remove them, they are
confusing

> +                       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;
>
> @@ -1133,8 +1184,8 @@ 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);
> +               /* XXX: should be a module btf if not vmlinux */
> +               err = bpf_map__init_kern_struct_ops(map, obj);
>                 if (err)
>                         return err;
>         }

[...]
Kui-Feng Lee Sept. 26, 2023, 12:12 a.m. UTC | #2
On 9/25/23 16:09, Andrii Nakryiko wrote:
> On Wed, Sep 20, 2023 at 9:00 AM <thinker.li@gmail.com> wrote:
>>
>> From: Kui-Feng Lee <thinker.li@gmail.com>
>>
>> Find module BTFs for struct_ops maps and progs and pass them to the kernel.
>> It ensures the kernel resolve type IDs from correct 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. It's FD is passed to the kernel as mod_btf_fd
>> when it is created.
>>
>> For a prog attaching to a struct_ops object, attach_btf_obj_fd of bpf_prog
>> is the FD pointing to a module BTF in the kernel.
>>
>> Signed-off-by: Kui-Feng Lee <thinker.li@gmail.com>
>> ---
>>   tools/lib/bpf/bpf.c    |   3 +-
>>   tools/lib/bpf/bpf.h    |   4 +-
>>   tools/lib/bpf/libbpf.c | 121 ++++++++++++++++++++++++-----------------
>>   3 files changed, 75 insertions(+), 53 deletions(-)
>>
>> diff --git a/tools/lib/bpf/bpf.c b/tools/lib/bpf/bpf.c
>> index b0f1913763a3..df4b7570ad92 100644
>> --- a/tools/lib/bpf/bpf.c
>> +++ b/tools/lib/bpf/bpf.c
>> @@ -169,7 +169,7 @@ 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, mod_btf_fd);
>>          union bpf_attr attr;
>>          int fd;
>>
>> @@ -191,6 +191,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.mod_btf_fd = OPTS_GET(opts, mod_btf_fd, 0);
>>
>>          attr.inner_map_fd = OPTS_GET(opts, inner_map_fd, 0);
>>          attr.map_flags = OPTS_GET(opts, map_flags, 0);
>> diff --git a/tools/lib/bpf/bpf.h b/tools/lib/bpf/bpf.h
>> index 74c2887cfd24..d18f75b0ccc9 100644
>> --- a/tools/lib/bpf/bpf.h
>> +++ b/tools/lib/bpf/bpf.h
>> @@ -51,8 +51,10 @@ struct bpf_map_create_opts {
>>
>>          __u32 numa_node;
>>          __u32 map_ifindex;
>> +
>> +       __u32 mod_btf_fd;
> 
> please add `size_t :0;` at the end to avoid compiler leaving garbage
> in added padding at the end of opts struct

Ok!

> 
>>   };
>> -#define bpf_map_create_opts__last_field map_ifindex
>> +#define bpf_map_create_opts__last_field mod_btf_fd
>>
>>   LIBBPF_API int bpf_map_create(enum bpf_map_type map_type,
>>                                const char *map_name,
>> diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c
>> index 3a6108e3238b..df6ba5494adb 100644
>> --- a/tools/lib/bpf/libbpf.c
>> +++ b/tools/lib/bpf/libbpf.c
>> @@ -519,6 +519,7 @@ struct bpf_map {
>>          struct bpf_map_def def;
>>          __u32 numa_node;
>>          __u32 btf_var_idx;
>> +       struct module_btf *mod_btf;
> 
> It would be simpler to just store btf_fd instead of entire struct
> module_btf pointer. You only need this to set btf_obj_fd on map
> creation and program loading, right?

Yes!

> 
>>          __u32 btf_key_type_id;
>>          __u32 btf_value_type_id;
>>          __u32 btf_vmlinux_value_type_id;
>> @@ -893,6 +894,42 @@ bpf_object__add_programs(struct bpf_object *obj, Elf_Data *sec_data,
>>          return 0;
>>   }
>>
>> +static int load_module_btfs(struct bpf_object *obj);
>> +
>> +static int find_kern_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, kern_name, kind);
>> +
>> +       if (id == -ENOENT) {
>> +               err = load_module_btfs(obj);
>> +               if (err)
>> +                       return err;
>> +
>> +               for (i = 0; i < obj->btf_module_cnt; i++) {
>> +                       /* 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, kern_name, kind);
>> +                       if (id != -ENOENT)
>> +                               break;
>> +               }
>> +       }
>> +       if (id <= 0)
>> +               return -ESRCH;
>> +
>> +       *res_btf = btf;
>> +       *res_mod_btf = mod_btf;
>> +       return id;
>> +}
>> +
> 
> there is no need to move the entire function body here, just add a
> forward declaration. It will also make it easier to see what actually
> changed about the function (if at all)

Got it

> 
>>   static const struct btf_member *
>>   find_member_by_offset(const struct btf_type *t, __u32 bit_offset)
>>   {
>> @@ -927,17 +964,23 @@ 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);
>> +       /* XXX: should search module BTFs as well. We need module name here
>> +        * to locate a correct BTF type.
>> +        */
> 
> aren't we searching module BTFs? Is this comment still relevant?
> 
>> +       kern_type_id = find_kern_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);
>> @@ -992,13 +1035,15 @@ 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)
>> +                                        struct bpf_object *obj)
> 
> no need to pass obj separately, you can get it through `map->obj`

Good to know!

> 
>>   {
>>          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_struct_ops *st_ops;
>> +       const struct btf *kern_btf;
>> +       struct module_btf *mod_btf;
>> +       const struct btf *btf = obj->btf;
>>          void *data, *kern_data;
>>          const char *tname;
>>          int err;
>> @@ -1006,16 +1051,19 @@ static int bpf_map__init_kern_struct_ops(struct bpf_map *map,
>>          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 = mod_btf;
>>          map->def.value_size = kern_vtype->size;
>>          map->btf_vmlinux_value_type_id = kern_vtype_id;
>>
>> @@ -1091,6 +1139,9 @@ static int bpf_map__init_kern_struct_ops(struct bpf_map *map,
>>                                  return -ENOTSUP;
>>                          }
>>
>> +                       /* XXX: attach_btf_obj_fd is needed as well */
> 
> seems like all these XXX comments are outdated and the code is already
> doing all that, is that right? If so, please remove them, they are
> confusing

Sure!

> 
>> +                       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;
>>
>> @@ -1133,8 +1184,8 @@ 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);
>> +               /* XXX: should be a module btf if not vmlinux */
>> +               err = bpf_map__init_kern_struct_ops(map, obj);
>>                  if (err)
>>                          return err;
>>          }
> 
> [...]
diff mbox series

Patch

diff --git a/tools/lib/bpf/bpf.c b/tools/lib/bpf/bpf.c
index b0f1913763a3..df4b7570ad92 100644
--- a/tools/lib/bpf/bpf.c
+++ b/tools/lib/bpf/bpf.c
@@ -169,7 +169,7 @@  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, mod_btf_fd);
 	union bpf_attr attr;
 	int fd;
 
@@ -191,6 +191,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.mod_btf_fd = OPTS_GET(opts, mod_btf_fd, 0);
 
 	attr.inner_map_fd = OPTS_GET(opts, inner_map_fd, 0);
 	attr.map_flags = OPTS_GET(opts, map_flags, 0);
diff --git a/tools/lib/bpf/bpf.h b/tools/lib/bpf/bpf.h
index 74c2887cfd24..d18f75b0ccc9 100644
--- a/tools/lib/bpf/bpf.h
+++ b/tools/lib/bpf/bpf.h
@@ -51,8 +51,10 @@  struct bpf_map_create_opts {
 
 	__u32 numa_node;
 	__u32 map_ifindex;
+
+	__u32 mod_btf_fd;
 };
-#define bpf_map_create_opts__last_field map_ifindex
+#define bpf_map_create_opts__last_field mod_btf_fd
 
 LIBBPF_API int bpf_map_create(enum bpf_map_type map_type,
 			      const char *map_name,
diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c
index 3a6108e3238b..df6ba5494adb 100644
--- a/tools/lib/bpf/libbpf.c
+++ b/tools/lib/bpf/libbpf.c
@@ -519,6 +519,7 @@  struct bpf_map {
 	struct bpf_map_def def;
 	__u32 numa_node;
 	__u32 btf_var_idx;
+	struct module_btf *mod_btf;
 	__u32 btf_key_type_id;
 	__u32 btf_value_type_id;
 	__u32 btf_vmlinux_value_type_id;
@@ -893,6 +894,42 @@  bpf_object__add_programs(struct bpf_object *obj, Elf_Data *sec_data,
 	return 0;
 }
 
+static int load_module_btfs(struct bpf_object *obj);
+
+static int find_kern_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, kern_name, kind);
+
+	if (id == -ENOENT) {
+		err = load_module_btfs(obj);
+		if (err)
+			return err;
+
+		for (i = 0; i < obj->btf_module_cnt; i++) {
+			/* 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, kern_name, kind);
+			if (id != -ENOENT)
+				break;
+		}
+	}
+	if (id <= 0)
+		return -ESRCH;
+
+	*res_btf = btf;
+	*res_mod_btf = mod_btf;
+	return id;
+}
+
 static const struct btf_member *
 find_member_by_offset(const struct btf_type *t, __u32 bit_offset)
 {
@@ -927,17 +964,23 @@  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);
+	/* XXX: should search module BTFs as well. We need module name here
+	 * to locate a correct BTF type.
+	 */
+	kern_type_id = find_kern_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);
@@ -992,13 +1035,15 @@  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)
+					 struct bpf_object *obj)
 {
 	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_struct_ops *st_ops;
+	const struct btf *kern_btf;
+	struct module_btf *mod_btf;
+	const struct btf *btf = obj->btf;
 	void *data, *kern_data;
 	const char *tname;
 	int err;
@@ -1006,16 +1051,19 @@  static int bpf_map__init_kern_struct_ops(struct bpf_map *map,
 	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 = mod_btf;
 	map->def.value_size = kern_vtype->size;
 	map->btf_vmlinux_value_type_id = kern_vtype_id;
 
@@ -1091,6 +1139,9 @@  static int bpf_map__init_kern_struct_ops(struct bpf_map *map,
 				return -ENOTSUP;
 			}
 
+			/* XXX: attach_btf_obj_fd is needed as well */
+			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;
 
@@ -1133,8 +1184,8 @@  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);
+		/* XXX: should be a module btf if not vmlinux */
+		err = bpf_map__init_kern_struct_ops(map, obj);
 		if (err)
 			return err;
 	}
@@ -5193,8 +5244,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.mod_btf_fd = map->mod_btf ? map->mod_btf->fd : 0;
+	}
 
 	if (obj->btf && btf__fd(obj->btf) >= 0) {
 		create_attr.btf_fd = btf__fd(obj->btf);
@@ -7700,40 +7753,6 @@  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)
-{
-	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);
-
-	if (id == -ENOENT) {
-		err = load_module_btfs(obj);
-		if (err)
-			return err;
-
-		for (i = 0; i < obj->btf_module_cnt; i++) {
-			/* 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);
-			if (id != -ENOENT)
-				break;
-		}
-	}
-	if (id <= 0)
-		return -ESRCH;
-
-	*res_btf = btf;
-	*res_mod_btf = mod_btf;
-	return id;
-}
-
 static int bpf_object__resolve_ksym_var_btf_id(struct bpf_object *obj,
 					       struct extern_desc *ext)
 {
@@ -7744,7 +7763,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_kern_btf_id(obj, ext->name, BTF_KIND_VAR, &btf, &mod_btf);
 	if (id < 0) {
 		if (id == -ESRCH && ext->is_weak)
 			return 0;
@@ -7798,7 +7817,7 @@  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,
+	kfunc_id = find_kern_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)
@@ -9464,9 +9483,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;
 
@@ -9531,7 +9550,7 @@  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",
@@ -12945,9 +12964,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);
 	}