Skip to content

Commit

Permalink
bpftool: Switch to libbpf's hashmap for programs/maps in BTF listing
Browse files Browse the repository at this point in the history
In order to show BPF programs and maps using BTF objects when the latter
are being listed, bpftool creates hash maps to store all relevant items.
This commit is part of a set that transitions from the kernel's hash map
implementation to the one coming with libbpf.

The motivation is to make bpftool less dependent of kernel headers, to
ease the path to a potential out-of-tree mirror, like libbpf has.

This commit focuses on the two hash maps used by bpftool when listing
BTF objects to store references to programs and maps, and convert them
to the libbpf's implementation.

Signed-off-by: Quentin Monnet <quentin@isovalent.com>
Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
Link: https://lore.kernel.org/bpf/20211023205154.6710-5-quentin@isovalent.com
  • Loading branch information
Quentin Monnet authored and Andrii Nakryiko committed Oct 26, 2021
1 parent 8f18473 commit 2828d0d
Show file tree
Hide file tree
Showing 2 changed files with 62 additions and 68 deletions.
125 changes: 57 additions & 68 deletions tools/bpf/bpftool/btf.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,16 @@
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <bpf/bpf.h>
#include <bpf/btf.h>
#include <bpf/libbpf.h>
#include <linux/btf.h>
#include <linux/hashtable.h>
#include <sys/types.h>
#include <sys/stat.h>

#include <bpf/bpf.h>
#include <bpf/btf.h>
#include <bpf/hashmap.h>
#include <bpf/libbpf.h>

#include "json_writer.h"
#include "main.h"

Expand All @@ -40,14 +42,9 @@ static const char * const btf_kind_str[NR_BTF_KINDS] = {
[BTF_KIND_DECL_TAG] = "DECL_TAG",
};

struct btf_attach_table {
DECLARE_HASHTABLE(table, 16);
};

struct btf_attach_point {
__u32 obj_id;
__u32 btf_id;
struct hlist_node hash;
};

static const char *btf_int_enc_str(__u8 encoding)
Expand Down Expand Up @@ -645,29 +642,15 @@ static int btf_parse_fd(int *argc, char ***argv)
return fd;
}

static void delete_btf_table(struct btf_attach_table *tab)
{
struct btf_attach_point *obj;
struct hlist_node *tmp;

unsigned int bkt;

hash_for_each_safe(tab->table, bkt, tmp, obj, hash) {
hash_del(&obj->hash);
free(obj);
}
}

