Skip to content

Commit

Permalink
bpftool: Switch to libbpf's hashmap for pinned paths of BPF objects
Browse files Browse the repository at this point in the history
In order to show pinned paths for BPF programs, maps, or links when
listing them with the "-f" option, bpftool creates hash maps to store
all relevant paths under the bpffs. So far, it would rely on the
kernel implementation (from tools/include/linux/hashtable.h).

We can make bpftool rely on libbpf's implementation instead. 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 is the first step of the conversion: the hash maps for
pinned paths for programs, maps, and links are converted to libbpf's
hashmap.{c,h}. Other hash maps used for the PIDs of process holding
references to BPF objects are left unchanged for now. On the build side,
this requires adding a dependency to a second header internal to libbpf,
and making it a dependency for the bootstrap bpftool version as well.
The rest of the changes are a rather straightforward conversion.

Signed-off-by: Quentin Monnet <quentin@isovalent.com>
Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
Link: https://lore.kernel.org/bpf/20211023205154.6710-4-quentin@isovalent.com
  • Loading branch information
Quentin Monnet authored and Andrii Nakryiko committed Oct 26, 2021
1 parent 4624127 commit 8f18473
Show file tree
Hide file tree
Showing 6 changed files with 111 additions and 84 deletions.
8 changes: 4 additions & 4 deletions tools/bpf/bpftool/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,9 @@ LIBBPF = $(LIBBPF_OUTPUT)libbpf.a
LIBBPF_BOOTSTRAP_OUTPUT = $(BOOTSTRAP_OUTPUT)libbpf/
LIBBPF_BOOTSTRAP = $(LIBBPF_BOOTSTRAP_OUTPUT)libbpf.a

# We need to copy nlattr.h which is not otherwise exported by libbpf, but still
# required by bpftool.
LIBBPF_INTERNAL_HDRS := $(addprefix $(LIBBPF_HDRS_DIR)/,nlattr.h)
# We need to copy hashmap.h and nlattr.h which is not otherwise exported by
# libbpf, but still required by bpftool.
LIBBPF_INTERNAL_HDRS := $(addprefix $(LIBBPF_HDRS_DIR)/,hashmap.h nlattr.h)

ifeq ($(BPFTOOL_VERSION),)
BPFTOOL_VERSION := $(shell make -rR --no-print-directory -sC ../../.. kernelversion)
Expand Down Expand Up @@ -209,7 +209,7 @@ $(BPFTOOL_BOOTSTRAP): $(BOOTSTRAP_OBJS) $(LIBBPF_BOOTSTRAP)
$(OUTPUT)bpftool: $(OBJS) $(LIBBPF)
$(QUIET_LINK)$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(OBJS) $(LIBS)

$(BOOTSTRAP_OUTPUT)%.o: %.c | $(BOOTSTRAP_OUTPUT)
$(BOOTSTRAP_OUTPUT)%.o: %.c $(LIBBPF_INTERNAL_HDRS) | $(BOOTSTRAP_OUTPUT)
$(QUIET_CC)$(HOSTCC) $(CFLAGS) -c -MMD -o $@ $<

$(OUTPUT)%.o: %.c
Expand Down
50 changes: 30 additions & 20 deletions tools/bpf/bpftool/common.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include <sys/vfs.h>

#include <bpf/bpf.h>
#include <bpf/hashmap.h>
#include <bpf/libbpf.h> /* libbpf_num_possible_cpus */

#include "main.h"
Expand Down Expand Up @@ -393,17 +394,17 @@ void print_hex_data_json(uint8_t *data, size_t len)
}

/* extra params for nftw cb */
static struct pinned_obj_table *build_fn_table;
static struct hashmap *build_fn_table;
static enum bpf_obj_type build_fn_type;

