libbpf: Refactor BTF-defined map definition parsing logic
authorAndrii Nakryiko <andriin@fb.com>
Wed, 29 Apr 2020 00:27:37 +0000 (17:27 -0700)
committerAlexei Starovoitov <ast@kernel.org>
Wed, 29 Apr 2020 00:35:03 +0000 (17:35 -0700)
Factor out BTF map definition logic into stand-alone routine for easier reuse
for map-in-map case.

Signed-off-by: Andrii Nakryiko <andriin@fb.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Link: https://lore.kernel.org/bpf/20200429002739.48006-2-andriin@fb.com
tools/lib/bpf/libbpf.c

index 8e1dc69..7d10436 100644 (file)
@@ -1914,109 +1914,54 @@ static int build_map_pin_path(struct bpf_map *map, const char *path)
        return 0;
 }
 
-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)
+
+static int parse_btf_map_def(struct bpf_object *obj,
+                            struct bpf_map *map,
+                            const struct btf_type *def,
+                            bool strict,
+                            const char *pin_root_path)
 {
-       const struct btf_type *var, *def, *t;
-       const struct btf_var_secinfo *vi;
-       const struct btf_var *var_extra;
+       const struct btf_type *t;
        const struct btf_member *m;
-       const char *map_name;
-       struct bpf_map *map;
        int vlen, i;
 
-       vi = btf_var_secinfos(sec) + var_idx;
-       var = btf__type_by_id(obj->btf, vi->type);
-       var_extra = btf_var(var);
-       map_name = btf__name_by_offset(obj->btf, var->name_off);
-       vlen = btf_vlen(var);
-
-       if (map_name == NULL || map_name[0] == '\0') {
-               pr_warn("map #%d: empty name.\n", var_idx);
-               return -EINVAL;
-       }
-       if ((__u64)vi->offset + vi->size > data->d_size) {
-               pr_warn("map '%s' BTF data is corrupted.\n", map_name);
-               return -EINVAL;
-       }
-       if (!btf_is_var(var)) {
-               pr_warn("map '%s': unexpected var kind %u.\n",
-                       map_name, btf_kind(var));
-               return -EINVAL;
-       }
-       if (var_extra->linkage != BTF_VAR_GLOBAL_ALLOCATED &&
-           var_extra->linkage != BTF_VAR_STATIC) {
-               pr_warn("map '%s': unsupported var linkage %u.\n",
-                       map_name, var_extra->linkage);
-               return -EOPNOTSUPP;
-       }
-
-       def = skip_mods_and_typedefs(obj->btf, var->type, NULL);
-       if (!btf_is_struct(def)) {
-               pr_warn("map '%s': unexpected def kind %u.\n",
-                       map_name, btf_kind(var));
-               return -EINVAL;
-       }
-       if (def->size > vi->size) {
-               pr_warn("map '%s': invalid def size.\n", map_name);
-               return -EINVAL;
-       }
-
-       map = bpf_object__add_map(obj);
-       if (IS_ERR(map))
-               return PTR_ERR(map);
-       map->name = strdup(map_name);
-       if (!map->name) {
-               pr_warn("map '%s': failed to alloc map name.\n", map_name);
-               return -ENOMEM;
-       }
-       map->libbpf_type = LIBBPF_MAP_UNSPEC;
-       map->def.type = BPF_MAP_TYPE_UNSPEC;
-       map->sec_idx = sec_idx;
-       map->sec_offset = vi->offset;
-       pr_debug("map '%s': at sec_idx %d, offset %zu.\n",
-                map_name, map->sec_idx, map->sec_offset);
-
        vlen = btf_vlen(def);
        m = btf_members(def);
        for (i = 0; i < vlen; i++, m++) {
                const char *name = btf__name_by_offset(obj->btf, m->name_off);
 
                if (!name) {
-                       pr_warn("map '%s': invalid field #%d.\n", map_name, i);
+                       pr_warn("map '%s': invalid field #%d.\n", map->name, i);
                        return -EINVAL;
                }
                if (strcmp(name, "type") == 0) {
-                       if (!get_map_field_int(map_name, obj->btf, m,
+                       if (!get_map_field_int(map->name, obj->btf, m,
                                               &map->def.type))
                                return -EINVAL;
                        pr_debug("map '%s': found type = %u.\n",
-                                map_name, map->def.type);
+                                map->name, map->def.type);
                } else if (strcmp(name, "max_entries") == 0) {
-                       if (!get_map_field_int(map_name, obj->btf, m,
+                       if (!get_map_field_int(map->name, obj->btf, m,
                                               &map->def.max_entries))
                                return -EINVAL;
                        pr_debug("map '%s': found max_entries = %u.\n",
-                                map_name, map->def.max_entries);
+                                map->name, map->def.max_entries);
                } else if (strcmp(name, "map_flags") == 0) {
-                       if (!get_map_field_int(map_name, obj->btf, m,
+                       if (!get_map_field_int(map->name, obj->btf, m,
                                               &map->def.map_flags))
                                return -EINVAL;
                        pr_debug("map '%s': found map_flags = %u.\n",
-                                map_name, map->def.map_flags);
+                                map->name, map->def.map_flags);
                } else if (strcmp(name, "key_size") == 0) {
                        __u32 sz;
 
-                       if (!get_map_field_int(map_name, obj->btf, m, &sz))
+                       if (!get_map_field_int(map->name, obj->btf, m, &sz))
                                return -EINVAL;
                        pr_debug("map '%s': found key_size = %u.\n",
-                                map_name, sz);
+                                map->name, sz);
                        if (map->def.key_size && map->def.key_size != sz) {
                                pr_warn("map '%s': conflicting key size %u != %u.\n",
-                                       map_name, map->def.key_size, sz);
+                                       map->name, map->def.key_size, sz);
                                return -EINVAL;
                        }
                        map->def.key_size = sz;
@@ -2026,25 +1971,25 @@ static int bpf_object__init_user_btf_map(struct bpf_object *obj,
                        t = btf__type_by_id(obj->btf, m->type);
                        if (!t) {
                                pr_warn("map '%s': key type [%d] not found.\n",
-                                       map_name, m->type);
+                                       map->name, m->type);
                                return -EINVAL;
                        }
                        if (!btf_is_ptr(t)) {
                                pr_warn("map '%s': key spec is not PTR: %u.\n",
-                                       map_name, btf_kind(t));
+                                       map->name, btf_kind(t));
                                return -EINVAL;
                        }
                        sz = btf__resolve_size(obj->btf, t->type);
                        if (sz < 0) {
                                pr_warn("map '%s': can't determine key size for type [%u]: %zd.\n",
-                                       map_name, t->type, (ssize_t)sz);
+                                       map->name, t->type, (ssize_t)sz);
                                return sz;
                        }
                        pr_debug("map '%s': found key [%u], sz = %zd.\n",
-                                map_name, t->type, (ssize_t)sz);
+                                map->name, t->type, (ssize_t)sz);
                        if (map->def.key_size && map->def.key_size != sz) {
                                pr_warn("map '%s': conflicting key size %u != %zd.\n",
-                                       map_name, map->def.key_size, (ssize_t)sz);
+                                       map->name, map->def.key_size, (ssize_t)sz);
                                return -EINVAL;
                        }
                        map->def.key_size = sz;
