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