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