iproute2/tc/e_bpf.c
<<
>>
Prefs
   1/*
   2 * e_bpf.c      BPF exec proxy
   3 *
   4 *              This program is free software; you can distribute it and/or
   5 *              modify it under the terms of the GNU General Public License
   6 *              as published by the Free Software Foundation; either version
   7 *              2 of the License, or (at your option) any later version.
   8 *
   9 * Authors:     Daniel Borkmann <daniel@iogearbox.net>
  10 */
  11
  12#include <stdio.h>
  13#include <unistd.h>
  14
  15#include "utils.h"
  16
  17#include "tc_util.h"
  18
  19#include "bpf_util.h"
  20#include "bpf_elf.h"
  21#include "bpf_scm.h"
  22
  23#define BPF_DEFAULT_CMD "/bin/sh"
  24
  25static char *argv_default[] = { BPF_DEFAULT_CMD, NULL };
  26
  27static void explain(void)
  28{
  29        fprintf(stderr,
  30                "Usage: ... bpf [ import UDS_FILE ] [ run CMD ]\n"
  31                "       ... bpf [ debug ]\n"
  32                "       ... bpf [ graft MAP_FILE ] [ key KEY ]\n"
  33                "          `... [ object-file OBJ_FILE ] [ type TYPE ] [ section NAME ] [ verbose ]\n"
  34                "          `... [ object-pinned PROG_FILE ]\n"
  35                "\n"
  36                "Where UDS_FILE provides the name of a unix domain socket file\n"
  37                "to import eBPF maps and the optional CMD denotes the command\n"
  38                "to be executed (default: \'%s\').\n"
  39                "Where MAP_FILE points to a pinned map, OBJ_FILE to an object file\n"
  40                "and PROG_FILE to a pinned program. TYPE can be {cls, act}, where\n"
  41                "\'cls\' is default. KEY is optional and can be inferred from the\n"
  42                "section name, otherwise it needs to be provided.\n",
  43                BPF_DEFAULT_CMD);
  44}
  45
  46static int bpf_num_env_entries(void)
  47{
  48        char **envp;
  49        int num;
  50
  51        for (num = 0, envp = environ; *envp != NULL; envp++)
  52                num++;
  53        return num;
  54}
  55
  56static int parse_bpf(struct exec_util *eu, int argc, char **argv)
  57{
  58        char **argv_run = argv_default, **envp_run, *tmp;
  59        int ret, i, env_old, env_num, env_map;
  60        const char *bpf_uds_name = NULL;
  61        int fds[BPF_SCM_MAX_FDS] = {};
  62        struct bpf_map_aux aux = {};
  63
  64        if (argc == 0)
  65                return 0;
  66
  67        while (argc > 0) {
  68                if (matches(*argv, "run") == 0) {
  69                        NEXT_ARG();
  70                        argv_run = argv;
  71                        break;
  72                } else if (matches(*argv, "import") == 0) {
  73                        NEXT_ARG();
  74                        bpf_uds_name = *argv;
  75                } else if (matches(*argv, "debug") == 0 ||
  76                           matches(*argv, "dbg") == 0) {
  77                        if (bpf_trace_pipe())
  78                                fprintf(stderr,
  79                                        "No trace pipe, tracefs not mounted?\n");
  80                        return -1;
  81                } else if (matches(*argv, "graft") == 0) {
  82                        const char *bpf_map_path;
  83                        bool has_key = false;
  84                        uint32_t key;
  85
  86                        NEXT_ARG();
  87                        bpf_map_path = *argv;
  88                        NEXT_ARG();
  89                        if (matches(*argv, "key") == 0) {
  90                                NEXT_ARG();
  91                                if (get_unsigned(&key, *argv, 0)) {
  92                                        fprintf(stderr, "Illegal \"key\"\n");
  93                                        return -1;
  94                                }
  95                                has_key = true;
  96                                NEXT_ARG();
  97                        }
  98                        return bpf_graft_map(bpf_map_path, has_key ?
  99                                             &key : NULL, argc, argv);
 100                } else {
 101                        explain();
 102                        return -1;
 103                }
 104
 105                NEXT_ARG_FWD();
 106        }
 107
 108        if (!bpf_uds_name) {
 109                fprintf(stderr, "bpf: No import parameter provided!\n");
 110                explain();
 111                return -1;
 112        }
 113
 114        if (argv_run != argv_default && argc == 0) {
 115                fprintf(stderr, "bpf: No run command provided!\n");
 116                explain();
 117                return -1;
 118        }
 119
 120        ret = bpf_recv_map_fds(bpf_uds_name, fds, &aux, ARRAY_SIZE(fds));
 121        if (ret < 0) {
 122                fprintf(stderr, "bpf: Could not receive fds!\n");
 123                return -1;
 124        }
 125
 126        if (aux.num_ent == 0) {
 127                envp_run = environ;
 128                goto out;
 129        }
 130
 131        env_old = bpf_num_env_entries();
 132        env_num = env_old + aux.num_ent + 2;
 133        env_map = env_old + 1;
 134
 135        envp_run = malloc(sizeof(*envp_run) * env_num);
 136        if (!envp_run) {
 137                fprintf(stderr, "bpf: No memory left to allocate env!\n");
 138                goto err;
 139        }
 140
 141        for (i = 0; i < env_old; i++)
 142                envp_run[i] = environ[i];
 143
 144        ret = asprintf(&tmp, "BPF_NUM_MAPS=%u", aux.num_ent);
 145        if (ret < 0)
 146                goto err_free;
 147
 148        envp_run[env_old] = tmp;
 149
 150        for (i = env_map; i < env_num - 1; i++) {
 151                ret = asprintf(&tmp, "BPF_MAP%u=%u",
 152                               aux.ent[i - env_map].id,
 153                               fds[i - env_map]);
 154                if (ret < 0)
 155                        goto err_free_env;
 156
 157                envp_run[i] = tmp;
 158        }
 159
 160        envp_run[env_num - 1] = NULL;
 161out:
 162        ret = execvpe(argv_run[0], argv_run, envp_run);
 163        free(envp_run);
 164        return ret;
 165
 166err_free_env:
 167        for (--i; i >= env_old; i--)
 168                free(envp_run[i]);
 169err_free:
 170        free(envp_run);
 171err:
 172        for (i = 0; i < aux.num_ent; i++)
 173                close(fds[i]);
 174        return -1;
 175}
 176
 177struct exec_util bpf_exec_util = {
 178        .id             = "bpf",
 179        .parse_eopt     = parse_bpf,
 180};
 181