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/cgen.h"
7 : :
8 : : #include <errno.h>
9 : : #include <stddef.h>
10 : : #include <stdint.h>
11 : : #include <stdio.h>
12 : : #include <stdlib.h>
13 : : #include <string.h>
14 : : #include <sys/types.h>
15 : : #include <unistd.h>
16 : :
17 : : #include <bpfilter/bpf.h>
18 : : #include <bpfilter/chain.h>
19 : : #include <bpfilter/core/list.h>
20 : : #include <bpfilter/counter.h>
21 : : #include <bpfilter/ctx.h>
22 : : #include <bpfilter/dump.h>
23 : : #include <bpfilter/helper.h>
24 : : #include <bpfilter/hook.h>
25 : : #include <bpfilter/io.h>
26 : : #include <bpfilter/logger.h>
27 : : #include <bpfilter/pack.h>
28 : :
29 : : #include "cgen/dump.h"
30 : : #include "cgen/handle.h"
31 : : #include "cgen/prog/link.h"
32 : : #include "cgen/prog/map.h"
33 : : #include "cgen/program.h"
34 : :
35 : : #define _BF_PROG_NAME "bf_prog"
36 : : #define _BF_CTX_PIN_NAME "bf_ctx"
37 : : #define _BF_CTX_TMP_PIN_NAME "bf_ctx_tmp"
38 : :
39 : 2598 : static int _bf_cgen_get_chain_pindir_fd(const char *name)
40 : : {
41 : 2598 : _cleanup_close_ int bf_fd = -1;
42 : 2598 : _cleanup_close_ int chain_fd = -1;
43 : :
44 : : assert(name);
45 : :
46 : 2598 : bf_fd = bf_ctx_get_pindir_fd();
47 [ + - ]: 2598 : if (bf_fd < 0)
48 : : return bf_fd;
49 : :
50 : 2598 : chain_fd = bf_opendir_at(bf_fd, name, true);
51 [ - + ]: 2598 : if (chain_fd < 0)
52 : : return chain_fd;
53 : :
54 : 2598 : return TAKE_FD(chain_fd);
55 : : }
56 : :
57 : : /**
58 : : * @brief Persist the codegen state to a BPF context map in bpffs.
59 : : *
60 : : * Serializes the cgen, creates a `BPF_MAP_TYPE_ARRAY` map with 1 entry
61 : : * containing the serialized data, pins it as `bf_ctx_tmp`, then atomically
62 : : * renames to `bf_ctx`. The map fd is closed after pinning - this is a
63 : : * one-shot operation.
64 : : *
65 : : * @param cgen Codegen to persist. Can't be NULL.
66 : : * @param dir_fd File descriptor of the chain's bpffs pin directory. Must be
67 : : * valid.
68 : : * @return 0 on success, or negative errno value on failure.
69 : : */
70 : 1180 : static int _bf_cgen_persist(const struct bf_cgen *cgen, int dir_fd)
71 : : {
72 : 1180 : _free_bf_wpack_ bf_wpack_t *pack = NULL;
73 : 1180 : _free_bf_map_ struct bf_map *map = NULL;
74 : : const void *data;
75 : : size_t data_len;
76 : 1180 : uint32_t key = 0;
77 : : int r;
78 : :
79 : : assert(cgen);
80 : :
81 : 1180 : r = bf_wpack_new(&pack);
82 [ - + ]: 1180 : if (r)
83 [ # # ]: 0 : return bf_err_r(r, "failed to create wpack for bf_cgen");
84 : :
85 : 1180 : r = bf_cgen_pack(cgen, pack);
86 [ - + ]: 1180 : if (r)
87 [ # # ]: 0 : return bf_err_r(r, "failed to pack bf_cgen");
88 : :
89 : 1180 : r = bf_wpack_get_data(pack, &data, &data_len);
90 [ - + ]: 1180 : if (r)
91 [ # # ]: 0 : return bf_err_r(r, "failed to get data from bf_cgen wpack");
92 : :
93 : 1180 : r = bf_map_new(&map, _BF_CTX_PIN_NAME, BF_MAP_TYPE_CTX, sizeof(uint32_t),
94 : : data_len, 1);
95 [ - + ]: 1180 : if (r)
96 [ # # ]: 0 : return bf_err_r(r, "failed to create context map");
97 : :
98 : 1180 : r = bf_map_set_elem(map, &key, (void *)data);
99 [ - + ]: 1180 : if (r)
100 [ # # ]: 0 : return bf_err_r(r, "failed to write context to map");
101 : :
102 : : // Remove stale temporary pin if present.
103 : 1180 : unlinkat(dir_fd, _BF_CTX_TMP_PIN_NAME, 0);
104 : :
105 : 1180 : r = bf_bpf_obj_pin(_BF_CTX_TMP_PIN_NAME, map->fd, dir_fd);
106 [ - + ]: 1180 : if (r)
107 [ # # ]: 0 : return bf_err_r(r, "failed to pin context map");
108 : :
109 : 1180 : r = renameat(dir_fd, _BF_CTX_TMP_PIN_NAME, dir_fd, _BF_CTX_PIN_NAME);
110 [ - + ]: 1180 : if (r) {
111 : 0 : r = -errno;
112 : 0 : unlinkat(dir_fd, _BF_CTX_TMP_PIN_NAME, 0);
113 [ # # ]: 0 : return bf_err_r(r, "failed to atomically replace context map pin");
114 : : }
115 : :
116 : : return 0;
117 : : }
118 : :
119 : 305 : static int _bf_cgen_new_from_pack(struct bf_cgen **cgen, bf_rpack_node_t node)
120 : : {
121 : 305 : _free_bf_cgen_ struct bf_cgen *_cgen = NULL;
122 : 305 : _cleanup_close_ int dir_fd = -1;
123 : : bf_rpack_node_t child;
124 : : int r;
125 : :
126 : : assert(cgen);
127 : :
128 : 305 : _cgen = calloc(1, sizeof(*_cgen));
129 [ + - ]: 305 : if (!_cgen)
130 : : return -ENOMEM;
131 : :
132 : 305 : r = bf_rpack_kv_obj(node, "chain", &child);
133 [ - + ]: 305 : if (r)
134 [ # # ]: 0 : return bf_rpack_key_err(r, "bf_cgen.chain");
135 : :
136 : 305 : r = bf_chain_new_from_pack(&_cgen->chain, child);
137 [ - + ]: 305 : if (r)
138 [ # # ]: 0 : return bf_rpack_key_err(r, "bf_cgen.chain");
139 : :
140 : 305 : r = bf_rpack_kv_node(node, "handle", &child);
141 [ - + ]: 305 : if (r)
142 [ # # ]: 0 : return bf_rpack_key_err(r, "bf_cgen.handle");
143 : :
144 : 305 : dir_fd = _bf_cgen_get_chain_pindir_fd(_cgen->chain->name);
145 [ - + ]: 305 : if (dir_fd < 0) {
146 [ # # ]: 0 : return bf_err_r(dir_fd, "failed to open chain pin directory for '%s'",
147 : : _cgen->chain->name);
148 : : }
149 : :
150 : 305 : r = bf_handle_new_from_pack(&_cgen->handle, dir_fd, child);
151 [ + - ]: 305 : if (r)
152 : : return r;
153 : :
154 : 305 : *cgen = TAKE_PTR(_cgen);
155 : :
156 : 305 : return 0;
157 : : }
158 : :
159 : 305 : int bf_cgen_new_from_dir_fd(struct bf_cgen **cgen, int dir_fd)
160 : : {
161 : 305 : _free_bf_rpack_ bf_rpack_t *pack = NULL;
162 : 305 : _cleanup_close_ int map_fd = -1;
163 : : _cleanup_free_ void *data = NULL;
164 : : struct bpf_map_info info;
165 : 305 : uint32_t key = 0;
166 : : int r;
167 : :
168 : : assert(cgen);
169 : : assert(dir_fd >= 0);
170 : :
171 : 305 : r = bf_bpf_obj_get(_BF_CTX_PIN_NAME, dir_fd, &map_fd);
172 [ - + ]: 305 : if (r < 0)
173 [ # # ]: 0 : return bf_err_r(r, "failed to open pinned context map");
174 : :
175 : 305 : r = bf_bpf_map_get_info(map_fd, &info);
176 [ - + ]: 305 : if (r)
177 [ # # ]: 0 : return bf_err_r(r, "failed to get context map info");
178 : :
179 [ - + ]: 305 : if (info.value_size == 0)
180 [ # # ]: 0 : return bf_err_r(-EINVAL, "invalid serialized context size");
181 : :
182 : 305 : data = malloc(info.value_size);
183 [ + - ]: 305 : if (!data)
184 : : return -ENOMEM;
185 : :
186 : 305 : r = bf_bpf_map_lookup_elem(map_fd, &key, data);
187 [ - + ]: 305 : if (r)
188 [ # # ]: 0 : return bf_err_r(r, "failed to read context from map");
189 : :
190 : 305 : r = bf_rpack_new(&pack, data, info.value_size);
191 [ - + ]: 305 : if (r)
192 [ # # ]: 0 : return bf_err_r(r, "failed to create rpack for bf_cgen");
193 : :
194 : 305 : r = _bf_cgen_new_from_pack(cgen, bf_rpack_root(pack));
195 [ - + ]: 305 : if (r)
196 [ # # ]: 0 : return bf_err_r(r, "failed to deserialize cgen from context map");
197 : :
198 : : return 0;
199 : : }
200 : :
201 : 1145 : int bf_cgen_new(struct bf_cgen **cgen, struct bf_chain **chain)
202 : : {
203 : 1145 : _free_bf_cgen_ struct bf_cgen *_cgen = NULL;
204 : : int r;
205 : :
206 : : assert(cgen);
207 : : assert(chain);
208 : :
209 : 1145 : _cgen = calloc(1, sizeof(*_cgen));
210 [ + - ]: 1145 : if (!_cgen)
211 : : return -ENOMEM;
212 : :
213 : 1145 : _cgen->chain = TAKE_PTR(*chain);
214 : :
215 : 1145 : r = bf_handle_new(&_cgen->handle, _BF_PROG_NAME);
216 [ + - ]: 1145 : if (r)
217 : : return r;
218 : :
219 : 1145 : *cgen = TAKE_PTR(_cgen);
220 : :
221 : 1145 : return 0;
222 : : }
223 : :
224 : 5317 : void bf_cgen_free(struct bf_cgen **cgen)
225 : : {
226 : 3867 : _cleanup_close_ int pin_fd = -1;
227 : :
228 : : assert(cgen);
229 : :
230 [ + + ]: 5317 : if (!*cgen)
231 : : return;
232 : :
233 : : /* Perform a non-recursive removal of the chain's pin directory: if
234 : : * the chain hasn't been pinned (e.g. due to a failure), the pin directory
235 : : * will be empty and will be removed. If the chain is valid and pinned, then
236 : : * the removal of the pin directory will fail, but that's alright. */
237 : 1450 : pin_fd = bf_ctx_get_pindir_fd();
238 [ + - ]: 1450 : if (pin_fd >= 0)
239 : 1450 : bf_rmdir_at(pin_fd, (*cgen)->chain->name, false);
240 : :
241 : 1450 : bf_handle_free(&(*cgen)->handle);
242 : 1450 : bf_chain_free(&(*cgen)->chain);
243 : :
244 : 1450 : free(*cgen);
245 : 1450 : *cgen = NULL;
246 : : }
247 : :
248 : 1180 : int bf_cgen_pack(const struct bf_cgen *cgen, bf_wpack_t *pack)
249 : : {
250 : : assert(cgen);
251 : : assert(pack);
252 : :
253 : 1180 : bf_wpack_open_object(pack, "chain");
254 : 1180 : bf_chain_pack(cgen->chain, pack);
255 : 1180 : bf_wpack_close_object(pack);
256 : :
257 : 1180 : bf_wpack_open_object(pack, "handle");
258 : 1180 : bf_handle_pack(cgen->handle, pack);
259 : 1180 : bf_wpack_close_object(pack);
260 : :
261 [ - + ]: 1180 : return bf_wpack_is_valid(pack) ? 0 : -EINVAL;
262 : : }
263 : :
264 : 16 : void bf_cgen_dump(const struct bf_cgen *cgen, prefix_t *prefix)
265 : : {
266 : : assert(cgen);
267 : : assert(prefix);
268 : :
269 [ - + ]: 16 : DUMP(prefix, "struct bf_cgen at %p", cgen);
270 : :
271 : 16 : bf_dump_prefix_push(prefix);
272 : :
273 : : // Chain
274 [ - + ]: 16 : DUMP(prefix, "chain: struct bf_chain *");
275 : 16 : bf_dump_prefix_push(prefix);
276 : 16 : bf_chain_dump(cgen->chain, bf_dump_prefix_last(prefix));
277 : 16 : bf_dump_prefix_pop(prefix);
278 : :
279 [ - + ]: 16 : DUMP(bf_dump_prefix_last(prefix), "handle: struct bf_handle *");
280 : 16 : bf_dump_prefix_push(prefix);
281 : 16 : bf_handle_dump(cgen->handle, bf_dump_prefix_last(prefix));
282 : 16 : bf_dump_prefix_pop(prefix);
283 : :
284 : 16 : bf_dump_prefix_pop(prefix);
285 : 16 : }
286 : :
287 : 3143 : int bf_cgen_get_counter(const struct bf_cgen *cgen,
288 : : enum bf_counter_type counter_idx,
289 : : struct bf_counter *counter)
290 : : {
291 : : assert(cgen);
292 : : assert(counter);
293 : :
294 : : /* There are two more counter than rules. The special counters must
295 : : * be accessed via the specific values, to avoid confusion. */
296 [ + + ]: 3143 : enum bf_counter_type rule_count = bf_list_size(&cgen->chain->rules);
297 [ + + ]: 3143 : if (counter_idx == BF_COUNTER_POLICY) {
298 : : counter_idx = rule_count;
299 [ + + ]: 2094 : } else if (counter_idx == BF_COUNTER_ERRORS) {
300 : 1049 : counter_idx = rule_count + 1;
301 [ + - ]: 1045 : } else if (counter_idx < 0 || counter_idx >= rule_count) {
302 : : return -EINVAL;
303 : : }
304 : :
305 : 3143 : return bf_handle_get_counter(cgen->handle, counter_idx, counter);
306 : : }
307 : :
308 : 1129 : int bf_cgen_set(struct bf_cgen *cgen, struct bf_hookopts **hookopts)
309 : : {
310 : 1129 : _free_bf_program_ struct bf_program *prog = NULL;
311 : 1129 : _cleanup_close_ int pindir_fd = -1;
312 : : int r;
313 : :
314 : : assert(cgen);
315 : :
316 : 1129 : pindir_fd = _bf_cgen_get_chain_pindir_fd(cgen->chain->name);
317 [ + - ]: 1129 : if (pindir_fd < 0)
318 : : return pindir_fd;
319 : :
320 : 1129 : r = bf_program_new(&prog, cgen->chain, cgen->handle);
321 [ + - ]: 1129 : if (r < 0)
322 : : return r;
323 : :
324 : 1129 : r = bf_program_generate(prog);
325 [ + + ]: 1129 : if (r < 0)
326 [ + - ]: 3 : return bf_err_r(r, "failed to generate bf_program");
327 : :
328 : 1126 : r = bf_program_load(prog);
329 [ - + ]: 1126 : if (r < 0)
330 [ # # ]: 0 : return bf_err_r(r, "failed to load the chain");
331 : :
332 [ + + ]: 1126 : if (hookopts) {
333 : 84 : r = bf_handle_attach(cgen->handle, cgen->chain->hook, hookopts);
334 [ + + ]: 84 : if (r < 0)
335 [ + - ]: 2 : return bf_err_r(r, "failed to load and attach the chain");
336 : : }
337 : :
338 : 1124 : r = bf_handle_pin(cgen->handle, pindir_fd);
339 [ + - ]: 1124 : if (r)
340 : : return r;
341 : :
342 : 1124 : r = _bf_cgen_persist(cgen, pindir_fd);
343 [ - + ]: 1124 : if (r) {
344 : 0 : bf_handle_unpin(cgen->handle, pindir_fd);
345 [ # # ]: 0 : return bf_err_r(r, "failed to persist cgen for '%s'",
346 : : cgen->chain->name);
347 : : }
348 : :
349 : : return 0;
350 : : }
351 : :
352 : 16 : int bf_cgen_load(struct bf_cgen *cgen)
353 : : {
354 : 16 : _free_bf_program_ struct bf_program *prog = NULL;
355 : 16 : _cleanup_close_ int pindir_fd = -1;
356 : : int r;
357 : :
358 : : assert(cgen);
359 : :
360 : 16 : pindir_fd = _bf_cgen_get_chain_pindir_fd(cgen->chain->name);
361 [ + - ]: 16 : if (pindir_fd < 0)
362 : : return pindir_fd;
363 : :
364 : 16 : r = bf_program_new(&prog, cgen->chain, cgen->handle);
365 [ + - ]: 16 : if (r < 0)
366 : : return r;
367 : :
368 : 16 : r = bf_program_generate(prog);
369 [ - + ]: 16 : if (r < 0)
370 [ # # ]: 0 : return bf_err_r(r, "failed to generate bf_program");
371 : :
372 : 16 : r = bf_program_load(prog);
373 [ - + ]: 16 : if (r < 0)
374 [ # # ]: 0 : return bf_err_r(r, "failed to load the chain");
375 : :
376 : 16 : r = bf_handle_pin(cgen->handle, pindir_fd);
377 [ + - ]: 16 : if (r)
378 : : return r;
379 : :
380 : 16 : r = _bf_cgen_persist(cgen, pindir_fd);
381 [ - + ]: 16 : if (r) {
382 : 0 : bf_handle_unpin(cgen->handle, pindir_fd);
383 [ # # ]: 0 : return bf_err_r(r, "failed to persist cgen for '%s'",
384 : : cgen->chain->name);
385 : : }
386 : :
387 [ + - ]: 16 : bf_info("load %s", cgen->chain->name);
388 : 16 : bf_cgen_dump(cgen, EMPTY_PREFIX);
389 : :
390 : 16 : return 0;
391 : : }
392 : :
393 : 14 : int bf_cgen_attach(struct bf_cgen *cgen, struct bf_hookopts **hookopts)
394 : : {
395 : 14 : _cleanup_close_ int pindir_fd = -1;
396 : : int r;
397 : :
398 : : assert(cgen);
399 : : assert(hookopts);
400 : :
401 [ + - ]: 14 : bf_info("attaching %s to %s", cgen->chain->name,
402 : : bf_hook_to_str(cgen->chain->hook));
403 : 14 : bf_hookopts_dump(*hookopts, EMPTY_PREFIX);
404 : :
405 : 14 : pindir_fd = _bf_cgen_get_chain_pindir_fd(cgen->chain->name);
406 [ + - ]: 14 : if (pindir_fd < 0)
407 : : return pindir_fd;
408 : :
409 : 14 : r = bf_handle_attach(cgen->handle, cgen->chain->hook, hookopts);
410 [ + + ]: 14 : if (r < 0)
411 [ + - ]: 2 : return bf_err_r(r, "failed to attach chain '%s'", cgen->chain->name);
412 : :
413 : 12 : r = bf_link_pin(cgen->handle->link, pindir_fd);
414 [ - + ]: 12 : if (r) {
415 : 0 : bf_handle_detach(cgen->handle);
416 : 0 : return r;
417 : : }
418 : :
419 : 12 : r = _bf_cgen_persist(cgen, pindir_fd);
420 [ - + ]: 12 : if (r) {
421 : 0 : bf_link_unpin(cgen->handle->link, pindir_fd);
422 : 0 : bf_handle_detach(cgen->handle);
423 [ # # ]: 0 : return bf_err_r(r, "failed to persist cgen for '%s'",
424 : : cgen->chain->name);
425 : : }
426 : :
427 : : return r;
428 : : }
429 : :
430 : : /**
431 : : * @brief Transfer all counters from old handle to new handle.
432 : : *
433 : : * Copies counter values 1:1 for all rule counters plus policy and error
434 : : * counters. The old and new chains must have the same number of rules.
435 : : * Both handles must be loaded.
436 : : *
437 : : * @param old_handle Handle with the source counter map. Can't be NULL.
438 : : * @param new_handle Handle with the destination counter map. Can't be NULL.
439 : : * @param n_rules Number of rules in the chain.
440 : : * @return 0 on success, or a negative errno value on failure.
441 : : */
442 : 8 : static int _bf_cgen_transfer_counters(const struct bf_handle *old_handle,
443 : : struct bf_handle *new_handle,
444 : : size_t n_rules)
445 : : {
446 : : int r;
447 : :
448 : : assert(old_handle);
449 : : assert(new_handle);
450 : :
451 [ + - - + ]: 8 : if (!old_handle->cmap || !new_handle->cmap)
452 [ # # ]: 0 : return bf_err_r(-ENOENT, "missing counter map for counter transfer");
453 : :
454 : : // n_rules entries for rules, +1 for policy, +1 for errors.
455 [ + + ]: 34 : for (uint32_t i = 0; i < n_rules + 2; ++i) {
456 : : struct bf_counter counter;
457 : :
458 : 26 : r = bf_handle_get_counter(old_handle, i, &counter);
459 [ - + ]: 26 : if (r)
460 [ # # ]: 0 : return bf_err_r(r, "failed to read counter %u", i);
461 : :
462 [ + + + - ]: 26 : if (!counter.count && !counter.size)
463 : 20 : continue;
464 : :
465 : 6 : r = bf_map_set_elem(new_handle->cmap, &i, &counter);
466 [ - + ]: 6 : if (r)
467 [ # # ]: 0 : return bf_err_r(r, "failed to write counter %u", i);
468 : : }
469 : :
470 : 8 : return 0;
471 : : }
472 : :
473 : 14 : int bf_cgen_update(struct bf_cgen *cgen, struct bf_chain **new_chain,
474 : : uint32_t flags)
475 : : {
476 : 14 : _free_bf_program_ struct bf_program *new_prog = NULL;
477 : 14 : _free_bf_handle_ struct bf_handle *new_handle = NULL;
478 : 14 : _cleanup_close_ int pindir_fd = -1;
479 : : struct bf_handle *old_handle;
480 : : int r;
481 : :
482 : : assert(cgen);
483 : : assert(new_chain);
484 : :
485 [ - + ]: 14 : if (flags & ~BF_FLAGS_MASK(_BF_CGEN_UPDATE_MAX))
486 [ # # ]: 0 : return bf_err_r(-EINVAL, "unknown update flags: 0x%x", flags);
487 : :
488 : 14 : old_handle = cgen->handle;
489 : :
490 : 14 : pindir_fd = _bf_cgen_get_chain_pindir_fd((*new_chain)->name);
491 [ + - ]: 14 : if (pindir_fd < 0)
492 : : return pindir_fd;
493 : :
494 : 14 : r = bf_handle_new(&new_handle, _BF_PROG_NAME);
495 [ + - ]: 14 : if (r)
496 : : return r;
497 : :
498 : 14 : r = bf_program_new(&new_prog, *new_chain, new_handle);
499 [ - + ]: 14 : if (r < 0)
500 [ # # ]: 0 : return bf_err_r(r, "failed to create a new bf_program");
501 : :
502 : 14 : r = bf_program_generate(new_prog);
503 [ - + ]: 14 : if (r < 0) {
504 [ # # ]: 0 : return bf_err_r(r,
505 : : "failed to generate the bytecode for a new bf_program");
506 : : }
507 : :
508 : 14 : r = bf_program_load(new_prog);
509 [ - + ]: 14 : if (r)
510 [ # # ]: 0 : return bf_err_r(r, "failed to load new program");
511 : :
512 [ + + ]: 14 : if (flags & BF_FLAG(BF_CGEN_UPDATE_PRESERVE_COUNTERS)) {
513 [ - + ]: 8 : if (bf_list_size(&cgen->chain->rules) !=
514 [ - + ]: 8 : bf_list_size(&(*new_chain)->rules)) {
515 [ # # ]: 0 : return bf_err_r(-EINVAL,
516 : : "rule count mismatch for counter transfer");
517 : : }
518 : :
519 : 8 : r = _bf_cgen_transfer_counters(old_handle, new_handle,
520 : : bf_list_size(&(*new_chain)->rules));
521 [ - + ]: 8 : if (r)
522 [ # # ]: 0 : return bf_err_r(r, "failed to transfer counters");
523 : : }
524 : :
525 : 14 : bf_handle_unpin(old_handle, pindir_fd);
526 : :
527 [ + + ]: 14 : if (old_handle->link) {
528 : 12 : r = bf_link_update(old_handle->link, new_handle->prog_fd);
529 [ - + ]: 12 : if (r) {
530 [ # # ]: 0 : bf_err_r(r, "failed to update bf_link object with new program");
531 [ # # ]: 0 : if (bf_handle_pin(old_handle, pindir_fd) < 0)
532 [ # # ]: 0 : bf_err("failed to repin old handle, ignoring");
533 : 0 : return r;
534 : : }
535 : :
536 : : // We updated the old link, we need to store it in the new handle
537 : 12 : bf_swap(new_handle->link, old_handle->link);
538 : : }
539 : :
540 : 14 : bf_swap(cgen->handle, new_handle);
541 : :
542 : 14 : r = bf_handle_pin(cgen->handle, pindir_fd);
543 [ - + ]: 14 : if (r)
544 [ # # ]: 0 : return bf_err_r(r, "failed to pin new handle");
545 : :
546 : 14 : r = _bf_cgen_persist(cgen, pindir_fd);
547 [ - + ]: 14 : if (r) {
548 : 0 : bf_handle_unpin(cgen->handle, pindir_fd);
549 [ # # ]: 0 : return bf_err_r(r, "failed to persist cgen for '%s'",
550 : : cgen->chain->name);
551 : : }
552 : :
553 : 14 : bf_chain_free(&cgen->chain);
554 : 14 : cgen->chain = TAKE_PTR(*new_chain);
555 : :
556 : 14 : r = _bf_cgen_persist(cgen, pindir_fd);
557 [ - + ]: 14 : if (r) {
558 : 0 : bf_handle_unpin(cgen->handle, pindir_fd);
559 [ # # ]: 0 : return bf_err_r(r, "failed to persist cgen for '%s'",
560 : : cgen->chain->name);
561 : : }
562 : :
563 : : return 0;
564 : : }
565 : :
566 : 0 : void bf_cgen_detach(struct bf_cgen *cgen)
567 : : {
568 : : assert(cgen);
569 : :
570 : 0 : bf_handle_detach(cgen->handle);
571 : 0 : }
572 : :
573 : 1120 : void bf_cgen_unload(struct bf_cgen *cgen)
574 : : {
575 : 1120 : _cleanup_close_ int chain_fd = -1;
576 : :
577 : : assert(cgen);
578 : :
579 : 1120 : chain_fd = _bf_cgen_get_chain_pindir_fd(cgen->chain->name);
580 [ - + ]: 1120 : if (chain_fd < 0) {
581 [ # # ]: 0 : bf_err_r(chain_fd, "failed to open pin directory for '%s'",
582 : : cgen->chain->name);
583 : : return;
584 : : }
585 : :
586 : : // The chain's pin directory will be removed in bf_cgen_free()
587 : 1120 : unlinkat(chain_fd, _BF_CTX_PIN_NAME, 0);
588 : 1120 : bf_handle_unpin(cgen->handle, chain_fd);
589 : 1120 : bf_handle_unload(cgen->handle);
590 : : }
591 : :
592 : 1049 : int bf_cgen_get_counters(const struct bf_cgen *cgen, bf_list *counters)
593 : : {
594 : : bf_list _counters;
595 : : int r;
596 : :
597 : : assert(cgen);
598 : : assert(counters);
599 : :
600 : 1049 : _counters = bf_list_default_from(*counters);
601 : :
602 : : /* Iterate over all the rules, then the policy counter (size(rules)) and
603 : : * the errors counters (sizeof(rules) + 1)*/
604 [ + + ]: 4192 : for (size_t i = 0; i < bf_list_size(&cgen->chain->rules) + 2; ++i) {
605 : 0 : _free_bf_counter_ struct bf_counter *counter = NULL;
606 : 3143 : ssize_t idx = (ssize_t)i;
607 : :
608 [ + + ]: 3143 : if (i == bf_list_size(&cgen->chain->rules))
609 : : idx = BF_COUNTER_POLICY;
610 [ + + ]: 2094 : else if (i == bf_list_size(&cgen->chain->rules) + 1)
611 : : idx = BF_COUNTER_ERRORS;
612 : :
613 : 3143 : r = bf_counter_new(&counter, 0, 0);
614 [ + - ]: 3143 : if (r)
615 : : return r;
616 : :
617 : 3143 : r = bf_cgen_get_counter(cgen, idx, counter);
618 [ + - ]: 3143 : if (r)
619 : : return r;
620 : :
621 : 3143 : r = bf_list_add_tail(&_counters, counter);
622 [ + - ]: 3143 : if (r)
623 : : return r;
624 : :
625 : 3143 : TAKE_PTR(counter);
626 : : }
627 : :
628 : 1049 : *counters = bf_list_move(_counters);
629 : :
630 : 1049 : return 0;
631 : : }
|