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 (info->btf_id) 253 jsonw_int_field(json_wtr, "btf_id", info->btf_id); 254 255 if (!hash_empty(prog_table.table)) { 256 struct pinned_obj *obj; 257 258 jsonw_name(json_wtr, "pinned"); 259 jsonw_start_array(json_wtr); 260 hash_for_each_possible(prog_table.table, obj, hash, info->id) { 261 if (obj->id == info->id) 262 jsonw_string(json_wtr, obj->path); 263 } 264 jsonw_end_array(json_wtr); 265 } 266 267 jsonw_end_object(json_wtr); 268 } 269 270 static void print_prog_plain(struct bpf_prog_info *info, int fd) 271 { 272 char *memlock; 273 274 printf("%u: ", info->id); 275 if (info->type < ARRAY_SIZE(prog_type_name)) 276 printf("%s ", prog_type_name[info->type]); 277 else 278 printf("type %u ", info->type); 279 280 if (*info->name) 281 printf("name %s ", info->name); 282 283 printf("tag "); 284 fprint_hex(stdout, info->tag, BPF_TAG_SIZE, ""); 285 print_dev_plain(info->ifindex, info->netns_dev, info->netns_ino); 286 printf("%s", info->gpl_compatible ? " gpl" : ""); 287 if (info->run_time_ns) 288 printf(" run_time_ns %lld run_cnt %lld", 289 info->run_time_ns, info->run_cnt); 290 printf("\n"); 291 292 if (info->load_time) { 293 char buf[32]; 294 295 print_boot_time(info->load_time, buf, sizeof(buf)); 296 297 /* Piggy back on load_time, since 0 uid is a valid one */ 298 printf("\tloaded_at %s uid %u\n", buf, info->created_by_uid); 299 } 300 301 printf("\txlated %uB", info->xlated_prog_len); 302 303 if (info->jited_prog_len) 304 printf(" jited %uB", info->jited_prog_len); 305 else 306 printf(" not jited"); 307 308 memlock = get_fdinfo(fd, "memlock"); 309 if (memlock) 310 printf(" memlock %sB", memlock); 311 free(memlock); 312 313 if (info->nr_map_ids) 314 show_prog_maps(fd, info->nr_map_ids); 315 316 if (!hash_empty(prog_table.table)) { 317 struct pinned_obj *obj; 318 319 hash_for_each_possible(prog_table.table, obj, hash, info->id) { 320 if (obj->id == info->id) 321 printf("\n\tpinned %s", obj->path); 322 } 323 } 324 325 if (info->btf_id) 326 printf("\n\tbtf_id %d", info->btf_id); 327 328 printf("\n"); 329 } 330 331 static int show_prog(int fd) 332 { 333 struct bpf_prog_info info = {}; 334 __u32 len = sizeof(info); 335 int err; 336 337 err = bpf_obj_get_info_by_fd(fd, &info, &len); 338 if (err) { 339 p_err("can't get prog info: %s", strerror(errno)); 340 return -1; 341 } 342 343 if (json_output) 344 print_prog_json(&info, fd); 345 else 346 print_prog_plain(&info, fd); 347 348 return 0; 349 } 350 351 static int do_show(int argc, char **argv) 352 { 353 __u32 id = 0; 354 int err; 355 int fd; 356 357 if (show_pinned) 358 build_pinned_obj_table(&prog_table, BPF_OBJ_PROG); 359 360 if (argc == 2) { 361 fd = prog_parse_fd(&argc, &argv); 362 if (fd < 0) 363 return -1; 364 365 err = show_prog(fd); 366 close(fd); 367 return err; 368 } 369 370 if (argc) 371 return BAD_ARG(); 372 373 if (json_output) 374 jsonw_start_array(json_wtr); 375 while (true) { 376 err = bpf_prog_get_next_id(id, &id); 377 if (err) { 378 if (errno == ENOENT) { 379 err = 0; 380 break; 381 } 382 p_err("can't get next program: %s%s", strerror(errno), 383 errno == EINVAL ? " -- kernel too old?" : ""); 384 err = -1; 385 break; 386 } 387 388 fd = bpf_prog_get_fd_by_id(id); 389 if (fd < 0) { 390 if (errno == ENOENT) 391 continue; 392 p_err("can't get prog by id (%u): %s", 393 id, strerror(errno)); 394 err = -1; 395 break; 396 } 397 398 err = show_prog(fd); 399 close(fd); 400 if (err) 401 break; 402 } 403 404 if (json_output) 405 jsonw_end_array(json_wtr); 406 407 return err; 408 } 409 410 static int do_dump(int argc, char **argv) 411 { 412 struct bpf_prog_info_linear *info_linear; 413 struct bpf_prog_linfo *prog_linfo = NULL; 414 enum {DUMP_JITED, DUMP_XLATED} mode; 415 const char *disasm_opt = NULL; 416 struct bpf_prog_info *info; 417 struct dump_data dd = {}; 418 void *func_info = NULL; 419 struct btf *btf = NULL; 420 char *filepath = NULL; 421 bool opcodes = false; 422 bool visual = false; 423 char func_sig[1024]; 424 unsigned char *buf; 425 bool linum = false; 426 __u32 member_len; 427 __u64 arrays; 428 ssize_t n; 429 int fd; 430 431 if (is_prefix(*argv, "jited")) { 432 if (disasm_init()) 433 return -1; 434 mode = DUMP_JITED; 435 } else if (is_prefix(*argv, "xlated")) { 436 mode = DUMP_XLATED; 437 } else { 438 p_err("expected 'xlated' or 'jited', got: %s", *argv); 439 return -1; 440 } 441 NEXT_ARG(); 442 443 if (argc < 2) 444 usage(); 445 446 fd = prog_parse_fd(&argc, &argv); 447 if (fd < 0) 448 return -1; 449 450 if (is_prefix(*argv, "file")) { 451 NEXT_ARG(); 452 if (!argc) { 453 p_err("expected file path"); 454 return -1; 455 } 456 457 filepath = *argv; 458 NEXT_ARG(); 459 } else if (is_prefix(*argv, "opcodes")) { 460 opcodes = true; 461 NEXT_ARG(); 462 } else if (is_prefix(*argv, "visual")) { 463 visual = true; 464 NEXT_ARG(); 465 } else if (is_prefix(*argv, "linum")) { 466 linum = true; 467 NEXT_ARG(); 468 } 469 470 if (argc) { 471 usage(); 472 return -1; 473 } 474 475 if (mode == DUMP_JITED) 476 arrays = 1UL << BPF_PROG_INFO_JITED_INSNS; 477 else 478 arrays = 1UL << BPF_PROG_INFO_XLATED_INSNS; 479 480 arrays |= 1UL << BPF_PROG_INFO_JITED_KSYMS; 481 arrays |= 1UL << BPF_PROG_INFO_JITED_FUNC_LENS; 482 arrays |= 1UL << BPF_PROG_INFO_FUNC_INFO; 483 arrays |= 1UL << BPF_PROG_INFO_LINE_INFO; 484 arrays |= 1UL << BPF_PROG_INFO_JITED_LINE_INFO; 485 486 info_linear = bpf_program__get_prog_info_linear(fd, arrays); 487 close(fd); 488 if (IS_ERR_OR_NULL(info_linear)) { 489 p_err("can't get prog info: %s", strerror(errno)); 490 return -1; 491 } 492 493 info = &info_linear->info; 494 if (mode == DUMP_JITED) { 495 if (info->jited_prog_len == 0) { 496 p_info("no instructions returned"); 497 goto err_free; 498 } 499 buf = (unsigned char *)(info->jited_prog_insns); 500 member_len = info->jited_prog_len; 501 } else { /* DUMP_XLATED */ 502 if (info->xlated_prog_len == 0) { 503 p_err("error retrieving insn dump: kernel.kptr_restrict set?"); 504 goto err_free; 505 } 506 buf = (unsigned char *)info->xlated_prog_insns; 507 member_len = info->xlated_prog_len; 508 } 509 510 if (info->btf_id && btf__get_from_id(info->btf_id, &btf)) { 511 p_err("failed to get btf"); 512 goto err_free; 513 } 514 515 func_info = (void *)info->func_info; 516 517 if (info->nr_line_info) { 518 prog_linfo = bpf_prog_linfo__new(info); 519 if (!prog_linfo) 520 p_info("error in processing bpf_line_info. continue without it."); 521 } 522 523 if (filepath) { 524 fd = open(filepath, O_WRONLY | O_CREAT | O_TRUNC, 0600); 525 if (fd < 0) { 526 p_err("can't open file %s: %s", filepath, 527 strerror(errno)); 528 goto err_free; 529 } 530 531 n = write(fd, buf, member_len); 532 close(fd); 533 if (n != member_len) { 534 p_err("error writing output file: %s", 535 n < 0 ? strerror(errno) : "short write"); 536 goto err_free; 537 } 538 539 if (json_output) 540 jsonw_null(json_wtr); 541 } else if (mode == DUMP_JITED) { 542 const char *name = NULL; 543 544 if (info->ifindex) { 545 name = ifindex_to_bfd_params(info->ifindex, 546 info->netns_dev, 547 info->netns_ino, 548 &disasm_opt); 549 if (!name) 550 goto err_free; 551 } 552 553 if (info->nr_jited_func_lens && info->jited_func_lens) { 554 struct kernel_sym *sym = NULL; 555 struct bpf_func_info *record; 556 char sym_name[SYM_MAX_NAME]; 557 unsigned char *img = buf; 558 __u64 *ksyms = NULL; 559 __u32 *lens; 560 __u32 i; 561 if (info->nr_jited_ksyms) { 562 kernel_syms_load(&dd); 563 ksyms = (__u64 *) info->jited_ksyms; 564 } 565 566 if (json_output) 567 jsonw_start_array(json_wtr); 568 569 lens = (__u32 *) info->jited_func_lens; 570 for (i = 0; i < info->nr_jited_func_lens; i++) { 571 if (ksyms) { 572 sym = kernel_syms_search(&dd, ksyms[i]); 573 if (sym) 574 sprintf(sym_name, "%s", sym->name); 575 else 576 sprintf(sym_name, "0x%016llx", ksyms[i]); 577 } else { 578 strcpy(sym_name, "unknown"); 579 } 580 581 if (func_info) { 582 record = func_info + i * info->func_info_rec_size; 583 btf_dumper_type_only(btf, record->type_id, 584 func_sig, 585 sizeof(func_sig)); 586 } 587 588 if (json_output) { 589 jsonw_start_object(json_wtr); 590 if (func_info && func_sig[0] != '\0') { 591 jsonw_name(json_wtr, "proto"); 592 jsonw_string(json_wtr, func_sig); 593 } 594 jsonw_name(json_wtr, "name"); 595 jsonw_string(json_wtr, sym_name); 596 jsonw_name(json_wtr, "insns"); 597 } else { 598 if (func_info && func_sig[0] != '\0') 599 printf("%s:\n", func_sig); 600 printf("%s:\n", sym_name); 601 } 602 603 disasm_print_insn(img, lens[i], opcodes, 604 name, disasm_opt, btf, 605 prog_linfo, ksyms[i], i, 606 linum); 607 608 img += lens[i]; 609 610 if (json_output) 611 jsonw_end_object(json_wtr); 612 else 613 printf("\n"); 614 } 615 616 if (json_output) 617 jsonw_end_array(json_wtr); 618 } else { 619 disasm_print_insn(buf, member_len, opcodes, name, 620 disasm_opt, btf, NULL, 0, 0, false); 621 } 622 } else if (visual) { 623 if (json_output) 624 jsonw_null(json_wtr); 625 else 626 dump_xlated_cfg(buf, member_len); 627 } else { 628 kernel_syms_load(&dd); 629 dd.nr_jited_ksyms = info->nr_jited_ksyms; 630 dd.jited_ksyms = (__u64 *) info->jited_ksyms; 631 dd.btf = btf; 632 dd.func_info = func_info; 633 dd.finfo_rec_size = info->func_info_rec_size; 634 dd.prog_linfo = prog_linfo; 635 636 if (json_output) 637 dump_xlated_json(&dd, buf, member_len, opcodes, 638 linum); 639 else 640 dump_xlated_plain(&dd, buf, member_len, opcodes, 641 linum); 642 kernel_syms_destroy(&dd); 643 } 644 645 free(info_linear); 646 return 0; 647 648 err_free: 649 free(info_linear); 650 return -1; 651 } 652 653 static int do_pin(int argc, char **argv) 654 { 655 int err; 656 657 err = do_pin_any(argc, argv, bpf_prog_get_fd_by_id); 658 if (!err && json_output) 659 jsonw_null(json_wtr); 660 return err; 661 } 662 663 struct map_replace { 664 int idx; 665 int fd; 666 char *name; 667 }; 668 669 static int map_replace_compar(const void *p1, const void *p2) 670 { 671 const struct map_replace *a = p1, *b = p2; 672 673 return a->idx - b->idx; 674 } 675 676 static int parse_attach_detach_args(int argc, char **argv, int *progfd, 677 enum bpf_attach_type *attach_type, 678 int *mapfd) 679 { 680 if (!REQ_ARGS(3)) 681 return -EINVAL; 682 683 *progfd = prog_parse_fd(&argc, &argv); 684 if (*progfd < 0) 685 return *progfd; 686 687 *attach_type = parse_attach_type(*argv); 688 if (*attach_type == __MAX_BPF_ATTACH_TYPE) { 689 p_err("invalid attach/detach type"); 690 return -EINVAL; 691 } 692 693 if (*attach_type == BPF_FLOW_DISSECTOR) { 694 *mapfd = -1; 695 return 0; 696 } 697 698 NEXT_ARG(); 699 if (!REQ_ARGS(2)) 700 return -EINVAL; 701 702 *mapfd = map_parse_fd(&argc, &argv); 703 if (*mapfd < 0) 704 return *mapfd; 705 706 return 0; 707 } 708 709 static int do_attach(int argc, char **argv) 710 { 711 enum bpf_attach_type attach_type; 712 int err, progfd; 713 int mapfd; 714 715 err = parse_attach_detach_args(argc, argv, 716 &progfd, &attach_type, &mapfd); 717 if (err) 718 return err; 719 720 err = bpf_prog_attach(progfd, mapfd, attach_type, 0); 721 if (err) { 722 p_err("failed prog attach to map"); 723 return -EINVAL; 724 } 725 726 if (json_output) 727 jsonw_null(json_wtr); 728 return 0; 729 } 730 731 static int do_detach(int argc, char **argv) 732 { 733 enum bpf_attach_type attach_type; 734 int err, progfd; 735 int mapfd; 736 737 err = parse_attach_detach_args(argc, argv, 738 &progfd, &attach_type, &mapfd); 739 if (err) 740 return err; 741 742 err = bpf_prog_detach2(progfd, mapfd, attach_type); 743 if (err) { 744 p_err("failed prog detach from map"); 745 return -EINVAL; 746 } 747 748 if (json_output) 749 jsonw_null(json_wtr); 750 return 0; 751 } 752 753 static int load_with_options(int argc, char **argv, bool first_prog_only) 754 { 755 enum bpf_attach_type expected_attach_type; 756 struct bpf_object_open_attr attr = { 757 .prog_type = BPF_PROG_TYPE_UNSPEC, 758 }; 759 struct map_replace *map_replace = NULL; 760 struct bpf_program *prog = NULL, *pos; 761 unsigned int old_map_fds = 0; 762 const char *pinmaps = NULL; 763 struct bpf_object *obj; 764 struct bpf_map *map; 765 const char *pinfile; 766 unsigned int i, j; 767 __u32 ifindex = 0; 768 int idx, err; 769 770 if (!REQ_ARGS(2)) 771 return -1; 772 attr.file = GET_ARG(); 773 pinfile = GET_ARG(); 774 775 while (argc) { 776 if (is_prefix(*argv, "type")) { 777 char *type; 778 779 NEXT_ARG(); 780 781 if (attr.prog_type != BPF_PROG_TYPE_UNSPEC) { 782 p_err("program type already specified"); 783 goto err_free_reuse_maps; 784 } 785 if (!REQ_ARGS(1)) 786 goto err_free_reuse_maps; 787 788 /* Put a '/' at the end of type to appease libbpf */ 789 type = malloc(strlen(*argv) + 2); 790 if (!type) { 791 p_err("mem alloc failed"); 792 goto err_free_reuse_maps; 793 } 794 *type = 0; 795 strcat(type, *argv); 796 strcat(type, "/"); 797 798 err = libbpf_prog_type_by_name(type, &attr.prog_type, 799 &expected_attach_type); 800 free(type); 801 if (err < 0) 802 goto err_free_reuse_maps; 803 804 NEXT_ARG(); 805 } else if (is_prefix(*argv, "map")) { 806 void *new_map_replace; 807 char *endptr, *name; 808 int fd; 809 810 NEXT_ARG(); 811 812 if (!REQ_ARGS(4)) 813 goto err_free_reuse_maps; 814 815 if (is_prefix(*argv, "idx")) { 816 NEXT_ARG(); 817 818 idx = strtoul(*argv, &endptr, 0); 819 if (*endptr) { 820 p_err("can't parse %s as IDX", *argv); 821 goto err_free_reuse_maps; 822 } 823 name = NULL; 824 } else if (is_prefix(*argv, "name")) { 825 NEXT_ARG(); 826 827 name = *argv; 828 idx = -1; 829 } else { 830 p_err("expected 'idx' or 'name', got: '%s'?", 831 *argv); 832 goto err_free_reuse_maps; 833 } 834 NEXT_ARG(); 835 836 fd = map_parse_fd(&argc, &argv); 837 if (fd < 0) 838 goto err_free_reuse_maps; 839 840 new_map_replace = reallocarray(map_replace, 841 old_map_fds + 1, 842 sizeof(*map_replace)); 843 if (!new_map_replace) { 844 p_err("mem alloc failed"); 845 goto err_free_reuse_maps; 846 } 847 map_replace = new_map_replace; 848 849 map_replace[old_map_fds].idx = idx; 850 map_replace[old_map_fds].name = name; 851 map_replace[old_map_fds].fd = fd; 852 old_map_fds++; 853 } else if (is_prefix(*argv, "dev")) { 854 NEXT_ARG(); 855 856 if (ifindex) { 857 p_err("offload device already specified"); 858 goto err_free_reuse_maps; 859 } 860 if (!REQ_ARGS(1)) 861 goto err_free_reuse_maps; 862 863 ifindex = if_nametoindex(*argv); 864 if (!ifindex) { 865 p_err("unrecognized netdevice '%s': %s", 866 *argv, strerror(errno)); 867 goto err_free_reuse_maps; 868 } 869 NEXT_ARG(); 870 } else if (is_prefix(*argv, "pinmaps")) { 871 NEXT_ARG(); 872 873 if (!REQ_ARGS(1)) 874 goto err_free_reuse_maps; 875 876 pinmaps = GET_ARG(); 877 } else { 878 p_err("expected no more arguments, 'type', 'map' or 'dev', got: '%s'?", 879 *argv); 880 goto err_free_reuse_maps; 881 } 882 } 883 884 set_max_rlimit(); 885 886 obj = __bpf_object__open_xattr(&attr, bpf_flags); 887 if (IS_ERR_OR_NULL(obj)) { 888 p_err("failed to open object file"); 889 goto err_free_reuse_maps; 890 } 891 892 bpf_object__for_each_program(pos, obj) { 893 enum bpf_prog_type prog_type = attr.prog_type; 894 895 if (attr.prog_type == BPF_PROG_TYPE_UNSPEC) { 896 const char *sec_name = bpf_program__title(pos, false); 897 898 err = libbpf_prog_type_by_name(sec_name, &prog_type, 899 &expected_attach_type); 900 if (err < 0) 901 goto err_close_obj; 902 } 903 904 bpf_program__set_ifindex(pos, ifindex); 905 bpf_program__set_type(pos, prog_type); 906 bpf_program__set_expected_attach_type(pos, expected_attach_type); 907 } 908 909 qsort(map_replace, old_map_fds, sizeof(*map_replace), 910 map_replace_compar); 911 912 /* After the sort maps by name will be first on the list, because they 913 * have idx == -1. Resolve them. 914 */ 915 j = 0; 916 while (j < old_map_fds && map_replace[j].name) { 917 i = 0; 918 bpf_object__for_each_map(map, obj) { 919 if (!strcmp(bpf_map__name(map), map_replace[j].name)) { 920 map_replace[j].idx = i; 921 break; 922 } 923 i++; 924 } 925 if (map_replace[j].idx == -1) { 926 p_err("unable to find map '%s'", map_replace[j].name); 927 goto err_close_obj; 928 } 929 j++; 930 } 931 /* Resort if any names were resolved */ 932 if (j) 933 qsort(map_replace, old_map_fds, sizeof(*map_replace), 934 map_replace_compar); 935 936 /* Set ifindex and name reuse */ 937 j = 0; 938 idx = 0; 939 bpf_object__for_each_map(map, obj) { 940 if (!bpf_map__is_offload_neutral(map)) 941 bpf_map__set_ifindex(map, ifindex); 942 943 if (j < old_map_fds && idx == map_replace[j].idx) { 944 err = bpf_map__reuse_fd(map, map_replace[j++].fd); 945 if (err) { 946 p_err("unable to set up map reuse: %d", err); 947 goto err_close_obj; 948 } 949 950 /* Next reuse wants to apply to the same map */ 951 if (j < old_map_fds && map_replace[j].idx == idx) { 952 p_err("replacement for map idx %d specified more than once", 953 idx); 954 goto err_close_obj; 955 } 956 } 957 958 idx++; 959 } 960 if (j < old_map_fds) { 961 p_err("map idx '%d' not used", map_replace[j].idx); 962 goto err_close_obj; 963 } 964 965 err = bpf_object__load(obj); 966 if (err) { 967 p_err("failed to load object file"); 968 goto err_close_obj; 969 } 970 971 err = mount_bpffs_for_pin(pinfile); 972 if (err) 973 goto err_close_obj; 974 975 if (first_prog_only) { 976 prog = bpf_program__next(NULL, obj); 977 if (!prog) { 978 p_err("object file doesn't contain any bpf program"); 979 goto err_close_obj; 980 } 981 982 err = bpf_obj_pin(bpf_program__fd(prog), pinfile); 983 if (err) { 984 p_err("failed to pin program %s", 985 bpf_program__title(prog, false)); 986 goto err_close_obj; 987 } 988 } else { 989 err = bpf_object__pin_programs(obj, pinfile); 990 if (err) { 991 p_err("failed to pin all programs"); 992 goto err_close_obj; 993 } 994 } 995 996 if (pinmaps) { 997 err = bpf_object__pin_maps(obj, pinmaps); 998 if (err) { 999 p_err("failed to pin all maps"); 1000 goto err_unpin; 1001 } 1002 } 1003 1004 if (json_output) 1005 jsonw_null(json_wtr); 1006 1007 bpf_object__close(obj); 1008 for (i = 0; i < old_map_fds; i++) 1009 close(map_replace[i].fd); 1010 free(map_replace); 1011 1012 return 0; 1013 1014 err_unpin: 1015 if (first_prog_only) 1016 unlink(pinfile); 1017 else 1018 bpf_object__unpin_programs(obj, pinfile); 1019 err_close_obj: 1020 bpf_object__close(obj); 1021 err_free_reuse_maps: 1022 for (i = 0; i < old_map_fds; i++) 1023 close(map_replace[i].fd); 1024 free(map_replace); 1025 return -1; 1026 } 1027 1028 static int do_load(int argc, char **argv) 1029 { 1030 return load_with_options(argc, argv, true); 1031 } 1032 1033 static int do_loadall(int argc, char **argv) 1034 { 1035 return load_with_options(argc, argv, false); 1036 } 1037 1038 static int do_help(int argc, char **argv) 1039 { 1040 if (json_output) { 1041 jsonw_null(json_wtr); 1042 return 0; 1043 } 1044 1045 fprintf(stderr, 1046 "Usage: %s %s { show | list } [PROG]\n" 1047 " %s %s dump xlated PROG [{ file FILE | opcodes | visual | linum }]\n" 1048 " %s %s dump jited PROG [{ file FILE | opcodes | linum }]\n" 1049 " %s %s pin PROG FILE\n" 1050 " %s %s { load | loadall } OBJ PATH \\\n" 1051 " [type TYPE] [dev NAME] \\\n" 1052 " [map { idx IDX | name NAME } MAP]\\\n" 1053 " [pinmaps MAP_DIR]\n" 1054 " %s %s attach PROG ATTACH_TYPE [MAP]\n" 1055 " %s %s detach PROG ATTACH_TYPE [MAP]\n" 1056 " %s %s tracelog\n" 1057 " %s %s help\n" 1058 "\n" 1059 " " HELP_SPEC_MAP "\n" 1060 " " HELP_SPEC_PROGRAM "\n" 1061 " TYPE := { socket | kprobe | kretprobe | classifier | action |\n" 1062 " tracepoint | raw_tracepoint | xdp | perf_event | cgroup/skb |\n" 1063 " cgroup/sock | cgroup/dev | lwt_in | lwt_out | lwt_xmit |\n" 1064 " lwt_seg6local | sockops | sk_skb | sk_msg | lirc_mode2 |\n" 1065 " sk_reuseport | flow_dissector | cgroup/sysctl |\n" 1066 " cgroup/bind4 | cgroup/bind6 | cgroup/post_bind4 |\n" 1067 " cgroup/post_bind6 | cgroup/connect4 | cgroup/connect6 |\n" 1068 " cgroup/sendmsg4 | cgroup/sendmsg6 | cgroup/recvmsg4 |\n" 1069 " cgroup/recvmsg6 }\n" 1070 " ATTACH_TYPE := { msg_verdict | stream_verdict | stream_parser |\n" 1071 " flow_dissector }\n" 1072 " " HELP_SPEC_OPTIONS "\n" 1073 "", 1074 bin_name, argv[-2], bin_name, argv[-2], bin_name, argv[-2], 1075 bin_name, argv[-2], bin_name, argv[-2], bin_name, argv[-2], 1076 bin_name, argv[-2], bin_name, argv[-2], bin_name, argv[-2]); 1077 1078 return 0; 1079 } 1080 1081 static const struct cmd cmds[] = { 1082 { "show", do_show }, 1083 { "list", do_show }, 1084 { "help", do_help }, 1085 { "dump", do_dump }, 1086 { "pin", do_pin }, 1087 { "load", do_load }, 1088 { "loadall", do_loadall }, 1089 { "attach", do_attach }, 1090 { "detach", do_detach }, 1091 { "tracelog", do_tracelog }, 1092 { 0 } 1093 }; 1094 1095 int do_prog(int argc, char **argv) 1096 { 1097 return cmd_select(cmds, argc, argv, do_help); 1098 } 1099
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.