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 : 2218 : int bf_bpf(enum bf_bpf_cmd cmd, union bpf_attr *attr)
32 : : {
33 : 2218 : int r = (int)syscall(_BF_NR_bpf, cmd, attr, sizeof(*attr));
34 [ + + ]: 2218 : if (r < 0)
35 : 17 : return -errno;
36 : :
37 : : return r;
38 : : }
39 : :
40 : 125 : 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 : : assert(name);
49 : : assert(img);
50 : : assert(fd);
51 : :
52 : 125 : memset(&attr, 0, sizeof(attr));
53 : :
54 : 125 : attr.prog_type = prog_type;
55 : 125 : attr.insns = bf_ptr_to_u64(img);
56 : 125 : attr.insn_cnt = (unsigned int)img_len;
57 : 125 : attr.license = bf_ptr_to_u64("GPL");
58 : 125 : attr.expected_attach_type = attach_type;
59 : 125 : attr.log_buf = bf_ptr_to_u64(log_buf);
60 : 125 : attr.log_size = log_size;
61 : 125 : attr.log_level = 1;
62 : :
63 : 125 : (void)snprintf(attr.prog_name, BPF_OBJ_NAME_LEN, "%s", name);
64 : :
65 [ + + ]: 125 : if (token_fd != -1) {
66 : 1 : attr.prog_token_fd = token_fd;
67 : 1 : attr.prog_flags |= BPF_F_TOKEN_FD;
68 : : }
69 : :
70 : 125 : r = bf_bpf(BF_BPF_PROG_LOAD, &attr);
71 [ + + ]: 125 : if (r < 0)
72 : : return r;
73 : :
74 : 124 : *fd = r;
75 : :
76 : 124 : return 0;
77 : : }
78 : :
79 : 149 : int bf_bpf_map_lookup_elem(int fd, const void *key, void *value)
80 : : {
81 : : union bpf_attr attr;
82 : :
83 : : assert(key);
84 : : assert(value);
85 : :
86 : 149 : memset(&attr, 0, sizeof(attr));
87 : :
88 : 149 : attr.map_fd = fd;
89 : 149 : attr.key = (uint64_t)key;
90 : 149 : attr.value = (uint64_t)value;
91 : :
92 : 149 : return bf_bpf(BF_BPF_MAP_LOOKUP_ELEM, &attr);
93 : : }
94 : :
95 : 7 : int bf_bpf_map_get_info(int fd, struct bpf_map_info *info)
96 : : {
97 : : union bpf_attr attr;
98 : :
99 : : assert(info);
100 : :
101 : 7 : memset(&attr, 0, sizeof(attr));
102 : 7 : memset(info, 0, sizeof(*info));
103 : :
104 : 7 : attr.info.bpf_fd = fd;
105 : 7 : attr.info.info_len = sizeof(*info);
106 : 7 : attr.info.info = bf_ptr_to_u64(info);
107 : :
108 : 7 : return bf_bpf(BF_BPF_OBJ_GET_INFO_BY_FD, &attr);
109 : : }
110 : :
111 : 718 : int bf_bpf_obj_pin(const char *path, int fd, int dir_fd)
112 : : {
113 : : union bpf_attr attr;
114 : :
115 : : assert(path);
116 : : assert(dir_fd >= 0);
117 : : assert(path[0] == '/' ? !dir_fd : 1);
118 : :
119 : 718 : memset(&attr, 0, sizeof(attr));
120 : :
121 : 718 : attr.pathname = bf_ptr_to_u64(path);
122 : 718 : attr.bpf_fd = fd;
123 [ + + ]: 718 : attr.file_flags = dir_fd ? BPF_F_PATH_FD : 0;
124 : 718 : attr.path_fd = dir_fd;
125 : :
126 : 718 : return bf_bpf(BF_BPF_OBJ_PIN, &attr);
127 : : }
128 : :
129 : 30 : int bf_bpf_obj_get(const char *path, int dir_fd, int *fd)
130 : : {
131 : : union bpf_attr attr;
132 : : int r;
133 : :
134 : : assert(path);
135 : : assert(fd);
136 : : assert(dir_fd >= 0);
137 : : assert(path[0] == '/' ? !dir_fd : 1);
138 : :
139 : 30 : memset(&attr, 0, sizeof(attr));
140 : :
141 : 30 : attr.pathname = bf_ptr_to_u64(path);
142 [ + + ]: 30 : attr.file_flags = dir_fd ? BPF_F_PATH_FD : 0;
143 : 30 : attr.path_fd = dir_fd;
144 : :
145 : 30 : r = bf_bpf(BF_BPF_OBJ_GET, &attr);
146 [ + + ]: 30 : if (r < 0)
147 : : return r;
148 : :
149 : 26 : *fd = r;
150 : :
151 : 26 : return 0;
152 : : }
153 : :
154 : 3 : int bf_bpf_prog_run(int prog_fd, const void *pkt, size_t pkt_len,
155 : : const void *ctx, size_t ctx_len)
156 : : {
157 : : union bpf_attr attr;
158 : : int r;
159 : :
160 : : assert(pkt);
161 : : assert(pkt_len > 0);
162 : : assert(!(!!ctx ^ !!ctx_len));
163 : :
164 : 3 : memset(&attr, 0, sizeof(attr));
165 : :
166 : 3 : attr.test.prog_fd = prog_fd;
167 : 3 : attr.test.data_size_in = pkt_len;
168 : 3 : attr.test.data_in = ((unsigned long long)(pkt));
169 : 3 : attr.test.repeat = 1;
170 : :
171 [ + + ]: 3 : if (ctx_len) {
172 : 1 : attr.test.ctx_size_in = ctx_len;
173 : 1 : attr.test.ctx_in = ((unsigned long long)(ctx));
174 : : }
175 : :
176 : 3 : r = bf_bpf(BF_BPF_PROG_TEST_RUN, &attr);
177 [ + + ]: 3 : if (r)
178 [ + - ]: 1 : return bf_err_r(r, "failed to run the test program");
179 : :
180 : 2 : return (int)attr.test.retval;
181 : : }
182 : :
183 : 2 : int bf_bpf_token_create(int bpffs_fd)
184 : : {
185 : : union bpf_attr attr;
186 : :
187 : 2 : memset(&attr, 0, sizeof(attr));
188 : :
189 : 2 : attr.token_create.bpffs_fd = bpffs_fd;
190 : :
191 : 2 : return bf_bpf(BF_BPF_TOKEN_CREATE, &attr);
192 : : }
193 : :
194 : 124 : int bf_bpf_btf_load(const void *btf_data, size_t btf_data_len, int token_fd)
195 : : {
196 : : assert(btf_data);
197 : :
198 : : union bpf_attr attr;
199 : :
200 : 124 : memset(&attr, 0, sizeof(attr));
201 : :
202 : 124 : attr.btf = bf_ptr_to_u64(btf_data);
203 : 124 : attr.btf_size = btf_data_len;
204 : :
205 [ + + ]: 124 : if (token_fd != -1) {
206 : 1 : attr.btf_token_fd = token_fd;
207 : 1 : attr.btf_flags |= BPF_F_TOKEN_FD;
208 : : }
209 : :
210 : 124 : return bf_bpf(BF_BPF_BTF_LOAD, &attr);
211 : : }
212 : :
213 : 517 : int bf_bpf_map_create(const char *name, enum bf_bpf_map_type type,
214 : : size_t key_size, size_t value_size, size_t n_elems,
215 : : const struct bf_btf *btf, int token_fd)
216 : : {
217 : : assert(name);
218 : :
219 : : union bpf_attr attr;
220 : :
221 : 517 : memset(&attr, 0, sizeof(attr));
222 : :
223 : 517 : attr.map_type = type;
224 : 517 : attr.key_size = key_size;
225 : 517 : attr.value_size = value_size;
226 : 517 : attr.max_entries = n_elems;
227 : :
228 : : // NO_PREALLOC is *required* for LPM_TRIE map
229 [ + + ]: 517 : if (type == BF_BPF_MAP_TYPE_LPM_TRIE)
230 : 21 : attr.map_flags |= BPF_F_NO_PREALLOC;
231 : :
232 [ + + ]: 517 : if (token_fd != -1) {
233 : 1 : attr.map_token_fd = token_fd;
234 : 1 : attr.map_flags |= BPF_F_TOKEN_FD;
235 : : };
236 : :
237 [ + + ]: 517 : if (btf) {
238 : 122 : attr.btf_fd = btf->fd;
239 : 122 : attr.btf_key_type_id = btf->key_type_id;
240 : 122 : attr.btf_value_type_id = btf->value_type_id;
241 : : }
242 : :
243 : 517 : (void)snprintf(attr.map_name, BPF_OBJ_NAME_LEN, "%s", name);
244 : :
245 : 517 : return bf_bpf(BF_BPF_MAP_CREATE, &attr);
246 : : }
247 : :
248 : 273 : int bf_bpf_map_update_elem(int map_fd, const void *key, const void *value,
249 : : int flags)
250 : : {
251 : : assert(key);
252 : : assert(value);
253 : :
254 : : union bpf_attr attr;
255 : :
256 : 273 : memset(&attr, 0, sizeof(attr));
257 : :
258 : 273 : attr.map_fd = map_fd;
259 : 273 : attr.key = bf_ptr_to_u64(key);
260 : 273 : attr.value = bf_ptr_to_u64(value);
261 : 273 : attr.flags = flags;
262 : :
263 : 273 : return bf_bpf(BF_BPF_MAP_UPDATE_ELEM, &attr);
264 : : }
265 : :
266 : 103 : int bf_bpf_map_update_batch(int map_fd, const void *keys, const void *values,
267 : : size_t count, int flags)
268 : : {
269 : : assert(keys);
270 : : assert(values);
271 : :
272 : : union bpf_attr attr;
273 : :
274 : 103 : memset(&attr, 0, sizeof(attr));
275 : :
276 : 103 : attr.batch.map_fd = map_fd;
277 : 103 : attr.batch.keys = bf_ptr_to_u64(keys);
278 : 103 : attr.batch.values = bf_ptr_to_u64(values);
279 : 103 : attr.batch.count = count;
280 : 103 : attr.batch.flags = flags;
281 : :
282 : 103 : return bf_bpf(BF_BPF_MAP_UPDATE_BATCH, &attr);
283 : : }
284 : :
285 : 83 : int bf_bpf_link_create(int prog_fd, int target_fd, enum bf_hook hook, int flags,
286 : : uint32_t family, int32_t priority)
287 : : {
288 : : enum bf_bpf_attach_type attach_type;
289 : : union bpf_attr attr;
290 : :
291 : 83 : memset(&attr, 0, sizeof(attr));
292 : :
293 : 83 : attach_type = bf_hook_to_bpf_attach_type(hook);
294 : :
295 : 83 : attr.link_create.prog_fd = prog_fd;
296 : 83 : attr.link_create.target_fd = target_fd;
297 : 83 : attr.link_create.attach_type = attach_type;
298 : 83 : attr.link_create.flags = flags;
299 : :
300 [ + + ]: 83 : if (attach_type == BF_BPF_NETFILTER) {
301 : 16 : attr.link_create.netfilter.pf = family;
302 : 16 : attr.link_create.netfilter.hooknum = bf_hook_to_nf_hook(hook);
303 : 16 : attr.link_create.netfilter.priority = priority;
304 : : }
305 : :
306 : 83 : return bf_bpf(BF_BPF_LINK_CREATE, &attr);
307 : : }
308 : :
309 : 13 : int bf_bpf_link_update(int link_fd, int new_prog_fd)
310 : : {
311 : : union bpf_attr attr;
312 : :
313 : 13 : memset(&attr, 0, sizeof(attr));
314 : :
315 : 13 : attr.link_update.link_fd = link_fd;
316 : 13 : attr.link_update.new_map_fd = new_prog_fd;
317 : :
318 : 13 : return bf_bpf(BF_BPF_LINK_UPDATE, &attr);
319 : : }
320 : :
321 : 69 : int bf_bpf_link_detach(int link_fd)
322 : : {
323 : : union bpf_attr attr;
324 : :
325 : 69 : memset(&attr, 0, sizeof(attr));
326 : :
327 : 69 : attr.link_detach.link_fd = link_fd;
328 : :
329 : 69 : return bf_bpf(BF_BPF_LINK_DETACH, &attr);
330 : : }
|