LCOV - code coverage report
Current view: top level - core - chain.c (source / functions) Coverage Total Hit
Test: lcov.out Lines: 68.8 % 128 88
Test Date: 2025-08-19 17:27:08 Functions: 75.0 % 8 6

            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 "chain.h"
       7              : 
       8              : #include <errno.h>
       9              : #include <stdlib.h>
      10              : #include <string.h>
      11              : 
      12              : #include "core/dump.h"
      13              : #include "core/helper.h"
      14              : #include "core/hook.h"
      15              : #include "core/list.h"
      16              : #include "core/logger.h"
      17              : #include "core/marsh.h"
      18              : #include "core/rule.h"
      19              : #include "core/set.h"
      20              : #include "core/verdict.h"
      21              : 
      22           10 : static void _bf_chain_update_features(struct bf_chain *chain,
      23              :                                       const struct bf_rule *rule)
      24              : {
      25           10 :     bf_assert(rule);
      26              : 
      27           10 :     if (rule->log)
      28            0 :         chain->flags |= BF_FLAG(BF_CHAIN_LOG);
      29              : 
      30           80 :     bf_list_foreach (&rule->matchers, matcher_node) {
      31           30 :         struct bf_matcher *matcher = bf_list_node_get_data(matcher_node);
      32           30 :         if (matcher->type == BF_MATCHER_IP6_NEXTHDR) {
      33            0 :             chain->flags |= BF_FLAG(BF_CHAIN_STORE_NEXTHDR);
      34            0 :             break;
      35              :         }
      36              :     }
      37           10 : }
      38              : 
      39           19 : int bf_chain_new(struct bf_chain **chain, const char *name, enum bf_hook hook,
      40              :                  enum bf_verdict policy, bf_list *sets, bf_list *rules)
      41              : {
      42           15 :     _free_bf_chain_ struct bf_chain *_chain = NULL;
      43              :     size_t ridx = 0;
      44              : 
      45           19 :     bf_assert(chain && name);
      46           17 :     bf_assert(policy < _BF_TERMINAL_VERDICT_MAX);
      47              : 
      48           15 :     _chain = malloc(sizeof(*_chain));
      49           15 :     if (!_chain)
      50              :         return -ENOMEM;
      51              : 
      52           15 :     _chain->name = strdup(name);
      53           15 :     if (!_chain->name)
      54              :         return -ENOMEM;
      55              : 
      56           15 :     _chain->flags = 0;
      57           15 :     _chain->hook = hook;
      58           15 :     _chain->policy = policy;
      59              : 
      60           15 :     _chain->sets = bf_list_default(bf_set_free, bf_set_marsh);
      61           15 :     if (sets)
      62            1 :         _chain->sets = bf_list_move(*sets);
      63              : 
      64           15 :     _chain->rules = bf_list_default(bf_rule_free, bf_rule_marsh);
      65           15 :     if (rules)
      66            2 :         _chain->rules = bf_list_move(*rules);
      67           42 :     bf_list_foreach (&_chain->rules, rule_node) {
      68            6 :         struct bf_rule *rule = bf_list_node_get_data(rule_node);
      69              : 
      70            6 :         rule->index = ridx++;
      71            6 :         _bf_chain_update_features(_chain, rule);
      72              :     }
      73              : 
      74           15 :     *chain = TAKE_PTR(_chain);
      75              : 
      76           15 :     return 0;
      77              : }
      78              : 
      79            2 : int bf_chain_new_from_marsh(struct bf_chain **chain,
      80              :                             const struct bf_marsh *marsh)
      81              : {
      82            2 :     _free_bf_chain_ struct bf_chain *_chain = NULL;
      83              :     struct bf_marsh *child = NULL;
      84              :     struct bf_marsh *list_elem;
      85              :     enum bf_hook hook;
      86              :     enum bf_verdict policy;
      87              :     _cleanup_free_ const char *name = NULL;
      88              :     int r;
      89              : 
      90            2 :     bf_assert(chain && marsh);
      91              : 
      92            2 :     if (!(child = bf_marsh_next_child(marsh, child)))
      93              :         return -EINVAL;
      94            2 :     if (child->data_len == 0)
      95            0 :         return bf_err_r(-EINVAL, "serialized bf_chain.name is empty");
      96            2 :     name = strdup(child->data);
      97            2 :     if (!name)
      98              :         return -ENOMEM;
      99              : 
     100            2 :     if (!(child = bf_marsh_next_child(marsh, child)))
     101              :         return -EINVAL;
     102            2 :     memcpy(&hook, child->data, sizeof(hook));
     103              : 
     104            2 :     if (!(child = bf_marsh_next_child(marsh, child)))
     105              :         return -EINVAL;
     106            2 :     memcpy(&policy, child->data, sizeof(policy));
     107              : 
     108            2 :     r = bf_chain_new(&_chain, name, hook, policy, NULL, NULL);
     109            2 :     if (r)
     110              :         return r;
     111              : 
     112              :     // Unmarsh bf_chain.sets
     113              :     list_elem = NULL;
     114            2 :     if (!(child = bf_marsh_next_child(marsh, child)))
     115              :         return -EINVAL;
     116            2 :     while ((list_elem = bf_marsh_next_child(child, list_elem))) {
     117            0 :         _free_bf_set_ struct bf_set *set = NULL;
     118              : 
     119            0 :         r = bf_set_new_from_marsh(&set, list_elem);
     120            0 :         if (r)
     121              :             return r;
     122              : 
     123            0 :         r = bf_list_add_tail(&_chain->sets, set);
     124            0 :         if (r)
     125              :             return r;
     126              : 
     127            0 :         TAKE_PTR(set);
     128              :     }
     129              : 
     130              :     // Unmarsh bf_chain.rules
     131              :     list_elem = NULL;
     132            2 :     if (!(child = bf_marsh_next_child(marsh, child)))
     133              :         return -EINVAL;
     134            6 :     while ((list_elem = bf_marsh_next_child(child, list_elem))) {
     135            0 :         _free_bf_rule_ struct bf_rule *rule = NULL;
     136              : 
     137            4 :         r = bf_rule_unmarsh(list_elem, &rule);
     138            4 :         if (r)
     139              :             return r;
     140              : 
     141              :         // Using bf_chain_add_rule() will automatically update chain->flags
     142            4 :         r = bf_chain_add_rule(_chain, rule);
     143            4 :         if (r)
     144              :             return r;
     145              : 
     146            4 :         TAKE_PTR(rule);
     147              :     }
     148              : 
     149            2 :     *chain = TAKE_PTR(_chain);
     150              : 
     151            2 :     return 0;
     152              : }
     153              : 
     154           38 : void bf_chain_free(struct bf_chain **chain)
     155              : {
     156           38 :     bf_assert(chain);
     157              : 
     158           37 :     if (!*chain)
     159              :         return;
     160              : 
     161           15 :     bf_list_clean(&(*chain)->sets);
     162           15 :     bf_list_clean(&(*chain)->rules);
     163           15 :     freep((void *)&(*chain)->name);
     164              :     freep((void *)chain);
     165              : }
     166              : 
     167            2 : int bf_chain_marsh(const struct bf_chain *chain, struct bf_marsh **marsh)
     168              : {
     169            2 :     _free_bf_marsh_ struct bf_marsh *_marsh = NULL;
     170              :     int r;
     171              : 
     172            2 :     bf_assert(chain && marsh);
     173              : 
     174            2 :     r = bf_marsh_new(&_marsh, NULL, 0);
     175            2 :     if (r)
     176              :         return r;
     177              : 
     178            2 :     r = bf_marsh_add_child_raw(&_marsh, chain->name, strlen(chain->name) + 1);
     179            2 :     if (r < 0)
     180              :         return r;
     181              : 
     182            2 :     r = bf_marsh_add_child_raw(&_marsh, &chain->hook, sizeof(chain->hook));
     183            2 :     if (r < 0)
     184              :         return r;
     185              : 
     186            2 :     r = bf_marsh_add_child_raw(&_marsh, &chain->policy, sizeof(chain->policy));
     187            2 :     if (r)
     188              :         return r;
     189              : 
     190              :     {
     191              :         // Serialize bf_chain.sets
     192            2 :         _free_bf_marsh_ struct bf_marsh *child = NULL;
     193              : 
     194            2 :         r = bf_list_marsh(&chain->sets, &child);
     195            2 :         if (r < 0)
     196              :             return r;
     197              : 
     198            2 :         r = bf_marsh_add_child_obj(&_marsh, child);
     199            2 :         if (r < 0)
     200              :             return r;
     201              :     }
     202              : 
     203              :     {
     204              :         // Serialize bf_chain.rules
     205            2 :         _free_bf_marsh_ struct bf_marsh *child = NULL;
     206              : 
     207            2 :         r = bf_list_marsh(&chain->rules, &child);
     208            2 :         if (r < 0)
     209              :             return r;
     210              : 
     211            2 :         r = bf_marsh_add_child_obj(&_marsh, child);
     212            2 :         if (r < 0)
     213              :             return r;
     214              :     }
     215              : 
     216            2 :     *marsh = TAKE_PTR(_marsh);
     217              : 
     218            2 :     return 0;
     219              : }
     220              : 
     221            0 : void bf_chain_dump(const struct bf_chain *chain, prefix_t *prefix)
     222              : {
     223            0 :     bf_assert(chain && prefix);
     224              : 
     225            0 :     DUMP(prefix, "struct bf_chain at %p", chain);
     226            0 :     bf_dump_prefix_push(prefix);
     227              : 
     228            0 :     DUMP(prefix, "name: %s", chain->name);
     229            0 :     DUMP(prefix, "flags: %02x", chain->flags);
     230            0 :     DUMP(prefix, "hook: %s", bf_hook_to_str(chain->hook));
     231            0 :     DUMP(prefix, "policy: %s", bf_verdict_to_str(chain->policy));
     232              : 
     233            0 :     DUMP(prefix, "sets: bf_list<bf_set>[%lu]", bf_list_size(&chain->sets));
     234            0 :     bf_dump_prefix_push(prefix);
     235            0 :     bf_list_foreach (&chain->sets, set_node) {
     236            0 :         if (bf_list_is_tail(&chain->sets, set_node))
     237            0 :             bf_dump_prefix_last(prefix);
     238              : 
     239            0 :         bf_set_dump(bf_list_node_get_data(set_node), prefix);
     240              :     }
     241            0 :     bf_dump_prefix_pop(prefix);
     242              : 
     243            0 :     DUMP(bf_dump_prefix_last(prefix), "rules: bf_list<bf_rule>[%lu]",
     244              :          bf_list_size(&chain->rules));
     245            0 :     bf_dump_prefix_push(prefix);
     246            0 :     bf_list_foreach (&chain->rules, rule_node) {
     247            0 :         if (bf_list_is_tail(&chain->rules, rule_node))
     248            0 :             bf_dump_prefix_last(prefix);
     249              : 
     250            0 :         bf_rule_dump(bf_list_node_get_data(rule_node), prefix);
     251              :     }
     252            0 :     bf_dump_prefix_pop(prefix);
     253              : 
     254            0 :     bf_dump_prefix_pop(prefix);
     255            0 : }
     256              : 
     257            4 : int bf_chain_add_rule(struct bf_chain *chain, struct bf_rule *rule)
     258              : {
     259            4 :     bf_assert(chain && rule);
     260              : 
     261            4 :     rule->index = bf_list_size(&chain->rules);
     262            4 :     _bf_chain_update_features(chain, rule);
     263              : 
     264            4 :     return bf_list_add_tail(&chain->rules, rule);
     265              : }
     266              : 
     267            0 : struct bf_set *bf_chain_get_set_for_matcher(const struct bf_chain *chain,
     268              :                                             const struct bf_matcher *matcher)
     269              : {
     270            0 :     bf_assert(chain && matcher);
     271              : 
     272              :     uint32_t set_id;
     273              : 
     274            0 :     if (matcher->type != BF_MATCHER_SET)
     275              :         return NULL;
     276              : 
     277            0 :     set_id = *(uint32_t *)matcher->payload;
     278              : 
     279            0 :     return bf_list_get_at(&chain->sets, set_id);
     280              : }
        

Generated by: LCOV version 2.0-1