LCOV - code coverage report
Current view: top level - core - chain.c (source / functions) Coverage Total Hit
Test: lcov.out Lines: 61.1 % 144 88
Test Date: 2025-02-26 17:59:59 Functions: 66.7 % 6 4

            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 : int bf_chain_new(struct bf_chain **chain, enum bf_hook hook,
      23              :                  enum bf_verdict policy, bf_list *sets, bf_list *rules)
      24              : {
      25            9 :     _cleanup_bf_chain_ struct bf_chain *_chain = NULL;
      26              :     int r;
      27              : 
      28           10 :     bf_assert(chain);
      29           10 :     bf_assert(0 <= policy && policy < _BF_TERMINAL_VERDICT_MAX);
      30              : 
      31            9 :     _chain = malloc(sizeof(*_chain));
      32            9 :     if (!_chain)
      33              :         return -ENOMEM;
      34              : 
      35            9 :     _chain->hook = hook;
      36            9 :     _chain->hook_opts = (struct bf_hook_opts) {};
      37            9 :     _chain->policy = policy;
      38              : 
      39            9 :     _chain->sets = bf_set_list();
      40            9 :     if (sets)
      41            0 :         bf_swap(_chain->sets, *sets);
      42              : 
      43            9 :     _chain->rules = bf_rule_list();
      44            9 :     if (rules) {
      45            0 :         bf_list_foreach (rules, rule_node) {
      46            0 :             r = bf_chain_add_rule(_chain, bf_list_node_get_data(rule_node));
      47            0 :             if (r)
      48              :                 return r;
      49              : 
      50            0 :             bf_list_node_take_data(rule_node);
      51              :         }
      52              :     }
      53              : 
      54            9 :     *chain = TAKE_PTR(_chain);
      55              : 
      56            9 :     return 0;
      57              : }
      58              : 
      59            1 : int bf_chain_new_from_marsh(struct bf_chain **chain,
      60              :                             const struct bf_marsh *marsh)
      61              : {
      62            1 :     _cleanup_bf_chain_ struct bf_chain *_chain = NULL;
      63              :     struct bf_marsh *chain_elem = NULL;
      64              :     struct bf_marsh *list_elem = NULL;
      65              :     enum bf_hook hook;
      66              :     enum bf_verdict policy;
      67              :     int r;
      68              : 
      69            1 :     bf_assert(chain);
      70            1 :     bf_assert(marsh);
      71              : 
      72            1 :     if (!(chain_elem = bf_marsh_next_child(marsh, chain_elem)))
      73              :         return -EINVAL;
      74            1 :     memcpy(&hook, chain_elem->data, sizeof(hook));
      75              : 
      76            1 :     if (!(chain_elem = bf_marsh_next_child(marsh, chain_elem)))
      77              :         return -EINVAL;
      78            1 :     memcpy(&policy, chain_elem->data, sizeof(policy));
      79              : 
      80            1 :     r = bf_chain_new(&_chain, hook, policy, NULL, NULL);
      81            1 :     if (r)
      82              :         return r;
      83              : 
      84              :     // Unmarsh bf_chain.hook_opts
      85            1 :     if (!(chain_elem = bf_marsh_next_child(marsh, chain_elem)))
      86              :         return -EINVAL;
      87              :     {
      88            1 :         if (!(list_elem = bf_marsh_next_child(chain_elem, NULL)))
      89              :             return -EINVAL;
      90            1 :         memcpy(&_chain->hook_opts.used_opts, list_elem->data,
      91              :                sizeof(_chain->hook_opts.used_opts));
      92              : 
      93            1 :         if (!(list_elem = bf_marsh_next_child(chain_elem, list_elem)))
      94              :             return -EINVAL;
      95            1 :         memcpy(&_chain->hook_opts.ifindex, list_elem->data,
      96              :                sizeof(_chain->hook_opts.ifindex));
      97              : 
      98            1 :         if (!(list_elem = bf_marsh_next_child(chain_elem, list_elem)))
      99              :             return -EINVAL;
     100              : 
     101            1 :         if (list_elem->data_len) {
     102            0 :             _chain->hook_opts.cgroup = strdup(list_elem->data);
     103            0 :             if (!_chain->hook_opts.cgroup)
     104              :                 return -ENOMEM;
     105              :         }
     106              : 
     107            1 :         if (!(list_elem = bf_marsh_next_child(chain_elem, list_elem)))
     108              :             return -EINVAL;
     109              : 
     110            1 :         if (list_elem->data_len) {
     111            0 :             _chain->hook_opts.name = strdup(list_elem->data);
     112            0 :             if (!_chain->hook_opts.name)
     113              :                 return -ENOMEM;
     114              :         }
     115              : 
     116            1 :         if (!(list_elem = bf_marsh_next_child(chain_elem, list_elem)))
     117              :             return -EINVAL;
     118            1 :         memcpy(&_chain->hook_opts.attach, list_elem->data,
     119              :                sizeof(_chain->hook_opts.attach));
     120              : 
     121            1 :         if (bf_marsh_next_child(chain_elem, list_elem)) {
     122            0 :             return bf_err_r(-E2BIG,
     123              :                             "too many serialized fields for bf_hook_opts");
     124              :         }
     125              :     }
     126              : 
     127              :     // Unmarsh bf_chain.sets
     128            1 :     if (!(chain_elem = bf_marsh_next_child(marsh, chain_elem)))
     129              :         return -EINVAL;
     130              : 
     131              :     list_elem = NULL;
     132            1 :     while ((list_elem = bf_marsh_next_child(chain_elem, list_elem))) {
     133            0 :         _cleanup_bf_set_ struct bf_set *set = NULL;
     134              : 
     135            0 :         r = bf_set_new_from_marsh(&set, list_elem);
     136            0 :         if (r)
     137              :             return r;
     138              : 
     139            0 :         r = bf_list_add_tail(&_chain->sets, set);
     140            0 :         if (r)
     141              :             return r;
     142              : 
     143            0 :         TAKE_PTR(set);
     144              :     }
     145              : 
     146              :     // Unmarsh bf_chain.rules
     147            1 :     if (!(chain_elem = bf_marsh_next_child(marsh, chain_elem)))
     148              :         return -EINVAL;
     149              :     list_elem = NULL;
     150            1 :     while ((list_elem = bf_marsh_next_child(chain_elem, list_elem))) {
     151            0 :         _cleanup_bf_rule_ struct bf_rule *rule = NULL;
     152              : 
     153            0 :         r = bf_rule_unmarsh(list_elem, &rule);
     154            0 :         if (r)
     155              :             return r;
     156              : 
     157            0 :         r = bf_list_add_tail(&_chain->rules, rule);
     158            0 :         if (r)
     159              :             return r;
     160              : 
     161            0 :         TAKE_PTR(rule);
     162              :     }
     163              : 
     164            1 :     *chain = TAKE_PTR(_chain);
     165              : 
     166            1 :     return 0;
     167              : }
     168              : 
     169           23 : void bf_chain_free(struct bf_chain **chain)
     170              : {
     171           23 :     bf_assert(chain);
     172              : 
     173           23 :     if (!*chain)
     174              :         return;
     175              : 
     176            9 :     bf_list_clean(&(*chain)->sets);
     177            9 :     bf_list_clean(&(*chain)->rules);
     178            9 :     bf_hook_opts_clean(&(*chain)->hook_opts);
     179              :     freep((void *)chain);
     180              : }
     181              : 
     182            1 : int bf_chain_marsh(const struct bf_chain *chain, struct bf_marsh **marsh)
     183              : {
     184            1 :     _cleanup_bf_marsh_ struct bf_marsh *_marsh = NULL;
     185              :     int r;
     186              : 
     187            1 :     bf_assert(chain);
     188            1 :     bf_assert(marsh);
     189              : 
     190            1 :     r = bf_marsh_new(&_marsh, NULL, 0);
     191            1 :     if (r)
     192              :         return r;
     193              : 
     194            1 :     r = bf_marsh_add_child_raw(&_marsh, &chain->hook, sizeof(chain->hook));
     195            1 :     if (r < 0)
     196              :         return r;
     197              : 
     198            1 :     r = bf_marsh_add_child_raw(&_marsh, &chain->policy, sizeof(chain->policy));
     199            1 :     if (r)
     200              :         return r;
     201              : 
     202              :     {
     203              :         // Serialize bf_chain.hook_opts
     204            1 :         _cleanup_bf_marsh_ struct bf_marsh *child = NULL;
     205            1 :         const char *cg_path = chain->hook_opts.cgroup;
     206            1 :         const char *name = chain->hook_opts.name;
     207              : 
     208            1 :         r = bf_marsh_new(&child, NULL, 0);
     209            1 :         if (r < 0)
     210            0 :             return bf_err_r(r, "failed to creaet marsh for bf_chain");
     211              : 
     212            1 :         r = bf_marsh_add_child_raw(&child, &chain->hook_opts.used_opts,
     213              :                                    sizeof(chain->hook_opts.used_opts));
     214            1 :         if (r < 0)
     215              :             return r;
     216              : 
     217            1 :         r = bf_marsh_add_child_raw(&child, &chain->hook_opts.ifindex,
     218              :                                    sizeof(chain->hook_opts.ifindex));
     219            1 :         if (r)
     220              :             return r;
     221              : 
     222              :         /* If a cgroup path is defined, serialize it, including the nul
     223              :          * termination character (to simplify deserializing with strdup()).
     224              :          * Otherwise, create an empty child marsh (NULL data and 0 length). */
     225            1 :         r = bf_marsh_add_child_raw(&child, cg_path,
     226            0 :                                    cg_path ? strlen(cg_path) + 1 : 0);
     227            1 :         if (r)
     228              :             return r;
     229              : 
     230              :         // Similar to cg_path
     231            1 :         r = bf_marsh_add_child_raw(&child, name, name ? strlen(name) + 1 : 0);
     232            1 :         if (r)
     233              :             return r;
     234              : 
     235            1 :         r = bf_marsh_add_child_raw(&child, &chain->hook_opts.attach,
     236              :                                    sizeof(chain->hook_opts.attach));
     237            1 :         if (r < 0)
     238              :             return r;
     239              : 
     240            1 :         r = bf_marsh_add_child_obj(&_marsh, child);
     241            1 :         if (r < 0)
     242              :             return r;
     243              :     }
     244              : 
     245              :     {
     246              :         // Serialize bf_chain.sets
     247            1 :         _cleanup_bf_marsh_ struct bf_marsh *child = NULL;
     248              : 
     249            1 :         r = bf_list_marsh(&chain->sets, &child);
     250            1 :         if (r < 0)
     251              :             return r;
     252              : 
     253            1 :         r = bf_marsh_add_child_obj(&_marsh, child);
     254            1 :         if (r < 0)
     255              :             return r;
     256              :     }
     257              : 
     258              :     {
     259              :         // Serialize bf_chain.rules
     260            1 :         _cleanup_bf_marsh_ struct bf_marsh *child = NULL;
     261              : 
     262            1 :         r = bf_list_marsh(&chain->rules, &child);
     263            1 :         if (r < 0)
     264              :             return r;
     265              : 
     266            1 :         r = bf_marsh_add_child_obj(&_marsh, child);
     267            1 :         if (r < 0)
     268              :             return r;
     269              :     }
     270              : 
     271            1 :     *marsh = TAKE_PTR(_marsh);
     272              : 
     273            1 :     return 0;
     274              : }
     275              : 
     276            0 : void bf_chain_dump(const struct bf_chain *chain, prefix_t *prefix)
     277              : {
     278            0 :     bf_assert(chain);
     279            0 :     bf_assert(prefix);
     280              : 
     281            0 :     DUMP(prefix, "struct bf_chain at %p", chain);
     282              : 
     283            0 :     bf_dump_prefix_push(prefix);
     284            0 :     DUMP(prefix, "hook: %s", bf_hook_to_str(chain->hook));
     285            0 :     DUMP(prefix, "hook_opts: struct bf_hook_opts");
     286            0 :     bf_hook_opts_dump(&chain->hook_opts, prefix, chain->hook);
     287            0 :     DUMP(prefix, "policy: %s", bf_verdict_to_str(chain->policy));
     288              : 
     289            0 :     DUMP(prefix, "sets: bf_list<bf_set>[%lu]", bf_list_size(&chain->sets));
     290            0 :     bf_dump_prefix_push(prefix);
     291            0 :     bf_list_foreach (&chain->sets, set_node) {
     292            0 :         struct bf_set *set = bf_list_node_get_data(set_node);
     293              : 
     294            0 :         if (bf_list_is_tail(&chain->sets, set_node))
     295            0 :             bf_dump_prefix_last(prefix);
     296              : 
     297            0 :         bf_set_dump(set, prefix);
     298              :     }
     299            0 :     bf_dump_prefix_pop(prefix);
     300              : 
     301            0 :     DUMP(bf_dump_prefix_last(prefix), "rules: bf_list<bf_rule>[%lu]",
     302              :          bf_list_size(&chain->rules));
     303            0 :     bf_dump_prefix_push(prefix);
     304            0 :     bf_list_foreach (&chain->rules, rule_node) {
     305            0 :         struct bf_rule *rule = bf_list_node_get_data(rule_node);
     306              : 
     307            0 :         if (bf_list_is_tail(&chain->rules, rule_node))
     308            0 :             bf_dump_prefix_last(prefix);
     309              : 
     310            0 :         bf_rule_dump(rule, prefix);
     311              :     }
     312              : 
     313            0 :     bf_dump_prefix_pop(prefix);
     314            0 :     bf_dump_prefix_pop(prefix);
     315            0 : }
     316              : 
     317            0 : int bf_chain_add_rule(struct bf_chain *chain, struct bf_rule *rule)
     318              : {
     319            0 :     bf_assert(chain);
     320            0 :     bf_assert(rule);
     321              : 
     322            0 :     rule->index = bf_list_size(&chain->rules);
     323              : 
     324            0 :     return bf_list_add_tail(&chain->rules, rule);
     325              : }
        

Generated by: LCOV version 2.0-1