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 <errno.h> 6 #include <fcntl.h> 7 #include <stdarg.h> 8 #include <stdio.h> 9 #include <stdlib.h> 10 #include <string.h> 11 #include <time.h> 12 #include <unistd.h> 13 #include <net/if.h> 14 #include <sys/types.h> 15 #include <sys/stat.h> 16 17 #include <linux/err.h> 18 19 #include <bpf.h> 20 #include <btf.h> 21 #include <libbpf.h> 22 23 #include "cfg.h" 24 #include "main.h" 25 #include "xlated_dumper.h" 26 27 static const char * const attach_type_strings[] = { 28 [BPF_SK_SKB_STREAM_PARSER] = "stream_parser", 29 [BPF_SK_SKB_STREAM_VERDICT] = "stream_verdict", 30 [BPF_SK_MSG_VERDICT] = "msg_verdict", 31 [BPF_FLOW_DISSECTOR] = "flow_dissector", 32 [__MAX_BPF_ATTACH_TYPE] = NULL, 33 }; 34 35 static enum bpf_attach_type parse_attach_type(const char *str) 36 { 37 enum bpf_attach_type type; 38 39 for (type = 0; type < __MAX_BPF_ATTACH_TYPE; type++) { 40 if (attach_type_strings[type] && 41 is_prefix(str, attach_type_strings[type])) 42 return type; 43 } 44 45 return __MAX_BPF_ATTACH_TYPE; 46 } 47 48 static void print_boot_time(__u64 nsecs, char *buf, unsigned int size) 49 { 50 struct timespec real_time_ts, boot_time_ts; 51 time_t wallclock_secs; 52 struct tm load_tm; 53 54 buf[--size] = '\0'; 55 56 if (clock_gettime(CLOCK_REALTIME, &real_time_ts) || 57 clock_gettime(CLOCK_BOOTTIME, &boot_time_ts)) { 58 perror("Can't read clocks"); 59 snprintf(buf, size, "%llu", nsecs / 1000000000); 60 return; 61 } 62 63 wallclock_secs = (real_time_ts.tv_sec - boot_time_ts.tv_sec) + 64 (real_time_ts.tv_nsec - boot_time_ts.tv_nsec + nsecs) / 65 1000000000; 66 67 68 if (!localtime_r(&wallclock_secs, &load_tm)) { 69 snprintf(buf, size, "%llu", nsecs / 1000000000); 70 return; 71 } 72 73 if (json_output) 74 strftime(buf, size, "%s", &load_tm); 75 else 76 strftime(buf, size, "%FT%T%z", &load_tm); 77 } 78 79 static int prog_fd_by_tag(unsigned char *tag) 80 { 81 unsigned int id = 0; 82 int err; 83 int fd; 84 85 while (true) { 86 struct bpf_prog_info info = {}; 87 __u32 len = sizeof(info); 88 89 err = bpf_prog_get_next_id(id, &id); 90 if (err) { 91 p_err("%s", strerror(errno)); 92 return -1; 93 } 94 95 fd = bpf_prog_get_fd_by_id(id); 96 if (fd < 0) { 97 p_err("can't get prog by id (%u): %s", 98 id, strerror(errno)); 99 return -1; 100 } 101 102 err = bpf_obj_get_info_by_fd(fd, &info, &len); 103 if (err) { 104 p_err("can't get prog info (%u): %s", 105 id, strerror(errno)); 106 close(fd); 107 return -1; 108 } 109 110 if (!memcmp(tag, info.tag, BPF_TAG_SIZE)) 111 return fd; 112 113 close(fd); 114 } 115 } 116 117 int prog_parse_fd(int *argc, char ***argv) 118 { 119 int fd; 120 121 if (is_prefix(**argv, "id")) { 122 unsigned int id; 123 char *endptr; 124 125 NEXT_ARGP(); 126 127 id = strtoul(**argv, &endptr, 0); 128 if (*endptr) { 129 p_err("can't parse %s as ID", **argv); 130 return -1; 131 } 132 NEXT_ARGP(); 133 134 fd = bpf_prog_get_fd_by_id(id); 135 if (fd < 0) 136 p_err("get by id (%u): %s", id, strerror(errno)); 137 return fd; 138 } else if (is_prefix(**argv, "tag")) { 139 unsigned char tag[BPF_TAG_SIZE]; 140 141 NEXT_ARGP(); 142 143 if (sscanf(**argv, BPF_TAG_FMT, tag, tag + 1, tag + 2, 144 tag + 3, tag + 4, tag + 5, tag + 6, tag + 7) 145 != BPF_TAG_SIZE) { 146 p_err("can't parse tag"); 147 return -1; 148 } 149 NEXT_ARGP(); 150 151 return prog_fd_by_tag(tag); 152 } else if (is_prefix(**argv, "pinned")) { 153 char *path; 154 155 NEXT_ARGP(); 156 157 path = **argv; 158 NEXT_ARGP(); 159 160 return open_obj_pinned_any(path, BPF_OBJ_PROG); 161 } 162 163 p_err("expected 'id', 'tag' or 'pinned', got: '%s'?", **argv); 164 return -1; 165 } 166 167 static void show_prog_maps(int fd, u32 num_maps) 168 { 169 struct bpf_prog_info info = {}; 170 __u32 len = sizeof(info); 171 __u32 map_ids[num_maps]; 172 unsigned int i; 173 int err; 174 175 info.nr_map_ids = num_maps; 176 info.map_ids = ptr_to_u64(map_ids); 177 178 err = bpf_obj_get_info_by_fd(fd, &info, &len); 179 if (err || !info.nr_map_ids) 180 return; 181 182 if (json_output) { 183 jsonw_name(json_wtr, "map_ids"); 184 jsonw_start_array(json_wtr); 185 for (i = 0; i < info.nr_map_ids; i++) 186 jsonw_uint(json_wtr, map_ids[i]); 187 jsonw_end_array(json_wtr); 188 } else { 189 printf(" map_ids "); 190 for (i = 0; i < info.nr_map_ids; i++) 191 printf("%u%s", map_ids[i], 192 i == info.nr_map_ids - 1 ? "" : ","); 193 } 194 } 195 196 static void print_prog_json(struct bpf_prog_info *info, int fd) 197 { 198 char *memlock; 199 200 jsonw_start_object(json_wtr); 201 jsonw_uint_field(json_wtr, "id", info->id); 202 if (info->type < ARRAY_SIZE(prog_type_name)) 203 jsonw_string_field(json_wtr, "type", 204 prog_type_name[info->type]); 205 else 206 jsonw_uint_field(json_wtr, "type", info->type); 207 208 if (*info->name) 209 jsonw_string_field(json_wtr, "name", info->name); 210 211 jsonw_name(json_wtr, "tag"); 212 jsonw_printf(json_wtr, "\"" BPF_TAG_FMT "\"", 213 info->tag[0], info->tag[1], info->tag[2], info->tag[3], 214 info->tag[4], info->tag[5], info->tag[6], info->tag[7]); 215 216 jsonw_bool_field(json_wtr, "gpl_compatible", info->gpl_compatible); 217 if (info->run_time_ns) { 218 jsonw_uint_field(json_wtr, "run_time_ns", info->run_time_ns); 219 jsonw_uint_field(json_wtr, "run_cnt", info->run_cnt); 220 } 221 222 print_dev_json(info->ifindex, info->netns_dev, info->netns_ino); 223 224 if (info->load_time) { 225 char buf[32]; 226 227 print_boot_time(info->load_time, buf, sizeof(buf)); 228 229 /* Piggy back on load_time, since 0 uid is a valid one */ 230 jsonw_name(json_wtr, "loaded_at"); 231 jsonw_printf(json_wtr, "%s", buf); 232 jsonw_uint_field(json_wtr, "uid", info->created_by_uid); 233 } 234 235 jsonw_uint_field(json_wtr, "bytes_xlated", info->xlated_prog_len); 236 237 if (info->jited_prog_len) { 238 jsonw_bool_field(json_wtr, "jited", true); 239 jsonw_uint_field(json_wtr, "bytes_jited", info->jited_prog_len); 240 } else { 241 jsonw_bool_field(json_wtr, "jited", false); 242 } 243 244 memlock = get_fdinfo(fd, "memlock"); 245 if (memlock) 246 jsonw_int_field(json_wtr, "bytes_memlock", atoi(memlock)); 247 free(memlock); 248 249 if (info->nr_map_ids) 250 show_prog_maps(fd, info->nr_map_ids); 251 252 if (!hash_empty(prog_table.table)) { 253 struct pinned_obj *obj; 254 255 jsonw_name(json_wtr, "pinned"); 256 jsonw_start_array(json_wtr); 257 hash_for_each_possible(prog_table.table, obj, hash, info->id) { 258 if (obj->id == info->id) 259 jsonw_string(json_wtr, obj->path); 260 } 261 jsonw_end_array(json_wtr); 262 } 263 264 jsonw_end_object(json_wtr); 265 } 266 267 static void print_prog_plain(struct bpf_prog_info *info, int fd) 268 { 269 char *memlock; 270 271 printf("%u: ", info->id); 272 if (info->type < ARRAY_SIZE(prog_type_name)) 273 printf("%s ", prog_type_name[info->type]); 274 else 275 printf("type %u ", info->type); 276 277 if (*info->name) 278 printf("name %s ", info->name); 279 280 printf("tag "); 281 fprint_hex(stdout, info->tag, BPF_TAG_SIZE, ""); 282 print_dev_plain(info->ifindex, info->netns_dev, info->netns_ino); 283 printf("%s", info->gpl_compatible ? " gpl" : ""); 284 if (info->run_time_ns) 285 printf(" run_time_ns %lld run_cnt %lld", 286 info->run_time_ns, info->run_cnt); 287 printf("\n"); 288 289 if (info->load_time) { 290 char buf[32]; 291 292 print_boot_time(info->load_time, buf, sizeof(buf)); 293 294 /* Piggy back on load_time, since 0 uid is a valid one */ 295 printf("\tloaded_at %s uid %u\n", buf, info->created_by_uid); 296 } 297 298 printf("\txlated %uB", info->xlated_prog_len); 299 300 if (info->jited_prog_len) 301 printf(" jited %uB", info->jited_prog_len); 302 else 303 printf(" not jited"); 304 305 memlock = get_fdinfo(fd, "memlock"); 306 if (memlock) 307 printf(" memlock %sB", memlock); 308 free(memlock); 309 310 if (info->nr_map_ids) 311 show_prog_maps(fd, info->nr_map_ids); 312 313 if (!hash_empty(prog_table.table)) { 314 struct pinned_obj *obj; 315 316 hash_for_each_possible(prog_table.table, obj, hash, info->id) { 317 if (obj->id == info->id) 318 printf("\n\tpinned %s", obj->path); 319 } 320 } 321 322 printf("\n"); 323 } 324 325 static int show_prog(int fd) 326 { 327 struct bpf_prog_info info = {}; 328 __u32 len = sizeof(info); 329 int err; 330 331 err = bpf_obj_get_info_by_fd(fd, &info, &len); 332 if (err) { 333 p_err("can't get prog info: %s", strerror(errno)); 334 return -1; 335 } 336 337 if (json_output) 338 print_prog_json(&info, fd); 339 else 340 print_prog_plain(&info, fd); 341 342 return 0; 343 } 344 345 static int do_show(int argc, char **argv) 346 { 347 __u32 id = 0; 348 int err; 349 int fd; 350 351 if (show_pinned) 352 build_pinned_obj_table(&prog_table, BPF_OBJ_PROG); 353 354 if (argc == 2) { 355 fd = prog_parse_fd(&argc, &argv); 356 if (fd < 0) 357 return -1; 358 359 return show_prog(fd); 360 } 361 362 if (argc) 363 return BAD_ARG(); 364 365 if (json_output) 366 jsonw_start_array(json_wtr); 367 while (true) { 368 err = bpf_prog_get_next_id(id, &id); 369 if (err) { 370 if (errno == ENOENT) { 371 err = 0; 372 break; 373 } 374 p_err("can't get next program: %s%s", strerror(errno), 375 errno == EINVAL ? " -- kernel too old?" : ""); 376 err = -1; 377 break; 378 } 379 380 fd = bpf_prog_get_fd_by_id(id); 381 if (fd < 0) { 382 if (errno == ENOENT) 383 continue; 384 p_err("can't get prog by id (%u): %s", 385 id, strerror(errno)); 386 err = -1; 387 break; 388 } 389 390 err = show_prog(fd); 391 close(fd); 392 if (err) 393 break; 394 } 395 396 if (json_output) 397 jsonw_end_array(json_wtr); 398 399 return err; 400 } 401 402 static int do_dump(int argc, char **argv) 403 { 404 struct bpf_prog_info_linear *info_linear; 405 struct bpf_prog_linfo *prog_linfo = NULL; 406 enum {DUMP_JITED, DUMP_XLATED} mode; 407 const char *disasm_opt = NULL; 408 struct bpf_prog_info *info; 409 struct dump_data dd = {}; 410 void *func_info = NULL; 411 struct btf *btf = NULL; 412 char *filepath = NULL; 413 bool opcodes = false; 414 bool visual = false; 415 char func_sig[1024]; 416 unsigned char *buf; 417 bool linum = false; 418 __u32 member_len; 419 __u64 arrays; 420 ssize_t n; 421 int fd; 422 423 if (is_prefix(*argv, "jited")) { 424 if (disasm_init()) 425 return -1; 426 mode = DUMP_JITED; 427 } else if (is_prefix(*argv, "xlated")) { 428 mode = DUMP_XLATED; 429 } else { 430 p_err("expected 'xlated' or 'jited', got: %s", *argv); 431 return -1; 432 } 433 NEXT_ARG(); 434 435 if (argc < 2) 436 usage(); 437 438 fd = prog_parse_fd(&argc, &argv); 439 if (fd < 0) 440 return -1; 441 442 if (is_prefix(*argv, "file")) { 443 NEXT_ARG(); 444 if (!argc) { 445 p_err("expected file path"); 446 return -1; 447 } 448 449 filepath = *argv; 450 NEXT_ARG(); 451 } else if (is_prefix(*argv, "opcodes")) { 452 opcodes = true; 453 NEXT_ARG(); 454 } else if (is_prefix(*argv, "visual")) { 455 visual = true; 456 NEXT_ARG(); 457 } else if (is_prefix(*argv, "linum")) { 458 linum = true; 459 NEXT_ARG(); 460 } 461 462 if (argc) { 463 usage(); 464 return -1; 465 } 466 467 if (mode == DUMP_JITED) 468 arrays = 1UL << BPF_PROG_INFO_JITED_INSNS; 469 else 470 arrays = 1UL << BPF_PROG_INFO_XLATED_INSNS; 471 472 arrays |= 1UL << BPF_PROG_INFO_JITED_KSYMS; 473 arrays |= 1UL << BPF_PROG_INFO_JITED_FUNC_LENS; 474 arrays |= 1UL << BPF_PROG_INFO_FUNC_INFO; 475 arrays |= 1UL << BPF_PROG_INFO_LINE_INFO; 476 arrays |= 1UL << BPF_PROG_INFO_JITED_LINE_INFO; 477 478 info_linear = bpf_program__get_prog_info_linear(fd, arrays); 479 close(fd); 480 if (IS_ERR_OR_NULL(info_linear)) { 481 p_err("can't get prog info: %s", strerror(errno)); 482 return -1; 483 } 484 485 info = &info_linear->info; 486 if (mode == DUMP_JITED) { 487 if (info->jited_prog_len == 0) { 488 p_info("no instructions returned"); 489 goto err_free; 490 } 491 buf = (unsigned char *)(info->jited_prog_insns); 492 member_len = info->jited_prog_len; 493 } else { /* DUMP_XLATED */ 494 if (info->xlated_prog_len == 0) { 495 p_err("error retrieving insn dump: kernel.kptr_restrict set?"); 496 goto err_free; 497 } 498 buf = (unsigned char *)info->xlated_prog_insns; 499 member_len = info->xlated_prog_len; 500 } 501 502 if (info->btf_id && btf__get_from_id(info->btf_id, &btf)) { 503 p_err("failed to get btf"); 504 goto err_free; 505 } 506 507 func_info = (void *)info->func_info; 508 509 if (info->nr_line_info) { 510 prog_linfo = bpf_prog_linfo__new(info); 511 if (!prog_linfo) 512 p_info("error in processing bpf_line_info. continue without it."); 513 } 514 515 if (filepath) { 516 fd = open(filepath, O_WRONLY | O_CREAT | O_TRUNC, 0600); 517 if (fd < 0) { 518 p_err("can't open file %s: %s", filepath, 519 strerror(errno)); 520 goto err_free; 521 } 522 523 n = write(fd, buf, member_len); 524 close(fd); 525 if (n != member_len) { 526 p_err("error writing output file: %s", 527 n < 0 ? strerror(errno) : "short write"); 528 goto err_free; 529 } 530 531 if (json_output) 532 jsonw_null(json_wtr); 533 } else if (mode == DUMP_JITED) { 534 const char *name = NULL; 535 536 if (info->ifindex) { 537 name = ifindex_to_bfd_params(info->ifindex, 538 info->netns_dev, 539 info->netns_ino, 540 &disasm_opt); 541 if (!name) 542 goto err_free; 543 } 544 545 if (info->nr_jited_func_lens && info->jited_func_lens) { 546 struct kernel_sym *sym = NULL; 547 struct bpf_func_info *record; 548 char sym_name[SYM_MAX_NAME]; 549 unsigned char *img = buf; 550 __u64 *ksyms = NULL; 551 __u32 *lens; 552 __u32 i; 553 if (info->nr_jited_ksyms) { 554 kernel_syms_load(&dd); 555 ksyms = (__u64 *) info->jited_ksyms; 556 } 557 558 if (json_output) 559 jsonw_start_array(json_wtr); 560 561 lens = (__u32 *) info->jited_func_lens; 562 for (i = 0; i < info->nr_jited_func_lens; i++) { 563 if (ksyms) { 564 sym = kernel_syms_search(&dd, ksyms[i]); 565 if (sym) 566 sprintf(sym_name, "%s", sym->name); 567 else 568 sprintf(sym_name, "0x%016llx", ksyms[i]); 569 } else { 570 strcpy(sym_name, "unknown"); 571 } 572 573 if (func_info) { 574 record = func_info + i * info->func_info_rec_size; 575 btf_dumper_type_only(btf, record->type_id, 576 func_sig, 577 sizeof(func_sig)); 578 } 579 580 if (json_output) { 581 jsonw_start_object(json_wtr); 582 if (func_info && func_sig[0] != '\0') { 583 jsonw_name(json_wtr, "proto"); 584 jsonw_string(json_wtr, func_sig); 585 } 586 jsonw_name(json_wtr, "name"); 587 jsonw_string(json_wtr, sym_name); 588 jsonw_name(json_wtr, "insns"); 589 } else { 590 if (func_info && func_sig[0] != '\0') 591 printf("%s:\n", func_sig); 592 printf("%s:\n", sym_name); 593 } 594 595 disasm_print_insn(img, lens[i], opcodes, 596 name, disasm_opt, btf, 597 prog_linfo, ksyms[i], i, 598 linum); 599 600 img += lens[i]; 601 602 if (json_output) 603 jsonw_end_object(json_wtr); 604 else 605 printf("\n"); 606 } 607 608 if (json_output) 609 jsonw_end_array(json_wtr); 610 } else { 611 disasm_print_insn(buf, member_len, opcodes, name, 612 disasm_opt, btf, NULL, 0, 0, false); 613 } 614 } else if (visual) { 615 if (json_output) 616 jsonw_null(json_wtr); 617 else 618 dump_xlated_cfg(buf, member_len); 619 } else { 620 kernel_syms_load(&dd); 621 dd.nr_jited_ksyms = info->nr_jited_ksyms; 622 dd.jited_ksyms = (__u64 *) info->jited_ksyms; 623 dd.btf = btf; 624 dd.func_info = func_info; 625 dd.finfo_rec_size = info->func_info_rec_size; 626 dd.prog_linfo = prog_linfo; 627 628 if (json_output) 629 dump_xlated_json(&dd, buf, member_len, opcodes, 630 linum); 631 else 632 dump_xlated_plain(&dd, buf, member_len, opcodes, 633 linum); 634 kernel_syms_destroy(&dd); 635 } 636 637 free(info_linear); 638 return 0; 639 640 err_free: 641 free(info_linear); 642 return -1; 643 } 644 645 static int do_pin(int argc, char **argv) 646 { 647 int err; 648 649 err = do_pin_any(argc, argv, bpf_prog_get_fd_by_id); 650 if (!err && json_output) 651 jsonw_null(json_wtr); 652 return err; 653 } 654 655 struct map_replace { 656 int idx; 657 int fd; 658 char *name; 659 }; 660 661 static int map_replace_compar(const void *p1, const void *p2) 662 { 663 const struct map_replace *a = p1, *b = p2; 664 665 return a->idx - b->idx; 666 } 667 668 static int parse_attach_detach_args(int argc, char **argv, int *progfd, 669 enum bpf_attach_type *attach_type, 670 int *mapfd) 671 { 672 if (!REQ_ARGS(3)) 673 return -EINVAL; 674 675 *progfd = prog_parse_fd(&argc, &argv); 676 if (*progfd < 0) 677 return *progfd; 678 679 *attach_type = parse_attach_type(*argv); 680 if (*attach_type == __MAX_BPF_ATTACH_TYPE) { 681 p_err("invalid attach/detach type"); 682 return -EINVAL; 683 } 684 685 if (*attach_type == BPF_FLOW_DISSECTOR) { 686 *mapfd = -1; 687 return 0; 688 } 689 690 NEXT_ARG(); 691 if (!REQ_ARGS(2)) 692 return -EINVAL; 693 694 *mapfd = map_parse_fd(&argc, &argv); 695 if (*mapfd < 0) 696 return *mapfd; 697 698 return 0; 699 } 700 701 static int do_attach(int argc, char **argv) 702 { 703 enum bpf_attach_type attach_type; 704 int err, progfd; 705 int mapfd; 706 707 err = parse_attach_detach_args(argc, argv, 708 &progfd, &attach_type, &mapfd); 709 if (err) 710 return err; 711 712 err = bpf_prog_attach(progfd, mapfd, attach_type, 0); 713 if (err) { 714 p_err("failed prog attach to map"); 715 return -EINVAL; 716 } 717 718 if (json_output) 719 jsonw_null(json_wtr); 720 return 0; 721 } 722 723 static int do_detach(int argc, char **argv) 724 { 725 enum bpf_attach_type attach_type; 726 int err, progfd; 727 int mapfd; 728 729 err = parse_attach_detach_args(argc, argv, 730 &progfd, &attach_type, &mapfd); 731 if (err) 732 return err; 733 734 err = bpf_prog_detach2(progfd, mapfd, attach_type); 735 if (err) { 736 p_err("failed prog detach from map"); 737 return -EINVAL; 738 } 739 740 if (json_output) 741 jsonw_null(json_wtr); 742 return 0; 743 } 744 745 static int load_with_options(int argc, char **argv, bool first_prog_only) 746 { 747 enum bpf_attach_type expected_attach_type; 748 struct bpf_object_open_attr attr = { 749 .prog_type = BPF_PROG_TYPE_UNSPEC, 750 }; 751 struct map_replace *map_replace = NULL; 752 struct bpf_program *prog = NULL, *pos; 753 unsigned int old_map_fds = 0; 754 const char *pinmaps = NULL; 755 struct bpf_object *obj; 756 struct bpf_map *map; 757 const char *pinfile; 758 unsigned int i, j; 759 __u32 ifindex = 0; 760 int idx, err; 761 762 if (!REQ_ARGS(2)) 763 return -1; 764 attr.file = GET_ARG(); 765 pinfile = GET_ARG(); 766 767 while (argc) { 768 if (is_prefix(*argv, "type")) { 769 char *type; 770 771 NEXT_ARG(); 772 773 if (attr.prog_type != BPF_PROG_TYPE_UNSPEC) { 774 p_err("program type already specified"); 775 goto err_free_reuse_maps; 776 } 777 if (!REQ_ARGS(1)) 778 goto err_free_reuse_maps; 779 780 /* Put a '/' at the end of type to appease libbpf */ 781 type = malloc(strlen(*argv) + 2); 782 if (!type) { 783 p_err("mem alloc failed"); 784 goto err_free_reuse_maps; 785 } 786 *type = 0; 787 strcat(type, *argv); 788 strcat(type, "/"); 789 790 err = libbpf_prog_type_by_name(type, &attr.prog_type, 791 &expected_attach_type); 792 free(type); 793 if (err < 0) 794 goto err_free_reuse_maps; 795 796 NEXT_ARG(); 797 } else if (is_prefix(*argv, "map")) { 798 void *new_map_replace; 799 char *endptr, *name; 800 int fd; 801 802 NEXT_ARG(); 803 804 if (!REQ_ARGS(4)) 805 goto err_free_reuse_maps; 806 807 if (is_prefix(*argv, "idx")) { 808 NEXT_ARG(); 809 810 idx = strtoul(*argv, &endptr, 0); 811 if (*endptr) { 812 p_err("can't parse %s as IDX", *argv); 813 goto err_free_reuse_maps; 814 } 815 name = NULL; 816 } else if (is_prefix(*argv, "name")) { 817 NEXT_ARG(); 818 819 name = *argv; 820 idx = -1; 821 } else { 822 p_err("expected 'idx' or 'name', got: '%s'?", 823 *argv); 824 goto err_free_reuse_maps; 825 } 826 NEXT_ARG(); 827 828 fd = map_parse_fd(&argc, &argv); 829 if (fd < 0) 830 goto err_free_reuse_maps; 831 832 new_map_replace = reallocarray(map_replace, 833 old_map_fds + 1, 834 sizeof(*map_replace)); 835 if (!new_map_replace) { 836 p_err("mem alloc failed"); 837 goto err_free_reuse_maps; 838 } 839 map_replace = new_map_replace; 840 841 map_replace[old_map_fds].idx = idx; 842 map_replace[old_map_fds].name = name; 843 map_replace[old_map_fds].fd = fd; 844 old_map_fds++; 845 } else if (is_prefix(*argv, "dev")) { 846 NEXT_ARG(); 847 848 if (ifindex) { 849 p_err("offload device already specified"); 850 goto err_free_reuse_maps; 851 } 852 if (!REQ_ARGS(1)) 853 goto err_free_reuse_maps; 854 855 ifindex = if_nametoindex(*argv); 856 if (!ifindex) { 857 p_err("unrecognized netdevice '%s': %s", 858 *argv, strerror(errno)); 859 goto err_free_reuse_maps; 860 } 861 NEXT_ARG(); 862 } else if (is_prefix(*argv, "pinmaps")) { 863 NEXT_ARG(); 864 865 if (!REQ_ARGS(1)) 866 goto err_free_reuse_maps; 867 868 pinmaps = GET_ARG(); 869 } else { 870 p_err("expected no more arguments, 'type', 'map' or 'dev', got: '%s'?", 871 *argv); 872 goto err_free_reuse_maps; 873 } 874 } 875 876 obj = __bpf_object__open_xattr(&attr, bpf_flags); 877 if (IS_ERR_OR_NULL(obj)) { 878 p_err("failed to open object file"); 879 goto err_free_reuse_maps; 880 } 881 882 bpf_object__for_each_program(pos, obj) { 883 enum bpf_prog_type prog_type = attr.prog_type; 884 885 if (attr.prog_type == BPF_PROG_TYPE_UNSPEC) { 886 const char *sec_name = bpf_program__title(pos, false); 887 888 err = libbpf_prog_type_by_name(sec_name, &prog_type, 889 &expected_attach_type); 890 if (err < 0) 891 goto err_close_obj; 892 } 893 894 bpf_program__set_ifindex(pos, ifindex); 895 bpf_program__set_type(pos, prog_type); 896 bpf_program__set_expected_attach_type(pos, expected_attach_type); 897 } 898 899 qsort(map_replace, old_map_fds, sizeof(*map_replace), 900 map_replace_compar); 901 902 /* After the sort maps by name will be first on the list, because they 903 * have idx == -1. Resolve them. 904 */ 905 j = 0; 906 while (j < old_map_fds && map_replace[j].name) { 907 i = 0; 908 bpf_object__for_each_map(map, obj) { 909 if (!strcmp(bpf_map__name(map), map_replace[j].name)) { 910 map_replace[j].idx = i; 911 break; 912 } 913 i++; 914 } 915 if (map_replace[j].idx == -1) { 916 p_err("unable to find map '%s'", map_replace[j].name); 917 goto err_close_obj; 918 } 919 j++; 920 } 921 /* Resort if any names were resolved */ 922 if (j) 923 qsort(map_replace, old_map_fds, sizeof(*map_replace), 924 map_replace_compar); 925 926 /* Set ifindex and name reuse */ 927 j = 0; 928 idx = 0; 929 bpf_object__for_each_map(map, obj) { 930 if (!bpf_map__is_offload_neutral(map)) 931 bpf_map__set_ifindex(map, ifindex); 932 933 if (j < old_map_fds && idx == map_replace[j].idx) { 934 err = bpf_map__reuse_fd(map, map_replace[j++].fd); 935 if (err) { 936 p_err("unable to set up map reuse: %d", err); 937 goto err_close_obj; 938 } 939 940 /* Next reuse wants to apply to the same map */ 941 if (j < old_map_fds && map_replace[j].idx == idx) { 942 p_err("replacement for map idx %d specified more than once", 943 idx); 944 goto err_close_obj; 945 } 946 } 947 948 idx++; 949 } 950 if (j < old_map_fds) { 951 p_err("map idx '%d' not used", map_replace[j].idx); 952 goto err_close_obj; 953 } 954 955 set_max_rlimit(); 956 957 err = bpf_object__load(obj); 958 if (err) { 959 p_err("failed to load object file"); 960 goto err_close_obj; 961 } 962 963 err = mount_bpffs_for_pin(pinfile); 964 if (err) 965 goto err_close_obj; 966 967 if (first_prog_only) { 968 prog = bpf_program__next(NULL, obj); 969 if (!prog) { 970 p_err("object file doesn't contain any bpf program"); 971 goto err_close_obj; 972 } 973 974 err = bpf_obj_pin(bpf_program__fd(prog), pinfile); 975 if (err) { 976 p_err("failed to pin program %s", 977 bpf_program__title(prog, false)); 978 goto err_close_obj; 979 } 980 } else { 981 err = bpf_object__pin_programs(obj, pinfile); 982 if (err) { 983 p_err("failed to pin all programs"); 984 goto err_close_obj; 985 } 986 } 987 988 if (pinmaps) { 989 err = bpf_object__pin_maps(obj, pinmaps); 990 if (err) { 991 p_err("failed to pin all maps"); 992 goto err_unpin; 993 } 994 } 995 996 if (json_output) 997 jsonw_null(json_wtr); 998 999 bpf_object__close(obj); 1000 for (i = 0; i < old_map_fds; i++) 1001 close(map_replace[i].fd); 1002 free(map_replace); 1003 1004 return 0; 1005 1006 err_unpin: 1007 if (first_prog_only) 1008 unlink(pinfile); 1009 else 1010 bpf_object__unpin_programs(obj, pinfile); 1011 err_close_obj: 1012 bpf_object__close(obj); 1013 err_free_reuse_maps: 1014 for (i = 0; i < old_map_fds; i++) 1015 close(map_replace[i].fd); 1016 free(map_replace); 1017 return -1; 1018 } 1019 1020 static int do_load(int argc, char **argv) 1021 { 1022 return load_with_options(argc, argv, true); 1023 } 1024 1025 static int do_loadall(int argc, char **argv) 1026 { 1027 return load_with_options(argc, argv, false); 1028 } 1029 1030 static int do_help(int argc, char **argv) 1031 { 1032 if (json_output) { 1033 jsonw_null(json_wtr); 1034 return 0; 1035 } 1036 1037 fprintf(stderr, 1038 "Usage: %s %s { show | list } [PROG]\n" 1039 " %s %s dump xlated PROG [{ file FILE | opcodes | visual | linum }]\n" 1040 " %s %s dump jited PROG [{ file FILE | opcodes | linum }]\n" 1041 " %s %s pin PROG FILE\n" 1042 " %s %s { load | loadall } OBJ PATH \\\n" 1043 " [type TYPE] [dev NAME] \\\n" 1044 " [map { idx IDX | name NAME } MAP]\\\n" 1045 " [pinmaps MAP_DIR]\n" 1046 " %s %s attach PROG ATTACH_TYPE [MAP]\n" 1047 " %s %s detach PROG ATTACH_TYPE [MAP]\n" 1048 " %s %s tracelog\n" 1049 " %s %s help\n" 1050 "\n" 1051 " " HELP_SPEC_MAP "\n" 1052 " " HELP_SPEC_PROGRAM "\n" 1053 " TYPE := { socket | kprobe | kretprobe | classifier | action |\n" 1054 " tracepoint | raw_tracepoint | xdp | perf_event | cgroup/skb |\n" 1055 " cgroup/sock | cgroup/dev | lwt_in | lwt_out | lwt_xmit |\n" 1056 " lwt_seg6local | sockops | sk_skb | sk_msg | lirc_mode2 |\n" 1057 " sk_reuseport | flow_dissector |\n" 1058 " cgroup/bind4 | cgroup/bind6 | cgroup/post_bind4 |\n" 1059 " cgroup/post_bind6 | cgroup/connect4 | cgroup/connect6 |\n" 1060 " cgroup/sendmsg4 | cgroup/sendmsg6 }\n" 1061 " ATTACH_TYPE := { msg_verdict | stream_verdict | stream_parser |\n" 1062 " flow_dissector }\n" 1063 " " HELP_SPEC_OPTIONS "\n" 1064 "", 1065 bin_name, argv[-2], bin_name, argv[-2], bin_name, argv[-2], 1066 bin_name, argv[-2], bin_name, argv[-2], bin_name, argv[-2], 1067 bin_name, argv[-2], bin_name, argv[-2], bin_name, argv[-2]); 1068 1069 return 0; 1070 } 1071 1072 static const struct cmd cmds[] = { 1073 { "show", do_show }, 1074 { "list", do_show }, 1075 { "help", do_help }, 1076 { "dump", do_dump }, 1077 { "pin", do_pin }, 1078 { "load", do_load }, 1079 { "loadall", do_loadall }, 1080 { "attach", do_attach }, 1081 { "detach", do_detach }, 1082 { "tracelog", do_tracelog }, 1083 { 0 } 1084 }; 1085 1086 int do_prog(int argc, char **argv) 1087 { 1088 return cmd_select(cmds, argc, argv, do_help); 1089 } 1090