@@ -2052,13 +1997,13 @@ static int bpf_object__init_user_btf_map(struct bpf_object *obj,
                } else if (strcmp(name, "value_size") == 0) {
                        __u32 sz;
 
-                       if (!get_map_field_int(map_name, obj->btf, m, &sz))
+                       if (!get_map_field_int(map->name, obj->btf, m, &sz))
                                return -EINVAL;
                        pr_debug("map '%s': found value_size = %u.\n",
-                                map_name, sz);
+                                map->name, sz);
                        if (map->def.value_size && map->def.value_size != sz) {
                                pr_warn("map '%s': conflicting value size %u != %u.\n",
-                                       map_name, map->def.value_size, sz);
+                                       map->name, map->def.value_size, sz);
                                return -EINVAL;
                        }
                        map->def.value_size = sz;
@@ -2068,25 +2013,25 @@ static int bpf_object__init_user_btf_map(struct bpf_object *obj,
                        t = btf__type_by_id(obj->btf, m->type);
                        if (!t) {
                                pr_warn("map '%s': value type [%d] not found.\n",
-                                       map_name, m->type);
+                                       map->name, m->type);
                                return -EINVAL;
                        }
                        if (!btf_is_ptr(t)) {
                                pr_warn("map '%s': value spec is not PTR: %u.\n",
-                                       map_name, btf_kind(t));
+                                       map->name, btf_kind(t));
                                return -EINVAL;
                        }
                        sz = btf__resolve_size(obj->btf, t->type);
                        if (sz < 0) {
                                pr_warn("map '%s': can't determine value size for type [%u]: %zd.\n",
-                                       map_name, t->type, (ssize_t)sz);
+                                       map->name, t->type, (ssize_t)sz);
                                return sz;
                        }
                        pr_debug("map '%s': found value [%u], sz = %zd.\n",
-                                map_name, t->type, (ssize_t)sz);
+                                map->name, t->type, (ssize_t)sz);
                        if (map->def.value_size && map->def.value_size != sz) {
                                pr_warn("map '%s': conflicting value size %u != %zd.\n",
-                                       map_name, map->def.value_size, (ssize_t)sz);
+                                       map->name, map->def.value_size, (ssize_t)sz);
                                return -EINVAL;
                        }
                        map->def.value_size = sz;
