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