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