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