Skip to content

Commit 8f18473

Browse files
qmonnetanakryiko
authored andcommitted
bpftool: Switch to libbpf's hashmap for pinned paths of BPF objects
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
1 parent 4624127 commit 8f18473

File tree

6 files changed

+111
-84
lines changed

6 files changed

+111
-84
lines changed

tools/bpf/bpftool/Makefile

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,9 @@ LIBBPF = $(LIBBPF_OUTPUT)libbpf.a
3131
LIBBPF_BOOTSTRAP_OUTPUT = $(BOOTSTRAP_OUTPUT)libbpf/
3232
LIBBPF_BOOTSTRAP = $(LIBBPF_BOOTSTRAP_OUTPUT)libbpf.a
3333

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

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

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

215215
$(OUTPUT)%.o: %.c

tools/bpf/bpftool/common.c

Lines changed: 30 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include <sys/vfs.h>
2323

2424
#include <bpf/bpf.h>
25+
#include <bpf/hashmap.h>
2526
#include <bpf/libbpf.h> /* libbpf_num_possible_cpus */
2627

2728
#include "main.h"
@@ -393,17 +394,17 @@ void print_hex_data_json(uint8_t *data, size_t len)
393394
}
394395

395396
/* extra params for nftw cb */
396-
static struct pinned_obj_table *build_fn_table;
397+
static struct hashmap *build_fn_table;
397398
static enum bpf_obj_type build_fn_type;
398399

