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