| .. | .. |
|---|
| 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 | | - */ |
|---|
| 1 | +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) |
|---|
| 2 | +/* Copyright (C) 2017-2018 Netronome Systems, Inc. */ |
|---|
| 33 | 3 | |
|---|
| 34 | | -#include <bfd.h> |
|---|
| 35 | 4 | #include <ctype.h> |
|---|
| 36 | 5 | #include <errno.h> |
|---|
| 37 | 6 | #include <getopt.h> |
|---|
| .. | .. |
|---|
| 40 | 9 | #include <stdlib.h> |
|---|
| 41 | 10 | #include <string.h> |
|---|
| 42 | 11 | |
|---|
| 43 | | -#include <bpf.h> |
|---|
| 12 | +#include <bpf/bpf.h> |
|---|
| 13 | +#include <bpf/libbpf.h> |
|---|
| 44 | 14 | |
|---|
| 45 | 15 | #include "main.h" |
|---|
| 46 | 16 | |
|---|
| .. | .. |
|---|
| 55 | 25 | bool pretty_output; |
|---|
| 56 | 26 | bool json_output; |
|---|
| 57 | 27 | bool show_pinned; |
|---|
| 28 | +bool block_mount; |
|---|
| 29 | +bool verifier_logs; |
|---|
| 30 | +bool relaxed_maps; |
|---|
| 58 | 31 | struct pinned_obj_table prog_table; |
|---|
| 59 | 32 | struct pinned_obj_table map_table; |
|---|
| 33 | +struct pinned_obj_table link_table; |
|---|
| 34 | +struct obj_refs_table refs_table; |
|---|
| 60 | 35 | |
|---|
| 61 | 36 | static void __noreturn clean_and_exit(int i) |
|---|
| 62 | 37 | { |
|---|
| .. | .. |
|---|
| 85 | 60 | " %s batch file FILE\n" |
|---|
| 86 | 61 | " %s version\n" |
|---|
| 87 | 62 | "\n" |
|---|
| 88 | | - " OBJECT := { prog | map | cgroup | perf }\n" |
|---|
| 63 | + " OBJECT := { prog | map | link | cgroup | perf | net | feature | btf | gen | struct_ops | iter }\n" |
|---|
| 89 | 64 | " " HELP_SPEC_OPTIONS "\n" |
|---|
| 90 | 65 | "", |
|---|
| 91 | 66 | bin_name, bin_name, bin_name); |
|---|
| .. | .. |
|---|
| 95 | 70 | |
|---|
| 96 | 71 | static int do_version(int argc, char **argv) |
|---|
| 97 | 72 | { |
|---|
| 73 | +#ifdef HAVE_LIBBFD_SUPPORT |
|---|
| 74 | + const bool has_libbfd = true; |
|---|
| 75 | +#else |
|---|
| 76 | + const bool has_libbfd = false; |
|---|
| 77 | +#endif |
|---|
| 78 | +#ifdef BPFTOOL_WITHOUT_SKELETONS |
|---|
| 79 | + const bool has_skeletons = false; |
|---|
| 80 | +#else |
|---|
| 81 | + const bool has_skeletons = true; |
|---|
| 82 | +#endif |
|---|
| 83 | + |
|---|
| 98 | 84 | if (json_output) { |
|---|
| 99 | | - jsonw_start_object(json_wtr); |
|---|
| 85 | + jsonw_start_object(json_wtr); /* root object */ |
|---|
| 86 | + |
|---|
| 100 | 87 | jsonw_name(json_wtr, "version"); |
|---|
| 101 | 88 | jsonw_printf(json_wtr, "\"%s\"", BPFTOOL_VERSION); |
|---|
| 102 | | - jsonw_end_object(json_wtr); |
|---|
| 89 | + |
|---|
| 90 | + jsonw_name(json_wtr, "features"); |
|---|
| 91 | + jsonw_start_object(json_wtr); /* features */ |
|---|
| 92 | + jsonw_bool_field(json_wtr, "libbfd", has_libbfd); |
|---|
| 93 | + jsonw_bool_field(json_wtr, "skeletons", has_skeletons); |
|---|
| 94 | + jsonw_end_object(json_wtr); /* features */ |
|---|
| 95 | + |
|---|
| 96 | + jsonw_end_object(json_wtr); /* root object */ |
|---|
| 103 | 97 | } else { |
|---|
| 98 | + unsigned int nb_features = 0; |
|---|
| 99 | + |
|---|
| 104 | 100 | printf("%s v%s\n", bin_name, BPFTOOL_VERSION); |
|---|
| 101 | + printf("features:"); |
|---|
| 102 | + if (has_libbfd) { |
|---|
| 103 | + printf(" libbfd"); |
|---|
| 104 | + nb_features++; |
|---|
| 105 | + } |
|---|
| 106 | + if (has_skeletons) |
|---|
| 107 | + printf("%s skeletons", nb_features++ ? "," : ""); |
|---|
| 108 | + printf("\n"); |
|---|
| 105 | 109 | } |
|---|
| 106 | 110 | return 0; |
|---|
| 107 | 111 | } |
|---|
| .. | .. |
|---|
| 118 | 122 | if (argc < 1 && cmds[0].func) |
|---|
| 119 | 123 | return cmds[0].func(argc, argv); |
|---|
| 120 | 124 | |
|---|
| 121 | | - for (i = 0; cmds[i].func; i++) |
|---|
| 122 | | - if (is_prefix(*argv, cmds[i].cmd)) |
|---|
| 125 | + for (i = 0; cmds[i].cmd; i++) { |
|---|
| 126 | + if (is_prefix(*argv, cmds[i].cmd)) { |
|---|
| 127 | + if (!cmds[i].func) { |
|---|
| 128 | + p_err("command '%s' is not supported in bootstrap mode", |
|---|
| 129 | + cmds[i].cmd); |
|---|
| 130 | + return -1; |
|---|
| 131 | + } |
|---|
| 123 | 132 | return cmds[i].func(argc - 1, argv + 1); |
|---|
| 133 | + } |
|---|
| 134 | + } |
|---|
| 124 | 135 | |
|---|
| 125 | 136 | help(argc - 1, argv + 1); |
|---|
| 126 | 137 | |
|---|
| .. | .. |
|---|
| 135 | 146 | return false; |
|---|
| 136 | 147 | |
|---|
| 137 | 148 | return !memcmp(str, pfx, strlen(pfx)); |
|---|
| 149 | +} |
|---|
| 150 | + |
|---|
| 151 | +/* Last argument MUST be NULL pointer */ |
|---|
| 152 | +int detect_common_prefix(const char *arg, ...) |
|---|
| 153 | +{ |
|---|
| 154 | + unsigned int count = 0; |
|---|
| 155 | + const char *ref; |
|---|
| 156 | + char msg[256]; |
|---|
| 157 | + va_list ap; |
|---|
| 158 | + |
|---|
| 159 | + snprintf(msg, sizeof(msg), "ambiguous prefix: '%s' could be '", arg); |
|---|
| 160 | + va_start(ap, arg); |
|---|
| 161 | + while ((ref = va_arg(ap, const char *))) { |
|---|
| 162 | + if (!is_prefix(arg, ref)) |
|---|
| 163 | + continue; |
|---|
| 164 | + count++; |
|---|
| 165 | + if (count > 1) |
|---|
| 166 | + strncat(msg, "' or '", sizeof(msg) - strlen(msg) - 1); |
|---|
| 167 | + strncat(msg, ref, sizeof(msg) - strlen(msg) - 1); |
|---|
| 168 | + } |
|---|
| 169 | + va_end(ap); |
|---|
| 170 | + strncat(msg, "'", sizeof(msg) - strlen(msg) - 1); |
|---|
| 171 | + |
|---|
| 172 | + if (count >= 2) { |
|---|
| 173 | + p_err("%s", msg); |
|---|
| 174 | + return -1; |
|---|
| 175 | + } |
|---|
| 176 | + |
|---|
| 177 | + return 0; |
|---|
| 138 | 178 | } |
|---|
| 139 | 179 | |
|---|
| 140 | 180 | void fprint_hex(FILE *f, void *arg, unsigned int n, const char *sep) |
|---|
| .. | .. |
|---|
| 213 | 253 | { "batch", do_batch }, |
|---|
| 214 | 254 | { "prog", do_prog }, |
|---|
| 215 | 255 | { "map", do_map }, |
|---|
| 256 | + { "link", do_link }, |
|---|
| 216 | 257 | { "cgroup", do_cgroup }, |
|---|
| 217 | 258 | { "perf", do_perf }, |
|---|
| 259 | + { "net", do_net }, |
|---|
| 260 | + { "feature", do_feature }, |
|---|
| 261 | + { "btf", do_btf }, |
|---|
| 262 | + { "gen", do_gen }, |
|---|
| 263 | + { "struct_ops", do_struct_ops }, |
|---|
| 264 | + { "iter", do_iter }, |
|---|
| 218 | 265 | { "version", do_version }, |
|---|
| 219 | 266 | { 0 } |
|---|
| 220 | 267 | }; |
|---|
| .. | .. |
|---|
| 227 | 274 | int n_argc; |
|---|
| 228 | 275 | FILE *fp; |
|---|
| 229 | 276 | char *cp; |
|---|
| 230 | | - int err; |
|---|
| 277 | + int err = 0; |
|---|
| 231 | 278 | int i; |
|---|
| 232 | 279 | |
|---|
| 233 | 280 | if (argc < 2) { |
|---|
| .. | .. |
|---|
| 321 | 368 | p_err("reading batch file failed: %s", strerror(errno)); |
|---|
| 322 | 369 | err = -1; |
|---|
| 323 | 370 | } else { |
|---|
| 324 | | - p_info("processed %d commands", lines); |
|---|
| 325 | | - err = 0; |
|---|
| 371 | + if (!json_output) |
|---|
| 372 | + printf("processed %d commands\n", lines); |
|---|
| 326 | 373 | } |
|---|
| 327 | 374 | err_close: |
|---|
| 328 | 375 | if (fp != stdin) |
|---|
| .. | .. |
|---|
| 342 | 389 | { "pretty", no_argument, NULL, 'p' }, |
|---|
| 343 | 390 | { "version", no_argument, NULL, 'V' }, |
|---|
| 344 | 391 | { "bpffs", no_argument, NULL, 'f' }, |
|---|
| 392 | + { "mapcompat", no_argument, NULL, 'm' }, |
|---|
| 393 | + { "nomount", no_argument, NULL, 'n' }, |
|---|
| 394 | + { "debug", no_argument, NULL, 'd' }, |
|---|
| 345 | 395 | { 0 } |
|---|
| 346 | 396 | }; |
|---|
| 347 | 397 | int opt, ret; |
|---|
| 398 | + |
|---|
| 399 | + setlinebuf(stdout); |
|---|
| 400 | + |
|---|
| 401 | +#ifdef USE_LIBCAP |
|---|
| 402 | + /* Libcap < 2.63 hooks before main() to compute the number of |
|---|
| 403 | + * capabilities of the running kernel, and doing so it calls prctl() |
|---|
| 404 | + * which may fail and set errno to non-zero. |
|---|
| 405 | + * Let's reset errno to make sure this does not interfere with the |
|---|
| 406 | + * batch mode. |
|---|
| 407 | + */ |
|---|
| 408 | + errno = 0; |
|---|
| 409 | +#endif |
|---|
| 348 | 410 | |
|---|
| 349 | 411 | last_do_help = do_help; |
|---|
| 350 | 412 | pretty_output = false; |
|---|
| 351 | 413 | json_output = false; |
|---|
| 352 | 414 | show_pinned = false; |
|---|
| 415 | + block_mount = false; |
|---|
| 353 | 416 | bin_name = argv[0]; |
|---|
| 354 | 417 | |
|---|
| 355 | 418 | hash_init(prog_table.table); |
|---|
| 356 | 419 | hash_init(map_table.table); |
|---|
| 420 | + hash_init(link_table.table); |
|---|
| 357 | 421 | |
|---|
| 358 | 422 | opterr = 0; |
|---|
| 359 | | - while ((opt = getopt_long(argc, argv, "Vhpjf", |
|---|
| 423 | + while ((opt = getopt_long(argc, argv, "Vhpjfmnd", |
|---|
| 360 | 424 | options, NULL)) >= 0) { |
|---|
| 361 | 425 | switch (opt) { |
|---|
| 362 | 426 | case 'V': |
|---|
| .. | .. |
|---|
| 380 | 444 | case 'f': |
|---|
| 381 | 445 | show_pinned = true; |
|---|
| 382 | 446 | break; |
|---|
| 447 | + case 'm': |
|---|
| 448 | + relaxed_maps = true; |
|---|
| 449 | + break; |
|---|
| 450 | + case 'n': |
|---|
| 451 | + block_mount = true; |
|---|
| 452 | + break; |
|---|
| 453 | + case 'd': |
|---|
| 454 | + libbpf_set_print(print_all_levels); |
|---|
| 455 | + verifier_logs = true; |
|---|
| 456 | + break; |
|---|
| 383 | 457 | default: |
|---|
| 384 | 458 | p_err("unrecognized option '%s'", argv[optind - 1]); |
|---|
| 385 | 459 | if (json_output) |
|---|
| .. | .. |
|---|
| 394 | 468 | if (argc < 0) |
|---|
| 395 | 469 | usage(); |
|---|
| 396 | 470 | |
|---|
| 397 | | - bfd_init(); |
|---|
| 398 | | - |
|---|
| 399 | 471 | ret = cmd_select(cmds, argc, argv, do_help); |
|---|
| 400 | 472 | |
|---|
| 401 | 473 | if (json_output) |
|---|
| .. | .. |
|---|
| 404 | 476 | if (show_pinned) { |
|---|
| 405 | 477 | delete_pinned_obj_table(&prog_table); |
|---|
| 406 | 478 | delete_pinned_obj_table(&map_table); |
|---|
| 479 | + delete_pinned_obj_table(&link_table); |
|---|
| 407 | 480 | } |
|---|
| 408 | 481 | |
|---|
| 409 | 482 | return ret; |
|---|