399400
static int do_build_table_cb(const char *fpath, const struct stat *sb,
400401
int typeflag, struct FTW *ftwbuf)
401402
{
402403
struct bpf_prog_info pinned_info;
403404
__u32 len = sizeof(pinned_info);
404-
struct pinned_obj *obj_node;
405405
enum bpf_obj_type objtype;
406406
int fd, err = 0;
407+
char *path;
407408

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

423-
obj_node = calloc(1, sizeof(*obj_node));
424-
if (!obj_node) {
424+
path = strdup(fpath);
425+
if (!path) {
425426
err = -1;
426427
goto out_close;
427428
}
428429

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

437-
hash_add(build_fn_table->table, &obj_node->hash, obj_node->id);
438437
out_close:
439438
close(fd);
440439
out_ret:
441440
return err;
442441
}
443442

444-
int build_pinned_obj_table(struct pinned_obj_table *tab,
443+
int build_pinned_obj_table(struct hashmap *tab,
445444
enum bpf_obj_type type)
446445
{
447446
struct mntent *mntent = NULL;
@@ -470,17 +469,18 @@ int build_pinned_obj_table(struct pinned_obj_table *tab,
470469
return err;
471470
}
472471

473-
void delete_pinned_obj_table(struct pinned_obj_table *tab)
472+
void delete_pinned_obj_table(struct hashmap *map)
474473
{
475-
struct pinned_obj *obj;
476-
struct hlist_node *tmp;
477-
unsigned int bkt;
474+
struct hashmap_entry *entry;
475+
size_t bkt;
478476

479-
hash_for_each_safe(tab->table, bkt, tmp, obj, hash) {
480-
hash_del(&obj->hash);
481-
free(obj->path);
482-
free(obj);
483-
}
477+
if (!map)
478+
return;
479+
480+
hashmap__for_each_entry(map, entry, bkt)
481+
free(entry->value);
482+
483+
hashmap__free(map);
484484
}
485485

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

963963
return fd;
964964
}
965+
966+
size_t hash_fn_for_key_as_id(const void *key, void *ctx)
967+
{
968+
return (size_t)key;
969+
}
970+
971+
bool equal_fn_for_key_as_id(const void *k1, const void *k2, void *ctx)
972+
{
973+
return k1 == k2;
974+
}

tools/bpf/bpftool/link.c

Lines changed: 20 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#include <unistd.h>
88

99
#include <bpf/bpf.h>
10+
#include <bpf/hashmap.h>
1011

1112
#include "json_writer.h"
1213
#include "main.h"
@@ -20,7 +21,7 @@ static const char * const link_type_name[] = {
2021
[BPF_LINK_TYPE_NETNS] = "netns",
2122
};
2223

23-
static struct pinned_obj_table link_table;
24+
static struct hashmap *link_table;
2425

2526
static int link_parse_fd(int *argc, char ***argv)
2627
{
@@ -158,15 +159,14 @@ static int show_link_close_json(int fd, struct bpf_link_info *info)
158159
break;
159160
}
160161

161-
if (!hash_empty(link_table.table)) {
162-
struct pinned_obj *obj;
162+
if (!hashmap__empty(link_table)) {
163+
struct hashmap_entry *entry;
163164

164165
jsonw_name(json_wtr, "pinned");
165166
jsonw_start_array(json_wtr);
166-
hash_for_each_possible(link_table.table, obj, hash, info->id) {
167-
if (obj->id == info->id)
168-
jsonw_string(json_wtr, obj->path);
169-
}
167+
hashmap__for_each_key_entry(link_table, entry,
168+
u32_as_hash_field(info->id))
169+
jsonw_string(json_wtr, entry->value);
170170
jsonw_end_array(json_wtr);
171171
}
172172

@@ -246,13 +246,12 @@ static int show_link_close_plain(int fd, struct bpf_link_info *info)
246246
break;
247247
}
248248

249-
if (!hash_empty(link_table.table)) {
250-
struct pinned_obj *obj;
249+
if (!hashmap__empty(link_table)) {
250+
struct hashmap_entry *entry;
251251

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

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

307306
if (show_pinned) {
308-
hash_init(link_table.table);
309-
build_pinned_obj_table(&link_table, BPF_OBJ_LINK);
307+
link_table = hashmap__new(hash_fn_for_key_as_id,
308+
equal_fn_for_key_as_id, NULL);
309+
if (!link_table) {
310+
p_err("failed to create hashmap for pinned paths");
311+
return -1;
312+
}
313+
build_pinned_obj_table(link_table, BPF_OBJ_LINK);
310314
}
311315
build_obj_refs_table(&refs_table, BPF_OBJ_LINK);
312316

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

353357
if (show_pinned)
354-
delete_pinned_obj_table(&link_table);
358+
delete_pinned_obj_table(link_table);
355359

356360
return errno == ENOENT ? 0 : -1;
357361
}

tools/bpf/bpftool/main.h

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include <linux/hashtable.h>
1515
#include <tools/libc_compat.h>
1616

17+
#include <bpf/hashmap.h>
1718
#include <bpf/libbpf.h>
1819

1920
#include "json_writer.h"
@@ -105,16 +106,6 @@ void set_max_rlimit(void);
105106

106107
int mount_tracefs(const char *target);
107108

108-
struct pinned_obj_table {
109-
DECLARE_HASHTABLE(table, 16);
110-
};
111-
112-
struct pinned_obj {
113-
__u32 id;
114-
char *path;
115-
struct hlist_node hash;
116-
};
117-
118109
struct obj_refs_table {
119110
DECLARE_HASHTABLE(table, 16);
120111
};
@@ -134,9 +125,9 @@ struct obj_refs {
134125
struct btf;
135126
struct bpf_line_info;
136127

137-
int build_pinned_obj_table(struct pinned_obj_table *table,
128+
int build_pinned_obj_table(struct hashmap *table,
138129
enum bpf_obj_type type);
139-
void delete_pinned_obj_table(struct pinned_obj_table *tab);
130+
void delete_pinned_obj_table(struct hashmap *table);
140131
__weak int build_obj_refs_table(struct obj_refs_table *table,
141132
enum bpf_obj_type type);
142133
__weak void delete_obj_refs_table(struct obj_refs_table *table);
@@ -256,4 +247,18 @@ int do_filter_dump(struct tcmsg *ifinfo, struct nlattr **tb, const char *kind,
256247

257248
int print_all_levels(__maybe_unused enum libbpf_print_level level,
258249
const char *format, va_list args);
250+
251+
size_t hash_fn_for_key_as_id(const void *key, void *ctx);
252+
bool equal_fn_for_key_as_id(const void *k1, const void *k2, void *ctx);
253+
254+
static inline void *u32_as_hash_field(__u32 x)
255+
{
256+
return (void *)(uintptr_t)x;
257+
}
258+
259+
static inline bool hashmap__empty(struct hashmap *map)
260+
{
261+
return map ? hashmap__size(map) == 0 : true;
262+
}
263+
259264
#endif

tools/bpf/bpftool/map.c

Lines changed: 20 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
#include <bpf/bpf.h>
1919
#include <bpf/btf.h>
20+
#include <bpf/hashmap.h>
2021

2122
#include "json_writer.h"
2223
#include "main.h"
@@ -56,7 +57,7 @@ const char * const map_type_name[] = {
5657

5758
const size_t map_type_name_size = ARRAY_SIZE(map_type_name);
5859

59-
static struct pinned_obj_table map_table;
60+
static struct hashmap *map_table;
6061

6162
static bool map_is_per_cpu(__u32 type)
6263
{
@@ -537,15 +538,14 @@ static int show_map_close_json(int fd, struct bpf_map_info *info)
537538
if (info->btf_id)
538539
jsonw_int_field(json_wtr, "btf_id", info->btf_id);
539540

540-
if (!hash_empty(map_table.table)) {
541-
struct pinned_obj *obj;
541+
if (!hashmap__empty(map_table)) {
542+
struct hashmap_entry *entry;
542543

543544
jsonw_name(json_wtr, "pinned");
544545
jsonw_start_array(json_wtr);
545-
hash_for_each_possible(map_table.table, obj, hash, info->id) {
546-
if (obj->id == info->id)
547-
jsonw_string(json_wtr, obj->path);
548-
}
546+
hashmap__for_each_key_entry(map_table, entry,
547+
u32_as_hash_field(info->id))
548+
jsonw_string(json_wtr, entry->value);
549549
jsonw_end_array(json_wtr);
550550
}
551551

@@ -612,13 +612,12 @@ static int show_map_close_plain(int fd, struct bpf_map_info *info)
612612
}
613613
close(fd);
614614

615-
if (!hash_empty(map_table.table)) {
616-
struct pinned_obj *obj;
615+
if (!hashmap__empty(map_table)) {
616+
struct hashmap_entry *entry;
617617

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

@@ -697,8 +696,13 @@ static int do_show(int argc, char **argv)
697696
int fd;
698697

699698
if (show_pinned) {
700-
hash_init(map_table.table);
701-
build_pinned_obj_table(&map_table, BPF_OBJ_MAP);
699+
map_table = hashmap__new(hash_fn_for_key_as_id,
700+
equal_fn_for_key_as_id, NULL);
701+
if (!map_table) {
702+
p_err("failed to create hashmap for pinned paths");
703+
return -1;
704+
}
705+
build_pinned_obj_table(map_table, BPF_OBJ_MAP);
702706
}
703707
build_obj_refs_table(&refs_table, BPF_OBJ_MAP);
704708

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

749753
if (show_pinned)
750-
delete_pinned_obj_table(&map_table);
754+
delete_pinned_obj_table(map_table);
751755

752756
return errno == ENOENT ? 0 : -1;
753757
}

0 commit comments

Comments
 (0)