mirror_iproute2/tc/e_bpf.c
Matteo Croce 8589eb4efd treewide: refactor help messages
Every tool in the iproute2 package have one or more function to show
an help message to the user. Some of these functions print the help
line by line with a series of printf call, e.g. ip/xfrm_state.c does
60 fprintf calls.
If we group all the calls to a single one and just concatenate strings,
we save a lot of libc calls and thus object size. The size difference
of the compiled binaries calculated with bloat-o-meter is:

        ip/ip:
        add/remove: 0/0 grow/shrink: 5/15 up/down: 103/-4796 (-4693)
        Total: Before=672591, After=667898, chg -0.70%
        ip/rtmon:
        add/remove: 0/0 grow/shrink: 0/1 up/down: 0/-54 (-54)
        Total: Before=48879, After=48825, chg -0.11%
        tc/tc:
        add/remove: 0/2 grow/shrink: 31/10 up/down: 882/-6133 (-5251)
        Total: Before=351912, After=346661, chg -1.49%
        bridge/bridge:
        add/remove: 0/0 grow/shrink: 0/1 up/down: 0/-459 (-459)
        Total: Before=70502, After=70043, chg -0.65%
        misc/lnstat:
        add/remove: 0/1 grow/shrink: 1/0 up/down: 48/-486 (-438)
        Total: Before=9960, After=9522, chg -4.40%
        tipc/tipc:
        add/remove: 0/0 grow/shrink: 1/1 up/down: 18/-62 (-44)
        Total: Before=79182, After=79138, chg -0.06%

While at it, indent some strings which were starting at column 0,
and use tabs where possible, to have a consistent style across helps.

Signed-off-by: Matteo Croce <mcroce@redhat.com>
Signed-off-by: David Ahern <dsahern@gmail.com>
2019-05-20 14:35:07 -07:00

179 lines
4.0 KiB
C

/*
* e_bpf.c BPF exec proxy
*
* This program is free software; you can distribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
* Authors: Daniel Borkmann <daniel@iogearbox.net>
*/
#include <stdio.h>
#include <unistd.h>
#include "utils.h"
#include "tc_util.h"
#include "bpf_util.h"
#include "bpf_elf.h"
#include "bpf_scm.h"
#define BPF_DEFAULT_CMD "/bin/sh"
static char *argv_default[] = { BPF_DEFAULT_CMD, NULL };
static void explain(void)
{
fprintf(stderr,
"Usage: ... bpf [ import UDS_FILE ] [ run CMD ]\n"
" ... bpf [ debug ]\n"
" ... bpf [ graft MAP_FILE ] [ key KEY ]\n"
" `... [ object-file OBJ_FILE ] [ type TYPE ] [ section NAME ] [ verbose ]\n"
" `... [ object-pinned PROG_FILE ]\n"
"\n"
"Where UDS_FILE provides the name of a unix domain socket file\n"
"to import eBPF maps and the optional CMD denotes the command\n"
"to be executed (default: \'%s\').\n"
"Where MAP_FILE points to a pinned map, OBJ_FILE to an object file\n"
"and PROG_FILE to a pinned program. TYPE can be {cls, act}, where\n"
"\'cls\' is default. KEY is optional and can be inferred from the\n"
"section name, otherwise it needs to be provided.\n",
BPF_DEFAULT_CMD);
}
static int bpf_num_env_entries(void)
{
char **envp;
int num;
for (num = 0, envp = environ; *envp != NULL; envp++)
num++;
return num;
}
static int parse_bpf(struct exec_util *eu, int argc, char **argv)
{
char **argv_run = argv_default, **envp_run, *tmp;
int ret, i, env_old, env_num, env_map;
const char *bpf_uds_name = NULL;
int fds[BPF_SCM_MAX_FDS] = {};
struct bpf_map_aux aux = {};
if (argc == 0)
return 0;
while (argc > 0) {
if (matches(*argv, "run") == 0) {
NEXT_ARG();
argv_run = argv;
break;
} else if (matches(*argv, "import") == 0) {
NEXT_ARG();
bpf_uds_name = *argv;
} else if (matches(*argv, "debug") == 0 ||
matches(*argv, "dbg") == 0) {
if (bpf_trace_pipe())
fprintf(stderr,
"No trace pipe, tracefs not mounted?\n");
return -1;
} else if (matches(*argv, "graft") == 0) {
const char *bpf_map_path;
bool has_key = false;
uint32_t key;
NEXT_ARG();
bpf_map_path = *argv;
NEXT_ARG();
if (matches(*argv, "key") == 0) {
NEXT_ARG();
if (get_unsigned(&key, *argv, 0)) {
fprintf(stderr, "Illegal \"key\"\n");
return -1;
}
has_key = true;
NEXT_ARG();
}
return bpf_graft_map(bpf_map_path, has_key ?
&key : NULL, argc, argv);
} else {
explain();
return -1;
}
NEXT_ARG_FWD();
}
if (!bpf_uds_name) {
fprintf(stderr, "bpf: No import parameter provided!\n");
explain();
return -1;
}
if (argv_run != argv_default && argc == 0) {
fprintf(stderr, "bpf: No run command provided!\n");
explain();
return -1;
}
ret = bpf_recv_map_fds(bpf_uds_name, fds, &aux, ARRAY_SIZE(fds));
if (ret < 0) {
fprintf(stderr, "bpf: Could not receive fds!\n");
return -1;
}
if (aux.num_ent == 0) {
envp_run = environ;
goto out;
}
env_old = bpf_num_env_entries();
env_num = env_old + aux.num_ent + 2;
env_map = env_old + 1;
envp_run = malloc(sizeof(*envp_run) * env_num);
if (!envp_run) {
fprintf(stderr, "bpf: No memory left to allocate env!\n");
goto err;
}
for (i = 0; i < env_old; i++)
envp_run[i] = environ[i];
ret = asprintf(&tmp, "BPF_NUM_MAPS=%u", aux.num_ent);
if (ret < 0)
goto err_free;
envp_run[env_old] = tmp;
for (i = env_map; i < env_num - 1; i++) {
ret = asprintf(&tmp, "BPF_MAP%u=%u",
aux.ent[i - env_map].id,
fds[i - env_map]);
if (ret < 0)
goto err_free_env;
envp_run[i] = tmp;
}
envp_run[env_num - 1] = NULL;
out:
return execvpe(argv_run[0], argv_run, envp_run);
err_free_env:
for (--i; i >= env_old; i--)
free(envp_run[i]);
err_free:
free(envp_run);
err:
for (i = 0; i < aux.num_ent; i++)
close(fds[i]);
return -1;
}
struct exec_util bpf_exec_util = {
.id = "bpf",
.parse_eopt = parse_bpf,
};