Commit 9327acd0 authored by Andrii Nakryiko's avatar Andrii Nakryiko

Merge branch 'bpftool: Switch to libbpf's hashmap for referencing BPF objects'

Quentin Monnet says:

====================

When listing BPF objects, bpftool can print a number of properties about
items holding references to these objects. For example, it can show pinned
paths for BPF programs, maps, and links; or programs and maps using a given
BTF object; or the names and PIDs of processes referencing BPF objects. To
collect this information, bpftool uses hash maps (to be clear: the data
structures, inside bpftool - we are not talking of BPF maps). It uses the
implementation available from the kernel, and picks it up from
tools/include/linux/hashtable.h.

This patchset converts bpftool's hash maps to a distinct implementation
instead, the one coming with libbpf. The main motivation for this change is
that it should ease the path towards a potential out-of-tree mirror for
bpftool, like the one libbpf already has. Although it's not perfect to
depend on libbpf's internal components, bpftool is intimately tied with the
library anyway, and this looks better than depending too much on (non-UAPI)
kernel headers.

The first two patches contain preparatory work on the Makefile and on the
initialisation of the hash maps for collecting pinned paths for objects.
Then the transition is split into several steps, one for each kind of
properties for which the collection is backed by hash maps.

v2:
  - Move hashmap cleanup for pinned paths for links from do_detach() to
    do_show().
  - Handle errors on hashmap__append() (in three of the patches).
  - Rename bpftool_hash_fn() and bpftool_equal_fn() as hash_fn_for_key_id()
    and equal_fn_for_key_id(), respectively.
  - Add curly braces for hashmap__for_each_key_entry() { } in
    show_btf_plain() and show_btf_json(), where the flow was difficult to
    read.
