xref: /OK3568_Linux_fs/kernel/tools/bpf/bpftool/common.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
2*4882a593Smuzhiyun /* Copyright (C) 2017-2018 Netronome Systems, Inc. */
3*4882a593Smuzhiyun 
4*4882a593Smuzhiyun #define _GNU_SOURCE
5*4882a593Smuzhiyun #include <ctype.h>
6*4882a593Smuzhiyun #include <errno.h>
7*4882a593Smuzhiyun #include <fcntl.h>
8*4882a593Smuzhiyun #include <ftw.h>
9*4882a593Smuzhiyun #include <libgen.h>
10*4882a593Smuzhiyun #include <mntent.h>
11*4882a593Smuzhiyun #include <stdbool.h>
12*4882a593Smuzhiyun #include <stdio.h>
13*4882a593Smuzhiyun #include <stdlib.h>
14*4882a593Smuzhiyun #include <string.h>
15*4882a593Smuzhiyun #include <unistd.h>
16*4882a593Smuzhiyun #include <linux/limits.h>
17*4882a593Smuzhiyun #include <linux/magic.h>
18*4882a593Smuzhiyun #include <net/if.h>
19*4882a593Smuzhiyun #include <sys/mount.h>
20*4882a593Smuzhiyun #include <sys/resource.h>
21*4882a593Smuzhiyun #include <sys/stat.h>
22*4882a593Smuzhiyun #include <sys/vfs.h>
23*4882a593Smuzhiyun 
24*4882a593Smuzhiyun #include <bpf/bpf.h>
25*4882a593Smuzhiyun #include <bpf/libbpf.h> /* libbpf_num_possible_cpus */
26*4882a593Smuzhiyun 
27*4882a593Smuzhiyun #include "main.h"
28*4882a593Smuzhiyun 
29*4882a593Smuzhiyun #ifndef BPF_FS_MAGIC
30*4882a593Smuzhiyun #define BPF_FS_MAGIC		0xcafe4a11
31*4882a593Smuzhiyun #endif
32*4882a593Smuzhiyun 
33*4882a593Smuzhiyun const char * const attach_type_name[__MAX_BPF_ATTACH_TYPE] = {
34*4882a593Smuzhiyun 	[BPF_CGROUP_INET_INGRESS]	= "ingress",
35*4882a593Smuzhiyun 	[BPF_CGROUP_INET_EGRESS]	= "egress",
36*4882a593Smuzhiyun 	[BPF_CGROUP_INET_SOCK_CREATE]	= "sock_create",
37*4882a593Smuzhiyun 	[BPF_CGROUP_INET_SOCK_RELEASE]	= "sock_release",
38*4882a593Smuzhiyun 	[BPF_CGROUP_SOCK_OPS]		= "sock_ops",
39*4882a593Smuzhiyun 	[BPF_CGROUP_DEVICE]		= "device",
40*4882a593Smuzhiyun 	[BPF_CGROUP_INET4_BIND]		= "bind4",
41*4882a593Smuzhiyun 	[BPF_CGROUP_INET6_BIND]		= "bind6",
42*4882a593Smuzhiyun 	[BPF_CGROUP_INET4_CONNECT]	= "connect4",
43*4882a593Smuzhiyun 	[BPF_CGROUP_INET6_CONNECT]	= "connect6",
44*4882a593Smuzhiyun 	[BPF_CGROUP_INET4_POST_BIND]	= "post_bind4",
45*4882a593Smuzhiyun 	[BPF_CGROUP_INET6_POST_BIND]	= "post_bind6",
46*4882a593Smuzhiyun 	[BPF_CGROUP_INET4_GETPEERNAME]	= "getpeername4",
47*4882a593Smuzhiyun 	[BPF_CGROUP_INET6_GETPEERNAME]	= "getpeername6",
48*4882a593Smuzhiyun 	[BPF_CGROUP_INET4_GETSOCKNAME]	= "getsockname4",
49*4882a593Smuzhiyun 	[BPF_CGROUP_INET6_GETSOCKNAME]	= "getsockname6",
50*4882a593Smuzhiyun 	[BPF_CGROUP_UDP4_SENDMSG]	= "sendmsg4",
51*4882a593Smuzhiyun 	[BPF_CGROUP_UDP6_SENDMSG]	= "sendmsg6",
52*4882a593Smuzhiyun 	[BPF_CGROUP_SYSCTL]		= "sysctl",
53*4882a593Smuzhiyun 	[BPF_CGROUP_UDP4_RECVMSG]	= "recvmsg4",
54*4882a593Smuzhiyun 	[BPF_CGROUP_UDP6_RECVMSG]	= "recvmsg6",
55*4882a593Smuzhiyun 	[BPF_CGROUP_GETSOCKOPT]		= "getsockopt",
56*4882a593Smuzhiyun 	[BPF_CGROUP_SETSOCKOPT]		= "setsockopt",
57*4882a593Smuzhiyun 
58*4882a593Smuzhiyun 	[BPF_SK_SKB_STREAM_PARSER]	= "sk_skb_stream_parser",
59*4882a593Smuzhiyun 	[BPF_SK_SKB_STREAM_VERDICT]	= "sk_skb_stream_verdict",
60*4882a593Smuzhiyun 	[BPF_SK_MSG_VERDICT]		= "sk_msg_verdict",
61*4882a593Smuzhiyun 	[BPF_LIRC_MODE2]		= "lirc_mode2",
62*4882a593Smuzhiyun 	[BPF_FLOW_DISSECTOR]		= "flow_dissector",
63*4882a593Smuzhiyun 	[BPF_TRACE_RAW_TP]		= "raw_tp",
64*4882a593Smuzhiyun 	[BPF_TRACE_FENTRY]		= "fentry",
65*4882a593Smuzhiyun 	[BPF_TRACE_FEXIT]		= "fexit",
66*4882a593Smuzhiyun 	[BPF_MODIFY_RETURN]		= "mod_ret",
67*4882a593Smuzhiyun 	[BPF_LSM_MAC]			= "lsm_mac",
68*4882a593Smuzhiyun 	[BPF_SK_LOOKUP]			= "sk_lookup",
69*4882a593Smuzhiyun };
70*4882a593Smuzhiyun 
p_err(const char * fmt,...)71*4882a593Smuzhiyun void p_err(const char *fmt, ...)
72*4882a593Smuzhiyun {
73*4882a593Smuzhiyun 	va_list ap;
74*4882a593Smuzhiyun 
75*4882a593Smuzhiyun 	va_start(ap, fmt);
76*4882a593Smuzhiyun 	if (json_output) {
77*4882a593Smuzhiyun 		jsonw_start_object(json_wtr);
78*4882a593Smuzhiyun 		jsonw_name(json_wtr, "error");
79*4882a593Smuzhiyun 		jsonw_vprintf_enquote(json_wtr, fmt, ap);
80*4882a593Smuzhiyun 		jsonw_end_object(json_wtr);
81*4882a593Smuzhiyun 	} else {
82*4882a593Smuzhiyun 		fprintf(stderr, "Error: ");
83*4882a593Smuzhiyun 		vfprintf(stderr, fmt, ap);
84*4882a593Smuzhiyun 		fprintf(stderr, "\n");
85*4882a593Smuzhiyun 	}
86*4882a593Smuzhiyun 	va_end(ap);
87*4882a593Smuzhiyun }
88*4882a593Smuzhiyun 
p_info(const char * fmt,...)89*4882a593Smuzhiyun void p_info(const char *fmt, ...)
90*4882a593Smuzhiyun {
91*4882a593Smuzhiyun 	va_list ap;
92*4882a593Smuzhiyun 
93*4882a593Smuzhiyun 	if (json_output)
94*4882a593Smuzhiyun 		return;
95*4882a593Smuzhiyun 
96*4882a593Smuzhiyun 	va_start(ap, fmt);
97*4882a593Smuzhiyun 	vfprintf(stderr, fmt, ap);
98*4882a593Smuzhiyun 	fprintf(stderr, "\n");
99*4882a593Smuzhiyun 	va_end(ap);
100*4882a593Smuzhiyun }
101*4882a593Smuzhiyun 
is_bpffs(char * path)102*4882a593Smuzhiyun static bool is_bpffs(char *path)
103*4882a593Smuzhiyun {
104*4882a593Smuzhiyun 	struct statfs st_fs;
105*4882a593Smuzhiyun 
106*4882a593Smuzhiyun 	if (statfs(path, &st_fs) < 0)
107*4882a593Smuzhiyun 		return false;
108*4882a593Smuzhiyun 
109*4882a593Smuzhiyun 	return (unsigned long)st_fs.f_type == BPF_FS_MAGIC;
110*4882a593Smuzhiyun }
111*4882a593Smuzhiyun 
set_max_rlimit(void)112*4882a593Smuzhiyun void set_max_rlimit(void)
113*4882a593Smuzhiyun {
114*4882a593Smuzhiyun 	struct rlimit rinf = { RLIM_INFINITY, RLIM_INFINITY };
115*4882a593Smuzhiyun 
116*4882a593Smuzhiyun 	setrlimit(RLIMIT_MEMLOCK, &rinf);
117*4882a593Smuzhiyun }
118*4882a593Smuzhiyun 
119*4882a593Smuzhiyun static int
mnt_fs(const char * target,const char * type,char * buff,size_t bufflen)120*4882a593Smuzhiyun mnt_fs(const char *target, const char *type, char *buff, size_t bufflen)
121*4882a593Smuzhiyun {
122*4882a593Smuzhiyun 	bool bind_done = false;
123*4882a593Smuzhiyun 
124*4882a593Smuzhiyun 	while (mount("", target, "none", MS_PRIVATE | MS_REC, NULL)) {
125*4882a593Smuzhiyun 		if (errno != EINVAL || bind_done) {
126*4882a593Smuzhiyun 			snprintf(buff, bufflen,
127*4882a593Smuzhiyun 				 "mount --make-private %s failed: %s",
128*4882a593Smuzhiyun 				 target, strerror(errno));
129*4882a593Smuzhiyun 			return -1;
130*4882a593Smuzhiyun 		}
131*4882a593Smuzhiyun 
132*4882a593Smuzhiyun 		if (mount(target, target, "none", MS_BIND, NULL)) {
133*4882a593Smuzhiyun 			snprintf(buff, bufflen,
134*4882a593Smuzhiyun 				 "mount --bind %s %s failed: %s",
135*4882a593Smuzhiyun 				 target, target, strerror(errno));
136*4882a593Smuzhiyun 			return -1;
137*4882a593Smuzhiyun 		}
138*4882a593Smuzhiyun 
139*4882a593Smuzhiyun 		bind_done = true;
140*4882a593Smuzhiyun 	}
141*4882a593Smuzhiyun 
142*4882a593Smuzhiyun 	if (mount(type, target, type, 0, "mode=0700")) {
143*4882a593Smuzhiyun 		snprintf(buff, bufflen, "mount -t %s %s %s failed: %s",
144*4882a593Smuzhiyun 			 type, type, target, strerror(errno));
145*4882a593Smuzhiyun 		return -1;
146*4882a593Smuzhiyun 	}
147*4882a593Smuzhiyun 
148*4882a593Smuzhiyun 	return 0;
149*4882a593Smuzhiyun }
150*4882a593Smuzhiyun 
mount_tracefs(const char * target)151*4882a593Smuzhiyun int mount_tracefs(const char *target)
152*4882a593Smuzhiyun {
153*4882a593Smuzhiyun 	char err_str[ERR_MAX_LEN];
154*4882a593Smuzhiyun 	int err;
155*4882a593Smuzhiyun 
156*4882a593Smuzhiyun 	err = mnt_fs(target, "tracefs", err_str, ERR_MAX_LEN);
157*4882a593Smuzhiyun 	if (err) {
158*4882a593Smuzhiyun 		err_str[ERR_MAX_LEN - 1] = '\0';
159*4882a593Smuzhiyun 		p_err("can't mount tracefs: %s", err_str);
160*4882a593Smuzhiyun 	}
161*4882a593Smuzhiyun 
162*4882a593Smuzhiyun 	return err;
163*4882a593Smuzhiyun }
164*4882a593Smuzhiyun 
open_obj_pinned(const char * path,bool quiet)165*4882a593Smuzhiyun int open_obj_pinned(const char *path, bool quiet)
166*4882a593Smuzhiyun {
167*4882a593Smuzhiyun 	char *pname;
168*4882a593Smuzhiyun 	int fd = -1;
169*4882a593Smuzhiyun 
170*4882a593Smuzhiyun 	pname = strdup(path);
171*4882a593Smuzhiyun 	if (!pname) {
172*4882a593Smuzhiyun 		if (!quiet)
173*4882a593Smuzhiyun 			p_err("mem alloc failed");
174*4882a593Smuzhiyun 		goto out_ret;
175*4882a593Smuzhiyun 	}
176*4882a593Smuzhiyun 
177*4882a593Smuzhiyun 	fd = bpf_obj_get(pname);
178*4882a593Smuzhiyun 	if (fd < 0) {
179*4882a593Smuzhiyun 		if (!quiet)
180*4882a593Smuzhiyun 			p_err("bpf obj get (%s): %s", pname,
181*4882a593Smuzhiyun 			      errno == EACCES && !is_bpffs(dirname(pname)) ?
182*4882a593Smuzhiyun 			    "directory not in bpf file system (bpffs)" :
183*4882a593Smuzhiyun 			    strerror(errno));
184*4882a593Smuzhiyun 		goto out_free;
185*4882a593Smuzhiyun 	}
186*4882a593Smuzhiyun 
187*4882a593Smuzhiyun out_free:
188*4882a593Smuzhiyun 	free(pname);
189*4882a593Smuzhiyun out_ret:
190*4882a593Smuzhiyun 	return fd;
191*4882a593Smuzhiyun }
192*4882a593Smuzhiyun 
open_obj_pinned_any(const char * path,enum bpf_obj_type exp_type)193*4882a593Smuzhiyun int open_obj_pinned_any(const char *path, enum bpf_obj_type exp_type)
194*4882a593Smuzhiyun {
195*4882a593Smuzhiyun 	enum bpf_obj_type type;
196*4882a593Smuzhiyun 	int fd;
197*4882a593Smuzhiyun 
198*4882a593Smuzhiyun 	fd = open_obj_pinned(path, false);
199*4882a593Smuzhiyun 	if (fd < 0)
200*4882a593Smuzhiyun 		return -1;
201*4882a593Smuzhiyun 
202*4882a593Smuzhiyun 	type = get_fd_type(fd);
203*4882a593Smuzhiyun 	if (type < 0) {
204*4882a593Smuzhiyun 		close(fd);
205*4882a593Smuzhiyun 		return type;
206*4882a593Smuzhiyun 	}
207*4882a593Smuzhiyun 	if (type != exp_type) {
208*4882a593Smuzhiyun 		p_err("incorrect object type: %s", get_fd_type_name(type));
209*4882a593Smuzhiyun 		close(fd);
210*4882a593Smuzhiyun 		return -1;
211*4882a593Smuzhiyun 	}
212*4882a593Smuzhiyun 
213*4882a593Smuzhiyun 	return fd;
214*4882a593Smuzhiyun }
215*4882a593Smuzhiyun 
mount_bpffs_for_pin(const char * name)216*4882a593Smuzhiyun int mount_bpffs_for_pin(const char *name)
217*4882a593Smuzhiyun {
218*4882a593Smuzhiyun 	char err_str[ERR_MAX_LEN];
219*4882a593Smuzhiyun 	char *file;
220*4882a593Smuzhiyun 	char *dir;
221*4882a593Smuzhiyun 	int err = 0;
222*4882a593Smuzhiyun 
223*4882a593Smuzhiyun 	file = malloc(strlen(name) + 1);
224*4882a593Smuzhiyun 	if (!file) {
225*4882a593Smuzhiyun 		p_err("mem alloc failed");
226*4882a593Smuzhiyun 		return -1;
227*4882a593Smuzhiyun 	}
228*4882a593Smuzhiyun 
229*4882a593Smuzhiyun 	strcpy(file, name);
230*4882a593Smuzhiyun 	dir = dirname(file);
231*4882a593Smuzhiyun 
232*4882a593Smuzhiyun 	if (is_bpffs(dir))
233*4882a593Smuzhiyun 		/* nothing to do if already mounted */
234*4882a593Smuzhiyun 		goto out_free;
235*4882a593Smuzhiyun 
236*4882a593Smuzhiyun 	if (block_mount) {
237*4882a593Smuzhiyun 		p_err("no BPF file system found, not mounting it due to --nomount option");
238*4882a593Smuzhiyun 		err = -1;
239*4882a593Smuzhiyun 		goto out_free;
240*4882a593Smuzhiyun 	}
241*4882a593Smuzhiyun 
242*4882a593Smuzhiyun 	err = mnt_fs(dir, "bpf", err_str, ERR_MAX_LEN);
243*4882a593Smuzhiyun 	if (err) {
244*4882a593Smuzhiyun 		err_str[ERR_MAX_LEN - 1] = '\0';
245*4882a593Smuzhiyun 		p_err("can't mount BPF file system to pin the object (%s): %s",
246*4882a593Smuzhiyun 		      name, err_str);
247*4882a593Smuzhiyun 	}
248*4882a593Smuzhiyun 
249*4882a593Smuzhiyun out_free:
250*4882a593Smuzhiyun 	free(file);
251*4882a593Smuzhiyun 	return err;
252*4882a593Smuzhiyun }
253*4882a593Smuzhiyun 
do_pin_fd(int fd,const char * name)254*4882a593Smuzhiyun int do_pin_fd(int fd, const char *name)
255*4882a593Smuzhiyun {
256*4882a593Smuzhiyun 	int err;
257*4882a593Smuzhiyun 
258*4882a593Smuzhiyun 	err = mount_bpffs_for_pin(name);
259*4882a593Smuzhiyun 	if (err)
260*4882a593Smuzhiyun 		return err;
261*4882a593Smuzhiyun 
262*4882a593Smuzhiyun 	err = bpf_obj_pin(fd, name);
263*4882a593Smuzhiyun 	if (err)
264*4882a593Smuzhiyun 		p_err("can't pin the object (%s): %s", name, strerror(errno));
265*4882a593Smuzhiyun 
266*4882a593Smuzhiyun 	return err;
267*4882a593Smuzhiyun }
268*4882a593Smuzhiyun 
do_pin_any(int argc,char ** argv,int (* get_fd)(int *,char ***))269*4882a593Smuzhiyun int do_pin_any(int argc, char **argv, int (*get_fd)(int *, char ***))
270*4882a593Smuzhiyun {
271*4882a593Smuzhiyun 	int err;
272*4882a593Smuzhiyun 	int fd;
273*4882a593Smuzhiyun 
274*4882a593Smuzhiyun 	if (!REQ_ARGS(3))
275*4882a593Smuzhiyun 		return -EINVAL;
276*4882a593Smuzhiyun 
277*4882a593Smuzhiyun 	fd = get_fd(&argc, &argv);
278*4882a593Smuzhiyun 	if (fd < 0)
279*4882a593Smuzhiyun 		return fd;
280*4882a593Smuzhiyun 
281*4882a593Smuzhiyun 	err = do_pin_fd(fd, *argv);
282*4882a593Smuzhiyun 
283*4882a593Smuzhiyun 	close(fd);
284*4882a593Smuzhiyun 	return err;
285*4882a593Smuzhiyun }
286*4882a593Smuzhiyun 
get_fd_type_name(enum bpf_obj_type type)287*4882a593Smuzhiyun const char *get_fd_type_name(enum bpf_obj_type type)
288*4882a593Smuzhiyun {
289*4882a593Smuzhiyun 	static const char * const names[] = {
290*4882a593Smuzhiyun 		[BPF_OBJ_UNKNOWN]	= "unknown",
291*4882a593Smuzhiyun 		[BPF_OBJ_PROG]		= "prog",
292*4882a593Smuzhiyun 		[BPF_OBJ_MAP]		= "map",
293*4882a593Smuzhiyun 	};
294*4882a593Smuzhiyun 
295*4882a593Smuzhiyun 	if (type < 0 || type >= ARRAY_SIZE(names) || !names[type])
296*4882a593Smuzhiyun 		return names[BPF_OBJ_UNKNOWN];
297*4882a593Smuzhiyun 
298*4882a593Smuzhiyun 	return names[type];
299*4882a593Smuzhiyun }
300*4882a593Smuzhiyun 
get_fd_type(int fd)301*4882a593Smuzhiyun int get_fd_type(int fd)
302*4882a593Smuzhiyun {
303*4882a593Smuzhiyun 	char path[PATH_MAX];
304*4882a593Smuzhiyun 	char buf[512];
305*4882a593Smuzhiyun 	ssize_t n;
306*4882a593Smuzhiyun 
307*4882a593Smuzhiyun 	snprintf(path, sizeof(path), "/proc/self/fd/%d", fd);
308*4882a593Smuzhiyun 
309*4882a593Smuzhiyun 	n = readlink(path, buf, sizeof(buf));
310*4882a593Smuzhiyun 	if (n < 0) {
311*4882a593Smuzhiyun 		p_err("can't read link type: %s", strerror(errno));
312*4882a593Smuzhiyun 		return -1;
313*4882a593Smuzhiyun 	}
314*4882a593Smuzhiyun 	if (n == sizeof(path)) {
315*4882a593Smuzhiyun 		p_err("can't read link type: path too long!");
316*4882a593Smuzhiyun 		return -1;
317*4882a593Smuzhiyun 	}
318*4882a593Smuzhiyun 
319*4882a593Smuzhiyun 	if (strstr(buf, "bpf-map"))
320*4882a593Smuzhiyun 		return BPF_OBJ_MAP;
321*4882a593Smuzhiyun 	else if (strstr(buf, "bpf-prog"))
322*4882a593Smuzhiyun 		return BPF_OBJ_PROG;
323*4882a593Smuzhiyun 	else if (strstr(buf, "bpf-link"))
324*4882a593Smuzhiyun 		return BPF_OBJ_LINK;
325*4882a593Smuzhiyun 
326*4882a593Smuzhiyun 	return BPF_OBJ_UNKNOWN;
327*4882a593Smuzhiyun }
328*4882a593Smuzhiyun 
get_fdinfo(int fd,const char * key)329*4882a593Smuzhiyun char *get_fdinfo(int fd, const char *key)
330*4882a593Smuzhiyun {
331*4882a593Smuzhiyun 	char path[PATH_MAX];
332*4882a593Smuzhiyun 	char *line = NULL;
333*4882a593Smuzhiyun 	size_t line_n = 0;
334*4882a593Smuzhiyun 	ssize_t n;
335*4882a593Smuzhiyun 	FILE *fdi;
336*4882a593Smuzhiyun 
337*4882a593Smuzhiyun 	snprintf(path, sizeof(path), "/proc/self/fdinfo/%d", fd);
338*4882a593Smuzhiyun 
339*4882a593Smuzhiyun 	fdi = fopen(path, "r");
340*4882a593Smuzhiyun 	if (!fdi)
341*4882a593Smuzhiyun 		return NULL;
342*4882a593Smuzhiyun 
343*4882a593Smuzhiyun 	while ((n = getline(&line, &line_n, fdi)) > 0) {
344*4882a593Smuzhiyun 		char *value;
345*4882a593Smuzhiyun 		int len;
346*4882a593Smuzhiyun 
347*4882a593Smuzhiyun 		if (!strstr(line, key))
348*4882a593Smuzhiyun 			continue;
349*4882a593Smuzhiyun 
350*4882a593Smuzhiyun 		fclose(fdi);
351*4882a593Smuzhiyun 
352*4882a593Smuzhiyun 		value = strchr(line, '\t');
353*4882a593Smuzhiyun 		if (!value || !value[1]) {
354*4882a593Smuzhiyun 			free(line);
355*4882a593Smuzhiyun 			return NULL;
356*4882a593Smuzhiyun 		}
357*4882a593Smuzhiyun 		value++;
358*4882a593Smuzhiyun 
359*4882a593Smuzhiyun 		len = strlen(value);
360*4882a593Smuzhiyun 		memmove(line, value, len);
361*4882a593Smuzhiyun 		line[len - 1] = '\0';
362*4882a593Smuzhiyun 
363*4882a593Smuzhiyun 		return line;
364*4882a593Smuzhiyun 	}
365*4882a593Smuzhiyun 
366*4882a593Smuzhiyun 	free(line);
367*4882a593Smuzhiyun 	fclose(fdi);
368*4882a593Smuzhiyun 	return NULL;
369*4882a593Smuzhiyun }
370*4882a593Smuzhiyun 
print_data_json(uint8_t * data,size_t len)371*4882a593Smuzhiyun void print_data_json(uint8_t *data, size_t len)
372*4882a593Smuzhiyun {
373*4882a593Smuzhiyun 	unsigned int i;
374*4882a593Smuzhiyun 
375*4882a593Smuzhiyun 	jsonw_start_array(json_wtr);
376*4882a593Smuzhiyun 	for (i = 0; i < len; i++)
377*4882a593Smuzhiyun 		jsonw_printf(json_wtr, "%d", data[i]);
378*4882a593Smuzhiyun 	jsonw_end_array(json_wtr);
379*4882a593Smuzhiyun }
380*4882a593Smuzhiyun 
print_hex_data_json(uint8_t * data,size_t len)381*4882a593Smuzhiyun void print_hex_data_json(uint8_t *data, size_t len)
382*4882a593Smuzhiyun {
383*4882a593Smuzhiyun 	unsigned int i;
384*4882a593Smuzhiyun 
385*4882a593Smuzhiyun 	jsonw_start_array(json_wtr);
386*4882a593Smuzhiyun 	for (i = 0; i < len; i++)
387*4882a593Smuzhiyun 		jsonw_printf(json_wtr, "\"0x%02hhx\"", data[i]);
388*4882a593Smuzhiyun 	jsonw_end_array(json_wtr);
389*4882a593Smuzhiyun }
390*4882a593Smuzhiyun 
391*4882a593Smuzhiyun /* extra params for nftw cb */
392*4882a593Smuzhiyun static struct pinned_obj_table *build_fn_table;
393*4882a593Smuzhiyun static enum bpf_obj_type build_fn_type;
394*4882a593Smuzhiyun 
do_build_table_cb(const char * fpath,const struct stat * sb,int typeflag,struct FTW * ftwbuf)395*4882a593Smuzhiyun static int do_build_table_cb(const char *fpath, const struct stat *sb,
396*4882a593Smuzhiyun 			     int typeflag, struct FTW *ftwbuf)
397*4882a593Smuzhiyun {
398*4882a593Smuzhiyun 	struct bpf_prog_info pinned_info;
399*4882a593Smuzhiyun 	__u32 len = sizeof(pinned_info);
400*4882a593Smuzhiyun 	struct pinned_obj *obj_node;
401*4882a593Smuzhiyun 	enum bpf_obj_type objtype;
402*4882a593Smuzhiyun 	int fd, err = 0;
403*4882a593Smuzhiyun 
404*4882a593Smuzhiyun 	if (typeflag != FTW_F)
405*4882a593Smuzhiyun 		goto out_ret;
406*4882a593Smuzhiyun 
407*4882a593Smuzhiyun 	fd = open_obj_pinned(fpath, true);
408*4882a593Smuzhiyun 	if (fd < 0)
409*4882a593Smuzhiyun 		goto out_ret;
410*4882a593Smuzhiyun 
411*4882a593Smuzhiyun 	objtype = get_fd_type(fd);
412*4882a593Smuzhiyun 	if (objtype != build_fn_type)
413*4882a593Smuzhiyun 		goto out_close;
414*4882a593Smuzhiyun 
415*4882a593Smuzhiyun 	memset(&pinned_info, 0, sizeof(pinned_info));
416*4882a593Smuzhiyun 	if (bpf_obj_get_info_by_fd(fd, &pinned_info, &len))
417*4882a593Smuzhiyun 		goto out_close;
418*4882a593Smuzhiyun 
419*4882a593Smuzhiyun 	obj_node = calloc(1, sizeof(*obj_node));
420*4882a593Smuzhiyun 	if (!obj_node) {
421*4882a593Smuzhiyun 		err = -1;
422*4882a593Smuzhiyun 		goto out_close;
423*4882a593Smuzhiyun 	}
424*4882a593Smuzhiyun 
425*4882a593Smuzhiyun 	obj_node->id = pinned_info.id;
426*4882a593Smuzhiyun 	obj_node->path = strdup(fpath);
427*4882a593Smuzhiyun 	if (!obj_node->path) {
428*4882a593Smuzhiyun 		err = -1;
429*4882a593Smuzhiyun 		free(obj_node);
430*4882a593Smuzhiyun 		goto out_close;
431*4882a593Smuzhiyun 	}
432*4882a593Smuzhiyun 
433*4882a593Smuzhiyun 	hash_add(build_fn_table->table, &obj_node->hash, obj_node->id);
434*4882a593Smuzhiyun out_close:
435*4882a593Smuzhiyun 	close(fd);
436*4882a593Smuzhiyun out_ret:
437*4882a593Smuzhiyun 	return err;
438*4882a593Smuzhiyun }
439*4882a593Smuzhiyun 
build_pinned_obj_table(struct pinned_obj_table * tab,enum bpf_obj_type type)440*4882a593Smuzhiyun int build_pinned_obj_table(struct pinned_obj_table *tab,
441*4882a593Smuzhiyun 			   enum bpf_obj_type type)
442*4882a593Smuzhiyun {
443*4882a593Smuzhiyun 	struct mntent *mntent = NULL;
444*4882a593Smuzhiyun 	FILE *mntfile = NULL;
445*4882a593Smuzhiyun 	int flags = FTW_PHYS;
446*4882a593Smuzhiyun 	int nopenfd = 16;
447*4882a593Smuzhiyun 	int err = 0;
448*4882a593Smuzhiyun 
449*4882a593Smuzhiyun 	mntfile = setmntent("/proc/mounts", "r");
450*4882a593Smuzhiyun 	if (!mntfile)
451*4882a593Smuzhiyun 		return -1;
452*4882a593Smuzhiyun 
453*4882a593Smuzhiyun 	build_fn_table = tab;
454*4882a593Smuzhiyun 	build_fn_type = type;
455*4882a593Smuzhiyun 
456*4882a593Smuzhiyun 	while ((mntent = getmntent(mntfile))) {
457*4882a593Smuzhiyun 		char *path = mntent->mnt_dir;
458*4882a593Smuzhiyun 
459*4882a593Smuzhiyun 		if (strncmp(mntent->mnt_type, "bpf", 3) != 0)
460*4882a593Smuzhiyun 			continue;
461*4882a593Smuzhiyun 		err = nftw(path, do_build_table_cb, nopenfd, flags);
462*4882a593Smuzhiyun 		if (err)
463*4882a593Smuzhiyun 			break;
464*4882a593Smuzhiyun 	}
465*4882a593Smuzhiyun 	fclose(mntfile);
466*4882a593Smuzhiyun 	return err;
467*4882a593Smuzhiyun }
468*4882a593Smuzhiyun 
delete_pinned_obj_table(struct pinned_obj_table * tab)469*4882a593Smuzhiyun void delete_pinned_obj_table(struct pinned_obj_table *tab)
470*4882a593Smuzhiyun {
471*4882a593Smuzhiyun 	struct pinned_obj *obj;
472*4882a593Smuzhiyun 	struct hlist_node *tmp;
473*4882a593Smuzhiyun 	unsigned int bkt;
474*4882a593Smuzhiyun 
475*4882a593Smuzhiyun 	hash_for_each_safe(tab->table, bkt, tmp, obj, hash) {
476*4882a593Smuzhiyun 		hash_del(&obj->hash);
477*4882a593Smuzhiyun 		free(obj->path);
478*4882a593Smuzhiyun 		free(obj);
479*4882a593Smuzhiyun 	}
480*4882a593Smuzhiyun }
481*4882a593Smuzhiyun 
get_page_size(void)482*4882a593Smuzhiyun unsigned int get_page_size(void)
483*4882a593Smuzhiyun {
484*4882a593Smuzhiyun 	static int result;
485*4882a593Smuzhiyun 
486*4882a593Smuzhiyun 	if (!result)
487*4882a593Smuzhiyun 		result = getpagesize();
488*4882a593Smuzhiyun 	return result;
489*4882a593Smuzhiyun }
490*4882a593Smuzhiyun 
get_possible_cpus(void)491*4882a593Smuzhiyun unsigned int get_possible_cpus(void)
492*4882a593Smuzhiyun {
493*4882a593Smuzhiyun 	int cpus = libbpf_num_possible_cpus();
494*4882a593Smuzhiyun 
495*4882a593Smuzhiyun 	if (cpus < 0) {
496*4882a593Smuzhiyun 		p_err("Can't get # of possible cpus: %s", strerror(-cpus));
497*4882a593Smuzhiyun 		exit(-1);
498*4882a593Smuzhiyun 	}
499*4882a593Smuzhiyun 	return cpus;
500*4882a593Smuzhiyun }
501*4882a593Smuzhiyun 
502*4882a593Smuzhiyun static char *
ifindex_to_name_ns(__u32 ifindex,__u32 ns_dev,__u32 ns_ino,char * buf)503*4882a593Smuzhiyun ifindex_to_name_ns(__u32 ifindex, __u32 ns_dev, __u32 ns_ino, char *buf)
504*4882a593Smuzhiyun {
505*4882a593Smuzhiyun 	struct stat st;
506*4882a593Smuzhiyun 	int err;
507*4882a593Smuzhiyun 
508*4882a593Smuzhiyun 	err = stat("/proc/self/ns/net", &st);
509*4882a593Smuzhiyun 	if (err) {
510*4882a593Smuzhiyun 		p_err("Can't stat /proc/self: %s", strerror(errno));
511*4882a593Smuzhiyun 		return NULL;
512*4882a593Smuzhiyun 	}
513*4882a593Smuzhiyun 
514*4882a593Smuzhiyun 	if (st.st_dev != ns_dev || st.st_ino != ns_ino)
515*4882a593Smuzhiyun 		return NULL;
516*4882a593Smuzhiyun 
517*4882a593Smuzhiyun 	return if_indextoname(ifindex, buf);
518*4882a593Smuzhiyun }
519*4882a593Smuzhiyun 
read_sysfs_hex_int(char * path)520*4882a593Smuzhiyun static int read_sysfs_hex_int(char *path)
521*4882a593Smuzhiyun {
522*4882a593Smuzhiyun 	char vendor_id_buf[8];
523*4882a593Smuzhiyun 	int len;
524*4882a593Smuzhiyun 	int fd;
525*4882a593Smuzhiyun 
526*4882a593Smuzhiyun 	fd = open(path, O_RDONLY);
527*4882a593Smuzhiyun 	if (fd < 0) {
528*4882a593Smuzhiyun 		p_err("Can't open %s: %s", path, strerror(errno));
529*4882a593Smuzhiyun 		return -1;
530*4882a593Smuzhiyun 	}
531*4882a593Smuzhiyun 
532*4882a593Smuzhiyun 	len = read(fd, vendor_id_buf, sizeof(vendor_id_buf));
533*4882a593Smuzhiyun 	close(fd);
534*4882a593Smuzhiyun 	if (len < 0) {
535*4882a593Smuzhiyun 		p_err("Can't read %s: %s", path, strerror(errno));
536*4882a593Smuzhiyun 		return -1;
537*4882a593Smuzhiyun 	}
538*4882a593Smuzhiyun 	if (len >= (int)sizeof(vendor_id_buf)) {
539*4882a593Smuzhiyun 		p_err("Value in %s too long", path);
540*4882a593Smuzhiyun 		return -1;
541*4882a593Smuzhiyun 	}
542*4882a593Smuzhiyun 
543*4882a593Smuzhiyun 	vendor_id_buf[len] = 0;
544*4882a593Smuzhiyun 
545*4882a593Smuzhiyun 	return strtol(vendor_id_buf, NULL, 0);
546*4882a593Smuzhiyun }
547*4882a593Smuzhiyun 
read_sysfs_netdev_hex_int(char * devname,const char * entry_name)548*4882a593Smuzhiyun static int read_sysfs_netdev_hex_int(char *devname, const char *entry_name)
549*4882a593Smuzhiyun {
550*4882a593Smuzhiyun 	char full_path[64];
551*4882a593Smuzhiyun 
552*4882a593Smuzhiyun 	snprintf(full_path, sizeof(full_path), "/sys/class/net/%s/device/%s",
553*4882a593Smuzhiyun 		 devname, entry_name);
554*4882a593Smuzhiyun 
555*4882a593Smuzhiyun 	return read_sysfs_hex_int(full_path);
556*4882a593Smuzhiyun }
557*4882a593Smuzhiyun 
558*4882a593Smuzhiyun const char *
ifindex_to_bfd_params(__u32 ifindex,__u64 ns_dev,__u64 ns_ino,const char ** opt)559*4882a593Smuzhiyun ifindex_to_bfd_params(__u32 ifindex, __u64 ns_dev, __u64 ns_ino,
560*4882a593Smuzhiyun 		      const char **opt)
561*4882a593Smuzhiyun {
562*4882a593Smuzhiyun 	char devname[IF_NAMESIZE];
563*4882a593Smuzhiyun 	int vendor_id;
564*4882a593Smuzhiyun 	int device_id;
565*4882a593Smuzhiyun 
566*4882a593Smuzhiyun 	if (!ifindex_to_name_ns(ifindex, ns_dev, ns_ino, devname)) {
567*4882a593Smuzhiyun 		p_err("Can't get net device name for ifindex %d: %s", ifindex,
568*4882a593Smuzhiyun 		      strerror(errno));
569*4882a593Smuzhiyun 		return NULL;
570*4882a593Smuzhiyun 	}
571*4882a593Smuzhiyun 
572*4882a593Smuzhiyun 	vendor_id = read_sysfs_netdev_hex_int(devname, "vendor");
573*4882a593Smuzhiyun 	if (vendor_id < 0) {
574*4882a593Smuzhiyun 		p_err("Can't get device vendor id for %s", devname);
575*4882a593Smuzhiyun 		return NULL;
576*4882a593Smuzhiyun 	}
577*4882a593Smuzhiyun 
578*4882a593Smuzhiyun 	switch (vendor_id) {
579*4882a593Smuzhiyun 	case 0x19ee:
580*4882a593Smuzhiyun 		device_id = read_sysfs_netdev_hex_int(devname, "device");
581*4882a593Smuzhiyun 		if (device_id != 0x4000 &&
582*4882a593Smuzhiyun 		    device_id != 0x6000 &&
583*4882a593Smuzhiyun 		    device_id != 0x6003)
584*4882a593Smuzhiyun 			p_info("Unknown NFP device ID, assuming it is NFP-6xxx arch");
585*4882a593Smuzhiyun 		*opt = "ctx4";
586*4882a593Smuzhiyun 		return "NFP-6xxx";
587*4882a593Smuzhiyun 	default:
588*4882a593Smuzhiyun 		p_err("Can't get bfd arch name for device vendor id 0x%04x",
589*4882a593Smuzhiyun 		      vendor_id);
590*4882a593Smuzhiyun 		return NULL;
591*4882a593Smuzhiyun 	}
592*4882a593Smuzhiyun }
593*4882a593Smuzhiyun 
print_dev_plain(__u32 ifindex,__u64 ns_dev,__u64 ns_inode)594*4882a593Smuzhiyun void print_dev_plain(__u32 ifindex, __u64 ns_dev, __u64 ns_inode)
595*4882a593Smuzhiyun {
596*4882a593Smuzhiyun 	char name[IF_NAMESIZE];
597*4882a593Smuzhiyun 
598*4882a593Smuzhiyun 	if (!ifindex)
599*4882a593Smuzhiyun 		return;
600*4882a593Smuzhiyun 
601*4882a593Smuzhiyun 	printf("  offloaded_to ");
602*4882a593Smuzhiyun 	if (ifindex_to_name_ns(ifindex, ns_dev, ns_inode, name))
603*4882a593Smuzhiyun 		printf("%s", name);
604*4882a593Smuzhiyun 	else
605*4882a593Smuzhiyun 		printf("ifindex %u ns_dev %llu ns_ino %llu",
606*4882a593Smuzhiyun 		       ifindex, ns_dev, ns_inode);
607*4882a593Smuzhiyun }
608*4882a593Smuzhiyun 
print_dev_json(__u32 ifindex,__u64 ns_dev,__u64 ns_inode)609*4882a593Smuzhiyun void print_dev_json(__u32 ifindex, __u64 ns_dev, __u64 ns_inode)
610*4882a593Smuzhiyun {
611*4882a593Smuzhiyun 	char name[IF_NAMESIZE];
612*4882a593Smuzhiyun 
613*4882a593Smuzhiyun 	if (!ifindex)
614*4882a593Smuzhiyun 		return;
615*4882a593Smuzhiyun 
616*4882a593Smuzhiyun 	jsonw_name(json_wtr, "dev");
617*4882a593Smuzhiyun 	jsonw_start_object(json_wtr);
618*4882a593Smuzhiyun 	jsonw_uint_field(json_wtr, "ifindex", ifindex);
619*4882a593Smuzhiyun 	jsonw_uint_field(json_wtr, "ns_dev", ns_dev);
620*4882a593Smuzhiyun 	jsonw_uint_field(json_wtr, "ns_inode", ns_inode);
621*4882a593Smuzhiyun 	if (ifindex_to_name_ns(ifindex, ns_dev, ns_inode, name))
622*4882a593Smuzhiyun 		jsonw_string_field(json_wtr, "ifname", name);
623*4882a593Smuzhiyun 	jsonw_end_object(json_wtr);
624*4882a593Smuzhiyun }
625*4882a593Smuzhiyun 
parse_u32_arg(int * argc,char *** argv,__u32 * val,const char * what)626*4882a593Smuzhiyun int parse_u32_arg(int *argc, char ***argv, __u32 *val, const char *what)
627*4882a593Smuzhiyun {
628*4882a593Smuzhiyun 	char *endptr;
629*4882a593Smuzhiyun 
630*4882a593Smuzhiyun 	NEXT_ARGP();
631*4882a593Smuzhiyun 
632*4882a593Smuzhiyun 	if (*val) {
633*4882a593Smuzhiyun 		p_err("%s already specified", what);
634*4882a593Smuzhiyun 		return -1;
635*4882a593Smuzhiyun 	}
636*4882a593Smuzhiyun 
637*4882a593Smuzhiyun 	*val = strtoul(**argv, &endptr, 0);
638*4882a593Smuzhiyun 	if (*endptr) {
639*4882a593Smuzhiyun 		p_err("can't parse %s as %s", **argv, what);
640*4882a593Smuzhiyun 		return -1;
641*4882a593Smuzhiyun 	}
642*4882a593Smuzhiyun 	NEXT_ARGP();
643*4882a593Smuzhiyun 
644*4882a593Smuzhiyun 	return 0;
645*4882a593Smuzhiyun }
646*4882a593Smuzhiyun 
647*4882a593Smuzhiyun int __printf(2, 0)
print_all_levels(__maybe_unused enum libbpf_print_level level,const char * format,va_list args)648*4882a593Smuzhiyun print_all_levels(__maybe_unused enum libbpf_print_level level,
649*4882a593Smuzhiyun 		 const char *format, va_list args)
650*4882a593Smuzhiyun {
651*4882a593Smuzhiyun 	return vfprintf(stderr, format, args);
652*4882a593Smuzhiyun }
653*4882a593Smuzhiyun 
prog_fd_by_nametag(void * nametag,int ** fds,bool tag)654*4882a593Smuzhiyun static int prog_fd_by_nametag(void *nametag, int **fds, bool tag)
655*4882a593Smuzhiyun {
656*4882a593Smuzhiyun 	unsigned int id = 0;
657*4882a593Smuzhiyun 	int fd, nb_fds = 0;
658*4882a593Smuzhiyun 	void *tmp;
659*4882a593Smuzhiyun 	int err;
660*4882a593Smuzhiyun 
661*4882a593Smuzhiyun 	while (true) {
662*4882a593Smuzhiyun 		struct bpf_prog_info info = {};
663*4882a593Smuzhiyun 		__u32 len = sizeof(info);
664*4882a593Smuzhiyun 
665*4882a593Smuzhiyun 		err = bpf_prog_get_next_id(id, &id);
666*4882a593Smuzhiyun 		if (err) {
667*4882a593Smuzhiyun 			if (errno != ENOENT) {
668*4882a593Smuzhiyun 				p_err("%s", strerror(errno));
669*4882a593Smuzhiyun 				goto err_close_fds;
670*4882a593Smuzhiyun 			}
671*4882a593Smuzhiyun 			return nb_fds;
672*4882a593Smuzhiyun 		}
673*4882a593Smuzhiyun 
674*4882a593Smuzhiyun 		fd = bpf_prog_get_fd_by_id(id);
675*4882a593Smuzhiyun 		if (fd < 0) {
676*4882a593Smuzhiyun 			p_err("can't get prog by id (%u): %s",
677*4882a593Smuzhiyun 			      id, strerror(errno));
678*4882a593Smuzhiyun 			goto err_close_fds;
679*4882a593Smuzhiyun 		}
680*4882a593Smuzhiyun 
681*4882a593Smuzhiyun 		err = bpf_obj_get_info_by_fd(fd, &info, &len);
682*4882a593Smuzhiyun 		if (err) {
683*4882a593Smuzhiyun 			p_err("can't get prog info (%u): %s",
684*4882a593Smuzhiyun 			      id, strerror(errno));
685*4882a593Smuzhiyun 			goto err_close_fd;
686*4882a593Smuzhiyun 		}
687*4882a593Smuzhiyun 
688*4882a593Smuzhiyun 		if ((tag && memcmp(nametag, info.tag, BPF_TAG_SIZE)) ||
689*4882a593Smuzhiyun 		    (!tag && strncmp(nametag, info.name, BPF_OBJ_NAME_LEN))) {
690*4882a593Smuzhiyun 			close(fd);
691*4882a593Smuzhiyun 			continue;
692*4882a593Smuzhiyun 		}
693*4882a593Smuzhiyun 
694*4882a593Smuzhiyun 		if (nb_fds > 0) {
695*4882a593Smuzhiyun 			tmp = realloc(*fds, (nb_fds + 1) * sizeof(int));
696*4882a593Smuzhiyun 			if (!tmp) {
697*4882a593Smuzhiyun 				p_err("failed to realloc");
698*4882a593Smuzhiyun 				goto err_close_fd;
699*4882a593Smuzhiyun 			}
700*4882a593Smuzhiyun 			*fds = tmp;
701*4882a593Smuzhiyun 		}
702*4882a593Smuzhiyun 		(*fds)[nb_fds++] = fd;
703*4882a593Smuzhiyun 	}
704*4882a593Smuzhiyun 
705*4882a593Smuzhiyun err_close_fd:
706*4882a593Smuzhiyun 	close(fd);
707*4882a593Smuzhiyun err_close_fds:
708*4882a593Smuzhiyun 	while (--nb_fds >= 0)
709*4882a593Smuzhiyun 		close((*fds)[nb_fds]);
710*4882a593Smuzhiyun 	return -1;
711*4882a593Smuzhiyun }
712*4882a593Smuzhiyun 
prog_parse_fds(int * argc,char *** argv,int ** fds)713*4882a593Smuzhiyun int prog_parse_fds(int *argc, char ***argv, int **fds)
714*4882a593Smuzhiyun {
715*4882a593Smuzhiyun 	if (is_prefix(**argv, "id")) {
716*4882a593Smuzhiyun 		unsigned int id;
717*4882a593Smuzhiyun 		char *endptr;
718*4882a593Smuzhiyun 
719*4882a593Smuzhiyun 		NEXT_ARGP();
720*4882a593Smuzhiyun 
721*4882a593Smuzhiyun 		id = strtoul(**argv, &endptr, 0);
722*4882a593Smuzhiyun 		if (*endptr) {
723*4882a593Smuzhiyun 			p_err("can't parse %s as ID", **argv);
724*4882a593Smuzhiyun 			return -1;
725*4882a593Smuzhiyun 		}
726*4882a593Smuzhiyun 		NEXT_ARGP();
727*4882a593Smuzhiyun 
728*4882a593Smuzhiyun 		(*fds)[0] = bpf_prog_get_fd_by_id(id);
729*4882a593Smuzhiyun 		if ((*fds)[0] < 0) {
730*4882a593Smuzhiyun 			p_err("get by id (%u): %s", id, strerror(errno));
731*4882a593Smuzhiyun 			return -1;
732*4882a593Smuzhiyun 		}
733*4882a593Smuzhiyun 		return 1;
734*4882a593Smuzhiyun 	} else if (is_prefix(**argv, "tag")) {
735*4882a593Smuzhiyun 		unsigned char tag[BPF_TAG_SIZE];
736*4882a593Smuzhiyun 
737*4882a593Smuzhiyun 		NEXT_ARGP();
738*4882a593Smuzhiyun 
739*4882a593Smuzhiyun 		if (sscanf(**argv, BPF_TAG_FMT, tag, tag + 1, tag + 2,
740*4882a593Smuzhiyun 			   tag + 3, tag + 4, tag + 5, tag + 6, tag + 7)
741*4882a593Smuzhiyun 		    != BPF_TAG_SIZE) {
742*4882a593Smuzhiyun 			p_err("can't parse tag");
743*4882a593Smuzhiyun 			return -1;
744*4882a593Smuzhiyun 		}
745*4882a593Smuzhiyun 		NEXT_ARGP();
746*4882a593Smuzhiyun 
747*4882a593Smuzhiyun 		return prog_fd_by_nametag(tag, fds, true);
748*4882a593Smuzhiyun 	} else if (is_prefix(**argv, "name")) {
749*4882a593Smuzhiyun 		char *name;
750*4882a593Smuzhiyun 
751*4882a593Smuzhiyun 		NEXT_ARGP();
752*4882a593Smuzhiyun 
753*4882a593Smuzhiyun 		name = **argv;
754*4882a593Smuzhiyun 		if (strlen(name) > BPF_OBJ_NAME_LEN - 1) {
755*4882a593Smuzhiyun 			p_err("can't parse name");
756*4882a593Smuzhiyun 			return -1;
757*4882a593Smuzhiyun 		}
758*4882a593Smuzhiyun 		NEXT_ARGP();
759*4882a593Smuzhiyun 
760*4882a593Smuzhiyun 		return prog_fd_by_nametag(name, fds, false);
761*4882a593Smuzhiyun 	} else if (is_prefix(**argv, "pinned")) {
762*4882a593Smuzhiyun 		char *path;
763*4882a593Smuzhiyun 
764*4882a593Smuzhiyun 		NEXT_ARGP();
765*4882a593Smuzhiyun 
766*4882a593Smuzhiyun 		path = **argv;
767*4882a593Smuzhiyun 		NEXT_ARGP();
768*4882a593Smuzhiyun 
769*4882a593Smuzhiyun 		(*fds)[0] = open_obj_pinned_any(path, BPF_OBJ_PROG);
770*4882a593Smuzhiyun 		if ((*fds)[0] < 0)
771*4882a593Smuzhiyun 			return -1;
772*4882a593Smuzhiyun 		return 1;
773*4882a593Smuzhiyun 	}
774*4882a593Smuzhiyun 
775*4882a593Smuzhiyun 	p_err("expected 'id', 'tag', 'name' or 'pinned', got: '%s'?", **argv);
776*4882a593Smuzhiyun 	return -1;
777*4882a593Smuzhiyun }
778*4882a593Smuzhiyun 
prog_parse_fd(int * argc,char *** argv)779*4882a593Smuzhiyun int prog_parse_fd(int *argc, char ***argv)
780*4882a593Smuzhiyun {
781*4882a593Smuzhiyun 	int *fds = NULL;
782*4882a593Smuzhiyun 	int nb_fds, fd;
783*4882a593Smuzhiyun 
784*4882a593Smuzhiyun 	fds = malloc(sizeof(int));
785*4882a593Smuzhiyun 	if (!fds) {
786*4882a593Smuzhiyun 		p_err("mem alloc failed");
787*4882a593Smuzhiyun 		return -1;
788*4882a593Smuzhiyun 	}
789*4882a593Smuzhiyun 	nb_fds = prog_parse_fds(argc, argv, &fds);
790*4882a593Smuzhiyun 	if (nb_fds != 1) {
791*4882a593Smuzhiyun 		if (nb_fds > 1) {
792*4882a593Smuzhiyun 			p_err("several programs match this handle");
793*4882a593Smuzhiyun 			while (nb_fds--)
794*4882a593Smuzhiyun 				close(fds[nb_fds]);
795*4882a593Smuzhiyun 		}
796*4882a593Smuzhiyun 		fd = -1;
797*4882a593Smuzhiyun 		goto exit_free;
798*4882a593Smuzhiyun 	}
799*4882a593Smuzhiyun 
800*4882a593Smuzhiyun 	fd = fds[0];
801*4882a593Smuzhiyun exit_free:
802*4882a593Smuzhiyun 	free(fds);
803*4882a593Smuzhiyun 	return fd;
804*4882a593Smuzhiyun }
805*4882a593Smuzhiyun 
map_fd_by_name(char * name,int ** fds)806*4882a593Smuzhiyun static int map_fd_by_name(char *name, int **fds)
807*4882a593Smuzhiyun {
808*4882a593Smuzhiyun 	unsigned int id = 0;
809*4882a593Smuzhiyun 	int fd, nb_fds = 0;
810*4882a593Smuzhiyun 	void *tmp;
811*4882a593Smuzhiyun 	int err;
812*4882a593Smuzhiyun 
813*4882a593Smuzhiyun 	while (true) {
814*4882a593Smuzhiyun 		struct bpf_map_info info = {};
815*4882a593Smuzhiyun 		__u32 len = sizeof(info);
816*4882a593Smuzhiyun 
817*4882a593Smuzhiyun 		err = bpf_map_get_next_id(id, &id);
818*4882a593Smuzhiyun 		if (err) {
819*4882a593Smuzhiyun 			if (errno != ENOENT) {
820*4882a593Smuzhiyun 				p_err("%s", strerror(errno));
821*4882a593Smuzhiyun 				goto err_close_fds;
822*4882a593Smuzhiyun 			}
823*4882a593Smuzhiyun 			return nb_fds;
824*4882a593Smuzhiyun 		}
825*4882a593Smuzhiyun 
826*4882a593Smuzhiyun 		fd = bpf_map_get_fd_by_id(id);
827*4882a593Smuzhiyun 		if (fd < 0) {
828*4882a593Smuzhiyun 			p_err("can't get map by id (%u): %s",
829*4882a593Smuzhiyun 			      id, strerror(errno));
830*4882a593Smuzhiyun 			goto err_close_fds;
831*4882a593Smuzhiyun 		}
832*4882a593Smuzhiyun 
833*4882a593Smuzhiyun 		err = bpf_obj_get_info_by_fd(fd, &info, &len);
834*4882a593Smuzhiyun 		if (err) {
835*4882a593Smuzhiyun 			p_err("can't get map info (%u): %s",
836*4882a593Smuzhiyun 			      id, strerror(errno));
837*4882a593Smuzhiyun 			goto err_close_fd;
838*4882a593Smuzhiyun 		}
839*4882a593Smuzhiyun 
840*4882a593Smuzhiyun 		if (strncmp(name, info.name, BPF_OBJ_NAME_LEN)) {
841*4882a593Smuzhiyun 			close(fd);
842*4882a593Smuzhiyun 			continue;
843*4882a593Smuzhiyun 		}
844*4882a593Smuzhiyun 
845*4882a593Smuzhiyun 		if (nb_fds > 0) {
846*4882a593Smuzhiyun 			tmp = realloc(*fds, (nb_fds + 1) * sizeof(int));
847*4882a593Smuzhiyun 			if (!tmp) {
848*4882a593Smuzhiyun 				p_err("failed to realloc");
849*4882a593Smuzhiyun 				goto err_close_fd;
850*4882a593Smuzhiyun 			}
851*4882a593Smuzhiyun 			*fds = tmp;
852*4882a593Smuzhiyun 		}
853*4882a593Smuzhiyun 		(*fds)[nb_fds++] = fd;
854*4882a593Smuzhiyun 	}
855*4882a593Smuzhiyun 
856*4882a593Smuzhiyun err_close_fd:
857*4882a593Smuzhiyun 	close(fd);
858*4882a593Smuzhiyun err_close_fds:
859*4882a593Smuzhiyun 	while (--nb_fds >= 0)
860*4882a593Smuzhiyun 		close((*fds)[nb_fds]);
861*4882a593Smuzhiyun 	return -1;
862*4882a593Smuzhiyun }
863*4882a593Smuzhiyun 
map_parse_fds(int * argc,char *** argv,int ** fds)864*4882a593Smuzhiyun int map_parse_fds(int *argc, char ***argv, int **fds)
865*4882a593Smuzhiyun {
866*4882a593Smuzhiyun 	if (is_prefix(**argv, "id")) {
867*4882a593Smuzhiyun 		unsigned int id;
868*4882a593Smuzhiyun 		char *endptr;
869*4882a593Smuzhiyun 
870*4882a593Smuzhiyun 		NEXT_ARGP();
871*4882a593Smuzhiyun 
872*4882a593Smuzhiyun 		id = strtoul(**argv, &endptr, 0);
873*4882a593Smuzhiyun 		if (*endptr) {
874*4882a593Smuzhiyun 			p_err("can't parse %s as ID", **argv);
875*4882a593Smuzhiyun 			return -1;
876*4882a593Smuzhiyun 		}
877*4882a593Smuzhiyun 		NEXT_ARGP();
878*4882a593Smuzhiyun 
879*4882a593Smuzhiyun 		(*fds)[0] = bpf_map_get_fd_by_id(id);
880*4882a593Smuzhiyun 		if ((*fds)[0] < 0) {
881*4882a593Smuzhiyun 			p_err("get map by id (%u): %s", id, strerror(errno));
882*4882a593Smuzhiyun 			return -1;
883*4882a593Smuzhiyun 		}
884*4882a593Smuzhiyun 		return 1;
885*4882a593Smuzhiyun 	} else if (is_prefix(**argv, "name")) {
886*4882a593Smuzhiyun 		char *name;
887*4882a593Smuzhiyun 
888*4882a593Smuzhiyun 		NEXT_ARGP();
889*4882a593Smuzhiyun 
890*4882a593Smuzhiyun 		name = **argv;
891*4882a593Smuzhiyun 		if (strlen(name) > BPF_OBJ_NAME_LEN - 1) {
892*4882a593Smuzhiyun 			p_err("can't parse name");
893*4882a593Smuzhiyun 			return -1;
894*4882a593Smuzhiyun 		}
895*4882a593Smuzhiyun 		NEXT_ARGP();
896*4882a593Smuzhiyun 
897*4882a593Smuzhiyun 		return map_fd_by_name(name, fds);
898*4882a593Smuzhiyun 	} else if (is_prefix(**argv, "pinned")) {
899*4882a593Smuzhiyun 		char *path;
900*4882a593Smuzhiyun 
901*4882a593Smuzhiyun 		NEXT_ARGP();
902*4882a593Smuzhiyun 
903*4882a593Smuzhiyun 		path = **argv;
904*4882a593Smuzhiyun 		NEXT_ARGP();
905*4882a593Smuzhiyun 
906*4882a593Smuzhiyun 		(*fds)[0] = open_obj_pinned_any(path, BPF_OBJ_MAP);
907*4882a593Smuzhiyun 		if ((*fds)[0] < 0)
908*4882a593Smuzhiyun 			return -1;
909*4882a593Smuzhiyun 		return 1;
910*4882a593Smuzhiyun 	}
911*4882a593Smuzhiyun 
912*4882a593Smuzhiyun 	p_err("expected 'id', 'name' or 'pinned', got: '%s'?", **argv);
913*4882a593Smuzhiyun 	return -1;
914*4882a593Smuzhiyun }
915*4882a593Smuzhiyun 
map_parse_fd(int * argc,char *** argv)916*4882a593Smuzhiyun int map_parse_fd(int *argc, char ***argv)
917*4882a593Smuzhiyun {
918*4882a593Smuzhiyun 	int *fds = NULL;
919*4882a593Smuzhiyun 	int nb_fds, fd;
920*4882a593Smuzhiyun 
921*4882a593Smuzhiyun 	fds = malloc(sizeof(int));
922*4882a593Smuzhiyun 	if (!fds) {
923*4882a593Smuzhiyun 		p_err("mem alloc failed");
924*4882a593Smuzhiyun 		return -1;
925*4882a593Smuzhiyun 	}
926*4882a593Smuzhiyun 	nb_fds = map_parse_fds(argc, argv, &fds);
927*4882a593Smuzhiyun 	if (nb_fds != 1) {
928*4882a593Smuzhiyun 		if (nb_fds > 1) {
929*4882a593Smuzhiyun 			p_err("several maps match this handle");
930*4882a593Smuzhiyun 			while (nb_fds--)
931*4882a593Smuzhiyun 				close(fds[nb_fds]);
932*4882a593Smuzhiyun 		}
933*4882a593Smuzhiyun 		fd = -1;
934*4882a593Smuzhiyun 		goto exit_free;
935*4882a593Smuzhiyun 	}
936*4882a593Smuzhiyun 
937*4882a593Smuzhiyun 	fd = fds[0];
938*4882a593Smuzhiyun exit_free:
939*4882a593Smuzhiyun 	free(fds);
940*4882a593Smuzhiyun 	return fd;
941*4882a593Smuzhiyun }
942*4882a593Smuzhiyun 
map_parse_fd_and_info(int * argc,char *** argv,void * info,__u32 * info_len)943*4882a593Smuzhiyun int map_parse_fd_and_info(int *argc, char ***argv, void *info, __u32 *info_len)
944*4882a593Smuzhiyun {
945*4882a593Smuzhiyun 	int err;
946*4882a593Smuzhiyun 	int fd;
947*4882a593Smuzhiyun 
948*4882a593Smuzhiyun 	fd = map_parse_fd(argc, argv);
949*4882a593Smuzhiyun 	if (fd < 0)
950*4882a593Smuzhiyun 		return -1;
951*4882a593Smuzhiyun 
952*4882a593Smuzhiyun 	err = bpf_obj_get_info_by_fd(fd, info, info_len);
953*4882a593Smuzhiyun 	if (err) {
954*4882a593Smuzhiyun 		p_err("can't get map info: %s", strerror(errno));
955*4882a593Smuzhiyun 		close(fd);
956*4882a593Smuzhiyun 		return err;
957*4882a593Smuzhiyun 	}
958*4882a593Smuzhiyun 
959*4882a593Smuzhiyun 	return fd;
960*4882a593Smuzhiyun }
961