All of lore.kernel.org
 help / color / mirror / Atom feed
From: Andrii Nakryiko <andrii.nakryiko@gmail.com>
To: Yonghong Song <yhs@fb.com>
Cc: Andrii Nakryiko <andrii@kernel.org>, bpf <bpf@vger.kernel.org>,
	Networking <netdev@vger.kernel.org>,
	Alexei Starovoitov <ast@fb.com>,
	Daniel Borkmann <daniel@iogearbox.net>,
	Kernel Team <kernel-team@fb.com>
Subject: Re: [PATCH v2 bpf-next 06/17] libbpf: refactor BTF map definition parsing
Date: Thu, 22 Apr 2021 11:40:42 -0700	[thread overview]
Message-ID: <CAEf4Bzb40Ki+eZdKJ+QFnzuaburPRC6v4fVPtiWXtj5ZyWLg=A@mail.gmail.com> (raw)
In-Reply-To: <0ae37c13-e8d9-b0ca-00ca-1750dc2799c9@fb.com>

On Thu, Apr 22, 2021 at 8:33 AM Yonghong Song <yhs@fb.com> wrote:
>
>
>
> On 4/16/21 1:23 PM, Andrii Nakryiko wrote:
> > Refactor BTF-defined maps parsing logic to allow it to be nicely reused by BPF
> > static linker. Further, at least for BPF static linker, it's important to know
> > which attributes of a BPF map were defined explicitly, so provide a bit set
> > for each known portion of BTF map definition. This allows BPF static linker to
> > do a simple check when dealing with extern map declarations.
> >
> > The same capabilities allow to distinguish attributes explicitly set to zero
> > (e.g., __uint(max_entries, 0)) vs the case of not specifying it at all (no
> > max_entries attribute at all). Libbpf is currently not utilizing that, but it
> > could be useful for backwards compatibility reasons later.
> >
> > Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
> > ---
> >   tools/lib/bpf/libbpf.c          | 256 ++++++++++++++++++--------------
> >   tools/lib/bpf/libbpf_internal.h |  32 ++++
> >   2 files changed, 177 insertions(+), 111 deletions(-)
> >
> > diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c
> > index a0e6d6bc47f3..f6f4126389ac 100644
> > --- a/tools/lib/bpf/libbpf.c
> > +++ b/tools/lib/bpf/libbpf.c
> > @@ -2025,255 +2025,262 @@ static int build_map_pin_path(struct bpf_map *map, const char *path)
> >       return bpf_map__set_pin_path(map, buf);
> >   }
> >
> > -
> > -static int parse_btf_map_def(struct bpf_object *obj,
> > -                          struct bpf_map *map,
> > -                          const struct btf_type *def,
> > -                          bool strict, bool is_inner,
> > -                          const char *pin_root_path)
> > +int parse_btf_map_def(const char *map_name, struct btf *btf,
> > +                   const struct btf_type *def_t, bool strict,
> > +                   struct btf_map_def *map_def, struct btf_map_def *inner_def)
> >   {
> >       const struct btf_type *t;
> >       const struct btf_member *m;
> > +     bool is_inner = inner_def == NULL;
> >       int vlen, i;
> >
> > -     vlen = btf_vlen(def);
> > -     m = btf_members(def);
> > +     vlen = btf_vlen(def_t);
> > +     m = btf_members(def_t);
> >       for (i = 0; i < vlen; i++, m++) {
> > -             const char *name = btf__name_by_offset(obj->btf, m->name_off);
> > +             const char *name = btf__name_by_offset(btf, m->name_off);
> >
> [...]
> >               }
> >               else if (strcmp(name, "values") == 0) {
> > +                     char inner_map_name[128];
> >                       int err;
> >
> >                       if (is_inner) {
> >                               pr_warn("map '%s': multi-level inner maps not supported.\n",
> > -                                     map->name);
> > +                                     map_name);
> >                               return -ENOTSUP;
> >                       }
> >                       if (i != vlen - 1) {
> >                               pr_warn("map '%s': '%s' member should be last.\n",
> > -                                     map->name, name);
> > +                                     map_name, name);
> >                               return -EINVAL;
> >                       }
> > -                     if (!bpf_map_type__is_map_in_map(map->def.type)) {
> > +                     if (!bpf_map_type__is_map_in_map(map_def->map_type)) {
> >                               pr_warn("map '%s': should be map-in-map.\n",
> > -                                     map->name);
> > +                                     map_name);
> >                               return -ENOTSUP;
> >                       }
> > -                     if (map->def.value_size && map->def.value_size != 4) {
> > +                     if (map_def->value_size && map_def->value_size != 4) {
> >                               pr_warn("map '%s': conflicting value size %u != 4.\n",
> > -                                     map->name, map->def.value_size);
> > +                                     map_name, map_def->value_size);
> >                               return -EINVAL;
> >                       }
> > -                     map->def.value_size = 4;
> > -                     t = btf__type_by_id(obj->btf, m->type);
> > +                     map_def->value_size = 4;
> > +                     t = btf__type_by_id(btf, m->type);
> >                       if (!t) {
> >                               pr_warn("map '%s': map-in-map inner type [%d] not found.\n",
> > -                                     map->name, m->type);
> > +                                     map_name, m->type);
> >                               return -EINVAL;
> >                       }
> >                       if (!btf_is_array(t) || btf_array(t)->nelems) {
> >                               pr_warn("map '%s': map-in-map inner spec is not a zero-sized array.\n",
> > -                                     map->name);
> > +                                     map_name);
> >                               return -EINVAL;
> >                       }
> > -                     t = skip_mods_and_typedefs(obj->btf, btf_array(t)->type,
> > -                                                NULL);
> > +                     t = skip_mods_and_typedefs(btf, btf_array(t)->type, NULL);
> >                       if (!btf_is_ptr(t)) {
> >                               pr_warn("map '%s': map-in-map inner def is of unexpected kind %s.\n",
> > -                                     map->name, btf_kind_str(t));
> > +                                     map_name, btf_kind_str(t));
> >                               return -EINVAL;
> >                       }
> > -                     t = skip_mods_and_typedefs(obj->btf, t->type, NULL);
> > +                     t = skip_mods_and_typedefs(btf, t->type, NULL);
> >                       if (!btf_is_struct(t)) {
> >                               pr_warn("map '%s': map-in-map inner def is of unexpected kind %s.\n",
> > -                                     map->name, btf_kind_str(t));
> > +                                     map_name, btf_kind_str(t));
> >                               return -EINVAL;
> >                       }
> >
> > -                     map->inner_map = calloc(1, sizeof(*map->inner_map));
> > -                     if (!map->inner_map)
> > -                             return -ENOMEM;
> > -                     map->inner_map->fd = -1;
> > -                     map->inner_map->sec_idx = obj->efile.btf_maps_shndx;
>
> The refactoring didn't set map->inner_map->sec_idx. I guess since
> inner_map is only used internally by libbpf, so it does not
> have a user visible sec_idx and hence useless? It is worthwhile to
> mention in the commit message for this difference, I think.
>
> > -                     map->inner_map->name = malloc(strlen(map->name) +
> > -                                                   sizeof(".inner") + 1);
> > -                     if (!map->inner_map->name)
> > -                             return -ENOMEM;
> > -                     sprintf(map->inner_map->name, "%s.inner", map->name);
> > -
> > -                     err = parse_btf_map_def(obj, map->inner_map, t, strict,
> > -                                             true /* is_inner */, NULL);
> > +                     snprintf(inner_map_name, sizeof(inner_map_name), "%s.inner", map_name);
> > +                     err = parse_btf_map_def(inner_map_name, btf, t, strict, inner_def, NULL);
> >                       if (err)
> >                               return err;
> > +
> > +                     map_def->parts |= MAP_DEF_INNER_MAP;
> >               } else if (strcmp(name, "pinning") == 0) {
> >                       __u32 val;
> > -                     int err;
> >
> >                       if (is_inner) {
> > -                             pr_debug("map '%s': inner def can't be pinned.\n",
> > -                                      map->name);
> > +                             pr_warn("map '%s': inner def can't be pinned.\n", map_name);
> >                               return -EINVAL;
> >                       }
> > -                     if (!get_map_field_int(map->name, obj->btf, m, &val))
> > +                     if (!get_map_field_int(map_name, btf, m, &val))
> >                               return -EINVAL;
> > -                     pr_debug("map '%s': found pinning = %u.\n",
> > -                              map->name, val);
> > -
> > -                     if (val != LIBBPF_PIN_NONE &&
> > -                         val != LIBBPF_PIN_BY_NAME) {
> > +                     if (val != LIBBPF_PIN_NONE && val != LIBBPF_PIN_BY_NAME) {
> >                               pr_warn("map '%s': invalid pinning value %u.\n",
> > -                                     map->name, val);
> > +                                     map_name, val);
> >                               return -EINVAL;
> >                       }
> > -                     if (val == LIBBPF_PIN_BY_NAME) {
> > -                             err = build_map_pin_path(map, pin_root_path);
> > -                             if (err) {
> > -                                     pr_warn("map '%s': couldn't build pin path.\n",
> > -                                             map->name);
> > -                                     return err;
> > -                             }
> > -                     }
> > +                     map_def->pinning = val;
> > +                     map_def->parts |= MAP_DEF_PINNING;
> >               } else {
> >                       if (strict) {
> > -                             pr_warn("map '%s': unknown field '%s'.\n",
> > -                                     map->name, name);
> > +                             pr_warn("map '%s': unknown field '%s'.\n", map_name, name);
> >                               return -ENOTSUP;
> >                       }
> > -                     pr_debug("map '%s': ignoring unknown field '%s'.\n",
> > -                              map->name, name);
> > +                     pr_debug("map '%s': ignoring unknown field '%s'.\n", map_name, name);
> >               }
> >       }
> >
> > -     if (map->def.type == BPF_MAP_TYPE_UNSPEC) {
> > -             pr_warn("map '%s': map type isn't specified.\n", map->name);
> > +     if (map_def->map_type == BPF_MAP_TYPE_UNSPEC) {
> > +             pr_warn("map '%s': map type isn't specified.\n", map_name);
> >               return -EINVAL;
> >       }
> >
> >       return 0;
> >   }
> >
> > +static void fill_map_from_def(struct bpf_map *map, const struct btf_map_def *def)
> > +{
> [...]
> > +}
> > +
> >   static int bpf_object__init_user_btf_map(struct bpf_object *obj,
> >                                        const struct btf_type *sec,
> >                                        int var_idx, int sec_idx,
> >                                        const Elf_Data *data, bool strict,
> >                                        const char *pin_root_path)
> >   {
> > +     struct btf_map_def map_def = {}, inner_def = {};
> >       const struct btf_type *var, *def;
> >       const struct btf_var_secinfo *vi;
> >       const struct btf_var *var_extra;
> >       const char *map_name;
> >       struct bpf_map *map;
> > +     int err;
> >
> >       vi = btf_var_secinfos(sec) + var_idx;
> >       var = btf__type_by_id(obj->btf, vi->type);
> > @@ -2327,7 +2334,34 @@ static int bpf_object__init_user_btf_map(struct bpf_object *obj,
> >       pr_debug("map '%s': at sec_idx %d, offset %zu.\n",
> >                map_name, map->sec_idx, map->sec_offset);
> >
> > -     return parse_btf_map_def(obj, map, def, strict, false, pin_root_path);
> > +     err = parse_btf_map_def(map->name, obj->btf, def, strict, &map_def, &inner_def);
> > +     if (err)
> > +             return err;
> > +
> > +     fill_map_from_def(map, &map_def);
> > +
> > +     if (map_def.pinning == LIBBPF_PIN_BY_NAME) {
> > +             err = build_map_pin_path(map, pin_root_path);
> > +             if (err) {
> > +                     pr_warn("map '%s': couldn't build pin path.\n", map->name);
> > +                     return err;
> > +             }
> > +     }
> > +
> > +     if (map_def.parts & MAP_DEF_INNER_MAP) {
> > +             map->inner_map = calloc(1, sizeof(*map->inner_map));
> > +             if (!map->inner_map)
> > +                     return -ENOMEM;
> > +             map->inner_map->fd = -1;
>
> missing set map->inner_map->sec_idx here.

I'll add it back here, but it was never really necessary. More for the
completeness sake. sec_idx is used only to match relo to a map, and
this inner_map is never matched and never referenced by a relocation.

>
> > +             map->inner_map->name = malloc(strlen(map_name) + sizeof(".inner") + 1);
> > +             if (!map->inner_map->name)
> > +                     return -ENOMEM;
> > +             sprintf(map->inner_map->name, "%s.inner", map_name);
> > +
> > +             fill_map_from_def(map->inner_map, &inner_def);
> > +     }
> > +
> > +     return 0;
> >   }
> >
> >   static int bpf_object__init_user_btf_maps(struct bpf_object *obj, bool strict,
> > diff --git a/tools/lib/bpf/libbpf_internal.h b/tools/lib/bpf/libbpf_internal.h
> > index 92b7eae10c6d..17883073710c 100644
> > --- a/tools/lib/bpf/libbpf_internal.h
> > +++ b/tools/lib/bpf/libbpf_internal.h
> > @@ -138,6 +138,38 @@ static inline __u32 btf_type_info(int kind, int vlen, int kflag)
> >       return (kflag << 31) | (kind << 24) | vlen;
> >   }
> >
> [...]

  reply	other threads:[~2021-04-22 18:40 UTC|newest]

Thread overview: 67+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-04-16 20:23 [PATCH v2 bpf-next 00/17] BPF static linker: support externs Andrii Nakryiko
2021-04-16 20:23 ` [PATCH v2 bpf-next 01/17] bpftool: support dumping BTF VAR's "extern" linkage Andrii Nakryiko
2021-04-22  3:02   ` Yonghong Song
2021-04-16 20:23 ` [PATCH v2 bpf-next 02/17] bpftool: dump more info about DATASEC members Andrii Nakryiko
2021-04-22  3:09   ` Yonghong Song
2021-04-16 20:23 ` [PATCH v2 bpf-next 03/17] libbpf: suppress compiler warning when using SEC() macro with externs Andrii Nakryiko
2021-04-22  3:47   ` Yonghong Song
2021-04-22  3:59     ` Andrii Nakryiko
2021-04-16 20:23 ` [PATCH v2 bpf-next 04/17] libbpf: mark BPF subprogs with hidden visibility as static for BPF verifier Andrii Nakryiko
2021-04-22  5:43   ` Yonghong Song
2021-04-22 18:09     ` Andrii Nakryiko
2021-04-22 23:00       ` Yonghong Song
2021-04-22 23:28         ` Andrii Nakryiko
2021-04-16 20:23 ` [PATCH v2 bpf-next 05/17] libbpf: allow gaps in BPF program sections to support overriden weak functions Andrii Nakryiko
2021-04-22  6:25   ` Yonghong Song
2021-04-22 18:10     ` Andrii Nakryiko
2021-04-16 20:23 ` [PATCH v2 bpf-next 06/17] libbpf: refactor BTF map definition parsing Andrii Nakryiko
2021-04-22 15:33   ` Yonghong Song
2021-04-22 18:40     ` Andrii Nakryiko [this message]
2021-04-16 20:23 ` [PATCH v2 bpf-next 07/17] libbpf: factor out symtab and relos sanity checks Andrii Nakryiko
2021-04-22 16:06   ` Yonghong Song
2021-04-22 18:16     ` Andrii Nakryiko
2021-04-16 20:23 ` [PATCH v2 bpf-next 08/17] libbpf: make few internal helpers available outside of libbpf.c Andrii Nakryiko
2021-04-22 16:19   ` Yonghong Song
2021-04-22 18:18     ` Andrii Nakryiko
2021-04-16 20:23 ` [PATCH v2 bpf-next 09/17] libbpf: extend sanity checking ELF symbols with externs validation Andrii Nakryiko
2021-04-22 16:35   ` Yonghong Song
2021-04-22 18:20     ` Andrii Nakryiko
2021-04-22 23:13       ` Yonghong Song
2021-04-16 20:23 ` [PATCH v2 bpf-next 10/17] libbpf: tighten BTF type ID rewriting with error checking Andrii Nakryiko
2021-04-22 16:50   ` Yonghong Song
2021-04-22 18:24     ` Andrii Nakryiko
2021-04-23  2:54       ` Alexei Starovoitov
2021-04-23  4:25         ` Andrii Nakryiko
2021-04-23  5:11           ` Alexei Starovoitov
2021-04-23 16:09             ` Andrii Nakryiko
2021-04-23 16:18               ` Alexei Starovoitov
2021-04-23 16:30                 ` Andrii Nakryiko
2021-04-23 16:34                   ` Alexei Starovoitov
2021-04-23 17:02                     ` Andrii Nakryiko
2021-04-16 20:23 ` [PATCH v2 bpf-next 11/17] libbpf: add linker extern resolution support for functions and global variables Andrii Nakryiko
2021-04-22 21:27   ` Yonghong Song
2021-04-22 22:12     ` Andrii Nakryiko
2021-04-22 23:57       ` Yonghong Song
2021-04-23  2:36         ` Yonghong Song
2021-04-23  4:28           ` Andrii Nakryiko
2021-04-23  4:27         ` Andrii Nakryiko
2021-04-16 20:23 ` [PATCH v2 bpf-next 12/17] libbpf: support extern resolution for BTF-defined maps in .maps section Andrii Nakryiko
2021-04-22 22:56   ` Yonghong Song
2021-04-22 23:32     ` Andrii Nakryiko
2021-04-16 20:24 ` [PATCH v2 bpf-next 13/17] selftests/bpf: use -O0 instead of -Og in selftests builds Andrii Nakryiko
2021-04-23  0:05   ` Yonghong Song
2021-04-16 20:24 ` [PATCH v2 bpf-next 14/17] selftests/bpf: omit skeleton generation for multi-linked BPF object files Andrii Nakryiko
2021-04-23  0:13   ` Yonghong Song
2021-04-16 20:24 ` [PATCH v2 bpf-next 15/17] selftests/bpf: add function linking selftest Andrii Nakryiko
2021-04-23  0:50   ` Yonghong Song
2021-04-23  2:34     ` Alexei Starovoitov
2021-04-23  4:29       ` Andrii Nakryiko
2021-04-23 17:18     ` Andrii Nakryiko
2021-04-23 17:35       ` Yonghong Song
2021-04-23 17:55         ` Andrii Nakryiko
2021-04-23 17:58           ` Yonghong Song
2021-04-23 17:59             ` Andrii Nakryiko
2021-04-16 20:24 ` [PATCH v2 bpf-next 16/17] selftests/bpf: add global variables " Andrii Nakryiko
2021-04-23  1:01   ` Yonghong Song
2021-04-16 20:24 ` [PATCH v2 bpf-next 17/17] sleftests/bpf: add map " Andrii Nakryiko
2021-04-23  1:20   ` Yonghong Song

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to='CAEf4Bzb40Ki+eZdKJ+QFnzuaburPRC6v4fVPtiWXtj5ZyWLg=A@mail.gmail.com' \
    --to=andrii.nakryiko@gmail.com \
    --cc=andrii@kernel.org \
    --cc=ast@fb.com \
    --cc=bpf@vger.kernel.org \
    --cc=daniel@iogearbox.net \
    --cc=kernel-team@fb.com \
    --cc=netdev@vger.kernel.org \
    --cc=yhs@fb.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.