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