1 /* 2 * Copyright (C) 2017-2018 Netronome Systems, Inc. 3 * 4 * This software is dual licensed under the GNU General License Version 2, 5 * June 1991 as shown in the file COPYING in the top-level directory of this 6 * source tree or the BSD 2-Clause License provided below. You have the 7 * option to license this software under the complete terms of either license. 8 * 9 * The BSD 2-Clause License: 10 * 11 * Redistribution and use in source and binary forms, with or 12 * without modification, are permitted provided that the following 13 * conditions are met: 14 * 15 * 1. Redistributions of source code must retain the above 16 * copyright notice, this list of conditions and the following 17 * disclaimer. 18 * 19 * 2. Redistributions in binary form must reproduce the above 20 * copyright notice, this list of conditions and the following 21 * disclaimer in the documentation and/or other materials 22 * provided with the distribution. 23 * 24 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 25 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 26 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 27 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 28 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 29 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 30 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 31 * SOFTWARE. 32 */ 33 34 #define _GNU_SOURCE 35 #include <errno.h> 36 #include <fcntl.h> 37 #include <stdarg.h> 38 #include <stdio.h> 39 #include <stdlib.h> 40 #include <string.h> 41 #include <time.h> 42 #include <unistd.h> 43 #include <net/if.h> 44 #include <sys/types.h> 45 #include <sys/stat.h> 46 47 #include <linux/err.h> 48 49 #include <bpf.h> 50 #include <libbpf.h> 51 52 #include "cfg.h" 53 #include "main.h" 54 #include "xlated_dumper.h" 55 56 static const char * const prog_type_name[] = { 57 [BPF_PROG_TYPE_UNSPEC] = "unspec", 58 [BPF_PROG_TYPE_SOCKET_FILTER] = "socket_filter", 59 [BPF_PROG_TYPE_KPROBE] = "kprobe", 60 [BPF_PROG_TYPE_SCHED_CLS] = "sched_cls", 61 [BPF_PROG_TYPE_SCHED_ACT] = "sched_act", 62 [BPF_PROG_TYPE_TRACEPOINT] = "tracepoint", 63 [BPF_PROG_TYPE_XDP] = "xdp", 64 [BPF_PROG_TYPE_PERF_EVENT] = "perf_event", 65 [BPF_PROG_TYPE_CGROUP_SKB] = "cgroup_skb", 66 [BPF_PROG_TYPE_CGROUP_SOCK] = "cgroup_sock", 67 [BPF_PROG_TYPE_LWT_IN] = "lwt_in", 68 [BPF_PROG_TYPE_LWT_OUT] = "lwt_out", 69 [BPF_PROG_TYPE_LWT_XMIT] = "lwt_xmit", 70 [BPF_PROG_TYPE_SOCK_OPS] = "sock_ops", 71 [BPF_PROG_TYPE_SK_SKB] = "sk_skb", 72 [BPF_PROG_TYPE_CGROUP_DEVICE] = "cgroup_device", 73 [BPF_PROG_TYPE_SK_MSG] = "sk_msg", 74 [BPF_PROG_TYPE_RAW_TRACEPOINT] = "raw_tracepoint", 75 [BPF_PROG_TYPE_CGROUP_SOCK_ADDR] = "cgroup_sock_addr", 76 [BPF_PROG_TYPE_LIRC_MODE2] = "lirc_mode2", 77 [BPF_PROG_TYPE_FLOW_DISSECTOR] = "flow_dissector", 78 }; 79 80 static void print_boot_time(__u64 nsecs, char *buf, unsigned int size) 81 { 82 struct timespec real_time_ts, boot_time_ts; 83 time_t wallclock_secs; 84 struct tm load_tm; 85 86 buf[--size] = '\0'; 87 88 if (clock_gettime(CLOCK_REALTIME, &real_time_ts) || 89 clock_gettime(CLOCK_BOOTTIME, &boot_time_ts)) { 90 perror("Can't read clocks"); 91 snprintf(buf, size, "%llu", nsecs / 1000000000); 92 return; 93 } 94 95 wallclock_secs = (real_time_ts.tv_sec - boot_time_ts.tv_sec) + 96 (real_time_ts.tv_nsec - boot_time_ts.tv_nsec + nsecs) / 97 1000000000; 98 99 100 if (!localtime_r(&wallclock_secs, &load_tm)) { 101 snprintf(buf, size, "%llu", nsecs / 1000000000); 102 return; 103 } 104 105 if (json_output) 106 strftime(buf, size, "%s", &load_tm); 107 else 108 strftime(buf, size, "%FT%T%z", &load_tm); 109 } 110 111 static int prog_fd_by_tag(unsigned char *tag) 112 { 113 struct bpf_prog_info info = {}; 114 __u32 len = sizeof(info); 115 unsigned int id = 0; 116 int err; 117 int fd; 118 119 while (true) { 120 err = bpf_prog_get_next_id(id, &id); 121 if (err) { 122 p_err("%s", strerror(errno)); 123 return -1; 124 } 125 126 fd = bpf_prog_get_fd_by_id(id); 127 if (fd < 0) { 128 p_err("can't get prog by id (%u): %s", 129 id, strerror(errno)); 130 return -1; 131 } 132 133 err = bpf_obj_get_info_by_fd(fd, &info, &len); 134 if (err) { 135 p_err("can't get prog info (%u): %s", 136 id, strerror(errno)); 137 close(fd); 138 return -1; 139 } 140 141 if (!memcmp(tag, info.tag, BPF_TAG_SIZE)) 142 return fd; 143 144 close(fd); 145 } 146 } 147 148 int prog_parse_fd(int *argc, char ***argv) 149 { 150 int fd; 151 152 if (is_prefix(**argv, "id")) { 153 unsigned int id; 154 char *endptr; 155 156 NEXT_ARGP(); 157 158 id = strtoul(**argv, &endptr, 0); 159 if (*endptr) { 160 p_err("can't parse %s as ID", **argv); 161 return -1; 162 } 163 NEXT_ARGP(); 164 165 fd = bpf_prog_get_fd_by_id(id); 166 if (fd < 0) 167 p_err("get by id (%u): %s", id, strerror(errno)); 168 return fd; 169 } else if (is_prefix(**argv, "tag")) { 170 unsigned char tag[BPF_TAG_SIZE]; 171 172 NEXT_ARGP(); 173 174 if (sscanf(**argv, BPF_TAG_FMT, tag, tag + 1, tag + 2, 175 tag + 3, tag + 4, tag + 5, tag + 6, tag + 7) 176 != BPF_TAG_SIZE) { 177 p_err("can't parse tag"); 178 return -1; 179 } 180 NEXT_ARGP(); 181 182 return prog_fd_by_tag(tag); 183 } else if (is_prefix(**argv, "pinned")) { 184 char *path; 185 186 NEXT_ARGP(); 187 188 path = **argv; 189 NEXT_ARGP(); 190 191 return open_obj_pinned_any(path, BPF_OBJ_PROG); 192 } 193 194 p_err("expected 'id', 'tag' or 'pinned', got: '%s'?", **argv); 195 return -1; 196 } 197 198 static void show_prog_maps(int fd, u32 num_maps) 199 { 200 struct bpf_prog_info info = {}; 201 __u32 len = sizeof(info); 202 __u32 map_ids[num_maps]; 203 unsigned int i; 204 int err; 205 206 info.nr_map_ids = num_maps; 207 info.map_ids = ptr_to_u64(map_ids); 208 209 err = bpf_obj_get_info_by_fd(fd, &info, &len); 210 if (err || !info.nr_map_ids) 211 return; 212 213 if (json_output) { 214 jsonw_name(json_wtr, "map_ids"); 215 jsonw_start_array(json_wtr); 216 for (i = 0; i < info.nr_map_ids; i++) 217 jsonw_uint(json_wtr, map_ids[i]); 218 jsonw_end_array(json_wtr); 219 } else { 220 printf(" map_ids "); 221 for (i = 0; i < info.nr_map_ids; i++) 222 printf("%u%s", map_ids[i], 223 i == info.nr_map_ids - 1 ? "" : ","); 224 } 225 } 226 227 static void print_prog_json(struct bpf_prog_info *info, int fd) 228 { 229 char *memlock; 230 231 jsonw_start_object(json_wtr); 232 jsonw_uint_field(json_wtr, "id", info->id); 233 if (info->type < ARRAY_SIZE(prog_type_name)) 234 jsonw_string_field(json_wtr, "type", 235 prog_type_name[info->type]); 236 else 237 jsonw_uint_field(json_wtr, "type", info->type); 238 239 if (*info->name) 240 jsonw_string_field(json_wtr, "name", info->name); 241 242 jsonw_name(json_wtr, "tag"); 243 jsonw_printf(json_wtr, "\"" BPF_TAG_FMT "\"", 244 info->tag[0], info->tag[1], info->tag[2], info->tag[3], 245 info->tag[4], info->tag[5], info->tag[6], info->tag[7]); 246 247 jsonw_bool_field(json_wtr, "gpl_compatible", info->gpl_compatible); 248 249 print_dev_json(info->ifindex, info->netns_dev, info->netns_ino); 250 251 if (info->load_time) { 252 char buf[32]; 253 254 print_boot_time(info->load_time, buf, sizeof(buf)); 255 256 /* Piggy back on load_time, since 0 uid is a valid one */ 257 jsonw_name(json_wtr, "loaded_at"); 258 jsonw_printf(json_wtr, "%s", buf); 259 jsonw_uint_field(json_wtr, "uid", info->created_by_uid); 260 } 261 262 jsonw_uint_field(json_wtr, "bytes_xlated", info->xlated_prog_len); 263 264 if (info->jited_prog_len) { 265 jsonw_bool_field(json_wtr, "jited", true); 266 jsonw_uint_field(json_wtr, "bytes_jited", info->jited_prog_len); 267 } else { 268 jsonw_bool_field(json_wtr, "jited", false); 269 } 270 271 memlock = get_fdinfo(fd, "memlock"); 272 if (memlock) 273 jsonw_int_field(json_wtr, "bytes_memlock", atoi(memlock)); 274 free(memlock); 275 276 if (info->nr_map_ids) 277 show_prog_maps(fd, info->nr_map_ids); 278 279 if (!hash_empty(prog_table.table)) { 280 struct pinned_obj *obj; 281 282 jsonw_name(json_wtr, "pinned"); 283 jsonw_start_array(json_wtr); 284 hash_for_each_possible(prog_table.table, obj, hash, info->id) { 285 if (obj->id == info->id) 286 jsonw_string(json_wtr, obj->path); 287 } 288 jsonw_end_array(json_wtr); 289 } 290 291 jsonw_end_object(json_wtr); 292 } 293 294 static void print_prog_plain(struct bpf_prog_info *info, int fd) 295 { 296 char *memlock; 297 298 printf("%u: ", info->id); 299 if (info->type < ARRAY_SIZE(prog_type_name)) 300 printf("%s ", prog_type_name[info->type]); 301 else 302 printf("type %u ", info->type); 303 304 if (*info->name) 305 printf("name %s ", info->name); 306 307 printf("tag "); 308 fprint_hex(stdout, info->tag, BPF_TAG_SIZE, ""); 309 print_dev_plain(info->ifindex, info->netns_dev, info->netns_ino); 310 printf("%s", info->gpl_compatible ? " gpl" : ""); 311 printf("\n"); 312 313 if (info->load_time) { 314 char buf[32]; 315 316 print_boot_time(info->load_time, buf, sizeof(buf)); 317 318 /* Piggy back on load_time, since 0 uid is a valid one */ 319 printf("\tloaded_at %s uid %u\n", buf, info->created_by_uid); 320 } 321 322 printf("\txlated %uB", info->xlated_prog_len); 323 324 if (info->jited_prog_len) 325 printf(" jited %uB", info->jited_prog_len); 326 else 327 printf(" not jited"); 328 329 memlock = get_fdinfo(fd, "memlock"); 330 if (memlock) 331 printf(" memlock %sB", memlock); 332 free(memlock); 333 334 if (info->nr_map_ids) 335 show_prog_maps(fd, info->nr_map_ids); 336 337 if (!hash_empty(prog_table.table)) { 338 struct pinned_obj *obj; 339 340 printf("\n"); 341 hash_for_each_possible(prog_table.table, obj, hash, info->id) { 342 if (obj->id == info->id) 343 printf("\tpinned %s\n", obj->path); 344 } 345 } 346 347 printf("\n"); 348 } 349 350 static int show_prog(int fd) 351 { 352 struct bpf_prog_info info = {}; 353 __u32 len = sizeof(info); 354 int err; 355 356 err = bpf_obj_get_info_by_fd(fd, &info, &len); 357 if (err) { 358 p_err("can't get prog info: %s", strerror(errno)); 359 return -1; 360 } 361 362 if (json_output) 363 print_prog_json(&info, fd); 364 else 365 print_prog_plain(&info, fd); 366 367 return 0; 368 } 369 370 static int do_show(int argc, char **argv) 371 { 372 __u32 id = 0; 373 int err; 374 int fd; 375 376 if (show_pinned) 377 build_pinned_obj_table(&prog_table, BPF_OBJ_PROG); 378 379 if (argc == 2) { 380 fd = prog_parse_fd(&argc, &argv); 381 if (fd < 0) 382 return -1; 383 384 return show_prog(fd); 385 } 386 387 if (argc) 388 return BAD_ARG(); 389 390 if (json_output) 391 jsonw_start_array(json_wtr); 392 while (true) { 393 err = bpf_prog_get_next_id(id, &id); 394 if (err) { 395 if (errno == ENOENT) { 396 err = 0; 397 break; 398 } 399 p_err("can't get next program: %s%s", strerror(errno), 400 errno == EINVAL ? " -- kernel too old?" : ""); 401 err = -1; 402 break; 403 } 404 405 fd = bpf_prog_get_fd_by_id(id); 406 if (fd < 0) { 407 if (errno == ENOENT) 408 continue; 409 p_err("can't get prog by id (%u): %s", 410 id, strerror(errno)); 411 err = -1; 412 break; 413 } 414 415 err = show_prog(fd); 416 close(fd); 417 if (err) 418 break; 419 } 420 421 if (json_output) 422 jsonw_end_array(json_wtr); 423 424 return err; 425 } 426 427 static int do_dump(int argc, char **argv) 428 { 429 unsigned long *func_ksyms = NULL; 430 struct bpf_prog_info info = {}; 431 unsigned int *func_lens = NULL; 432 unsigned int nr_func_ksyms; 433 unsigned int nr_func_lens; 434 struct dump_data dd = {}; 435 __u32 len = sizeof(info); 436 unsigned int buf_size; 437 char *filepath = NULL; 438 bool opcodes = false; 439 bool visual = false; 440 unsigned char *buf; 441 __u32 *member_len; 442 __u64 *member_ptr; 443 ssize_t n; 444 int err; 445 int fd; 446 447 if (is_prefix(*argv, "jited")) { 448 member_len = &info.jited_prog_len; 449 member_ptr = &info.jited_prog_insns; 450 } else if (is_prefix(*argv, "xlated")) { 451 member_len = &info.xlated_prog_len; 452 member_ptr = &info.xlated_prog_insns; 453 } else { 454 p_err("expected 'xlated' or 'jited', got: %s", *argv); 455 return -1; 456 } 457 NEXT_ARG(); 458 459 if (argc < 2) 460 usage(); 461 462 fd = prog_parse_fd(&argc, &argv); 463 if (fd < 0) 464 return -1; 465 466 if (is_prefix(*argv, "file")) { 467 NEXT_ARG(); 468 if (!argc) { 469 p_err("expected file path"); 470 return -1; 471 } 472 473 filepath = *argv; 474 NEXT_ARG(); 475 } else if (is_prefix(*argv, "opcodes")) { 476 opcodes = true; 477 NEXT_ARG(); 478 } else if (is_prefix(*argv, "visual")) { 479 visual = true; 480 NEXT_ARG(); 481 } 482 483 if (argc) { 484 usage(); 485 return -1; 486 } 487 488 err = bpf_obj_get_info_by_fd(fd, &info, &len); 489 if (err) { 490 p_err("can't get prog info: %s", strerror(errno)); 491 return -1; 492 } 493 494 if (!*member_len) { 495 p_info("no instructions returned"); 496 close(fd); 497 return 0; 498 } 499 500 buf_size = *member_len; 501 502 buf = malloc(buf_size); 503 if (!buf) { 504 p_err("mem alloc failed"); 505 close(fd); 506 return -1; 507 } 508 509 nr_func_ksyms = info.nr_jited_ksyms; 510 if (nr_func_ksyms) { 511 func_ksyms = malloc(nr_func_ksyms * sizeof(__u64)); 512 if (!func_ksyms) { 513 p_err("mem alloc failed"); 514 close(fd); 515 goto err_free; 516 } 517 } 518 519 nr_func_lens = info.nr_jited_func_lens; 520 if (nr_func_lens) { 521 func_lens = malloc(nr_func_lens * sizeof(__u32)); 522 if (!func_lens) { 523 p_err("mem alloc failed"); 524 close(fd); 525 goto err_free; 526 } 527 } 528 529 memset(&info, 0, sizeof(info)); 530 531 *member_ptr = ptr_to_u64(buf); 532 *member_len = buf_size; 533 info.jited_ksyms = ptr_to_u64(func_ksyms); 534 info.nr_jited_ksyms = nr_func_ksyms; 535 info.jited_func_lens = ptr_to_u64(func_lens); 536 info.nr_jited_func_lens = nr_func_lens; 537 538 err = bpf_obj_get_info_by_fd(fd, &info, &len); 539 close(fd); 540 if (err) { 541 p_err("can't get prog info: %s", strerror(errno)); 542 goto err_free; 543 } 544 545 if (*member_len > buf_size) { 546 p_err("too many instructions returned"); 547 goto err_free; 548 } 549 550 if (info.nr_jited_ksyms > nr_func_ksyms) { 551 p_err("too many addresses returned"); 552 goto err_free; 553 } 554 555 if (info.nr_jited_func_lens > nr_func_lens) { 556 p_err("too many values returned"); 557 goto err_free; 558 } 559 560 if ((member_len == &info.jited_prog_len && 561 info.jited_prog_insns == 0) || 562 (member_len == &info.xlated_prog_len && 563 info.xlated_prog_insns == 0)) { 564 p_err("error retrieving insn dump: kernel.kptr_restrict set?"); 565 goto err_free; 566 } 567 568 if (filepath) { 569 fd = open(filepath, O_WRONLY | O_CREAT | O_TRUNC, 0600); 570 if (fd < 0) { 571 p_err("can't open file %s: %s", filepath, 572 strerror(errno)); 573 goto err_free; 574 } 575 576 n = write(fd, buf, *member_len); 577 close(fd); 578 if (n != *member_len) { 579 p_err("error writing output file: %s", 580 n < 0 ? strerror(errno) : "short write"); 581 goto err_free; 582 } 583 584 if (json_output) 585 jsonw_null(json_wtr); 586 } else if (member_len == &info.jited_prog_len) { 587 const char *name = NULL; 588 589 if (info.ifindex) { 590 name = ifindex_to_bfd_name_ns(info.ifindex, 591 info.netns_dev, 592 info.netns_ino); 593 if (!name) 594 goto err_free; 595 } 596 597 if (info.nr_jited_func_lens && info.jited_func_lens) { 598 struct kernel_sym *sym = NULL; 599 char sym_name[SYM_MAX_NAME]; 600 unsigned char *img = buf; 601 __u64 *ksyms = NULL; 602 __u32 *lens; 603 __u32 i; 604 605 if (info.nr_jited_ksyms) { 606 kernel_syms_load(&dd); 607 ksyms = (__u64 *) info.jited_ksyms; 608 } 609 610 if (json_output) 611 jsonw_start_array(json_wtr); 612 613 lens = (__u32 *) info.jited_func_lens; 614 for (i = 0; i < info.nr_jited_func_lens; i++) { 615 if (ksyms) { 616 sym = kernel_syms_search(&dd, ksyms[i]); 617 if (sym) 618 sprintf(sym_name, "%s", sym->name); 619 else 620 sprintf(sym_name, "0x%016llx", ksyms[i]); 621 } else { 622 strcpy(sym_name, "unknown"); 623 } 624 625 if (json_output) { 626 jsonw_start_object(json_wtr); 627 jsonw_name(json_wtr, "name"); 628 jsonw_string(json_wtr, sym_name); 629 jsonw_name(json_wtr, "insns"); 630 } else { 631 printf("%s:\n", sym_name); 632 } 633 634 disasm_print_insn(img, lens[i], opcodes, name); 635 img += lens[i]; 636 637 if (json_output) 638 jsonw_end_object(json_wtr); 639 else 640 printf("\n"); 641 } 642 643 if (json_output) 644 jsonw_end_array(json_wtr); 645 } else { 646 disasm_print_insn(buf, *member_len, opcodes, name); 647 } 648 } else if (visual) { 649 if (json_output) 650 jsonw_null(json_wtr); 651 else 652 dump_xlated_cfg(buf, *member_len); 653 } else { 654 kernel_syms_load(&dd); 655 dd.nr_jited_ksyms = info.nr_jited_ksyms; 656 dd.jited_ksyms = (__u64 *) info.jited_ksyms; 657 658 if (json_output) 659 dump_xlated_json(&dd, buf, *member_len, opcodes); 660 else 661 dump_xlated_plain(&dd, buf, *member_len, opcodes); 662 kernel_syms_destroy(&dd); 663 } 664 665 free(buf); 666 free(func_ksyms); 667 free(func_lens); 668 return 0; 669 670 err_free: 671 free(buf); 672 free(func_ksyms); 673 free(func_lens); 674 return -1; 675 } 676 677 static int do_pin(int argc, char **argv) 678 { 679 int err; 680 681 err = do_pin_any(argc, argv, bpf_prog_get_fd_by_id); 682 if (!err && json_output) 683 jsonw_null(json_wtr); 684 return err; 685 } 686 687 struct map_replace { 688 int idx; 689 int fd; 690 char *name; 691 }; 692 693 int map_replace_compar(const void *p1, const void *p2) 694 { 695 const struct map_replace *a = p1, *b = p2; 696 697 return a->idx - b->idx; 698 } 699 700 static int do_load(int argc, char **argv) 701 { 702 enum bpf_attach_type expected_attach_type; 703 struct bpf_object_open_attr attr = { 704 .prog_type = BPF_PROG_TYPE_UNSPEC, 705 }; 706 struct map_replace *map_replace = NULL; 707 unsigned int old_map_fds = 0; 708 struct bpf_program *prog; 709 struct bpf_object *obj; 710 struct bpf_map *map; 711 const char *pinfile; 712 unsigned int i, j; 713 __u32 ifindex = 0; 714 int idx, err; 715 716 if (!REQ_ARGS(2)) 717 return -1; 718 attr.file = GET_ARG(); 719 pinfile = GET_ARG(); 720 721 while (argc) { 722 if (is_prefix(*argv, "type")) { 723 char *type; 724 725 NEXT_ARG(); 726 727 if (attr.prog_type != BPF_PROG_TYPE_UNSPEC) { 728 p_err("program type already specified"); 729 goto err_free_reuse_maps; 730 } 731 if (!REQ_ARGS(1)) 732 goto err_free_reuse_maps; 733 734 /* Put a '/' at the end of type to appease libbpf */ 735 type = malloc(strlen(*argv) + 2); 736 if (!type) { 737 p_err("mem alloc failed"); 738 goto err_free_reuse_maps; 739 } 740 *type = 0; 741 strcat(type, *argv); 742 strcat(type, "/"); 743 744 err = libbpf_prog_type_by_name(type, &attr.prog_type, 745 &expected_attach_type); 746 free(type); 747 if (err < 0) { 748 p_err("unknown program type '%s'", *argv); 749 goto err_free_reuse_maps; 750 } 751 NEXT_ARG(); 752 } else if (is_prefix(*argv, "map")) { 753 char *endptr, *name; 754 int fd; 755 756 NEXT_ARG(); 757 758 if (!REQ_ARGS(4)) 759 goto err_free_reuse_maps; 760 761 if (is_prefix(*argv, "idx")) { 762 NEXT_ARG(); 763 764 idx = strtoul(*argv, &endptr, 0); 765 if (*endptr) { 766 p_err("can't parse %s as IDX", *argv); 767 goto err_free_reuse_maps; 768 } 769 name = NULL; 770 } else if (is_prefix(*argv, "name")) { 771 NEXT_ARG(); 772 773 name = *argv; 774 idx = -1; 775 } else { 776 p_err("expected 'idx' or 'name', got: '%s'?", 777 *argv); 778 goto err_free_reuse_maps; 779 } 780 NEXT_ARG(); 781 782 fd = map_parse_fd(&argc, &argv); 783 if (fd < 0) 784 goto err_free_reuse_maps; 785 786 map_replace = reallocarray(map_replace, old_map_fds + 1, 787 sizeof(*map_replace)); 788 if (!map_replace) { 789 p_err("mem alloc failed"); 790 goto err_free_reuse_maps; 791 } 792 map_replace[old_map_fds].idx = idx; 793 map_replace[old_map_fds].name = name; 794 map_replace[old_map_fds].fd = fd; 795 old_map_fds++; 796 } else if (is_prefix(*argv, "dev")) { 797 NEXT_ARG(); 798 799 if (ifindex) { 800 p_err("offload device already specified"); 801 goto err_free_reuse_maps; 802 } 803 if (!REQ_ARGS(1)) 804 goto err_free_reuse_maps; 805 806 ifindex = if_nametoindex(*argv); 807 if (!ifindex) { 808 p_err("unrecognized netdevice '%s': %s", 809 *argv, strerror(errno)); 810 goto err_free_reuse_maps; 811 } 812 NEXT_ARG(); 813 } else { 814 p_err("expected no more arguments, 'type', 'map' or 'dev', got: '%s'?", 815 *argv); 816 goto err_free_reuse_maps; 817 } 818 } 819 820 obj = bpf_object__open_xattr(&attr); 821 if (IS_ERR_OR_NULL(obj)) { 822 p_err("failed to open object file"); 823 goto err_free_reuse_maps; 824 } 825 826 prog = bpf_program__next(NULL, obj); 827 if (!prog) { 828 p_err("object file doesn't contain any bpf program"); 829 goto err_close_obj; 830 } 831 832 bpf_program__set_ifindex(prog, ifindex); 833 if (attr.prog_type == BPF_PROG_TYPE_UNSPEC) { 834 const char *sec_name = bpf_program__title(prog, false); 835 836 err = libbpf_prog_type_by_name(sec_name, &attr.prog_type, 837 &expected_attach_type); 838 if (err < 0) { 839 p_err("failed to guess program type based on section name %s\n", 840 sec_name); 841 goto err_close_obj; 842 } 843 } 844 bpf_program__set_type(prog, attr.prog_type); 845 bpf_program__set_expected_attach_type(prog, expected_attach_type); 846 847 qsort(map_replace, old_map_fds, sizeof(*map_replace), 848 map_replace_compar); 849 850 /* After the sort maps by name will be first on the list, because they 851 * have idx == -1. Resolve them. 852 */ 853 j = 0; 854 while (j < old_map_fds && map_replace[j].name) { 855 i = 0; 856 bpf_map__for_each(map, obj) { 857 if (!strcmp(bpf_map__name(map), map_replace[j].name)) { 858 map_replace[j].idx = i; 859 break; 860 } 861 i++; 862 } 863 if (map_replace[j].idx == -1) { 864 p_err("unable to find map '%s'", map_replace[j].name); 865 goto err_close_obj; 866 } 867 j++; 868 } 869 /* Resort if any names were resolved */ 870 if (j) 871 qsort(map_replace, old_map_fds, sizeof(*map_replace), 872 map_replace_compar); 873 874 /* Set ifindex and name reuse */ 875 j = 0; 876 idx = 0; 877 bpf_map__for_each(map, obj) { 878 if (!bpf_map__is_offload_neutral(map)) 879 bpf_map__set_ifindex(map, ifindex); 880 881 if (j < old_map_fds && idx == map_replace[j].idx) { 882 err = bpf_map__reuse_fd(map, map_replace[j++].fd); 883 if (err) { 884 p_err("unable to set up map reuse: %d", err); 885 goto err_close_obj; 886 } 887 888 /* Next reuse wants to apply to the same map */ 889 if (j < old_map_fds && map_replace[j].idx == idx) { 890 p_err("replacement for map idx %d specified more than once", 891 idx); 892 goto err_close_obj; 893 } 894 } 895 896 idx++; 897 } 898 if (j < old_map_fds) { 899 p_err("map idx '%d' not used", map_replace[j].idx); 900 goto err_close_obj; 901 } 902 903 err = bpf_object__load(obj); 904 if (err) { 905 p_err("failed to load object file"); 906 goto err_close_obj; 907 } 908 909 if (do_pin_fd(bpf_program__fd(prog), pinfile)) 910 goto err_close_obj; 911 912 if (json_output) 913 jsonw_null(json_wtr); 914 915 bpf_object__close(obj); 916 for (i = 0; i < old_map_fds; i++) 917 close(map_replace[i].fd); 918 free(map_replace); 919 920 return 0; 921 922 err_close_obj: 923 bpf_object__close(obj); 924 err_free_reuse_maps: 925 for (i = 0; i < old_map_fds; i++) 926 close(map_replace[i].fd); 927 free(map_replace); 928 return -1; 929 } 930 931 static int do_help(int argc, char **argv) 932 { 933 if (json_output) { 934 jsonw_null(json_wtr); 935 return 0; 936 } 937 938 fprintf(stderr, 939 "Usage: %s %s { show | list } [PROG]\n" 940 " %s %s dump xlated PROG [{ file FILE | opcodes | visual }]\n" 941 " %s %s dump jited PROG [{ file FILE | opcodes }]\n" 942 " %s %s pin PROG FILE\n" 943 " %s %s load OBJ FILE [type TYPE] [dev NAME] \\\n" 944 " [map { idx IDX | name NAME } MAP]\n" 945 " %s %s help\n" 946 "\n" 947 " " HELP_SPEC_MAP "\n" 948 " " HELP_SPEC_PROGRAM "\n" 949 " TYPE := { socket | kprobe | kretprobe | classifier | action |\n" 950 " tracepoint | raw_tracepoint | xdp | perf_event | cgroup/skb |\n" 951 " cgroup/sock | cgroup/dev | lwt_in | lwt_out | lwt_xmit |\n" 952 " lwt_seg6local | sockops | sk_skb | sk_msg | lirc_mode2 |\n" 953 " cgroup/bind4 | cgroup/bind6 | cgroup/post_bind4 |\n" 954 " cgroup/post_bind6 | cgroup/connect4 | cgroup/connect6 |\n" 955 " cgroup/sendmsg4 | cgroup/sendmsg6 }\n" 956 " " HELP_SPEC_OPTIONS "\n" 957 "", 958 bin_name, argv[-2], bin_name, argv[-2], bin_name, argv[-2], 959 bin_name, argv[-2], bin_name, argv[-2], bin_name, argv[-2]); 960 961 return 0; 962 } 963 964 static const struct cmd cmds[] = { 965 { "show", do_show }, 966 { "list", do_show }, 967 { "help", do_help }, 968 { "dump", do_dump }, 969 { "pin", do_pin }, 970 { "load", do_load }, 971 { 0 } 972 }; 973 974 int do_prog(int argc, char **argv) 975 { 976 return cmd_select(cmds, argc, argv, do_help); 977 } 978