xref: /linux/tools/bpf/bpftool/common.c (revision 07fdad3a93756b872da7b53647715c48d0f4a2d0)
1 // SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
2 /* Copyright (C) 2017-2018 Netronome Systems, Inc. */
3 
4 #ifndef _GNU_SOURCE
5 #define _GNU_SOURCE
6 #endif
7 #include <assert.h>
8 #include <ctype.h>
9 #include <errno.h>
10 #include <fcntl.h>
11 #include <ftw.h>
12 #include <libgen.h>
13 #include <mntent.h>
14 #include <stdbool.h>
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <string.h>
18 #include <unistd.h>
19 #include <net/if.h>
20 #include <sys/mount.h>
21 #include <sys/resource.h>
22 #include <sys/stat.h>
23 #include <sys/vfs.h>
24 #include <sys/utsname.h>
25 
26 #include <linux/filter.h>
27 #include <linux/limits.h>
28 #include <linux/magic.h>
29 #include <linux/unistd.h>
30 
31 #include <bpf/bpf.h>
32 #include <bpf/hashmap.h>
33 #include <bpf/libbpf.h> /* libbpf_num_possible_cpus */
34 #include <bpf/btf.h>
35 #include <zlib.h>
36 
37 #include "main.h"
38 
39 #ifndef BPF_FS_MAGIC
40 #define BPF_FS_MAGIC		0xcafe4a11
41 #endif
42 
43 void p_err(const char *fmt, ...)
44 {
45 	va_list ap;
46 
47 	va_start(ap, fmt);
48 	if (json_output) {
49 		jsonw_start_object(json_wtr);
50 		jsonw_name(json_wtr, "error");
51 		jsonw_vprintf_enquote(json_wtr, fmt, ap);
52 		jsonw_end_object(json_wtr);
53 	} else {
54 		fprintf(stderr, "Error: ");
55 		vfprintf(stderr, fmt, ap);
56 		fprintf(stderr, "\n");
57 	}
58 	va_end(ap);
59 }
60 
61 void p_info(const char *fmt, ...)
62 {
63 	va_list ap;
64 
65 	if (json_output)
66 		return;
67 
68 	va_start(ap, fmt);
69 	vfprintf(stderr, fmt, ap);
70 	fprintf(stderr, "\n");
71 	va_end(ap);
72 }
73 
74 static bool is_bpffs(const char *path)
75 {
76 	struct statfs st_fs;
77 
78 	if (statfs(path, &st_fs) < 0)
79 		return false;
80 
81 	return (unsigned long)st_fs.f_type == BPF_FS_MAGIC;
82 }
83 
84 /* Probe whether kernel switched from memlock-based (RLIMIT_MEMLOCK) to
85  * memcg-based memory accounting for BPF maps and programs. This was done in
86  * commit 97306be45fbe ("Merge branch 'switch to memcg-based memory
87  * accounting'"), in Linux 5.11.
88  *
89  * Libbpf also offers to probe for memcg-based accounting vs rlimit, but does
90  * so by checking for the availability of a given BPF helper and this has
91  * failed on some kernels with backports in the past, see commit 6b4384ff1088
92  * ("Revert "bpftool: Use libbpf 1.0 API mode instead of RLIMIT_MEMLOCK"").
93  * Instead, we can probe by lowering the process-based rlimit to 0, trying to
94  * load a BPF object, and resetting the rlimit. If the load succeeds then
95  * memcg-based accounting is supported.
96  *
97  * This would be too dangerous to do in the library, because multithreaded
98  * applications might attempt to load items while the rlimit is at 0. Given
99  * that bpftool is single-threaded, this is fine to do here.
100  */
101 static bool known_to_need_rlimit(void)
102 {
103 	struct rlimit rlim_init, rlim_cur_zero = {};
104 	struct bpf_insn insns[] = {
105 		BPF_MOV64_IMM(BPF_REG_0, 0),
106 		BPF_EXIT_INSN(),
107 	};
108 	size_t insn_cnt = ARRAY_SIZE(insns);
109 	union bpf_attr attr;
110 	int prog_fd, err;
111 
112 	memset(&attr, 0, sizeof(attr));
113 	attr.prog_type = BPF_PROG_TYPE_SOCKET_FILTER;
114 	attr.insns = ptr_to_u64(insns);
115 	attr.insn_cnt = insn_cnt;
116 	attr.license = ptr_to_u64("GPL");
117 
118 	if (getrlimit(RLIMIT_MEMLOCK, &rlim_init))
119 		return false;
120 
121 	/* Drop the soft limit to zero. We maintain the hard limit to its
122 	 * current value, because lowering it would be a permanent operation
123 	 * for unprivileged users.
124 	 */
125 	rlim_cur_zero.rlim_max = rlim_init.rlim_max;
126 	if (setrlimit(RLIMIT_MEMLOCK, &rlim_cur_zero))
127 		return false;
128 
129 	/* Do not use bpf_prog_load() from libbpf here, because it calls
130 	 * bump_rlimit_memlock(), interfering with the current probe.
131 	 */
132 	prog_fd = syscall(__NR_bpf, BPF_PROG_LOAD, &attr, sizeof(attr));
133 	err = errno;
134 
135 	/* reset soft rlimit to its initial value */
136 	setrlimit(RLIMIT_MEMLOCK, &rlim_init);
137 
138 	if (prog_fd < 0)
139 		return err == EPERM;
140 
141 	close(prog_fd);
142 	return false;
143 }
144 
145 void set_max_rlimit(void)
146 {
147 	struct rlimit rinf = { RLIM_INFINITY, RLIM_INFINITY };
148 
149 	if (known_to_need_rlimit())
150 		setrlimit(RLIMIT_MEMLOCK, &rinf);
151 }
152 
153 static int
154 mnt_fs(const char *target, const char *type, char *buff, size_t bufflen)
155 {
156 	bool bind_done = false;
157 
158 	while (mount("", target, "none", MS_PRIVATE | MS_REC, NULL)) {
159 		if (errno != EINVAL || bind_done) {
160 			snprintf(buff, bufflen,
161 				 "mount --make-private %s failed: %s",
162 				 target, strerror(errno));
163 			return -1;
164 		}
165 
166 		if (mount(target, target, "none", MS_BIND, NULL)) {
167 			snprintf(buff, bufflen,
168 				 "mount --bind %s %s failed: %s",
169 				 target, target, strerror(errno));
170 			return -1;
171 		}
172 
173 		bind_done = true;
174 	}
175 
176 	if (mount(type, target, type, 0, "mode=0700")) {
177 		snprintf(buff, bufflen, "mount -t %s %s %s failed: %s",
178 			 type, type, target, strerror(errno));
179 		return -1;
180 	}
181 
182 	return 0;
183 }
184 
185 int mount_tracefs(const char *target)
186 {
187 	char err_str[ERR_MAX_LEN];
188 	int err;
189 
190 	err = mnt_fs(target, "tracefs", err_str, ERR_MAX_LEN);
191 	if (err) {
192 		err_str[ERR_MAX_LEN - 1] = '\0';
193 		p_err("can't mount tracefs: %s", err_str);
194 	}
195 
196 	return err;
197 }
198 
199 int open_obj_pinned(const char *path, bool quiet,
200 		    const struct bpf_obj_get_opts *opts)
201 {
202 	char *pname;
203 	int fd = -1;
204 
205 	pname = strdup(path);
206 	if (!pname) {
207 		if (!quiet)
208 			p_err("mem alloc failed");
209 		goto out_ret;
210 	}
211 
212 	fd = bpf_obj_get_opts(pname, opts);
213 	if (fd < 0) {
214 		if (!quiet)
215 			p_err("bpf obj get (%s): %s", pname,
216 			      errno == EACCES && !is_bpffs(dirname(pname)) ?
217 			    "directory not in bpf file system (bpffs)" :
218 			    strerror(errno));
219 		goto out_free;
220 	}
221 
222 out_free:
223 	free(pname);
224 out_ret:
225 	return fd;
226 }
227 
228 int open_obj_pinned_any(const char *path, enum bpf_obj_type exp_type,
229 			const struct bpf_obj_get_opts *opts)
230 {
231 	enum bpf_obj_type type;
232 	int fd;
233 
234 	fd = open_obj_pinned(path, false, opts);
235 	if (fd < 0)
236 		return -1;
237 
238 	type = get_fd_type(fd);
239 	if (type < 0) {
240 		close(fd);
241 		return type;
242 	}
243 	if (type != exp_type) {
244 		p_err("incorrect object type: %s", get_fd_type_name(type));
245 		close(fd);
246 		return -1;
247 	}
248 
249 	return fd;
250 }
251 
252 int create_and_mount_bpffs_dir(const char *dir_name)
253 {
254 	char err_str[ERR_MAX_LEN];
255 	bool dir_exists;
256 	int err = 0;
257 
258 	if (is_bpffs(dir_name))
259 		return err;
260 
261 	dir_exists = access(dir_name, F_OK) == 0;
262 
263 	if (!dir_exists) {
264 		char *temp_name;
265 		char *parent_name;
266 
267 		temp_name = strdup(dir_name);
268 		if (!temp_name) {
269 			p_err("mem alloc failed");
270 			return -1;
271 		}
272 
273 		parent_name = dirname(temp_name);
274 
275 		if (is_bpffs(parent_name)) {
276 			/* nothing to do if already mounted */
277 			free(temp_name);
278 			return err;
279 		}
280 
281 		if (access(parent_name, F_OK) == -1) {
282 			p_err("can't create dir '%s' to pin BPF object: parent dir '%s' doesn't exist",
283 			      dir_name, parent_name);
284 			free(temp_name);
285 			return -1;
286 		}
287 
288 		free(temp_name);
289 	}
290 
291 	if (block_mount) {
292 		p_err("no BPF file system found, not mounting it due to --nomount option");
293 		return -1;
294 	}
295 
296 	if (!dir_exists) {
297 		err = mkdir(dir_name, S_IRWXU);
298 		if (err) {
299 			p_err("failed to create dir '%s': %s", dir_name, strerror(errno));
300 			return err;
301 		}
302 	}
303 
304 	err = mnt_fs(dir_name, "bpf", err_str, ERR_MAX_LEN);
305 	if (err) {
306 		err_str[ERR_MAX_LEN - 1] = '\0';
307 		p_err("can't mount BPF file system on given dir '%s': %s",
308 		      dir_name, err_str);
309 
310 		if (!dir_exists)
311 			rmdir(dir_name);
312 	}
313 
314 	return err;
315 }
316 
317 int mount_bpffs_for_file(const char *file_name)
318 {
319 	char err_str[ERR_MAX_LEN];
320 	char *temp_name;
321 	char *dir;
322 	int err = 0;
323 
324 	if (access(file_name, F_OK) != -1) {
325 		p_err("can't pin BPF object: path '%s' already exists", file_name);
326 		return -1;
327 	}
328 
329 	temp_name = strdup(file_name);
330 	if (!temp_name) {
331 		p_err("mem alloc failed");
332 		return -1;
333 	}
334 
335 	dir = dirname(temp_name);
336 
337 	if (is_bpffs(dir))
338 		/* nothing to do if already mounted */
339 		goto out_free;
340 
341 	if (access(dir, F_OK) == -1) {
342 		p_err("can't pin BPF object: dir '%s' doesn't exist", dir);
343 		err = -1;
344 		goto out_free;
345 	}
346 
347 	if (block_mount) {
348 		p_err("no BPF file system found, not mounting it due to --nomount option");
349 		err = -1;
350 		goto out_free;
351 	}
352 
353 	err = mnt_fs(dir, "bpf", err_str, ERR_MAX_LEN);
354 	if (err) {
355 		err_str[ERR_MAX_LEN - 1] = '\0';
356 		p_err("can't mount BPF file system to pin the object '%s': %s",
357 		      file_name, err_str);
358 	}
359 
360 out_free:
361 	free(temp_name);
362 	return err;
363 }
364 
365 int do_pin_fd(int fd, const char *name)
366 {
367 	int err;
368 
369 	err = mount_bpffs_for_file(name);
370 	if (err)
371 		return err;
372 
373 	err = bpf_obj_pin(fd, name);
374 	if (err)
375 		p_err("can't pin the object (%s): %s", name, strerror(errno));
376 
377 	return err;
378 }
379 
380 int do_pin_any(int argc, char **argv, int (*get_fd)(int *, char ***))
381 {
382 	int err;
383 	int fd;
384 
385 	if (!REQ_ARGS(3))
386 		return -EINVAL;
387 
388 	fd = get_fd(&argc, &argv);
389 	if (fd < 0)
390 		return fd;
391 
392 	err = do_pin_fd(fd, *argv);
393 
394 	close(fd);
395 	return err;
396 }
397 
398 const char *get_fd_type_name(enum bpf_obj_type type)
399 {
400 	static const char * const names[] = {
401 		[BPF_OBJ_UNKNOWN]	= "unknown",
402 		[BPF_OBJ_PROG]		= "prog",
403 		[BPF_OBJ_MAP]		= "map",
404 		[BPF_OBJ_LINK]		= "link",
405 	};
406 
407 	if (type < 0 || type >= ARRAY_SIZE(names) || !names[type])
408 		return names[BPF_OBJ_UNKNOWN];
409 
410 	return names[type];
411 }
412 
413 void get_prog_full_name(const struct bpf_prog_info *prog_info, int prog_fd,
414 			char *name_buff, size_t buff_len)
415 {
416 	const char *prog_name = prog_info->name;
417 	const struct btf_type *func_type;
418 	struct bpf_func_info finfo = {};
419 	struct bpf_prog_info info = {};
420 	__u32 info_len = sizeof(info);
421 	struct btf *prog_btf = NULL;
422 
423 	if (buff_len <= BPF_OBJ_NAME_LEN ||
424 	    strlen(prog_info->name) < BPF_OBJ_NAME_LEN - 1)
425 		goto copy_name;
426 
427 	if (!prog_info->btf_id || prog_info->nr_func_info == 0)
428 		goto copy_name;
429 
430 	info.nr_func_info = 1;
431 	info.func_info_rec_size = prog_info->func_info_rec_size;
432 	if (info.func_info_rec_size > sizeof(finfo))
433 		info.func_info_rec_size = sizeof(finfo);
434 	info.func_info = ptr_to_u64(&finfo);
435 
436 	if (bpf_prog_get_info_by_fd(prog_fd, &info, &info_len))
437 		goto copy_name;
438 
439 	prog_btf = btf__load_from_kernel_by_id(info.btf_id);
440 	if (!prog_btf)
441 		goto copy_name;
442 
443 	func_type = btf__type_by_id(prog_btf, finfo.type_id);
444 	if (!func_type || !btf_is_func(func_type))
445 		goto copy_name;
446 
447 	prog_name = btf__name_by_offset(prog_btf, func_type->name_off);
448 
449 copy_name:
450 	snprintf(name_buff, buff_len, "%s", prog_name);
451 
452 	if (prog_btf)
453 		btf__free(prog_btf);
454 }
455 
456 int get_fd_type(int fd)
457 {
458 	char path[PATH_MAX];
459 	char buf[512];
460 	ssize_t n;
461 
462 	snprintf(path, sizeof(path), "/proc/self/fd/%d", fd);
463 
464 	n = readlink(path, buf, sizeof(buf));
465 	if (n < 0) {
466 		p_err("can't read link type: %s", strerror(errno));
467 		return -1;
468 	}
469 	if (n == sizeof(buf)) {
470 		p_err("can't read link type: path too long!");
471 		return -1;
472 	}
473 	buf[n] = '\0';
474 
475 	if (strstr(buf, "bpf-map"))
476 		return BPF_OBJ_MAP;
477 	else if (strstr(buf, "bpf-prog"))
478 		return BPF_OBJ_PROG;
479 	else if (strstr(buf, "bpf-link"))
480 		return BPF_OBJ_LINK;
481 
482 	return BPF_OBJ_UNKNOWN;
483 }
484 
485 char *get_fdinfo(int fd, const char *key)
486 {
487 	char path[PATH_MAX];
488 	char *line = NULL;
489 	size_t line_n = 0;
490 	ssize_t n;
491 	FILE *fdi;
492 
493 	snprintf(path, sizeof(path), "/proc/self/fdinfo/%d", fd);
494 
495 	fdi = fopen(path, "r");
496 	if (!fdi)
497 		return NULL;
498 
499 	while ((n = getline(&line, &line_n, fdi)) > 0) {
500 		char *value;
501 		int len;
502 
503 		if (!strstr(line, key))
504 			continue;
505 
506 		fclose(fdi);
507 
508 		value = strchr(line, '\t');
509 		if (!value || !value[1]) {
510 			free(line);
511 			return NULL;
512 		}
513 		value++;
514 
515 		len = strlen(value);
516 		memmove(line, value, len);
517 		line[len - 1] = '\0';
518 
519 		return line;
520 	}
521 
522 	free(line);
523 	fclose(fdi);
524 	return NULL;
525 }
526 
527 void print_data_json(uint8_t *data, size_t len)
528 {
529 	unsigned int i;
530 
531 	jsonw_start_array(json_wtr);
532 	for (i = 0; i < len; i++)
533 		jsonw_printf(json_wtr, "%d", data[i]);
534 	jsonw_end_array(json_wtr);
535 }
536 
537 void print_hex_data_json(uint8_t *data, size_t len)
538 {
539 	unsigned int i;
540 
541 	jsonw_start_array(json_wtr);
542 	for (i = 0; i < len; i++)
543 		jsonw_printf(json_wtr, "\"0x%02hhx\"", data[i]);
544 	jsonw_end_array(json_wtr);
545 }
546 
547 /* extra params for nftw cb */
548 static struct hashmap *build_fn_table;
549 static enum bpf_obj_type build_fn_type;
550 
551 static int do_build_table_cb(const char *fpath, const struct stat *sb,
552 			     int typeflag, struct FTW *ftwbuf)
553 {
554 	struct bpf_prog_info pinned_info;
555 	__u32 len = sizeof(pinned_info);
556 	enum bpf_obj_type objtype;
557 	int fd, err = 0;
558 	char *path;
559 
560 	if (typeflag != FTW_F)
561 		goto out_ret;
562 
563 	fd = open_obj_pinned(fpath, true, NULL);
564 	if (fd < 0)
565 		goto out_ret;
566 
567 	objtype = get_fd_type(fd);
568 	if (objtype != build_fn_type)
569 		goto out_close;
570 
571 	memset(&pinned_info, 0, sizeof(pinned_info));
572 	if (bpf_prog_get_info_by_fd(fd, &pinned_info, &len))
573 		goto out_close;
574 
575 	path = strdup(fpath);
576 	if (!path) {
577 		err = -1;
578 		goto out_close;
579 	}
580 
581 	err = hashmap__append(build_fn_table, pinned_info.id, path);
582 	if (err) {
583 		p_err("failed to append entry to hashmap for ID %u, path '%s': %s",
584 		      pinned_info.id, path, strerror(errno));
585 		free(path);
586 		goto out_close;
587 	}
588 
589 out_close:
590 	close(fd);
591 out_ret:
592 	return err;
593 }
594 
595 int build_pinned_obj_table(struct hashmap *tab,
596 			   enum bpf_obj_type type)
597 {
598 	struct mntent *mntent = NULL;
599 	FILE *mntfile = NULL;
600 	int flags = FTW_PHYS;
601 	int nopenfd = 16;
602 	int err = 0;
603 
604 	mntfile = setmntent("/proc/mounts", "r");
605 	if (!mntfile)
606 		return -1;
607 
608 	build_fn_table = tab;
609 	build_fn_type = type;
610 
611 	while ((mntent = getmntent(mntfile))) {
612 		char *path = mntent->mnt_dir;
613 
614 		if (strncmp(mntent->mnt_type, "bpf", 3) != 0)
615 			continue;
616 		err = nftw(path, do_build_table_cb, nopenfd, flags);
617 		if (err)
618 			break;
619 	}
620 	fclose(mntfile);
621 	return err;
622 }
623 
624 void delete_pinned_obj_table(struct hashmap *map)
625 {
626 	struct hashmap_entry *entry;
627 	size_t bkt;
628 
629 	if (!map)
630 		return;
631 
632 	hashmap__for_each_entry(map, entry, bkt)
633 		free(entry->pvalue);
634 
635 	hashmap__free(map);
636 }
637 
638 unsigned int get_page_size(void)
639 {
640 	static int result;
641 
642 	if (!result)
643 		result = getpagesize();
644 	return result;
645 }
646 
647 unsigned int get_possible_cpus(void)
648 {
649 	int cpus = libbpf_num_possible_cpus();
650 
651 	if (cpus < 0) {
652 		p_err("Can't get # of possible cpus: %s", strerror(-cpus));
653 		exit(-1);
654 	}
655 	return cpus;
656 }
657 
658 static char *
659 ifindex_to_name_ns(__u32 ifindex, __u32 ns_dev, __u32 ns_ino, char *buf)
660 {
661 	struct stat st;
662 	int err;
663 
664 	err = stat("/proc/self/ns/net", &st);
665 	if (err) {
666 		p_err("Can't stat /proc/self: %s", strerror(errno));
667 		return NULL;
668 	}
669 
670 	if (st.st_dev != ns_dev || st.st_ino != ns_ino)
671 		return NULL;
672 
673 	return if_indextoname(ifindex, buf);
674 }
675 
676 static int read_sysfs_hex_int(char *path)
677 {
678 	char vendor_id_buf[8];
679 	int len;
680 	int fd;
681 
682 	fd = open(path, O_RDONLY);
683 	if (fd < 0) {
684 		p_err("Can't open %s: %s", path, strerror(errno));
685 		return -1;
686 	}
687 
688 	len = read(fd, vendor_id_buf, sizeof(vendor_id_buf));
689 	close(fd);
690 	if (len < 0) {
691 		p_err("Can't read %s: %s", path, strerror(errno));
692 		return -1;
693 	}
694 	if (len >= (int)sizeof(vendor_id_buf)) {
695 		p_err("Value in %s too long", path);
696 		return -1;
697 	}
698 
699 	vendor_id_buf[len] = 0;
700 
701 	return strtol(vendor_id_buf, NULL, 0);
702 }
703 
704 static int read_sysfs_netdev_hex_int(char *devname, const char *entry_name)
705 {
706 	char full_path[64];
707 
708 	snprintf(full_path, sizeof(full_path), "/sys/class/net/%s/device/%s",
709 		 devname, entry_name);
710 
711 	return read_sysfs_hex_int(full_path);
712 }
713 
714 const char *
715 ifindex_to_arch(__u32 ifindex, __u64 ns_dev, __u64 ns_ino, const char **opt)
716 {
717 	__maybe_unused int device_id;
718 	char devname[IF_NAMESIZE];
719 	int vendor_id;
720 
721 	if (!ifindex_to_name_ns(ifindex, ns_dev, ns_ino, devname)) {
722 		p_err("Can't get net device name for ifindex %u: %s", ifindex,
723 		      strerror(errno));
724 		return NULL;
725 	}
726 
727 	vendor_id = read_sysfs_netdev_hex_int(devname, "vendor");
728 	if (vendor_id < 0) {
729 		p_err("Can't get device vendor id for %s", devname);
730 		return NULL;
731 	}
732 
733 	switch (vendor_id) {
734 #ifdef HAVE_LIBBFD_SUPPORT
735 	case 0x19ee:
736 		device_id = read_sysfs_netdev_hex_int(devname, "device");
737 		if (device_id != 0x4000 &&
738 		    device_id != 0x6000 &&
739 		    device_id != 0x6003)
740 			p_info("Unknown NFP device ID, assuming it is NFP-6xxx arch");
741 		*opt = "ctx4";
742 		return "NFP-6xxx";
743 #endif /* HAVE_LIBBFD_SUPPORT */
744 	/* No NFP support in LLVM, we have no valid triple to return. */
745 	default:
746 		p_err("Can't get arch name for device vendor id 0x%04x",
747 		      (unsigned int)vendor_id);
748 		return NULL;
749 	}
750 }
751 
752 void print_dev_plain(__u32 ifindex, __u64 ns_dev, __u64 ns_inode)
753 {
754 	char name[IF_NAMESIZE];
755 
756 	if (!ifindex)
757 		return;
758 
759 	printf("  offloaded_to ");
760 	if (ifindex_to_name_ns(ifindex, ns_dev, ns_inode, name))
761 		printf("%s", name);
762 	else
763 		printf("ifindex %u ns_dev %llu ns_ino %llu",
764 		       ifindex, ns_dev, ns_inode);
765 }
766 
767 void print_dev_json(__u32 ifindex, __u64 ns_dev, __u64 ns_inode)
768 {
769 	char name[IF_NAMESIZE];
770 
771 	if (!ifindex)
772 		return;
773 
774 	jsonw_name(json_wtr, "dev");
775 	jsonw_start_object(json_wtr);
776 	jsonw_uint_field(json_wtr, "ifindex", ifindex);
777 	jsonw_uint_field(json_wtr, "ns_dev", ns_dev);
778 	jsonw_uint_field(json_wtr, "ns_inode", ns_inode);
779 	if (ifindex_to_name_ns(ifindex, ns_dev, ns_inode, name))
780 		jsonw_string_field(json_wtr, "ifname", name);
781 	jsonw_end_object(json_wtr);
782 }
783 
784 int parse_u32_arg(int *argc, char ***argv, __u32 *val, const char *what)
785 {
786 	char *endptr;
787 
788 	NEXT_ARGP();
789 
790 	if (*val) {
791 		p_err("%s already specified", what);
792 		return -1;
793 	}
794 
795 	*val = strtoul(**argv, &endptr, 0);
796 	if (*endptr) {
797 		p_err("can't parse %s as %s", **argv, what);
798 		return -1;
799 	}
800 	NEXT_ARGP();
801 
802 	return 0;
803 }
804 
805 int __printf(2, 0)
806 print_all_levels(__maybe_unused enum libbpf_print_level level,
807 		 const char *format, va_list args)
808 {
809 	return vfprintf(stderr, format, args);
810 }
811 
812 static int prog_fd_by_nametag(void *nametag, int **fds, bool tag)
813 {
814 	char prog_name[MAX_PROG_FULL_NAME];
815 	unsigned int id = 0;
816 	int fd, nb_fds = 0;
817 	void *tmp;
818 	int err;
819 
820 	while (true) {
821 		struct bpf_prog_info info = {};
822 		__u32 len = sizeof(info);
823 
824 		err = bpf_prog_get_next_id(id, &id);
825 		if (err) {
826 			if (errno != ENOENT) {
827 				p_err("%s", strerror(errno));
828 				goto err_close_fds;
829 			}
830 			return nb_fds;
831 		}
832 
833 		fd = bpf_prog_get_fd_by_id(id);
834 		if (fd < 0) {
835 			p_err("can't get prog by id (%u): %s",
836 			      id, strerror(errno));
837 			goto err_close_fds;
838 		}
839 
840 		err = bpf_prog_get_info_by_fd(fd, &info, &len);
841 		if (err) {
842 			p_err("can't get prog info (%u): %s",
843 			      id, strerror(errno));
844 			goto err_close_fd;
845 		}
846 
847 		if (tag && memcmp(nametag, info.tag, BPF_TAG_SIZE)) {
848 			close(fd);
849 			continue;
850 		}
851 
852 		if (!tag) {
853 			get_prog_full_name(&info, fd, prog_name,
854 					   sizeof(prog_name));
855 			if (strncmp(nametag, prog_name, sizeof(prog_name))) {
856 				close(fd);
857 				continue;
858 			}
859 		}
860 
861 		if (nb_fds > 0) {
862 			tmp = realloc(*fds, (nb_fds + 1) * sizeof(int));
863 			if (!tmp) {
864 				p_err("failed to realloc");
865 				goto err_close_fd;
866 			}
867 			*fds = tmp;
868 		}
869 		(*fds)[nb_fds++] = fd;
870 	}
871 
872 err_close_fd:
873 	close(fd);
874 err_close_fds:
875 	while (--nb_fds >= 0)
876 		close((*fds)[nb_fds]);
877 	return -1;
878 }
879 
880 int prog_parse_fds(int *argc, char ***argv, int **fds)
881 {
882 	if (is_prefix(**argv, "id")) {
883 		unsigned int id;
884 		char *endptr;
885 
886 		NEXT_ARGP();
887 
888 		id = strtoul(**argv, &endptr, 0);
889 		if (*endptr) {
890 			p_err("can't parse %s as ID", **argv);
891 			return -1;
892 		}
893 		NEXT_ARGP();
894 
895 		(*fds)[0] = bpf_prog_get_fd_by_id(id);
896 		if ((*fds)[0] < 0) {
897 			p_err("get by id (%u): %s", id, strerror(errno));
898 			return -1;
899 		}
900 		return 1;
901 	} else if (is_prefix(**argv, "tag")) {
902 		unsigned char tag[BPF_TAG_SIZE];
903 
904 		NEXT_ARGP();
905 
906 		if (sscanf(**argv, BPF_TAG_FMT, tag, tag + 1, tag + 2,
907 			   tag + 3, tag + 4, tag + 5, tag + 6, tag + 7)
908 		    != BPF_TAG_SIZE) {
909 			p_err("can't parse tag");
910 			return -1;
911 		}
912 		NEXT_ARGP();
913 
914 		return prog_fd_by_nametag(tag, fds, true);
915 	} else if (is_prefix(**argv, "name")) {
916 		char *name;
917 
918 		NEXT_ARGP();
919 
920 		name = **argv;
921 		if (strlen(name) > MAX_PROG_FULL_NAME - 1) {
922 			p_err("can't parse name");
923 			return -1;
924 		}
925 		NEXT_ARGP();
926 
927 		return prog_fd_by_nametag(name, fds, false);
928 	} else if (is_prefix(**argv, "pinned")) {
929 		char *path;
930 
931 		NEXT_ARGP();
932 
933 		path = **argv;
934 		NEXT_ARGP();
935 
936 		(*fds)[0] = open_obj_pinned_any(path, BPF_OBJ_PROG, NULL);
937 		if ((*fds)[0] < 0)
938 			return -1;
939 		return 1;
940 	}
941 
942 	p_err("expected 'id', 'tag', 'name' or 'pinned', got: '%s'?", **argv);
943 	return -1;
944 }
945 
946 int prog_parse_fd(int *argc, char ***argv)
947 {
948 	int *fds = NULL;
949 	int nb_fds, fd;
950 
951 	fds = malloc(sizeof(int));
952 	if (!fds) {
953 		p_err("mem alloc failed");
954 		return -1;
955 	}
956 	nb_fds = prog_parse_fds(argc, argv, &fds);
957 	if (nb_fds != 1) {
958 		if (nb_fds > 1) {
959 			p_err("several programs match this handle");
960 			while (nb_fds--)
961 				close(fds[nb_fds]);
962 		}
963 		fd = -1;
964 		goto exit_free;
965 	}
966 
967 	fd = fds[0];
968 exit_free:
969 	free(fds);
970 	return fd;
971 }
972 
973 static int map_fd_by_name(char *name, int **fds,
974 			  const struct bpf_get_fd_by_id_opts *opts)
975 {
976 	unsigned int id = 0;
977 	int fd, nb_fds = 0;
978 	void *tmp;
979 	int err;
980 
981 	while (true) {
982 		LIBBPF_OPTS(bpf_get_fd_by_id_opts, opts_ro);
983 		struct bpf_map_info info = {};
984 		__u32 len = sizeof(info);
985 
986 		err = bpf_map_get_next_id(id, &id);
987 		if (err) {
988 			if (errno != ENOENT) {
989 				p_err("%s", strerror(errno));
990 				goto err_close_fds;
991 			}
992 			return nb_fds;
993 		}
994 
995 		/* Request a read-only fd to query the map info */
996 		opts_ro.open_flags = BPF_F_RDONLY;
997 		fd = bpf_map_get_fd_by_id_opts(id, &opts_ro);
998 		if (fd < 0) {
999 			p_err("can't get map by id (%u): %s",
1000 			      id, strerror(errno));
1001 			goto err_close_fds;
1002 		}
1003 
1004 		err = bpf_map_get_info_by_fd(fd, &info, &len);
1005 		if (err) {
1006 			p_err("can't get map info (%u): %s",
1007 			      id, strerror(errno));
1008 			goto err_close_fd;
1009 		}
1010 
1011 		if (strncmp(name, info.name, BPF_OBJ_NAME_LEN)) {
1012 			close(fd);
1013 			continue;
1014 		}
1015 
1016 		/* Get an fd with the requested options, if they differ
1017 		 * from the read-only options used to get the fd above.
1018 		 */
1019 		if (memcmp(opts, &opts_ro, sizeof(opts_ro))) {
1020 			close(fd);
1021 			fd = bpf_map_get_fd_by_id_opts(id, opts);
1022 			if (fd < 0) {
1023 				p_err("can't get map by id (%u): %s", id,
1024 					strerror(errno));
1025 				goto err_close_fds;
1026 			}
1027 		}
1028 
1029 		if (nb_fds > 0) {
1030 			tmp = realloc(*fds, (nb_fds + 1) * sizeof(int));
1031 			if (!tmp) {
1032 				p_err("failed to realloc");
1033 				goto err_close_fd;
1034 			}
1035 			*fds = tmp;
1036 		}
1037 		(*fds)[nb_fds++] = fd;
1038 	}
1039 
1040 err_close_fd:
1041 	close(fd);
1042 err_close_fds:
1043 	while (--nb_fds >= 0)
1044 		close((*fds)[nb_fds]);
1045 	return -1;
1046 }
1047 
1048 int map_parse_fds(int *argc, char ***argv, int **fds, __u32 open_flags)
1049 {
1050 	LIBBPF_OPTS(bpf_get_fd_by_id_opts, opts);
1051 
1052 	assert((open_flags & ~BPF_F_RDONLY) == 0);
1053 	opts.open_flags = open_flags;
1054 
1055 	if (is_prefix(**argv, "id")) {
1056 		unsigned int id;
1057 		char *endptr;
1058 
1059 		NEXT_ARGP();
1060 
1061 		id = strtoul(**argv, &endptr, 0);
1062 		if (*endptr) {
1063 			p_err("can't parse %s as ID", **argv);
1064 			return -1;
1065 		}
1066 		NEXT_ARGP();
1067 
1068 		(*fds)[0] = bpf_map_get_fd_by_id_opts(id, &opts);
1069 		if ((*fds)[0] < 0) {
1070 			p_err("get map by id (%u): %s", id, strerror(errno));
1071 			return -1;
1072 		}
1073 		return 1;
1074 	} else if (is_prefix(**argv, "name")) {
1075 		char *name;
1076 
1077 		NEXT_ARGP();
1078 
1079 		name = **argv;
1080 		if (strlen(name) > BPF_OBJ_NAME_LEN - 1) {
1081 			p_err("can't parse name");
1082 			return -1;
1083 		}
1084 		NEXT_ARGP();
1085 
1086 		return map_fd_by_name(name, fds, &opts);
1087 	} else if (is_prefix(**argv, "pinned")) {
1088 		char *path;
1089 		LIBBPF_OPTS(bpf_obj_get_opts, get_opts);
1090 		get_opts.file_flags = open_flags;
1091 
1092 		NEXT_ARGP();
1093 
1094 		path = **argv;
1095 		NEXT_ARGP();
1096 
1097 		(*fds)[0] = open_obj_pinned_any(path, BPF_OBJ_MAP, &get_opts);
1098 		if ((*fds)[0] < 0)
1099 			return -1;
1100 		return 1;
1101 	}
1102 
1103 	p_err("expected 'id', 'name' or 'pinned', got: '%s'?", **argv);
1104 	return -1;
1105 }
1106 
1107 int map_parse_fd(int *argc, char ***argv, __u32 open_flags)
1108 {
1109 	int *fds = NULL;
1110 	int nb_fds, fd;
1111 
1112 	fds = malloc(sizeof(int));
1113 	if (!fds) {
1114 		p_err("mem alloc failed");
1115 		return -1;
1116 	}
1117 	nb_fds = map_parse_fds(argc, argv, &fds, open_flags);
1118 	if (nb_fds != 1) {
1119 		if (nb_fds > 1) {
1120 			p_err("several maps match this handle");
1121 			while (nb_fds--)
1122 				close(fds[nb_fds]);
1123 		}
1124 		fd = -1;
1125 		goto exit_free;
1126 	}
1127 
1128 	fd = fds[0];
1129 exit_free:
1130 	free(fds);
1131 	return fd;
1132 }
1133 
1134 int map_parse_fd_and_info(int *argc, char ***argv, struct bpf_map_info *info,
1135 			  __u32 *info_len, __u32 open_flags)
1136 {
1137 	int err;
1138 	int fd;
1139 
1140 	fd = map_parse_fd(argc, argv, open_flags);
1141 	if (fd < 0)
1142 		return -1;
1143 
1144 	err = bpf_map_get_info_by_fd(fd, info, info_len);
1145 	if (err) {
1146 		p_err("can't get map info: %s", strerror(errno));
1147 		close(fd);
1148 		return err;
1149 	}
1150 
1151 	return fd;
1152 }
1153 
1154 size_t hash_fn_for_key_as_id(long key, void *ctx)
1155 {
1156 	return key;
1157 }
1158 
1159 bool equal_fn_for_key_as_id(long k1, long k2, void *ctx)
1160 {
1161 	return k1 == k2;
1162 }
1163 
1164 const char *bpf_attach_type_input_str(enum bpf_attach_type t)
1165 {
1166 	switch (t) {
1167 	case BPF_CGROUP_INET_INGRESS:		return "ingress";
1168 	case BPF_CGROUP_INET_EGRESS:		return "egress";
1169 	case BPF_CGROUP_INET_SOCK_CREATE:	return "sock_create";
1170 	case BPF_CGROUP_INET_SOCK_RELEASE:	return "sock_release";
1171 	case BPF_CGROUP_SOCK_OPS:		return "sock_ops";
1172 	case BPF_CGROUP_DEVICE:			return "device";
1173 	case BPF_CGROUP_INET4_BIND:		return "bind4";
1174 	case BPF_CGROUP_INET6_BIND:		return "bind6";
1175 	case BPF_CGROUP_INET4_CONNECT:		return "connect4";
1176 	case BPF_CGROUP_INET6_CONNECT:		return "connect6";
1177 	case BPF_CGROUP_INET4_POST_BIND:	return "post_bind4";
1178 	case BPF_CGROUP_INET6_POST_BIND:	return "post_bind6";
1179 	case BPF_CGROUP_INET4_GETPEERNAME:	return "getpeername4";
1180 	case BPF_CGROUP_INET6_GETPEERNAME:	return "getpeername6";
1181 	case BPF_CGROUP_INET4_GETSOCKNAME:	return "getsockname4";
1182 	case BPF_CGROUP_INET6_GETSOCKNAME:	return "getsockname6";
1183 	case BPF_CGROUP_UDP4_SENDMSG:		return "sendmsg4";
1184 	case BPF_CGROUP_UDP6_SENDMSG:		return "sendmsg6";
1185 	case BPF_CGROUP_SYSCTL:			return "sysctl";
1186 	case BPF_CGROUP_UDP4_RECVMSG:		return "recvmsg4";
1187 	case BPF_CGROUP_UDP6_RECVMSG:		return "recvmsg6";
1188 	case BPF_CGROUP_GETSOCKOPT:		return "getsockopt";
1189 	case BPF_CGROUP_SETSOCKOPT:		return "setsockopt";
1190 	case BPF_TRACE_RAW_TP:			return "raw_tp";
1191 	case BPF_TRACE_FENTRY:			return "fentry";
1192 	case BPF_TRACE_FEXIT:			return "fexit";
1193 	case BPF_MODIFY_RETURN:			return "mod_ret";
1194 	case BPF_SK_REUSEPORT_SELECT:		return "sk_skb_reuseport_select";
1195 	case BPF_SK_REUSEPORT_SELECT_OR_MIGRATE:	return "sk_skb_reuseport_select_or_migrate";
1196 	default:	return libbpf_bpf_attach_type_str(t);
1197 	}
1198 }
1199 
1200 int pathname_concat(char *buf, int buf_sz, const char *path,
1201 		    const char *name)
1202 {
1203 	int len;
1204 
1205 	len = snprintf(buf, buf_sz, "%s/%s", path, name);
1206 	if (len < 0)
1207 		return -EINVAL;
1208 	if (len >= buf_sz)
1209 		return -ENAMETOOLONG;
1210 
1211 	return 0;
1212 }
1213 
1214 static bool read_next_kernel_config_option(gzFile file, char *buf, size_t n,
1215 					   char **value)
1216 {
1217 	char *sep;
1218 
1219 	while (gzgets(file, buf, n)) {
1220 		if (strncmp(buf, "CONFIG_", 7))
1221 			continue;
1222 
1223 		sep = strchr(buf, '=');
1224 		if (!sep)
1225 			continue;
1226 
1227 		/* Trim ending '\n' */
1228 		buf[strlen(buf) - 1] = '\0';
1229 
1230 		/* Split on '=' and ensure that a value is present. */
1231 		*sep = '\0';
1232 		if (!sep[1])
1233 			continue;
1234 
1235 		*value = sep + 1;
1236 		return true;
1237 	}
1238 
1239 	return false;
1240 }
1241 
1242 int read_kernel_config(const struct kernel_config_option *requested_options,
1243 		       size_t num_options, char **out_values,
1244 		       const char *define_prefix)
1245 {
1246 	struct utsname utsn;
1247 	char path[PATH_MAX];
1248 	gzFile file = NULL;
1249 	char buf[4096];
1250 	char *value;
1251 	size_t i;
1252 	int ret = 0;
1253 
1254 	if (!requested_options || !out_values || num_options == 0)
1255 		return -1;
1256 
1257 	if (!uname(&utsn)) {
1258 		snprintf(path, sizeof(path), "/boot/config-%s", utsn.release);
1259 
1260 		/* gzopen also accepts uncompressed files. */
1261 		file = gzopen(path, "r");
1262 	}
1263 
1264 	if (!file) {
1265 		/* Some distributions build with CONFIG_IKCONFIG=y and put the
1266 		 * config file at /proc/config.gz.
1267 		 */
1268 		file = gzopen("/proc/config.gz", "r");
1269 	}
1270 
1271 	if (!file) {
1272 		p_info("skipping kernel config, can't open file: %s",
1273 			strerror(errno));
1274 		return -1;
1275 	}
1276 
1277 	if (!gzgets(file, buf, sizeof(buf)) || !gzgets(file, buf, sizeof(buf))) {
1278 		p_info("skipping kernel config, can't read from file: %s",
1279 			strerror(errno));
1280 		ret = -1;
1281 		goto end_parse;
1282 	}
1283 
1284 	if (strcmp(buf, "# Automatically generated file; DO NOT EDIT.\n")) {
1285 		p_info("skipping kernel config, can't find correct file");
1286 		ret = -1;
1287 		goto end_parse;
1288 	}
1289 
1290 	while (read_next_kernel_config_option(file, buf, sizeof(buf), &value)) {
1291 		for (i = 0; i < num_options; i++) {
1292 			if ((define_prefix && !requested_options[i].macro_dump) ||
1293 			     out_values[i] || strcmp(buf, requested_options[i].name))
1294 				continue;
1295 
1296 			out_values[i] = strdup(value);
1297 		}
1298 	}
1299 
1300 end_parse:
1301 	gzclose(file);
1302 	return ret;
1303 }
1304