LCOV - code coverage report
Current view: top level - libbpfilter - chain.c (source / functions) Coverage Total Hit
Test: lcov.out Lines: 57.1 % 126 72
Test Date: 2025-09-30 16:37:25 Functions: 66.7 % 9 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 "bpfilter/chain.h"
       7              : 
       8              : #include <errno.h>
       9              : #include <stdlib.h>
      10              : #include <string.h>
      11              : 
      12              : #include "bpfilter/dump.h"
      13              : #include "bpfilter/helper.h"
      14              : #include "bpfilter/hook.h"
      15              : #include "bpfilter/list.h"
      16              : #include "bpfilter/logger.h"
      17              : #include "bpfilter/pack.h"
      18              : #include "bpfilter/rule.h"
      19              : #include "bpfilter/set.h"
      20              : #include "bpfilter/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           10 :     if (bf_rule_mark_is_set(rule))
      31            0 :         chain->flags |= BF_FLAG(BF_CHAIN_SET_MARK);
      32              : 
      33           80 :     bf_list_foreach (&rule->matchers, matcher_node) {
      34           30 :         struct bf_matcher *matcher = bf_list_node_get_data(matcher_node);
      35           30 :         if (bf_matcher_get_type(matcher) == BF_MATCHER_IP6_NEXTHDR)
      36            0 :             chain->flags |= BF_FLAG(BF_CHAIN_STORE_NEXTHDR);
      37              : 
      38           30 :         if (bf_matcher_get_type(matcher) == BF_MATCHER_META_MARK)
      39            0 :             chain->flags |= BF_FLAG(BF_CHAIN_GET_MARK);
      40              :     }
      41           10 : }
      42              : 
      43           19 : int bf_chain_new(struct bf_chain **chain, const char *name, enum bf_hook hook,
      44              :                  enum bf_verdict policy, bf_list *sets, bf_list *rules)
      45              : {
      46           15 :     _free_bf_chain_ struct bf_chain *_chain = NULL;
      47              :     size_t ridx = 0;
      48              : 
      49           19 :     bf_assert(chain && name);
      50           17 :     bf_assert(policy < _BF_TERMINAL_VERDICT_MAX);
      51              : 
      52           15 :     _chain = malloc(sizeof(*_chain));
      53           15 :     if (!_chain)
      54              :         return -ENOMEM;
      55              : 
      56           15 :     _chain->name = strdup(name);
      57           15 :     if (!_chain->name)
      58              :         return -ENOMEM;
      59              : 
      60           15 :     _chain->flags = 0;
      61           15 :     _chain->hook = hook;
      62           15 :     _chain->policy = policy;
      63              : 
      64           15 :     _chain->sets = bf_list_default(bf_set_free, bf_set_pack);
      65           15 :     if (sets)
      66            3 :         _chain->sets = bf_list_move(*sets);
      67              : 
      68           15 :     _chain->rules = bf_list_default(bf_rule_free, bf_rule_pack);
      69           15 :     if (rules)
      70            4 :         _chain->rules = bf_list_move(*rules);
      71           50 :     bf_list_foreach (&_chain->rules, rule_node) {
      72           10 :         struct bf_rule *rule = bf_list_node_get_data(rule_node);
      73              : 
      74           10 :         rule->index = ridx++;
      75           10 :         _bf_chain_update_features(_chain, rule);
      76              :     }
      77              : 
      78           15 :     *chain = TAKE_PTR(_chain);
      79              : 
      80           15 :     return 0;
      81              : }
      82              : 
      83            2 : int bf_chain_new_from_pack(struct bf_chain **chain, bf_rpack_node_t node)
      84              : {
      85            2 :     _free_bf_chain_ struct bf_chain *_chain = NULL;
      86            2 :     _cleanup_free_ char *name = NULL;
      87              :     enum bf_hook hook;
      88              :     enum bf_verdict policy;
      89              :     bf_rpack_node_t array, array_node;
      90            2 :     bf_list rules = bf_list_default(bf_rule_free, bf_rule_pack);
      91            2 :     bf_list sets = bf_list_default(bf_set_free, bf_set_pack);
      92              :     int r;
      93              : 
      94            2 :     r = bf_rpack_kv_str(node, "name", &name);
      95            2 :     if (r)
      96            0 :         return bf_rpack_key_err(r, "bf_chain.name");
      97              : 
      98            2 :     r = bf_rpack_kv_enum(node, "hook", &hook);
      99              :     if (r)
     100            0 :         return bf_rpack_key_err(r, "bf_chain.hook");
     101              : 
     102            2 :     r = bf_rpack_kv_enum(node, "policy", &policy);
     103              :     if (r)
     104            0 :         return bf_rpack_key_err(r, "bf_chain.policy");
     105              : 
     106            2 :     r = bf_rpack_kv_array(node, "sets", &array);
     107            2 :     if (r)
     108            0 :         return bf_rpack_key_err(r, "bf_chain.sets");
     109            4 :     bf_rpack_array_foreach (array, array_node) {
     110            0 :         _free_bf_set_ struct bf_set *set = NULL;
     111              : 
     112            0 :         r = bf_list_emplace(&sets, bf_set_new_from_pack, set, array_node);
     113              :         if (r) {
     114            0 :             return bf_err_r(r, "failed to unpack bf_set into bf_chain.sets");
     115              :         }
     116              :     }
     117              : 
     118            2 :     r = bf_rpack_kv_array(node, "rules", &array);
     119            2 :     if (r)
     120            0 :         return bf_rpack_key_err(r, "bf_chain.rules");
     121           12 :     bf_rpack_array_foreach (array, array_node) {
     122            8 :         _free_bf_rule_ struct bf_rule *rule = NULL;
     123              : 
     124            4 :         r = bf_list_emplace(&rules, bf_rule_new_from_pack, rule, array_node);
     125              :         if (r) {
     126            0 :             return bf_err_r(r, "failed to unpack bf_rule into bf_chain.rules");
     127              :         }
     128              :     }
     129              : 
     130            2 :     r = bf_chain_new(&_chain, name, hook, policy, &sets, &rules);
     131            2 :     if (r)
     132            0 :         return bf_err_r(r, "failed to create bf_chain from pack");
     133              : 
     134            2 :     *chain = TAKE_PTR(_chain);
     135              : 
     136            2 :     return 0;
     137              : }
     138              : 
     139           37 : void bf_chain_free(struct bf_chain **chain)
     140              : {
     141           37 :     bf_assert(chain);
     142              : 
     143           36 :     if (!*chain)
     144              :         return;
     145              : 
     146           15 :     bf_list_clean(&(*chain)->sets);
     147           15 :     bf_list_clean(&(*chain)->rules);
     148           15 :     freep((void *)&(*chain)->name);
     149              :     freep((void *)chain);
     150              : }
     151              : 
     152            4 : int bf_chain_pack(const struct bf_chain *chain, bf_wpack_t *pack)
     153              : {
     154            4 :     bf_assert(chain);
     155            3 :     bf_assert(pack);
     156              : 
     157            2 :     bf_wpack_kv_str(pack, "name", chain->name);
     158            2 :     bf_wpack_kv_enum(pack, "hook", chain->hook);
     159            2 :     bf_wpack_kv_enum(pack, "policy", chain->policy);
     160              : 
     161            2 :     bf_wpack_kv_list(pack, "sets", &chain->sets);
     162            2 :     bf_wpack_kv_list(pack, "rules", &chain->rules);
     163              : 
     164            2 :     return bf_wpack_is_valid(pack) ? 0 : -EINVAL;
     165              : }
     166              : 
     167            0 : void bf_chain_dump(const struct bf_chain *chain, prefix_t *prefix)
     168              : {
     169            0 :     bf_assert(chain && prefix);
     170              : 
     171            0 :     DUMP(prefix, "struct bf_chain at %p", chain);
     172            0 :     bf_dump_prefix_push(prefix);
     173              : 
     174            0 :     DUMP(prefix, "name: %s", chain->name);
     175            0 :     DUMP(prefix, "flags: %02x", chain->flags);
     176            0 :     DUMP(prefix, "hook: %s", bf_hook_to_str(chain->hook));
     177            0 :     DUMP(prefix, "policy: %s", bf_verdict_to_str(chain->policy));
     178              : 
     179            0 :     DUMP(prefix, "sets: bf_list<bf_set>[%lu]", bf_list_size(&chain->sets));
     180            0 :     bf_dump_prefix_push(prefix);
     181            0 :     bf_list_foreach (&chain->sets, set_node) {
     182            0 :         if (bf_list_is_tail(&chain->sets, set_node))
     183            0 :             bf_dump_prefix_last(prefix);
     184              : 
     185            0 :         bf_set_dump(bf_list_node_get_data(set_node), prefix);
     186              :     }
     187            0 :     bf_dump_prefix_pop(prefix);
     188              : 
     189            0 :     DUMP(bf_dump_prefix_last(prefix), "rules: bf_list<bf_rule>[%lu]",
     190              :          bf_list_size(&chain->rules));
     191            0 :     bf_dump_prefix_push(prefix);
     192            0 :     bf_list_foreach (&chain->rules, rule_node) {
     193            0 :         if (bf_list_is_tail(&chain->rules, rule_node))
     194            0 :             bf_dump_prefix_last(prefix);
     195              : 
     196            0 :         bf_rule_dump(bf_list_node_get_data(rule_node), prefix);
     197              :     }
     198            0 :     bf_dump_prefix_pop(prefix);
     199              : 
     200            0 :     bf_dump_prefix_pop(prefix);
     201            0 : }
     202              : 
     203            0 : int bf_chain_add_rule(struct bf_chain *chain, struct bf_rule *rule)
     204              : {
     205            0 :     bf_assert(chain && rule);
     206              : 
     207            0 :     rule->index = bf_list_size(&chain->rules);
     208            0 :     _bf_chain_update_features(chain, rule);
     209              : 
     210            0 :     return bf_list_add_tail(&chain->rules, rule);
     211              : }
     212              : 
     213            0 : struct bf_set *bf_chain_get_set_for_matcher(const struct bf_chain *chain,
     214              :                                             const struct bf_matcher *matcher)
     215              : {
     216            0 :     bf_assert(chain && matcher);
     217              : 
     218              :     uint32_t set_id;
     219              : 
     220            0 :     if (bf_matcher_get_type(matcher) != BF_MATCHER_SET)
     221              :         return NULL;
     222              : 
     223            0 :     set_id = *(uint32_t *)bf_matcher_payload(matcher);
     224              : 
     225            0 :     return bf_list_get_at(&chain->sets, set_id);
     226              : }
     227              : 
     228            8 : bool bf_chain_validate(struct bf_chain *chain)
     229              : {
     230            8 :     bf_assert(chain);
     231              : 
     232            8 :     if (chain->flags & BF_FLAG(BF_CHAIN_SET_MARK) &&
     233            0 :         (chain->hook == BF_HOOK_XDP || chain->hook == BF_HOOK_NF_PRE_ROUTING ||
     234              :          chain->hook == BF_HOOK_NF_POST_ROUTING ||
     235              :          chain->hook == BF_HOOK_NF_FORWARD ||
     236              :          chain->hook == BF_HOOK_NF_LOCAL_IN ||
     237              :          chain->hook == BF_HOOK_NF_LOCAL_OUT)) {
     238            0 :         bf_err("XDP and Netfilter chains can't set packet mark");
     239            0 :         return false;
     240              :     }
     241              : 
     242            8 :     if (chain->flags & BF_FLAG(BF_CHAIN_GET_MARK) &&
     243            0 :         chain->hook == BF_HOOK_XDP) {
     244            0 :         bf_err("XDP chains can't read packet mark");
     245            0 :         return false;
     246              :     }
     247              : 
     248              :     return true;
     249              : }
        

Generated by: LCOV version 2.0-1