0001
0002
0003
0004 #define _GNU_SOURCE
0005 #include <ctype.h>
0006 #include <errno.h>
0007 #include <fcntl.h>
0008 #include <ftw.h>
0009 #include <libgen.h>
0010 #include <mntent.h>
0011 #include <stdbool.h>
0012 #include <stdio.h>
0013 #include <stdlib.h>
0014 #include <string.h>
0015 #include <unistd.h>
0016 #include <net/if.h>
0017 #include <sys/mount.h>
0018 #include <sys/resource.h>
0019 #include <sys/stat.h>
0020 #include <sys/vfs.h>
0021
0022 #include <linux/filter.h>
0023 #include <linux/limits.h>
0024 #include <linux/magic.h>
0025 #include <linux/unistd.h>
0026
0027 #include <bpf/bpf.h>
0028 #include <bpf/hashmap.h>
0029 #include <bpf/libbpf.h> /* libbpf_num_possible_cpus */
0030 #include <bpf/btf.h>
0031
0032 #include "main.h"
0033
0034 #ifndef BPF_FS_MAGIC
0035 #define BPF_FS_MAGIC 0xcafe4a11
0036 #endif
0037
0038 void p_err(const char *fmt, ...)
0039 {
0040 va_list ap;
0041
0042 va_start(ap, fmt);
0043 if (json_output) {
0044 jsonw_start_object(json_wtr);
0045 jsonw_name(json_wtr, "error");
0046 jsonw_vprintf_enquote(json_wtr, fmt, ap);
0047 jsonw_end_object(json_wtr);
0048 } else {
0049 fprintf(stderr, "Error: ");
0050 vfprintf(stderr, fmt, ap);
0051 fprintf(stderr, "\n");
0052 }
0053 va_end(ap);
0054 }
0055
0056 void p_info(const char *fmt, ...)
0057 {
0058 va_list ap;
0059
0060 if (json_output)
0061 return;
0062
0063 va_start(ap, fmt);
0064 vfprintf(stderr, fmt, ap);
0065 fprintf(stderr, "\n");
0066 va_end(ap);
0067 }
0068
0069 static bool is_bpffs(char *path)
0070 {
0071 struct statfs st_fs;
0072
0073 if (statfs(path, &st_fs) < 0)
0074 return false;
0075
0076 return (unsigned long)st_fs.f_type == BPF_FS_MAGIC;
0077 }
0078
0079
0080
0081
0082
0083
0084
0085
0086
0087
0088
0089
0090
0091
0092
0093
0094
0095
0096 static bool known_to_need_rlimit(void)
0097 {
0098 struct rlimit rlim_init, rlim_cur_zero = {};
0099 struct bpf_insn insns[] = {
0100 BPF_MOV64_IMM(BPF_REG_0, 0),
0101 BPF_EXIT_INSN(),
0102 };
0103 size_t insn_cnt = ARRAY_SIZE(insns);
0104 union bpf_attr attr;
0105 int prog_fd, err;
0106
0107 memset(&attr, 0, sizeof(attr));
0108 attr.prog_type = BPF_PROG_TYPE_SOCKET_FILTER;
0109 attr.insns = ptr_to_u64(insns);
0110 attr.insn_cnt = insn_cnt;
0111 attr.license = ptr_to_u64("GPL");
0112
0113 if (getrlimit(RLIMIT_MEMLOCK, &rlim_init))
0114 return false;
0115
0116
0117
0118
0119
0120 rlim_cur_zero.rlim_max = rlim_init.rlim_max;
0121 if (setrlimit(RLIMIT_MEMLOCK, &rlim_cur_zero))
0122 return false;
0123
0124
0125
0126
0127 prog_fd = syscall(__NR_bpf, BPF_PROG_LOAD, &attr, sizeof(attr));
0128 err = errno;
0129
0130
0131 setrlimit(RLIMIT_MEMLOCK, &rlim_init);
0132
0133 if (prog_fd < 0)
0134 return err == EPERM;
0135
0136 close(prog_fd);
0137 return false;
0138 }
0139
0140 void set_max_rlimit(void)
0141 {
0142 struct rlimit rinf = { RLIM_INFINITY, RLIM_INFINITY };
0143
0144 if (known_to_need_rlimit())
0145 setrlimit(RLIMIT_MEMLOCK, &rinf);
0146 }
0147
0148 static int
0149 mnt_fs(const char *target, const char *type, char *buff, size_t bufflen)
0150 {
0151 bool bind_done = false;
0152
0153 while (mount("", target, "none", MS_PRIVATE | MS_REC, NULL)) {
0154 if (errno != EINVAL || bind_done) {
0155 snprintf(buff, bufflen,
0156 "mount --make-private %s failed: %s",
0157 target, strerror(errno));
0158 return -1;
0159 }
0160
0161 if (mount(target, target, "none", MS_BIND, NULL)) {
0162 snprintf(buff, bufflen,
0163 "mount --bind %s %s failed: %s",
0164 target, target, strerror(errno));
0165 return -1;
0166 }
0167
0168 bind_done = true;
0169 }
0170
0171 if (mount(type, target, type, 0, "mode=0700")) {
0172 snprintf(buff, bufflen, "mount -t %s %s %s failed: %s",
0173 type, type, target, strerror(errno));
0174 return -1;
0175 }
0176
0177 return 0;
0178 }
0179
0180 int mount_tracefs(const char *target)
0181 {
0182 char err_str[ERR_MAX_LEN];
0183 int err;
0184
0185 err = mnt_fs(target, "tracefs", err_str, ERR_MAX_LEN);
0186 if (err) {
0187 err_str[ERR_MAX_LEN - 1] = '\0';
0188 p_err("can't mount tracefs: %s", err_str);
0189 }
0190
0191 return err;
0192 }
0193
0194 int open_obj_pinned(const char *path, bool quiet)
0195 {
0196 char *pname;
0197 int fd = -1;
0198
0199 pname = strdup(path);
0200 if (!pname) {
0201 if (!quiet)
0202 p_err("mem alloc failed");
0203 goto out_ret;
0204 }
0205
0206 fd = bpf_obj_get(pname);
0207 if (fd < 0) {
0208 if (!quiet)
0209 p_err("bpf obj get (%s): %s", pname,
0210 errno == EACCES && !is_bpffs(dirname(pname)) ?
0211 "directory not in bpf file system (bpffs)" :
0212 strerror(errno));
0213 goto out_free;
0214 }
0215
0216 out_free:
0217 free(pname);
0218 out_ret:
0219 return fd;
0220 }
0221
0222 int open_obj_pinned_any(const char *path, enum bpf_obj_type exp_type)
0223 {
0224 enum bpf_obj_type type;
0225 int fd;
0226
0227 fd = open_obj_pinned(path, false);
0228 if (fd < 0)
0229 return -1;
0230
0231 type = get_fd_type(fd);
0232 if (type < 0) {
0233 close(fd);
0234 return type;
0235 }
0236 if (type != exp_type) {
0237 p_err("incorrect object type: %s", get_fd_type_name(type));
0238 close(fd);
0239 return -1;
0240 }
0241
0242 return fd;
0243 }
0244
0245 int mount_bpffs_for_pin(const char *name)
0246 {
0247 char err_str[ERR_MAX_LEN];
0248 char *file;
0249 char *dir;
0250 int err = 0;
0251
0252 file = malloc(strlen(name) + 1);
0253 if (!file) {
0254 p_err("mem alloc failed");
0255 return -1;
0256 }
0257
0258 strcpy(file, name);
0259 dir = dirname(file);
0260
0261 if (is_bpffs(dir))
0262
0263 goto out_free;
0264
0265 if (block_mount) {
0266 p_err("no BPF file system found, not mounting it due to --nomount option");
0267 err = -1;
0268 goto out_free;
0269 }
0270
0271 err = mnt_fs(dir, "bpf", err_str, ERR_MAX_LEN);
0272 if (err) {
0273 err_str[ERR_MAX_LEN - 1] = '\0';
0274 p_err("can't mount BPF file system to pin the object (%s): %s",
0275 name, err_str);
0276 }
0277
0278 out_free:
0279 free(file);
0280 return err;
0281 }
0282
0283 int do_pin_fd(int fd, const char *name)
0284 {
0285 int err;
0286
0287 err = mount_bpffs_for_pin(name);
0288 if (err)
0289 return err;
0290
0291 err = bpf_obj_pin(fd, name);
0292 if (err)
0293 p_err("can't pin the object (%s): %s", name, strerror(errno));
0294
0295 return err;
0296 }
0297
0298 int do_pin_any(int argc, char **argv, int (*get_fd)(int *, char ***))
0299 {
0300 int err;
0301 int fd;
0302
0303 fd = get_fd(&argc, &argv);
0304 if (fd < 0)
0305 return fd;
0306
0307 err = do_pin_fd(fd, *argv);
0308
0309 close(fd);
0310 return err;
0311 }
0312
0313 const char *get_fd_type_name(enum bpf_obj_type type)
0314 {
0315 static const char * const names[] = {
0316 [BPF_OBJ_UNKNOWN] = "unknown",
0317 [BPF_OBJ_PROG] = "prog",
0318 [BPF_OBJ_MAP] = "map",
0319 [BPF_OBJ_LINK] = "link",
0320 };
0321
0322 if (type < 0 || type >= ARRAY_SIZE(names) || !names[type])
0323 return names[BPF_OBJ_UNKNOWN];
0324
0325 return names[type];
0326 }
0327
0328 void get_prog_full_name(const struct bpf_prog_info *prog_info, int prog_fd,
0329 char *name_buff, size_t buff_len)
0330 {
0331 const char *prog_name = prog_info->name;
0332 const struct btf_type *func_type;
0333 const struct bpf_func_info finfo = {};
0334 struct bpf_prog_info info = {};
0335 __u32 info_len = sizeof(info);
0336 struct btf *prog_btf = NULL;
0337
0338 if (buff_len <= BPF_OBJ_NAME_LEN ||
0339 strlen(prog_info->name) < BPF_OBJ_NAME_LEN - 1)
0340 goto copy_name;
0341
0342 if (!prog_info->btf_id || prog_info->nr_func_info == 0)
0343 goto copy_name;
0344
0345 info.nr_func_info = 1;
0346 info.func_info_rec_size = prog_info->func_info_rec_size;
0347 if (info.func_info_rec_size > sizeof(finfo))
0348 info.func_info_rec_size = sizeof(finfo);
0349 info.func_info = ptr_to_u64(&finfo);
0350
0351 if (bpf_obj_get_info_by_fd(prog_fd, &info, &info_len))
0352 goto copy_name;
0353
0354 prog_btf = btf__load_from_kernel_by_id(info.btf_id);
0355 if (!prog_btf)
0356 goto copy_name;
0357
0358 func_type = btf__type_by_id(prog_btf, finfo.type_id);
0359 if (!func_type || !btf_is_func(func_type))
0360 goto copy_name;
0361
0362 prog_name = btf__name_by_offset(prog_btf, func_type->name_off);
0363
0364 copy_name:
0365 snprintf(name_buff, buff_len, "%s", prog_name);
0366
0367 if (prog_btf)
0368 btf__free(prog_btf);
0369 }
0370
0371 int get_fd_type(int fd)
0372 {
0373 char path[PATH_MAX];
0374 char buf[512];
0375 ssize_t n;
0376
0377 snprintf(path, sizeof(path), "/proc/self/fd/%d", fd);
0378
0379 n = readlink(path, buf, sizeof(buf));
0380 if (n < 0) {
0381 p_err("can't read link type: %s", strerror(errno));
0382 return -1;
0383 }
0384 if (n == sizeof(path)) {
0385 p_err("can't read link type: path too long!");
0386 return -1;
0387 }
0388
0389 if (strstr(buf, "bpf-map"))
0390 return BPF_OBJ_MAP;
0391 else if (strstr(buf, "bpf-prog"))
0392 return BPF_OBJ_PROG;
0393 else if (strstr(buf, "bpf-link"))
0394 return BPF_OBJ_LINK;
0395
0396 return BPF_OBJ_UNKNOWN;
0397 }
0398
0399 char *get_fdinfo(int fd, const char *key)
0400 {
0401 char path[PATH_MAX];
0402 char *line = NULL;
0403 size_t line_n = 0;
0404 ssize_t n;
0405 FILE *fdi;
0406
0407 snprintf(path, sizeof(path), "/proc/self/fdinfo/%d", fd);
0408
0409 fdi = fopen(path, "r");
0410 if (!fdi)
0411 return NULL;
0412
0413 while ((n = getline(&line, &line_n, fdi)) > 0) {
0414 char *value;
0415 int len;
0416
0417 if (!strstr(line, key))
0418 continue;
0419
0420 fclose(fdi);
0421
0422 value = strchr(line, '\t');
0423 if (!value || !value[1]) {
0424 free(line);
0425 return NULL;
0426 }
0427 value++;
0428
0429 len = strlen(value);
0430 memmove(line, value, len);
0431 line[len - 1] = '\0';
0432
0433 return line;
0434 }
0435
0436 free(line);
0437 fclose(fdi);
0438 return NULL;
0439 }
0440
0441 void print_data_json(uint8_t *data, size_t len)
0442 {
0443 unsigned int i;
0444
0445 jsonw_start_array(json_wtr);
0446 for (i = 0; i < len; i++)
0447 jsonw_printf(json_wtr, "%d", data[i]);
0448 jsonw_end_array(json_wtr);
0449 }
0450
0451 void print_hex_data_json(uint8_t *data, size_t len)
0452 {
0453 unsigned int i;
0454
0455 jsonw_start_array(json_wtr);
0456 for (i = 0; i < len; i++)
0457 jsonw_printf(json_wtr, "\"0x%02hhx\"", data[i]);
0458 jsonw_end_array(json_wtr);
0459 }
0460
0461
0462 static struct hashmap *build_fn_table;
0463 static enum bpf_obj_type build_fn_type;
0464
0465 static int do_build_table_cb(const char *fpath, const struct stat *sb,
0466 int typeflag, struct FTW *ftwbuf)
0467 {
0468 struct bpf_prog_info pinned_info;
0469 __u32 len = sizeof(pinned_info);
0470 enum bpf_obj_type objtype;
0471 int fd, err = 0;
0472 char *path;
0473
0474 if (typeflag != FTW_F)
0475 goto out_ret;
0476
0477 fd = open_obj_pinned(fpath, true);
0478 if (fd < 0)
0479 goto out_ret;
0480
0481 objtype = get_fd_type(fd);
0482 if (objtype != build_fn_type)
0483 goto out_close;
0484
0485 memset(&pinned_info, 0, sizeof(pinned_info));
0486 if (bpf_obj_get_info_by_fd(fd, &pinned_info, &len))
0487 goto out_close;
0488
0489 path = strdup(fpath);
0490 if (!path) {
0491 err = -1;
0492 goto out_close;
0493 }
0494
0495 err = hashmap__append(build_fn_table, u32_as_hash_field(pinned_info.id), path);
0496 if (err) {
0497 p_err("failed to append entry to hashmap for ID %u, path '%s': %s",
0498 pinned_info.id, path, strerror(errno));
0499 goto out_close;
0500 }
0501
0502 out_close:
0503 close(fd);
0504 out_ret:
0505 return err;
0506 }
0507
0508 int build_pinned_obj_table(struct hashmap *tab,
0509 enum bpf_obj_type type)
0510 {
0511 struct mntent *mntent = NULL;
0512 FILE *mntfile = NULL;
0513 int flags = FTW_PHYS;
0514 int nopenfd = 16;
0515 int err = 0;
0516
0517 mntfile = setmntent("/proc/mounts", "r");
0518 if (!mntfile)
0519 return -1;
0520
0521 build_fn_table = tab;
0522 build_fn_type = type;
0523
0524 while ((mntent = getmntent(mntfile))) {
0525 char *path = mntent->mnt_dir;
0526
0527 if (strncmp(mntent->mnt_type, "bpf", 3) != 0)
0528 continue;
0529 err = nftw(path, do_build_table_cb, nopenfd, flags);
0530 if (err)
0531 break;
0532 }
0533 fclose(mntfile);
0534 return err;
0535 }
0536
0537 void delete_pinned_obj_table(struct hashmap *map)
0538 {
0539 struct hashmap_entry *entry;
0540 size_t bkt;
0541
0542 if (!map)
0543 return;
0544
0545 hashmap__for_each_entry(map, entry, bkt)
0546 free(entry->value);
0547
0548 hashmap__free(map);
0549 }
0550
0551 unsigned int get_page_size(void)
0552 {
0553 static int result;
0554
0555 if (!result)
0556 result = getpagesize();
0557 return result;
0558 }
0559
0560 unsigned int get_possible_cpus(void)
0561 {
0562 int cpus = libbpf_num_possible_cpus();
0563
0564 if (cpus < 0) {
0565 p_err("Can't get # of possible cpus: %s", strerror(-cpus));
0566 exit(-1);
0567 }
0568 return cpus;
0569 }
0570
0571 static char *
0572 ifindex_to_name_ns(__u32 ifindex, __u32 ns_dev, __u32 ns_ino, char *buf)
0573 {
0574 struct stat st;
0575 int err;
0576
0577 err = stat("/proc/self/ns/net", &st);
0578 if (err) {
0579 p_err("Can't stat /proc/self: %s", strerror(errno));
0580 return NULL;
0581 }
0582
0583 if (st.st_dev != ns_dev || st.st_ino != ns_ino)
0584 return NULL;
0585
0586 return if_indextoname(ifindex, buf);
0587 }
0588
0589 static int read_sysfs_hex_int(char *path)
0590 {
0591 char vendor_id_buf[8];
0592 int len;
0593 int fd;
0594
0595 fd = open(path, O_RDONLY);
0596 if (fd < 0) {
0597 p_err("Can't open %s: %s", path, strerror(errno));
0598 return -1;
0599 }
0600
0601 len = read(fd, vendor_id_buf, sizeof(vendor_id_buf));
0602 close(fd);
0603 if (len < 0) {
0604 p_err("Can't read %s: %s", path, strerror(errno));
0605 return -1;
0606 }
0607 if (len >= (int)sizeof(vendor_id_buf)) {
0608 p_err("Value in %s too long", path);
0609 return -1;
0610 }
0611
0612 vendor_id_buf[len] = 0;
0613
0614 return strtol(vendor_id_buf, NULL, 0);
0615 }
0616
0617 static int read_sysfs_netdev_hex_int(char *devname, const char *entry_name)
0618 {
0619 char full_path[64];
0620
0621 snprintf(full_path, sizeof(full_path), "/sys/class/net/%s/device/%s",
0622 devname, entry_name);
0623
0624 return read_sysfs_hex_int(full_path);
0625 }
0626
0627 const char *
0628 ifindex_to_bfd_params(__u32 ifindex, __u64 ns_dev, __u64 ns_ino,
0629 const char **opt)
0630 {
0631 char devname[IF_NAMESIZE];
0632 int vendor_id;
0633 int device_id;
0634
0635 if (!ifindex_to_name_ns(ifindex, ns_dev, ns_ino, devname)) {
0636 p_err("Can't get net device name for ifindex %d: %s", ifindex,
0637 strerror(errno));
0638 return NULL;
0639 }
0640
0641 vendor_id = read_sysfs_netdev_hex_int(devname, "vendor");
0642 if (vendor_id < 0) {
0643 p_err("Can't get device vendor id for %s", devname);
0644 return NULL;
0645 }
0646
0647 switch (vendor_id) {
0648 case 0x19ee:
0649 device_id = read_sysfs_netdev_hex_int(devname, "device");
0650 if (device_id != 0x4000 &&
0651 device_id != 0x6000 &&
0652 device_id != 0x6003)
0653 p_info("Unknown NFP device ID, assuming it is NFP-6xxx arch");
0654 *opt = "ctx4";
0655 return "NFP-6xxx";
0656 default:
0657 p_err("Can't get bfd arch name for device vendor id 0x%04x",
0658 vendor_id);
0659 return NULL;
0660 }
0661 }
0662
0663 void print_dev_plain(__u32 ifindex, __u64 ns_dev, __u64 ns_inode)
0664 {
0665 char name[IF_NAMESIZE];
0666
0667 if (!ifindex)
0668 return;
0669
0670 printf(" offloaded_to ");
0671 if (ifindex_to_name_ns(ifindex, ns_dev, ns_inode, name))
0672 printf("%s", name);
0673 else
0674 printf("ifindex %u ns_dev %llu ns_ino %llu",
0675 ifindex, ns_dev, ns_inode);
0676 }
0677
0678 void print_dev_json(__u32 ifindex, __u64 ns_dev, __u64 ns_inode)
0679 {
0680 char name[IF_NAMESIZE];
0681
0682 if (!ifindex)
0683 return;
0684
0685 jsonw_name(json_wtr, "dev");
0686 jsonw_start_object(json_wtr);
0687 jsonw_uint_field(json_wtr, "ifindex", ifindex);
0688 jsonw_uint_field(json_wtr, "ns_dev", ns_dev);
0689 jsonw_uint_field(json_wtr, "ns_inode", ns_inode);
0690 if (ifindex_to_name_ns(ifindex, ns_dev, ns_inode, name))
0691 jsonw_string_field(json_wtr, "ifname", name);
0692 jsonw_end_object(json_wtr);
0693 }
0694
0695 int parse_u32_arg(int *argc, char ***argv, __u32 *val, const char *what)
0696 {
0697 char *endptr;
0698
0699 NEXT_ARGP();
0700
0701 if (*val) {
0702 p_err("%s already specified", what);
0703 return -1;
0704 }
0705
0706 *val = strtoul(**argv, &endptr, 0);
0707 if (*endptr) {
0708 p_err("can't parse %s as %s", **argv, what);
0709 return -1;
0710 }
0711 NEXT_ARGP();
0712
0713 return 0;
0714 }
0715
0716 int __printf(2, 0)
0717 print_all_levels(__maybe_unused enum libbpf_print_level level,
0718 const char *format, va_list args)
0719 {
0720 return vfprintf(stderr, format, args);
0721 }
0722
0723 static int prog_fd_by_nametag(void *nametag, int **fds, bool tag)
0724 {
0725 unsigned int id = 0;
0726 int fd, nb_fds = 0;
0727 void *tmp;
0728 int err;
0729
0730 while (true) {
0731 struct bpf_prog_info info = {};
0732 __u32 len = sizeof(info);
0733
0734 err = bpf_prog_get_next_id(id, &id);
0735 if (err) {
0736 if (errno != ENOENT) {
0737 p_err("%s", strerror(errno));
0738 goto err_close_fds;
0739 }
0740 return nb_fds;
0741 }
0742
0743 fd = bpf_prog_get_fd_by_id(id);
0744 if (fd < 0) {
0745 p_err("can't get prog by id (%u): %s",
0746 id, strerror(errno));
0747 goto err_close_fds;
0748 }
0749
0750 err = bpf_obj_get_info_by_fd(fd, &info, &len);
0751 if (err) {
0752 p_err("can't get prog info (%u): %s",
0753 id, strerror(errno));
0754 goto err_close_fd;
0755 }
0756
0757 if ((tag && memcmp(nametag, info.tag, BPF_TAG_SIZE)) ||
0758 (!tag && strncmp(nametag, info.name, BPF_OBJ_NAME_LEN))) {
0759 close(fd);
0760 continue;
0761 }
0762
0763 if (nb_fds > 0) {
0764 tmp = realloc(*fds, (nb_fds + 1) * sizeof(int));
0765 if (!tmp) {
0766 p_err("failed to realloc");
0767 goto err_close_fd;
0768 }
0769 *fds = tmp;
0770 }
0771 (*fds)[nb_fds++] = fd;
0772 }
0773
0774 err_close_fd:
0775 close(fd);
0776 err_close_fds:
0777 while (--nb_fds >= 0)
0778 close((*fds)[nb_fds]);
0779 return -1;
0780 }
0781
0782 int prog_parse_fds(int *argc, char ***argv, int **fds)
0783 {
0784 if (is_prefix(**argv, "id")) {
0785 unsigned int id;
0786 char *endptr;
0787
0788 NEXT_ARGP();
0789
0790 id = strtoul(**argv, &endptr, 0);
0791 if (*endptr) {
0792 p_err("can't parse %s as ID", **argv);
0793 return -1;
0794 }
0795 NEXT_ARGP();
0796
0797 (*fds)[0] = bpf_prog_get_fd_by_id(id);
0798 if ((*fds)[0] < 0) {
0799 p_err("get by id (%u): %s", id, strerror(errno));
0800 return -1;
0801 }
0802 return 1;
0803 } else if (is_prefix(**argv, "tag")) {
0804 unsigned char tag[BPF_TAG_SIZE];
0805
0806 NEXT_ARGP();
0807
0808 if (sscanf(**argv, BPF_TAG_FMT, tag, tag + 1, tag + 2,
0809 tag + 3, tag + 4, tag + 5, tag + 6, tag + 7)
0810 != BPF_TAG_SIZE) {
0811 p_err("can't parse tag");
0812 return -1;
0813 }
0814 NEXT_ARGP();
0815
0816 return prog_fd_by_nametag(tag, fds, true);
0817 } else if (is_prefix(**argv, "name")) {
0818 char *name;
0819
0820 NEXT_ARGP();
0821
0822 name = **argv;
0823 if (strlen(name) > BPF_OBJ_NAME_LEN - 1) {
0824 p_err("can't parse name");
0825 return -1;
0826 }
0827 NEXT_ARGP();
0828
0829 return prog_fd_by_nametag(name, fds, false);
0830 } else if (is_prefix(**argv, "pinned")) {
0831 char *path;
0832
0833 NEXT_ARGP();
0834
0835 path = **argv;
0836 NEXT_ARGP();
0837
0838 (*fds)[0] = open_obj_pinned_any(path, BPF_OBJ_PROG);
0839 if ((*fds)[0] < 0)
0840 return -1;
0841 return 1;
0842 }
0843
0844 p_err("expected 'id', 'tag', 'name' or 'pinned', got: '%s'?", **argv);
0845 return -1;
0846 }
0847
0848 int prog_parse_fd(int *argc, char ***argv)
0849 {
0850 int *fds = NULL;
0851 int nb_fds, fd;
0852
0853 fds = malloc(sizeof(int));
0854 if (!fds) {
0855 p_err("mem alloc failed");
0856 return -1;
0857 }
0858 nb_fds = prog_parse_fds(argc, argv, &fds);
0859 if (nb_fds != 1) {
0860 if (nb_fds > 1) {
0861 p_err("several programs match this handle");
0862 while (nb_fds--)
0863 close(fds[nb_fds]);
0864 }
0865 fd = -1;
0866 goto exit_free;
0867 }
0868
0869 fd = fds[0];
0870 exit_free:
0871 free(fds);
0872 return fd;
0873 }
0874
0875 static int map_fd_by_name(char *name, int **fds)
0876 {
0877 unsigned int id = 0;
0878 int fd, nb_fds = 0;
0879 void *tmp;
0880 int err;
0881
0882 while (true) {
0883 struct bpf_map_info info = {};
0884 __u32 len = sizeof(info);
0885
0886 err = bpf_map_get_next_id(id, &id);
0887 if (err) {
0888 if (errno != ENOENT) {
0889 p_err("%s", strerror(errno));
0890 goto err_close_fds;
0891 }
0892 return nb_fds;
0893 }
0894
0895 fd = bpf_map_get_fd_by_id(id);
0896 if (fd < 0) {
0897 p_err("can't get map by id (%u): %s",
0898 id, strerror(errno));
0899 goto err_close_fds;
0900 }
0901
0902 err = bpf_obj_get_info_by_fd(fd, &info, &len);
0903 if (err) {
0904 p_err("can't get map info (%u): %s",
0905 id, strerror(errno));
0906 goto err_close_fd;
0907 }
0908
0909 if (strncmp(name, info.name, BPF_OBJ_NAME_LEN)) {
0910 close(fd);
0911 continue;
0912 }
0913
0914 if (nb_fds > 0) {
0915 tmp = realloc(*fds, (nb_fds + 1) * sizeof(int));
0916 if (!tmp) {
0917 p_err("failed to realloc");
0918 goto err_close_fd;
0919 }
0920 *fds = tmp;
0921 }
0922 (*fds)[nb_fds++] = fd;
0923 }
0924
0925 err_close_fd:
0926 close(fd);
0927 err_close_fds:
0928 while (--nb_fds >= 0)
0929 close((*fds)[nb_fds]);
0930 return -1;
0931 }
0932
0933 int map_parse_fds(int *argc, char ***argv, int **fds)
0934 {
0935 if (is_prefix(**argv, "id")) {
0936 unsigned int id;
0937 char *endptr;
0938
0939 NEXT_ARGP();
0940
0941 id = strtoul(**argv, &endptr, 0);
0942 if (*endptr) {
0943 p_err("can't parse %s as ID", **argv);
0944 return -1;
0945 }
0946 NEXT_ARGP();
0947
0948 (*fds)[0] = bpf_map_get_fd_by_id(id);
0949 if ((*fds)[0] < 0) {
0950 p_err("get map by id (%u): %s", id, strerror(errno));
0951 return -1;
0952 }
0953 return 1;
0954 } else if (is_prefix(**argv, "name")) {
0955 char *name;
0956
0957 NEXT_ARGP();
0958
0959 name = **argv;
0960 if (strlen(name) > BPF_OBJ_NAME_LEN - 1) {
0961 p_err("can't parse name");
0962 return -1;
0963 }
0964 NEXT_ARGP();
0965
0966 return map_fd_by_name(name, fds);
0967 } else if (is_prefix(**argv, "pinned")) {
0968 char *path;
0969
0970 NEXT_ARGP();
0971
0972 path = **argv;
0973 NEXT_ARGP();
0974
0975 (*fds)[0] = open_obj_pinned_any(path, BPF_OBJ_MAP);
0976 if ((*fds)[0] < 0)
0977 return -1;
0978 return 1;
0979 }
0980
0981 p_err("expected 'id', 'name' or 'pinned', got: '%s'?", **argv);
0982 return -1;
0983 }
0984
0985 int map_parse_fd(int *argc, char ***argv)
0986 {
0987 int *fds = NULL;
0988 int nb_fds, fd;
0989
0990 fds = malloc(sizeof(int));
0991 if (!fds) {
0992 p_err("mem alloc failed");
0993 return -1;
0994 }
0995 nb_fds = map_parse_fds(argc, argv, &fds);
0996 if (nb_fds != 1) {
0997 if (nb_fds > 1) {
0998 p_err("several maps match this handle");
0999 while (nb_fds--)
1000 close(fds[nb_fds]);
1001 }
1002 fd = -1;
1003 goto exit_free;
1004 }
1005
1006 fd = fds[0];
1007 exit_free:
1008 free(fds);
1009 return fd;
1010 }
1011
1012 int map_parse_fd_and_info(int *argc, char ***argv, void *info, __u32 *info_len)
1013 {
1014 int err;
1015 int fd;
1016
1017 fd = map_parse_fd(argc, argv);
1018 if (fd < 0)
1019 return -1;
1020
1021 err = bpf_obj_get_info_by_fd(fd, info, info_len);
1022 if (err) {
1023 p_err("can't get map info: %s", strerror(errno));
1024 close(fd);
1025 return err;
1026 }
1027
1028 return fd;
1029 }
1030
1031 size_t hash_fn_for_key_as_id(const void *key, void *ctx)
1032 {
1033 return (size_t)key;
1034 }
1035
1036 bool equal_fn_for_key_as_id(const void *k1, const void *k2, void *ctx)
1037 {
1038 return k1 == k2;
1039 }
1040
1041 const char *bpf_attach_type_input_str(enum bpf_attach_type t)
1042 {
1043 switch (t) {
1044 case BPF_CGROUP_INET_INGRESS: return "ingress";
1045 case BPF_CGROUP_INET_EGRESS: return "egress";
1046 case BPF_CGROUP_INET_SOCK_CREATE: return "sock_create";
1047 case BPF_CGROUP_INET_SOCK_RELEASE: return "sock_release";
1048 case BPF_CGROUP_SOCK_OPS: return "sock_ops";
1049 case BPF_CGROUP_DEVICE: return "device";
1050 case BPF_CGROUP_INET4_BIND: return "bind4";
1051 case BPF_CGROUP_INET6_BIND: return "bind6";
1052 case BPF_CGROUP_INET4_CONNECT: return "connect4";
1053 case BPF_CGROUP_INET6_CONNECT: return "connect6";
1054 case BPF_CGROUP_INET4_POST_BIND: return "post_bind4";
1055 case BPF_CGROUP_INET6_POST_BIND: return "post_bind6";
1056 case BPF_CGROUP_INET4_GETPEERNAME: return "getpeername4";
1057 case BPF_CGROUP_INET6_GETPEERNAME: return "getpeername6";
1058 case BPF_CGROUP_INET4_GETSOCKNAME: return "getsockname4";
1059 case BPF_CGROUP_INET6_GETSOCKNAME: return "getsockname6";
1060 case BPF_CGROUP_UDP4_SENDMSG: return "sendmsg4";
1061 case BPF_CGROUP_UDP6_SENDMSG: return "sendmsg6";
1062 case BPF_CGROUP_SYSCTL: return "sysctl";
1063 case BPF_CGROUP_UDP4_RECVMSG: return "recvmsg4";
1064 case BPF_CGROUP_UDP6_RECVMSG: return "recvmsg6";
1065 case BPF_CGROUP_GETSOCKOPT: return "getsockopt";
1066 case BPF_CGROUP_SETSOCKOPT: return "setsockopt";
1067 case BPF_TRACE_RAW_TP: return "raw_tp";
1068 case BPF_TRACE_FENTRY: return "fentry";
1069 case BPF_TRACE_FEXIT: return "fexit";
1070 case BPF_MODIFY_RETURN: return "mod_ret";
1071 case BPF_SK_REUSEPORT_SELECT: return "sk_skb_reuseport_select";
1072 case BPF_SK_REUSEPORT_SELECT_OR_MIGRATE: return "sk_skb_reuseport_select_or_migrate";
1073 default: return libbpf_bpf_attach_type_str(t);
1074 }
1075 }