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