diff mbox series

[bpf-next,v2,3/5] libbpf: add subskeleton scaffolding

Message ID b7ab6736af3976a8739f0ed75feb4ca58f5e926f.1646957399.git.delyank@fb.com (mailing list archive)
State Superseded
Delegated to: BPF
Headers show
Series Subskeleton support for BPF libraries | expand

Checks

Context Check Description
netdev/tree_selection success Clearly marked for bpf-next
netdev/fixes_present success Fixes tag not required for -next series
netdev/subject_prefix success Link
netdev/cover_letter success Series has a cover letter
netdev/patch_count success Link
netdev/header_inline success No static functions without inline keyword in header files
netdev/build_32bit success Errors and warnings before: 0 this patch: 0
netdev/cc_maintainers warning 6 maintainers not CCed: kpsingh@kernel.org john.fastabend@gmail.com kafai@fb.com songliubraving@fb.com yhs@fb.com netdev@vger.kernel.org
netdev/build_clang success Errors and warnings before: 0 this patch: 0
netdev/module_param success Was 0 now: 0
netdev/verify_signedoff success Signed-off-by tag matches author and committer
netdev/verify_fixes success No Fixes tag
netdev/build_allmodconfig_warn success Errors and warnings before: 0 this patch: 0
netdev/checkpatch fail CHECK: No space is necessary after a cast ERROR: "foo* bar" should be "foo *bar" WARNING: line length of 85 exceeds 80 columns
netdev/kdoc success Errors and warnings before: 38 this patch: 38
netdev/source_inline success Was 0 now: 0
bpf/vmtest-bpf-next-PR success PR summary
bpf/vmtest-bpf-next success VM_Test

Commit Message

Delyan Kratunov March 11, 2022, 12:11 a.m. UTC
In symmetry with bpf_object__open_skeleton(),
bpf_object__open_subskeleton() performs the actual walking and linking
of maps, progs, and globals described by bpf_*_skeleton objects.

Signed-off-by: Delyan Kratunov <delyank@fb.com>
---
 tools/lib/bpf/libbpf.c   | 136 +++++++++++++++++++++++++++++++++------
 tools/lib/bpf/libbpf.h   |  29 +++++++++
 tools/lib/bpf/libbpf.map |   2 +
 3 files changed, 146 insertions(+), 21 deletions(-)

Comments

