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 "cgen/program.h"
7 : :
8 : : #include <linux/bpf.h>
9 : : #include <linux/bpf_common.h>
10 : : #include <linux/limits.h>
11 : :
12 : : #include <errno.h>
13 : : #include <fcntl.h>
14 : : #include <limits.h>
15 : : #include <stddef.h>
16 : : #include <stdint.h>
17 : : #include <stdio.h>
18 : : #include <stdlib.h>
19 : : #include <string.h>
20 : : #include <unistd.h>
21 : :
22 : : #include <bpfilter/bpf.h>
23 : : #include <bpfilter/btf.h>
24 : : #include <bpfilter/chain.h>
25 : : #include <bpfilter/counter.h>
26 : : #include <bpfilter/dump.h>
27 : : #include <bpfilter/flavor.h>
28 : : #include <bpfilter/helper.h>
29 : : #include <bpfilter/hook.h>
30 : : #include <bpfilter/io.h>
31 : : #include <bpfilter/list.h>
32 : : #include <bpfilter/logger.h>
33 : : #include <bpfilter/matcher.h>
34 : : #include <bpfilter/pack.h>
35 : : #include <bpfilter/rule.h>
36 : : #include <bpfilter/set.h>
37 : : #include <bpfilter/verdict.h>
38 : :
39 : : #include "cgen/cgroup.h"
40 : : #include "cgen/dump.h"
41 : : #include "cgen/fixup.h"
42 : : #include "cgen/jmp.h"
43 : : #include "cgen/matcher/icmp.h"
44 : : #include "cgen/matcher/ip4.h"
45 : : #include "cgen/matcher/ip6.h"
46 : : #include "cgen/matcher/meta.h"
47 : : #include "cgen/matcher/set.h"
48 : : #include "cgen/matcher/tcp.h"
49 : : #include "cgen/matcher/udp.h"
50 : : #include "cgen/nf.h"
51 : : #include "cgen/printer.h"
52 : : #include "cgen/prog/link.h"
53 : : #include "cgen/prog/map.h"
54 : : #include "cgen/stub.h"
55 : : #include "cgen/tc.h"
56 : : #include "cgen/xdp.h"
57 : : #include "ctx.h"
58 : : #include "filter.h"
59 : : #include "opts.h"
60 : :
61 : : #define _BF_LOG_BUF_SIZE \
62 : : (UINT32_MAX >> 8) /* verifier maximum in kernels <= 5.1 */
63 : : #define _BF_PROGRAM_DEFAULT_IMG_SIZE (1 << 6)
64 : : #define _BF_LOG_MAP_N_ENTRIES 1000
65 : : #define _BF_LOG_MAP_SIZE \
66 : : _bf_round_next_power_of_2(sizeof(struct bf_log) * _BF_LOG_MAP_N_ENTRIES)
67 : :
68 : 173 : static inline size_t _bf_round_next_power_of_2(size_t value)
69 : : {
70 : 173 : value--;
71 : 173 : value |= value >> 1;
72 : 173 : value |= value >> 2;
73 : 173 : value |= value >> 4;
74 : 173 : value |= value >> 8;
75 : 173 : value |= value >> 16;
76 : :
77 : 173 : return ++value;
78 : : }
79 : :
80 : : static const struct bf_flavor_ops *bf_flavor_ops_get(enum bf_flavor flavor)
81 : : {
82 : : static const struct bf_flavor_ops *flavor_ops[] = {
83 : : [BF_FLAVOR_TC] = &bf_flavor_ops_tc,
84 : : [BF_FLAVOR_NF] = &bf_flavor_ops_nf,
85 : : [BF_FLAVOR_XDP] = &bf_flavor_ops_xdp,
86 : : [BF_FLAVOR_CGROUP] = &bf_flavor_ops_cgroup,
87 : : };
88 : :
89 : : static_assert(ARRAY_SIZE(flavor_ops) == _BF_FLAVOR_MAX,
90 : : "missing entries in bf_flavor_ops array");
91 : :
92 : 67 : return flavor_ops[flavor];
93 : : }
94 : :
95 : 67 : int bf_program_new(struct bf_program **program, const struct bf_chain *chain)
96 : : {
97 : 67 : _free_bf_program_ struct bf_program *_program = NULL;
98 : : char name[BPF_OBJ_NAME_LEN];
99 : : uint32_t set_idx = 0;
100 : : int r;
101 : :
102 : : assert(program);
103 : : assert(chain);
104 : :
105 : 67 : _program = calloc(1, sizeof(*_program));
106 [ + - ]: 67 : if (!_program)
107 : : return -ENOMEM;
108 : :
109 : 67 : _program->flavor = bf_hook_to_flavor(chain->hook);
110 : 67 : _program->runtime.prog_fd = -1;
111 : 67 : _program->runtime.ops = bf_flavor_ops_get(_program->flavor);
112 : 67 : _program->runtime.chain = chain;
113 : :
114 : 67 : (void)snprintf(_program->prog_name, BPF_OBJ_NAME_LEN, "%s", "bf_prog");
115 : :
116 : 67 : r = bf_map_new(&_program->cmap, "counters_map", BF_MAP_TYPE_COUNTERS,
117 : : sizeof(uint32_t), sizeof(struct bf_counter), 1);
118 [ - + ]: 67 : if (r < 0)
119 [ # # ]: 0 : return bf_err_r(r, "failed to create the counters bf_map object");
120 : :
121 : 67 : r = bf_map_new(&_program->pmap, "printer_map", BF_MAP_TYPE_PRINTER,
122 : : sizeof(uint32_t), BF_MAP_VALUE_SIZE_UNKNOWN, 1);
123 [ - + ]: 67 : if (r < 0)
124 [ # # ]: 0 : return bf_err_r(r, "failed to create the printer bf_map object");
125 : :
126 : 67 : r = bf_map_new(&_program->lmap, "log_map", BF_MAP_TYPE_LOG, 0, 0,
127 : : _BF_LOG_MAP_SIZE);
128 [ - + ]: 67 : if (r < 0)
129 [ # # ]: 0 : return bf_err_r(r, "failed to create the log bf_map object");
130 : :
131 : 67 : _program->sets = bf_list_default(bf_map_free, bf_map_pack);
132 [ + + + + : 294 : bf_list_foreach (&chain->sets, set_node) {
+ + ]
133 : : struct bf_set *set = bf_list_node_get_data(set_node);
134 : 0 : _free_bf_map_ struct bf_map *map = NULL;
135 : :
136 : 80 : (void)snprintf(name, BPF_OBJ_NAME_LEN, "set_%04x", (uint8_t)set_idx++);
137 : 80 : r = bf_map_new_from_set(&map, name, set);
138 [ + - ]: 80 : if (r < 0)
139 : : return r;
140 : :
141 : 80 : r = bf_list_add_tail(&_program->sets, map);
142 [ + - ]: 80 : if (r < 0)
143 : : return r;
144 : 80 : TAKE_PTR(map);
145 : : };
146 : :
147 : 67 : r = bf_link_new(&_program->link, "bf_link");
148 [ + - ]: 67 : if (r)
149 : : return r;
150 : :
151 : 67 : r = bf_printer_new(&_program->printer);
152 [ + - ]: 67 : if (r)
153 : : return r;
154 : :
155 : 67 : bf_list_init(&_program->fixups,
156 : 67 : (bf_list_ops[]) {{.free = (bf_list_ops_free)bf_fixup_free}});
157 : :
158 : 67 : *program = TAKE_PTR(_program);
159 : :
160 : 67 : return 0;
161 : : }
162 : :
163 : 3 : int bf_program_new_from_pack(struct bf_program **program,
164 : : const struct bf_chain *chain, int dir_fd,
165 : : bf_rpack_node_t node)
166 : : {
167 : 3 : _free_bf_program_ struct bf_program *_program = NULL;
168 : 3 : _free_bf_link_ struct bf_link *link = NULL;
169 : : const void *img;
170 : : size_t img_len;
171 : : bf_rpack_node_t child, array_node;
172 : : int r;
173 : :
174 : : assert(program);
175 : : assert(chain);
176 : :
177 : 3 : r = bf_program_new(&_program, chain);
178 [ + - ]: 3 : if (r < 0)
179 : : return r;
180 : :
181 : 3 : bf_map_free(&_program->cmap);
182 : 3 : r = bf_rpack_kv_obj(node, "cmap", &child);
183 [ - + ]: 3 : if (r)
184 [ # # ]: 0 : return bf_rpack_key_err(r, "bf_program.cmap");
185 : 3 : r = bf_map_new_from_pack(&_program->cmap, dir_fd, child);
186 [ + - ]: 3 : if (r)
187 : : return r;
188 : :
189 : 3 : bf_map_free(&_program->pmap);
190 : 3 : r = bf_rpack_kv_obj(node, "pmap", &child);
191 [ - + ]: 3 : if (r)
192 [ # # ]: 0 : return bf_rpack_key_err(r, "bf_program.pmap");
193 : 3 : r = bf_map_new_from_pack(&_program->pmap, dir_fd, child);
194 [ + - ]: 3 : if (r)
195 : : return r;
196 : :
197 : 3 : bf_map_free(&_program->lmap);
198 : 3 : r = bf_rpack_kv_obj(node, "lmap", &child);
199 [ - + ]: 3 : if (r)
200 [ # # ]: 0 : return bf_rpack_key_err(r, "bf_program.lmap");
201 : 3 : r = bf_map_new_from_pack(&_program->lmap, dir_fd, child);
202 [ + - ]: 3 : if (r)
203 : : return r;
204 : :
205 : 3 : bf_list_clean(&_program->sets);
206 : 3 : _program->sets = bf_list_default(bf_map_free, bf_map_pack);
207 : 3 : r = bf_rpack_kv_array(node, "sets", &child);
208 [ - + ]: 3 : if (r)
209 [ # # ]: 0 : return bf_rpack_key_err(r, "bf_program.sets");
210 [ - + - - : 6 : bf_rpack_array_foreach (child, array_node) {
- + ]
211 : 0 : _free_bf_map_ struct bf_map *map = NULL;
212 : :
213 [ # # # # : 0 : r = bf_list_emplace(&_program->sets, bf_map_new_from_pack, map, dir_fd,
# # # # ]
214 : : array_node);
215 : : if (r)
216 [ # # ]: 0 : return bf_err_r(r, "failed to unpack bf_map into bf_program.sets");
217 : : }
218 : :
219 : : /* Try to restore the link: on success, replace the program's link with the
220 : : * restored on. If -ENOENT is returned, the link doesn't exist, meaning the
221 : : * program is not attached. Otherwise, return an error. */
222 : 3 : r = bf_rpack_kv_obj(node, "link", &child);
223 [ - + ]: 3 : if (r)
224 [ # # ]: 0 : return bf_rpack_key_err(r, "bf_program.link");
225 : 3 : r = bf_link_new_from_pack(&link, dir_fd, child);
226 [ + + ]: 3 : if (!r)
227 : 2 : bf_swap(_program->link, link);
228 [ - + ]: 1 : else if (r != -ENOENT)
229 [ # # ]: 0 : return bf_err_r(r, "failed to restore bf_program.link");
230 : :
231 : 3 : bf_printer_free(&_program->printer);
232 : 3 : r = bf_rpack_kv_obj(node, "printer", &child);
233 [ - + ]: 3 : if (r)
234 [ # # ]: 0 : return bf_rpack_key_err(r, "bf_program.printer");
235 : 3 : r = bf_printer_new_from_pack(&_program->printer, child);
236 [ + - ]: 3 : if (r)
237 : : return r;
238 : :
239 : 3 : r = bf_rpack_kv_bin(node, "img", &img, &img_len);
240 [ - + ]: 3 : if (r)
241 [ # # ]: 0 : return bf_rpack_key_err(r, "bf_program.img");
242 : 3 : _program->img = bf_memdup(img, img_len);
243 [ - + ]: 3 : if (!_program->img)
244 [ # # ]: 0 : return bf_rpack_key_err(-ENOMEM, "bf_program.img");
245 : 3 : _program->img_size = img_len / sizeof(struct bpf_insn);
246 : 3 : _program->img_cap = _program->img_size;
247 : :
248 : 3 : r = bf_bpf_obj_get(_program->prog_name, dir_fd, &_program->runtime.prog_fd);
249 [ - + ]: 3 : if (r < 0)
250 [ # # ]: 0 : return bf_err_r(r, "failed to restore bf_program.fd");
251 : :
252 : 3 : *program = TAKE_PTR(_program);
253 : :
254 : 3 : return 0;
255 : : }
256 : :
257 : 197 : void bf_program_free(struct bf_program **program)
258 : : {
259 [ + + ]: 197 : if (!*program)
260 : : return;
261 : :
262 : 67 : bf_list_clean(&(*program)->fixups);
263 : 67 : free((*program)->img);
264 : :
265 : : /* Close the file descriptors if they are still open. If --transient is
266 : : * used, then the file descriptors are already closed (as
267 : : * bf_program_unload() has been called). Otherwise, bf_program_unload()
268 : : * won't be called, but the programs are pinned, so they can be closed
269 : : * safely. */
270 : 67 : closep(&(*program)->runtime.prog_fd);
271 : :
272 : 67 : bf_map_free(&(*program)->cmap);
273 : 67 : bf_map_free(&(*program)->pmap);
274 : 67 : bf_map_free(&(*program)->lmap);
275 : 67 : bf_list_clean(&(*program)->sets);
276 : 67 : bf_link_free(&(*program)->link);
277 : 67 : bf_printer_free(&(*program)->printer);
278 : :
279 : 67 : free(*program);
280 : 67 : *program = NULL;
281 : : }
282 : :
283 : 169 : int bf_program_pack(const struct bf_program *program, bf_wpack_t *pack)
284 : : {
285 : : assert(program);
286 : : assert(pack);
287 : :
288 : 169 : bf_wpack_open_object(pack, "cmap");
289 : 169 : bf_map_pack(program->cmap, pack);
290 : 169 : bf_wpack_close_object(pack);
291 : :
292 : 169 : bf_wpack_open_object(pack, "pmap");
293 : 169 : bf_map_pack(program->pmap, pack);
294 : 169 : bf_wpack_close_object(pack);
295 : :
296 : 169 : bf_wpack_open_object(pack, "lmap");
297 : 169 : bf_map_pack(program->lmap, pack);
298 : 169 : bf_wpack_close_object(pack);
299 : :
300 : 169 : bf_wpack_kv_list(pack, "sets", &program->sets);
301 : :
302 : 169 : bf_wpack_open_object(pack, "link");
303 : 169 : bf_link_pack(program->link, pack);
304 : 169 : bf_wpack_close_object(pack);
305 : :
306 : 169 : bf_wpack_open_object(pack, "printer");
307 : 169 : bf_printer_pack(program->printer, pack);
308 : 169 : bf_wpack_close_object(pack);
309 : :
310 : 169 : bf_wpack_kv_bin(pack, "img", program->img,
311 : 169 : program->img_size * sizeof(struct bpf_insn));
312 : :
313 [ - + ]: 169 : return bf_wpack_is_valid(pack) ? 0 : -EINVAL;
314 : : }
315 : :
316 : 3 : void bf_program_dump(const struct bf_program *program, prefix_t *prefix)
317 : : {
318 : : assert(program);
319 : : assert(prefix);
320 : :
321 [ + - ]: 3 : DUMP(prefix, "struct bf_program at %p", program);
322 : :
323 : 3 : bf_dump_prefix_push(prefix);
324 : :
325 [ + - ]: 3 : DUMP(prefix, "prog_name: %s", program->prog_name);
326 : :
327 [ + - ]: 3 : DUMP(prefix, "cmap: struct bf_map *");
328 : 3 : bf_dump_prefix_push(prefix);
329 : 3 : bf_map_dump(program->cmap, bf_dump_prefix_last(prefix));
330 : 3 : bf_dump_prefix_pop(prefix);
331 : :
332 [ + - ]: 3 : DUMP(prefix, "pmap: struct bf_map *");
333 : 3 : bf_dump_prefix_push(prefix);
334 : 3 : bf_map_dump(program->pmap, bf_dump_prefix_last(prefix));
335 : 3 : bf_dump_prefix_pop(prefix);
336 : :
337 [ + - ]: 3 : DUMP(prefix, "lmap: struct bf_map *");
338 : 3 : bf_dump_prefix_push(prefix);
339 : 3 : bf_map_dump(program->lmap, bf_dump_prefix_last(prefix));
340 : 3 : bf_dump_prefix_pop(prefix);
341 : :
342 [ + - ]: 3 : DUMP(prefix, "sets: bf_list<bf_map>[%lu]", bf_list_size(&program->sets));
343 : 3 : bf_dump_prefix_push(prefix);
344 [ - + - - : 6 : bf_list_foreach (&program->sets, map_node) {
- + ]
345 : : struct bf_map *map = bf_list_node_get_data(map_node);
346 : :
347 [ # # ]: 0 : if (bf_list_is_tail(&program->sets, map_node))
348 : 0 : bf_dump_prefix_last(prefix);
349 : :
350 : 0 : bf_map_dump(map, prefix);
351 : : }
352 : 3 : bf_dump_prefix_pop(prefix);
353 : :
354 [ + - ]: 3 : DUMP(prefix, "link: struct bf_link *");
355 : 3 : bf_dump_prefix_push(prefix);
356 : 3 : bf_link_dump(program->link, prefix);
357 : 3 : bf_dump_prefix_pop(prefix);
358 : :
359 [ + - ]: 3 : DUMP(prefix, "printer: struct bf_printer *");
360 : 3 : bf_dump_prefix_push(prefix);
361 : 3 : bf_printer_dump(program->printer, prefix);
362 : 3 : bf_dump_prefix_pop(prefix);
363 : :
364 [ + - ]: 3 : DUMP(prefix, "img: %p", program->img);
365 [ + - ]: 3 : DUMP(prefix, "img_size: %lu", program->img_size);
366 [ + - ]: 3 : DUMP(prefix, "img_cap: %lu", program->img_cap);
367 : :
368 [ + - ]: 3 : DUMP(prefix, "fixups: bf_list<struct bf_fixup>[%lu]",
369 : : bf_list_size(&program->fixups));
370 : 3 : bf_dump_prefix_push(prefix);
371 [ - + - - : 6 : bf_list_foreach (&program->fixups, fixup_node) {
- + ]
372 : : struct bf_fixup *fixup = bf_list_node_get_data(fixup_node);
373 : :
374 [ # # ]: 0 : if (bf_list_is_tail(&program->fixups, fixup_node))
375 : 0 : bf_dump_prefix_last(prefix);
376 : :
377 : 0 : bf_fixup_dump(fixup, prefix);
378 : : }
379 : 3 : bf_dump_prefix_pop(prefix);
380 : :
381 [ + - ]: 3 : DUMP(bf_dump_prefix_last(prefix), "runtime: <anonymous>");
382 : 3 : bf_dump_prefix_push(prefix);
383 [ + - ]: 3 : DUMP(prefix, "prog_fd: %d", program->runtime.prog_fd);
384 [ + - ]: 3 : DUMP(bf_dump_prefix_last(prefix), "ops: %p", program->runtime.ops);
385 : 3 : bf_dump_prefix_pop(prefix);
386 : :
387 : 3 : bf_dump_prefix_pop(prefix);
388 : 3 : }
389 : :
390 : 237 : int bf_program_grow_img(struct bf_program *program)
391 : : {
392 : : size_t new_cap = _BF_PROGRAM_DEFAULT_IMG_SIZE;
393 : : int r;
394 : :
395 : : assert(program);
396 : :
397 [ + + ]: 237 : if (program->img)
398 : 173 : new_cap = _bf_round_next_power_of_2(program->img_cap << 1);
399 : :
400 : 237 : r = bf_realloc((void **)&program->img, new_cap * sizeof(struct bpf_insn));
401 [ - + ]: 237 : if (r < 0) {
402 [ # # ]: 0 : return bf_err_r(r, "failed to grow program img from %lu to %lu insn",
403 : : program->img_cap, new_cap);
404 : : }
405 : :
406 : 237 : program->img_cap = new_cap;
407 : :
408 : 237 : return 0;
409 : : }
410 : :
411 : 4446 : static void _bf_program_fixup_insn(struct bpf_insn *insn,
412 : : enum bf_fixup_insn type, int32_t value)
413 : : {
414 [ + + - ]: 4446 : switch (type) {
415 : 2977 : case BF_FIXUP_INSN_OFF:
416 : : assert(!insn->off);
417 : : assert(value < SHRT_MAX);
418 : 2977 : insn->off = (int16_t)value;
419 : 2977 : break;
420 : 1469 : case BF_FIXUP_INSN_IMM:
421 : : assert(!insn->imm);
422 : 1469 : insn->imm = value;
423 : 1469 : break;
424 : 0 : default:
425 [ # # ]: 0 : bf_abort(
426 : : "unsupported fixup instruction type, this should not happen: %d",
427 : : type);
428 : : break;
429 : : }
430 : 4446 : }
431 : :
432 : 624 : static int _bf_program_fixup(struct bf_program *program,
433 : : enum bf_fixup_type type)
434 : : {
435 : : assert(program);
436 : : assert(type >= 0 && type < _BF_FIXUP_TYPE_MAX);
437 : :
438 [ + + + + : 35442 : bf_list_foreach (&program->fixups, fixup_node) {
+ + ]
439 : : enum bf_fixup_insn insn_type = _BF_FIXUP_INSN_MAX;
440 : : int32_t value;
441 : : size_t offset;
442 : : struct bf_fixup *fixup = bf_list_node_get_data(fixup_node);
443 : 17097 : struct bpf_insn *insn = &program->img[fixup->insn];
444 : : struct bf_map *map;
445 : :
446 [ + + ]: 17097 : if (type != fixup->type)
447 : 12651 : continue;
448 : :
449 [ + + + + : 4446 : switch (type) {
+ + - ]
450 : 2977 : case BF_FIXUP_TYPE_JMP_NEXT_RULE:
451 : : insn_type = BF_FIXUP_INSN_OFF;
452 : 2977 : value = (int)(program->img_size - fixup->insn - 1U);
453 : 2977 : break;
454 : 590 : case BF_FIXUP_TYPE_COUNTERS_MAP_FD:
455 : : insn_type = BF_FIXUP_INSN_IMM;
456 : 590 : value = program->cmap->fd;
457 : 590 : break;
458 : 88 : case BF_FIXUP_TYPE_PRINTER_MAP_FD:
459 : : insn_type = BF_FIXUP_INSN_IMM;
460 : 88 : value = program->pmap->fd;
461 : 88 : break;
462 : 24 : case BF_FIXUP_TYPE_LOG_MAP_FD:
463 : : insn_type = BF_FIXUP_INSN_IMM;
464 : 24 : value = program->lmap->fd;
465 : 24 : break;
466 : 80 : case BF_FIXUP_TYPE_SET_MAP_FD:
467 : 80 : map = bf_list_get_at(&program->sets, fixup->attr.set_index);
468 [ - + ]: 80 : if (!map) {
469 [ # # ]: 0 : return bf_err_r(-ENOENT, "can't find set map at index %lu",
470 : : fixup->attr.set_index);
471 : : }
472 : : insn_type = BF_FIXUP_INSN_IMM;
473 : 80 : value = map->fd;
474 : 80 : break;
475 : 687 : case BF_FIXUP_ELFSTUB_CALL:
476 : : insn_type = BF_FIXUP_INSN_IMM;
477 : 687 : offset = program->elfstubs_location[fixup->attr.elfstub_id] -
478 : : fixup->insn - 1;
479 [ - + ]: 687 : if (offset >= INT_MAX)
480 [ # # ]: 0 : return bf_err_r(-EINVAL, "invalid ELF stub call offset");
481 : 687 : value = (int32_t)offset;
482 : 687 : break;
483 : 0 : default:
484 [ # # ]: 0 : bf_abort("unsupported fixup type, this should not happen: %d",
485 : : type);
486 : : break;
487 : : }
488 : :
489 : 4446 : _bf_program_fixup_insn(insn, insn_type, value);
490 : 4446 : bf_list_delete(&program->fixups, fixup_node);
491 : : }
492 : :
493 : : return 0;
494 : : }
495 : :
496 : 304 : static int _bf_program_generate_rule(struct bf_program *program,
497 : : struct bf_rule *rule)
498 : : {
499 : : int r;
500 : :
501 : : assert(program);
502 : : assert(rule);
503 : :
504 [ + - + + : 3530 : bf_list_foreach (&rule->matchers, matcher_node) {
+ + ]
505 : : struct bf_matcher *matcher = bf_list_node_get_data(matcher_node);
506 : :
507 [ + + + + : 1461 : switch (bf_matcher_get_type(matcher)) {
+ + + - ]
508 : 375 : case BF_MATCHER_META_IFACE:
509 : : case BF_MATCHER_META_L3_PROTO:
510 : : case BF_MATCHER_META_L4_PROTO:
511 : : case BF_MATCHER_META_PROBABILITY:
512 : : case BF_MATCHER_META_SPORT:
513 : : case BF_MATCHER_META_DPORT:
514 : : case BF_MATCHER_META_MARK:
515 : : case BF_MATCHER_META_FLOW_HASH:
516 : 375 : r = bf_matcher_generate_meta(program, matcher);
517 [ + - ]: 375 : if (r)
518 : : return r;
519 : : break;
520 : 132 : case BF_MATCHER_IP4_SADDR:
521 : : case BF_MATCHER_IP4_SNET:
522 : : case BF_MATCHER_IP4_DADDR:
523 : : case BF_MATCHER_IP4_DNET:
524 : : case BF_MATCHER_IP4_PROTO:
525 : : case BF_MATCHER_IP4_DSCP:
526 : 132 : r = bf_matcher_generate_ip4(program, matcher);
527 [ + - ]: 132 : if (r)
528 : : return r;
529 : : break;
530 : 250 : case BF_MATCHER_IP6_SADDR:
531 : : case BF_MATCHER_IP6_SNET:
532 : : case BF_MATCHER_IP6_DADDR:
533 : : case BF_MATCHER_IP6_DNET:
534 : : case BF_MATCHER_IP6_NEXTHDR:
535 : : case BF_MATCHER_IP6_DSCP:
536 : 250 : r = bf_matcher_generate_ip6(program, matcher);
537 [ + - ]: 250 : if (r)
538 : : return r;
539 : : break;
540 : 260 : case BF_MATCHER_TCP_SPORT:
541 : : case BF_MATCHER_TCP_DPORT:
542 : : case BF_MATCHER_TCP_FLAGS:
543 : 260 : r = bf_matcher_generate_tcp(program, matcher);
544 [ + - ]: 260 : if (r)
545 : : return r;
546 : : break;
547 : 160 : case BF_MATCHER_UDP_SPORT:
548 : : case BF_MATCHER_UDP_DPORT:
549 : 160 : r = bf_matcher_generate_udp(program, matcher);
550 [ + - ]: 160 : if (r)
551 : : return r;
552 : : break;
553 : 204 : case BF_MATCHER_ICMP_TYPE:
554 : : case BF_MATCHER_ICMP_CODE:
555 : : case BF_MATCHER_ICMPV6_TYPE:
556 : : case BF_MATCHER_ICMPV6_CODE:
557 : 204 : r = bf_matcher_generate_icmp(program, matcher);
558 [ + - ]: 204 : if (r)
559 : : return r;
560 : : break;
561 : 80 : case BF_MATCHER_SET:
562 : 80 : r = bf_matcher_generate_set(program, matcher);
563 [ + - ]: 80 : if (r)
564 : : return r;
565 : : break;
566 : 0 : default:
567 [ # # ]: 0 : return bf_err_r(-EINVAL, "unknown matcher type %d",
568 : : bf_matcher_get_type(matcher));
569 : : };
570 : : }
571 : :
572 [ + + ]: 304 : if (bf_rule_mark_is_set(rule)) {
573 [ - + ]: 10 : if (!program->runtime.ops->gen_inline_set_mark) {
574 [ # # ]: 0 : return bf_err_r(-ENOTSUP, "set mark is not supported by %s",
575 : : program->runtime.chain->name);
576 : : }
577 : :
578 : 10 : r = program->runtime.ops->gen_inline_set_mark(program,
579 : : bf_rule_mark_get(rule));
580 [ - + ]: 10 : if (r) {
581 [ # # ]: 0 : return bf_err_r(r,
582 : : "failed to generate bytecode to set mark for '%s'",
583 : : program->runtime.chain->name);
584 : : }
585 : : }
586 : :
587 [ + + ]: 304 : if (rule->log) {
588 [ - + ]: 33 : EMIT(program, BPF_MOV64_REG(BPF_REG_1, BPF_REG_10));
589 [ - + ]: 33 : EMIT(program, BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, BF_PROG_CTX_OFF(arg)));
590 [ - + ]: 33 : EMIT(program, BPF_MOV64_IMM(BPF_REG_2, rule->index));
591 [ - + ]: 33 : EMIT(program, BPF_MOV64_IMM(BPF_REG_3, rule->log));
592 [ - + ]: 33 : EMIT(program, BPF_MOV64_IMM(BPF_REG_4, rule->verdict));
593 : :
594 : : // Pack l3_proto and l4_proto
595 [ - + ]: 33 : EMIT(program, BPF_MOV64_REG(BPF_REG_5, BPF_REG_7));
596 [ - + ]: 33 : EMIT(program, BPF_ALU64_IMM(BPF_LSH, BPF_REG_5, 16));
597 [ - + ]: 33 : EMIT(program, BPF_ALU64_REG(BPF_OR, BPF_REG_5, BPF_REG_8));
598 : :
599 [ + - ]: 33 : EMIT_FIXUP_ELFSTUB(program, BF_ELFSTUB_LOG);
600 : : }
601 : :
602 [ + + ]: 304 : if (rule->counters) {
603 [ - + ]: 289 : EMIT(program, BPF_MOV64_REG(BPF_REG_1, BPF_REG_10));
604 [ - + ]: 289 : EMIT(program, BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, BF_PROG_CTX_OFF(arg)));
605 [ + - + - ]: 289 : EMIT_LOAD_COUNTERS_FD_FIXUP(program, BPF_REG_2);
606 [ - + ]: 289 : EMIT(program, BPF_MOV32_IMM(BPF_REG_3, rule->index));
607 [ + - ]: 289 : EMIT_FIXUP_ELFSTUB(program, BF_ELFSTUB_UPDATE_COUNTERS);
608 : : }
609 : :
610 [ + - + ]: 304 : switch (rule->verdict) {
611 : 264 : case BF_VERDICT_ACCEPT:
612 : : case BF_VERDICT_DROP:
613 : 264 : r = program->runtime.ops->get_verdict(rule->verdict);
614 [ + - ]: 264 : if (r < 0)
615 : : return r;
616 [ - + ]: 264 : EMIT(program, BPF_MOV64_IMM(BPF_REG_0, r));
617 [ - + ]: 264 : EMIT(program, BPF_EXIT_INSN());
618 : 264 : break;
619 : : case BF_VERDICT_CONTINUE:
620 : : // Fall through to next rule or default chain policy.
621 : : break;
622 : 0 : default:
623 [ # # ]: 0 : bf_abort("unsupported verdict, this should not happen: %d",
624 : : rule->verdict);
625 : : break;
626 : : }
627 : :
628 : 304 : r = _bf_program_fixup(program, BF_FIXUP_TYPE_JMP_NEXT_RULE);
629 [ - + ]: 304 : if (r)
630 [ # # ]: 0 : return bf_err_r(r, "failed to generate next rule fixups");
631 : :
632 : : return 0;
633 : : }
634 : :
635 : 64 : static int _bf_program_generate_elfstubs(struct bf_program *program)
636 : : {
637 : : const struct bf_elfstub *elfstub;
638 : : size_t start_at;
639 : : int r;
640 : :
641 : : assert(program);
642 : :
643 [ + - + + : 3066 : bf_list_foreach (&program->fixups, fixup_node) {
+ + ]
644 : : struct bf_fixup *fixup = bf_list_node_get_data(fixup_node);
645 : 1469 : size_t off = program->img_size;
646 : :
647 [ + + ]: 1469 : if (fixup->type != BF_FIXUP_ELFSTUB_CALL)
648 : 782 : continue;
649 : :
650 : : // Only generate each ELF stub once
651 [ + + ]: 687 : if (program->elfstubs_location[fixup->attr.elfstub_id])
652 : 535 : continue;
653 : :
654 [ + - ]: 152 : bf_dbg("generate ELF stub for ID %d", fixup->attr.elfstub_id);
655 : :
656 : 152 : elfstub = bf_ctx_get_elfstub(fixup->attr.elfstub_id);
657 [ - + ]: 152 : if (!elfstub) {
658 [ # # ]: 0 : return bf_err_r(-ENOENT, "no ELF stub found for ID %d",
659 : : fixup->attr.elfstub_id);
660 : : }
661 : :
662 : 152 : start_at = program->img_size;
663 : :
664 [ + + ]: 6974 : for (size_t i = 0; i < elfstub->ninsns; ++i) {
665 : 6822 : r = bf_program_emit(program, elfstub->insns[i]);
666 [ - + ]: 6822 : if (r)
667 [ # # ]: 0 : return bf_err_r(r, "failed to insert ELF stub instruction");
668 : : }
669 : :
670 [ + + - + : 480 : bf_list_foreach (&elfstub->strs, pstr_node) {
+ + ]
671 : 88 : _free_bf_fixup_ struct bf_fixup *fixup = NULL;
672 : : struct bf_printk_str *pstr = bf_list_node_get_data(pstr_node);
673 : 88 : size_t insn_idx = start_at + pstr->insn_idx;
674 : : const struct bf_printer_msg *msg =
675 : 88 : bf_printer_add_msg(program->printer, pstr->str);
676 : : struct bpf_insn ld_insn[2] = {
677 : : BPF_LD_MAP_FD(BPF_REG_1, 0),
678 : : };
679 : :
680 : : ld_insn[0].src_reg = BPF_PSEUDO_MAP_VALUE;
681 : 88 : ld_insn[1].imm = (int)bf_printer_msg_offset(msg);
682 : :
683 : 88 : program->img[insn_idx] = ld_insn[0];
684 : 88 : program->img[insn_idx + 1] = ld_insn[1];
685 : :
686 : 88 : r = bf_fixup_new(&fixup, BF_FIXUP_TYPE_PRINTER_MAP_FD, insn_idx,
687 : : NULL);
688 [ + - ]: 88 : if (r)
689 : : return r;
690 : :
691 : 88 : r = bf_list_add_tail(&program->fixups, fixup);
692 [ + - ]: 88 : if (r)
693 : : return r;
694 : :
695 : 88 : TAKE_PTR(fixup);
696 : : }
697 : :
698 : 152 : program->elfstubs_location[fixup->attr.elfstub_id] = off;
699 : : }
700 : :
701 : : return 0;
702 : : }
703 : :
704 : 28346 : int bf_program_emit(struct bf_program *program, struct bpf_insn insn)
705 : : {
706 : : int r;
707 : :
708 : : assert(program);
709 : :
710 [ + + ]: 28346 : if (program->img_size == program->img_cap) {
711 : 183 : r = bf_program_grow_img(program);
712 [ + - ]: 183 : if (r)
713 : : return r;
714 : : }
715 : :
716 : 28346 : program->img[program->img_size++] = insn;
717 : :
718 : 28346 : return 0;
719 : : }
720 : :
721 : 237 : int bf_program_emit_kfunc_call(struct bf_program *program, const char *name)
722 : : {
723 : : int r;
724 : :
725 : : assert(program);
726 : : assert(name);
727 : :
728 : 237 : r = bf_btf_get_id(name);
729 [ + - ]: 237 : if (r < 0)
730 : : return r;
731 : :
732 [ - + ]: 237 : EMIT(program, ((struct bpf_insn) {.code = BPF_JMP | BPF_CALL,
733 : : .dst_reg = 0,
734 : : .src_reg = BPF_PSEUDO_KFUNC_CALL,
735 : : .off = 0,
736 : : .imm = r}));
737 : :
738 : 237 : return 0;
739 : : }
740 : :
741 : 3671 : int bf_program_emit_fixup(struct bf_program *program, enum bf_fixup_type type,
742 : : struct bpf_insn insn, const union bf_fixup_attr *attr)
743 : : {
744 : 3671 : _free_bf_fixup_ struct bf_fixup *fixup = NULL;
745 : : int r;
746 : :
747 : : assert(program);
748 : :
749 [ + + ]: 3671 : if (program->img_size == program->img_cap) {
750 : 18 : r = bf_program_grow_img(program);
751 [ + - ]: 18 : if (r)
752 : : return r;
753 : : }
754 : :
755 : 3671 : r = bf_fixup_new(&fixup, type, program->img_size, attr);
756 [ + - ]: 3671 : if (r)
757 : : return r;
758 : :
759 : 3671 : r = bf_list_add_tail(&program->fixups, fixup);
760 [ + - ]: 3671 : if (r)
761 : : return r;
762 : :
763 : 3671 : TAKE_PTR(fixup);
764 : :
765 : : /* This call could fail and return an error, in which case it is not
766 : : * properly handled. However, this shouldn't be an issue as we previously
767 : : * test whether enough room is available in cgen.img, which is currently
768 : : * the only reason for EMIT() to fail. */
769 : 3671 : EMIT(program, insn);
770 : :
771 : : return 0;
772 : : }
773 : :
774 : 687 : int bf_program_emit_fixup_elfstub(struct bf_program *program,
775 : : enum bf_elfstub_id id)
776 : : {
777 : 687 : _free_bf_fixup_ struct bf_fixup *fixup = NULL;
778 : : int r;
779 : :
780 : : assert(program);
781 : :
782 [ + + ]: 687 : if (program->img_size == program->img_cap) {
783 : 36 : r = bf_program_grow_img(program);
784 [ + - ]: 36 : if (r)
785 : : return r;
786 : : }
787 : :
788 : 687 : r = bf_fixup_new(&fixup, BF_FIXUP_ELFSTUB_CALL, program->img_size, NULL);
789 [ + - ]: 687 : if (r)
790 : : return r;
791 : :
792 : 687 : fixup->attr.elfstub_id = id;
793 : :
794 : 687 : r = bf_list_add_tail(&program->fixups, fixup);
795 [ + - ]: 687 : if (r)
796 : : return r;
797 : :
798 : 687 : TAKE_PTR(fixup);
799 : :
800 [ - + ]: 687 : EMIT(program, BPF_CALL_REL(0));
801 : :
802 : 687 : return 0;
803 : : }
804 : :
805 : 64 : int bf_program_generate(struct bf_program *program)
806 : : {
807 : 64 : const struct bf_chain *chain = program->runtime.chain;
808 : : int r;
809 : :
810 : : // Save the program's argument into the context.
811 [ - + ]: 64 : EMIT(program,
812 : : BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_1, BF_PROG_CTX_OFF(arg)));
813 : :
814 : : // Reset the protocol ID registers
815 [ - + ]: 64 : EMIT(program, BPF_MOV64_IMM(BPF_REG_7, 0));
816 [ - + ]: 64 : EMIT(program, BPF_MOV64_IMM(BPF_REG_8, 0));
817 : :
818 : : // If at least one rule logs the matched packets, populate ctx->log_map
819 [ + + ]: 64 : if (program->runtime.chain->flags & BF_FLAG(BF_CHAIN_LOG)) {
820 [ + - + - ]: 24 : EMIT_LOAD_LOG_FD_FIXUP(program, BPF_REG_2);
821 [ - + ]: 24 : EMIT(program, BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_2,
822 : : BF_PROG_CTX_OFF(log_map)));
823 : : }
824 : :
825 : : // Zeroing IPv6 extension headers
826 [ + + ]: 64 : if (program->runtime.chain->flags & BF_FLAG(BF_CHAIN_STORE_NEXTHDR)) {
827 [ - + ]: 10 : EMIT(program, BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_7,
828 : : BF_PROG_CTX_OFF(ipv6_eh)));
829 : : }
830 : :
831 : 64 : r = program->runtime.ops->gen_inline_prologue(program);
832 [ + - ]: 64 : if (r)
833 : : return r;
834 : :
835 [ + + + + : 736 : bf_list_foreach (&chain->rules, rule_node) {
+ + ]
836 : 304 : r = _bf_program_generate_rule(program,
837 : : bf_list_node_get_data(rule_node));
838 [ + - ]: 304 : if (r)
839 : : return r;
840 : : }
841 : :
842 : 64 : r = program->runtime.ops->gen_inline_epilogue(program);
843 [ + - ]: 64 : if (r)
844 : : return r;
845 : :
846 : : // Call the update counters function
847 : : /// @todo Allow chains to have no counters at all.
848 [ - + ]: 64 : EMIT(program, BPF_MOV64_REG(BPF_REG_1, BPF_REG_10));
849 [ - + ]: 64 : EMIT(program, BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, BF_PROG_CTX_OFF(arg)));
850 [ + - + - ]: 64 : EMIT_LOAD_COUNTERS_FD_FIXUP(program, BPF_REG_2);
851 [ - + ]: 64 : EMIT(program,
852 : : BPF_MOV32_IMM(BPF_REG_3, bf_program_chain_counter_idx(program)));
853 [ + - ]: 64 : EMIT_FIXUP_ELFSTUB(program, BF_ELFSTUB_UPDATE_COUNTERS);
854 : :
855 : 64 : r = program->runtime.ops->get_verdict(chain->policy);
856 [ + - ]: 64 : if (r < 0)
857 : : return r;
858 [ - + ]: 64 : EMIT(program, BPF_MOV64_IMM(BPF_REG_0, r));
859 [ - + ]: 64 : EMIT(program, BPF_EXIT_INSN());
860 : :
861 : 64 : r = _bf_program_generate_elfstubs(program);
862 [ + - ]: 64 : if (r)
863 : : return r;
864 : :
865 : 64 : r = _bf_program_fixup(program, BF_FIXUP_ELFSTUB_CALL);
866 [ - + ]: 64 : if (r)
867 [ # # ]: 0 : return bf_err_r(r, "failed to generate ELF stub call fixups");
868 : :
869 : : return 0;
870 : : }
871 : :
872 : 64 : static int _bf_program_load_printer_map(struct bf_program *program)
873 : : {
874 : 64 : _cleanup_free_ void *pstr = NULL;
875 : : size_t pstr_len;
876 : 64 : uint32_t key = 0;
877 : : int r;
878 : :
879 : : assert(program);
880 : :
881 : 64 : r = bf_printer_assemble(program->printer, &pstr, &pstr_len);
882 [ - + ]: 64 : if (r)
883 [ # # ]: 0 : return bf_err_r(r, "failed to assemble printer map string");
884 : :
885 : 64 : r = bf_map_set_value_size(program->pmap, pstr_len);
886 [ + - ]: 64 : if (r < 0)
887 : : return r;
888 : :
889 : 64 : r = bf_map_create(program->pmap);
890 [ + - ]: 64 : if (r < 0)
891 : : return r;
892 : :
893 : 64 : r = bf_map_set_elem(program->pmap, &key, pstr);
894 [ + - ]: 64 : if (r)
895 : : return r;
896 : :
897 : 64 : r = _bf_program_fixup(program, BF_FIXUP_TYPE_PRINTER_MAP_FD);
898 [ - + ]: 64 : if (r) {
899 : 0 : bf_map_destroy(program->pmap);
900 [ # # ]: 0 : return bf_err_r(r, "failed to fixup printer map FD");
901 : : }
902 : :
903 : : return 0;
904 : : }
905 : :
906 : 64 : static int _bf_program_load_counters_map(struct bf_program *program)
907 : : {
908 : 64 : _cleanup_close_ int _fd = -1;
909 : : int r;
910 : :
911 : : assert(program);
912 : :
913 : 64 : r = bf_map_set_n_elems(program->cmap,
914 : 64 : bf_list_size(&program->runtime.chain->rules) + 2);
915 [ + - ]: 64 : if (r < 0)
916 : : return r;
917 : :
918 : 64 : r = bf_map_create(program->cmap);
919 [ + - ]: 64 : if (r < 0)
920 : : return r;
921 : :
922 : 64 : r = _bf_program_fixup(program, BF_FIXUP_TYPE_COUNTERS_MAP_FD);
923 [ - + ]: 64 : if (r < 0) {
924 : 0 : bf_map_destroy(program->cmap);
925 [ # # ]: 0 : return bf_err_r(r, "failed to fixup counters map FD");
926 : : }
927 : :
928 : : return 0;
929 : : }
930 : :
931 : 64 : static int _bf_program_load_log_map(struct bf_program *program)
932 : : {
933 : 64 : _cleanup_close_ int _fd = -1;
934 : : int r;
935 : :
936 : : assert(program);
937 : :
938 : 64 : r = bf_map_create(program->lmap);
939 [ + - ]: 64 : if (r < 0)
940 : : return r;
941 : :
942 : 64 : r = _bf_program_fixup(program, BF_FIXUP_TYPE_LOG_MAP_FD);
943 [ - + ]: 64 : if (r < 0) {
944 : 0 : bf_map_destroy(program->lmap);
945 [ # # ]: 0 : return bf_err_r(r, "failed to fixup log map FD");
946 : : }
947 : :
948 : : return 0;
949 : : }
950 : :
951 : 64 : static int _bf_program_load_sets_maps(struct bf_program *new_prog)
952 : : {
953 : : const bf_list_node *set_node;
954 : : const bf_list_node *map_node;
955 : : int r;
956 : :
957 : : assert(new_prog);
958 : :
959 : 64 : set_node = bf_list_get_head(&new_prog->runtime.chain->sets);
960 : : map_node = bf_list_get_head(&new_prog->sets);
961 : :
962 : : // Fill the bf_map with the sets content
963 [ + + ]: 144 : while (set_node && map_node) {
964 : : _cleanup_free_ uint8_t *values = NULL;
965 : : _cleanup_free_ uint8_t *keys = NULL;
966 : : struct bf_set *set = bf_list_node_get_data(set_node);
967 : : struct bf_map *map = bf_list_node_get_data(map_node);
968 : : size_t nelems = bf_list_size(&set->elems);
969 : : size_t idx = 0;
970 : :
971 : 80 : r = bf_map_create(map);
972 [ - + ]: 80 : if (r < 0) {
973 [ # # ]: 0 : r = bf_err_r(r, "failed to create BPF map for set");
974 : 0 : goto err_destroy_maps;
975 : : }
976 : :
977 : 80 : values = malloc(nelems);
978 [ - + ]: 80 : if (!values) {
979 [ # # ]: 0 : r = bf_err_r(errno, "failed to allocate map values");
980 : 0 : goto err_destroy_maps;
981 : : }
982 : :
983 : 80 : keys = malloc(set->elem_size * nelems);
984 [ - + ]: 80 : if (!keys) {
985 [ # # ]: 0 : r = bf_err_r(errno, "failed to allocate map keys");
986 : 0 : goto err_destroy_maps;
987 : : }
988 : :
989 [ + - + + ]: 500 : bf_list_foreach (&set->elems, elem_node) {
990 : : void *elem = bf_list_node_get_data(elem_node);
991 : :
992 : 210 : memcpy(keys + (idx * set->elem_size), elem, set->elem_size);
993 : 210 : values[idx] = 1;
994 [ + + ]: 210 : ++idx;
995 : : }
996 : :
997 : 80 : r = bf_bpf_map_update_batch(map->fd, keys, values, nelems, BPF_ANY);
998 [ - + ]: 80 : if (r < 0) {
999 [ # # ]: 0 : bf_err_r(r, "failed to add set elements to the map");
1000 : 0 : goto err_destroy_maps;
1001 : : }
1002 : :
1003 : : set_node = bf_list_node_next(set_node);
1004 : : map_node = bf_list_node_next(map_node);
1005 : : }
1006 : :
1007 : 64 : r = _bf_program_fixup(new_prog, BF_FIXUP_TYPE_SET_MAP_FD);
1008 [ - + ]: 64 : if (r < 0)
1009 : 0 : goto err_destroy_maps;
1010 : :
1011 : : return 0;
1012 : :
1013 : 0 : err_destroy_maps:
1014 [ # # # # : 0 : bf_list_foreach (&new_prog->sets, map_node)
# # ]
1015 : 0 : bf_map_destroy(bf_list_node_get_data(map_node));
1016 : : return r;
1017 : : }
1018 : :
1019 : 64 : int bf_program_load(struct bf_program *prog)
1020 : : {
1021 : : _cleanup_free_ char *log_buf = NULL;
1022 : : int r;
1023 : :
1024 : : assert(prog);
1025 : :
1026 : 64 : r = _bf_program_load_sets_maps(prog);
1027 [ + - ]: 64 : if (r)
1028 : : return r;
1029 : :
1030 : 64 : r = _bf_program_load_counters_map(prog);
1031 [ + - ]: 64 : if (r)
1032 : : return r;
1033 : :
1034 : 64 : r = _bf_program_load_printer_map(prog);
1035 [ + - ]: 64 : if (r)
1036 : : return r;
1037 : :
1038 : 64 : r = _bf_program_load_log_map(prog);
1039 [ + - ]: 64 : if (r)
1040 : : return r;
1041 : :
1042 [ + - ]: 64 : if (bf_opts_is_verbose(BF_VERBOSE_DEBUG)) {
1043 : 64 : log_buf = malloc(_BF_LOG_BUF_SIZE);
1044 [ - + ]: 64 : if (!log_buf) {
1045 [ # # ]: 0 : return bf_err_r(-ENOMEM,
1046 : : "failed to allocate BPF_PROG_LOAD logs buffer");
1047 : : }
1048 : : }
1049 : :
1050 [ - + ]: 64 : if (bf_opts_is_verbose(BF_VERBOSE_BYTECODE))
1051 : 0 : bf_program_dump_bytecode(prog);
1052 : :
1053 [ - + ]: 64 : r = bf_bpf_prog_load(
1054 : 64 : prog->prog_name, bf_hook_to_bpf_prog_type(prog->runtime.chain->hook),
1055 : 64 : prog->img, prog->img_size,
1056 : 64 : bf_hook_to_bpf_attach_type(prog->runtime.chain->hook), log_buf,
1057 : : log_buf ? _BF_LOG_BUF_SIZE : 0, bf_ctx_token(), &prog->runtime.prog_fd);
1058 [ - + ]: 64 : if (r) {
1059 [ # # # # ]: 0 : return bf_err_r(r, "failed to load bf_program (%lu bytes):\n%s\nerrno:",
1060 : : prog->img_size, log_buf ? log_buf : "<NO LOG BUFFER>");
1061 : : }
1062 : :
1063 : : return r;
1064 : : }
1065 : :
1066 : 28 : int bf_program_attach(struct bf_program *prog, struct bf_hookopts **hookopts)
1067 : : {
1068 : : int r;
1069 : :
1070 : : assert(prog);
1071 : : assert(hookopts);
1072 : :
1073 : 28 : r = bf_link_attach(prog->link, prog->runtime.chain->hook, hookopts,
1074 : : prog->runtime.prog_fd);
1075 [ + + ]: 28 : if (r) {
1076 [ + - ]: 4 : return bf_err_r(r, "failed to attach bf_link for %s program",
1077 : : bf_flavor_to_str(prog->flavor));
1078 : : }
1079 : :
1080 : : return r;
1081 : : }
1082 : :
1083 : 0 : void bf_program_detach(struct bf_program *prog)
1084 : : {
1085 : : assert(prog);
1086 : :
1087 : 0 : bf_link_detach(prog->link);
1088 : 0 : }
1089 : :
1090 : 38 : void bf_program_unload(struct bf_program *prog)
1091 : : {
1092 : : assert(prog);
1093 : :
1094 : 38 : closep(&prog->runtime.prog_fd);
1095 : 38 : bf_link_detach(prog->link);
1096 : 38 : bf_map_destroy(prog->cmap);
1097 : 38 : bf_map_destroy(prog->pmap);
1098 : 38 : bf_map_destroy(prog->lmap);
1099 [ - + - - : 76 : bf_list_foreach (&prog->sets, map_node)
- + ]
1100 : 0 : bf_map_destroy(bf_list_node_get_data(map_node));
1101 : 38 : }
1102 : :
1103 : 32 : int bf_program_get_counter(const struct bf_program *program,
1104 : : uint32_t counter_idx, struct bf_counter *counter)
1105 : : {
1106 : : assert(program);
1107 : : assert(counter);
1108 : :
1109 : : int r;
1110 : :
1111 : 32 : r = bf_bpf_map_lookup_elem(program->cmap->fd, &counter_idx, counter);
1112 [ - + ]: 32 : if (r < 0)
1113 [ # # ]: 0 : return bf_err_r(errno, "failed to lookup counters map");
1114 : :
1115 : : return 0;
1116 : : }
1117 : :
1118 : 0 : int bf_cgen_set_counters(struct bf_program *program,
1119 : : const struct bf_counter *counters)
1120 : : {
1121 : : (void)program;
1122 : : (void)counters;
1123 : :
1124 : 0 : return -ENOTSUP;
1125 : : }
1126 : :
1127 : 62 : int bf_program_pin(struct bf_program *prog, int dir_fd)
1128 : : {
1129 : : const char *name;
1130 : : int r;
1131 : :
1132 : : assert(prog);
1133 : :
1134 : 62 : name = prog->runtime.chain->name;
1135 : :
1136 : 62 : r = bf_bpf_obj_pin(prog->prog_name, prog->runtime.prog_fd, dir_fd);
1137 [ - + ]: 62 : if (r) {
1138 [ # # ]: 0 : bf_err_r(r, "failed to pin BPF program for '%s'", name);
1139 : 0 : goto err_unpin_all;
1140 : : }
1141 : :
1142 : 62 : r = bf_map_pin(prog->cmap, dir_fd);
1143 [ - + ]: 62 : if (r) {
1144 [ # # ]: 0 : bf_err_r(r, "failed to pin BPF counters map for '%s'", name);
1145 : 0 : goto err_unpin_all;
1146 : : }
1147 : :
1148 : 62 : r = bf_map_pin(prog->pmap, dir_fd);
1149 [ - + ]: 62 : if (r) {
1150 [ # # ]: 0 : bf_err_r(r, "failed to pin BPF printer map for '%s'", name);
1151 : 0 : goto err_unpin_all;
1152 : : }
1153 : :
1154 : 62 : r = bf_map_pin(prog->lmap, dir_fd);
1155 [ - + ]: 62 : if (r) {
1156 [ # # ]: 0 : bf_err_r(r, "failed to pin BPF log map for '%s'", name);
1157 : 0 : goto err_unpin_all;
1158 : : }
1159 : :
1160 [ + + + + : 284 : bf_list_foreach (&prog->sets, set_node) {
+ + ]
1161 : 80 : r = bf_map_pin(bf_list_node_get_data(set_node), dir_fd);
1162 [ - + ]: 80 : if (r) {
1163 [ # # ]: 0 : bf_err_r(r, "failed to pin BPF set map for '%s'", name);
1164 : 0 : goto err_unpin_all;
1165 : : }
1166 : : }
1167 : :
1168 : : // If a link exists, pin it too.
1169 [ + + ]: 62 : if (prog->link->hookopts) {
1170 : 21 : r = bf_link_pin(prog->link, dir_fd);
1171 [ + - ]: 21 : if (r) {
1172 [ # # ]: 0 : bf_err_r(r, "failed to pin BPF link for '%s'", name);
1173 : 0 : goto err_unpin_all;
1174 : : }
1175 : : }
1176 : :
1177 : : return 0;
1178 : :
1179 : 0 : err_unpin_all:
1180 : 0 : bf_program_unpin(prog, dir_fd);
1181 : 0 : return r;
1182 : : }
1183 : :
1184 : 42 : void bf_program_unpin(struct bf_program *prog, int dir_fd)
1185 : : {
1186 : : assert(prog);
1187 : :
1188 : 42 : bf_map_unpin(prog->cmap, dir_fd);
1189 : 42 : bf_map_unpin(prog->pmap, dir_fd);
1190 : 42 : bf_map_unpin(prog->lmap, dir_fd);
1191 : :
1192 [ - + - - : 84 : bf_list_foreach (&prog->sets, set_node)
- + ]
1193 : 0 : bf_map_unpin(bf_list_node_get_data(set_node), dir_fd);
1194 : :
1195 : 42 : bf_link_unpin(prog->link, dir_fd);
1196 : :
1197 : 42 : unlinkat(dir_fd, prog->prog_name, 0);
1198 : 42 : }
1199 : :
1200 : 64 : size_t bf_program_chain_counter_idx(const struct bf_program *program)
1201 : : {
1202 : 64 : return bf_list_size(&program->runtime.chain->rules);
1203 : : }
1204 : :
1205 : 237 : size_t bf_program_error_counter_idx(const struct bf_program *program)
1206 : : {
1207 : 237 : return bf_list_size(&program->runtime.chain->rules) + 1;
1208 : : }
|