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