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