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

Generated by: LCOV version 2.0-1