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