Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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: Andrii Nakryiko <andrii@kernel.org>

+262 -228
+6 -6
tools/bpf/bpftool/Makefile
··· 31 31 LIBBPF_BOOTSTRAP_OUTPUT = $(BOOTSTRAP_OUTPUT)libbpf/ 32 32 LIBBPF_BOOTSTRAP = $(LIBBPF_BOOTSTRAP_OUTPUT)libbpf.a 33 33 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) 37 37 38 38 ifeq ($(BPFTOOL_VERSION),) 39 39 BPFTOOL_VERSION := $(shell make -rR --no-print-directory -sC ../../.. kernelversion) 40 40 endif 41 41 42 - $(LIBBPF_OUTPUT) $(BOOTSTRAP_OUTPUT) $(LIBBPF_BOOTSTRAP_OUTPUT): 42 + $(LIBBPF_OUTPUT) $(BOOTSTRAP_OUTPUT) $(LIBBPF_BOOTSTRAP_OUTPUT) $(LIBBPF_HDRS_DIR): 43 43 $(QUIET_MKDIR)mkdir -p $@ 44 44 45 45 $(LIBBPF): $(wildcard $(BPF_DIR)/*.[ch] $(BPF_DIR)/Makefile) | $(LIBBPF_OUTPUT) 46 46 $(Q)$(MAKE) -C $(BPF_DIR) OUTPUT=$(LIBBPF_OUTPUT) \ 47 47 DESTDIR=$(LIBBPF_DESTDIR) prefix= $(LIBBPF) install_headers 48 48 49 - $(LIBBPF_INTERNAL_HDRS): $(LIBBPF_HDRS_DIR)/%.h: $(BPF_DIR)/%.h $(LIBBPF) 49 + $(LIBBPF_INTERNAL_HDRS): $(LIBBPF_HDRS_DIR)/%.h: $(BPF_DIR)/%.h | $(LIBBPF_HDRS_DIR) 50 50 $(call QUIET_INSTALL, $@) 51 51 $(Q)install -m 644 -t $(LIBBPF_HDRS_DIR) $< 52 52 ··· 209 209 $(OUTPUT)bpftool: $(OBJS) $(LIBBPF) 210 210 $(QUIET_LINK)$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(OBJS) $(LIBS) 211 211 212 - $(BOOTSTRAP_OUTPUT)%.o: %.c | $(BOOTSTRAP_OUTPUT) 212 + $(BOOTSTRAP_OUTPUT)%.o: %.c $(LIBBPF_INTERNAL_HDRS) | $(BOOTSTRAP_OUTPUT) 213 213 $(QUIET_CC)$(HOSTCC) $(CFLAGS) -c -MMD -o $@ $< 214 214 215 215 $(OUTPUT)%.o: %.c
+60 -72
tools/bpf/bpftool/btf.c
··· 8 8 #include <stdio.h> 9 9 #include <string.h> 10 10 #include <unistd.h> 11 - #include <bpf/bpf.h> 12 - #include <bpf/btf.h> 13 - #include <bpf/libbpf.h> 14 11 #include <linux/btf.h> 15 - #include <linux/hashtable.h> 16 12 #include <sys/types.h> 17 13 #include <sys/stat.h> 14 + 15 + #include <bpf/bpf.h> 16 + #include <bpf/btf.h> 17 + #include <bpf/hashmap.h> 18 + #include <bpf/libbpf.h> 18 19 19 20 #include "json_writer.h" 20 21 #include "main.h" ··· 41 40 [BTF_KIND_DECL_TAG] = "DECL_TAG", 42 41 }; 43 42 44 - struct btf_attach_table { 45 - DECLARE_HASHTABLE(table, 16); 46 - }; 47 - 48 43 struct btf_attach_point { 49 44 __u32 obj_id; 50 45 __u32 btf_id; 51 - struct hlist_node hash; 52 46 }; 53 47 54 48 static const char *btf_int_enc_str(__u8 encoding) ··· 641 645 return fd; 642 646 } 643 647 644 - static void delete_btf_table(struct btf_attach_table *tab) 645 - { 646 - struct btf_attach_point *obj; 647 - struct hlist_node *tmp; 648 - 649 - unsigned int bkt; 650 - 651 - hash_for_each_safe(tab->table, bkt, tmp, obj, hash) { 652 - hash_del(&obj->hash); 653 - free(obj); 654 - } 655 - } 656 - 657 648 static int 658 - build_btf_type_table(struct btf_attach_table *tab, enum bpf_obj_type type, 649 + build_btf_type_table(struct hashmap *tab, enum bpf_obj_type type, 659 650 void *info, __u32 *len) 660 651 { 661 652 static const char * const names[] = { ··· 650 667 [BPF_OBJ_PROG] = "prog", 651 668 [BPF_OBJ_MAP] = "map", 652 669 }; 653 - struct btf_attach_point *obj_node; 654 670 __u32 btf_id, id = 0; 655 671 int err; 656 672 int fd; ··· 723 741 if (!btf_id) 724 742 continue; 725 743 726 - obj_node = calloc(1, sizeof(*obj_node)); 727 - if (!obj_node) { 728 - p_err("failed to allocate memory: %s", strerror(errno)); 729 - err = -ENOMEM; 744 + err = hashmap__append(tab, u32_as_hash_field(btf_id), 745 + u32_as_hash_field(id)); 746 + if (err) { 747 + p_err("failed to append entry to hashmap for BTF ID %u, object ID %u: %s", 748 + btf_id, id, strerror(errno)); 730 749 goto err_free; 731 750 } 732 - 733 - obj_node->obj_id = id; 734 - obj_node->btf_id = btf_id; 735 - hash_add(tab->table, &obj_node->hash, obj_node->btf_id); 736 751 } 737 752 738 753 return 0; 739 754 740 755 err_free: 741 - delete_btf_table(tab); 756 + hashmap__free(tab); 742 757 return err; 743 758 } 744 759 745 760 static int 746 - build_btf_tables(struct btf_attach_table *btf_prog_table, 747 - struct btf_attach_table *btf_map_table) 761 + build_btf_tables(struct hashmap *btf_prog_table, 762 + struct hashmap *btf_map_table) 748 763 { 749 764 struct bpf_prog_info prog_info; 750 765 __u32 prog_len = sizeof(prog_info); ··· 757 778 err = build_btf_type_table(btf_map_table, BPF_OBJ_MAP, &map_info, 758 779 &map_len); 759 780 if (err) { 760 - delete_btf_table(btf_prog_table); 781 + hashmap__free(btf_prog_table); 761 782 return err; 762 783 } 763 784 ··· 766 787 767 788 static void 768 789 show_btf_plain(struct bpf_btf_info *info, int fd, 769 - struct btf_attach_table *btf_prog_table, 770 - struct btf_attach_table *btf_map_table) 790 + struct hashmap *btf_prog_table, 791 + struct hashmap *btf_map_table) 771 792 { 772 - struct btf_attach_point *obj; 793 + struct hashmap_entry *entry; 773 794 const char *name = u64_to_ptr(info->name); 774 795 int n; 775 796 ··· 783 804 printf("size %uB", info->btf_size); 784 805 785 806 n = 0; 786 - hash_for_each_possible(btf_prog_table->table, obj, hash, info->id) { 787 - if (obj->btf_id == info->id) 788 - printf("%s%u", n++ == 0 ? " prog_ids " : ",", 789 - obj->obj_id); 807 + hashmap__for_each_key_entry(btf_prog_table, entry, 808 + u32_as_hash_field(info->id)) { 809 + printf("%s%u", n++ == 0 ? " prog_ids " : ",", 810 + hash_field_as_u32(entry->value)); 790 811 } 791 812 792 813 n = 0; 793 - hash_for_each_possible(btf_map_table->table, obj, hash, info->id) { 794 - if (obj->btf_id == info->id) 795 - printf("%s%u", n++ == 0 ? " map_ids " : ",", 796 - obj->obj_id); 814 + hashmap__for_each_key_entry(btf_map_table, entry, 815 + u32_as_hash_field(info->id)) { 816 + printf("%s%u", n++ == 0 ? " map_ids " : ",", 817 + hash_field_as_u32(entry->value)); 797 818 } 798 - emit_obj_refs_plain(&refs_table, info->id, "\n\tpids "); 819 + 820 + emit_obj_refs_plain(refs_table, info->id, "\n\tpids "); 799 821 800 822 printf("\n"); 801 823 } 802 824 803 825 static void 804 826 show_btf_json(struct bpf_btf_info *info, int fd, 805 - struct btf_attach_table *btf_prog_table, 806 - struct btf_attach_table *btf_map_table) 827 + struct hashmap *btf_prog_table, 828 + struct hashmap *btf_map_table) 807 829 { 808 - struct btf_attach_point *obj; 830 + struct hashmap_entry *entry; 809 831 const char *name = u64_to_ptr(info->name); 810 832 811 833 jsonw_start_object(json_wtr); /* btf object */ ··· 815 835 816 836 jsonw_name(json_wtr, "prog_ids"); 817 837 jsonw_start_array(json_wtr); /* prog_ids */ 818 - hash_for_each_possible(btf_prog_table->table, obj, hash, 819 - info->id) { 820 - if (obj->btf_id == info->id) 821 - jsonw_uint(json_wtr, obj->obj_id); 838 + hashmap__for_each_key_entry(btf_prog_table, entry, 839 + u32_as_hash_field(info->id)) { 840 + jsonw_uint(json_wtr, hash_field_as_u32(entry->value)); 822 841 } 823 842 jsonw_end_array(json_wtr); /* prog_ids */ 824 843 825 844 jsonw_name(json_wtr, "map_ids"); 826 845 jsonw_start_array(json_wtr); /* map_ids */ 827 - hash_for_each_possible(btf_map_table->table, obj, hash, 828 - info->id) { 829 - if (obj->btf_id == info->id) 830 - jsonw_uint(json_wtr, obj->obj_id); 846 + hashmap__for_each_key_entry(btf_map_table, entry, 847 + u32_as_hash_field(info->id)) { 848 + jsonw_uint(json_wtr, hash_field_as_u32(entry->value)); 831 849 } 832 850 jsonw_end_array(json_wtr); /* map_ids */ 833 851 834 - emit_obj_refs_json(&refs_table, info->id, json_wtr); /* pids */ 852 + emit_obj_refs_json(refs_table, info->id, json_wtr); /* pids */ 835 853 836 854 jsonw_bool_field(json_wtr, "kernel", info->kernel_btf); 837 855 ··· 840 862 } 841 863 842 864 static int 843 - show_btf(int fd, struct btf_attach_table *btf_prog_table, 844 - struct btf_attach_table *btf_map_table) 865 + show_btf(int fd, struct hashmap *btf_prog_table, 866 + struct hashmap *btf_map_table) 845 867 { 846 868 struct bpf_btf_info info; 847 869 __u32 len = sizeof(info); ··· 878 900 879 901 static int do_show(int argc, char **argv) 880 902 { 881 - struct btf_attach_table btf_prog_table; 882 - struct btf_attach_table btf_map_table; 903 + struct hashmap *btf_prog_table; 904 + struct hashmap *btf_map_table; 883 905 int err, fd = -1; 884 906 __u32 id = 0; 885 907 ··· 895 917 return BAD_ARG(); 896 918 } 897 919 898 - hash_init(btf_prog_table.table); 899 - hash_init(btf_map_table.table); 900 - err = build_btf_tables(&btf_prog_table, &btf_map_table); 920 + btf_prog_table = hashmap__new(hash_fn_for_key_as_id, 921 + equal_fn_for_key_as_id, NULL); 922 + btf_map_table = hashmap__new(hash_fn_for_key_as_id, 923 + equal_fn_for_key_as_id, NULL); 924 + if (!btf_prog_table || !btf_map_table) { 925 + hashmap__free(btf_prog_table); 926 + hashmap__free(btf_map_table); 927 + if (fd >= 0) 928 + close(fd); 929 + p_err("failed to create hashmap for object references"); 930 + return -1; 931 + } 932 + err = build_btf_tables(btf_prog_table, btf_map_table); 901 933 if (err) { 902 934 if (fd >= 0) 903 935 close(fd); ··· 916 928 build_obj_refs_table(&refs_table, BPF_OBJ_BTF); 917 929 918 930 if (fd >= 0) { 919 - err = show_btf(fd, &btf_prog_table, &btf_map_table); 931 + err = show_btf(fd, btf_prog_table, btf_map_table); 920 932 close(fd); 921 933 goto exit_free; 922 934 } ··· 948 960 break; 949 961 } 950 962 951 - err = show_btf(fd, &btf_prog_table, &btf_map_table); 963 + err = show_btf(fd, btf_prog_table, btf_map_table); 952 964 close(fd); 953 965 if (err) 954 966 break; ··· 958 970 jsonw_end_array(json_wtr); /* root array */ 959 971 960 972 exit_free: 961 - delete_btf_table(&btf_prog_table); 962 - delete_btf_table(&btf_map_table); 963 - delete_obj_refs_table(&refs_table); 973 + hashmap__free(btf_prog_table); 974 + hashmap__free(btf_map_table); 975 + delete_obj_refs_table(refs_table); 964 976 965 977 return err; 966 978 }
+30 -20
tools/bpf/bpftool/common.c
··· 22 22 #include <sys/vfs.h> 23 23 24 24 #include <bpf/bpf.h> 25 + #include <bpf/hashmap.h> 25 26 #include <bpf/libbpf.h> /* libbpf_num_possible_cpus */ 26 27 27 28 #include "main.h" ··· 394 393 } 395 394 396 395 /* extra params for nftw cb */ 397 - static struct pinned_obj_table *build_fn_table; 396 + static struct hashmap *build_fn_table; 398 397 static enum bpf_obj_type build_fn_type; 399 398 400 399 static int do_build_table_cb(const char *fpath, const struct stat *sb, ··· 402 401 { 403 402 struct bpf_prog_info pinned_info; 404 403 __u32 len = sizeof(pinned_info); 405 - struct pinned_obj *obj_node; 406 404 enum bpf_obj_type objtype; 407 405 int fd, err = 0; 406 + char *path; 408 407 409 408 if (typeflag != FTW_F) 410 409 goto out_ret; ··· 421 420 if (bpf_obj_get_info_by_fd(fd, &pinned_info, &len)) 422 421 goto out_close; 423 422 424 - obj_node = calloc(1, sizeof(*obj_node)); 425 - if (!obj_node) { 423 + path = strdup(fpath); 424 + if (!path) { 426 425 err = -1; 427 426 goto out_close; 428 427 } 429 428 430 - obj_node->id = pinned_info.id; 431 - obj_node->path = strdup(fpath); 432 - if (!obj_node->path) { 433 - err = -1; 434 - free(obj_node); 429 + err = hashmap__append(build_fn_table, u32_as_hash_field(pinned_info.id), path); 430 + if (err) { 431 + p_err("failed to append entry to hashmap for ID %u, path '%s': %s", 432 + pinned_info.id, path, strerror(errno)); 435 433 goto out_close; 436 434 } 437 435 438 - hash_add(build_fn_table->table, &obj_node->hash, obj_node->id); 439 436 out_close: 440 437 close(fd); 441 438 out_ret: 442 439 return err; 443 440 } 444 441 445 - int build_pinned_obj_table(struct pinned_obj_table *tab, 442 + int build_pinned_obj_table(struct hashmap *tab, 446 443 enum bpf_obj_type type) 447 444 { 448 445 struct mntent *mntent = NULL; ··· 469 470 return err; 470 471 } 471 472 472 - void delete_pinned_obj_table(struct pinned_obj_table *tab) 473 + void delete_pinned_obj_table(struct hashmap *map) 473 474 { 474 - struct pinned_obj *obj; 475 - struct hlist_node *tmp; 476 - unsigned int bkt; 475 + struct hashmap_entry *entry; 476 + size_t bkt; 477 477 478 - hash_for_each_safe(tab->table, bkt, tmp, obj, hash) { 479 - hash_del(&obj->hash); 480 - free(obj->path); 481 - free(obj); 482 - } 478 + if (!map) 479 + return; 480 + 481 + hashmap__for_each_entry(map, entry, bkt) 482 + free(entry->value); 483 + 484 + hashmap__free(map); 483 485 } 484 486 485 487 unsigned int get_page_size(void) ··· 961 961 } 962 962 963 963 return fd; 964 + } 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; 964 974 }
+28 -17
tools/bpf/bpftool/link.c
··· 7 7 #include <unistd.h> 8 8 9 9 #include <bpf/bpf.h> 10 + #include <bpf/hashmap.h> 10 11 11 12 #include "json_writer.h" 12 13 #include "main.h" ··· 20 19 [BPF_LINK_TYPE_ITER] = "iter", 21 20 [BPF_LINK_TYPE_NETNS] = "netns", 22 21 }; 22 + 23 + static struct hashmap *link_table; 23 24 24 25 static int link_parse_fd(int *argc, char ***argv) 25 26 { ··· 159 156 break; 160 157 } 161 158 162 - if (!hash_empty(link_table.table)) { 163 - struct pinned_obj *obj; 159 + if (!hashmap__empty(link_table)) { 160 + struct hashmap_entry *entry; 164 161 165 162 jsonw_name(json_wtr, "pinned"); 166 163 jsonw_start_array(json_wtr); 167 - hash_for_each_possible(link_table.table, obj, hash, info->id) { 168 - if (obj->id == info->id) 169 - jsonw_string(json_wtr, obj->path); 170 - } 164 + hashmap__for_each_key_entry(link_table, entry, 165 + u32_as_hash_field(info->id)) 166 + jsonw_string(json_wtr, entry->value); 171 167 jsonw_end_array(json_wtr); 172 168 } 173 169 174 - emit_obj_refs_json(&refs_table, info->id, json_wtr); 170 + emit_obj_refs_json(refs_table, info->id, json_wtr); 175 171 176 172 jsonw_end_object(json_wtr); 177 173 ··· 246 244 break; 247 245 } 248 246 249 - if (!hash_empty(link_table.table)) { 250 - struct pinned_obj *obj; 247 + if (!hashmap__empty(link_table)) { 248 + struct hashmap_entry *entry; 251 249 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 - } 250 + hashmap__for_each_key_entry(link_table, entry, 251 + u32_as_hash_field(info->id)) 252 + printf("\n\tpinned %s", (char *)entry->value); 256 253 } 257 - emit_obj_refs_plain(&refs_table, info->id, "\n\tpids "); 254 + emit_obj_refs_plain(refs_table, info->id, "\n\tpids "); 258 255 259 256 printf("\n"); 260 257 ··· 303 302 __u32 id = 0; 304 303 int err, fd; 305 304 306 - if (show_pinned) 307 - build_pinned_obj_table(&link_table, BPF_OBJ_LINK); 305 + if (show_pinned) { 306 + link_table = hashmap__new(hash_fn_for_key_as_id, 307 + equal_fn_for_key_as_id, NULL); 308 + if (!link_table) { 309 + p_err("failed to create hashmap for pinned paths"); 310 + return -1; 311 + } 312 + build_pinned_obj_table(link_table, BPF_OBJ_LINK); 313 + } 308 314 build_obj_refs_table(&refs_table, BPF_OBJ_LINK); 309 315 310 316 if (argc == 2) { ··· 352 344 if (json_output) 353 345 jsonw_end_array(json_wtr); 354 346 355 - delete_obj_refs_table(&refs_table); 347 + delete_obj_refs_table(refs_table); 348 + 349 + if (show_pinned) 350 + delete_pinned_obj_table(link_table); 356 351 357 352 return errno == ENOENT ? 0 : -1; 358 353 }
+3 -14
tools/bpf/bpftool/main.c
··· 10 10 #include <string.h> 11 11 12 12 #include <bpf/bpf.h> 13 - #include <bpf/libbpf.h> 14 13 #include <bpf/btf.h> 14 + #include <bpf/hashmap.h> 15 + #include <bpf/libbpf.h> 15 16 16 17 #include "main.h" 17 18 ··· 32 31 bool relaxed_maps; 33 32 bool use_loader; 34 33 struct btf *base_btf; 35 - struct pinned_obj_table prog_table; 36 - struct pinned_obj_table map_table; 37 - struct pinned_obj_table link_table; 38 - struct obj_refs_table refs_table; 34 + struct hashmap *refs_table; 39 35 40 36 static void __noreturn clean_and_exit(int i) 41 37 { ··· 407 409 block_mount = false; 408 410 bin_name = argv[0]; 409 411 410 - hash_init(prog_table.table); 411 - hash_init(map_table.table); 412 - hash_init(link_table.table); 413 - 414 412 opterr = 0; 415 413 while ((opt = getopt_long(argc, argv, "VhpjfLmndB:", 416 414 options, NULL)) >= 0) { ··· 473 479 if (json_output) 474 480 jsonw_destroy(&json_wtr); 475 481 476 - if (show_pinned) { 477 - delete_pinned_obj_table(&prog_table); 478 - delete_pinned_obj_table(&map_table); 479 - delete_pinned_obj_table(&link_table); 480 - } 481 482 btf__free(base_btf); 482 483 483 484 return ret;
+27 -27
tools/bpf/bpftool/main.h
··· 11 11 #include <linux/bpf.h> 12 12 #include <linux/compiler.h> 13 13 #include <linux/kernel.h> 14 - #include <linux/hashtable.h> 15 14 #include <tools/libc_compat.h> 16 15 16 + #include <bpf/hashmap.h> 17 17 #include <bpf/libbpf.h> 18 18 19 19 #include "json_writer.h" ··· 91 91 extern bool relaxed_maps; 92 92 extern bool use_loader; 93 93 extern struct btf *base_btf; 94 - extern struct pinned_obj_table prog_table; 95 - extern struct pinned_obj_table map_table; 96 - extern struct pinned_obj_table link_table; 97 - extern struct obj_refs_table refs_table; 94 + extern struct hashmap *refs_table; 98 95 99 96 void __printf(1, 2) p_err(const char *fmt, ...); 100 97 void __printf(1, 2) p_info(const char *fmt, ...); ··· 105 108 106 109 int mount_tracefs(const char *target); 107 110 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 - 118 - struct obj_refs_table { 119 - DECLARE_HASHTABLE(table, 16); 120 - }; 121 - 122 111 struct obj_ref { 123 112 int pid; 124 113 char comm[16]; 125 114 }; 126 115 127 116 struct obj_refs { 128 - struct hlist_node node; 129 - __u32 id; 130 117 int ref_cnt; 131 118 struct obj_ref *refs; 132 119 }; ··· 118 137 struct btf; 119 138 struct bpf_line_info; 120 139 121 - int build_pinned_obj_table(struct pinned_obj_table *table, 140 + int build_pinned_obj_table(struct hashmap *table, 122 141 enum bpf_obj_type type); 123 - void delete_pinned_obj_table(struct pinned_obj_table *tab); 124 - __weak int build_obj_refs_table(struct obj_refs_table *table, 142 + void delete_pinned_obj_table(struct hashmap *table); 143 + __weak int build_obj_refs_table(struct hashmap **table, 125 144 enum bpf_obj_type type); 126 - __weak void delete_obj_refs_table(struct obj_refs_table *table); 127 - __weak void emit_obj_refs_json(struct obj_refs_table *table, __u32 id, 145 + __weak void delete_obj_refs_table(struct hashmap *table); 146 + __weak void emit_obj_refs_json(struct hashmap *table, __u32 id, 128 147 json_writer_t *json_wtr); 129 - __weak void emit_obj_refs_plain(struct obj_refs_table *table, __u32 id, 148 + __weak void emit_obj_refs_plain(struct hashmap *table, __u32 id, 130 149 const char *prefix); 131 150 void print_dev_plain(__u32 ifindex, __u64 ns_dev, __u64 ns_inode); 132 151 void print_dev_json(__u32 ifindex, __u64 ns_dev, __u64 ns_inode); ··· 240 259 241 260 int print_all_levels(__maybe_unused enum libbpf_print_level level, 242 261 const char *format, va_list args); 262 + 263 + size_t hash_fn_for_key_as_id(const void *key, void *ctx); 264 + bool equal_fn_for_key_as_id(const void *k1, const void *k2, void *ctx); 265 + 266 + static inline void *u32_as_hash_field(__u32 x) 267 + { 268 + return (void *)(uintptr_t)x; 269 + } 270 + 271 + static inline __u32 hash_field_as_u32(const void *x) 272 + { 273 + return (__u32)(uintptr_t)x; 274 + } 275 + 276 + static inline bool hashmap__empty(struct hashmap *map) 277 + { 278 + return map ? hashmap__size(map) == 0 : true; 279 + } 280 + 243 281 #endif
+28 -17
tools/bpf/bpftool/map.c
··· 17 17 18 18 #include <bpf/bpf.h> 19 19 #include <bpf/btf.h> 20 + #include <bpf/hashmap.h> 20 21 21 22 #include "json_writer.h" 22 23 #include "main.h" ··· 56 55 }; 57 56 58 57 const size_t map_type_name_size = ARRAY_SIZE(map_type_name); 58 + 59 + static struct hashmap *map_table; 59 60 60 61 static bool map_is_per_cpu(__u32 type) 61 62 { ··· 538 535 if (info->btf_id) 539 536 jsonw_int_field(json_wtr, "btf_id", info->btf_id); 540 537 541 - if (!hash_empty(map_table.table)) { 542 - struct pinned_obj *obj; 538 + if (!hashmap__empty(map_table)) { 539 + struct hashmap_entry *entry; 543 540 544 541 jsonw_name(json_wtr, "pinned"); 545 542 jsonw_start_array(json_wtr); 546 - hash_for_each_possible(map_table.table, obj, hash, info->id) { 547 - if (obj->id == info->id) 548 - jsonw_string(json_wtr, obj->path); 549 - } 543 + hashmap__for_each_key_entry(map_table, entry, 544 + u32_as_hash_field(info->id)) 545 + jsonw_string(json_wtr, entry->value); 550 546 jsonw_end_array(json_wtr); 551 547 } 552 548 553 - emit_obj_refs_json(&refs_table, info->id, json_wtr); 549 + emit_obj_refs_json(refs_table, info->id, json_wtr); 554 550 555 551 jsonw_end_object(json_wtr); 556 552 ··· 612 610 } 613 611 close(fd); 614 612 615 - if (!hash_empty(map_table.table)) { 616 - struct pinned_obj *obj; 613 + if (!hashmap__empty(map_table)) { 614 + struct hashmap_entry *entry; 617 615 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 - } 616 + hashmap__for_each_key_entry(map_table, entry, 617 + u32_as_hash_field(info->id)) 618 + printf("\n\tpinned %s", (char *)entry->value); 622 619 } 623 620 printf("\n"); 624 621 ··· 637 636 if (frozen) 638 637 printf("%sfrozen", info->btf_id ? " " : ""); 639 638 640 - emit_obj_refs_plain(&refs_table, info->id, "\n\tpids "); 639 + emit_obj_refs_plain(refs_table, info->id, "\n\tpids "); 641 640 642 641 printf("\n"); 643 642 return 0; ··· 695 694 int err; 696 695 int fd; 697 696 698 - if (show_pinned) 699 - build_pinned_obj_table(&map_table, BPF_OBJ_MAP); 697 + if (show_pinned) { 698 + map_table = hashmap__new(hash_fn_for_key_as_id, 699 + equal_fn_for_key_as_id, NULL); 700 + if (!map_table) { 701 + p_err("failed to create hashmap for pinned paths"); 702 + return -1; 703 + } 704 + build_pinned_obj_table(map_table, BPF_OBJ_MAP); 705 + } 700 706 build_obj_refs_table(&refs_table, BPF_OBJ_MAP); 701 707 702 708 if (argc == 2) ··· 748 740 if (json_output) 749 741 jsonw_end_array(json_wtr); 750 742 751 - delete_obj_refs_table(&refs_table); 743 + delete_obj_refs_table(refs_table); 744 + 745 + if (show_pinned) 746 + delete_pinned_obj_table(map_table); 752 747 753 748 return errno == ENOENT ? 0 : -1; 754 749 }
+52 -38
tools/bpf/bpftool/pids.c
··· 6 6 #include <stdlib.h> 7 7 #include <string.h> 8 8 #include <unistd.h> 9 + 9 10 #include <bpf/bpf.h> 11 + #include <bpf/hashmap.h> 10 12 11 13 #include "main.h" 12 14 #include "skeleton/pid_iter.h" 13 15 14 16 #ifdef BPFTOOL_WITHOUT_SKELETONS 15 17 16 - int build_obj_refs_table(struct obj_refs_table *table, enum bpf_obj_type type) 18 + int build_obj_refs_table(struct hashmap **map, enum bpf_obj_type type) 17 19 { 18 20 return -ENOTSUP; 19 21 } 20 - void delete_obj_refs_table(struct obj_refs_table *table) {} 21 - void emit_obj_refs_plain(struct obj_refs_table *table, __u32 id, const char *prefix) {} 22 - void emit_obj_refs_json(struct obj_refs_table *table, __u32 id, json_writer_t *json_writer) {} 22 + void delete_obj_refs_table(struct hashmap *map) {} 23 + void emit_obj_refs_plain(struct hashmap *map, __u32 id, const char *prefix) {} 24 + void emit_obj_refs_json(struct hashmap *map, __u32 id, json_writer_t *json_writer) {} 23 25 24 26 #else /* BPFTOOL_WITHOUT_SKELETONS */ 25 27 26 28 #include "pid_iter.skel.h" 27 29 28 - static void add_ref(struct obj_refs_table *table, struct pid_iter_entry *e) 30 + static void add_ref(struct hashmap *map, struct pid_iter_entry *e) 29 31 { 32 + struct hashmap_entry *entry; 30 33 struct obj_refs *refs; 31 34 struct obj_ref *ref; 35 + int err, i; 32 36 void *tmp; 33 - int i; 34 37 35 - hash_for_each_possible(table->table, refs, node, e->id) { 36 - if (refs->id != e->id) 37 - continue; 38 + hashmap__for_each_key_entry(map, entry, u32_as_hash_field(e->id)) { 39 + refs = entry->value; 38 40 39 41 for (i = 0; i < refs->ref_cnt; i++) { 40 42 if (refs->refs[i].pid == e->pid) ··· 66 64 return; 67 65 } 68 66 69 - refs->id = e->id; 70 67 refs->refs = malloc(sizeof(*refs->refs)); 71 68 if (!refs->refs) { 72 69 free(refs); ··· 77 76 ref->pid = e->pid; 78 77 memcpy(ref->comm, e->comm, sizeof(ref->comm)); 79 78 refs->ref_cnt = 1; 80 - hash_add(table->table, &refs->node, e->id); 79 + 80 + err = hashmap__append(map, u32_as_hash_field(e->id), refs); 81 + if (err) 82 + p_err("failed to append entry to hashmap for ID %u: %s", 83 + e->id, strerror(errno)); 81 84 } 82 85 83 86 static int __printf(2, 0) ··· 92 87 return 0; 93 88 } 94 89 95 - int build_obj_refs_table(struct obj_refs_table *table, enum bpf_obj_type type) 90 + int build_obj_refs_table(struct hashmap **map, enum bpf_obj_type type) 96 91 { 97 92 struct pid_iter_entry *e; 98 93 char buf[4096 / sizeof(*e) * sizeof(*e)]; ··· 100 95 int err, ret, fd = -1, i; 101 96 libbpf_print_fn_t default_print; 102 97 103 - hash_init(table->table); 98 + *map = hashmap__new(hash_fn_for_key_as_id, equal_fn_for_key_as_id, NULL); 99 + if (!*map) { 100 + p_err("failed to create hashmap for PID references"); 101 + return -1; 102 + } 104 103 set_max_rlimit(); 105 104 106 105 skel = pid_iter_bpf__open(); ··· 160 151 161 152 e = (void *)buf; 162 153 for (i = 0; i < ret; i++, e++) { 163 - add_ref(table, e); 154 + add_ref(*map, e); 164 155 } 165 156 } 166 157 err = 0; ··· 171 162 return err; 172 163 } 173 164 174 - void delete_obj_refs_table(struct obj_refs_table *table) 165 + void delete_obj_refs_table(struct hashmap *map) 175 166 { 176 - struct obj_refs *refs; 177 - struct hlist_node *tmp; 178 - unsigned int bkt; 167 + struct hashmap_entry *entry; 168 + size_t bkt; 179 169 180 - hash_for_each_safe(table->table, bkt, tmp, refs, node) { 181 - hash_del(&refs->node); 170 + if (!map) 171 + return; 172 + 173 + hashmap__for_each_entry(map, entry, bkt) { 174 + struct obj_refs *refs = entry->value; 175 + 182 176 free(refs->refs); 183 177 free(refs); 184 178 } 179 + 180 + hashmap__free(map); 185 181 } 186 182 187 - void emit_obj_refs_json(struct obj_refs_table *table, __u32 id, 183 + void emit_obj_refs_json(struct hashmap *map, __u32 id, 188 184 json_writer_t *json_writer) 189 185 { 190 - struct obj_refs *refs; 191 - struct obj_ref *ref; 192 - int i; 186 + struct hashmap_entry *entry; 193 187 194 - if (hash_empty(table->table)) 188 + if (hashmap__empty(map)) 195 189 return; 196 190 197 - hash_for_each_possible(table->table, refs, node, id) { 198 - if (refs->id != id) 199 - continue; 191 + hashmap__for_each_key_entry(map, entry, u32_as_hash_field(id)) { 192 + struct obj_refs *refs = entry->value; 193 + int i; 194 + 200 195 if (refs->ref_cnt == 0) 201 196 break; 202 197 203 198 jsonw_name(json_writer, "pids"); 204 199 jsonw_start_array(json_writer); 205 200 for (i = 0; i < refs->ref_cnt; i++) { 206 - ref = &refs->refs[i]; 201 + struct obj_ref *ref = &refs->refs[i]; 202 + 207 203 jsonw_start_object(json_writer); 208 204 jsonw_int_field(json_writer, "pid", ref->pid); 209 205 jsonw_string_field(json_writer, "comm", ref->comm); ··· 219 205 } 220 206 } 221 207 222 - void emit_obj_refs_plain(struct obj_refs_table *table, __u32 id, const char *prefix) 208 + void emit_obj_refs_plain(struct hashmap *map, __u32 id, const char *prefix) 223 209 { 224 - struct obj_refs *refs; 225 - struct obj_ref *ref; 226 - int i; 210 + struct hashmap_entry *entry; 227 211 228 - if (hash_empty(table->table)) 212 + if (hashmap__empty(map)) 229 213 return; 230 214 231 - hash_for_each_possible(table->table, refs, node, id) { 232 - if (refs->id != id) 233 - continue; 215 + hashmap__for_each_key_entry(map, entry, u32_as_hash_field(id)) { 216 + struct obj_refs *refs = entry->value; 217 + int i; 218 + 234 219 if (refs->ref_cnt == 0) 235 220 break; 236 221 237 222 printf("%s", prefix); 238 223 for (i = 0; i < refs->ref_cnt; i++) { 239 - ref = &refs->refs[i]; 224 + struct obj_ref *ref = &refs->refs[i]; 225 + 240 226 printf("%s%s(%d)", i == 0 ? "" : ", ", ref->comm, ref->pid); 241 227 } 242 228 break;
+28 -17
tools/bpf/bpftool/prog.c
··· 24 24 25 25 #include <bpf/bpf.h> 26 26 #include <bpf/btf.h> 27 + #include <bpf/hashmap.h> 27 28 #include <bpf/libbpf.h> 28 29 #include <bpf/skel_internal.h> 29 30 ··· 84 83 [BPF_FLOW_DISSECTOR] = "flow_dissector", 85 84 [__MAX_BPF_ATTACH_TYPE] = NULL, 86 85 }; 86 + 87 + static struct hashmap *prog_table; 87 88 88 89 static enum bpf_attach_type parse_attach_type(const char *str) 89 90 { ··· 419 416 if (info->btf_id) 420 417 jsonw_int_field(json_wtr, "btf_id", info->btf_id); 421 418 422 - if (!hash_empty(prog_table.table)) { 423 - struct pinned_obj *obj; 419 + if (!hashmap__empty(prog_table)) { 420 + struct hashmap_entry *entry; 424 421 425 422 jsonw_name(json_wtr, "pinned"); 426 423 jsonw_start_array(json_wtr); 427 - hash_for_each_possible(prog_table.table, obj, hash, info->id) { 428 - if (obj->id == info->id) 429 - jsonw_string(json_wtr, obj->path); 430 - } 424 + hashmap__for_each_key_entry(prog_table, entry, 425 + u32_as_hash_field(info->id)) 426 + jsonw_string(json_wtr, entry->value); 431 427 jsonw_end_array(json_wtr); 432 428 } 433 429 434 - emit_obj_refs_json(&refs_table, info->id, json_wtr); 430 + emit_obj_refs_json(refs_table, info->id, json_wtr); 435 431 436 432 show_prog_metadata(fd, info->nr_map_ids); 437 433 ··· 490 488 if (info->nr_map_ids) 491 489 show_prog_maps(fd, info->nr_map_ids); 492 490 493 - if (!hash_empty(prog_table.table)) { 494 - struct pinned_obj *obj; 491 + if (!hashmap__empty(prog_table)) { 492 + struct hashmap_entry *entry; 495 493 496 - hash_for_each_possible(prog_table.table, obj, hash, info->id) { 497 - if (obj->id == info->id) 498 - printf("\n\tpinned %s", obj->path); 499 - } 494 + hashmap__for_each_key_entry(prog_table, entry, 495 + u32_as_hash_field(info->id)) 496 + printf("\n\tpinned %s", (char *)entry->value); 500 497 } 501 498 502 499 if (info->btf_id) 503 500 printf("\n\tbtf_id %d", info->btf_id); 504 501 505 - emit_obj_refs_plain(&refs_table, info->id, "\n\tpids "); 502 + emit_obj_refs_plain(refs_table, info->id, "\n\tpids "); 506 503 507 504 printf("\n"); 508 505 ··· 568 567 int err; 569 568 int fd; 570 569 571 - if (show_pinned) 572 - build_pinned_obj_table(&prog_table, BPF_OBJ_PROG); 570 + if (show_pinned) { 571 + prog_table = hashmap__new(hash_fn_for_key_as_id, 572 + equal_fn_for_key_as_id, NULL); 573 + if (!prog_table) { 574 + p_err("failed to create hashmap for pinned paths"); 575 + return -1; 576 + } 577 + build_pinned_obj_table(prog_table, BPF_OBJ_PROG); 578 + } 573 579 build_obj_refs_table(&refs_table, BPF_OBJ_PROG); 574 580 575 581 if (argc == 2) ··· 619 611 if (json_output) 620 612 jsonw_end_array(json_wtr); 621 613 622 - delete_obj_refs_table(&refs_table); 614 + delete_obj_refs_table(refs_table); 615 + 616 + if (show_pinned) 617 + delete_pinned_obj_table(prog_table); 623 618 624 619 return err; 625 620 }