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