Branch data Line data Source code
1 : : // SPDX-License-Identifier: GPL-2.0-only
2 : : /*
3 : : * Copyright (c) 2023 Meta Platforms, Inc. and affiliates.
4 : : */
5 : :
6 : : #include "bpfilter/bpf.h"
7 : :
8 : : #include <linux/bpf.h>
9 : :
10 : : #include <errno.h>
11 : : #include <stdint.h>
12 : : #include <stdio.h>
13 : : #include <stdlib.h>
14 : : #include <unistd.h>
15 : :
16 : : #include "bpfilter/bpf_types.h"
17 : : #include "bpfilter/btf.h"
18 : : #include "bpfilter/helper.h"
19 : : #include "bpfilter/logger.h"
20 : :
21 : : #ifdef __i386__
22 : : #define _BF_NR_bpf 357
23 : : #elif defined(__x86_64__)
24 : : #define _BF_NR_bpf 321
25 : : #elif defined(__aarch64__)
26 : : #define _BF_NR_bpf 280
27 : : #else
28 : : #error _BF_NR_bpf not defined. bpfilter does not support your arch.
29 : : #endif
30 : :
31 : 1012 : int bf_bpf(enum bf_bpf_cmd cmd, union bpf_attr *attr)
32 : : {
33 : 1012 : int r = (int)syscall(_BF_NR_bpf, cmd, attr, sizeof(*attr));
34 [ + + ]: 1012 : if (r < 0)
35 : 94 : return -errno;
36 : :
37 : : return r;
38 : : }
39 : :
40 : 63 : int bf_bpf_prog_load(const char *name, enum bf_bpf_prog_type prog_type,
41 : : void *img, size_t img_len,
42 : : enum bf_bpf_attach_type attach_type, const char *log_buf,
43 : : size_t log_size, int token_fd, int *fd)
44 : : {
45 : : union bpf_attr attr;
46 : : int r;
47 : :
48 : : bf_assert(name && img && fd);
49 : :
50 : 63 : memset(&attr, 0, sizeof(attr));
51 : :
52 : 63 : attr.prog_type = prog_type;
53 : 63 : attr.insns = bf_ptr_to_u64(img);
54 : 63 : attr.insn_cnt = (unsigned int)img_len;
55 : 63 : attr.license = bf_ptr_to_u64("GPL");
56 : 63 : attr.expected_attach_type = attach_type;
57 : 63 : attr.log_buf = bf_ptr_to_u64(log_buf);
58 : 63 : attr.log_size = log_size;
59 : 63 : attr.log_level = 1;
60 : :
61 : 63 : (void)snprintf(attr.prog_name, BPF_OBJ_NAME_LEN, "%s", name);
62 : :
63 [ + + ]: 63 : if (token_fd != -1) {
64 : 61 : attr.prog_token_fd = token_fd;
65 : 61 : attr.prog_flags |= BPF_F_TOKEN_FD;
66 : : }
67 : :
68 : 63 : r = bf_bpf(BF_BPF_PROG_LOAD, &attr);
69 [ + + ]: 63 : if (r < 0)
70 : : return r;
71 : :
72 : 62 : *fd = r;
73 : :
74 : 62 : return 0;
75 : : }
76 : :
77 : 34 : int bf_bpf_map_lookup_elem(int fd, const void *key, void *value)
78 : : {
79 : : union bpf_attr attr;
80 : :
81 : : bf_assert(key);
82 : : bf_assert(value);
83 : :
84 : 34 : memset(&attr, 0, sizeof(attr));
85 : :
86 : 34 : attr.map_fd = fd;
87 : 34 : attr.key = (uint64_t)key;
88 : 34 : attr.value = (uint64_t)value;
89 : :
90 : 34 : return bf_bpf(BF_BPF_MAP_LOOKUP_ELEM, &attr);
91 : : }
92 : :
93 : 338 : int bf_bpf_obj_pin(const char *path, int fd, int dir_fd)
94 : : {
95 : : union bpf_attr attr;
96 : :
97 : : bf_assert(path);
98 : : bf_assert(dir_fd >= 0);
99 : : bf_assert(path[0] == '/' ? !dir_fd : 1);
100 : :
101 : 338 : memset(&attr, 0, sizeof(attr));
102 : :
103 : 338 : attr.pathname = bf_ptr_to_u64(path);
104 : 338 : attr.bpf_fd = fd;
105 [ + + ]: 338 : attr.file_flags = dir_fd ? BPF_F_PATH_FD : 0;
106 : 338 : attr.path_fd = dir_fd;
107 : :
108 : 338 : int r = bf_bpf(BF_BPF_OBJ_PIN, &attr);
109 : 338 : return r;
110 : : }
111 : :
112 : 12 : int bf_bpf_obj_get(const char *path, int dir_fd, int *fd)
113 : : {
114 : : union bpf_attr attr;
115 : : int r;
116 : :
117 : : bf_assert(path && fd);
118 : : bf_assert(dir_fd >= 0);
119 : : bf_assert(path[0] == '/' ? !dir_fd : 1);
120 : :
121 : 12 : memset(&attr, 0, sizeof(attr));
122 : :
123 : 12 : attr.pathname = bf_ptr_to_u64(path);
124 [ + + ]: 12 : attr.file_flags = dir_fd ? BPF_F_PATH_FD : 0;
125 : 12 : attr.path_fd = dir_fd;
126 : :
127 : 12 : r = bf_bpf(BF_BPF_OBJ_GET, &attr);
128 [ + + ]: 12 : if (r < 0)
129 : : return r;
130 : :
131 : 10 : *fd = r;
132 : :
133 : 10 : return 0;
134 : : }
135 : :
136 : 3 : int bf_bpf_prog_run(int prog_fd, const void *pkt, size_t pkt_len,
137 : : const void *ctx, size_t ctx_len)
138 : : {
139 : : union bpf_attr attr;
140 : : int r;
141 : :
142 : : bf_assert(pkt);
143 : : bf_assert(pkt_len > 0);
144 : : bf_assert(!(!!ctx ^ !!ctx_len));
145 : :
146 : 3 : memset(&attr, 0, sizeof(attr));
147 : :
148 : 3 : attr.test.prog_fd = prog_fd;
149 : 3 : attr.test.data_size_in = pkt_len;
150 : 3 : attr.test.data_in = ((unsigned long long)(pkt));
151 : 3 : attr.test.repeat = 1;
152 : :
153 [ + + ]: 3 : if (ctx_len) {
154 : 1 : attr.test.ctx_size_in = ctx_len;
155 : 1 : attr.test.ctx_in = ((unsigned long long)(ctx));
156 : : }
157 : :
158 : 3 : r = bf_bpf(BF_BPF_PROG_TEST_RUN, &attr);
159 [ + + ]: 3 : if (r)
160 [ + - ]: 1 : return bf_err_r(r, "failed to run the test program");
161 : :
162 : 2 : return (int)attr.test.retval;
163 : : }
164 : :
165 : 22 : int bf_bpf_token_create(int bpffs_fd)
166 : : {
167 : : union bpf_attr attr;
168 : :
169 : 22 : memset(&attr, 0, sizeof(attr));
170 : :
171 : 22 : attr.token_create.bpffs_fd = bpffs_fd;
172 : :
173 : 22 : return bf_bpf(BF_BPF_TOKEN_CREATE, &attr);
174 : : }
175 : :
176 : 62 : int bf_bpf_btf_load(const void *btf_data, int token_fd)
177 : : {
178 : : bf_assert(btf_data);
179 : :
180 : : union bpf_attr attr;
181 : :
182 : 62 : memset(&attr, 0, sizeof(attr));
183 : :
184 : 62 : attr.btf = bf_ptr_to_u64(btf_data);
185 : :
186 [ + + ]: 62 : if (token_fd != -1) {
187 : 61 : attr.btf_token_fd = token_fd;
188 : 61 : attr.btf_flags |= BPF_F_TOKEN_FD;
189 : : }
190 : :
191 : 62 : return bf_bpf(BF_BPF_BTF_LOAD, &attr);
192 : : }
193 : :
194 : 263 : int bf_bpf_map_create(const char *name, enum bf_bpf_map_type type,
195 : : size_t key_size, size_t value_size, size_t n_elems,
196 : : const struct bf_btf *btf, int token_fd)
197 : : {
198 : : bf_assert(name);
199 : :
200 : : union bpf_attr attr;
201 : :
202 : 263 : memset(&attr, 0, sizeof(attr));
203 : :
204 : 263 : attr.map_type = type;
205 : 263 : attr.key_size = key_size;
206 : 263 : attr.value_size = value_size;
207 : 263 : attr.max_entries = n_elems;
208 : :
209 : : // NO_PREALLOC is *required* for LPM_TRIE map
210 [ + + ]: 263 : if (type == BF_BPF_MAP_TYPE_LPM_TRIE)
211 : 21 : attr.map_flags |= BPF_F_NO_PREALLOC;
212 : :
213 [ + + ]: 263 : if (token_fd != -1) {
214 : 261 : attr.map_token_fd = token_fd;
215 : 261 : attr.map_flags |= BPF_F_TOKEN_FD;
216 : : };
217 : :
218 [ - + ]: 263 : if (btf) {
219 : 0 : attr.btf_fd = btf->fd;
220 : 0 : attr.btf_key_type_id = btf->key_type_id;
221 : 0 : attr.btf_value_type_id = btf->value_type_id;
222 : : }
223 : :
224 : 263 : (void)snprintf(attr.map_name, BPF_OBJ_NAME_LEN, "%s", name);
225 : :
226 : 263 : return bf_bpf(BF_BPF_MAP_CREATE, &attr);
227 : : }
228 : :
229 : 62 : int bf_bpf_map_update_elem(int map_fd, const void *key, const void *value,
230 : : int flags)
231 : : {
232 : : bf_assert(key && value);
233 : :
234 : : union bpf_attr attr;
235 : :
236 : 62 : memset(&attr, 0, sizeof(attr));
237 : :
238 : 62 : attr.map_fd = map_fd;
239 : 62 : attr.key = bf_ptr_to_u64(key);
240 : 62 : attr.value = bf_ptr_to_u64(value);
241 : 62 : attr.flags = flags;
242 : :
243 : 62 : return bf_bpf(BF_BPF_MAP_UPDATE_ELEM, &attr);
244 : : }
245 : :
246 : 81 : int bf_bpf_map_update_batch(int map_fd, const void *keys, const void *values,
247 : : size_t count, int flags)
248 : : {
249 : : bf_assert(keys && values);
250 : :
251 : : union bpf_attr attr;
252 : :
253 : 81 : memset(&attr, 0, sizeof(attr));
254 : :
255 : 81 : attr.batch.map_fd = map_fd;
256 : 81 : attr.batch.keys = bf_ptr_to_u64(keys);
257 : 81 : attr.batch.values = bf_ptr_to_u64(values);
258 : 81 : attr.batch.count = count;
259 : 81 : attr.batch.flags = flags;
260 : :
261 : 81 : return bf_bpf(BF_BPF_MAP_UPDATE_BATCH, &attr);
262 : : }
263 : :
264 : 28 : int bf_bpf_link_create(int prog_fd, int target_fd, enum bf_hook hook,
265 : : const struct bf_hookopts *opts, int flags)
266 : : {
267 : : enum bf_bpf_attach_type attach_type;
268 : : union bpf_attr attr;
269 : :
270 : 28 : memset(&attr, 0, sizeof(attr));
271 : :
272 : 28 : attach_type = bf_hook_to_bpf_attach_type(hook);
273 : :
274 : 28 : attr.link_create.prog_fd = prog_fd;
275 : 28 : attr.link_create.target_fd = target_fd;
276 : 28 : attr.link_create.attach_type = attach_type;
277 : 28 : attr.link_create.flags = flags;
278 : :
279 [ + + ]: 28 : if (attach_type == BF_BPF_NETFILTER) {
280 [ + + ]: 8 : if (!opts)
281 : : return -EINVAL;
282 : :
283 : 7 : attr.link_create.netfilter.pf = opts->family;
284 : 7 : attr.link_create.netfilter.hooknum = bf_hook_to_nf_hook(hook);
285 : 7 : attr.link_create.netfilter.priority = opts->priorities[0];
286 : : }
287 : :
288 : 27 : return bf_bpf(BF_BPF_LINK_CREATE, &attr);
289 : : }
290 : :
291 : 5 : int bf_bpf_link_update(int link_fd, int new_prog_fd)
292 : : {
293 : : union bpf_attr attr;
294 : :
295 : 5 : memset(&attr, 0, sizeof(attr));
296 : :
297 : 5 : attr.link_update.link_fd = link_fd;
298 : 5 : attr.link_update.new_map_fd = new_prog_fd;
299 : :
300 : 5 : return bf_bpf(BF_BPF_LINK_UPDATE, &attr);
301 : : }
302 : :
303 : 38 : int bf_bpf_link_detach(int link_fd)
304 : : {
305 : : union bpf_attr attr;
306 : :
307 : 38 : memset(&attr, 0, sizeof(attr));
308 : :
309 : 38 : attr.link_detach.link_fd = link_fd;
310 : :
311 : 38 : return bf_bpf(BF_BPF_LINK_DETACH, &attr);
312 : : }
|