linux/tools/bpf/bpftool/main.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2017 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/* Author: Jakub Kicinski <kubakici@wp.pl> */
  35
  36#include <bfd.h>
  37#include <ctype.h>
  38#include <errno.h>
  39#include <getopt.h>
  40#include <linux/bpf.h>
  41#include <stdio.h>
  42#include <stdlib.h>
  43#include <string.h>
  44
  45#include <bpf.h>
  46
  47#include "main.h"
  48
  49const char *bin_name;
  50static int last_argc;
  51static char **last_argv;
  52static int (*last_do_help)(int argc, char **argv);
  53json_writer_t *json_wtr;
  54bool pretty_output;
  55bool json_output;
  56bool show_pinned;
  57struct pinned_obj_table prog_table;
  58struct pinned_obj_table map_table;
  59
  60static void __noreturn clean_and_exit(int i)
  61{
  62        if (json_output)
  63                jsonw_destroy(&json_wtr);
  64
  65        exit(i);
  66}
  67
  68void usage(void)
  69{
  70        last_do_help(last_argc - 1, last_argv + 1);
  71
  72        clean_and_exit(-1);
  73}
  74
  75static int do_help(int argc, char **argv)
  76{
  77        if (json_output) {
  78                jsonw_null(json_wtr);
  79                return 0;
  80        }
  81
  82        fprintf(stderr,
  83                "Usage: %s [OPTIONS] OBJECT { COMMAND | help }\n"
  84                "       %s batch file FILE\n"
  85                "       %s version\n"
  86                "\n"
  87                "       OBJECT := { prog | map | cgroup }\n"
  88                "       " HELP_SPEC_OPTIONS "\n"
  89                "",
  90                bin_name, bin_name, bin_name);
  91
  92        return 0;
  93}
  94
  95static int do_version(int argc, char **argv)
  96{
  97        if (json_output) {
  98                jsonw_start_object(json_wtr);
  99                jsonw_name(json_wtr, "version");
 100                jsonw_printf(json_wtr, "\"%s\"", BPFTOOL_VERSION);
 101                jsonw_end_object(json_wtr);
 102        } else {
 103                printf("%s v%s\n", bin_name, BPFTOOL_VERSION);
 104        }
 105        return 0;
 106}
 107
 108int cmd_select(const struct cmd *cmds, int argc, char **argv,
 109               int (*help)(int argc, char **argv))
 110{
 111        unsigned int i;
 112
 113        last_argc = argc;
 114        last_argv = argv;
 115        last_do_help = help;
 116
 117        if (argc < 1 && cmds[0].func)
 118                return cmds[0].func(argc, argv);
 119
 120        for (i = 0; cmds[i].func; i++)
 121                if (is_prefix(*argv, cmds[i].cmd))
 122                        return cmds[i].func(argc - 1, argv + 1);
 123
 124        help(argc - 1, argv + 1);
 125
 126        return -1;
 127}
 128
 129bool is_prefix(const char *pfx, const char *str)
 130{
 131        if (!pfx)
 132                return false;
 133        if (strlen(str) < strlen(pfx))
 134                return false;
 135
 136        return !memcmp(str, pfx, strlen(pfx));
 137}
 138
 139void fprint_hex(FILE *f, void *arg, unsigned int n, const char *sep)
 140{
 141        unsigned char *data = arg;
 142        unsigned int i;
 143
 144        for (i = 0; i < n; i++) {
 145                const char *pfx = "";
 146
 147                if (!i)
 148                        /* nothing */;
 149                else if (!(i % 16))
 150                        fprintf(f, "\n");
 151                else if (!(i % 8))
 152                        fprintf(f, "  ");
 153                else
 154                        pfx = sep;
 155
 156                fprintf(f, "%s%02hhx", i ? pfx : "", data[i]);
 157        }
 158}
 159
 160static int do_batch(int argc, char **argv);
 161
 162static const struct cmd cmds[] = {
 163        { "help",       do_help },
 164        { "batch",      do_batch },
 165        { "prog",       do_prog },
 166        { "map",        do_map },
 167        { "cgroup",     do_cgroup },
 168        { "version",    do_version },
 169        { 0 }
 170};
 171
 172static int do_batch(int argc, char **argv)
 173{
 174        unsigned int lines = 0;
 175        char *n_argv[4096];
 176        char buf[65536];
 177        int n_argc;
 178        FILE *fp;
 179        int err;
 180        int i;
 181
 182        if (argc < 2) {
 183                p_err("too few parameters for batch");
 184                return -1;
 185        } else if (!is_prefix(*argv, "file")) {
 186                p_err("expected 'file', got: %s", *argv);
 187                return -1;
 188        } else if (argc > 2) {
 189                p_err("too many parameters for batch");
 190                return -1;
 191        }
 192        NEXT_ARG();
 193
 194        fp = fopen(*argv, "r");
 195        if (!fp) {
 196                p_err("Can't open file (%s): %s", *argv, strerror(errno));
 197                return -1;
 198        }
 199
 200        if (json_output)
 201                jsonw_start_array(json_wtr);
 202        while (fgets(buf, sizeof(buf), fp)) {
 203                if (strlen(buf) == sizeof(buf) - 1) {
 204                        errno = E2BIG;
 205                        break;
 206                }
 207
 208                n_argc = 0;
 209                n_argv[n_argc] = strtok(buf, " \t\n");
 210
 211                while (n_argv[n_argc]) {
 212                        n_argc++;
 213                        if (n_argc == ARRAY_SIZE(n_argv)) {
 214                                p_err("line %d has too many arguments, skip",
 215                                      lines);
 216                                n_argc = 0;
 217                                break;
 218                        }
 219                        n_argv[n_argc] = strtok(NULL, " \t\n");
 220                }
 221
 222                if (!n_argc)
 223                        continue;
 224
 225                if (json_output) {
 226                        jsonw_start_object(json_wtr);
 227                        jsonw_name(json_wtr, "command");
 228                        jsonw_start_array(json_wtr);
 229                        for (i = 0; i < n_argc; i++)
 230                                jsonw_string(json_wtr, n_argv[i]);
 231                        jsonw_end_array(json_wtr);
 232                        jsonw_name(json_wtr, "output");
 233                }
 234
 235                err = cmd_select(cmds, n_argc, n_argv, do_help);
 236
 237                if (json_output)
 238                        jsonw_end_object(json_wtr);
 239
 240                if (err)
 241                        goto err_close;
 242
 243                lines++;
 244        }
 245
 246        if (errno && errno != ENOENT) {
 247                p_err("reading batch file failed: %s", strerror(errno));
 248                err = -1;
 249        } else {
 250                p_info("processed %d lines", lines);
 251                err = 0;
 252        }
 253err_close:
 254        fclose(fp);
 255
 256        if (json_output)
 257                jsonw_end_array(json_wtr);
 258
 259        return err;
 260}
 261
 262int main(int argc, char **argv)
 263{
 264        static const struct option options[] = {
 265                { "json",       no_argument,    NULL,   'j' },
 266                { "help",       no_argument,    NULL,   'h' },
 267                { "pretty",     no_argument,    NULL,   'p' },
 268                { "version",    no_argument,    NULL,   'V' },
 269                { "bpffs",      no_argument,    NULL,   'f' },
 270                { 0 }
 271        };
 272        int opt, ret;
 273
 274        last_do_help = do_help;
 275        pretty_output = false;
 276        json_output = false;
 277        show_pinned = false;
 278        bin_name = argv[0];
 279
 280        hash_init(prog_table.table);
 281        hash_init(map_table.table);
 282
 283        opterr = 0;
 284        while ((opt = getopt_long(argc, argv, "Vhpjf",
 285                                  options, NULL)) >= 0) {
 286                switch (opt) {
 287                case 'V':
 288                        return do_version(argc, argv);
 289                case 'h':
 290                        return do_help(argc, argv);
 291                case 'p':
 292                        pretty_output = true;
 293                        /* fall through */
 294                case 'j':
 295                        if (!json_output) {
 296                                json_wtr = jsonw_new(stdout);
 297                                if (!json_wtr) {
 298                                        p_err("failed to create JSON writer");
 299                                        return -1;
 300                                }
 301                                json_output = true;
 302                        }
 303                        jsonw_pretty(json_wtr, pretty_output);
 304                        break;
 305                case 'f':
 306                        show_pinned = true;
 307                        break;
 308                default:
 309                        p_err("unrecognized option '%s'", argv[optind - 1]);
 310                        if (json_output)
 311                                clean_and_exit(-1);
 312                        else
 313                                usage();
 314                }
 315        }
 316
 317        argc -= optind;
 318        argv += optind;
 319        if (argc < 0)
 320                usage();
 321
 322        bfd_init();
 323
 324        ret = cmd_select(cmds, argc, argv, do_help);
 325
 326        if (json_output)
 327                jsonw_destroy(&json_wtr);
 328
 329        if (show_pinned) {
 330                delete_pinned_obj_table(&prog_table);
 331                delete_pinned_obj_table(&map_table);
 332        }
 333
 334        return ret;
 335}
 336