static int
build_btf_type_table(struct btf_attach_table *tab, enum bpf_obj_type type,
build_btf_type_table(struct hashmap *tab, enum bpf_obj_type type,
void *info, __u32 *len)
{
static const char * const names[] = {
[BPF_OBJ_UNKNOWN] = "unknown",
[BPF_OBJ_PROG] = "prog",
[BPF_OBJ_MAP] = "map",
};
struct btf_attach_point *obj_node;
__u32 btf_id, id = 0;
int err;
int fd;
Expand Down Expand Up @@ -741,28 +724,25 @@ build_btf_type_table(struct btf_attach_table *tab, enum bpf_obj_type type,
if (!btf_id)
continue;

obj_node = calloc(1, sizeof(*obj_node));
if (!obj_node) {
p_err("failed to allocate memory: %s", strerror(errno));
err = -ENOMEM;
err = hashmap__append(tab, u32_as_hash_field(btf_id),
u32_as_hash_field(id));
if (err) {
p_err("failed to append entry to hashmap for BTF ID %u, object ID %u: %s",
btf_id, id, strerror(errno));
goto err_free;
}

obj_node->obj_id = id;
obj_node->btf_id = btf_id;
hash_add(tab->table, &obj_node->hash, obj_node->btf_id);
}

return 0;

err_free:
delete_btf_table(tab);
hashmap__free(tab);
return err;
}

static int
build_btf_tables(struct btf_attach_table *btf_prog_table,
struct btf_attach_table *btf_map_table)
build_btf_tables(struct hashmap *btf_prog_table,
struct hashmap *btf_map_table)
{
struct bpf_prog_info prog_info;
__u32 prog_len = sizeof(prog_info);
Expand All @@ -778,7 +758,7 @@ build_btf_tables(struct btf_attach_table *btf_prog_table,
err = build_btf_type_table(btf_map_table, BPF_OBJ_MAP, &map_info,
&map_len);
if (err) {
delete_btf_table(btf_prog_table);
hashmap__free(btf_prog_table);
return err;
}

Expand All @@ -787,10 +767,10 @@ build_btf_tables(struct btf_attach_table *btf_prog_table,

static void
show_btf_plain(struct bpf_btf_info *info, int fd,
struct btf_attach_table *btf_prog_table,
struct btf_attach_table *btf_map_table)
struct hashmap *btf_prog_table,
struct hashmap *btf_map_table)
{
struct btf_attach_point *obj;
struct hashmap_entry *entry;
const char *name = u64_to_ptr(info->name);
int n;

Expand All @@ -804,29 +784,30 @@ show_btf_plain(struct bpf_btf_info *info, int fd,
printf("size %uB", info->btf_size);

n = 0;
hash_for_each_possible(btf_prog_table->table, obj, hash, info->id) {
if (obj->btf_id == info->id)
printf("%s%u", n++ == 0 ? " prog_ids " : ",",
obj->obj_id);
hashmap__for_each_key_entry(btf_prog_table, entry,
u32_as_hash_field(info->id)) {
printf("%s%u", n++ == 0 ? " prog_ids " : ",",
hash_field_as_u32(entry->value));
}

n = 0;
hash_for_each_possible(btf_map_table->table, obj, hash, info->id) {
if (obj->btf_id == info->id)
printf("%s%u", n++ == 0 ? " map_ids " : ",",
obj->obj_id);
hashmap__for_each_key_entry(btf_map_table, entry,
u32_as_hash_field(info->id)) {
printf("%s%u", n++ == 0 ? " map_ids " : ",",
hash_field_as_u32(entry->value));
}

emit_obj_refs_plain(&refs_table, info->id, "\n\tpids ");

printf("\n");
}

static void
show_btf_json(struct bpf_btf_info *info, int fd,
struct btf_attach_table *btf_prog_table,
struct btf_attach_table *btf_map_table)
struct hashmap *btf_prog_table,
struct hashmap *btf_map_table)
{
struct btf_attach_point *obj;
struct hashmap_entry *entry;
const char *name = u64_to_ptr(info->name);

jsonw_start_object(json_wtr); /* btf object */
Expand All @@ -835,19 +816,17 @@ show_btf_json(struct bpf_btf_info *info, int fd,

jsonw_name(json_wtr, "prog_ids");
jsonw_start_array(json_wtr); /* prog_ids */
hash_for_each_possible(btf_prog_table->table, obj, hash,
info->id) {
if (obj->btf_id == info->id)
jsonw_uint(json_wtr, obj->obj_id);
hashmap__for_each_key_entry(btf_prog_table, entry,
u32_as_hash_field(info->id)) {
jsonw_uint(json_wtr, hash_field_as_u32(entry->value));
}
jsonw_end_array(json_wtr); /* prog_ids */

jsonw_name(json_wtr, "map_ids");
jsonw_start_array(json_wtr); /* map_ids */
hash_for_each_possible(btf_map_table->table, obj, hash,
info->id) {
if (obj->btf_id == info->id)
jsonw_uint(json_wtr, obj->obj_id);
hashmap__for_each_key_entry(btf_map_table, entry,
u32_as_hash_field(info->id)) {
jsonw_uint(json_wtr, hash_field_as_u32(entry->value));
}
jsonw_end_array(json_wtr); /* map_ids */

Expand All @@ -862,8 +841,8 @@ show_btf_json(struct bpf_btf_info *info, int fd,
}

static int
show_btf(int fd, struct btf_attach_table *btf_prog_table,
struct btf_attach_table *btf_map_table)
show_btf(int fd, struct hashmap *btf_prog_table,
struct hashmap *btf_map_table)
{
struct bpf_btf_info info;
__u32 len = sizeof(info);
Expand Down Expand Up @@ -900,8 +879,8 @@ show_btf(int fd, struct btf_attach_table *btf_prog_table,

static int do_show(int argc, char **argv)
{
struct btf_attach_table btf_prog_table;
struct btf_attach_table btf_map_table;
struct hashmap *btf_prog_table;
struct hashmap *btf_map_table;
int err, fd = -1;
__u32 id = 0;

Expand All @@ -917,9 +896,19 @@ static int do_show(int argc, char **argv)
return BAD_ARG();
}

hash_init(btf_prog_table.table);
hash_init(btf_map_table.table);
err = build_btf_tables(&btf_prog_table, &btf_map_table);
btf_prog_table = hashmap__new(hash_fn_for_key_as_id,
equal_fn_for_key_as_id, NULL);
btf_map_table = hashmap__new(hash_fn_for_key_as_id,
equal_fn_for_key_as_id, NULL);
if (!btf_prog_table || !btf_map_table) {
hashmap__free(btf_prog_table);
hashmap__free(btf_map_table);
if (fd >= 0)
close(fd);
p_err("failed to create hashmap for object references");
return -1;
}
err = build_btf_tables(btf_prog_table, btf_map_table);
if (err) {
if (fd >= 0)
close(fd);
Expand All @@ -928,7 +917,7 @@ static int do_show(int argc, char **argv)
build_obj_refs_table(&refs_table, BPF_OBJ_BTF);

if (fd >= 0) {
err = show_btf(fd, &btf_prog_table, &btf_map_table);
err = show_btf(fd, btf_prog_table, btf_map_table);
close(fd);
goto exit_free;
}
Expand Down Expand Up @@ -960,7 +949,7 @@ static int do_show(int argc, char **argv)
break;
}

err = show_btf(fd, &btf_prog_table, &btf_map_table);
err = show_btf(fd, btf_prog_table, btf_map_table);
close(fd);
if (err)
break;
Expand All @@ -970,8 +959,8 @@ static int do_show(int argc, char **argv)
jsonw_end_array(json_wtr); /* root array */

exit_free:
delete_btf_table(&btf_prog_table);
delete_btf_table(&btf_map_table);
hashmap__free(btf_prog_table);
hashmap__free(btf_map_table);
delete_obj_refs_table(&refs_table);

return err;
Expand Down
5 changes: 5 additions & 0 deletions tools/bpf/bpftool/main.h
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,11 @@ static inline void *u32_as_hash_field(__u32 x)
return (void *)(uintptr_t)x;
}

static inline __u32 hash_field_as_u32(const void *x)
{
return (__u32)(uintptr_t)x;
}

static inline bool hashmap__empty(struct hashmap *map)
{
return map ? hashmap__size(map) == 0 : true;
Expand Down

0 comments on commit 2828d0d

Please sign in to comment.