static int do_build_table_cb(const char *fpath, const struct stat *sb,
int typeflag, struct FTW *ftwbuf)
{
struct bpf_prog_info pinned_info;
__u32 len = sizeof(pinned_info);
struct pinned_obj *obj_node;
enum bpf_obj_type objtype;
int fd, err = 0;
char *path;

if (typeflag != FTW_F)
goto out_ret;
Expand All @@ -420,28 +421,26 @@ static int do_build_table_cb(const char *fpath, const struct stat *sb,
if (bpf_obj_get_info_by_fd(fd, &pinned_info, &len))
goto out_close;

obj_node = calloc(1, sizeof(*obj_node));
if (!obj_node) {
path = strdup(fpath);
if (!path) {
err = -1;
goto out_close;
}

obj_node->id = pinned_info.id;
obj_node->path = strdup(fpath);
if (!obj_node->path) {
err = -1;
free(obj_node);
err = hashmap__append(build_fn_table, u32_as_hash_field(pinned_info.id), path);
if (err) {
p_err("failed to append entry to hashmap for ID %u, path '%s': %s",
pinned_info.id, path, strerror(errno));
goto out_close;
}

hash_add(build_fn_table->table, &obj_node->hash, obj_node->id);
out_close:
close(fd);
out_ret:
return err;
}

int build_pinned_obj_table(struct pinned_obj_table *tab,
int build_pinned_obj_table(struct hashmap *tab,
enum bpf_obj_type type)
{
struct mntent *mntent = NULL;
Expand Down Expand Up @@ -470,17 +469,18 @@ int build_pinned_obj_table(struct pinned_obj_table *tab,
return err;
}

void delete_pinned_obj_table(struct pinned_obj_table *tab)
void delete_pinned_obj_table(struct hashmap *map)
{
struct pinned_obj *obj;
struct hlist_node *tmp;
unsigned int bkt;
struct hashmap_entry *entry;
size_t bkt;

hash_for_each_safe(tab->table, bkt, tmp, obj, hash) {
hash_del(&obj->hash);
free(obj->path);
free(obj);
}
if (!map)
return;

hashmap__for_each_entry(map, entry, bkt)
free(entry->value);

hashmap__free(map);
}

unsigned int get_page_size(void)
Expand Down Expand Up @@ -962,3 +962,13 @@ int map_parse_fd_and_info(int *argc, char ***argv, void *info, __u32 *info_len)

return fd;
}

size_t hash_fn_for_key_as_id(const void *key, void *ctx)
{
return (size_t)key;
}

bool equal_fn_for_key_as_id(const void *k1, const void *k2, void *ctx)
{
return k1 == k2;
}
36 changes: 20 additions & 16 deletions tools/bpf/bpftool/link.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include <unistd.h>

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

#include "json_writer.h"
#include "main.h"
Expand All @@ -20,7 +21,7 @@ static const char * const link_type_name[] = {
[BPF_LINK_TYPE_NETNS] = "netns",
};

static struct pinned_obj_table link_table;
static struct hashmap *link_table;

static int link_parse_fd(int *argc, char ***argv)
{
Expand Down Expand Up @@ -158,15 +159,14 @@ static int show_link_close_json(int fd, struct bpf_link_info *info)
break;
}

if (!hash_empty(link_table.table)) {
struct pinned_obj *obj;
if (!hashmap__empty(link_table)) {
struct hashmap_entry *entry;

jsonw_name(json_wtr, "pinned");
jsonw_start_array(json_wtr);
hash_for_each_possible(link_table.table, obj, hash, info->id) {
if (obj->id == info->id)
jsonw_string(json_wtr, obj->path);
}
hashmap__for_each_key_entry(link_table, entry,
u32_as_hash_field(info->id))
jsonw_string(json_wtr, entry->value);
jsonw_end_array(json_wtr);
}

Expand Down Expand Up @@ -246,13 +246,12 @@ static int show_link_close_plain(int fd, struct bpf_link_info *info)
break;
}

if (!hash_empty(link_table.table)) {
struct pinned_obj *obj;
if (!hashmap__empty(link_table)) {
struct hashmap_entry *entry;

hash_for_each_possible(link_table.table, obj, hash, info->id) {
if (obj->id == info->id)
printf("\n\tpinned %s", obj->path);
}
hashmap__for_each_key_entry(link_table, entry,
u32_as_hash_field(info->id))
printf("\n\tpinned %s", (char *)entry->value);
}
emit_obj_refs_plain(&refs_table, info->id, "\n\tpids ");

Expand Down Expand Up @@ -305,8 +304,13 @@ static int do_show(int argc, char **argv)
int err, fd;

if (show_pinned) {
hash_init(link_table.table);
build_pinned_obj_table(&link_table, BPF_OBJ_LINK);
link_table = hashmap__new(hash_fn_for_key_as_id,
equal_fn_for_key_as_id, NULL);
if (!link_table) {
p_err("failed to create hashmap for pinned paths");
return -1;
}
build_pinned_obj_table(link_table, BPF_OBJ_LINK);
}
build_obj_refs_table(&refs_table, BPF_OBJ_LINK);

Expand Down Expand Up @@ -351,7 +355,7 @@ static int do_show(int argc, char **argv)
delete_obj_refs_table(&refs_table);

if (show_pinned)
delete_pinned_obj_table(&link_table);
delete_pinned_obj_table(link_table);

return errno == ENOENT ? 0 : -1;
}
Expand Down
29 changes: 17 additions & 12 deletions tools/bpf/bpftool/main.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include <linux/hashtable.h>
#include <tools/libc_compat.h>

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

#include "json_writer.h"
Expand Down Expand Up @@ -105,16 +106,6 @@ void set_max_rlimit(void);

int mount_tracefs(const char *target);

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

struct pinned_obj {
__u32 id;
char *path;
struct hlist_node hash;
};

struct obj_refs_table {
DECLARE_HASHTABLE(table, 16);
};
Expand All @@ -134,9 +125,9 @@ struct obj_refs {
struct btf;
struct bpf_line_info;

int build_pinned_obj_table(struct pinned_obj_table *table,
int build_pinned_obj_table(struct hashmap *table,
enum bpf_obj_type type);
void delete_pinned_obj_table(struct pinned_obj_table *tab);
void delete_pinned_obj_table(struct hashmap *table);
__weak int build_obj_refs_table(struct obj_refs_table *table,
enum bpf_obj_type type);
__weak void delete_obj_refs_table(struct obj_refs_table *table);
Expand Down Expand Up @@ -256,4 +247,18 @@ int do_filter_dump(struct tcmsg *ifinfo, struct nlattr **tb, const char *kind,

int print_all_levels(__maybe_unused enum libbpf_print_level level,
const char *format, va_list args);

size_t hash_fn_for_key_as_id(const void *key, void *ctx);
bool equal_fn_for_key_as_id(const void *k1, const void *k2, void *ctx);

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

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

#endif
36 changes: 20 additions & 16 deletions tools/bpf/bpftool/map.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

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

#include "json_writer.h"
#include "main.h"
Expand Down Expand Up @@ -56,7 +57,7 @@ const char * const map_type_name[] = {

const size_t map_type_name_size = ARRAY_SIZE(map_type_name);

static struct pinned_obj_table map_table;
static struct hashmap *map_table;

static bool map_is_per_cpu(__u32 type)
{
Expand Down Expand Up @@ -537,15 +538,14 @@ static int show_map_close_json(int fd, struct bpf_map_info *info)
if (info->btf_id)
jsonw_int_field(json_wtr, "btf_id", info->btf_id);

if (!hash_empty(map_table.table)) {
struct pinned_obj *obj;
if (!hashmap__empty(map_table)) {
struct hashmap_entry *entry;

jsonw_name(json_wtr, "pinned");
jsonw_start_array(json_wtr);
hash_for_each_possible(map_table.table, obj, hash, info->id) {
if (obj->id == info->id)
jsonw_string(json_wtr, obj->path);
}
hashmap__for_each_key_entry(map_table, entry,
u32_as_hash_field(info->id))
jsonw_string(json_wtr, entry->value);
jsonw_end_array(json_wtr);
}

Expand Down Expand Up @@ -612,13 +612,12 @@ static int show_map_close_plain(int fd, struct bpf_map_info *info)
}
close(fd);

if (!hash_empty(map_table.table)) {
struct pinned_obj *obj;
if (!hashmap__empty(map_table)) {
struct hashmap_entry *entry;

hash_for_each_possible(map_table.table, obj, hash, info->id) {
if (obj->id == info->id)
printf("\n\tpinned %s", obj->path);
}
hashmap__for_each_key_entry(map_table, entry,
u32_as_hash_field(info->id))
printf("\n\tpinned %s", (char *)entry->value);
}
printf("\n");

Expand Down Expand Up @@ -697,8 +696,13 @@ static int do_show(int argc, char **argv)
int fd;

if (show_pinned) {
hash_init(map_table.table);
build_pinned_obj_table(&map_table, BPF_OBJ_MAP);
map_table = hashmap__new(hash_fn_for_key_as_id,
equal_fn_for_key_as_id, NULL);
if (!map_table) {
p_err("failed to create hashmap for pinned paths");
return -1;
}
build_pinned_obj_table(map_table, BPF_OBJ_MAP);
}
build_obj_refs_table(&refs_table, BPF_OBJ_MAP);

Expand Down Expand Up @@ -747,7 +751,7 @@ static int do_show(int argc, char **argv)
delete_obj_refs_table(&refs_table);

if (show_pinned)
delete_pinned_obj_table(&map_table);
delete_pinned_obj_table(map_table);

return errno == ENOENT ? 0 : -1;
}
Expand Down
Loading

0 comments on commit 8f18473

Please sign in to comment.