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