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