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 return show_prog(fd); 367 } 368 369 if (argc) 370 return BAD_ARG(); 371 372 if (json_output) 373 jsonw_start_array(json_wtr); 374 while (true) { 375 err = bpf_prog_get_next_id(id, &id); 376 if (err) { 377 if (errno == ENOENT) { 378 err = 0; 379 break; 380 } 381 p_err("can't get next program: %s%s", strerror(errno), 382 errno == EINVAL ? " -- kernel too old?" : ""); 383 err = -1; 384 break; 385 } 386 387 fd = bpf_prog_get_fd_by_id(id); 388 if (fd < 0) { 389 if (errno == ENOENT) 390 continue; 391 p_err("can't get prog by id (%u): %s", 392 id, strerror(errno)); 393 err = -1; 394 break; 395 } 396 397 err = show_prog(fd); 398 close(fd); 399 if (err) 400 break; 401 } 402 403 if (json_output) 404 jsonw_end_array(json_wtr); 405 406 return err; 407 } 408 409 static int do_dump(int argc, char **argv) 410 { 411 struct bpf_prog_info_linear *info_linear; 412 struct bpf_prog_linfo *prog_linfo = NULL; 413 enum {DUMP_JITED, DUMP_XLATED} mode; 414 const char *disasm_opt = NULL; 415 struct bpf_prog_info *info; 416 struct dump_data dd = {}; 417 void *func_info = NULL; 418 struct btf *btf = NULL; 419 char *filepath = NULL; 420 bool opcodes = false; 421 bool visual = false; 422 char func_sig[1024]; 423 unsigned char *buf; 424 bool linum = false; 425 __u32 member_len; 426 __u64 arrays; 427 ssize_t n; 428 int fd; 429 430 if (is_prefix(*argv, "jited")) { 431 if (disasm_init()) 432 return -1; 433 mode = DUMP_JITED; 434 } else if (is_prefix(*argv, "xlated")) { 435 mode = DUMP_XLATED; 436 } else { 437 p_err("expected 'xlated' or 'jited', got: %s", *argv); 438 return -1; 439 } 440 NEXT_ARG(); 441 442 if (argc < 2) 443 usage(); 444 445 fd = prog_parse_fd(&argc, &argv); 446 if (fd < 0) 447 return -1; 448 449 if (is_prefix(*argv, "file")) { 450 NEXT_ARG(); 451 if (!argc) { 452 p_err("expected file path"); 453 return -1; 454 } 455 456 filepath = *argv; 457 NEXT_ARG(); 458 } else if (is_prefix(*argv, "opcodes")) { 459 opcodes = true; 460 NEXT_ARG(); 461 } else if (is_prefix(*argv, "visual")) { 462 visual = true; 463 NEXT_ARG(); 464 } else if (is_prefix(*argv, "linum")) { 465 linum = true; 466 NEXT_ARG(); 467 } 468 469 if (argc) { 470 usage(); 471 return -1; 472 } 473 474 if (mode == DUMP_JITED) 475 arrays = 1UL << BPF_PROG_INFO_JITED_INSNS; 476 else 477 arrays = 1UL << BPF_PROG_INFO_XLATED_INSNS; 478 479 arrays |= 1UL << BPF_PROG_INFO_JITED_KSYMS; 480 arrays |= 1UL << BPF_PROG_INFO_JITED_FUNC_LENS; 481 arrays |= 1UL << BPF_PROG_INFO_FUNC_INFO; 482 arrays |= 1UL << BPF_PROG_INFO_LINE_INFO; 483 arrays |= 1UL << BPF_PROG_INFO_JITED_LINE_INFO; 484 485 info_linear = bpf_program__get_prog_info_linear(fd, arrays); 486 close(fd); 487 if (IS_ERR_OR_NULL(info_linear)) { 488 p_err("can't get prog info: %s", strerror(errno)); 489 return -1; 490 } 491 492 info = &info_linear->info; 493 if (mode == DUMP_JITED) { 494 if (info->jited_prog_len == 0) { 495 p_info("no instructions returned"); 496 goto err_free; 497 } 498 buf = (unsigned char *)(info->jited_prog_insns); 499 member_len = info->jited_prog_len; 500 } else { /* DUMP_XLATED */ 501 if (info->xlated_prog_len == 0) { 502 p_err("error retrieving insn dump: kernel.kptr_restrict set?"); 503 goto err_free; 504 } 505 buf = (unsigned char *)info->xlated_prog_insns; 506 member_len = info->xlated_prog_len; 507 } 508 509 if (info->btf_id && btf__get_from_id(info->btf_id, &btf)) { 510 p_err("failed to get btf"); 511 goto err_free; 512 } 513 514 func_info = (void *)info->func_info; 515 516 if (info->nr_line_info) { 517 prog_linfo = bpf_prog_linfo__new(info); 518 if (!prog_linfo) 519 p_info("error in processing bpf_line_info. continue without it."); 520 } 521 522 if (filepath) { 523 fd = open(filepath, O_WRONLY | O_CREAT | O_TRUNC, 0600); 524 if (fd < 0) { 525 p_err("can't open file %s: %s", filepath, 526 strerror(errno)); 527 goto err_free; 528 } 529 530 n = write(fd, buf, member_len); 531 close(fd); 532 if (n != member_len) { 533 p_err("error writing output file: %s", 534 n < 0 ? strerror(errno) : "short write"); 535 goto err_free; 536 } 537 538 if (json_output) 539 jsonw_null(json_wtr); 540 } else if (mode == DUMP_JITED) { 541 const char *name = NULL; 542 543 if (info->ifindex) { 544 name = ifindex_to_bfd_params(info->ifindex, 545 info->netns_dev, 546 info->netns_ino, 547 &disasm_opt); 548 if (!name) 549 goto err_free; 550 } 551 552 if (info->nr_jited_func_lens && info->jited_func_lens) { 553 struct kernel_sym *sym = NULL; 554 struct bpf_func_info *record; 555 char sym_name[SYM_MAX_NAME]; 556 unsigned char *img = buf; 557 __u64 *ksyms = NULL; 558 __u32 *lens; 559 __u32 i; 560 if (info->nr_jited_ksyms) { 561 kernel_syms_load(&dd); 562 ksyms = (__u64 *) info->jited_ksyms; 563 } 564 565 if (json_output) 566 jsonw_start_array(json_wtr); 567 568 lens = (__u32 *) info->jited_func_lens; 569 for (i = 0; i < info->nr_jited_func_lens; i++) { 570 if (ksyms) { 571 sym = kernel_syms_search(&dd, ksyms[i]); 572 if (sym) 573 sprintf(sym_name, "%s", sym->name); 574 else 575 sprintf(sym_name, "0x%016llx", ksyms[i]); 576 } else { 577 strcpy(sym_name, "unknown"); 578 } 579 580 if (func_info) { 581 record = func_info + i * info->func_info_rec_size; 582 btf_dumper_type_only(btf, record->type_id, 583 func_sig, 584 sizeof(func_sig)); 585 } 586 587 if (json_output) { 588 jsonw_start_object(json_wtr); 589 if (func_info && func_sig[0] != '\0') { 590 jsonw_name(json_wtr, "proto"); 591 jsonw_string(json_wtr, func_sig); 592 } 593 jsonw_name(json_wtr, "name"); 594 jsonw_string(json_wtr, sym_name); 595 jsonw_name(json_wtr, "insns"); 596 } else { 597 if (func_info && func_sig[0] != '\0') 598 printf("%s:\n", func_sig); 599 printf("%s:\n", sym_name); 600 } 601 602 disasm_print_insn(img, lens[i], opcodes, 603 name, disasm_opt, btf, 604 prog_linfo, ksyms[i], i, 605 linum); 606 607 img += lens[i]; 608 609 if (json_output) 610 jsonw_end_object(json_wtr); 611 else 612 printf("\n"); 613 } 614 615 if (json_output) 616 jsonw_end_array(json_wtr); 617 } else { 618 disasm_print_insn(buf, member_len, opcodes, name, 619 disasm_opt, btf, NULL, 0, 0, false); 620 } 621 } else if (visual) { 622 if (json_output) 623 jsonw_null(json_wtr); 624 else 625 dump_xlated_cfg(buf, member_len); 626 } else { 627 kernel_syms_load(&dd); 628 dd.nr_jited_ksyms = info->nr_jited_ksyms; 629 dd.jited_ksyms = (__u64 *) info->jited_ksyms; 630 dd.btf = btf; 631 dd.func_info = func_info; 632 dd.finfo_rec_size = info->func_info_rec_size; 633 dd.prog_linfo = prog_linfo; 634 635 if (json_output) 636 dump_xlated_json(&dd, buf, member_len, opcodes, 637 linum); 638 else 639 dump_xlated_plain(&dd, buf, member_len, opcodes, 640 linum); 641 kernel_syms_destroy(&dd); 642 } 643 644 free(info_linear); 645 return 0; 646 647 err_free: 648 free(info_linear); 649 return -1; 650 } 651 652 static int do_pin(int argc, char **argv) 653 { 654 int err; 655 656 err = do_pin_any(argc, argv, bpf_prog_get_fd_by_id); 657 if (!err && json_output) 658 jsonw_null(json_wtr); 659 return err; 660 } 661 662 struct map_replace { 663 int idx; 664 int fd; 665 char *name; 666 }; 667 668 static int map_replace_compar(const void *p1, const void *p2) 669 { 670 const struct map_replace *a = p1, *b = p2; 671 672 return a->idx - b->idx; 673 } 674 675 static int parse_attach_detach_args(int argc, char **argv, int *progfd, 676 enum bpf_attach_type *attach_type, 677 int *mapfd) 678 { 679 if (!REQ_ARGS(3)) 680 return -EINVAL; 681 682 *progfd = prog_parse_fd(&argc, &argv); 683 if (*progfd < 0) 684 return *progfd; 685 686 *attach_type = parse_attach_type(*argv); 687 if (*attach_type == __MAX_BPF_ATTACH_TYPE) { 688 p_err("invalid attach/detach type"); 689 return -EINVAL; 690 } 691 692 if (*attach_type == BPF_FLOW_DISSECTOR) { 693 *mapfd = -1; 694 return 0; 695 } 696 697 NEXT_ARG(); 698 if (!REQ_ARGS(2)) 699 return -EINVAL; 700 701 *mapfd = map_parse_fd(&argc, &argv); 702 if (*mapfd < 0) 703 return *mapfd; 704 705 return 0; 706 } 707 708 static int do_attach(int argc, char **argv) 709 { 710 enum bpf_attach_type attach_type; 711 int err, progfd; 712 int mapfd; 713 714 err = parse_attach_detach_args(argc, argv, 715 &progfd, &attach_type, &mapfd); 716 if (err) 717 return err; 718 719 err = bpf_prog_attach(progfd, mapfd, attach_type, 0); 720 if (err) { 721 p_err("failed prog attach to map"); 722 return -EINVAL; 723 } 724 725 if (json_output) 726 jsonw_null(json_wtr); 727 return 0; 728 } 729 730 static int do_detach(int argc, char **argv) 731 { 732 enum bpf_attach_type attach_type; 733 int err, progfd; 734 int mapfd; 735 736 err = parse_attach_detach_args(argc, argv, 737 &progfd, &attach_type, &mapfd); 738 if (err) 739 return err; 740 741 err = bpf_prog_detach2(progfd, mapfd, attach_type); 742 if (err) { 743 p_err("failed prog detach from map"); 744 return -EINVAL; 745 } 746 747 if (json_output) 748 jsonw_null(json_wtr); 749 return 0; 750 } 751 752 static int check_single_stdin(char *file_data_in, char *file_ctx_in) 753 { 754 if (file_data_in && file_ctx_in && 755 !strcmp(file_data_in, "-") && !strcmp(file_ctx_in, "-")) { 756 p_err("cannot use standard input for both data_in and ctx_in"); 757 return -1; 758 } 759 760 return 0; 761 } 762 763 static int get_run_data(const char *fname, void **data_ptr, unsigned int *size) 764 { 765 size_t block_size = 256; 766 size_t buf_size = block_size; 767 size_t nb_read = 0; 768 void *tmp; 769 FILE *f; 770 771 if (!fname) { 772 *data_ptr = NULL; 773 *size = 0; 774 return 0; 775 } 776 777 if (!strcmp(fname, "-")) 778 f = stdin; 779 else 780 f = fopen(fname, "r"); 781 if (!f) { 782 p_err("failed to open %s: %s", fname, strerror(errno)); 783 return -1; 784 } 785 786 *data_ptr = malloc(block_size); 787 if (!*data_ptr) { 788 p_err("failed to allocate memory for data_in/ctx_in: %s", 789 strerror(errno)); 790 goto err_fclose; 791 } 792 793 while ((nb_read += fread(*data_ptr + nb_read, 1, block_size, f))) { 794 if (feof(f)) 795 break; 796 if (ferror(f)) { 797 p_err("failed to read data_in/ctx_in from %s: %s", 798 fname, strerror(errno)); 799 goto err_free; 800 } 801 if (nb_read > buf_size - block_size) { 802 if (buf_size == UINT32_MAX) { 803 p_err("data_in/ctx_in is too long (max: %d)", 804 UINT32_MAX); 805 goto err_free; 806 } 807 /* No space for fread()-ing next chunk; realloc() */ 808 buf_size *= 2; 809 tmp = realloc(*data_ptr, buf_size); 810 if (!tmp) { 811 p_err("failed to reallocate data_in/ctx_in: %s", 812 strerror(errno)); 813 goto err_free; 814 } 815 *data_ptr = tmp; 816 } 817 } 818 if (f != stdin) 819 fclose(f); 820 821 *size = nb_read; 822 return 0; 823 824 err_free: 825 free(*data_ptr); 826 *data_ptr = NULL; 827 err_fclose: 828 if (f != stdin) 829 fclose(f); 830 return -1; 831 } 832 833 static void hex_print(void *data, unsigned int size, FILE *f) 834 { 835 size_t i, j; 836 char c; 837 838 for (i = 0; i < size; i += 16) { 839 /* Row offset */ 840 fprintf(f, "%07zx\t", i); 841 842 /* Hexadecimal values */ 843 for (j = i; j < i + 16 && j < size; j++) 844 fprintf(f, "%02x%s", *(uint8_t *)(data + j), 845 j % 2 ? " " : ""); 846 for (; j < i + 16; j++) 847 fprintf(f, " %s", j % 2 ? " " : ""); 848 849 /* ASCII values (if relevant), '.' otherwise */ 850 fprintf(f, "| "); 851 for (j = i; j < i + 16 && j < size; j++) { 852 c = *(char *)(data + j); 853 if (c < ' ' || c > '~') 854 c = '.'; 855 fprintf(f, "%c%s", c, j == i + 7 ? " " : ""); 856 } 857 858 fprintf(f, "\n"); 859 } 860 } 861 862 static int 863 print_run_output(void *data, unsigned int size, const char *fname, 864 const char *json_key) 865 { 866 size_t nb_written; 867 FILE *f; 868 869 if (!fname) 870 return 0; 871 872 if (!strcmp(fname, "-")) { 873 f = stdout; 874 if (json_output) { 875 jsonw_name(json_wtr, json_key); 876 print_data_json(data, size); 877 } else { 878 hex_print(data, size, f); 879 } 880 return 0; 881 } 882 883 f = fopen(fname, "w"); 884 if (!f) { 885 p_err("failed to open %s: %s", fname, strerror(errno)); 886 return -1; 887 } 888 889 nb_written = fwrite(data, 1, size, f); 890 fclose(f); 891 if (nb_written != size) { 892 p_err("failed to write output data/ctx: %s", strerror(errno)); 893 return -1; 894 } 895 896 return 0; 897 } 898 899 static int alloc_run_data(void **data_ptr, unsigned int size_out) 900 { 901 *data_ptr = calloc(size_out, 1); 902 if (!*data_ptr) { 903 p_err("failed to allocate memory for output data/ctx: %s", 904 strerror(errno)); 905 return -1; 906 } 907 908 return 0; 909 } 910 911 static int do_run(int argc, char **argv) 912 { 913 char *data_fname_in = NULL, *data_fname_out = NULL; 914 char *ctx_fname_in = NULL, *ctx_fname_out = NULL; 915 struct bpf_prog_test_run_attr test_attr = {0}; 916 const unsigned int default_size = SZ_32K; 917 void *data_in = NULL, *data_out = NULL; 918 void *ctx_in = NULL, *ctx_out = NULL; 919 unsigned int repeat = 1; 920 int fd, err; 921 922 if (!REQ_ARGS(4)) 923 return -1; 924 925 fd = prog_parse_fd(&argc, &argv); 926 if (fd < 0) 927 return -1; 928 929 while (argc) { 930 if (detect_common_prefix(*argv, "data_in", "data_out", 931 "data_size_out", NULL)) 932 return -1; 933 if (detect_common_prefix(*argv, "ctx_in", "ctx_out", 934 "ctx_size_out", NULL)) 935 return -1; 936 937 if (is_prefix(*argv, "data_in")) { 938 NEXT_ARG(); 939 if (!REQ_ARGS(1)) 940 return -1; 941 942 data_fname_in = GET_ARG(); 943 if (check_single_stdin(data_fname_in, ctx_fname_in)) 944 return -1; 945 } else if (is_prefix(*argv, "data_out")) { 946 NEXT_ARG(); 947 if (!REQ_ARGS(1)) 948 return -1; 949 950 data_fname_out = GET_ARG(); 951 } else if (is_prefix(*argv, "data_size_out")) { 952 char *endptr; 953 954 NEXT_ARG(); 955 if (!REQ_ARGS(1)) 956 return -1; 957 958 test_attr.data_size_out = strtoul(*argv, &endptr, 0); 959 if (*endptr) { 960 p_err("can't parse %s as output data size", 961 *argv); 962 return -1; 963 } 964 NEXT_ARG(); 965 } else if (is_prefix(*argv, "ctx_in")) { 966 NEXT_ARG(); 967 if (!REQ_ARGS(1)) 968 return -1; 969 970 ctx_fname_in = GET_ARG(); 971 if (check_single_stdin(data_fname_in, ctx_fname_in)) 972 return -1; 973 } else if (is_prefix(*argv, "ctx_out")) { 974 NEXT_ARG(); 975 if (!REQ_ARGS(1)) 976 return -1; 977 978 ctx_fname_out = GET_ARG(); 979 } else if (is_prefix(*argv, "ctx_size_out")) { 980 char *endptr; 981 982 NEXT_ARG(); 983 if (!REQ_ARGS(1)) 984 return -1; 985 986 test_attr.ctx_size_out = strtoul(*argv, &endptr, 0); 987 if (*endptr) { 988 p_err("can't parse %s as output context size", 989 *argv); 990 return -1; 991 } 992 NEXT_ARG(); 993 } else if (is_prefix(*argv, "repeat")) { 994 char *endptr; 995 996 NEXT_ARG(); 997 if (!REQ_ARGS(1)) 998 return -1; 999 1000 repeat = strtoul(*argv, &endptr, 0); 1001 if (*endptr) { 1002 p_err("can't parse %s as repeat number", 1003 *argv); 1004 return -1; 1005 } 1006 NEXT_ARG(); 1007 } else { 1008 p_err("expected no more arguments, 'data_in', 'data_out', 'data_size_out', 'ctx_in', 'ctx_out', 'ctx_size_out' or 'repeat', got: '%s'?", 1009 *argv); 1010 return -1; 1011 } 1012 } 1013 1014 err = get_run_data(data_fname_in, &data_in, &test_attr.data_size_in); 1015 if (err) 1016 return -1; 1017 1018 if (data_in) { 1019 if (!test_attr.data_size_out) 1020 test_attr.data_size_out = default_size; 1021 err = alloc_run_data(&data_out, test_attr.data_size_out); 1022 if (err) 1023 goto free_data_in; 1024 } 1025 1026 err = get_run_data(ctx_fname_in, &ctx_in, &test_attr.ctx_size_in); 1027 if (err) 1028 goto free_data_out; 1029 1030 if (ctx_in) { 1031 if (!test_attr.ctx_size_out) 1032 test_attr.ctx_size_out = default_size; 1033 err = alloc_run_data(&ctx_out, test_attr.ctx_size_out); 1034 if (err) 1035 goto free_ctx_in; 1036 } 1037 1038 test_attr.prog_fd = fd; 1039 test_attr.repeat = repeat; 1040 test_attr.data_in = data_in; 1041 test_attr.data_out = data_out; 1042 test_attr.ctx_in = ctx_in; 1043 test_attr.ctx_out = ctx_out; 1044 1045 err = bpf_prog_test_run_xattr(&test_attr); 1046 if (err) { 1047 p_err("failed to run program: %s", strerror(errno)); 1048 goto free_ctx_out; 1049 } 1050 1051 err = 0; 1052 1053 if (json_output) 1054 jsonw_start_object(json_wtr); /* root */ 1055 1056 /* Do not exit on errors occurring when printing output data/context, 1057 * we still want to print return value and duration for program run. 1058 */ 1059 if (test_attr.data_size_out) 1060 err += print_run_output(test_attr.data_out, 1061 test_attr.data_size_out, 1062 data_fname_out, "data_out"); 1063 if (test_attr.ctx_size_out) 1064 err += print_run_output(test_attr.ctx_out, 1065 test_attr.ctx_size_out, 1066 ctx_fname_out, "ctx_out"); 1067 1068 if (json_output) { 1069 jsonw_uint_field(json_wtr, "retval", test_attr.retval); 1070 jsonw_uint_field(json_wtr, "duration", test_attr.duration); 1071 jsonw_end_object(json_wtr); /* root */ 1072 } else { 1073 fprintf(stdout, "Return value: %u, duration%s: %uns\n", 1074 test_attr.retval, 1075 repeat > 1 ? " (average)" : "", test_attr.duration); 1076 } 1077 1078 free_ctx_out: 1079 free(ctx_out); 1080 free_ctx_in: 1081 free(ctx_in); 1082 free_data_out: 1083 free(data_out); 1084 free_data_in: 1085 free(data_in); 1086 1087 return err; 1088 } 1089 1090 static int load_with_options(int argc, char **argv, bool first_prog_only) 1091 { 1092 struct bpf_object_load_attr load_attr = { 0 }; 1093 struct bpf_object_open_attr open_attr = { 1094 .prog_type = BPF_PROG_TYPE_UNSPEC, 1095 }; 1096 enum bpf_attach_type expected_attach_type; 1097 struct map_replace *map_replace = NULL; 1098 struct bpf_program *prog = NULL, *pos; 1099 unsigned int old_map_fds = 0; 1100 const char *pinmaps = NULL; 1101 struct bpf_object *obj; 1102 struct bpf_map *map; 1103 const char *pinfile; 1104 unsigned int i, j; 1105 __u32 ifindex = 0; 1106 int idx, err; 1107 1108 if (!REQ_ARGS(2)) 1109 return -1; 1110 open_attr.file = GET_ARG(); 1111 pinfile = GET_ARG(); 1112 1113 while (argc) { 1114 if (is_prefix(*argv, "type")) { 1115 char *type; 1116 1117 NEXT_ARG(); 1118 1119 if (open_attr.prog_type != BPF_PROG_TYPE_UNSPEC) { 1120 p_err("program type already specified"); 1121 goto err_free_reuse_maps; 1122 } 1123 if (!REQ_ARGS(1)) 1124 goto err_free_reuse_maps; 1125 1126 /* Put a '/' at the end of type to appease libbpf */ 1127 type = malloc(strlen(*argv) + 2); 1128 if (!type) { 1129 p_err("mem alloc failed"); 1130 goto err_free_reuse_maps; 1131 } 1132 *type = 0; 1133 strcat(type, *argv); 1134 strcat(type, "/"); 1135 1136 err = libbpf_prog_type_by_name(type, 1137 &open_attr.prog_type, 1138 &expected_attach_type); 1139 free(type); 1140 if (err < 0) 1141 goto err_free_reuse_maps; 1142 1143 NEXT_ARG(); 1144 } else if (is_prefix(*argv, "map")) { 1145 void *new_map_replace; 1146 char *endptr, *name; 1147 int fd; 1148 1149 NEXT_ARG(); 1150 1151 if (!REQ_ARGS(4)) 1152 goto err_free_reuse_maps; 1153 1154 if (is_prefix(*argv, "idx")) { 1155 NEXT_ARG(); 1156 1157 idx = strtoul(*argv, &endptr, 0); 1158 if (*endptr) { 1159 p_err("can't parse %s as IDX", *argv); 1160 goto err_free_reuse_maps; 1161 } 1162 name = NULL; 1163 } else if (is_prefix(*argv, "name")) { 1164 NEXT_ARG(); 1165 1166 name = *argv; 1167 idx = -1; 1168 } else { 1169 p_err("expected 'idx' or 'name', got: '%s'?", 1170 *argv); 1171 goto err_free_reuse_maps; 1172 } 1173 NEXT_ARG(); 1174 1175 fd = map_parse_fd(&argc, &argv); 1176 if (fd < 0) 1177 goto err_free_reuse_maps; 1178 1179 new_map_replace = reallocarray(map_replace, 1180 old_map_fds + 1, 1181 sizeof(*map_replace)); 1182 if (!new_map_replace) { 1183 p_err("mem alloc failed"); 1184 goto err_free_reuse_maps; 1185 } 1186 map_replace = new_map_replace; 1187 1188 map_replace[old_map_fds].idx = idx; 1189 map_replace[old_map_fds].name = name; 1190 map_replace[old_map_fds].fd = fd; 1191 old_map_fds++; 1192 } else if (is_prefix(*argv, "dev")) { 1193 NEXT_ARG(); 1194 1195 if (ifindex) { 1196 p_err("offload device already specified"); 1197 goto err_free_reuse_maps; 1198 } 1199 if (!REQ_ARGS(1)) 1200 goto err_free_reuse_maps; 1201 1202 ifindex = if_nametoindex(*argv); 1203 if (!ifindex) { 1204 p_err("unrecognized netdevice '%s': %s", 1205 *argv, strerror(errno)); 1206 goto err_free_reuse_maps; 1207 } 1208 NEXT_ARG(); 1209 } else if (is_prefix(*argv, "pinmaps")) { 1210 NEXT_ARG(); 1211 1212 if (!REQ_ARGS(1)) 1213 goto err_free_reuse_maps; 1214 1215 pinmaps = GET_ARG(); 1216 } else { 1217 p_err("expected no more arguments, 'type', 'map' or 'dev', got: '%s'?", 1218 *argv); 1219 goto err_free_reuse_maps; 1220 } 1221 } 1222 1223 set_max_rlimit(); 1224 1225 obj = __bpf_object__open_xattr(&open_attr, bpf_flags); 1226 if (IS_ERR_OR_NULL(obj)) { 1227 p_err("failed to open object file"); 1228 goto err_free_reuse_maps; 1229 } 1230 1231 bpf_object__for_each_program(pos, obj) { 1232 enum bpf_prog_type prog_type = open_attr.prog_type; 1233 1234 if (open_attr.prog_type == BPF_PROG_TYPE_UNSPEC) { 1235 const char *sec_name = bpf_program__title(pos, false); 1236 1237 err = libbpf_prog_type_by_name(sec_name, &prog_type, 1238 &expected_attach_type); 1239 if (err < 0) 1240 goto err_close_obj; 1241 } 1242 1243 bpf_program__set_ifindex(pos, ifindex); 1244 bpf_program__set_type(pos, prog_type); 1245 bpf_program__set_expected_attach_type(pos, expected_attach_type); 1246 } 1247 1248 qsort(map_replace, old_map_fds, sizeof(*map_replace), 1249 map_replace_compar); 1250 1251 /* After the sort maps by name will be first on the list, because they 1252 * have idx == -1. Resolve them. 1253 */ 1254 j = 0; 1255 while (j < old_map_fds && map_replace[j].name) { 1256 i = 0; 1257 bpf_object__for_each_map(map, obj) { 1258 if (!strcmp(bpf_map__name(map), map_replace[j].name)) { 1259 map_replace[j].idx = i; 1260 break; 1261 } 1262 i++; 1263 } 1264 if (map_replace[j].idx == -1) { 1265 p_err("unable to find map '%s'", map_replace[j].name); 1266 goto err_close_obj; 1267 } 1268 j++; 1269 } 1270 /* Resort if any names were resolved */ 1271 if (j) 1272 qsort(map_replace, old_map_fds, sizeof(*map_replace), 1273 map_replace_compar); 1274 1275 /* Set ifindex and name reuse */ 1276 j = 0; 1277 idx = 0; 1278 bpf_object__for_each_map(map, obj) { 1279 if (!bpf_map__is_offload_neutral(map)) 1280 bpf_map__set_ifindex(map, ifindex); 1281 1282 if (j < old_map_fds && idx == map_replace[j].idx) { 1283 err = bpf_map__reuse_fd(map, map_replace[j++].fd); 1284 if (err) { 1285 p_err("unable to set up map reuse: %d", err); 1286 goto err_close_obj; 1287 } 1288 1289 /* Next reuse wants to apply to the same map */ 1290 if (j < old_map_fds && map_replace[j].idx == idx) { 1291 p_err("replacement for map idx %d specified more than once", 1292 idx); 1293 goto err_close_obj; 1294 } 1295 } 1296 1297 idx++; 1298 } 1299 if (j < old_map_fds) { 1300 p_err("map idx '%d' not used", map_replace[j].idx); 1301 goto err_close_obj; 1302 } 1303 1304 load_attr.obj = obj; 1305 if (verifier_logs) 1306 /* log_level1 + log_level2 + stats, but not stable UAPI */ 1307 load_attr.log_level = 1 + 2 + 4; 1308 1309 err = bpf_object__load_xattr(&load_attr); 1310 if (err) { 1311 p_err("failed to load object file"); 1312 goto err_close_obj; 1313 } 1314 1315 err = mount_bpffs_for_pin(pinfile); 1316 if (err) 1317 goto err_close_obj; 1318 1319 if (first_prog_only) { 1320 prog = bpf_program__next(NULL, obj); 1321 if (!prog) { 1322 p_err("object file doesn't contain any bpf program"); 1323 goto err_close_obj; 1324 } 1325 1326 err = bpf_obj_pin(bpf_program__fd(prog), pinfile); 1327 if (err) { 1328 p_err("failed to pin program %s", 1329 bpf_program__title(prog, false)); 1330 goto err_close_obj; 1331 } 1332 } else { 1333 err = bpf_object__pin_programs(obj, pinfile); 1334 if (err) { 1335 p_err("failed to pin all programs"); 1336 goto err_close_obj; 1337 } 1338 } 1339 1340 if (pinmaps) { 1341 err = bpf_object__pin_maps(obj, pinmaps); 1342 if (err) { 1343 p_err("failed to pin all maps"); 1344 goto err_unpin; 1345 } 1346 } 1347 1348 if (json_output) 1349 jsonw_null(json_wtr); 1350 1351 bpf_object__close(obj); 1352 for (i = 0; i < old_map_fds; i++) 1353 close(map_replace[i].fd); 1354 free(map_replace); 1355 1356 return 0; 1357 1358 err_unpin: 1359 if (first_prog_only) 1360 unlink(pinfile); 1361 else 1362 bpf_object__unpin_programs(obj, pinfile); 1363 err_close_obj: 1364 bpf_object__close(obj); 1365 err_free_reuse_maps: 1366 for (i = 0; i < old_map_fds; i++) 1367 close(map_replace[i].fd); 1368 free(map_replace); 1369 return -1; 1370 } 1371 1372 static int do_load(int argc, char **argv) 1373 { 1374 return load_with_options(argc, argv, true); 1375 } 1376 1377 static int do_loadall(int argc, char **argv) 1378 { 1379 return load_with_options(argc, argv, false); 1380 } 1381 1382 static int do_help(int argc, char **argv) 1383 { 1384 if (json_output) { 1385 jsonw_null(json_wtr); 1386 return 0; 1387 } 1388 1389 fprintf(stderr, 1390 "Usage: %s %s { show | list } [PROG]\n" 1391 " %s %s dump xlated PROG [{ file FILE | opcodes | visual | linum }]\n" 1392 " %s %s dump jited PROG [{ file FILE | opcodes | linum }]\n" 1393 " %s %s pin PROG FILE\n" 1394 " %s %s { load | loadall } OBJ PATH \\\n" 1395 " [type TYPE] [dev NAME] \\\n" 1396 " [map { idx IDX | name NAME } MAP]\\\n" 1397 " [pinmaps MAP_DIR]\n" 1398 " %s %s attach PROG ATTACH_TYPE [MAP]\n" 1399 " %s %s detach PROG ATTACH_TYPE [MAP]\n" 1400 " %s %s run PROG \\\n" 1401 " data_in FILE \\\n" 1402 " [data_out FILE [data_size_out L]] \\\n" 1403 " [ctx_in FILE [ctx_out FILE [ctx_size_out M]]] \\\n" 1404 " [repeat N]\n" 1405 " %s %s tracelog\n" 1406 " %s %s help\n" 1407 "\n" 1408 " " HELP_SPEC_MAP "\n" 1409 " " HELP_SPEC_PROGRAM "\n" 1410 " TYPE := { socket | kprobe | kretprobe | classifier | action |\n" 1411 " tracepoint | raw_tracepoint | xdp | perf_event | cgroup/skb |\n" 1412 " cgroup/sock | cgroup/dev | lwt_in | lwt_out | lwt_xmit |\n" 1413 " lwt_seg6local | sockops | sk_skb | sk_msg | lirc_mode2 |\n" 1414 " sk_reuseport | flow_dissector | cgroup/sysctl |\n" 1415 " cgroup/bind4 | cgroup/bind6 | cgroup/post_bind4 |\n" 1416 " cgroup/post_bind6 | cgroup/connect4 | cgroup/connect6 |\n" 1417 " cgroup/sendmsg4 | cgroup/sendmsg6 | cgroup/recvmsg4 |\n" 1418 " cgroup/recvmsg6 | cgroup/getsockopt |\n" 1419 " cgroup/setsockopt }\n" 1420 " ATTACH_TYPE := { msg_verdict | stream_verdict | stream_parser |\n" 1421 " flow_dissector }\n" 1422 " " HELP_SPEC_OPTIONS "\n" 1423 "", 1424 bin_name, argv[-2], bin_name, argv[-2], bin_name, argv[-2], 1425 bin_name, argv[-2], bin_name, argv[-2], bin_name, argv[-2], 1426 bin_name, argv[-2], bin_name, argv[-2], bin_name, argv[-2], 1427 bin_name, argv[-2]); 1428 1429 return 0; 1430 } 1431 1432 static const struct cmd cmds[] = { 1433 { "show", do_show }, 1434 { "list", do_show }, 1435 { "help", do_help }, 1436 { "dump", do_dump }, 1437 { "pin", do_pin }, 1438 { "load", do_load }, 1439 { "loadall", do_loadall }, 1440 { "attach", do_attach }, 1441 { "detach", do_detach }, 1442 { "tracelog", do_tracelog }, 1443 { "run", do_run }, 1444 { 0 } 1445 }; 1446 1447 int do_prog(int argc, char **argv) 1448 { 1449 return cmd_select(cmds, argc, argv, do_help); 1450 } 1451