]> git.proxmox.com Git - mirror_iproute2.git/blame - tc/e_bpf.c
make yacc usage POSIX compatible
[mirror_iproute2.git] / tc / e_bpf.c
CommitLineData
4bd62446
DB
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"
4bd62446 18
e4225669 19#include "bpf_util.h"
4bd62446
DB
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{
8589eb4e
MC
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);
4bd62446
DB
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;
d17b136f
PS
61 int fds[BPF_SCM_MAX_FDS] = {};
62 struct bpf_map_aux aux = {};
4bd62446
DB
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;
32e93fb7 72 } else if (matches(*argv, "import") == 0) {
4bd62446
DB
73 NEXT_ARG();
74 bpf_uds_name = *argv;
32e93fb7
DB
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;
91d88eeb
DB
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);
4bd62446
DB
100 } else {
101 explain();
102 return -1;
103 }
104
32e93fb7 105 NEXT_ARG_FWD();
4bd62446
DB
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
4bd62446
DB
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 return execvpe(argv_run[0], argv_run, envp_run);
163
164err_free_env:
165 for (--i; i >= env_old; i--)
166 free(envp_run[i]);
167err_free:
168 free(envp_run);
169err:
170 for (i = 0; i < aux.num_ent; i++)
171 close(fds[i]);
172 return -1;
173}
174
175struct exec_util bpf_exec_util = {
32e93fb7
DB
176 .id = "bpf",
177 .parse_eopt = parse_bpf,
4bd62446 178};