]> git.proxmox.com Git - mirror_iproute2.git/blob - tc/e_bpf.c
Merge branch 'master' into net-next
[mirror_iproute2.git] / tc / e_bpf.c
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 #include "tc_bpf.h"
19
20 #include "bpf_elf.h"
21 #include "bpf_scm.h"
22
23 #define BPF_DEFAULT_CMD "/bin/sh"
24
25 static char *argv_default[] = { BPF_DEFAULT_CMD, NULL };
26
27 static void explain(void)
28 {
29 fprintf(stderr, "Usage: ... bpf [ import UDS_FILE ] [ run CMD ] [ debug ]\n\n");
30 fprintf(stderr, "Where UDS_FILE provides the name of a unix domain socket file\n");
31 fprintf(stderr, "to import eBPF maps and the optional CMD denotes the command\n");
32 fprintf(stderr, "to be executed (default: \'%s\').\n", BPF_DEFAULT_CMD);
33 }
34
35 static int bpf_num_env_entries(void)
36 {
37 char **envp;
38 int num;
39
40 for (num = 0, envp = environ; *envp != NULL; envp++)
41 num++;
42 return num;
43 }
44
45 static int parse_bpf(struct exec_util *eu, int argc, char **argv)
46 {
47 char **argv_run = argv_default, **envp_run, *tmp;
48 int ret, i, env_old, env_num, env_map;
49 const char *bpf_uds_name = NULL;
50 int fds[BPF_SCM_MAX_FDS];
51 struct bpf_map_aux aux;
52
53 if (argc == 0)
54 return 0;
55
56 while (argc > 0) {
57 if (matches(*argv, "run") == 0) {
58 NEXT_ARG();
59 argv_run = argv;
60 break;
61 } else if (matches(*argv, "import") == 0) {
62 NEXT_ARG();
63 bpf_uds_name = *argv;
64 } else if (matches(*argv, "debug") == 0 ||
65 matches(*argv, "dbg") == 0) {
66 if (bpf_trace_pipe())
67 fprintf(stderr,
68 "No trace pipe, tracefs not mounted?\n");
69 return -1;
70 } else {
71 explain();
72 return -1;
73 }
74
75 NEXT_ARG_FWD();
76 }
77
78 if (!bpf_uds_name) {
79 fprintf(stderr, "bpf: No import parameter provided!\n");
80 explain();
81 return -1;
82 }
83
84 if (argv_run != argv_default && argc == 0) {
85 fprintf(stderr, "bpf: No run command provided!\n");
86 explain();
87 return -1;
88 }
89
90 memset(fds, 0, sizeof(fds));
91 memset(&aux, 0, sizeof(aux));
92
93 ret = bpf_recv_map_fds(bpf_uds_name, fds, &aux, ARRAY_SIZE(fds));
94 if (ret < 0) {
95 fprintf(stderr, "bpf: Could not receive fds!\n");
96 return -1;
97 }
98
99 if (aux.num_ent == 0) {
100 envp_run = environ;
101 goto out;
102 }
103
104 env_old = bpf_num_env_entries();
105 env_num = env_old + aux.num_ent + 2;
106 env_map = env_old + 1;
107
108 envp_run = malloc(sizeof(*envp_run) * env_num);
109 if (!envp_run) {
110 fprintf(stderr, "bpf: No memory left to allocate env!\n");
111 goto err;
112 }
113
114 for (i = 0; i < env_old; i++)
115 envp_run[i] = environ[i];
116
117 ret = asprintf(&tmp, "BPF_NUM_MAPS=%u", aux.num_ent);
118 if (ret < 0)
119 goto err_free;
120
121 envp_run[env_old] = tmp;
122
123 for (i = env_map; i < env_num - 1; i++) {
124 ret = asprintf(&tmp, "BPF_MAP%u=%u",
125 aux.ent[i - env_map].id,
126 fds[i - env_map]);
127 if (ret < 0)
128 goto err_free_env;
129
130 envp_run[i] = tmp;
131 }
132
133 envp_run[env_num - 1] = NULL;
134 out:
135 return execvpe(argv_run[0], argv_run, envp_run);
136
137 err_free_env:
138 for (--i; i >= env_old; i--)
139 free(envp_run[i]);
140 err_free:
141 free(envp_run);
142 err:
143 for (i = 0; i < aux.num_ent; i++)
144 close(fds[i]);
145 return -1;
146 }
147
148 struct exec_util bpf_exec_util = {
149 .id = "bpf",
150 .parse_eopt = parse_bpf,
151 };