@@ -2095,44 +2040,110 @@ static int bpf_object__init_user_btf_map(struct bpf_object *obj,
                        __u32 val;
                        int err;
 
-                       if (!get_map_field_int(map_name, obj->btf, m, &val))
+                       if (!get_map_field_int(map->name, obj->btf, m, &val))
                                return -EINVAL;
                        pr_debug("map '%s': found pinning = %u.\n",
-                                map_name, val);
+                                map->name, val);
 
                        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);
+                                               map->name);
                                        return err;
                                }
                        }
                } else {
                        if (strict) {
                                pr_warn("map '%s': unknown field '%s'.\n",
-                                       map_name, name);
+                                       map->name, name);
                                return -ENOTSUP;
                        }
                        pr_debug("map '%s': ignoring unknown field '%s'.\n",
-                                map_name, name);
+                                map->name, name);
                }
        }
 
        if (map->def.type == BPF_MAP_TYPE_UNSPEC) {
-               pr_warn("map '%s': map type isn't specified.\n", map_name);
+               pr_warn("map '%s': map type isn't specified.\n", map->name);
                return -EINVAL;
        }
 
        return 0;
 }
 
+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)
+{
+       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;
+
+       vi = btf_var_secinfos(sec) + var_idx;
+       var = btf__type_by_id(obj->btf, vi->type);
+       var_extra = btf_var(var);
+       map_name = btf__name_by_offset(obj->btf, var->name_off);
+
+       if (map_name == NULL || map_name[0] == '\0') {
+               pr_warn("map #%d: empty name.\n", var_idx);
+               return -EINVAL;
+       }
+       if ((__u64)vi->offset + vi->size > data->d_size) {
+               pr_warn("map '%s' BTF data is corrupted.\n", map_name);
+               return -EINVAL;
+       }
+       if (!btf_is_var(var)) {
+               pr_warn("map '%s': unexpected var kind %u.\n",
+                       map_name, btf_kind(var));
+               return -EINVAL;
+       }
+       if (var_extra->linkage != BTF_VAR_GLOBAL_ALLOCATED &&
+           var_extra->linkage != BTF_VAR_STATIC) {
+               pr_warn("map '%s': unsupported var linkage %u.\n",
+                       map_name, var_extra->linkage);
+               return -EOPNOTSUPP;
+       }
+
+       def = skip_mods_and_typedefs(obj->btf, var->type, NULL);
+       if (!btf_is_struct(def)) {
+               pr_warn("map '%s': unexpected def kind %u.\n",
+                       map_name, btf_kind(var));
+               return -EINVAL;
+       }
+       if (def->size > vi->size) {
+               pr_warn("map '%s': invalid def size.\n", map_name);
+               return -EINVAL;
+       }
+
+       map = bpf_object__add_map(obj);
+       if (IS_ERR(map))
+               return PTR_ERR(map);
+       map->name = strdup(map_name);
+       if (!map->name) {
+               pr_warn("map '%s': failed to alloc map name.\n", map_name);
+               return -ENOMEM;
+       }
+       map->libbpf_type = LIBBPF_MAP_UNSPEC;
+       map->def.type = BPF_MAP_TYPE_UNSPEC;
+       map->sec_idx = sec_idx;
+       map->sec_offset = vi->offset;
+       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, pin_root_path);
+}
+
 static int bpf_object__init_user_btf_maps(struct bpf_object *obj, bool strict,
                                          const char *pin_root_path)
 {