Orange Pi5 kernel

Deprecated Linux kernel 5.10.110 for OrangePi 5/5B/5+ boards

3 Commits   0 Branches   0 Tags
^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) }