^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /* Copyright (C) 2020 Facebook */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) #include <errno.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) #include <stdio.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) #include <unistd.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) #include <linux/err.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <bpf/bpf.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <bpf/btf.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <bpf/libbpf.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include "json_writer.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include "main.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #define STRUCT_OPS_VALUE_PREFIX "bpf_struct_ops_"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) static const struct btf_type *map_info_type;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) static __u32 map_info_alloc_len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) static struct btf *btf_vmlinux;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) static __s32 map_info_type_id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) struct res {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) unsigned int nr_maps;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) unsigned int nr_errs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) static const struct btf *get_btf_vmlinux(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) if (btf_vmlinux)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) return btf_vmlinux;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) btf_vmlinux = libbpf_find_kernel_btf();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) if (IS_ERR(btf_vmlinux))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) p_err("struct_ops requires kernel CONFIG_DEBUG_INFO_BTF=y");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) return btf_vmlinux;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) static const char *get_kern_struct_ops_name(const struct bpf_map_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) const struct btf *kern_btf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) const struct btf_type *t;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) const char *st_ops_name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) kern_btf = get_btf_vmlinux();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) if (IS_ERR(kern_btf))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) return "<btf_vmlinux_not_found>";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) t = btf__type_by_id(kern_btf, info->btf_vmlinux_value_type_id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) st_ops_name = btf__name_by_offset(kern_btf, t->name_off);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) st_ops_name += strlen(STRUCT_OPS_VALUE_PREFIX);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) return st_ops_name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) static __s32 get_map_info_type_id(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) const struct btf *kern_btf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) if (map_info_type_id)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) return map_info_type_id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) kern_btf = get_btf_vmlinux();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) if (IS_ERR(kern_btf)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) map_info_type_id = PTR_ERR(kern_btf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) return map_info_type_id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) map_info_type_id = btf__find_by_name_kind(kern_btf, "bpf_map_info",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) BTF_KIND_STRUCT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) if (map_info_type_id < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) p_err("can't find bpf_map_info from btf_vmlinux");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) return map_info_type_id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) map_info_type = btf__type_by_id(kern_btf, map_info_type_id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) /* Ensure map_info_alloc() has at least what the bpftool needs */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) map_info_alloc_len = map_info_type->size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) if (map_info_alloc_len < sizeof(struct bpf_map_info))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) map_info_alloc_len = sizeof(struct bpf_map_info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) return map_info_type_id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) /* If the subcmd needs to print out the bpf_map_info,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) * it should always call map_info_alloc to allocate
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) * a bpf_map_info object instead of allocating it
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) * on the stack.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) * map_info_alloc() will take the running kernel's btf
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) * into account. i.e. it will consider the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) * sizeof(struct bpf_map_info) of the running kernel.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) * It will enable the "struct_ops" cmd to print the latest
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) * "struct bpf_map_info".
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) * [ Recall that "struct_ops" requires the kernel's btf to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) * be available ]
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) static struct bpf_map_info *map_info_alloc(__u32 *alloc_len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) struct bpf_map_info *info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) if (get_map_info_type_id() < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) info = calloc(1, map_info_alloc_len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) if (!info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) p_err("mem alloc failed");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) *alloc_len = map_info_alloc_len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) return info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) /* It iterates all struct_ops maps of the system.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) * It returns the fd in "*res_fd" and map_info in "*info".
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) * In the very first iteration, info->id should be 0.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) * An optional map "*name" filter can be specified.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) * The filter can be made more flexible in the future.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) * e.g. filter by kernel-struct-ops-name, regex-name, glob-name, ...etc.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) * Return value:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) * 1: A struct_ops map found. It is returned in "*res_fd" and "*info".
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) * The caller can continue to call get_next in the future.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) * 0: No struct_ops map is returned.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) * All struct_ops map has been found.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) * -1: Error and the caller should abort the iteration.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) static int get_next_struct_ops_map(const char *name, int *res_fd,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) struct bpf_map_info *info, __u32 info_len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) __u32 id = info->id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) int err, fd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) while (true) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) err = bpf_map_get_next_id(id, &id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) if (err) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) if (errno == ENOENT)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) p_err("can't get next map: %s", strerror(errno));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) fd = bpf_map_get_fd_by_id(id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) if (fd < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) if (errno == ENOENT)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) p_err("can't get map by id (%u): %s",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) id, strerror(errno));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) err = bpf_obj_get_info_by_fd(fd, info, &info_len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) if (err) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) p_err("can't get map info: %s", strerror(errno));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) close(fd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) if (info->type == BPF_MAP_TYPE_STRUCT_OPS &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) (!name || !strcmp(name, info->name))) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) *res_fd = fd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) close(fd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) static int cmd_retval(const struct res *res, bool must_have_one_map)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) if (res->nr_errs || (!res->nr_maps && must_have_one_map))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) /* "data" is the work_func private storage */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) typedef int (*work_func)(int fd, const struct bpf_map_info *info, void *data,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) struct json_writer *wtr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) /* Find all struct_ops map in the system.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) * Filter out by "name" (if specified).
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) * Then call "func(fd, info, data, wtr)" on each struct_ops map found.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) static struct res do_search(const char *name, work_func func, void *data,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) struct json_writer *wtr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) struct bpf_map_info *info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) struct res res = {};
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) __u32 info_len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) int fd, err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) info = map_info_alloc(&info_len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) if (!info) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) res.nr_errs++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) return res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) if (wtr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) jsonw_start_array(wtr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) while ((err = get_next_struct_ops_map(name, &fd, info, info_len)) == 1) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) res.nr_maps++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) err = func(fd, info, data, wtr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) res.nr_errs++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) close(fd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) if (wtr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) jsonw_end_array(wtr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) res.nr_errs++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) if (!wtr && name && !res.nr_errs && !res.nr_maps)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) /* It is not printing empty [].
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) * Thus, needs to specifically say nothing found
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) * for "name" here.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) p_err("no struct_ops found for %s", name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) else if (!wtr && json_output && !res.nr_errs)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) /* The "func()" above is not writing any json (i.e. !wtr
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) * test here).
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) * However, "-j" is enabled and there is no errs here,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) * so call json_null() as the current convention of
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) * other cmds.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) jsonw_null(json_wtr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) free(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) return res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) static struct res do_one_id(const char *id_str, work_func func, void *data,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) struct json_writer *wtr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) struct bpf_map_info *info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) struct res res = {};
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) unsigned long id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) __u32 info_len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) char *endptr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) int fd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) id = strtoul(id_str, &endptr, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) if (*endptr || !id || id > UINT32_MAX) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) p_err("invalid id %s", id_str);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) res.nr_errs++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) return res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) fd = bpf_map_get_fd_by_id(id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) if (fd == -1) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) p_err("can't get map by id (%lu): %s", id, strerror(errno));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) res.nr_errs++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) return res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) info = map_info_alloc(&info_len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) if (!info) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) res.nr_errs++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) goto done;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) if (bpf_obj_get_info_by_fd(fd, info, &info_len)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) p_err("can't get map info: %s", strerror(errno));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) res.nr_errs++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) goto done;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) if (info->type != BPF_MAP_TYPE_STRUCT_OPS) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) p_err("%s id %u is not a struct_ops map", info->name, info->id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) res.nr_errs++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) goto done;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) res.nr_maps++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) if (func(fd, info, data, wtr))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) res.nr_errs++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) else if (!wtr && json_output)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) /* The "func()" above is not writing any json (i.e. !wtr
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) * test here).
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) * However, "-j" is enabled and there is no errs here,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) * so call json_null() as the current convention of
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) * other cmds.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) jsonw_null(json_wtr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) done:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) free(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) close(fd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) return res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) static struct res do_work_on_struct_ops(const char *search_type,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) const char *search_term,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) work_func func, void *data,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) struct json_writer *wtr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) if (search_type) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) if (is_prefix(search_type, "id"))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) return do_one_id(search_term, func, data, wtr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) else if (!is_prefix(search_type, "name"))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) usage();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) return do_search(search_term, func, data, wtr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) static int __do_show(int fd, const struct bpf_map_info *info, void *data,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) struct json_writer *wtr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) if (wtr) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) jsonw_start_object(wtr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) jsonw_uint_field(wtr, "id", info->id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) jsonw_string_field(wtr, "name", info->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) jsonw_string_field(wtr, "kernel_struct_ops",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) get_kern_struct_ops_name(info));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) jsonw_end_object(wtr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) printf("%u: %-15s %-32s\n", info->id, info->name,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) get_kern_struct_ops_name(info));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) static int do_show(int argc, char **argv)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) const char *search_type = NULL, *search_term = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) struct res res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) if (argc && argc != 2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) usage();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) if (argc == 2) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) search_type = GET_ARG();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) search_term = GET_ARG();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) res = do_work_on_struct_ops(search_type, search_term, __do_show,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) NULL, json_wtr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) return cmd_retval(&res, !!search_term);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) static int __do_dump(int fd, const struct bpf_map_info *info, void *data,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) struct json_writer *wtr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) struct btf_dumper *d = (struct btf_dumper *)data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) const struct btf_type *struct_ops_type;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) const struct btf *kern_btf = d->btf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) const char *struct_ops_name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) int zero = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) void *value;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) /* note: d->jw == wtr */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) kern_btf = d->btf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) /* The kernel supporting BPF_MAP_TYPE_STRUCT_OPS must have
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) * btf_vmlinux_value_type_id.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) struct_ops_type = btf__type_by_id(kern_btf,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) info->btf_vmlinux_value_type_id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) struct_ops_name = btf__name_by_offset(kern_btf,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) struct_ops_type->name_off);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) value = calloc(1, info->value_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) if (!value) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) p_err("mem alloc failed");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) if (bpf_map_lookup_elem(fd, &zero, value)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) p_err("can't lookup struct_ops map %s id %u",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) info->name, info->id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) free(value);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) jsonw_start_object(wtr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) jsonw_name(wtr, "bpf_map_info");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) btf_dumper_type(d, map_info_type_id, (void *)info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) jsonw_end_object(wtr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) jsonw_start_object(wtr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) jsonw_name(wtr, struct_ops_name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) btf_dumper_type(d, info->btf_vmlinux_value_type_id, value);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) jsonw_end_object(wtr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) free(value);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) static int do_dump(int argc, char **argv)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) const char *search_type = NULL, *search_term = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) json_writer_t *wtr = json_wtr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) const struct btf *kern_btf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) struct btf_dumper d = {};
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) struct res res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) if (argc && argc != 2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) usage();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) if (argc == 2) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) search_type = GET_ARG();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) search_term = GET_ARG();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) kern_btf = get_btf_vmlinux();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) if (IS_ERR(kern_btf))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) if (!json_output) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) wtr = jsonw_new(stdout);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) if (!wtr) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) p_err("can't create json writer");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) jsonw_pretty(wtr, true);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) d.btf = kern_btf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) d.jw = wtr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) d.is_plain_text = !json_output;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) d.prog_id_as_func_ptr = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435) res = do_work_on_struct_ops(search_type, search_term, __do_dump, &d,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) wtr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) if (!json_output)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) jsonw_destroy(&wtr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) return cmd_retval(&res, !!search_term);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) static int __do_unregister(int fd, const struct bpf_map_info *info, void *data,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) struct json_writer *wtr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447) int zero = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449) if (bpf_map_delete_elem(fd, &zero)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450) p_err("can't unload %s %s id %u: %s",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451) get_kern_struct_ops_name(info), info->name,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452) info->id, strerror(errno));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456) p_info("Unregistered %s %s id %u",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457) get_kern_struct_ops_name(info), info->name,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458) info->id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463) static int do_unregister(int argc, char **argv)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465) const char *search_type, *search_term;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466) struct res res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468) if (argc != 2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469) usage();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471) search_type = GET_ARG();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472) search_term = GET_ARG();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474) res = do_work_on_struct_ops(search_type, search_term,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475) __do_unregister, NULL, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477) return cmd_retval(&res, true);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480) static int do_register(int argc, char **argv)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482) struct bpf_object_load_attr load_attr = {};
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483) const struct bpf_map_def *def;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484) struct bpf_map_info info = {};
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485) __u32 info_len = sizeof(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486) int nr_errs = 0, nr_maps = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) struct bpf_object *obj;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488) struct bpf_link *link;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) struct bpf_map *map;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490) const char *file;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492) if (argc != 1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493) usage();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495) file = GET_ARG();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497) obj = bpf_object__open(file);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498) if (IS_ERR_OR_NULL(obj))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501) set_max_rlimit();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503) load_attr.obj = obj;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504) if (verifier_logs)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505) /* log_level1 + log_level2 + stats, but not stable UAPI */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506) load_attr.log_level = 1 + 2 + 4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508) if (bpf_object__load_xattr(&load_attr)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509) bpf_object__close(obj);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513) bpf_object__for_each_map(map, obj) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514) def = bpf_map__def(map);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515) if (def->type != BPF_MAP_TYPE_STRUCT_OPS)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518) link = bpf_map__attach_struct_ops(map);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519) if (IS_ERR(link)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520) p_err("can't register struct_ops %s: %s",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521) bpf_map__name(map),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522) strerror(-PTR_ERR(link)));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523) nr_errs++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526) nr_maps++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528) bpf_link__disconnect(link);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529) bpf_link__destroy(link);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531) if (!bpf_obj_get_info_by_fd(bpf_map__fd(map), &info,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532) &info_len))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533) p_info("Registered %s %s id %u",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534) get_kern_struct_ops_name(&info),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535) bpf_map__name(map),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536) info.id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538) /* Not p_err. The struct_ops was attached
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539) * successfully.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541) p_info("Registered %s but can't find id: %s",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542) bpf_map__name(map), strerror(errno));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545) bpf_object__close(obj);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547) if (nr_errs)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550) if (!nr_maps) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551) p_err("no struct_ops found in %s", file);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555) if (json_output)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 556) jsonw_null(json_wtr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 557)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 558) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 559) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 560)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 561) static int do_help(int argc, char **argv)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 562) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 563) if (json_output) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 564) jsonw_null(json_wtr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 565) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 566) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 567)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 568) fprintf(stderr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 569) "Usage: %1$s %2$s { show | list } [STRUCT_OPS_MAP]\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 570) " %1$s %2$s dump [STRUCT_OPS_MAP]\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 571) " %1$s %2$s register OBJ\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 572) " %1$s %2$s unregister STRUCT_OPS_MAP\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 573) " %1$s %2$s help\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 574) "\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 575) " OPTIONS := { {-j|--json} [{-p|--pretty}] }\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 576) " STRUCT_OPS_MAP := [ id STRUCT_OPS_MAP_ID | name STRUCT_OPS_MAP_NAME ]\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 577) "",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 578) bin_name, argv[-2]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 579)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 580) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 581) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 582)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 583) static const struct cmd cmds[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 584) { "show", do_show },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 585) { "list", do_show },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 586) { "register", do_register },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 587) { "unregister", do_unregister },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 588) { "dump", do_dump },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 589) { "help", do_help },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 590) { 0 }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 591) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 592)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 593) int do_struct_ops(int argc, char **argv)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 594) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 595) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 596)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 597) err = cmd_select(cmds, argc, argv, do_help);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 598)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 599) if (!IS_ERR(btf_vmlinux))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 600) btf__free(btf_vmlinux);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 601)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 602) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 603) }