1 // SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) 2 /* Copyright (C) 2017-2018 Netronome Systems, Inc. */ 3 4 #ifndef _GNU_SOURCE 5 #define _GNU_SOURCE 6 #endif 7 #include <assert.h> 8 #include <ctype.h> 9 #include <errno.h> 10 #include <fcntl.h> 11 #include <ftw.h> 12 #include <libgen.h> 13 #include <mntent.h> 14 #include <stdbool.h> 15 #include <stdio.h> 16 #include <stdlib.h> 17 #include <string.h> 18 #include <unistd.h> 19 #include <net/if.h> 20 #include <sys/mount.h> 21 #include <sys/resource.h> 22 #include <sys/stat.h> 23 #include <sys/vfs.h> 24 #include <sys/utsname.h> 25 26 #include <linux/filter.h> 27 #include <linux/limits.h> 28 #include <linux/magic.h> 29 #include <linux/unistd.h> 30 31 #include <bpf/bpf.h> 32 #include <bpf/hashmap.h> 33 #include <bpf/libbpf.h> /* libbpf_num_possible_cpus */ 34 #include <bpf/btf.h> 35 #include <zlib.h> 36 37 #include "main.h" 38 39 #ifndef BPF_FS_MAGIC 40 #define BPF_FS_MAGIC 0xcafe4a11 41 #endif 42 43 void p_err(const char *fmt, ...) 44 { 45 va_list ap; 46 47 va_start(ap, fmt); 48 if (json_output) { 49 jsonw_start_object(json_wtr); 50 jsonw_name(json_wtr, "error"); 51 jsonw_vprintf_enquote(json_wtr, fmt, ap); 52 jsonw_end_object(json_wtr); 53 } else { 54 fprintf(stderr, "Error: "); 55 vfprintf(stderr, fmt, ap); 56 fprintf(stderr, "\n"); 57 } 58 va_end(ap); 59 } 60 61 void p_info(const char *fmt, ...) 62 { 63 va_list ap; 64 65 if (json_output) 66 return; 67 68 va_start(ap, fmt); 69 vfprintf(stderr, fmt, ap); 70 fprintf(stderr, "\n"); 71 va_end(ap); 72 } 73 74 static bool is_bpffs(const char *path) 75 { 76 struct statfs st_fs; 77 78 if (statfs(path, &st_fs) < 0) 79 return false; 80 81 return (unsigned long)st_fs.f_type == BPF_FS_MAGIC; 82 } 83 84 /* Probe whether kernel switched from memlock-based (RLIMIT_MEMLOCK) to 85 * memcg-based memory accounting for BPF maps and programs. This was done in 86 * commit 97306be45fbe ("Merge branch 'switch to memcg-based memory 87 * accounting'"), in Linux 5.11. 88 * 89 * Libbpf also offers to probe for memcg-based accounting vs rlimit, but does 90 * so by checking for the availability of a given BPF helper and this has 91 * failed on some kernels with backports in the past, see commit 6b4384ff1088 92 * ("Revert "bpftool: Use libbpf 1.0 API mode instead of RLIMIT_MEMLOCK""). 93 * Instead, we can probe by lowering the process-based rlimit to 0, trying to 94 * load a BPF object, and resetting the rlimit. If the load succeeds then 95 * memcg-based accounting is supported. 96 * 97 * This would be too dangerous to do in the library, because multithreaded 98 * applications might attempt to load items while the rlimit is at 0. Given 99 * that bpftool is single-threaded, this is fine to do here. 100 */ 101 static bool known_to_need_rlimit(void) 102 { 103 struct rlimit rlim_init, rlim_cur_zero = {}; 104 struct bpf_insn insns[] = { 105 BPF_MOV64_IMM(BPF_REG_0, 0), 106 BPF_EXIT_INSN(), 107 }; 108 size_t insn_cnt = ARRAY_SIZE(insns); 109 union bpf_attr attr; 110 int prog_fd, err; 111 112 memset(&attr, 0, sizeof(attr)); 113 attr.prog_type = BPF_PROG_TYPE_SOCKET_FILTER; 114 attr.insns = ptr_to_u64(insns); 115 attr.insn_cnt = insn_cnt; 116 attr.license = ptr_to_u64("GPL"); 117 118 if (getrlimit(RLIMIT_MEMLOCK, &rlim_init)) 119 return false; 120 121 /* Drop the soft limit to zero. We maintain the hard limit to its 122 * current value, because lowering it would be a permanent operation 123 * for unprivileged users. 124 */ 125 rlim_cur_zero.rlim_max = rlim_init.rlim_max; 126 if (setrlimit(RLIMIT_MEMLOCK, &rlim_cur_zero)) 127 return false; 128 129 /* Do not use bpf_prog_load() from libbpf here, because it calls 130 * bump_rlimit_memlock(), interfering with the current probe. 131 */ 132 prog_fd = syscall(__NR_bpf, BPF_PROG_LOAD, &attr, sizeof(attr)); 133 err = errno; 134 135 /* reset soft rlimit to its initial value */ 136 setrlimit(RLIMIT_MEMLOCK, &rlim_init); 137 138 if (prog_fd < 0) 139 return err == EPERM; 140 141 close(prog_fd); 142 return false; 143 } 144 145 void set_max_rlimit(void) 146 { 147 struct rlimit rinf = { RLIM_INFINITY, RLIM_INFINITY }; 148 149 if (known_to_need_rlimit()) 150 setrlimit(RLIMIT_MEMLOCK, &rinf); 151 } 152 153 static int 154 mnt_fs(const char *target, const char *type, char *buff, size_t bufflen) 155 { 156 bool bind_done = false; 157 158 while (mount("", target, "none", MS_PRIVATE | MS_REC, NULL)) { 159 if (errno != EINVAL || bind_done) { 160 snprintf(buff, bufflen, 161 "mount --make-private %s failed: %s", 162 target, strerror(errno)); 163 return -1; 164 } 165 166 if (mount(target, target, "none", MS_BIND, NULL)) { 167 snprintf(buff, bufflen, 168 "mount --bind %s %s failed: %s", 169 target, target, strerror(errno)); 170 return -1; 171 } 172 173 bind_done = true; 174 } 175 176 if (mount(type, target, type, 0, "mode=0700")) { 177 snprintf(buff, bufflen, "mount -t %s %s %s failed: %s", 178 type, type, target, strerror(errno)); 179 return -1; 180 } 181 182 return 0; 183 } 184 185 int mount_tracefs(const char *target) 186 { 187 char err_str[ERR_MAX_LEN]; 188 int err; 189 190 err = mnt_fs(target, "tracefs", err_str, ERR_MAX_LEN); 191 if (err) { 192 err_str[ERR_MAX_LEN - 1] = '\0'; 193 p_err("can't mount tracefs: %s", err_str); 194 } 195 196 return err; 197 } 198 199 int open_obj_pinned(const char *path, bool quiet, 200 const struct bpf_obj_get_opts *opts) 201 { 202 char *pname; 203 int fd = -1; 204 205 pname = strdup(path); 206 if (!pname) { 207 if (!quiet) 208 p_err("mem alloc failed"); 209 goto out_ret; 210 } 211 212 fd = bpf_obj_get_opts(pname, opts); 213 if (fd < 0) { 214 if (!quiet) 215 p_err("bpf obj get (%s): %s", pname, 216 errno == EACCES && !is_bpffs(dirname(pname)) ? 217 "directory not in bpf file system (bpffs)" : 218 strerror(errno)); 219 goto out_free; 220 } 221 222 out_free: 223 free(pname); 224 out_ret: 225 return fd; 226 } 227 228 int open_obj_pinned_any(const char *path, enum bpf_obj_type exp_type, 229 const struct bpf_obj_get_opts *opts) 230 { 231 enum bpf_obj_type type; 232 int fd; 233 234 fd = open_obj_pinned(path, false, opts); 235 if (fd < 0) 236 return -1; 237 238 type = get_fd_type(fd); 239 if (type < 0) { 240 close(fd); 241 return type; 242 } 243 if (type != exp_type) { 244 p_err("incorrect object type: %s", get_fd_type_name(type)); 245 close(fd); 246 return -1; 247 } 248 249 return fd; 250 } 251 252 int create_and_mount_bpffs_dir(const char *dir_name) 253 { 254 char err_str[ERR_MAX_LEN]; 255 bool dir_exists; 256 int err = 0; 257 258 if (is_bpffs(dir_name)) 259 return err; 260 261 dir_exists = access(dir_name, F_OK) == 0; 262 263 if (!dir_exists) { 264 char *temp_name; 265 char *parent_name; 266 267 temp_name = strdup(dir_name); 268 if (!temp_name) { 269 p_err("mem alloc failed"); 270 return -1; 271 } 272 273 parent_name = dirname(temp_name); 274 275 if (is_bpffs(parent_name)) { 276 /* nothing to do if already mounted */ 277 free(temp_name); 278 return err; 279 } 280 281 if (access(parent_name, F_OK) == -1) { 282 p_err("can't create dir '%s' to pin BPF object: parent dir '%s' doesn't exist", 283 dir_name, parent_name); 284 free(temp_name); 285 return -1; 286 } 287 288 free(temp_name); 289 } 290 291 if (block_mount) { 292 p_err("no BPF file system found, not mounting it due to --nomount option"); 293 return -1; 294 } 295 296 if (!dir_exists) { 297 err = mkdir(dir_name, S_IRWXU); 298 if (err) { 299 p_err("failed to create dir '%s': %s", dir_name, strerror(errno)); 300 return err; 301 } 302 } 303 304 err = mnt_fs(dir_name, "bpf", err_str, ERR_MAX_LEN); 305 if (err) { 306 err_str[ERR_MAX_LEN - 1] = '\0'; 307 p_err("can't mount BPF file system on given dir '%s': %s", 308 dir_name, err_str); 309 310 if (!dir_exists) 311 rmdir(dir_name); 312 } 313 314 return err; 315 } 316 317 int mount_bpffs_for_file(const char *file_name) 318 { 319 char err_str[ERR_MAX_LEN]; 320 char *temp_name; 321 char *dir; 322 int err = 0; 323 324 if (access(file_name, F_OK) != -1) { 325 p_err("can't pin BPF object: path '%s' already exists", file_name); 326 return -1; 327 } 328 329 temp_name = strdup(file_name); 330 if (!temp_name) { 331 p_err("mem alloc failed"); 332 return -1; 333 } 334 335 dir = dirname(temp_name); 336 337 if (is_bpffs(dir)) 338 /* nothing to do if already mounted */ 339 goto out_free; 340 341 if (access(dir, F_OK) == -1) { 342 p_err("can't pin BPF object: dir '%s' doesn't exist", dir); 343 err = -1; 344 goto out_free; 345 } 346 347 if (block_mount) { 348 p_err("no BPF file system found, not mounting it due to --nomount option"); 349 err = -1; 350 goto out_free; 351 } 352 353 err = mnt_fs(dir, "bpf", err_str, ERR_MAX_LEN); 354 if (err) { 355 err_str[ERR_MAX_LEN - 1] = '\0'; 356 p_err("can't mount BPF file system to pin the object '%s': %s", 357 file_name, err_str); 358 } 359 360 out_free: 361 free(temp_name); 362 return err; 363 } 364 365 int do_pin_fd(int fd, const char *name) 366 { 367 int err; 368 369 err = mount_bpffs_for_file(name); 370 if (err) 371 return err; 372 373 err = bpf_obj_pin(fd, name); 374 if (err) 375 p_err("can't pin the object (%s): %s", name, strerror(errno)); 376 377 return err; 378 } 379 380 int do_pin_any(int argc, char **argv, int (*get_fd)(int *, char ***)) 381 { 382 int err; 383 int fd; 384 385 if (!REQ_ARGS(3)) 386 return -EINVAL; 387 388 fd = get_fd(&argc, &argv); 389 if (fd < 0) 390 return fd; 391 392 err = do_pin_fd(fd, *argv); 393 394 close(fd); 395 return err; 396 } 397 398 const char *get_fd_type_name(enum bpf_obj_type type) 399 { 400 static const char * const names[] = { 401 [BPF_OBJ_UNKNOWN] = "unknown", 402 [BPF_OBJ_PROG] = "prog", 403 [BPF_OBJ_MAP] = "map", 404 [BPF_OBJ_LINK] = "link", 405 }; 406 407 if (type < 0 || type >= ARRAY_SIZE(names) || !names[type]) 408 return names[BPF_OBJ_UNKNOWN]; 409 410 return names[type]; 411 } 412 413 void get_prog_full_name(const struct bpf_prog_info *prog_info, int prog_fd, 414 char *name_buff, size_t buff_len) 415 { 416 const char *prog_name = prog_info->name; 417 const struct btf_type *func_type; 418 struct bpf_func_info finfo = {}; 419 struct bpf_prog_info info = {}; 420 __u32 info_len = sizeof(info); 421 struct btf *prog_btf = NULL; 422 423 if (buff_len <= BPF_OBJ_NAME_LEN || 424 strlen(prog_info->name) < BPF_OBJ_NAME_LEN - 1) 425 goto copy_name; 426 427 if (!prog_info->btf_id || prog_info->nr_func_info == 0) 428 goto copy_name; 429 430 info.nr_func_info = 1; 431 info.func_info_rec_size = prog_info->func_info_rec_size; 432 if (info.func_info_rec_size > sizeof(finfo)) 433 info.func_info_rec_size = sizeof(finfo); 434 info.func_info = ptr_to_u64(&finfo); 435 436 if (bpf_prog_get_info_by_fd(prog_fd, &info, &info_len)) 437 goto copy_name; 438 439 prog_btf = btf__load_from_kernel_by_id(info.btf_id); 440 if (!prog_btf) 441 goto copy_name; 442 443 func_type = btf__type_by_id(prog_btf, finfo.type_id); 444 if (!func_type || !btf_is_func(func_type)) 445 goto copy_name; 446 447 prog_name = btf__name_by_offset(prog_btf, func_type->name_off); 448 449 copy_name: 450 snprintf(name_buff, buff_len, "%s", prog_name); 451 452 if (prog_btf) 453 btf__free(prog_btf); 454 } 455 456 int get_fd_type(int fd) 457 { 458 char path[PATH_MAX]; 459 char buf[512]; 460 ssize_t n; 461 462 snprintf(path, sizeof(path), "/proc/self/fd/%d", fd); 463 464 n = readlink(path, buf, sizeof(buf)); 465 if (n < 0) { 466 p_err("can't read link type: %s", strerror(errno)); 467 return -1; 468 } 469 if (n == sizeof(buf)) { 470 p_err("can't read link type: path too long!"); 471 return -1; 472 } 473 buf[n] = '\0'; 474 475 if (strstr(buf, "bpf-map")) 476 return BPF_OBJ_MAP; 477 else if (strstr(buf, "bpf-prog")) 478 return BPF_OBJ_PROG; 479 else if (strstr(buf, "bpf-link")) 480 return BPF_OBJ_LINK; 481 482 return BPF_OBJ_UNKNOWN; 483 } 484 485 char *get_fdinfo(int fd, const char *key) 486 { 487 char path[PATH_MAX]; 488 char *line = NULL; 489 size_t line_n = 0; 490 ssize_t n; 491 FILE *fdi; 492 493 snprintf(path, sizeof(path), "/proc/self/fdinfo/%d", fd); 494 495 fdi = fopen(path, "r"); 496 if (!fdi) 497 return NULL; 498 499 while ((n = getline(&line, &line_n, fdi)) > 0) { 500 char *value; 501 int len; 502 503 if (!strstr(line, key)) 504 continue; 505 506 fclose(fdi); 507 508 value = strchr(line, '\t'); 509 if (!value || !value[1]) { 510 free(line); 511 return NULL; 512 } 513 value++; 514 515 len = strlen(value); 516 memmove(line, value, len); 517 line[len - 1] = '\0'; 518 519 return line; 520 } 521 522 free(line); 523 fclose(fdi); 524 return NULL; 525 } 526 527 void print_data_json(uint8_t *data, size_t len) 528 { 529 unsigned int i; 530 531 jsonw_start_array(json_wtr); 532 for (i = 0; i < len; i++) 533 jsonw_printf(json_wtr, "%d", data[i]); 534 jsonw_end_array(json_wtr); 535 } 536 537 void print_hex_data_json(uint8_t *data, size_t len) 538 { 539 unsigned int i; 540 541 jsonw_start_array(json_wtr); 542 for (i = 0; i < len; i++) 543 jsonw_printf(json_wtr, "\"0x%02hhx\"", data[i]); 544 jsonw_end_array(json_wtr); 545 } 546 547 /* extra params for nftw cb */ 548 static struct hashmap *build_fn_table; 549 static enum bpf_obj_type build_fn_type; 550 551 static int do_build_table_cb(const char *fpath, const struct stat *sb, 552 int typeflag, struct FTW *ftwbuf) 553 { 554 struct bpf_prog_info pinned_info; 555 __u32 len = sizeof(pinned_info); 556 enum bpf_obj_type objtype; 557 int fd, err = 0; 558 char *path; 559 560 if (typeflag != FTW_F) 561 goto out_ret; 562 563 fd = open_obj_pinned(fpath, true, NULL); 564 if (fd < 0) 565 goto out_ret; 566 567 objtype = get_fd_type(fd); 568 if (objtype != build_fn_type) 569 goto out_close; 570 571 memset(&pinned_info, 0, sizeof(pinned_info)); 572 if (bpf_prog_get_info_by_fd(fd, &pinned_info, &len)) 573 goto out_close; 574 575 path = strdup(fpath); 576 if (!path) { 577 err = -1; 578 goto out_close; 579 } 580 581 err = hashmap__append(build_fn_table, pinned_info.id, path); 582 if (err) { 583 p_err("failed to append entry to hashmap for ID %u, path '%s': %s", 584 pinned_info.id, path, strerror(errno)); 585 free(path); 586 goto out_close; 587 } 588 589 out_close: 590 close(fd); 591 out_ret: 592 return err; 593 } 594 595 int build_pinned_obj_table(struct hashmap *tab, 596 enum bpf_obj_type type) 597 { 598 struct mntent *mntent = NULL; 599 FILE *mntfile = NULL; 600 int flags = FTW_PHYS; 601 int nopenfd = 16; 602 int err = 0; 603 604 mntfile = setmntent("/proc/mounts", "r"); 605 if (!mntfile) 606 return -1; 607 608 build_fn_table = tab; 609 build_fn_type = type; 610 611 while ((mntent = getmntent(mntfile))) { 612 char *path = mntent->mnt_dir; 613 614 if (strncmp(mntent->mnt_type, "bpf", 3) != 0) 615 continue; 616 err = nftw(path, do_build_table_cb, nopenfd, flags); 617 if (err) 618 break; 619 } 620 fclose(mntfile); 621 return err; 622 } 623 624 void delete_pinned_obj_table(struct hashmap *map) 625 { 626 struct hashmap_entry *entry; 627 size_t bkt; 628 629 if (!map) 630 return; 631 632 hashmap__for_each_entry(map, entry, bkt) 633 free(entry->pvalue); 634 635 hashmap__free(map); 636 } 637 638 unsigned int get_page_size(void) 639 { 640 static int result; 641 642 if (!result) 643 result = getpagesize(); 644 return result; 645 } 646 647 unsigned int get_possible_cpus(void) 648 { 649 int cpus = libbpf_num_possible_cpus(); 650 651 if (cpus < 0) { 652 p_err("Can't get # of possible cpus: %s", strerror(-cpus)); 653 exit(-1); 654 } 655 return cpus; 656 } 657 658 static char * 659 ifindex_to_name_ns(__u32 ifindex, __u32 ns_dev, __u32 ns_ino, char *buf) 660 { 661 struct stat st; 662 int err; 663 664 err = stat("/proc/self/ns/net", &st); 665 if (err) { 666 p_err("Can't stat /proc/self: %s", strerror(errno)); 667 return NULL; 668 } 669 670 if (st.st_dev != ns_dev || st.st_ino != ns_ino) 671 return NULL; 672 673 return if_indextoname(ifindex, buf); 674 } 675 676 static int read_sysfs_hex_int(char *path) 677 { 678 char vendor_id_buf[8]; 679 int len; 680 int fd; 681 682 fd = open(path, O_RDONLY); 683 if (fd < 0) { 684 p_err("Can't open %s: %s", path, strerror(errno)); 685 return -1; 686 } 687 688 len = read(fd, vendor_id_buf, sizeof(vendor_id_buf)); 689 close(fd); 690 if (len < 0) { 691 p_err("Can't read %s: %s", path, strerror(errno)); 692 return -1; 693 } 694 if (len >= (int)sizeof(vendor_id_buf)) { 695 p_err("Value in %s too long", path); 696 return -1; 697 } 698 699 vendor_id_buf[len] = 0; 700 701 return strtol(vendor_id_buf, NULL, 0); 702 } 703 704 static int read_sysfs_netdev_hex_int(char *devname, const char *entry_name) 705 { 706 char full_path[64]; 707 708 snprintf(full_path, sizeof(full_path), "/sys/class/net/%s/device/%s", 709 devname, entry_name); 710 711 return read_sysfs_hex_int(full_path); 712 } 713 714 const char * 715 ifindex_to_arch(__u32 ifindex, __u64 ns_dev, __u64 ns_ino, const char **opt) 716 { 717 __maybe_unused int device_id; 718 char devname[IF_NAMESIZE]; 719 int vendor_id; 720 721 if (!ifindex_to_name_ns(ifindex, ns_dev, ns_ino, devname)) { 722 p_err("Can't get net device name for ifindex %u: %s", ifindex, 723 strerror(errno)); 724 return NULL; 725 } 726 727 vendor_id = read_sysfs_netdev_hex_int(devname, "vendor"); 728 if (vendor_id < 0) { 729 p_err("Can't get device vendor id for %s", devname); 730 return NULL; 731 } 732 733 switch (vendor_id) { 734 #ifdef HAVE_LIBBFD_SUPPORT 735 case 0x19ee: 736 device_id = read_sysfs_netdev_hex_int(devname, "device"); 737 if (device_id != 0x4000 && 738 device_id != 0x6000 && 739 device_id != 0x6003) 740 p_info("Unknown NFP device ID, assuming it is NFP-6xxx arch"); 741 *opt = "ctx4"; 742 return "NFP-6xxx"; 743 #endif /* HAVE_LIBBFD_SUPPORT */ 744 /* No NFP support in LLVM, we have no valid triple to return. */ 745 default: 746 p_err("Can't get arch name for device vendor id 0x%04x", 747 (unsigned int)vendor_id); 748 return NULL; 749 } 750 } 751 752 void print_dev_plain(__u32 ifindex, __u64 ns_dev, __u64 ns_inode) 753 { 754 char name[IF_NAMESIZE]; 755 756 if (!ifindex) 757 return; 758 759 printf(" offloaded_to "); 760 if (ifindex_to_name_ns(ifindex, ns_dev, ns_inode, name)) 761 printf("%s", name); 762 else 763 printf("ifindex %u ns_dev %llu ns_ino %llu", 764 ifindex, ns_dev, ns_inode); 765 } 766 767 void print_dev_json(__u32 ifindex, __u64 ns_dev, __u64 ns_inode) 768 { 769 char name[IF_NAMESIZE]; 770 771 if (!ifindex) 772 return; 773 774 jsonw_name(json_wtr, "dev"); 775 jsonw_start_object(json_wtr); 776 jsonw_uint_field(json_wtr, "ifindex", ifindex); 777 jsonw_uint_field(json_wtr, "ns_dev", ns_dev); 778 jsonw_uint_field(json_wtr, "ns_inode", ns_inode); 779 if (ifindex_to_name_ns(ifindex, ns_dev, ns_inode, name)) 780 jsonw_string_field(json_wtr, "ifname", name); 781 jsonw_end_object(json_wtr); 782 } 783 784 int parse_u32_arg(int *argc, char ***argv, __u32 *val, const char *what) 785 { 786 char *endptr; 787 788 NEXT_ARGP(); 789 790 if (*val) { 791 p_err("%s already specified", what); 792 return -1; 793 } 794 795 *val = strtoul(**argv, &endptr, 0); 796 if (*endptr) { 797 p_err("can't parse %s as %s", **argv, what); 798 return -1; 799 } 800 NEXT_ARGP(); 801 802 return 0; 803 } 804 805 int __printf(2, 0) 806 print_all_levels(__maybe_unused enum libbpf_print_level level, 807 const char *format, va_list args) 808 { 809 return vfprintf(stderr, format, args); 810 } 811 812 static int prog_fd_by_nametag(void *nametag, int **fds, bool tag) 813 { 814 char prog_name[MAX_PROG_FULL_NAME]; 815 unsigned int id = 0; 816 int fd, nb_fds = 0; 817 void *tmp; 818 int err; 819 820 while (true) { 821 struct bpf_prog_info info = {}; 822 __u32 len = sizeof(info); 823 824 err = bpf_prog_get_next_id(id, &id); 825 if (err) { 826 if (errno != ENOENT) { 827 p_err("%s", strerror(errno)); 828 goto err_close_fds; 829 } 830 return nb_fds; 831 } 832 833 fd = bpf_prog_get_fd_by_id(id); 834 if (fd < 0) { 835 p_err("can't get prog by id (%u): %s", 836 id, strerror(errno)); 837 goto err_close_fds; 838 } 839 840 err = bpf_prog_get_info_by_fd(fd, &info, &len); 841 if (err) { 842 p_err("can't get prog info (%u): %s", 843 id, strerror(errno)); 844 goto err_close_fd; 845 } 846 847 if (tag && memcmp(nametag, info.tag, BPF_TAG_SIZE)) { 848 close(fd); 849 continue; 850 } 851 852 if (!tag) { 853 get_prog_full_name(&info, fd, prog_name, 854 sizeof(prog_name)); 855 if (strncmp(nametag, prog_name, sizeof(prog_name))) { 856 close(fd); 857 continue; 858 } 859 } 860 861 if (nb_fds > 0) { 862 tmp = realloc(*fds, (nb_fds + 1) * sizeof(int)); 863 if (!tmp) { 864 p_err("failed to realloc"); 865 goto err_close_fd; 866 } 867 *fds = tmp; 868 } 869 (*fds)[nb_fds++] = fd; 870 } 871 872 err_close_fd: 873 close(fd); 874 err_close_fds: 875 while (--nb_fds >= 0) 876 close((*fds)[nb_fds]); 877 return -1; 878 } 879 880 int prog_parse_fds(int *argc, char ***argv, int **fds) 881 { 882 if (is_prefix(**argv, "id")) { 883 unsigned int id; 884 char *endptr; 885 886 NEXT_ARGP(); 887 888 id = strtoul(**argv, &endptr, 0); 889 if (*endptr) { 890 p_err("can't parse %s as ID", **argv); 891 return -1; 892 } 893 NEXT_ARGP(); 894 895 (*fds)[0] = bpf_prog_get_fd_by_id(id); 896 if ((*fds)[0] < 0) { 897 p_err("get by id (%u): %s", id, strerror(errno)); 898 return -1; 899 } 900 return 1; 901 } else if (is_prefix(**argv, "tag")) { 902 unsigned char tag[BPF_TAG_SIZE]; 903 904 NEXT_ARGP(); 905 906 if (sscanf(**argv, BPF_TAG_FMT, tag, tag + 1, tag + 2, 907 tag + 3, tag + 4, tag + 5, tag + 6, tag + 7) 908 != BPF_TAG_SIZE) { 909 p_err("can't parse tag"); 910 return -1; 911 } 912 NEXT_ARGP(); 913 914 return prog_fd_by_nametag(tag, fds, true); 915 } else if (is_prefix(**argv, "name")) { 916 char *name; 917 918 NEXT_ARGP(); 919 920 name = **argv; 921 if (strlen(name) > MAX_PROG_FULL_NAME - 1) { 922 p_err("can't parse name"); 923 return -1; 924 } 925 NEXT_ARGP(); 926 927 return prog_fd_by_nametag(name, fds, false); 928 } else if (is_prefix(**argv, "pinned")) { 929 char *path; 930 931 NEXT_ARGP(); 932 933 path = **argv; 934 NEXT_ARGP(); 935 936 (*fds)[0] = open_obj_pinned_any(path, BPF_OBJ_PROG, NULL); 937 if ((*fds)[0] < 0) 938 return -1; 939 return 1; 940 } 941 942 p_err("expected 'id', 'tag', 'name' or 'pinned', got: '%s'?", **argv); 943 return -1; 944 } 945 946 int prog_parse_fd(int *argc, char ***argv) 947 { 948 int *fds = NULL; 949 int nb_fds, fd; 950 951 fds = malloc(sizeof(int)); 952 if (!fds) { 953 p_err("mem alloc failed"); 954 return -1; 955 } 956 nb_fds = prog_parse_fds(argc, argv, &fds); 957 if (nb_fds != 1) { 958 if (nb_fds > 1) { 959 p_err("several programs match this handle"); 960 while (nb_fds--) 961 close(fds[nb_fds]); 962 } 963 fd = -1; 964 goto exit_free; 965 } 966 967 fd = fds[0]; 968 exit_free: 969 free(fds); 970 return fd; 971 } 972 973 static int map_fd_by_name(char *name, int **fds, 974 const struct bpf_get_fd_by_id_opts *opts) 975 { 976 unsigned int id = 0; 977 int fd, nb_fds = 0; 978 void *tmp; 979 int err; 980 981 while (true) { 982 LIBBPF_OPTS(bpf_get_fd_by_id_opts, opts_ro); 983 struct bpf_map_info info = {}; 984 __u32 len = sizeof(info); 985 986 err = bpf_map_get_next_id(id, &id); 987 if (err) { 988 if (errno != ENOENT) { 989 p_err("%s", strerror(errno)); 990 goto err_close_fds; 991 } 992 return nb_fds; 993 } 994 995 /* Request a read-only fd to query the map info */ 996 opts_ro.open_flags = BPF_F_RDONLY; 997 fd = bpf_map_get_fd_by_id_opts(id, &opts_ro); 998 if (fd < 0) { 999 p_err("can't get map by id (%u): %s", 1000 id, strerror(errno)); 1001 goto err_close_fds; 1002 } 1003 1004 err = bpf_map_get_info_by_fd(fd, &info, &len); 1005 if (err) { 1006 p_err("can't get map info (%u): %s", 1007 id, strerror(errno)); 1008 goto err_close_fd; 1009 } 1010 1011 if (strncmp(name, info.name, BPF_OBJ_NAME_LEN)) { 1012 close(fd); 1013 continue; 1014 } 1015 1016 /* Get an fd with the requested options, if they differ 1017 * from the read-only options used to get the fd above. 1018 */ 1019 if (memcmp(opts, &opts_ro, sizeof(opts_ro))) { 1020 close(fd); 1021 fd = bpf_map_get_fd_by_id_opts(id, opts); 1022 if (fd < 0) { 1023 p_err("can't get map by id (%u): %s", id, 1024 strerror(errno)); 1025 goto err_close_fds; 1026 } 1027 } 1028 1029 if (nb_fds > 0) { 1030 tmp = realloc(*fds, (nb_fds + 1) * sizeof(int)); 1031 if (!tmp) { 1032 p_err("failed to realloc"); 1033 goto err_close_fd; 1034 } 1035 *fds = tmp; 1036 } 1037 (*fds)[nb_fds++] = fd; 1038 } 1039 1040 err_close_fd: 1041 close(fd); 1042 err_close_fds: 1043 while (--nb_fds >= 0) 1044 close((*fds)[nb_fds]); 1045 return -1; 1046 } 1047 1048 int map_parse_fds(int *argc, char ***argv, int **fds, __u32 open_flags) 1049 { 1050 LIBBPF_OPTS(bpf_get_fd_by_id_opts, opts); 1051 1052 assert((open_flags & ~BPF_F_RDONLY) == 0); 1053 opts.open_flags = open_flags; 1054 1055 if (is_prefix(**argv, "id")) { 1056 unsigned int id; 1057 char *endptr; 1058 1059 NEXT_ARGP(); 1060 1061 id = strtoul(**argv, &endptr, 0); 1062 if (*endptr) { 1063 p_err("can't parse %s as ID", **argv); 1064 return -1; 1065 } 1066 NEXT_ARGP(); 1067 1068 (*fds)[0] = bpf_map_get_fd_by_id_opts(id, &opts); 1069 if ((*fds)[0] < 0) { 1070 p_err("get map by id (%u): %s", id, strerror(errno)); 1071 return -1; 1072 } 1073 return 1; 1074 } else if (is_prefix(**argv, "name")) { 1075 char *name; 1076 1077 NEXT_ARGP(); 1078 1079 name = **argv; 1080 if (strlen(name) > BPF_OBJ_NAME_LEN - 1) { 1081 p_err("can't parse name"); 1082 return -1; 1083 } 1084 NEXT_ARGP(); 1085 1086 return map_fd_by_name(name, fds, &opts); 1087 } else if (is_prefix(**argv, "pinned")) { 1088 char *path; 1089 LIBBPF_OPTS(bpf_obj_get_opts, get_opts); 1090 get_opts.file_flags = open_flags; 1091 1092 NEXT_ARGP(); 1093 1094 path = **argv; 1095 NEXT_ARGP(); 1096 1097 (*fds)[0] = open_obj_pinned_any(path, BPF_OBJ_MAP, &get_opts); 1098 if ((*fds)[0] < 0) 1099 return -1; 1100 return 1; 1101 } 1102 1103 p_err("expected 'id', 'name' or 'pinned', got: '%s'?", **argv); 1104 return -1; 1105 } 1106 1107 int map_parse_fd(int *argc, char ***argv, __u32 open_flags) 1108 { 1109 int *fds = NULL; 1110 int nb_fds, fd; 1111 1112 fds = malloc(sizeof(int)); 1113 if (!fds) { 1114 p_err("mem alloc failed"); 1115 return -1; 1116 } 1117 nb_fds = map_parse_fds(argc, argv, &fds, open_flags); 1118 if (nb_fds != 1) { 1119 if (nb_fds > 1) { 1120 p_err("several maps match this handle"); 1121 while (nb_fds--) 1122 close(fds[nb_fds]); 1123 } 1124 fd = -1; 1125 goto exit_free; 1126 } 1127 1128 fd = fds[0]; 1129 exit_free: 1130 free(fds); 1131 return fd; 1132 } 1133 1134 int map_parse_fd_and_info(int *argc, char ***argv, struct bpf_map_info *info, 1135 __u32 *info_len, __u32 open_flags) 1136 { 1137 int err; 1138 int fd; 1139 1140 fd = map_parse_fd(argc, argv, open_flags); 1141 if (fd < 0) 1142 return -1; 1143 1144 err = bpf_map_get_info_by_fd(fd, info, info_len); 1145 if (err) { 1146 p_err("can't get map info: %s", strerror(errno)); 1147 close(fd); 1148 return err; 1149 } 1150 1151 return fd; 1152 } 1153 1154 size_t hash_fn_for_key_as_id(long key, void *ctx) 1155 { 1156 return key; 1157 } 1158 1159 bool equal_fn_for_key_as_id(long k1, long k2, void *ctx) 1160 { 1161 return k1 == k2; 1162 } 1163 1164 const char *bpf_attach_type_input_str(enum bpf_attach_type t) 1165 { 1166 switch (t) { 1167 case BPF_CGROUP_INET_INGRESS: return "ingress"; 1168 case BPF_CGROUP_INET_EGRESS: return "egress"; 1169 case BPF_CGROUP_INET_SOCK_CREATE: return "sock_create"; 1170 case BPF_CGROUP_INET_SOCK_RELEASE: return "sock_release"; 1171 case BPF_CGROUP_SOCK_OPS: return "sock_ops"; 1172 case BPF_CGROUP_DEVICE: return "device"; 1173 case BPF_CGROUP_INET4_BIND: return "bind4"; 1174 case BPF_CGROUP_INET6_BIND: return "bind6"; 1175 case BPF_CGROUP_INET4_CONNECT: return "connect4"; 1176 case BPF_CGROUP_INET6_CONNECT: return "connect6"; 1177 case BPF_CGROUP_INET4_POST_BIND: return "post_bind4"; 1178 case BPF_CGROUP_INET6_POST_BIND: return "post_bind6"; 1179 case BPF_CGROUP_INET4_GETPEERNAME: return "getpeername4"; 1180 case BPF_CGROUP_INET6_GETPEERNAME: return "getpeername6"; 1181 case BPF_CGROUP_INET4_GETSOCKNAME: return "getsockname4"; 1182 case BPF_CGROUP_INET6_GETSOCKNAME: return "getsockname6"; 1183 case BPF_CGROUP_UDP4_SENDMSG: return "sendmsg4"; 1184 case BPF_CGROUP_UDP6_SENDMSG: return "sendmsg6"; 1185 case BPF_CGROUP_SYSCTL: return "sysctl"; 1186 case BPF_CGROUP_UDP4_RECVMSG: return "recvmsg4"; 1187 case BPF_CGROUP_UDP6_RECVMSG: return "recvmsg6"; 1188 case BPF_CGROUP_GETSOCKOPT: return "getsockopt"; 1189 case BPF_CGROUP_SETSOCKOPT: return "setsockopt"; 1190 case BPF_TRACE_RAW_TP: return "raw_tp"; 1191 case BPF_TRACE_FENTRY: return "fentry"; 1192 case BPF_TRACE_FEXIT: return "fexit"; 1193 case BPF_MODIFY_RETURN: return "mod_ret"; 1194 case BPF_SK_REUSEPORT_SELECT: return "sk_skb_reuseport_select"; 1195 case BPF_SK_REUSEPORT_SELECT_OR_MIGRATE: return "sk_skb_reuseport_select_or_migrate"; 1196 default: return libbpf_bpf_attach_type_str(t); 1197 } 1198 } 1199 1200 int pathname_concat(char *buf, int buf_sz, const char *path, 1201 const char *name) 1202 { 1203 int len; 1204 1205 len = snprintf(buf, buf_sz, "%s/%s", path, name); 1206 if (len < 0) 1207 return -EINVAL; 1208 if (len >= buf_sz) 1209 return -ENAMETOOLONG; 1210 1211 return 0; 1212 } 1213 1214 static bool read_next_kernel_config_option(gzFile file, char *buf, size_t n, 1215 char **value) 1216 { 1217 char *sep; 1218 1219 while (gzgets(file, buf, n)) { 1220 if (strncmp(buf, "CONFIG_", 7)) 1221 continue; 1222 1223 sep = strchr(buf, '='); 1224 if (!sep) 1225 continue; 1226 1227 /* Trim ending '\n' */ 1228 buf[strlen(buf) - 1] = '\0'; 1229 1230 /* Split on '=' and ensure that a value is present. */ 1231 *sep = '\0'; 1232 if (!sep[1]) 1233 continue; 1234 1235 *value = sep + 1; 1236 return true; 1237 } 1238 1239 return false; 1240 } 1241 1242 int read_kernel_config(const struct kernel_config_option *requested_options, 1243 size_t num_options, char **out_values, 1244 const char *define_prefix) 1245 { 1246 struct utsname utsn; 1247 char path[PATH_MAX]; 1248 gzFile file = NULL; 1249 char buf[4096]; 1250 char *value; 1251 size_t i; 1252 int ret = 0; 1253 1254 if (!requested_options || !out_values || num_options == 0) 1255 return -1; 1256 1257 if (!uname(&utsn)) { 1258 snprintf(path, sizeof(path), "/boot/config-%s", utsn.release); 1259 1260 /* gzopen also accepts uncompressed files. */ 1261 file = gzopen(path, "r"); 1262 } 1263 1264 if (!file) { 1265 /* Some distributions build with CONFIG_IKCONFIG=y and put the 1266 * config file at /proc/config.gz. 1267 */ 1268 file = gzopen("/proc/config.gz", "r"); 1269 } 1270 1271 if (!file) { 1272 p_info("skipping kernel config, can't open file: %s", 1273 strerror(errno)); 1274 return -1; 1275 } 1276 1277 if (!gzgets(file, buf, sizeof(buf)) || !gzgets(file, buf, sizeof(buf))) { 1278 p_info("skipping kernel config, can't read from file: %s", 1279 strerror(errno)); 1280 ret = -1; 1281 goto end_parse; 1282 } 1283 1284 if (strcmp(buf, "# Automatically generated file; DO NOT EDIT.\n")) { 1285 p_info("skipping kernel config, can't find correct file"); 1286 ret = -1; 1287 goto end_parse; 1288 } 1289 1290 while (read_next_kernel_config_option(file, buf, sizeof(buf), &value)) { 1291 for (i = 0; i < num_options; i++) { 1292 if ((define_prefix && !requested_options[i].macro_dump) || 1293 out_values[i] || strcmp(buf, requested_options[i].name)) 1294 continue; 1295 1296 out_values[i] = strdup(value); 1297 } 1298 } 1299 1300 end_parse: 1301 gzclose(file); 1302 return ret; 1303 } 1304