Andrii Nakryiko March 11, 2022, 10:52 p.m. UTC | #1
On Thu, Mar 10, 2022 at 4:12 PM Delyan Kratunov <delyank@fb.com> wrote:
>
> In symmetry with bpf_object__open_skeleton(),
> bpf_object__open_subskeleton() performs the actual walking and linking
> of maps, progs, and globals described by bpf_*_skeleton objects.
>
> Signed-off-by: Delyan Kratunov <delyank@fb.com>
> ---
>  tools/lib/bpf/libbpf.c   | 136 +++++++++++++++++++++++++++++++++------
>  tools/lib/bpf/libbpf.h   |  29 +++++++++
>  tools/lib/bpf/libbpf.map |   2 +
>  3 files changed, 146 insertions(+), 21 deletions(-)
>
> diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c
> index 3fb9c926fe6e..ba7b25b11486 100644
> --- a/tools/lib/bpf/libbpf.c
> +++ b/tools/lib/bpf/libbpf.c
> @@ -11810,6 +11810,49 @@ int libbpf_num_possible_cpus(void)
>         return tmp_cpus;
>  }
>
> +static int populate_skeleton_maps(const struct bpf_object* obj,
> +                                 struct bpf_map_skeleton* maps,
> +                                 size_t map_cnt)
> +{
> +       int i;
> +
> +       for (i = 0; i < map_cnt; i++) {
> +               struct bpf_map **map = maps[i].map;
> +               const char *name = maps[i].name;
> +               void **mmaped = maps[i].mmaped;
> +
> +               *map = bpf_object__find_map_by_name(obj, name);
> +               if (!*map) {
> +                       pr_warn("failed to find skeleton map '%s'\n", name);
> +                       return libbpf_err(-ESRCH);

this is internal helper function, so no need (and it's a bit
misleading as well) to use libbpf_err() helper. Just return an error
and let user-facing API functions deal with error handling

> +               }
> +
> +               /* externs shouldn't be pre-setup from user code */
> +               if (mmaped && (*map)->libbpf_type != LIBBPF_MAP_KCONFIG)
> +                       *mmaped = (*map)->mmaped;
> +       }
> +       return 0;
> +}
> +
> +static int populate_skeleton_progs(const struct bpf_object* obj,
> +                                  struct bpf_prog_skeleton* progs,
> +                                  size_t prog_cnt)
> +{
> +       int i;
> +
> +       for (i = 0; i < prog_cnt; i++) {
> +               struct bpf_program **prog = progs[i].prog;
> +               const char *name = progs[i].name;
> +
> +               *prog = bpf_object__find_program_by_name(obj, name);
> +               if (!*prog) {
> +                       pr_warn("failed to find skeleton program '%s'\n", name);
> +                       return libbpf_err(-ESRCH);

same about libbpf_err() use

> +               }
> +       }
> +       return 0;
> +}
> +
>  int bpf_object__open_skeleton(struct bpf_object_skeleton *s,
>                               const struct bpf_object_open_opts *opts)
>  {
> @@ -11817,7 +11860,7 @@ int bpf_object__open_skeleton(struct bpf_object_skeleton *s,
>                 .object_name = s->name,
>         );
>         struct bpf_object *obj;
> -       int i, err;
> +       int err;
>
>         /* Attempt to preserve opts->object_name, unless overriden by user
>          * explicitly. Overwriting object name for skeletons is discouraged,
> @@ -11840,37 +11883,88 @@ int bpf_object__open_skeleton(struct bpf_object_skeleton *s,
>         }
>
>         *s->obj = obj;
> +       err = populate_skeleton_maps(obj, s->maps, s->map_cnt);
> +       if (err) {
> +               pr_warn("failed to populate skeleton maps for '%s': %d\n",
> +                       s->name, err);

nit: probably fits under 100 characters on single line

> +               return libbpf_err(err);
> +       }
>
> -       for (i = 0; i < s->map_cnt; i++) {
> -               struct bpf_map **map = s->maps[i].map;
> -               const char *name = s->maps[i].name;
> -               void **mmaped = s->maps[i].mmaped;
> +       err = populate_skeleton_progs(obj, s->progs, s->prog_cnt);
> +       if (err) {
> +               pr_warn("failed to populate skeleton progs for '%s': %d\n",
> +                       s->name, err);

and here

> +               return libbpf_err(err);
> +       }
>
> -               *map = bpf_object__find_map_by_name(obj, name);
> -               if (!*map) {
> -                       pr_warn("failed to find skeleton map '%s'\n", name);
> -                       return libbpf_err(-ESRCH);
> -               }
> +       return 0;
> +}
>
> -               /* externs shouldn't be pre-setup from user code */
> -               if (mmaped && (*map)->libbpf_type != LIBBPF_MAP_KCONFIG)
> -                       *mmaped = (*map)->mmaped;
> +int bpf_object__open_subskeleton(struct bpf_object_subskeleton *s)
> +{
> +       int err, len, var_idx, i;
> +       const char *var_name;
> +       const struct bpf_map *map;
> +       struct btf *btf;
> +       __u32 map_type_id;
> +       const struct btf_type *map_type, *var_type;
> +       const struct bpf_var_skeleton *var_skel;
> +       struct btf_var_secinfo *var;
> +
> +       if (!s->obj)
> +               return libbpf_err(-EINVAL);
> +
> +       btf = bpf_object__btf(s->obj);
> +       if (!btf)
> +               return -errno;

use libbpf_err(-errno) for consistency?

> +
> +       err = populate_skeleton_maps(s->obj, s->maps, s->map_cnt);
> +       if (err) {
> +               pr_warn("failed to populate subskeleton maps: %d\n", err);
> +               return libbpf_err(err);
>         }
>
> -       for (i = 0; i < s->prog_cnt; i++) {
> -               struct bpf_program **prog = s->progs[i].prog;
> -               const char *name = s->progs[i].name;
> +       err = populate_skeleton_progs(s->obj, s->progs, s->prog_cnt);
> +       if (err) {
> +               pr_warn("failed to populate subskeleton maps: %d\n", err);
> +               return libbpf_err(err);
> +       }
>
> -               *prog = bpf_object__find_program_by_name(obj, name);
> -               if (!*prog) {
> -                       pr_warn("failed to find skeleton program '%s'\n", name);
> -                       return libbpf_err(-ESRCH);
> +       for (var_idx = 0; var_idx < s->var_cnt; var_idx++) {
> +               var_skel = &s->vars[var_idx];
> +               map = *var_skel->map;
> +               map_type_id = bpf_map__btf_value_type_id(map);
> +               map_type = btf__type_by_id(btf, map_type_id);
> +

should we double-check that map_type is DATASEC?

> +               len = btf_vlen(map_type);
> +               var = btf_var_secinfos(map_type);
> +               for (i = 0; i < len; i++, var++) {
> +                       var_type = btf__type_by_id(btf, var->type);
> +                       if (!var_type) {

unless BTF itself is corrupted, this shouldn't ever happen. So
checking for DATASEC should be enough and this if (!var_type) is
redundant

> +                               pr_warn("Could not find var type for item %1$d in section %2$s",
> +                                       i, bpf_map__name(map));
> +                               return libbpf_err(-EINVAL);
> +                       }
> +                       var_name = btf__name_by_offset(btf, var_type->name_off);
> +                       if (strcmp(var_name, var_skel->name) == 0) {
> +                               *var_skel->addr = (char *) map->mmaped + var->offset;

is (char *) cast necessary? C allows pointer adjustment on void *, so
shouldn't be

> +                               break;
> +                       }
>                 }
>         }
> -
>         return 0;
>  }
>

[...]

>  struct gen_loader_opts {
>         size_t sz; /* size of this struct, for forward/backward compatiblity */
>         const char *data;
> diff --git a/tools/lib/bpf/libbpf.map b/tools/lib/bpf/libbpf.map
> index df1b947792c8..d744fbb8612e 100644
> --- a/tools/lib/bpf/libbpf.map
> +++ b/tools/lib/bpf/libbpf.map
> @@ -442,6 +442,8 @@ LIBBPF_0.7.0 {
>
>  LIBBPF_0.8.0 {
>         global:
> +               bpf_object__open_subskeleton;
> +               bpf_object__destroy_subskeleton;

nit: should be in alphabetic order

>                 libbpf_register_prog_handler;
>                 libbpf_unregister_prog_handler;
>  } LIBBPF_0.7.0;
> --
> 2.34.1
Andrii Nakryiko March 11, 2022, 11:08 p.m. UTC | #2
On Fri, Mar 11, 2022 at 2:52 PM Andrii Nakryiko
<andrii.nakryiko@gmail.com> wrote:
>
> On Thu, Mar 10, 2022 at 4:12 PM Delyan Kratunov <delyank@fb.com> wrote:
> >
> > In symmetry with bpf_object__open_skeleton(),
> > bpf_object__open_subskeleton() performs the actual walking and linking
> > of maps, progs, and globals described by bpf_*_skeleton objects.
> >
> > Signed-off-by: Delyan Kratunov <delyank@fb.com>
> > ---
> >  tools/lib/bpf/libbpf.c   | 136 +++++++++++++++++++++++++++++++++------
> >  tools/lib/bpf/libbpf.h   |  29 +++++++++
> >  tools/lib/bpf/libbpf.map |   2 +
> >  3 files changed, 146 insertions(+), 21 deletions(-)
> >
> > diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c
> > index 3fb9c926fe6e..ba7b25b11486 100644
> > --- a/tools/lib/bpf/libbpf.c
> > +++ b/tools/lib/bpf/libbpf.c
> > @@ -11810,6 +11810,49 @@ int libbpf_num_possible_cpus(void)
> >         return tmp_cpus;
> >  }
> >
> > +static int populate_skeleton_maps(const struct bpf_object* obj,
> > +                                 struct bpf_map_skeleton* maps,
> > +                                 size_t map_cnt)
> > +{
> > +       int i;
> > +
> > +       for (i = 0; i < map_cnt; i++) {
> > +               struct bpf_map **map = maps[i].map;
> > +               const char *name = maps[i].name;
> > +               void **mmaped = maps[i].mmaped;
> > +
> > +               *map = bpf_object__find_map_by_name(obj, name);
> > +               if (!*map) {
> > +                       pr_warn("failed to find skeleton map '%s'\n", name);
> > +                       return libbpf_err(-ESRCH);
>
> this is internal helper function, so no need (and it's a bit
> misleading as well) to use libbpf_err() helper. Just return an error
> and let user-facing API functions deal with error handling
>
> > +               }
> > +
> > +               /* externs shouldn't be pre-setup from user code */
> > +               if (mmaped && (*map)->libbpf_type != LIBBPF_MAP_KCONFIG)
> > +                       *mmaped = (*map)->mmaped;
> > +       }
> > +       return 0;
> > +}
> > +
> > +static int populate_skeleton_progs(const struct bpf_object* obj,
> > +                                  struct bpf_prog_skeleton* progs,
> > +                                  size_t prog_cnt)
> > +{
> > +       int i;
> > +
> > +       for (i = 0; i < prog_cnt; i++) {
> > +               struct bpf_program **prog = progs[i].prog;
> > +               const char *name = progs[i].name;
> > +
> > +               *prog = bpf_object__find_program_by_name(obj, name);
> > +               if (!*prog) {
> > +                       pr_warn("failed to find skeleton program '%s'\n", name);
> > +                       return libbpf_err(-ESRCH);
>
> same about libbpf_err() use
>
> > +               }
> > +       }
> > +       return 0;
> > +}
> > +
> >  int bpf_object__open_skeleton(struct bpf_object_skeleton *s,
> >                               const struct bpf_object_open_opts *opts)
> >  {
> > @@ -11817,7 +11860,7 @@ int bpf_object__open_skeleton(struct bpf_object_skeleton *s,
> >                 .object_name = s->name,
> >         );
> >         struct bpf_object *obj;
> > -       int i, err;
> > +       int err;
> >
> >         /* Attempt to preserve opts->object_name, unless overriden by user
> >          * explicitly. Overwriting object name for skeletons is discouraged,
> > @@ -11840,37 +11883,88 @@ int bpf_object__open_skeleton(struct bpf_object_skeleton *s,
> >         }
> >
> >         *s->obj = obj;
> > +       err = populate_skeleton_maps(obj, s->maps, s->map_cnt);
> > +       if (err) {
> > +               pr_warn("failed to populate skeleton maps for '%s': %d\n",
> > +                       s->name, err);
>
> nit: probably fits under 100 characters on single line
>
> > +               return libbpf_err(err);
> > +       }
> >
> > -       for (i = 0; i < s->map_cnt; i++) {
> > -               struct bpf_map **map = s->maps[i].map;
> > -               const char *name = s->maps[i].name;
> > -               void **mmaped = s->maps[i].mmaped;
> > +       err = populate_skeleton_progs(obj, s->progs, s->prog_cnt);
> > +       if (err) {
> > +               pr_warn("failed to populate skeleton progs for '%s': %d\n",
> > +                       s->name, err);
>
> and here
>
> > +               return libbpf_err(err);
> > +       }
> >
> > -               *map = bpf_object__find_map_by_name(obj, name);
> > -               if (!*map) {
> > -                       pr_warn("failed to find skeleton map '%s'\n", name);
> > -                       return libbpf_err(-ESRCH);
> > -               }
> > +       return 0;
> > +}
> >
> > -               /* externs shouldn't be pre-setup from user code */
> > -               if (mmaped && (*map)->libbpf_type != LIBBPF_MAP_KCONFIG)
> > -                       *mmaped = (*map)->mmaped;
> > +int bpf_object__open_subskeleton(struct bpf_object_subskeleton *s)
> > +{
> > +       int err, len, var_idx, i;
> > +       const char *var_name;
> > +       const struct bpf_map *map;
> > +       struct btf *btf;
> > +       __u32 map_type_id;
> > +       const struct btf_type *map_type, *var_type;
> > +       const struct bpf_var_skeleton *var_skel;
> > +       struct btf_var_secinfo *var;
> > +
> > +       if (!s->obj)
> > +               return libbpf_err(-EINVAL);
> > +
> > +       btf = bpf_object__btf(s->obj);
> > +       if (!btf)
> > +               return -errno;
>
> use libbpf_err(-errno) for consistency?
>
> > +
> > +       err = populate_skeleton_maps(s->obj, s->maps, s->map_cnt);
> > +       if (err) {
> > +               pr_warn("failed to populate subskeleton maps: %d\n", err);
> > +               return libbpf_err(err);
> >         }
> >
> > -       for (i = 0; i < s->prog_cnt; i++) {
> > -               struct bpf_program **prog = s->progs[i].prog;
> > -               const char *name = s->progs[i].name;
> > +       err = populate_skeleton_progs(s->obj, s->progs, s->prog_cnt);
> > +       if (err) {
> > +               pr_warn("failed to populate subskeleton maps: %d\n", err);
> > +               return libbpf_err(err);
> > +       }
> >
> > -               *prog = bpf_object__find_program_by_name(obj, name);
> > -               if (!*prog) {
> > -                       pr_warn("failed to find skeleton program '%s'\n", name);
> > -                       return libbpf_err(-ESRCH);
> > +       for (var_idx = 0; var_idx < s->var_cnt; var_idx++) {
> > +               var_skel = &s->vars[var_idx];
> > +               map = *var_skel->map;
> > +               map_type_id = bpf_map__btf_value_type_id(map);
> > +               map_type = btf__type_by_id(btf, map_type_id);
> > +
>
> should we double-check that map_type is DATASEC?
>
> > +               len = btf_vlen(map_type);
> > +               var = btf_var_secinfos(map_type);
> > +               for (i = 0; i < len; i++, var++) {
> > +                       var_type = btf__type_by_id(btf, var->type);
> > +                       if (!var_type) {
>
> unless BTF itself is corrupted, this shouldn't ever happen. So
> checking for DATASEC should be enough and this if (!var_type) is
> redundant
>
> > +                               pr_warn("Could not find var type for item %1$d in section %2$s",
> > +                                       i, bpf_map__name(map));
> > +                               return libbpf_err(-EINVAL);
> > +                       }
> > +                       var_name = btf__name_by_offset(btf, var_type->name_off);
> > +                       if (strcmp(var_name, var_skel->name) == 0) {
> > +                               *var_skel->addr = (char *) map->mmaped + var->offset;
>
> is (char *) cast necessary? C allows pointer adjustment on void *, so
> shouldn't be

oh, wait, it's so that C++ compiler doesn't complain, never mind

>
> > +                               break;
> > +                       }
> >                 }
> >         }
> > -
> >         return 0;
> >  }
> >
>
> [...]
>
> >  struct gen_loader_opts {
> >         size_t sz; /* size of this struct, for forward/backward compatiblity */
> >         const char *data;
> > diff --git a/tools/lib/bpf/libbpf.map b/tools/lib/bpf/libbpf.map
> > index df1b947792c8..d744fbb8612e 100644
> > --- a/tools/lib/bpf/libbpf.map
> > +++ b/tools/lib/bpf/libbpf.map
> > @@ -442,6 +442,8 @@ LIBBPF_0.7.0 {
> >
> >  LIBBPF_0.8.0 {
> >         global:
> > +               bpf_object__open_subskeleton;
> > +               bpf_object__destroy_subskeleton;
>
> nit: should be in alphabetic order
>
> >                 libbpf_register_prog_handler;
> >                 libbpf_unregister_prog_handler;
> >  } LIBBPF_0.7.0;
> > --
> > 2.34.1
Delyan Kratunov March 11, 2022, 11:28 p.m. UTC | #3
Thanks Andrii!

On Fri, 2022-03-11 at 15:08 -0800, Andrii Nakryiko wrote:
> On Fri, Mar 11, 2022 at 2:52 PM Andrii Nakryiko
> <andrii.nakryiko@gmail.com> wrote:
> 
> > 

[...]

> > > +
> > > +       err = populate_skeleton_maps(s->obj, s->maps, s->map_cnt);
> > > +       if (err) {
> > > +               pr_warn("failed to populate subskeleton maps: %d\n", err);
> > > +               return libbpf_err(err);
> > >         }
> > > 
> > > -       for (i = 0; i < s->prog_cnt; i++) {
> > > -               struct bpf_program **prog = s->progs[i].prog;
> > > -               const char *name = s->progs[i].name;
> > > +       err = populate_skeleton_progs(s->obj, s->progs, s->prog_cnt);
> > > +       if (err) {
> > > +               pr_warn("failed to populate subskeleton maps: %d\n", err);
> > > +               return libbpf_err(err);
> > > +       }
> > > 
> > > -               *prog = bpf_object__find_program_by_name(obj, name);
> > > -               if (!*prog) {
> > > -                       pr_warn("failed to find skeleton program '%s'\n", name);
> > > -                       return libbpf_err(-ESRCH);
> > > +       for (var_idx = 0; var_idx < s->var_cnt; var_idx++) {
> > > +               var_skel = &s->vars[var_idx];
> > > +               map = *var_skel->map;
> > > +               map_type_id = bpf_map__btf_value_type_id(map);
> > > +               map_type = btf__type_by_id(btf, map_type_id);
> > > +
> > 
> > should we double-check that map_type is DATASEC?

Sure, can do.

> > 
> > > +               len = btf_vlen(map_type);
> > > +               var = btf_var_secinfos(map_type);
> > > +               for (i = 0; i < len; i++, var++) {
> > > +                       var_type = btf__type_by_id(btf, var->type);
> > > +                       if (!var_type) {
> > 
> > unless BTF itself is corrupted, this shouldn't ever happen. So
> > checking for DATASEC should be enough and this if (!var_type) is
> > redundant
> > 
> > > +                               pr_warn("Could not find var type for item %1$d in section %2$s",
> > > +                                       i, bpf_map__name(map));
> > > +                               return libbpf_err(-EINVAL);
> > > +                       }
> > > +                       var_name = btf__name_by_offset(btf, var_type->name_off);
> > > +                       if (strcmp(var_name, var_skel->name) == 0) {
> > > +                               *var_skel->addr = (char *) map->mmaped + var->offset;
> > 
> > is (char *) cast necessary? C allows pointer adjustment on void *, so
> > shouldn't be
> 
> oh, wait, it's so that C++ compiler doesn't complain, never mind

This is libbpf code, not subskel code, so it shouldn't get compiled as C++. It's
really because of -Wpointer-arith and -Werror.

> 
> > 
> > > +                               break;
> > > +                       }
> > >                 }
> > >         }
> > > -
> > >         return 0;
> > >  }
> > > 
> > 
> > [...]
> > 
> > >  struct gen_loader_opts {
> > >         size_t sz; /* size of this struct, for forward/backward compatiblity */
> > >         const char *data;
> > > diff --git a/tools/lib/bpf/libbpf.map b/tools/lib/bpf/libbpf.map
> > > index df1b947792c8..d744fbb8612e 100644
> > > --- a/tools/lib/bpf/libbpf.map
> > > +++ b/tools/lib/bpf/libbpf.map
> > > @@ -442,6 +442,8 @@ LIBBPF_0.7.0 {
> > > 
> > >  LIBBPF_0.8.0 {
> > >         global:
> > > +               bpf_object__open_subskeleton;
> > > +               bpf_object__destroy_subskeleton;
> > 
> > nit: should be in alphabetic order
> > 
> > >                 libbpf_register_prog_handler;
> > >                 libbpf_unregister_prog_handler;
> > >  } LIBBPF_0.7.0;
> > > --
> > > 2.34.1
Andrii Nakryiko March 11, 2022, 11:41 p.m. UTC | #4
On Fri, Mar 11, 2022 at 3:28 PM Delyan Kratunov <delyank@fb.com> wrote:
>
> Thanks Andrii!
>
> On Fri, 2022-03-11 at 15:08 -0800, Andrii Nakryiko wrote:
> > On Fri, Mar 11, 2022 at 2:52 PM Andrii Nakryiko
> > <andrii.nakryiko@gmail.com> wrote:
> >
> > >
>
> [...]
>
> > > > +
> > > > +       err = populate_skeleton_maps(s->obj, s->maps, s->map_cnt);
> > > > +       if (err) {
> > > > +               pr_warn("failed to populate subskeleton maps: %d\n", err);
> > > > +               return libbpf_err(err);
> > > >         }
> > > >
> > > > -       for (i = 0; i < s->prog_cnt; i++) {
> > > > -               struct bpf_program **prog = s->progs[i].prog;
> > > > -               const char *name = s->progs[i].name;
> > > > +       err = populate_skeleton_progs(s->obj, s->progs, s->prog_cnt);
> > > > +       if (err) {
> > > > +               pr_warn("failed to populate subskeleton maps: %d\n", err);
> > > > +               return libbpf_err(err);
> > > > +       }
> > > >
> > > > -               *prog = bpf_object__find_program_by_name(obj, name);
> > > > -               if (!*prog) {
> > > > -                       pr_warn("failed to find skeleton program '%s'\n", name);
> > > > -                       return libbpf_err(-ESRCH);
> > > > +       for (var_idx = 0; var_idx < s->var_cnt; var_idx++) {
> > > > +               var_skel = &s->vars[var_idx];
> > > > +               map = *var_skel->map;
> > > > +               map_type_id = bpf_map__btf_value_type_id(map);
> > > > +               map_type = btf__type_by_id(btf, map_type_id);
> > > > +
> > >
> > > should we double-check that map_type is DATASEC?
>
> Sure, can do.
>
> > >
> > > > +               len = btf_vlen(map_type);
> > > > +               var = btf_var_secinfos(map_type);
> > > > +               for (i = 0; i < len; i++, var++) {
> > > > +                       var_type = btf__type_by_id(btf, var->type);
> > > > +                       if (!var_type) {
> > >
> > > unless BTF itself is corrupted, this shouldn't ever happen. So
> > > checking for DATASEC should be enough and this if (!var_type) is
> > > redundant
> > >
> > > > +                               pr_warn("Could not find var type for item %1$d in section %2$s",
> > > > +                                       i, bpf_map__name(map));
> > > > +                               return libbpf_err(-EINVAL);
> > > > +                       }
> > > > +                       var_name = btf__name_by_offset(btf, var_type->name_off);
> > > > +                       if (strcmp(var_name, var_skel->name) == 0) {
> > > > +                               *var_skel->addr = (char *) map->mmaped + var->offset;
> > >
> > > is (char *) cast necessary? C allows pointer adjustment on void *, so
> > > shouldn't be
> >
> > oh, wait, it's so that C++ compiler doesn't complain, never mind
>
> This is libbpf code, not subskel code, so it shouldn't get compiled as C++. It's
> really because of -Wpointer-arith and -Werror.

Oh, if it's libbpf code then it shouldn't be necessary, after all. I'm
pretty sure we assume in many places that we can do pointer arithmetic
on void *. Did you try and it didn't compile? Or you just did it
preemptively?

>
> >
> > >
> > > > +                               break;
> > > > +                       }
> > > >                 }
> > > >         }
> > > > -
> > > >         return 0;
> > > >  }
> > > >
> > >
> > > [...]
> > >
> > > >  struct gen_loader_opts {
> > > >         size_t sz; /* size of this struct, for forward/backward compatiblity */
> > > >         const char *data;
> > > > diff --git a/tools/lib/bpf/libbpf.map b/tools/lib/bpf/libbpf.map
> > > > index df1b947792c8..d744fbb8612e 100644
> > > > --- a/tools/lib/bpf/libbpf.map
> > > > +++ b/tools/lib/bpf/libbpf.map
> > > > @@ -442,6 +442,8 @@ LIBBPF_0.7.0 {
> > > >
> > > >  LIBBPF_0.8.0 {
> > > >         global:
> > > > +               bpf_object__open_subskeleton;
> > > > +               bpf_object__destroy_subskeleton;
> > >
> > > nit: should be in alphabetic order
> > >
> > > >                 libbpf_register_prog_handler;
> > > >                 libbpf_unregister_prog_handler;
> > > >  } LIBBPF_0.7.0;
> > > > --
> > > > 2.34.1
>
diff mbox series

Patch

diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c
index 3fb9c926fe6e..ba7b25b11486 100644
--- a/tools/lib/bpf/libbpf.c
+++ b/tools/lib/bpf/libbpf.c
@@ -11810,6 +11810,49 @@  int libbpf_num_possible_cpus(void)
 	return tmp_cpus;
 }
 
+static int populate_skeleton_maps(const struct bpf_object* obj,
+				  struct bpf_map_skeleton* maps,
+				  size_t map_cnt)
+{
+	int i;
+
+	for (i = 0; i < map_cnt; i++) {
+		struct bpf_map **map = maps[i].map;
+		const char *name = maps[i].name;
+		void **mmaped = maps[i].mmaped;
+
+		*map = bpf_object__find_map_by_name(obj, name);
+		if (!*map) {
+			pr_warn("failed to find skeleton map '%s'\n", name);
+			return libbpf_err(-ESRCH);
+		}
+
+		/* externs shouldn't be pre-setup from user code */
+		if (mmaped && (*map)->libbpf_type != LIBBPF_MAP_KCONFIG)
+			*mmaped = (*map)->mmaped;
+	}
+	return 0;
+}
+
+static int populate_skeleton_progs(const struct bpf_object* obj,
+				   struct bpf_prog_skeleton* progs,
+				   size_t prog_cnt)
+{
+	int i;
+
+	for (i = 0; i < prog_cnt; i++) {
+		struct bpf_program **prog = progs[i].prog;
+		const char *name = progs[i].name;
+
+		*prog = bpf_object__find_program_by_name(obj, name);
+		if (!*prog) {
+			pr_warn("failed to find skeleton program '%s'\n", name);
+			return libbpf_err(-ESRCH);
+		}
+	}
+	return 0;
+}
+
 int bpf_object__open_skeleton(struct bpf_object_skeleton *s,
 			      const struct bpf_object_open_opts *opts)
 {
@@ -11817,7 +11860,7 @@  int bpf_object__open_skeleton(struct bpf_object_skeleton *s,
 		.object_name = s->name,
 	);
 	struct bpf_object *obj;
-	int i, err;
+	int err;
 
 	/* Attempt to preserve opts->object_name, unless overriden by user
 	 * explicitly. Overwriting object name for skeletons is discouraged,
@@ -11840,37 +11883,88 @@  int bpf_object__open_skeleton(struct bpf_object_skeleton *s,
 	}
 
 	*s->obj = obj;
+	err = populate_skeleton_maps(obj, s->maps, s->map_cnt);
+	if (err) {
+		pr_warn("failed to populate skeleton maps for '%s': %d\n",
+			s->name, err);
+		return libbpf_err(err);
+	}
 
-	for (i = 0; i < s->map_cnt; i++) {
-		struct bpf_map **map = s->maps[i].map;
-		const char *name = s->maps[i].name;
-		void **mmaped = s->maps[i].mmaped;
+	err = populate_skeleton_progs(obj, s->progs, s->prog_cnt);
+	if (err) {
+		pr_warn("failed to populate skeleton progs for '%s': %d\n",
+			s->name, err);
+		return libbpf_err(err);
+	}
 
-		*map = bpf_object__find_map_by_name(obj, name);
-		if (!*map) {
-			pr_warn("failed to find skeleton map '%s'\n", name);
-			return libbpf_err(-ESRCH);
-		}
+	return 0;
+}
 
-		/* externs shouldn't be pre-setup from user code */
-		if (mmaped && (*map)->libbpf_type != LIBBPF_MAP_KCONFIG)
-			*mmaped = (*map)->mmaped;
+int bpf_object__open_subskeleton(struct bpf_object_subskeleton *s)
+{
+	int err, len, var_idx, i;
+	const char *var_name;
+	const struct bpf_map *map;
+	struct btf *btf;
+	__u32 map_type_id;
+	const struct btf_type *map_type, *var_type;
+	const struct bpf_var_skeleton *var_skel;
+	struct btf_var_secinfo *var;
+
+	if (!s->obj)
+		return libbpf_err(-EINVAL);
+
+	btf = bpf_object__btf(s->obj);
+	if (!btf)
+		return -errno;
+
+	err = populate_skeleton_maps(s->obj, s->maps, s->map_cnt);
+	if (err) {
+		pr_warn("failed to populate subskeleton maps: %d\n", err);
+		return libbpf_err(err);
 	}
 
-	for (i = 0; i < s->prog_cnt; i++) {
-		struct bpf_program **prog = s->progs[i].prog;
-		const char *name = s->progs[i].name;
+	err = populate_skeleton_progs(s->obj, s->progs, s->prog_cnt);
+	if (err) {
+		pr_warn("failed to populate subskeleton maps: %d\n", err);
+		return libbpf_err(err);
+	}
 
-		*prog = bpf_object__find_program_by_name(obj, name);
-		if (!*prog) {
-			pr_warn("failed to find skeleton program '%s'\n", name);
-			return libbpf_err(-ESRCH);
+	for (var_idx = 0; var_idx < s->var_cnt; var_idx++) {
+		var_skel = &s->vars[var_idx];
+		map = *var_skel->map;
+		map_type_id = bpf_map__btf_value_type_id(map);
+		map_type = btf__type_by_id(btf, map_type_id);
+
+		len = btf_vlen(map_type);
+		var = btf_var_secinfos(map_type);
+		for (i = 0; i < len; i++, var++) {
+			var_type = btf__type_by_id(btf, var->type);
+			if (!var_type) {
+				pr_warn("Could not find var type for item %1$d in section %2$s",
+					i, bpf_map__name(map));
+				return libbpf_err(-EINVAL);
+			}
+			var_name = btf__name_by_offset(btf, var_type->name_off);
+			if (strcmp(var_name, var_skel->name) == 0) {
+				*var_skel->addr = (char *) map->mmaped + var->offset;
+				break;
+			}
 		}
 	}
-
 	return 0;
 }
 
+void bpf_object__destroy_subskeleton(struct bpf_object_subskeleton *s)
+{
+	if (!s)
+		return;
+	free(s->maps);
+	free(s->progs);
+	free(s->vars);
+	free(s);
+}
+
 int bpf_object__load_skeleton(struct bpf_object_skeleton *s)
 {
 	int i, err;
diff --git a/tools/lib/bpf/libbpf.h b/tools/lib/bpf/libbpf.h
index c1b0c2ef14d8..1bff7647d797 100644
--- a/tools/lib/bpf/libbpf.h
+++ b/tools/lib/bpf/libbpf.h
@@ -1289,6 +1289,35 @@  LIBBPF_API int bpf_object__attach_skeleton(struct bpf_object_skeleton *s);
 LIBBPF_API void bpf_object__detach_skeleton(struct bpf_object_skeleton *s);
 LIBBPF_API void bpf_object__destroy_skeleton(struct bpf_object_skeleton *s);
 
+struct bpf_var_skeleton {
+	const char *name;
+	struct bpf_map **map;
+	void **addr;
+};
+
+struct bpf_object_subskeleton {
+	size_t sz; /* size of this struct, for forward/backward compatibility */
+
+	const struct bpf_object *obj;
+
+	int map_cnt;
+	int map_skel_sz; /* sizeof(struct bpf_map_skeleton) */
+	struct bpf_map_skeleton *maps;
+
+	int prog_cnt;
+	int prog_skel_sz; /* sizeof(struct bpf_prog_skeleton) */
+	struct bpf_prog_skeleton *progs;
+
+	int var_cnt;
+	int var_skel_sz; /* sizeof(struct bpf_var_skeleton) */
+	struct bpf_var_skeleton *vars;
+};
+
+LIBBPF_API int
+bpf_object__open_subskeleton(struct bpf_object_subskeleton *s);
+LIBBPF_API void
+bpf_object__destroy_subskeleton(struct bpf_object_subskeleton *s);
+
 struct gen_loader_opts {
 	size_t sz; /* size of this struct, for forward/backward compatiblity */
 	const char *data;
diff --git a/tools/lib/bpf/libbpf.map b/tools/lib/bpf/libbpf.map
index df1b947792c8..d744fbb8612e 100644
--- a/tools/lib/bpf/libbpf.map
+++ b/tools/lib/bpf/libbpf.map
@@ -442,6 +442,8 @@  LIBBPF_0.7.0 {
 
 LIBBPF_0.8.0 {
 	global:
+		bpf_object__open_subskeleton;
+		bpf_object__destroy_subskeleton;
 		libbpf_register_prog_handler;
 		libbpf_unregister_prog_handler;
 } LIBBPF_0.7.0;