Branch data Line data Source code
1 : : /* SPDX-License-Identifier: GPL-2.0-only */
2 : : /*
3 : : * Copyright (c) 2022 Meta Platforms, Inc. and affiliates.
4 : : */
5 : :
6 : : #include <errno.h>
7 : :
8 : : #include <bpfilter/chain.h>
9 : : #include <bpfilter/counter.h>
10 : : #include <bpfilter/front.h>
11 : : #include <bpfilter/helper.h>
12 : : #include <bpfilter/hook.h>
13 : : #include <bpfilter/io.h>
14 : : #include <bpfilter/list.h>
15 : : #include <bpfilter/logger.h>
16 : : #include <bpfilter/pack.h>
17 : : #include <bpfilter/request.h>
18 : : #include <bpfilter/response.h>
19 : :
20 : : #include "bpfilter/set.h"
21 : : #include "cgen/cgen.h"
22 : : #include "cgen/handle.h"
23 : : #include "cgen/prog/link.h"
24 : : #include "cgen/prog/map.h"
25 : : #include "cgen/program.h"
26 : : #include "ctx.h"
27 : : #include "xlate/front.h"
28 : :
29 : : static int _bf_cli_setup(void);
30 : : static int _bf_cli_teardown(void);
31 : : static int _bf_cli_request_handler(const struct bf_request *request,
32 : : struct bf_response **response);
33 : : static int _bf_cli_pack(bf_wpack_t *pack);
34 : : static int _bf_cli_unpack(bf_rpack_node_t node);
35 : :
36 : : const struct bf_front_ops cli_front = {
37 : : .setup = _bf_cli_setup,
38 : : .teardown = _bf_cli_teardown,
39 : : .request_handler = _bf_cli_request_handler,
40 : : .pack = _bf_cli_pack,
41 : : .unpack = _bf_cli_unpack,
42 : : };
43 : :
44 : 29 : static int _bf_cli_setup(void)
45 : : {
46 : 29 : return 0;
47 : : }
48 : :
49 : 28 : static int _bf_cli_teardown(void)
50 : : {
51 : 28 : return 0;
52 : : }
53 : :
54 : 6 : int _bf_cli_ruleset_flush(const struct bf_request *request,
55 : : struct bf_response **response)
56 : : {
57 : : (void)request;
58 : : (void)response;
59 : :
60 : 6 : bf_ctx_flush(BF_FRONT_CLI);
61 : :
62 : 6 : return 0;
63 : : }
64 : :
65 : 4 : static int _bf_cli_ruleset_get(const struct bf_request *request,
66 : : struct bf_response **response)
67 : : {
68 : 4 : _clean_bf_list_ bf_list cgens = bf_list_default(NULL, NULL);
69 : 4 : _clean_bf_list_ bf_list chains = bf_list_default(NULL, bf_chain_pack);
70 : 4 : _clean_bf_list_ bf_list hookopts = bf_list_default(NULL, bf_hookopts_pack);
71 : 4 : _clean_bf_list_ bf_list counters =
72 : : bf_list_default(bf_list_free, bf_list_pack);
73 : 4 : _free_bf_wpack_ bf_wpack_t *pack = NULL;
74 : : int r;
75 : :
76 : : (void)request;
77 : :
78 : 4 : r = bf_wpack_new(&pack);
79 [ + - ]: 4 : if (r)
80 : : return r;
81 : :
82 : 4 : r = bf_ctx_get_cgens_for_front(&cgens, BF_FRONT_CLI);
83 [ - + ]: 4 : if (r < 0)
84 [ # # ]: 0 : return bf_err_r(r, "failed to get cgen list");
85 : :
86 [ + - + + : 18 : bf_list_foreach (&cgens, cgen_node) {
+ + ]
87 : : struct bf_cgen *cgen = bf_list_node_get_data(cgen_node);
88 : 0 : _free_bf_list_ bf_list *cgen_counters = NULL;
89 : :
90 : 5 : r = bf_list_add_tail(&chains, cgen->chain);
91 [ - + ]: 5 : if (r)
92 [ # # ]: 0 : return bf_err_r(r, "failed to add chain to list");
93 : :
94 [ + + ]: 5 : r = bf_list_add_tail(&hookopts, cgen->handle->link ?
95 : : cgen->handle->link->hookopts :
96 : : NULL);
97 [ - + ]: 5 : if (r)
98 [ # # ]: 0 : return bf_err_r(r, "failed to add hookopts to list");
99 : :
100 : 5 : r = bf_list_new(&cgen_counters,
101 : 5 : &bf_list_ops_default(bf_counter_free, bf_counter_pack));
102 [ + - ]: 5 : if (r)
103 : : return r;
104 : :
105 : 5 : r = bf_cgen_get_counters(cgen, cgen_counters);
106 [ + - ]: 5 : if (r)
107 : : return r;
108 : :
109 : 5 : r = bf_list_add_tail(&counters, cgen_counters);
110 [ + - ]: 5 : if (r)
111 : : return r;
112 : :
113 : 5 : TAKE_PTR(cgen_counters);
114 : : }
115 : :
116 : 4 : bf_wpack_open_object(pack, "ruleset");
117 : 4 : bf_wpack_kv_list(pack, "chains", &chains);
118 : 4 : bf_wpack_kv_list(pack, "hookopts", &hookopts);
119 : 4 : bf_wpack_kv_list(pack, "counters", &counters);
120 : 4 : bf_wpack_close_object(pack);
121 : :
122 : 4 : return bf_response_new_from_pack(response, pack);
123 : : }
124 : :
125 : 8 : int _bf_cli_ruleset_set(const struct bf_request *request,
126 : : struct bf_response **response)
127 : : {
128 : 8 : _clean_bf_list_ bf_list cgens = bf_list_default(NULL, NULL);
129 : 8 : _free_bf_rpack_ bf_rpack_t *pack;
130 : : bf_rpack_node_t child, node;
131 : : int r;
132 : :
133 : : assert(request);
134 : :
135 : : (void)response;
136 : :
137 : 8 : bf_ctx_flush(BF_FRONT_CLI);
138 : :
139 : 8 : r = bf_rpack_new(&pack, bf_request_data(request),
140 : : bf_request_data_len(request));
141 [ + - ]: 8 : if (r)
142 : : return r;
143 : :
144 : 8 : r = bf_rpack_kv_array(bf_rpack_root(pack), "ruleset", &child);
145 [ + - ]: 8 : if (r)
146 : : return r;
147 [ + - + + : 36 : bf_rpack_array_foreach (child, node) {
+ + ]
148 : 12 : _free_bf_cgen_ struct bf_cgen *cgen = NULL;
149 : 12 : _free_bf_chain_ struct bf_chain *chain = NULL;
150 : 2 : _free_bf_hookopts_ struct bf_hookopts *hookopts = NULL;
151 : : bf_rpack_node_t child;
152 : :
153 : 12 : r = bf_rpack_kv_obj(node, "chain", &child);
154 [ - + ]: 12 : if (r)
155 : 0 : goto err_load;
156 : :
157 : 12 : r = bf_chain_new_from_pack(&chain, child);
158 [ - + ]: 12 : if (r)
159 : 0 : goto err_load;
160 : :
161 : 12 : r = bf_rpack_kv_node(node, "hookopts", &child);
162 [ - + ]: 12 : if (r)
163 : 0 : goto err_load;
164 [ + + ]: 12 : if (!bf_rpack_is_nil(child)) {
165 : 10 : r = bf_hookopts_new_from_pack(&hookopts, child);
166 [ - + ]: 10 : if (r)
167 : 0 : goto err_load;
168 : : }
169 : :
170 : 12 : r = bf_cgen_new(&cgen, BF_FRONT_CLI, &chain);
171 [ - + ]: 12 : if (r)
172 : 0 : goto err_load;
173 : :
174 : 12 : r = bf_cgen_set(cgen, bf_request_ns(request),
175 [ + + ]: 12 : hookopts ? &hookopts : NULL);
176 [ + + ]: 12 : if (r) {
177 [ + - ]: 2 : bf_err_r(r, "failed to set chain '%s'", cgen->chain->name);
178 : 2 : goto err_load;
179 : : }
180 : :
181 : 10 : r = bf_ctx_set_cgen(cgen);
182 [ - + ]: 10 : if (r) {
183 : : /* The codegen is loaded already, if the daemon runs in persistent
184 : : * mode, cleaning the codegen won't be sufficient to discard the
185 : : * chain, it must be unpinned. */
186 : 0 : bf_cgen_unload(cgen);
187 : 0 : goto err_load;
188 : : }
189 : :
190 : 10 : TAKE_PTR(cgen);
191 : : }
192 : :
193 : : return 0;
194 : :
195 : : err_load:
196 : 2 : bf_ctx_flush(BF_FRONT_CLI);
197 : 2 : return r;
198 : : }
199 : :
200 : 60 : int _bf_cli_chain_set(const struct bf_request *request,
201 : : struct bf_response **response)
202 : : {
203 : : struct bf_cgen *old_cgen;
204 : 60 : _free_bf_cgen_ struct bf_cgen *new_cgen = NULL;
205 : 60 : _free_bf_chain_ struct bf_chain *chain = NULL;
206 : 60 : _free_bf_hookopts_ struct bf_hookopts *hookopts = NULL;
207 : 60 : _free_bf_rpack_ bf_rpack_t *pack = NULL;
208 : : bf_rpack_node_t root, child;
209 : : int r;
210 : :
211 : : assert(request);
212 : :
213 : : (void)response;
214 : :
215 : 60 : r = bf_rpack_new(&pack, bf_request_data(request),
216 : : bf_request_data_len(request));
217 [ + - ]: 60 : if (r)
218 : : return r;
219 : :
220 : 60 : root = bf_rpack_root(pack);
221 : :
222 : 60 : r = bf_rpack_kv_obj(root, "chain", &child);
223 [ + - ]: 60 : if (r)
224 : : return r;
225 : 60 : r = bf_chain_new_from_pack(&chain, child);
226 [ + - ]: 60 : if (r)
227 : : return r;
228 : :
229 : 60 : r = bf_rpack_kv_node(root, "hookopts", &child);
230 [ + - ]: 60 : if (r)
231 : : return r;
232 [ + + ]: 60 : if (!bf_rpack_is_nil(child)) {
233 : 31 : r = bf_hookopts_new_from_pack(&hookopts, child);
234 [ + - ]: 31 : if (r)
235 : : return r;
236 : : }
237 : :
238 : 60 : r = bf_cgen_new(&new_cgen, BF_FRONT_CLI, &chain);
239 [ + - ]: 60 : if (r)
240 : : return r;
241 : :
242 : 60 : old_cgen = bf_ctx_get_cgen(new_cgen->chain->name);
243 [ + + ]: 60 : if (old_cgen) {
244 : : /* bf_ctx_delete_cgen() can only fail if the codegen is not found,
245 : : * but we know this codegen exist. */
246 : 22 : (void)bf_ctx_delete_cgen(old_cgen, true);
247 : : }
248 : :
249 : 60 : r = bf_cgen_set(new_cgen, bf_request_ns(request),
250 [ + + ]: 60 : hookopts ? &hookopts : NULL);
251 [ + + ]: 60 : if (r)
252 : : return r;
253 : :
254 : 57 : r = bf_ctx_set_cgen(new_cgen);
255 [ - + ]: 57 : if (r) {
256 : 0 : bf_cgen_unload(new_cgen);
257 : 0 : return r;
258 : : }
259 : :
260 : 57 : TAKE_PTR(new_cgen);
261 : :
262 : 57 : return r;
263 : : }
264 : :
265 : 34 : static int _bf_cli_chain_get(const struct bf_request *request,
266 : : struct bf_response **response)
267 : : {
268 : 34 : _clean_bf_list_ bf_list counters =
269 : : bf_list_default(bf_counter_free, bf_counter_pack);
270 : : struct bf_cgen *cgen;
271 : 34 : _cleanup_free_ char *name = NULL;
272 : 34 : _free_bf_wpack_ bf_wpack_t *wpack = NULL;
273 : 34 : _free_bf_rpack_ bf_rpack_t *rpack = NULL;
274 : : int r;
275 : :
276 : 34 : r = bf_rpack_new(&rpack, bf_request_data(request),
277 : : bf_request_data_len(request));
278 [ + - ]: 34 : if (r)
279 : : return r;
280 : :
281 : 34 : r = bf_rpack_kv_str(bf_rpack_root(rpack), "name", &name);
282 [ + - ]: 34 : if (r)
283 : : return r;
284 : :
285 : 34 : cgen = bf_ctx_get_cgen(name);
286 [ + + ]: 34 : if (!cgen)
287 [ + - ]: 1 : return bf_err_r(-ENOENT, "chain '%s' not found", name);
288 : :
289 : 33 : r = bf_cgen_get_counters(cgen, &counters);
290 [ - + ]: 33 : if (r)
291 [ # # ]: 0 : return bf_err_r(r, "failed to request counters for '%s'", name);
292 : :
293 : 33 : r = bf_wpack_new(&wpack);
294 [ + - ]: 33 : if (r)
295 : : return r;
296 : :
297 : 33 : bf_wpack_open_object(wpack, "chain");
298 : 33 : r = bf_chain_pack(cgen->chain, wpack);
299 [ + - ]: 33 : if (r)
300 : : return r;
301 : 33 : bf_wpack_close_object(wpack);
302 : :
303 [ + + ]: 33 : if (cgen->handle->link) {
304 : 26 : bf_wpack_open_object(wpack, "hookopts");
305 : 26 : r = bf_hookopts_pack(cgen->handle->link->hookopts, wpack);
306 [ + - ]: 26 : if (r)
307 : : return r;
308 : 26 : bf_wpack_close_object(wpack);
309 : : } else {
310 : 7 : bf_wpack_kv_nil(wpack, "hookopts");
311 : : }
312 : :
313 : 33 : bf_wpack_kv_list(wpack, "counters", &counters);
314 : :
315 : 33 : return bf_response_new_from_pack(response, wpack);
316 : : }
317 : :
318 : 0 : int _bf_cli_chain_prog_fd(const struct bf_request *request,
319 : : struct bf_response **response)
320 : : {
321 : : struct bf_cgen *cgen;
322 : 0 : _free_bf_rpack_ bf_rpack_t *pack = NULL;
323 : 0 : _cleanup_free_ char *name = NULL;
324 : : int r;
325 : :
326 : : (void)response;
327 : :
328 : 0 : r = bf_rpack_new(&pack, bf_request_data(request),
329 : : bf_request_data_len(request));
330 [ # # ]: 0 : if (r)
331 : : return r;
332 : :
333 : 0 : r = bf_rpack_kv_str(bf_rpack_root(pack), "name", &name);
334 [ # # ]: 0 : if (r)
335 : : return r;
336 : :
337 : 0 : cgen = bf_ctx_get_cgen(name);
338 [ # # ]: 0 : if (!cgen)
339 [ # # ]: 0 : return bf_err_r(-ENOENT, "failed to find chain '%s'", name);
340 : :
341 [ # # ]: 0 : if (cgen->handle->prog_fd == -1)
342 [ # # ]: 0 : return bf_err_r(-ENODEV, "chain '%s' has no loaded program", name);
343 : :
344 : 0 : r = bf_send_fd(bf_request_fd(request), cgen->handle->prog_fd);
345 [ # # ]: 0 : if (r < 0)
346 [ # # ]: 0 : return bf_err_r(errno, "failed to send prog FD for '%s'", name);
347 : :
348 : : return 0;
349 : : }
350 : :
351 : 0 : int _bf_cli_chain_logs_fd(const struct bf_request *request,
352 : : struct bf_response **response)
353 : : {
354 : : struct bf_cgen *cgen;
355 : 0 : _free_bf_rpack_ bf_rpack_t *pack = NULL;
356 : 0 : _cleanup_free_ char *name = NULL;
357 : : int r;
358 : :
359 : : (void)response;
360 : :
361 : 0 : r = bf_rpack_new(&pack, bf_request_data(request),
362 : : bf_request_data_len(request));
363 [ # # ]: 0 : if (r)
364 : : return r;
365 : :
366 : 0 : r = bf_rpack_kv_str(bf_rpack_root(pack), "name", &name);
367 [ # # ]: 0 : if (r)
368 : : return r;
369 : :
370 : 0 : cgen = bf_ctx_get_cgen(name);
371 [ # # ]: 0 : if (!cgen)
372 [ # # ]: 0 : return bf_err_r(-ENOENT, "failed to find chain '%s'", name);
373 : :
374 [ # # ]: 0 : if (!cgen->handle->lmap)
375 [ # # ]: 0 : return bf_err_r(-ENOENT, "chain '%s' has no logs buffer", name);
376 : :
377 : 0 : r = bf_send_fd(bf_request_fd(request), cgen->handle->lmap->fd);
378 [ # # ]: 0 : if (r < 0)
379 [ # # ]: 0 : return bf_err_r(errno, "failed to send logs FD for '%s'", name);
380 : :
381 : : return 0;
382 : : }
383 : :
384 : 12 : int _bf_cli_chain_load(const struct bf_request *request,
385 : : struct bf_response **response)
386 : : {
387 : 12 : _free_bf_cgen_ struct bf_cgen *cgen = NULL;
388 : 12 : _free_bf_chain_ struct bf_chain *chain = NULL;
389 : 12 : _free_bf_rpack_ bf_rpack_t *pack = NULL;
390 : : bf_rpack_node_t child;
391 : : int r;
392 : :
393 : : assert(request);
394 : :
395 : : (void)response;
396 : :
397 : 12 : r = bf_rpack_new(&pack, bf_request_data(request),
398 : : bf_request_data_len(request));
399 [ + - ]: 12 : if (r)
400 : : return r;
401 : :
402 : 12 : r = bf_rpack_kv_obj(bf_rpack_root(pack), "chain", &child);
403 [ + - ]: 12 : if (r)
404 : : return r;
405 : 12 : r = bf_chain_new_from_pack(&chain, child);
406 [ + - ]: 12 : if (r)
407 : : return r;
408 : :
409 [ - + ]: 12 : if (bf_ctx_get_cgen(chain->name)) {
410 [ # # ]: 0 : return bf_err_r(-EEXIST,
411 : : "_bf_cli_chain_load: chain '%s' already exists",
412 : : chain->name);
413 : : }
414 : :
415 : 12 : r = bf_cgen_new(&cgen, BF_FRONT_CLI, &chain);
416 [ + - ]: 12 : if (r)
417 : : return r;
418 : :
419 : 12 : r = bf_cgen_load(cgen);
420 [ + - ]: 12 : if (r)
421 : : return r;
422 : :
423 : 12 : r = bf_ctx_set_cgen(cgen);
424 [ - + ]: 12 : if (r) {
425 : 0 : bf_cgen_unload(cgen);
426 [ # # ]: 0 : return bf_err_r(
427 : : r, "bf_ctx_set_cgen: failed to add cgen to the runtime context");
428 : : }
429 : :
430 : 12 : TAKE_PTR(cgen);
431 : :
432 : 12 : return r;
433 : : }
434 : :
435 : 11 : int _bf_cli_chain_attach(const struct bf_request *request,
436 : : struct bf_response **response)
437 : : {
438 : 11 : _free_bf_chain_ struct bf_chain *chain = NULL;
439 : 11 : _free_bf_hookopts_ struct bf_hookopts *hookopts = NULL;
440 : 11 : _free_bf_rpack_ bf_rpack_t *pack = NULL;
441 : 11 : _cleanup_free_ char *name = NULL;
442 : : struct bf_cgen *cgen = NULL;
443 : : bf_rpack_node_t child;
444 : : int r;
445 : :
446 : : assert(request);
447 : :
448 : : (void)response;
449 : :
450 : 11 : r = bf_rpack_new(&pack, bf_request_data(request),
451 : : bf_request_data_len(request));
452 [ + - ]: 11 : if (r)
453 : : return r;
454 : :
455 : 11 : r = bf_rpack_kv_str(bf_rpack_root(pack), "name", &name);
456 [ + - ]: 11 : if (r)
457 : : return r;
458 : :
459 : 11 : r = bf_rpack_kv_obj(bf_rpack_root(pack), "hookopts", &child);
460 [ + - ]: 11 : if (r)
461 : : return r;
462 : 11 : r = bf_hookopts_new_from_pack(&hookopts, child);
463 [ + - ]: 11 : if (r)
464 : : return r;
465 : :
466 : 11 : cgen = bf_ctx_get_cgen(name);
467 [ - + ]: 11 : if (!cgen)
468 [ # # ]: 0 : return bf_err_r(-ENOENT, "chain '%s' does not exist", name);
469 [ - + ]: 11 : if (cgen->handle->link)
470 [ # # ]: 0 : return bf_err_r(-EBUSY, "chain '%s' is already linked to a hook", name);
471 : :
472 : 11 : r = bf_hookopts_validate(hookopts, cgen->chain->hook);
473 [ + + ]: 11 : if (r)
474 [ + - ]: 1 : return bf_err_r(r, "failed to validate hook options");
475 : :
476 : 10 : r = bf_cgen_attach(cgen, bf_request_ns(request), &hookopts);
477 [ + + ]: 10 : if (r)
478 [ + - ]: 2 : return bf_err_r(r, "failed to attach codegen to hook");
479 : :
480 : : return r;
481 : : }
482 : :
483 : 6 : int _bf_cli_chain_update(const struct bf_request *request,
484 : : struct bf_response **response)
485 : : {
486 : 6 : _free_bf_chain_ struct bf_chain *chain = NULL;
487 : : struct bf_cgen *cgen = NULL;
488 : 6 : _free_bf_rpack_ bf_rpack_t *pack = NULL;
489 : : bf_rpack_node_t child;
490 : : int r;
491 : :
492 : : assert(request);
493 : :
494 : : (void)response;
495 : :
496 : 6 : r = bf_rpack_new(&pack, bf_request_data(request),
497 : : bf_request_data_len(request));
498 [ + - ]: 6 : if (r)
499 : : return r;
500 : :
501 : 6 : r = bf_rpack_kv_obj(bf_rpack_root(pack), "chain", &child);
502 [ + - ]: 6 : if (r)
503 : : return r;
504 : 6 : r = bf_chain_new_from_pack(&chain, child);
505 [ + - ]: 6 : if (r)
506 : : return r;
507 : :
508 : 6 : cgen = bf_ctx_get_cgen(chain->name);
509 [ + + ]: 6 : if (!cgen)
510 : : return -ENOENT;
511 : :
512 : 5 : r = bf_cgen_update(cgen, &chain);
513 [ - + ]: 5 : if (r)
514 : 0 : return -EINVAL;
515 : :
516 : : return r;
517 : : }
518 : :
519 : 20 : int _bf_cli_chain_flush(const struct bf_request *request,
520 : : struct bf_response **response)
521 : : {
522 : : struct bf_cgen *cgen = NULL;
523 : 20 : _free_bf_rpack_ bf_rpack_t *pack = NULL;
524 : 20 : _cleanup_free_ char *name = NULL;
525 : : int r;
526 : :
527 : : assert(request);
528 : :
529 : : (void)response;
530 : :
531 : 20 : r = bf_rpack_new(&pack, bf_request_data(request),
532 : : bf_request_data_len(request));
533 [ + - ]: 20 : if (r)
534 : : return r;
535 : :
536 : 20 : r = bf_rpack_kv_str(bf_rpack_root(pack), "name", &name);
537 [ + - ]: 20 : if (r)
538 : : return r;
539 : :
540 : 20 : cgen = bf_ctx_get_cgen(name);
541 [ + - ]: 20 : if (!cgen)
542 : : return -ENOENT;
543 : :
544 : 20 : return bf_ctx_delete_cgen(cgen, true);
545 : : }
546 : :
547 : 6 : int _bf_cli_chain_update_set(const struct bf_request *request,
548 : : struct bf_response **response)
549 : : {
550 : 6 : _free_bf_set_ struct bf_set *to_add = NULL;
551 : 6 : _free_bf_set_ struct bf_set *to_remove = NULL;
552 : 6 : _free_bf_chain_ struct bf_chain *new_chain = NULL;
553 : 6 : _free_bf_rpack_ bf_rpack_t *pack = NULL;
554 : : struct bf_set *dest_set = NULL;
555 : 6 : _cleanup_free_ char *chain_name = NULL;
556 : : struct bf_cgen *cgen = NULL;
557 : : bf_rpack_node_t child;
558 : : int r;
559 : :
560 : : assert(request);
561 : :
562 : : (void)response;
563 : :
564 : 6 : r = bf_rpack_new(&pack, bf_request_data(request),
565 : : bf_request_data_len(request));
566 [ + - ]: 6 : if (r)
567 : : return r;
568 : :
569 : 6 : r = bf_rpack_kv_str(bf_rpack_root(pack), "name", &chain_name);
570 [ + - ]: 6 : if (r)
571 : : return r;
572 : :
573 : 6 : r = bf_rpack_kv_obj(bf_rpack_root(pack), "to_add", &child);
574 [ + - ]: 6 : if (r)
575 : : return r;
576 : 6 : r = bf_set_new_from_pack(&to_add, child);
577 [ + - ]: 6 : if (r)
578 : : return r;
579 : :
580 : 6 : r = bf_rpack_kv_obj(bf_rpack_root(pack), "to_remove", &child);
581 [ + - ]: 6 : if (r)
582 : : return r;
583 : 6 : r = bf_set_new_from_pack(&to_remove, child);
584 [ + - ]: 6 : if (r)
585 : : return r;
586 : :
587 [ - + ]: 6 : if (!bf_streq(to_add->name, to_remove->name))
588 [ # # ]: 0 : return bf_err_r(-EINVAL, "to_add->name must match to_remove->name");
589 : :
590 : 6 : cgen = bf_ctx_get_cgen(chain_name);
591 [ - + ]: 6 : if (!cgen)
592 [ # # ]: 0 : return bf_err_r(-ENOENT, "chain '%s' does not exist", chain_name);
593 : :
594 : 6 : r = bf_chain_new_from_copy(&new_chain, cgen->chain);
595 [ + - ]: 6 : if (r)
596 : : return r;
597 : :
598 : 6 : dest_set = bf_chain_get_set_by_name(new_chain, to_add->name);
599 [ - + ]: 6 : if (!dest_set)
600 [ # # ]: 0 : return bf_err_r(-ENOENT, "set '%s' does not exist", to_add->name);
601 : :
602 : 6 : r = bf_set_add_many(dest_set, &to_add);
603 [ - + ]: 6 : if (r)
604 [ # # ]: 0 : return bf_err_r(r, "failed to calculate set union");
605 : :
606 : 6 : r = bf_set_remove_many(dest_set, &to_remove);
607 [ - + ]: 6 : if (r)
608 [ # # ]: 0 : return bf_err_r(r, "failed to calculate set difference");
609 : :
610 : 6 : r = bf_cgen_update(cgen, &new_chain);
611 [ - + ]: 6 : if (r)
612 [ # # ]: 0 : return bf_err_r(r, "failed to update chain with new set data");
613 : :
614 : : return 0;
615 : : }
616 : :
617 : 167 : static int _bf_cli_request_handler(const struct bf_request *request,
618 : : struct bf_response **response)
619 : : {
620 : : int r;
621 : :
622 : : assert(request);
623 : : assert(response);
624 : :
625 [ + + + + : 167 : switch (bf_request_cmd(request)) {
+ - - + +
+ + + - ]
626 : 6 : case BF_REQ_RULESET_FLUSH:
627 : 6 : r = _bf_cli_ruleset_flush(request, response);
628 : 6 : break;
629 : 8 : case BF_REQ_RULESET_SET:
630 : 8 : r = _bf_cli_ruleset_set(request, response);
631 : 8 : break;
632 : 4 : case BF_REQ_RULESET_GET:
633 : 4 : r = _bf_cli_ruleset_get(request, response);
634 : 4 : break;
635 : 60 : case BF_REQ_CHAIN_SET:
636 : 60 : r = _bf_cli_chain_set(request, response);
637 : 60 : break;
638 : 34 : case BF_REQ_CHAIN_GET:
639 : 34 : r = _bf_cli_chain_get(request, response);
640 : 34 : break;
641 : 0 : case BF_REQ_CHAIN_PROG_FD:
642 : 0 : r = _bf_cli_chain_prog_fd(request, response);
643 : 0 : break;
644 : 0 : case BF_REQ_CHAIN_LOGS_FD:
645 : 0 : r = _bf_cli_chain_logs_fd(request, response);
646 : 0 : break;
647 : 12 : case BF_REQ_CHAIN_LOAD:
648 : 12 : r = _bf_cli_chain_load(request, response);
649 : 12 : break;
650 : 11 : case BF_REQ_CHAIN_ATTACH:
651 : 11 : r = _bf_cli_chain_attach(request, response);
652 : 11 : break;
653 : 6 : case BF_REQ_CHAIN_UPDATE:
654 : 6 : r = _bf_cli_chain_update(request, response);
655 : 6 : break;
656 : 20 : case BF_REQ_CHAIN_FLUSH:
657 : 20 : r = _bf_cli_chain_flush(request, response);
658 : 20 : break;
659 : 6 : case BF_REQ_CHAIN_UPDATE_SET:
660 : 6 : r = _bf_cli_chain_update_set(request, response);
661 : 6 : break;
662 : 0 : default:
663 [ # # ]: 0 : r = bf_err_r(-EINVAL, "unsupported command %d for CLI front-end",
664 : : bf_request_cmd(request));
665 : : break;
666 : : }
667 : :
668 : : /* If the callback don't need to send data back to the client, it can skip
669 : : * the response creation and return a status code instead (0 on success,
670 : : * negative errno value on error). The response is created based on the
671 : : * status code. */
672 [ + + ]: 167 : if (!*response) {
673 [ + + ]: 130 : if (!r)
674 : 120 : r = bf_response_new_success(response, NULL, 0);
675 : : else
676 : 10 : r = bf_response_new_failure(response, r);
677 : : }
678 : :
679 : 167 : return r;
680 : : }
681 : :
682 : 111 : static int _bf_cli_pack(bf_wpack_t *pack)
683 : : {
684 : : (void)pack;
685 : :
686 : 111 : return 0;
687 : : }
688 : :
689 : 5 : static int _bf_cli_unpack(bf_rpack_node_t node)
690 : : {
691 : : (void)node;
692 : :
693 : 5 : return 0;
694 : : }
|