cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

common.c (20361B)


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