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 #include <linux/sizes.h> 19 20 #include <bpf.h> 21 #include <btf.h> 22 #include <libbpf.h> 23 24 #include "cfg.h" 25 #include "main.h" 26 #include "xlated_dumper.h" 27 28 static const char * const attach_type_strings[] = { 29 [BPF_SK_SKB_STREAM_PARSER] = "stream_parser", 30 [BPF_SK_SKB_STREAM_VERDICT] = "stream_verdict", 31 [BPF_SK_MSG_VERDICT] = "msg_verdict", 32 [BPF_FLOW_DISSECTOR] = "flow_dissector", 33 [__MAX_BPF_ATTACH_TYPE] = NULL, 34 }; 35 36 static enum bpf_attach_type parse_attach_type(const char *str) 37 { 38 enum bpf_attach_type type; 39 40 for (type = 0; type < __MAX_BPF_ATTACH_TYPE; type++) { 41 if (attach_type_strings[type] && 42 is_prefix(str, attach_type_strings[type])) 43 return type; 44 } 45 46 return __MAX_BPF_ATTACH_TYPE; 47 } 48 49 static void print_boot_time(__u64 nsecs, char *buf, unsigned int size) 50 { 51 struct timespec real_time_ts, boot_time_ts; 52 time_t wallclock_secs; 53 struct tm load_tm; 54 55 buf[--size] = '\0'; 56 57 if (clock_gettime(CLOCK_REALTIME, &real_time_ts) || 58 clock_gettime(CLOCK_BOOTTIME, &boot_time_ts)) { 59 perror("Can't read clocks"); 60 snprintf(buf, size, "%llu", nsecs / 1000000000); 61 return; 62 } 63 64 wallclock_secs = (real_time_ts.tv_sec - boot_time_ts.tv_sec) + 65 (real_time_ts.tv_nsec - boot_time_ts.tv_nsec + nsecs) / 66 1000000000; 67 68 69 if (!localtime_r(&wallclock_secs, &load_tm)) { 70 snprintf(buf, size, "%llu", nsecs / 1000000000); 71 return; 72 } 73 74 if (json_output) 75 strftime(buf, size, "%s", &load_tm); 76 else 77 strftime(buf, size, "%FT%T%z", &load_tm); 78 } 79 80 static int prog_fd_by_tag(unsigned char *tag) 81 { 82 unsigned int id = 0; 83 int err; 84 int fd; 85 86 while (true) { 87 struct bpf_prog_info info = {}; 88 __u32 len = sizeof(info); 89 90 err = bpf_prog_get_next_id(id, &id); 91 if (err) { 92 p_err("%s", strerror(errno)); 93 return -1; 94 } 95 96 fd = bpf_prog_get_fd_by_id(id); 97 if (fd < 0) { 98 p_err("can't get prog by id (%u): %s", 99 id, strerror(errno)); 100 return -1; 101 } 102 103 err = bpf_obj_get_info_by_fd(fd, &info, &len); 104 if (err) { 105 p_err("can't get prog info (%u): %s", 106 id, strerror(errno)); 107 close(fd); 108 return -1; 109 } 110 111 if (!memcmp(tag, info.tag, BPF_TAG_SIZE)) 112 return fd; 113 114 close(fd); 115 } 116 } 117 118 int prog_parse_fd(int *argc, char ***argv) 119 { 120 int fd; 121 122 if (is_prefix(**argv, "id")) { 123 unsigned int id; 124 char *endptr; 125 126 NEXT_ARGP(); 127 128 id = strtoul(**argv, &endptr, 0); 129 if (*endptr) { 130 p_err("can't parse %s as ID", **argv); 131 return -1; 132 } 133 NEXT_ARGP(); 134 135 fd = bpf_prog_get_fd_by_id(id); 136 if (fd < 0) 137 p_err("get by id (%u): %s", id, strerror(errno)); 138 return fd; 139 } else if (is_prefix(**argv, "tag")) { 140 unsigned char tag[BPF_TAG_SIZE]; 141 142 NEXT_ARGP(); 143 144 if (sscanf(**argv, BPF_TAG_FMT, tag, tag + 1, tag + 2, 145 tag + 3, tag + 4, tag + 5, tag + 6, tag + 7) 146 != BPF_TAG_SIZE) { 147 p_err("can't parse tag"); 148 return -1; 149 } 150 NEXT_ARGP(); 151 152 return prog_fd_by_tag(tag); 153 } else if (is_prefix(**argv, "pinned")) { 154 char *path; 155 156 NEXT_ARGP(); 157 158 path = **argv; 159 NEXT_ARGP(); 160 161 return open_obj_pinned_any(path, BPF_OBJ_PROG); 162 } 163 164 p_err("expected 'id', 'tag' or 'pinned', got: '%s'?", **argv); 165 return -1; 166 } 167 168 static void show_prog_maps(int fd, u32 num_maps) 169 { 170 struct bpf_prog_info info = {}; 171 __u32 len = sizeof(info); 172 __u32 map_ids[num_maps]; 173 unsigned int i; 174 int err; 175 176 info.nr_map_ids = num_maps; 177 info.map_ids = ptr_to_u64(map_ids); 178 179 err = bpf_obj_get_info_by_fd(fd, &info, &len); 180 if (err || !info.nr_map_ids) 181 return; 182 183 if (json_output) { 184 jsonw_name(json_wtr, "map_ids"); 185 jsonw_start_array(json_wtr); 186 for (i = 0; i < info.nr_map_ids; i++) 187 jsonw_uint(json_wtr, map_ids[i]); 188 jsonw_end_array(json_wtr); 189 } else { 190 printf(" map_ids "); 191 for (i = 0; i < info.nr_map_ids; i++) 192 printf("%u%s", map_ids[i], 193 i == info.nr_map_ids - 1 ? "" : ","); 194 } 195 } 196 197 static void print_prog_json(struct bpf_prog_info *info, int fd) 198 { 199 char *memlock; 200 201 jsonw_start_object(json_wtr); 202 jsonw_uint_field(json_wtr, "id", info->id); 203 if (info->type < ARRAY_SIZE(prog_type_name)) 204 jsonw_string_field(json_wtr, "type", 205 prog_type_name[info->type]); 206 else 207 jsonw_uint_field(json_wtr, "type", info->type); 208 209 if (*info->name) 210 jsonw_string_field(json_wtr, "name", info->name); 211 212 jsonw_name(json_wtr, "tag"); 213 jsonw_printf(json_wtr, "\"" BPF_TAG_FMT "\"", 214 info->tag[0], info->tag[1], info->tag[2], info->tag[3], 215 info->tag[4], info->tag[5], info->tag[6], info->tag[7]); 216 217 jsonw_bool_field(json_wtr, "gpl_compatible", info->gpl_compatible); 218 if (info->run_time_ns) { 219 jsonw_uint_field(json_wtr, "run_time_ns", info->run_time_ns); 220 jsonw_uint_field(json_wtr, "run_cnt", info->run_cnt); 221 } 222 223 print_dev_json(info->ifindex, info->netns_dev, info->netns_ino); 224 225 if (info->load_time) { 226 char buf[32]; 227 228 print_boot_time(info->load_time, buf, sizeof(buf)); 229 230 /* Piggy back on load_time, since 0 uid is a valid one */ 231 jsonw_name(json_wtr, "loaded_at"); 232 jsonw_printf(json_wtr, "%s", buf); 233 jsonw_uint_field(json_wtr, "uid", info->created_by_uid); 234 } 235 236 jsonw_uint_field(json_wtr, "bytes_xlated", info->xlated_prog_len); 237 238 if (info->jited_prog_len) { 239 jsonw_bool_field(json_wtr, "jited", true); 240 jsonw_uint_field(json_wtr, "bytes_jited", info->jited_prog_len); 241 } else { 242 jsonw_bool_field(json_wtr, "jited", false); 243 } 244 245 memlock = get_fdinfo(fd, "memlock"); 246 if (memlock) 247 jsonw_int_field(json_wtr, "bytes_memlock", atoi(memlock)); 248 free(memlock); 249 250 if (info->nr_map_ids) 251 show_prog_maps(fd, info->nr_map_ids); 252 253 if (info->btf_id) 254 jsonw_int_field(json_wtr, "btf_id", info->btf_id); 255 256 if (!hash_empty(prog_table.table)) { 257 struct pinned_obj *obj; 258 259 jsonw_name(json_wtr, "pinned"); 260 jsonw_start_array(json_wtr); 261 hash_for_each_possible(prog_table.table, obj, hash, info->id) { 262 if (obj->id == info->id) 263 jsonw_string(json_wtr, obj->path); 264 } 265 jsonw_end_array(json_wtr); 266 } 267 268 jsonw_end_object(json_wtr); 269 } 270 271 static void print_prog_plain(struct bpf_prog_info *info, int fd) 272 { 273 char *memlock; 274 275 printf("%u: ", info->id); 276 if (info->type < ARRAY_SIZE(prog_type_name)) 277 printf("%s ", prog_type_name[info->type]); 278 else 279 printf("type %u ", info->type); 280 281 if (*info->name) 282 printf("name %s ", info->name); 283 284 printf("tag "); 285 fprint_hex(stdout, info->tag, BPF_TAG_SIZE, ""); 286 print_dev_plain(info->ifindex, info->netns_dev, info->netns_ino); 287 printf("%s", info->gpl_compatible ? " gpl" : ""); 288 if (info->run_time_ns) 289 printf(" run_time_ns %lld run_cnt %lld", 290 info->run_time_ns, info->run_cnt); 291 printf("\n"); 292 293 if (info->load_time) { 294 char buf[32]; 295 296 print_boot_time(info->load_time, buf, sizeof(buf)); 297 298 /* Piggy back on load_time, since 0 uid is a valid one */ 299 printf("\tloaded_at %s uid %u\n", buf, info->created_by_uid); 300 } 301 302 printf("\txlated %uB", info->xlated_prog_len); 303 304 if (info->jited_prog_len) 305 printf(" jited %uB", info->jited_prog_len); 306 else 307 printf(" not jited"); 308 309 memlock = get_fdinfo(fd, "memlock"); 310 if (memlock) 311 printf(" memlock %sB", memlock); 312 free(memlock); 313 314 if (info->nr_map_ids) 315 show_prog_maps(fd, info->nr_map_ids); 316 317 if (!hash_empty(prog_table.table)) { 318 struct pinned_obj *obj; 319 320 hash_for_each_possible(prog_table.table, obj, hash, info->id) { 321 if (obj->id == info->id) 322 printf("\n\tpinned %s", obj->path); 323 } 324 } 325 326 if (info->btf_id) 327 printf("\n\tbtf_id %d", info->btf_id); 328 329 printf("\n"); 330 } 331 332 static int show_prog(int fd) 333 { 334 struct bpf_prog_info info = {}; 335 __u32 len = sizeof(info); 336 int err; 337 338 err = bpf_obj_get_info_by_fd(fd, &info, &len); 339 if (err) { 340 p_err("can't get prog info: %s", strerror(errno)); 341 return -1; 342 } 343 344 if (json_output) 345 print_prog_json(&info, fd); 346 else 347 print_prog_plain(&info, fd); 348 349 return 0; 350 } 351 352 static int do_show(int argc, char **argv) 353 { 354 __u32 id = 0; 355 int err; 356 int fd; 357 358 if (show_pinned) 359 build_pinned_obj_table(&prog_table, BPF_OBJ_PROG); 360 361 if (argc == 2) { 362 fd = prog_parse_fd(&argc, &argv); 363 if (fd < 0) 364 return -1; 365 366 err = show_prog(fd); 367 close(fd); 368 return err; 369 } 370 371 if (argc) 372 return BAD_ARG(); 373 374 if (json_output) 375 jsonw_start_array(json_wtr); 376 while (true) { 377 err = bpf_prog_get_next_id(id, &id); 378 if (err) { 379 if (errno == ENOENT) { 380 err = 0; 381 break; 382 } 383 p_err("can't get next program: %s%s", strerror(errno), 384 errno == EINVAL ? " -- kernel too old?" : ""); 385 err = -1; 386 break; 387 } 388 389 fd = bpf_prog_get_fd_by_id(id); 390 if (fd < 0) { 391 if (errno == ENOENT) 392 continue; 393 p_err("can't get prog by id (%u): %s", 394 id, strerror(errno)); 395 err = -1; 396 break; 397 } 398 399 err = show_prog(fd); 400 close(fd); 401 if (err) 402 break; 403 } 404 405 if (json_output) 406 jsonw_end_array(json_wtr); 407 408 return err; 409 } 410 411 static int do_dump(int argc, char **argv) 412 { 413 struct bpf_prog_info_linear *info_linear; 414 struct bpf_prog_linfo *prog_linfo = NULL; 415 enum {DUMP_JITED, DUMP_XLATED} mode; 416 const char *disasm_opt = NULL; 417 struct bpf_prog_info *info; 418 struct dump_data dd = {}; 419 void *func_info = NULL; 420 struct btf *btf = NULL; 421 char *filepath = NULL; 422 bool opcodes = false; 423 bool visual = false; 424 char func_sig[1024]; 425 unsigned char *buf; 426 bool linum = false; 427 __u32 member_len; 428 __u64 arrays; 429 ssize_t n; 430 int fd; 431 432 if (is_prefix(*argv, "jited")) { 433 if (disasm_init()) 434 return -1; 435 mode = DUMP_JITED; 436 } else if (is_prefix(*argv, "xlated")) { 437 mode = DUMP_XLATED; 438 } else { 439 p_err("expected 'xlated' or 'jited', got: %s", *argv); 440 return -1; 441 } 442 NEXT_ARG(); 443 444 if (argc < 2) 445 usage(); 446 447 fd = prog_parse_fd(&argc, &argv); 448 if (fd < 0) 449 return -1; 450 451 if (is_prefix(*argv, "file")) { 452 NEXT_ARG(); 453 if (!argc) { 454 p_err("expected file path"); 455 return -1; 456 } 457 458 filepath = *argv; 459 NEXT_ARG(); 460 } else if (is_prefix(*argv, "opcodes")) { 461 opcodes = true; 462 NEXT_ARG(); 463 } else if (is_prefix(*argv, "visual")) { 464 visual = true; 465 NEXT_ARG(); 466 } else if (is_prefix(*argv, "linum")) { 467 linum = true; 468 NEXT_ARG(); 469 } 470 471 if (argc) { 472 usage(); 473 return -1; 474 } 475 476 if (mode == DUMP_JITED) 477 arrays = 1UL << BPF_PROG_INFO_JITED_INSNS; 478 else 479 arrays = 1UL << BPF_PROG_INFO_XLATED_INSNS; 480 481 arrays |= 1UL << BPF_PROG_INFO_JITED_KSYMS; 482 arrays |= 1UL << BPF_PROG_INFO_JITED_FUNC_LENS; 483 arrays |= 1UL << BPF_PROG_INFO_FUNC_INFO; 484 arrays |= 1UL << BPF_PROG_INFO_LINE_INFO; 485 arrays |= 1UL << BPF_PROG_INFO_JITED_LINE_INFO; 486 487 info_linear = bpf_program__get_prog_info_linear(fd, arrays); 488 close(fd); 489 if (IS_ERR_OR_NULL(info_linear)) { 490 p_err("can't get prog info: %s", strerror(errno)); 491 return -1; 492 } 493 494 info = &info_linear->info; 495 if (mode == DUMP_JITED) { 496 if (info->jited_prog_len == 0) { 497 p_info("no instructions returned"); 498 goto err_free; 499 } 500 buf = (unsigned char *)(info->jited_prog_insns); 501 member_len = info->jited_prog_len; 502 } else { /* DUMP_XLATED */ 503 if (info->xlated_prog_len == 0) { 504 p_err("error retrieving insn dump: kernel.kptr_restrict set?"); 505 goto err_free; 506 } 507 buf = (unsigned char *)info->xlated_prog_insns; 508 member_len = info->xlated_prog_len; 509 } 510 511 if (info->btf_id && btf__get_from_id(info->btf_id, &btf)) { 512 p_err("failed to get btf"); 513 goto err_free; 514 } 515 516 func_info = (void *)info->func_info; 517 518 if (info->nr_line_info) { 519 prog_linfo = bpf_prog_linfo__new(info); 520 if (!prog_linfo) 521 p_info("error in processing bpf_line_info. continue without it."); 522 } 523 524 if (filepath) { 525 fd = open(filepath, O_WRONLY | O_CREAT | O_TRUNC, 0600); 526 if (fd < 0) { 527 p_err("can't open file %s: %s", filepath, 528 strerror(errno)); 529 goto err_free; 530 } 531 532 n = write(fd, buf, member_len); 533 close(fd); 534 if (n != member_len) { 535 p_err("error writing output file: %s", 536 n < 0 ? strerror(errno) : "short write"); 537 goto err_free; 538 } 539 540 if (json_output) 541 jsonw_null(json_wtr); 542 } else if (mode == DUMP_JITED) { 543 const char *name = NULL; 544 545 if (info->ifindex) { 546 name = ifindex_to_bfd_params(info->ifindex, 547 info->netns_dev, 548 info->netns_ino, 549 &disasm_opt); 550 if (!name) 551 goto err_free; 552 } 553 554 if (info->nr_jited_func_lens && info->jited_func_lens) { 555 struct kernel_sym *sym = NULL; 556 struct bpf_func_info *record; 557 char sym_name[SYM_MAX_NAME]; 558 unsigned char *img = buf; 559 __u64 *ksyms = NULL; 560 __u32 *lens; 561 __u32 i; 562 if (info->nr_jited_ksyms) { 563 kernel_syms_load(&dd); 564 ksyms = (__u64 *) info->jited_ksyms; 565 } 566 567 if (json_output) 568 jsonw_start_array(json_wtr); 569 570 lens = (__u32 *) info->jited_func_lens; 571 for (i = 0; i < info->nr_jited_func_lens; i++) { 572 if (ksyms) { 573 sym = kernel_syms_search(&dd, ksyms[i]); 574 if (sym) 575 sprintf(sym_name, "%s", sym->name); 576 else 577 sprintf(sym_name, "0x%016llx", ksyms[i]); 578 } else { 579 strcpy(sym_name, "unknown"); 580 } 581 582 if (func_info) { 583 record = func_info + i * info->func_info_rec_size; 584 btf_dumper_type_only(btf, record->type_id, 585 func_sig, 586 sizeof(func_sig)); 587 } 588 589 if (json_output) { 590 jsonw_start_object(json_wtr); 591 if (func_info && func_sig[0] != '\0') { 592 jsonw_name(json_wtr, "proto"); 593 jsonw_string(json_wtr, func_sig); 594 } 595 jsonw_name(json_wtr, "name"); 596 jsonw_string(json_wtr, sym_name); 597 jsonw_name(json_wtr, "insns"); 598 } else { 599 if (func_info && func_sig[0] != '\0') 600 printf("%s:\n", func_sig); 601 printf("%s:\n", sym_name); 602 } 603 604 disasm_print_insn(img, lens[i], opcodes, 605 name, disasm_opt, btf, 606 prog_linfo, ksyms[i], i, 607 linum); 608 609 img += lens[i]; 610 611 if (json_output) 612 jsonw_end_object(json_wtr); 613 else 614 printf("\n"); 615 } 616 617 if (json_output) 618 jsonw_end_array(json_wtr); 619 } else { 620 disasm_print_insn(buf, member_len, opcodes, name, 621 disasm_opt, btf, NULL, 0, 0, false); 622 } 623 } else if (visual) { 624 if (json_output) 625 jsonw_null(json_wtr); 626 else 627 dump_xlated_cfg(buf, member_len); 628 } else { 629 kernel_syms_load(&dd); 630 dd.nr_jited_ksyms = info->nr_jited_ksyms; 631 dd.jited_ksyms = (__u64 *) info->jited_ksyms; 632 dd.btf = btf; 633 dd.func_info = func_info; 634 dd.finfo_rec_size = info->func_info_rec_size; 635 dd.prog_linfo = prog_linfo; 636 637 if (json_output) 638 dump_xlated_json(&dd, buf, member_len, opcodes, 639 linum); 640 else 641 dump_xlated_plain(&dd, buf, member_len, opcodes, 642 linum); 643 kernel_syms_destroy(&dd); 644 } 645 646 free(info_linear); 647 return 0; 648 649 err_free: 650 free(info_linear); 651 return -1; 652 } 653 654 static int do_pin(int argc, char **argv) 655 { 656 int err; 657 658 err = do_pin_any(argc, argv, bpf_prog_get_fd_by_id); 659 if (!err && json_output) 660 jsonw_null(json_wtr); 661 return err; 662 } 663 664 struct map_replace { 665 int idx; 666 int fd; 667 char *name; 668 }; 669 670 static int map_replace_compar(const void *p1, const void *p2) 671 { 672 const struct map_replace *a = p1, *b = p2; 673 674 return a->idx - b->idx; 675 } 676 677 static int parse_attach_detach_args(int argc, char **argv, int *progfd, 678 enum bpf_attach_type *attach_type, 679 int *mapfd) 680 { 681 if (!REQ_ARGS(3)) 682 return -EINVAL; 683 684 *progfd = prog_parse_fd(&argc, &argv); 685 if (*progfd < 0) 686 return *progfd; 687 688 *attach_type = parse_attach_type(*argv); 689 if (*attach_type == __MAX_BPF_ATTACH_TYPE) { 690 p_err("invalid attach/detach type"); 691 return -EINVAL; 692 } 693 694 if (*attach_type == BPF_FLOW_DISSECTOR) { 695 *mapfd = -1; 696 return 0; 697 } 698 699 NEXT_ARG(); 700 if (!REQ_ARGS(2)) 701 return -EINVAL; 702 703 *mapfd = map_parse_fd(&argc, &argv); 704 if (*mapfd < 0) 705 return *mapfd; 706 707 return 0; 708 } 709 710 static int do_attach(int argc, char **argv) 711 { 712 enum bpf_attach_type attach_type; 713 int err, progfd; 714 int mapfd; 715 716 err = parse_attach_detach_args(argc, argv, 717 &progfd, &attach_type, &mapfd); 718 if (err) 719 return err; 720 721 err = bpf_prog_attach(progfd, mapfd, attach_type, 0); 722 if (err) { 723 p_err("failed prog attach to map"); 724 return -EINVAL; 725 } 726 727 if (json_output) 728 jsonw_null(json_wtr); 729 return 0; 730 } 731 732 static int do_detach(int argc, char **argv) 733 { 734 enum bpf_attach_type attach_type; 735 int err, progfd; 736 int mapfd; 737 738 err = parse_attach_detach_args(argc, argv, 739 &progfd, &attach_type, &mapfd); 740 if (err) 741 return err; 742 743 err = bpf_prog_detach2(progfd, mapfd, attach_type); 744 if (err) { 745 p_err("failed prog detach from map"); 746 return -EINVAL; 747 } 748 749 if (json_output) 750 jsonw_null(json_wtr); 751 return 0; 752 } 753 754 static int check_single_stdin(char *file_data_in, char *file_ctx_in) 755 { 756 if (file_data_in && file_ctx_in && 757 !strcmp(file_data_in, "-") && !strcmp(file_ctx_in, "-")) { 758 p_err("cannot use standard input for both data_in and ctx_in"); 759 return -1; 760 } 761 762 return 0; 763 } 764 765 static int get_run_data(const char *fname, void **data_ptr, unsigned int *size) 766 { 767 size_t block_size = 256; 768 size_t buf_size = block_size; 769 size_t nb_read = 0; 770 void *tmp; 771 FILE *f; 772 773 if (!fname) { 774 *data_ptr = NULL; 775 *size = 0; 776 return 0; 777 } 778 779 if (!strcmp(fname, "-")) 780 f = stdin; 781 else 782 f = fopen(fname, "r"); 783 if (!f) { 784 p_err("failed to open %s: %s", fname, strerror(errno)); 785 return -1; 786 } 787 788 *data_ptr = malloc(block_size); 789 if (!*data_ptr) { 790 p_err("failed to allocate memory for data_in/ctx_in: %s", 791 strerror(errno)); 792 goto err_fclose; 793 } 794 795 while ((nb_read += fread(*data_ptr + nb_read, 1, block_size, f))) { 796 if (feof(f)) 797 break; 798 if (ferror(f)) { 799 p_err("failed to read data_in/ctx_in from %s: %s", 800 fname, strerror(errno)); 801 goto err_free; 802 } 803 if (nb_read > buf_size - block_size) { 804 if (buf_size == UINT32_MAX) { 805 p_err("data_in/ctx_in is too long (max: %d)", 806 UINT32_MAX); 807 goto err_free; 808 } 809 /* No space for fread()-ing next chunk; realloc() */ 810 buf_size *= 2; 811 tmp = realloc(*data_ptr, buf_size); 812 if (!tmp) { 813 p_err("failed to reallocate data_in/ctx_in: %s", 814 strerror(errno)); 815 goto err_free; 816 } 817 *data_ptr = tmp; 818 } 819 } 820 if (f != stdin) 821 fclose(f); 822 823 *size = nb_read; 824 return 0; 825 826 err_free: 827 free(*data_ptr); 828 *data_ptr = NULL; 829 err_fclose: 830 if (f != stdin) 831 fclose(f); 832 return -1; 833 } 834 835 static void hex_print(void *data, unsigned int size, FILE *f) 836 { 837 size_t i, j; 838 char c; 839 840 for (i = 0; i < size; i += 16) { 841 /* Row offset */ 842 fprintf(f, "%07zx\t", i); 843 844 /* Hexadecimal values */ 845 for (j = i; j < i + 16 && j < size; j++) 846 fprintf(f, "%02x%s", *(uint8_t *)(data + j), 847 j % 2 ? " " : ""); 848 for (; j < i + 16; j++) 849 fprintf(f, " %s", j % 2 ? " " : ""); 850 851 /* ASCII values (if relevant), '.' otherwise */ 852 fprintf(f, "| "); 853 for (j = i; j < i + 16 && j < size; j++) { 854 c = *(char *)(data + j); 855 if (c < ' ' || c > '~') 856 c = '.'; 857 fprintf(f, "%c%s", c, j == i + 7 ? " " : ""); 858 } 859 860 fprintf(f, "\n"); 861 } 862 } 863 864 static int 865 print_run_output(void *data, unsigned int size, const char *fname, 866 const char *json_key) 867 { 868 size_t nb_written; 869 FILE *f; 870 871 if (!fname) 872 return 0; 873 874 if (!strcmp(fname, "-")) { 875 f = stdout; 876 if (json_output) { 877 jsonw_name(json_wtr, json_key); 878 print_data_json(data, size); 879 } else { 880 hex_print(data, size, f); 881 } 882 return 0; 883 } 884 885 f = fopen(fname, "w"); 886 if (!f) { 887 p_err("failed to open %s: %s", fname, strerror(errno)); 888 return -1; 889 } 890 891 nb_written = fwrite(data, 1, size, f); 892 fclose(f); 893 if (nb_written != size) { 894 p_err("failed to write output data/ctx: %s", strerror(errno)); 895 return -1; 896 } 897 898 return 0; 899 } 900 901 static int alloc_run_data(void **data_ptr, unsigned int size_out) 902 { 903 *data_ptr = calloc(size_out, 1); 904 if (!*data_ptr) { 905 p_err("failed to allocate memory for output data/ctx: %s", 906 strerror(errno)); 907 return -1; 908 } 909 910 return 0; 911 } 912 913 static int do_run(int argc, char **argv) 914 { 915 char *data_fname_in = NULL, *data_fname_out = NULL; 916 char *ctx_fname_in = NULL, *ctx_fname_out = NULL; 917 struct bpf_prog_test_run_attr test_attr = {0}; 918 const unsigned int default_size = SZ_32K; 919 void *data_in = NULL, *data_out = NULL; 920 void *ctx_in = NULL, *ctx_out = NULL; 921 unsigned int repeat = 1; 922 int fd, err; 923 924 if (!REQ_ARGS(4)) 925 return -1; 926 927 fd = prog_parse_fd(&argc, &argv); 928 if (fd < 0) 929 return -1; 930 931 while (argc) { 932 if (detect_common_prefix(*argv, "data_in", "data_out", 933 "data_size_out", NULL)) 934 return -1; 935 if (detect_common_prefix(*argv, "ctx_in", "ctx_out", 936 "ctx_size_out", NULL)) 937 return -1; 938 939 if (is_prefix(*argv, "data_in")) { 940 NEXT_ARG(); 941 if (!REQ_ARGS(1)) 942 return -1; 943 944 data_fname_in = GET_ARG(); 945 if (check_single_stdin(data_fname_in, ctx_fname_in)) 946 return -1; 947 } else if (is_prefix(*argv, "data_out")) { 948 NEXT_ARG(); 949 if (!REQ_ARGS(1)) 950 return -1; 951 952 data_fname_out = GET_ARG(); 953 } else if (is_prefix(*argv, "data_size_out")) { 954 char *endptr; 955 956 NEXT_ARG(); 957 if (!REQ_ARGS(1)) 958 return -1; 959 960 test_attr.data_size_out = strtoul(*argv, &endptr, 0); 961 if (*endptr) { 962 p_err("can't parse %s as output data size", 963 *argv); 964 return -1; 965 } 966 NEXT_ARG(); 967 } else if (is_prefix(*argv, "ctx_in")) { 968 NEXT_ARG(); 969 if (!REQ_ARGS(1)) 970 return -1; 971 972 ctx_fname_in = GET_ARG(); 973 if (check_single_stdin(data_fname_in, ctx_fname_in)) 974 return -1; 975 } else if (is_prefix(*argv, "ctx_out")) { 976 NEXT_ARG(); 977 if (!REQ_ARGS(1)) 978 return -1; 979 980 ctx_fname_out = GET_ARG(); 981 } else if (is_prefix(*argv, "ctx_size_out")) { 982 char *endptr; 983 984 NEXT_ARG(); 985 if (!REQ_ARGS(1)) 986 return -1; 987 988 test_attr.ctx_size_out = strtoul(*argv, &endptr, 0); 989 if (*endptr) { 990 p_err("can't parse %s as output context size", 991 *argv); 992 return -1; 993 } 994 NEXT_ARG(); 995 } else if (is_prefix(*argv, "repeat")) { 996 char *endptr; 997 998 NEXT_ARG(); 999 if (!REQ_ARGS(1)) 1000 return -1; 1001 1002 repeat = strtoul(*argv, &endptr, 0); 1003 if (*endptr) { 1004 p_err("can't parse %s as repeat number", 1005 *argv); 1006 return -1; 1007 } 1008 NEXT_ARG(); 1009 } else { 1010 p_err("expected no more arguments, 'data_in', 'data_out', 'data_size_out', 'ctx_in', 'ctx_out', 'ctx_size_out' or 'repeat', got: '%s'?", 1011 *argv); 1012 return -1; 1013 } 1014 } 1015 1016 err = get_run_data(data_fname_in, &data_in, &test_attr.data_size_in); 1017 if (err) 1018 return -1; 1019 1020 if (data_in) { 1021 if (!test_attr.data_size_out) 1022 test_attr.data_size_out = default_size; 1023 err = alloc_run_data(&data_out, test_attr.data_size_out); 1024 if (err) 1025 goto free_data_in; 1026 } 1027 1028 err = get_run_data(ctx_fname_in, &ctx_in, &test_attr.ctx_size_in); 1029 if (err) 1030 goto free_data_out; 1031 1032 if (ctx_in) { 1033 if (!test_attr.ctx_size_out) 1034 test_attr.ctx_size_out = default_size; 1035 err = alloc_run_data(&ctx_out, test_attr.ctx_size_out); 1036 if (err) 1037 goto free_ctx_in; 1038 } 1039 1040 test_attr.prog_fd = fd; 1041 test_attr.repeat = repeat; 1042 test_attr.data_in = data_in; 1043 test_attr.data_out = data_out; 1044 test_attr.ctx_in = ctx_in; 1045 test_attr.ctx_out = ctx_out; 1046 1047 err = bpf_prog_test_run_xattr(&test_attr); 1048 if (err) { 1049 p_err("failed to run program: %s", strerror(errno)); 1050 goto free_ctx_out; 1051 } 1052 1053 err = 0; 1054 1055 if (json_output) 1056 jsonw_start_object(json_wtr); /* root */ 1057 1058 /* Do not exit on errors occurring when printing output data/context, 1059 * we still want to print return value and duration for program run. 1060 */ 1061 if (test_attr.data_size_out) 1062 err += print_run_output(test_attr.data_out, 1063 test_attr.data_size_out, 1064 data_fname_out, "data_out"); 1065 if (test_attr.ctx_size_out) 1066 err += print_run_output(test_attr.ctx_out, 1067 test_attr.ctx_size_out, 1068 ctx_fname_out, "ctx_out"); 1069 1070 if (json_output) { 1071 jsonw_uint_field(json_wtr, "retval", test_attr.retval); 1072 jsonw_uint_field(json_wtr, "duration", test_attr.duration); 1073 jsonw_end_object(json_wtr); /* root */ 1074 } else { 1075 fprintf(stdout, "Return value: %u, duration%s: %uns\n", 1076 test_attr.retval, 1077 repeat > 1 ? " (average)" : "", test_attr.duration); 1078 } 1079 1080 free_ctx_out: 1081 free(ctx_out); 1082 free_ctx_in: 1083 free(ctx_in); 1084 free_data_out: 1085 free(data_out); 1086 free_data_in: 1087 free(data_in); 1088 1089 return err; 1090 } 1091 1092 static int load_with_options(int argc, char **argv, bool first_prog_only) 1093 { 1094 enum bpf_prog_type common_prog_type = BPF_PROG_TYPE_UNSPEC; 1095 DECLARE_LIBBPF_OPTS(bpf_object_open_opts, open_opts, 1096 .relaxed_maps = relaxed_maps, 1097 ); 1098 struct bpf_object_load_attr load_attr = { 0 }; 1099 enum bpf_attach_type expected_attach_type; 1100 struct map_replace *map_replace = NULL; 1101 struct bpf_program *prog = NULL, *pos; 1102 unsigned int old_map_fds = 0; 1103 const char *pinmaps = NULL; 1104 struct bpf_object *obj; 1105 struct bpf_map *map; 1106 const char *pinfile; 1107 unsigned int i, j; 1108 __u32 ifindex = 0; 1109 const char *file; 1110 int idx, err; 1111 1112 1113 if (!REQ_ARGS(2)) 1114 return -1; 1115 file = GET_ARG(); 1116 pinfile = GET_ARG(); 1117 1118 while (argc) { 1119 if (is_prefix(*argv, "type")) { 1120 char *type; 1121 1122 NEXT_ARG(); 1123 1124 if (common_prog_type != BPF_PROG_TYPE_UNSPEC) { 1125 p_err("program type already specified"); 1126 goto err_free_reuse_maps; 1127 } 1128 if (!REQ_ARGS(1)) 1129 goto err_free_reuse_maps; 1130 1131 /* Put a '/' at the end of type to appease libbpf */ 1132 type = malloc(strlen(*argv) + 2); 1133 if (!type) { 1134 p_err("mem alloc failed"); 1135 goto err_free_reuse_maps; 1136 } 1137 *type = 0; 1138 strcat(type, *argv); 1139 strcat(type, "/"); 1140 1141 err = libbpf_prog_type_by_name(type, &common_prog_type, 1142 &expected_attach_type); 1143 free(type); 1144 if (err < 0) 1145 goto err_free_reuse_maps; 1146 1147 NEXT_ARG(); 1148 } else if (is_prefix(*argv, "map")) { 1149 void *new_map_replace; 1150 char *endptr, *name; 1151 int fd; 1152 1153 NEXT_ARG(); 1154 1155 if (!REQ_ARGS(4)) 1156 goto err_free_reuse_maps; 1157 1158 if (is_prefix(*argv, "idx")) { 1159 NEXT_ARG(); 1160 1161 idx = strtoul(*argv, &endptr, 0); 1162 if (*endptr) { 1163 p_err("can't parse %s as IDX", *argv); 1164 goto err_free_reuse_maps; 1165 } 1166 name = NULL; 1167 } else if (is_prefix(*argv, "name")) { 1168 NEXT_ARG(); 1169 1170 name = *argv; 1171 idx = -1; 1172 } else { 1173 p_err("expected 'idx' or 'name', got: '%s'?", 1174 *argv); 1175 goto err_free_reuse_maps; 1176 } 1177 NEXT_ARG(); 1178 1179 fd = map_parse_fd(&argc, &argv); 1180 if (fd < 0) 1181 goto err_free_reuse_maps; 1182 1183 new_map_replace = reallocarray(map_replace, 1184 old_map_fds + 1, 1185 sizeof(*map_replace)); 1186 if (!new_map_replace) { 1187 p_err("mem alloc failed"); 1188 goto err_free_reuse_maps; 1189 } 1190 map_replace = new_map_replace; 1191 1192 map_replace[old_map_fds].idx = idx; 1193 map_replace[old_map_fds].name = name; 1194 map_replace[old_map_fds].fd = fd; 1195 old_map_fds++; 1196 } else if (is_prefix(*argv, "dev")) { 1197 NEXT_ARG(); 1198 1199 if (ifindex) { 1200 p_err("offload device already specified"); 1201 goto err_free_reuse_maps; 1202 } 1203 if (!REQ_ARGS(1)) 1204 goto err_free_reuse_maps; 1205 1206 ifindex = if_nametoindex(*argv); 1207 if (!ifindex) { 1208 p_err("unrecognized netdevice '%s': %s", 1209 *argv, strerror(errno)); 1210 goto err_free_reuse_maps; 1211 } 1212 NEXT_ARG(); 1213 } else if (is_prefix(*argv, "pinmaps")) { 1214 NEXT_ARG(); 1215 1216 if (!REQ_ARGS(1)) 1217 goto err_free_reuse_maps; 1218 1219 pinmaps = GET_ARG(); 1220 } else { 1221 p_err("expected no more arguments, 'type', 'map' or 'dev', got: '%s'?", 1222 *argv); 1223 goto err_free_reuse_maps; 1224 } 1225 } 1226 1227 set_max_rlimit(); 1228 1229 obj = bpf_object__open_file(file, &open_opts); 1230 if (IS_ERR_OR_NULL(obj)) { 1231 p_err("failed to open object file"); 1232 goto err_free_reuse_maps; 1233 } 1234 1235 bpf_object__for_each_program(pos, obj) { 1236 enum bpf_prog_type prog_type = common_prog_type; 1237 1238 if (prog_type == BPF_PROG_TYPE_UNSPEC) { 1239 const char *sec_name = bpf_program__title(pos, false); 1240 1241 err = libbpf_prog_type_by_name(sec_name, &prog_type, 1242 &expected_attach_type); 1243 if (err < 0) 1244 goto err_close_obj; 1245 } 1246 1247 bpf_program__set_ifindex(pos, ifindex); 1248 bpf_program__set_type(pos, prog_type); 1249 bpf_program__set_expected_attach_type(pos, expected_attach_type); 1250 } 1251 1252 qsort(map_replace, old_map_fds, sizeof(*map_replace), 1253 map_replace_compar); 1254 1255 /* After the sort maps by name will be first on the list, because they 1256 * have idx == -1. Resolve them. 1257 */ 1258 j = 0; 1259 while (j < old_map_fds && map_replace[j].name) { 1260 i = 0; 1261 bpf_object__for_each_map(map, obj) { 1262 if (!strcmp(bpf_map__name(map), map_replace[j].name)) { 1263 map_replace[j].idx = i; 1264 break; 1265 } 1266 i++; 1267 } 1268 if (map_replace[j].idx == -1) { 1269 p_err("unable to find map '%s'", map_replace[j].name); 1270 goto err_close_obj; 1271 } 1272 j++; 1273 } 1274 /* Resort if any names were resolved */ 1275 if (j) 1276 qsort(map_replace, old_map_fds, sizeof(*map_replace), 1277 map_replace_compar); 1278 1279 /* Set ifindex and name reuse */ 1280 j = 0; 1281 idx = 0; 1282 bpf_object__for_each_map(map, obj) { 1283 if (!bpf_map__is_offload_neutral(map)) 1284 bpf_map__set_ifindex(map, ifindex); 1285 1286 if (j < old_map_fds && idx == map_replace[j].idx) { 1287 err = bpf_map__reuse_fd(map, map_replace[j++].fd); 1288 if (err) { 1289 p_err("unable to set up map reuse: %d", err); 1290 goto err_close_obj; 1291 } 1292 1293 /* Next reuse wants to apply to the same map */ 1294 if (j < old_map_fds && map_replace[j].idx == idx) { 1295 p_err("replacement for map idx %d specified more than once", 1296 idx); 1297 goto err_close_obj; 1298 } 1299 } 1300 1301 idx++; 1302 } 1303 if (j < old_map_fds) { 1304 p_err("map idx '%d' not used", map_replace[j].idx); 1305 goto err_close_obj; 1306 } 1307 1308 load_attr.obj = obj; 1309 if (verifier_logs) 1310 /* log_level1 + log_level2 + stats, but not stable UAPI */ 1311 load_attr.log_level = 1 + 2 + 4; 1312 1313 err = bpf_object__load_xattr(&load_attr); 1314 if (err) { 1315 p_err("failed to load object file"); 1316 goto err_close_obj; 1317 } 1318 1319 err = mount_bpffs_for_pin(pinfile); 1320 if (err) 1321 goto err_close_obj; 1322 1323 if (first_prog_only) { 1324 prog = bpf_program__next(NULL, obj); 1325 if (!prog) { 1326 p_err("object file doesn't contain any bpf program"); 1327 goto err_close_obj; 1328 } 1329 1330 err = bpf_obj_pin(bpf_program__fd(prog), pinfile); 1331 if (err) { 1332 p_err("failed to pin program %s", 1333 bpf_program__title(prog, false)); 1334 goto err_close_obj; 1335 } 1336 } else { 1337 err = bpf_object__pin_programs(obj, pinfile); 1338 if (err) { 1339 p_err("failed to pin all programs"); 1340 goto err_close_obj; 1341 } 1342 } 1343 1344 if (pinmaps) { 1345 err = bpf_object__pin_maps(obj, pinmaps); 1346 if (err) { 1347 p_err("failed to pin all maps"); 1348 goto err_unpin; 1349 } 1350 } 1351 1352 if (json_output) 1353 jsonw_null(json_wtr); 1354 1355 bpf_object__close(obj); 1356 for (i = 0; i < old_map_fds; i++) 1357 close(map_replace[i].fd); 1358 free(map_replace); 1359 1360 return 0; 1361 1362 err_unpin: 1363 if (first_prog_only) 1364 unlink(pinfile); 1365 else 1366 bpf_object__unpin_programs(obj, pinfile); 1367 err_close_obj: 1368 bpf_object__close(obj); 1369 err_free_reuse_maps: 1370 for (i = 0; i < old_map_fds; i++) 1371 close(map_replace[i].fd); 1372 free(map_replace); 1373 return -1; 1374 } 1375 1376 static int do_load(int argc, char **argv) 1377 { 1378 return load_with_options(argc, argv, true); 1379 } 1380 1381 static int do_loadall(int argc, char **argv) 1382 { 1383 return load_with_options(argc, argv, false); 1384 } 1385 1386 static int do_help(int argc, char **argv) 1387 { 1388 if (json_output) { 1389 jsonw_null(json_wtr); 1390 return 0; 1391 } 1392 1393 fprintf(stderr, 1394 "Usage: %s %s { show | list } [PROG]\n" 1395 " %s %s dump xlated PROG [{ file FILE | opcodes | visual | linum }]\n" 1396 " %s %s dump jited PROG [{ file FILE | opcodes | linum }]\n" 1397 " %s %s pin PROG FILE\n" 1398 " %s %s { load | loadall } OBJ PATH \\\n" 1399 " [type TYPE] [dev NAME] \\\n" 1400 " [map { idx IDX | name NAME } MAP]\\\n" 1401 " [pinmaps MAP_DIR]\n" 1402 " %s %s attach PROG ATTACH_TYPE [MAP]\n" 1403 " %s %s detach PROG ATTACH_TYPE [MAP]\n" 1404 " %s %s run PROG \\\n" 1405 " data_in FILE \\\n" 1406 " [data_out FILE [data_size_out L]] \\\n" 1407 " [ctx_in FILE [ctx_out FILE [ctx_size_out M]]] \\\n" 1408 " [repeat N]\n" 1409 " %s %s tracelog\n" 1410 " %s %s help\n" 1411 "\n" 1412 " " HELP_SPEC_MAP "\n" 1413 " " HELP_SPEC_PROGRAM "\n" 1414 " TYPE := { socket | kprobe | kretprobe | classifier | action |\n" 1415 " tracepoint | raw_tracepoint | xdp | perf_event | cgroup/skb |\n" 1416 " cgroup/sock | cgroup/dev | lwt_in | lwt_out | lwt_xmit |\n" 1417 " lwt_seg6local | sockops | sk_skb | sk_msg | lirc_mode2 |\n" 1418 " sk_reuseport | flow_dissector | cgroup/sysctl |\n" 1419 " cgroup/bind4 | cgroup/bind6 | cgroup/post_bind4 |\n" 1420 " cgroup/post_bind6 | cgroup/connect4 | cgroup/connect6 |\n" 1421 " cgroup/sendmsg4 | cgroup/sendmsg6 | cgroup/recvmsg4 |\n" 1422 " cgroup/recvmsg6 | cgroup/getsockopt |\n" 1423 " cgroup/setsockopt }\n" 1424 " ATTACH_TYPE := { msg_verdict | stream_verdict | stream_parser |\n" 1425 " flow_dissector }\n" 1426 " " HELP_SPEC_OPTIONS "\n" 1427 "", 1428 bin_name, argv[-2], bin_name, argv[-2], bin_name, argv[-2], 1429 bin_name, argv[-2], bin_name, argv[-2], bin_name, argv[-2], 1430 bin_name, argv[-2], bin_name, argv[-2], bin_name, argv[-2], 1431 bin_name, argv[-2]); 1432 1433 return 0; 1434 } 1435 1436 static const struct cmd cmds[] = { 1437 { "show", do_show }, 1438 { "list", do_show }, 1439 { "help", do_help }, 1440 { "dump", do_dump }, 1441 { "pin", do_pin }, 1442 { "load", do_load }, 1443 { "loadall", do_loadall }, 1444 { "attach", do_attach }, 1445 { "detach", do_detach }, 1446 { "tracelog", do_tracelog }, 1447 { "run", do_run }, 1448 { 0 } 1449 }; 1450 1451 int do_prog(int argc, char **argv) 1452 { 1453 return cmd_select(cmds, argc, argv, do_help); 1454 } 1455