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