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