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