LCOV - code coverage report
Current view: top level - bpfilter/cgen - cgen.c (source / functions) Coverage Total Hit
Test: lcov.out Lines: 40.0 % 135 54
Test Date: 2025-03-25 15:17:39 Functions: 44.4 % 9 4

            Line data    Source code
       1              : /* SPDX-License-Identifier: GPL-2.0-only */
       2              : /*
       3              :  * Copyright (c) 2023 Meta Platforms, Inc. and affiliates.
       4              :  */
       5              : 
       6              : #include "bpfilter/cgen/cgen.h"
       7              : 
       8              : #include <errno.h>
       9              : #include <stddef.h>
      10              : #include <stdint.h>
      11              : #include <stdlib.h>
      12              : #include <string.h>
      13              : 
      14              : #include "bpfilter/cgen/dump.h"
      15              : #include "bpfilter/cgen/program.h"
      16              : #include "bpfilter/ctx.h"
      17              : #include "core/chain.h"
      18              : #include "core/dump.h"
      19              : #include "core/front.h"
      20              : #include "core/helper.h"
      21              : #include "core/hook.h"
      22              : #include "core/list.h"
      23              : #include "core/logger.h"
      24              : #include "core/marsh.h"
      25              : #include "core/ns.h"
      26              : #include "core/opts.h"
      27              : #include "core/rule.h"
      28              : 
      29            9 : int bf_cgen_new(struct bf_cgen **cgen, enum bf_front front,
      30              :                 struct bf_chain **chain)
      31              : {
      32           12 :     bf_assert(cgen && chain && *chain);
      33              : 
      34            6 :     *cgen = malloc(sizeof(struct bf_cgen));
      35            6 :     if (!*cgen)
      36              :         return -ENOMEM;
      37              : 
      38            5 :     (*cgen)->front = front;
      39            5 :     (*cgen)->program = NULL;
      40            5 :     (*cgen)->chain = TAKE_PTR(*chain);
      41              : 
      42            5 :     return 0;
      43              : }
      44              : 
      45            3 : int bf_cgen_new_from_marsh(struct bf_cgen **cgen, const struct bf_marsh *marsh)
      46              : {
      47            1 :     _cleanup_bf_cgen_ struct bf_cgen *_cgen = NULL;
      48            1 :     _cleanup_bf_program_ struct bf_program *program = NULL;
      49            1 :     _cleanup_bf_chain_ struct bf_chain *chain = NULL;
      50              :     struct bf_marsh *marsh_elem = NULL;
      51              :     enum bf_front front;
      52              :     int r;
      53              : 
      54            3 :     bf_assert(cgen);
      55            2 :     bf_assert(marsh);
      56              : 
      57            1 :     if (!(marsh_elem = bf_marsh_next_child(marsh, marsh_elem)))
      58              :         return -EINVAL;
      59            1 :     memcpy(&front, marsh_elem->data, sizeof(front));
      60              : 
      61            1 :     if (!(marsh_elem = bf_marsh_next_child(marsh, marsh_elem)))
      62              :         return -EINVAL;
      63              : 
      64            1 :     r = bf_chain_new_from_marsh(&chain, marsh_elem);
      65            1 :     if (r < 0)
      66              :         return r;
      67              : 
      68            1 :     r = bf_cgen_new(&_cgen, front, &chain);
      69            1 :     if (r)
      70            0 :         return bf_err_r(r, "failed to allocate codegen object");
      71              : 
      72            1 :     if (!(marsh_elem = bf_marsh_next_child(marsh, marsh_elem)))
      73              :         return -EINVAL;
      74            1 :     if (!bf_marsh_is_empty(marsh_elem)) {
      75            0 :         r = bf_program_unmarsh(marsh_elem, &_cgen->program, _cgen->chain);
      76            0 :         if (r < 0)
      77              :             return r;
      78              :     }
      79              : 
      80            1 :     if (bf_marsh_next_child(marsh, marsh_elem))
      81            0 :         bf_warn("codegen marsh has more children than expected");
      82              : 
      83            1 :     *cgen = TAKE_PTR(_cgen);
      84              : 
      85            1 :     return 0;
      86              : }
      87              : 
      88            9 : void bf_cgen_free(struct bf_cgen **cgen)
      89              : {
      90            9 :     bf_assert(cgen);
      91              : 
      92            8 :     if (!*cgen)
      93              :         return;
      94              : 
      95            5 :     bf_program_free(&(*cgen)->program);
      96            5 :     bf_chain_free(&(*cgen)->chain);
      97              : 
      98            5 :     free(*cgen);
      99            5 :     *cgen = NULL;
     100              : }
     101              : 
     102            3 : int bf_cgen_marsh(const struct bf_cgen *cgen, struct bf_marsh **marsh)
     103              : {
     104            1 :     _cleanup_bf_marsh_ struct bf_marsh *_marsh = NULL;
     105              :     int r;
     106              : 
     107            3 :     bf_assert(cgen);
     108            2 :     bf_assert(marsh);
     109              : 
     110            1 :     r = bf_marsh_new(&_marsh, NULL, 0);
     111            1 :     if (r)
     112              :         return r;
     113              : 
     114            1 :     r = bf_marsh_add_child_raw(&_marsh, &cgen->front, sizeof(cgen->front));
     115            1 :     if (r < 0)
     116            0 :         return bf_err_r(r, "failed to serialize codegen");
     117              : 
     118              :     {
     119              :         // Serialize cgen.chain
     120            1 :         _cleanup_bf_marsh_ struct bf_marsh *chain_elem = NULL;
     121              : 
     122            1 :         r = bf_chain_marsh(cgen->chain, &chain_elem);
     123            1 :         if (r < 0)
     124              :             return r;
     125              : 
     126            1 :         r = bf_marsh_add_child_obj(&_marsh, chain_elem);
     127            1 :         if (r < 0)
     128              :             return r;
     129              :     }
     130              : 
     131              :     {
     132            1 :         _cleanup_bf_marsh_ struct bf_marsh *prog_elem = NULL;
     133              : 
     134            1 :         if (cgen->program) {
     135            0 :             r = bf_program_marsh(cgen->program, &prog_elem);
     136            0 :             if (r < 0)
     137              :                 return r;
     138              :         } else {
     139            1 :             r = bf_marsh_new(&prog_elem, NULL, 0);
     140            1 :             if (r < 0)
     141              :                 return r;
     142              :         }
     143              : 
     144            1 :         r = bf_marsh_add_child_obj(&_marsh, prog_elem);
     145            1 :         if (r)
     146              :             return r;
     147              :     }
     148              : 
     149            1 :     *marsh = TAKE_PTR(_marsh);
     150              : 
     151            1 :     return 0;
     152              : }
     153              : 
     154            0 : int bf_cgen_unload(struct bf_cgen *cgen)
     155              : {
     156            0 :     bf_assert(cgen);
     157              : 
     158            0 :     return bf_program_unload(cgen->program);
     159              : }
     160              : 
     161            0 : void bf_cgen_dump(const struct bf_cgen *cgen, prefix_t *prefix)
     162              : {
     163            0 :     bf_assert(cgen);
     164            0 :     bf_assert(prefix);
     165              : 
     166            0 :     DUMP(prefix, "struct bf_cgen at %p", cgen);
     167              : 
     168            0 :     bf_dump_prefix_push(prefix);
     169            0 :     DUMP(prefix, "front: %s", bf_front_to_str(cgen->front));
     170              : 
     171              :     // Chain
     172            0 :     DUMP(prefix, "chain: struct bf_chain *");
     173            0 :     bf_dump_prefix_push(prefix);
     174            0 :     bf_chain_dump(cgen->chain, bf_dump_prefix_last(prefix));
     175            0 :     bf_dump_prefix_pop(prefix);
     176              : 
     177              :     // Programs
     178            0 :     if (cgen->program) {
     179            0 :         DUMP(bf_dump_prefix_last(prefix), "program: struct bf_program *");
     180            0 :         bf_dump_prefix_push(prefix);
     181            0 :         bf_program_dump(cgen->program, bf_dump_prefix_last(prefix));
     182            0 :         bf_dump_prefix_pop(prefix);
     183              :     } else {
     184            0 :         DUMP(bf_dump_prefix_last(prefix), "program: (struct bf_program *)NULL");
     185              :     }
     186              : 
     187            0 :     bf_dump_prefix_pop(prefix);
     188            0 : }
     189              : 
     190            0 : int bf_cgen_get_counter(const struct bf_cgen *cgen,
     191              :                         enum bf_counter_type counter_idx,
     192              :                         struct bf_counter *counter)
     193              : {
     194            0 :     bf_assert(cgen && counter);
     195              : 
     196              :     /* There are two more counter than rules. The special counters must
     197              :      * be accessed via the specific values, to avoid confusion. */
     198            0 :     enum bf_counter_type rule_count = bf_list_size(&cgen->chain->rules);
     199            0 :     if (counter_idx == BF_COUNTER_POLICY) {
     200              :         counter_idx = rule_count;
     201            0 :     } else if (counter_idx == BF_COUNTER_ERRORS) {
     202            0 :         counter_idx = rule_count + 1;
     203            0 :     } else if (counter_idx < 0 || counter_idx >= rule_count) {
     204              :         return -EINVAL;
     205              :     }
     206              : 
     207            0 :     return bf_program_get_counter(cgen->program, counter_idx, counter);
     208              : }
     209              : 
     210            0 : int bf_cgen_up(struct bf_cgen *cgen, const struct bf_ns *ns)
     211              : {
     212            0 :     _cleanup_bf_program_ struct bf_program *prog = NULL;
     213              :     int r;
     214              : 
     215            0 :     bf_assert(cgen);
     216              : 
     217            0 :     if (bf_opts_is_verbose(BF_VERBOSE_DEBUG))
     218            0 :         bf_cgen_dump(cgen, EMPTY_PREFIX);
     219              : 
     220            0 :     r = bf_program_new(&prog, cgen->chain->hook, cgen->front, cgen->chain);
     221            0 :     if (r < 0)
     222              :         return r;
     223              : 
     224            0 :     r = bf_program_generate(prog);
     225            0 :     if (r < 0) {
     226            0 :         return bf_err_r(r, "failed to generate bf_program for %s",
     227              :                         bf_hook_to_str(cgen->chain->hook));
     228              :     }
     229              : 
     230            0 :     r = bf_ns_set(ns, bf_ctx_get_ns());
     231            0 :     if (r)
     232            0 :         return bf_err_r(r, "failed to switch to the client's namespaces");
     233              : 
     234            0 :     r = bf_program_load(prog, NULL);
     235            0 :     if (r < 0) {
     236            0 :         if (bf_ns_set(bf_ctx_get_ns(), ns))
     237            0 :             bf_abort("failed to restore previous namespaces, aborting");
     238            0 :         return bf_err_r(r, "failed to load and attach the chain");
     239              :     }
     240              : 
     241            0 :     if (bf_ns_set(bf_ctx_get_ns(), ns))
     242            0 :         bf_abort("failed to restore previous namespaces, aborting");
     243              : 
     244            0 :     cgen->program = TAKE_PTR(prog);
     245              : 
     246            0 :     return r;
     247              : }
     248              : 
     249            0 : int bf_cgen_update(struct bf_cgen *cgen, struct bf_chain **new_chain,
     250              :                    const struct bf_ns *ns)
     251              : {
     252            0 :     _cleanup_bf_program_ struct bf_program *new_prog = NULL;
     253              :     int r;
     254              : 
     255            0 :     bf_assert(cgen && new_chain);
     256              : 
     257            0 :     r = bf_program_new(&new_prog, (*new_chain)->hook, cgen->front, *new_chain);
     258            0 :     if (r < 0)
     259            0 :         return bf_err_r(r, "failed to create a new bf_program");
     260              : 
     261            0 :     r = bf_program_generate(new_prog);
     262            0 :     if (r < 0) {
     263            0 :         return bf_err_r(r,
     264              :                         "failed to generate the bytecode for a new bf_program");
     265              :     }
     266              : 
     267            0 :     r = bf_ns_set(ns, bf_ctx_get_ns());
     268            0 :     if (r)
     269            0 :         return bf_err_r(r, "failed to switch to the client's namespaces");
     270              : 
     271            0 :     r = bf_program_load(new_prog, cgen->program);
     272            0 :     if (r < 0) {
     273            0 :         if (bf_ns_set(bf_ctx_get_ns(), ns))
     274            0 :             bf_abort("failed to restore previous namespaces, aborting");
     275            0 :         return bf_err_r(r, "failed to load and attach the new chain");
     276              :     }
     277              : 
     278            0 :     if (bf_ns_set(bf_ctx_get_ns(), ns))
     279            0 :         bf_abort("failed to restore previous namespaces, aborting");
     280              : 
     281            0 :     bf_swap(cgen->program, new_prog);
     282            0 :     bf_swap(cgen->chain, *new_chain);
     283              : 
     284            0 :     if (bf_opts_is_verbose(BF_VERBOSE_DEBUG))
     285            0 :         bf_cgen_dump(cgen, EMPTY_PREFIX);
     286              : 
     287              :     return 0;
     288              : }
        

Generated by: LCOV version 2.0-1