====================
Signed-off-by: default avatarAndrii Nakryiko <andrii@kernel.org>
parents 57c8d362 d6699f8e
......@@ -31,22 +31,22 @@ 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)
endif
$(LIBBPF_OUTPUT) $(BOOTSTRAP_OUTPUT) $(LIBBPF_BOOTSTRAP_OUTPUT):
$(LIBBPF_OUTPUT) $(BOOTSTRAP_OUTPUT) $(LIBBPF_BOOTSTRAP_OUTPUT) $(LIBBPF_HDRS_DIR):
$(QUIET_MKDIR)mkdir -p $@
$(LIBBPF): $(wildcard $(BPF_DIR)/*.[ch] $(BPF_DIR)/Makefile) | $(LIBBPF_OUTPUT)
$(Q)$(MAKE) -C $(BPF_DIR) OUTPUT=$(LIBBPF_OUTPUT) \
DESTDIR=$(LIBBPF_DESTDIR) prefix= $(LIBBPF) install_headers
$(LIBBPF_INTERNAL_HDRS): $(LIBBPF_HDRS_DIR)/%.h: $(BPF_DIR)/%.h $(LIBBPF)
$(LIBBPF_INTERNAL_HDRS): $(LIBBPF_HDRS_DIR)/%.h: $(BPF_DIR)/%.h | $(LIBBPF_HDRS_DIR)
$(call QUIET_INSTALL, $@)
$(Q)install -m 644 -t $(LIBBPF_HDRS_DIR) $<
......@@ -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
......
......@@ -8,14 +8,15 @@
#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"
......@@ -40,14 +41,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)
......@@ -645,21 +641,8 @@ 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[] = {
......@@ -667,7 +650,6 @@ build_btf_type_table(struct btf_attach_table *tab, enum bpf_obj_type type,
[BPF_OBJ_PROG] = "prog",
[BPF_OBJ_MAP] = "map",
};
struct btf_attach_point *obj_node;
__u32 btf_id, id = 0;
int err;
int fd;
......@@ -741,28 +723,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);
......@@ -778,7 +757,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;
}
......@@ -787,10 +766,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;
......@@ -804,29 +783,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 ");
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 */
......@@ -835,23 +815,21 @@ 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 */
emit_obj_refs_json(&refs_table, info->id, json_wtr); /* pids */
emit_obj_refs_json(refs_table, info->id, json_wtr); /* pids */
jsonw_bool_field(json_wtr, "kernel", info->kernel_btf);
......@@ -862,8 +840,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);
......@@ -900,8 +878,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;
......@@ -917,9 +895,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);
......@@ -928,7 +916,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;
}
......@@ -960,7 +948,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;
......@@ -970,9 +958,9 @@ 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);
delete_obj_refs_table(&refs_table);
hashmap__free(btf_prog_table);
hashmap__free(btf_map_table);
delete_obj_refs_table(refs_table);
return err;
}
......
......@@ -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"
......@@ -393,7 +394,7 @@ 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,
......@@ -401,9 +402,9 @@ static int do_build_table_cb(const char *fpath, const struct stat *sb,
{
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;
......@@ -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;
......@@ -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)
......@@ -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;
}
......@@ -7,6 +7,7 @@
#include <unistd.h>
#include <bpf/bpf.h>
#include <bpf/hashmap.h>
#include "json_writer.h"
#include "main.h"
......@@ -20,6 +21,8 @@ static const char * const link_type_name[] = {
[BPF_LINK_TYPE_NETNS] = "netns",
};
static struct hashmap *link_table;
static int link_parse_fd(int *argc, char ***argv)
{
int fd;
......@@ -156,19 +159,18 @@ 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);
}
emit_obj_refs_json(&refs_table, info->id, json_wtr);
emit_obj_refs_json(refs_table, info->id, json_wtr);
jsonw_end_object(json_wtr);
......@@ -244,15 +246,14 @@ 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 ");
emit_obj_refs_plain(refs_table, info->id, "\n\tpids ");
printf("\n");
......@@ -302,8 +303,15 @@ static int do_show(int argc, char **argv)
__u32 id = 0;
int err, fd;
if (show_pinned)
build_pinned_obj_table(&link_table, BPF_OBJ_LINK);
if (show_pinned) {
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);
if (argc == 2) {
......@@ -344,7 +352,10 @@ static int do_show(int argc, char **argv)
if (json_output)
jsonw_end_array(json_wtr);
delete_obj_refs_table(&refs_table);
delete_obj_refs_table(refs_table);
if (show_pinned)
delete_pinned_obj_table(link_table);
return errno == ENOENT ? 0 : -1;
}
......
......@@ -10,8 +10,9 @@
#include <string.h>
#include <bpf/bpf.h>
#include <bpf/libbpf.h>
#include <bpf/btf.h>
#include <bpf/hashmap.h>
#include <bpf/libbpf.h>
#include "main.h"
......@@ -31,10 +32,7 @@ bool verifier_logs;
bool relaxed_maps;
bool use_loader;
struct btf *base_btf;
struct pinned_obj_table prog_table;
struct pinned_obj_table map_table;
struct pinned_obj_table link_table;
struct obj_refs_table refs_table;
struct hashmap *refs_table;
static void __noreturn clean_and_exit(int i)
{
......@@ -409,10 +407,6 @@ int main(int argc, char **argv)
block_mount = false;
bin_name = argv[0];
hash_init(prog_table.table);
hash_init(map_table.table);
hash_init(link_table.table);
opterr = 0;
while ((opt = getopt_long(argc, argv, "VhpjfLmndB:",
options, NULL)) >= 0) {
......@@ -479,11 +473,6 @@ int main(int argc, char **argv)
if (json_output)
jsonw_destroy(&json_wtr);
if (show_pinned) {
delete_pinned_obj_table(&prog_table);
delete_pinned_obj_table(&map_table);
delete_pinned_obj_table(&link_table);
}
btf__free(base_btf);
return ret;
......
......@@ -11,9 +11,9 @@
#include <linux/bpf.h>
#include <linux/compiler.h>
#include <linux/kernel.h>
#include <linux/hashtable.h>
#include <tools/libc_compat.h>
#include <bpf/hashmap.h>
#include <bpf/libbpf.h>
#include "json_writer.h"
......@@ -91,10 +91,7 @@ extern bool verifier_logs;
extern bool relaxed_maps;
extern bool use_loader;
extern struct btf *base_btf;
extern struct pinned_obj_table prog_table;
extern struct pinned_obj_table map_table;
extern struct pinned_obj_table link_table;
extern struct obj_refs_table refs_table;
extern struct hashmap *refs_table;
void __printf(1, 2) p_err(const char *fmt, ...);
void __printf(1, 2) p_info(const char *fmt, ...);
......@@ -108,28 +105,12 @@ 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);
};
struct obj_ref {
int pid;
char comm[16];
};
struct obj_refs {
struct hlist_node node;
__u32 id;
int ref_cnt;
struct obj_ref *refs;
};
......@@ -137,15 +118,15 @@ 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);
__weak int build_obj_refs_table(struct obj_refs_table *table,
void delete_pinned_obj_table(struct hashmap *table);
__weak int build_obj_refs_table(struct hashmap **table,
enum bpf_obj_type type);
__weak void delete_obj_refs_table(struct obj_refs_table *table);
__weak void emit_obj_refs_json(struct obj_refs_table *table, __u32 id,
__weak void delete_obj_refs_table(struct hashmap *table);
__weak void emit_obj_refs_json(struct hashmap *table, __u32 id,
json_writer_t *json_wtr);
__weak void emit_obj_refs_plain(struct obj_refs_table *table, __u32 id,
__weak void emit_obj_refs_plain(struct hashmap *table, __u32 id,
const char *prefix);
void print_dev_plain(__u32 ifindex, __u64 ns_dev, __u64 ns_inode);
void print_dev_json(__u32 ifindex, __u64 ns_dev, __u64 ns_inode);
......@@ -259,4 +240,23 @@ 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 __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;
}
#endif
......@@ -17,6 +17,7 @@
#include <bpf/bpf.h>
#include <bpf/btf.h>
#include <bpf/hashmap.h>
#include "json_writer.h"
#include "main.h"
......@@ -56,6 +57,8 @@ const char * const map_type_name[] = {
const size_t map_type_name_size = ARRAY_SIZE(map_type_name);
static struct hashmap *map_table;
static bool map_is_per_cpu(__u32 type)
{
return type == BPF_MAP_TYPE_PERCPU_HASH ||
......@@ -535,19 +538,18 @@ 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);
}
emit_obj_refs_json(&refs_table, info->id, json_wtr);
emit_obj_refs_json(refs_table, info->id, json_wtr);
jsonw_end_object(json_wtr);
......@@ -610,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");
......@@ -636,7 +637,7 @@ static int show_map_close_plain(int fd, struct bpf_map_info *info)
if (frozen)
printf("%sfrozen", info->btf_id ? " " : "");
emit_obj_refs_plain(&refs_table, info->id, "\n\tpids ");
emit_obj_refs_plain(refs_table, info->id, "\n\tpids ");
printf("\n");
return 0;
......@@ -694,8 +695,15 @@ static int do_show(int argc, char **argv)
int err;
int fd;
if (show_pinned)
build_pinned_obj_table(&map_table, BPF_OBJ_MAP);
if (show_pinned) {
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);
if (argc == 2)
......@@ -740,7 +748,10 @@ static int do_show(int argc, char **argv)
if (json_output)
jsonw_end_array(json_wtr);
delete_obj_refs_table(&refs_table);
delete_obj_refs_table(refs_table);
if (show_pinned)
delete_pinned_obj_table(map_table);
return errno == ENOENT ? 0 : -1;
}
......
......@@ -6,35 +6,37 @@
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <bpf/bpf.h>
#include <bpf/hashmap.h>
#include "main.h"
#include "skeleton/pid_iter.h"
#ifdef BPFTOOL_WITHOUT_SKELETONS
int build_obj_refs_table(struct obj_refs_table *table, enum bpf_obj_type type)
int build_obj_refs_table(struct hashmap **map, enum bpf_obj_type type)
{
return -ENOTSUP;
}
void delete_obj_refs_table(struct obj_refs_table *table) {}
void emit_obj_refs_plain(struct obj_refs_table *table, __u32 id, const char *prefix) {}
void emit_obj_refs_json(struct obj_refs_table *table, __u32 id, json_writer_t *json_writer) {}
void delete_obj_refs_table(struct hashmap *map) {}
void emit_obj_refs_plain(struct hashmap *map, __u32 id, const char *prefix) {}
void emit_obj_refs_json(struct hashmap *map, __u32 id, json_writer_t *json_writer) {}
#else /* BPFTOOL_WITHOUT_SKELETONS */
#include "pid_iter.skel.h"
static void add_ref(struct obj_refs_table *table, struct pid_iter_entry *e)
static void add_ref(struct hashmap *map, struct pid_iter_entry *e)
{
struct hashmap_entry *entry;
struct obj_refs *refs;
struct obj_ref *ref;
int err, i;
void *tmp;
int i;
hash_for_each_possible(table->table, refs, node, e->id) {
if (refs->id != e->id)
continue;
hashmap__for_each_key_entry(map, entry, u32_as_hash_field(e->id)) {
refs = entry->value;
for (i = 0; i < refs->ref_cnt; i++) {
if (refs->refs[i].pid == e->pid)
......@@ -64,7 +66,6 @@ static void add_ref(struct obj_refs_table *table, struct pid_iter_entry *e)
return;
}
refs->id = e->id;
refs->refs = malloc(sizeof(*refs->refs));
if (!refs->refs) {
free(refs);
......@@ -76,7 +77,11 @@ static void add_ref(struct obj_refs_table *table, struct pid_iter_entry *e)
ref->pid = e->pid;
memcpy(ref->comm, e->comm, sizeof(ref->comm));
refs->ref_cnt = 1;
hash_add(table->table, &refs->node, e->id);
err = hashmap__append(map, u32_as_hash_field(e->id), refs);
if (err)
p_err("failed to append entry to hashmap for ID %u: %s",
e->id, strerror(errno));
}
static int __printf(2, 0)
......@@ -87,7 +92,7 @@ libbpf_print_none(__maybe_unused enum libbpf_print_level level,
return 0;
}
int build_obj_refs_table(struct obj_refs_table *table, enum bpf_obj_type type)
int build_obj_refs_table(struct hashmap **map, enum bpf_obj_type type)
{
struct pid_iter_entry *e;
char buf[4096 / sizeof(*e) * sizeof(*e)];
......@@ -95,7 +100,11 @@ int build_obj_refs_table(struct obj_refs_table *table, enum bpf_obj_type type)
int err, ret, fd = -1, i;
libbpf_print_fn_t default_print;
hash_init(table->table);
*map = hashmap__new(hash_fn_for_key_as_id, equal_fn_for_key_as_id, NULL);
if (!*map) {
p_err("failed to create hashmap for PID references");
return -1;
}
set_max_rlimit();
skel = pid_iter_bpf__open();
......@@ -151,7 +160,7 @@ int build_obj_refs_table(struct obj_refs_table *table, enum bpf_obj_type type)
e = (void *)buf;
for (i = 0; i < ret; i++, e++) {
add_ref(table, e);
add_ref(*map, e);
}
}
err = 0;
......@@ -162,39 +171,44 @@ int build_obj_refs_table(struct obj_refs_table *table, enum bpf_obj_type type)
return err;
}
void delete_obj_refs_table(struct obj_refs_table *table)
void delete_obj_refs_table(struct hashmap *map)
{
struct obj_refs *refs;
struct hlist_node *tmp;
unsigned int bkt;
struct hashmap_entry *entry;
size_t bkt;
if (!map)
return;
hashmap__for_each_entry(map, entry, bkt) {
struct obj_refs *refs = entry->value;
hash_for_each_safe(table->table, bkt, tmp, refs, node) {
hash_del(&refs->node);
free(refs->refs);
free(refs);
}
hashmap__free(map);
}
void emit_obj_refs_json(struct obj_refs_table *table, __u32 id,
void emit_obj_refs_json(struct hashmap *map, __u32 id,
json_writer_t *json_writer)
{
struct obj_refs *refs;
struct obj_ref *ref;
int i;
struct hashmap_entry *entry;
if (hash_empty(table->table))
if (hashmap__empty(map))
return;
hash_for_each_possible(table->table, refs, node, id) {
if (refs->id != id)
continue;
hashmap__for_each_key_entry(map, entry, u32_as_hash_field(id)) {
struct obj_refs *refs = entry->value;
int i;
if (refs->ref_cnt == 0)
break;
jsonw_name(json_writer, "pids");
jsonw_start_array(json_writer);
for (i = 0; i < refs->ref_cnt; i++) {
ref = &refs->refs[i];
struct obj_ref *ref = &refs->refs[i];
jsonw_start_object(json_writer);
jsonw_int_field(json_writer, "pid", ref->pid);
jsonw_string_field(json_writer, "comm", ref->comm);
......@@ -205,24 +219,24 @@ void emit_obj_refs_json(struct obj_refs_table *table, __u32 id,
}
}
void emit_obj_refs_plain(struct obj_refs_table *table, __u32 id, const char *prefix)
void emit_obj_refs_plain(struct hashmap *map, __u32 id, const char *prefix)
{
struct obj_refs *refs;
struct obj_ref *ref;
int i;
struct hashmap_entry *entry;
if (hash_empty(table->table))
if (hashmap__empty(map))
return;
hash_for_each_possible(table->table, refs, node, id) {
if (refs->id != id)
continue;
hashmap__for_each_key_entry(map, entry, u32_as_hash_field(id)) {
struct obj_refs *refs = entry->value;
int i;
if (refs->ref_cnt == 0)
break;
printf("%s", prefix);
for (i = 0; i < refs->ref_cnt; i++) {
ref = &refs->refs[i];
struct obj_ref *ref = &refs->refs[i];
printf("%s%s(%d)", i == 0 ? "" : ", ", ref->comm, ref->pid);
}
break;
......
......@@ -24,6 +24,7 @@
#include <bpf/bpf.h>
#include <bpf/btf.h>
#include <bpf/hashmap.h>
#include <bpf/libbpf.h>
#include <bpf/skel_internal.h>
......@@ -84,6 +85,8 @@ static const char * const attach_type_strings[] = {
[__MAX_BPF_ATTACH_TYPE] = NULL,
};
static struct hashmap *prog_table;
static enum bpf_attach_type parse_attach_type(const char *str)
{
enum bpf_attach_type type;
......@@ -416,19 +419,18 @@ static void print_prog_json(struct bpf_prog_info *info, int fd)
if (info->btf_id)
jsonw_int_field(json_wtr, "btf_id", info->btf_id);
if (!hash_empty(prog_table.table)) {
struct pinned_obj *obj;
if (!hashmap__empty(prog_table)) {
struct hashmap_entry *entry;
jsonw_name(json_wtr, "pinned");
jsonw_start_array(json_wtr);
hash_for_each_possible(prog_table.table, obj, hash, info->id) {
if (obj->id == info->id)
jsonw_string(json_wtr, obj->path);
}
hashmap__for_each_key_entry(prog_table, entry,
u32_as_hash_field(info->id))
jsonw_string(json_wtr, entry->value);
jsonw_end_array(json_wtr);
}
emit_obj_refs_json(&refs_table, info->id, json_wtr);
emit_obj_refs_json(refs_table, info->id, json_wtr);
show_prog_metadata(fd, info->nr_map_ids);
......@@ -488,19 +490,18 @@ static void print_prog_plain(struct bpf_prog_info *info, int fd)
if (info->nr_map_ids)
show_prog_maps(fd, info->nr_map_ids);
if (!hash_empty(prog_table.table)) {
struct pinned_obj *obj;
if (!hashmap__empty(prog_table)) {
struct hashmap_entry *entry;
hash_for_each_possible(prog_table.table, obj, hash, info->id) {
if (obj->id == info->id)
printf("\n\tpinned %s", obj->path);
}
hashmap__for_each_key_entry(prog_table, entry,
u32_as_hash_field(info->id))
printf("\n\tpinned %s", (char *)entry->value);
}
if (info->btf_id)
printf("\n\tbtf_id %d", info->btf_id);
emit_obj_refs_plain(&refs_table, info->id, "\n\tpids ");
emit_obj_refs_plain(refs_table, info->id, "\n\tpids ");
printf("\n");
......@@ -567,8 +568,15 @@ static int do_show(int argc, char **argv)
int err;
int fd;
if (show_pinned)
build_pinned_obj_table(&prog_table, BPF_OBJ_PROG);
if (show_pinned) {
prog_table = hashmap__new(hash_fn_for_key_as_id,
equal_fn_for_key_as_id, NULL);
if (!prog_table) {
p_err("failed to create hashmap for pinned paths");
return -1;
}
build_pinned_obj_table(prog_table, BPF_OBJ_PROG);
}
build_obj_refs_table(&refs_table, BPF_OBJ_PROG);
if (argc == 2)
......@@ -611,7 +619,10 @@ static int do_show(int argc, char **argv)
if (json_output)
jsonw_end_array(json_wtr);
delete_obj_refs_table(&refs_table);
delete_obj_refs_table(refs_table);
if (show_pinned)
delete_pinned_obj_table(prog_table);
return err;
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment