LCOV - code coverage report
Current view: top level - libbpfilter/cgen - program.c (source / functions) Coverage Total Hit
Test: coverage.lcov Lines: 78.7 % 399 314
Test Date: 2026-05-11 12:01:08 Functions: 88.5 % 26 23
Branches: 50.0 % 466 233

             Branch data     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 "cgen/program.h"
       7                 :             : 
       8                 :             : #include <linux/bpf.h>
       9                 :             : #include <linux/bpf_common.h>
      10                 :             : #include <linux/limits.h>
      11                 :             : 
      12                 :             : #include <errno.h>
      13                 :             : #include <fcntl.h>
      14                 :             : #include <limits.h>
      15                 :             : #include <stddef.h>
      16                 :             : #include <stdint.h>
      17                 :             : #include <stdio.h>
      18                 :             : #include <stdlib.h>
      19                 :             : #include <string.h>
      20                 :             : #include <unistd.h>
      21                 :             : 
      22                 :             : #include <bpfilter/bpf.h>
      23                 :             : #include <bpfilter/btf.h>
      24                 :             : #include <bpfilter/chain.h>
      25                 :             : #include <bpfilter/core/list.h>
      26                 :             : #include <bpfilter/counter.h>
      27                 :             : #include <bpfilter/ctx.h>
      28                 :             : #include <bpfilter/dump.h>
      29                 :             : #include <bpfilter/flavor.h>
      30                 :             : #include <bpfilter/helper.h>
      31                 :             : #include <bpfilter/hook.h>
      32                 :             : #include <bpfilter/io.h>
      33                 :             : #include <bpfilter/logger.h>
      34                 :             : #include <bpfilter/matcher.h>
      35                 :             : #include <bpfilter/pack.h>
      36                 :             : #include <bpfilter/rule.h>
      37                 :             : #include <bpfilter/set.h>
      38                 :             : #include <bpfilter/verdict.h>
      39                 :             : 
      40                 :             : #include "cgen/cgroup_skb.h"
      41                 :             : #include "cgen/cgroup_sock_addr.h"
      42                 :             : #include "cgen/dump.h"
      43                 :             : #include "cgen/fixup.h"
      44                 :             : #include "cgen/handle.h"
      45                 :             : #include "cgen/jmp.h"
      46                 :             : #include "cgen/nf.h"
      47                 :             : #include "cgen/printer.h"
      48                 :             : #include "cgen/prog/link.h"
      49                 :             : #include "cgen/prog/map.h"
      50                 :             : #include "cgen/stub.h"
      51                 :             : #include "cgen/tc.h"
      52                 :             : #include "cgen/xdp.h"
      53                 :             : #include "filter.h"
      54                 :             : 
      55                 :             : #define _BF_LOG_BUF_SIZE                                                       \
      56                 :             :     (UINT32_MAX >> 8) /* verifier maximum in kernels <= 5.1 */
      57                 :             : #define _BF_LOG_MAP_N_ENTRIES 1000
      58                 :             : #define _BF_LOG_MAP_SIZE                                                       \
      59                 :             :     _bf_round_next_power_of_2(sizeof(struct bf_log) * _BF_LOG_MAP_N_ENTRIES)
      60                 :             : #define _BF_SET_MAP_PREFIX "bf_set_"
      61                 :             : #define _BF_COUNTER_MAP_NAME "bf_cmap"
      62                 :             : #define _BF_PRINTER_MAP_NAME "bf_pmap"
      63                 :             : #define _BF_LOG_MAP_NAME "bf_lmap"
      64                 :             : 
      65                 :             : static inline size_t _bf_round_next_power_of_2(size_t value)
      66                 :             : {
      67                 :             :     if (value == 0)
      68                 :             :         return 1;
      69                 :             : 
      70                 :             :     value--;
      71                 :             :     value |= value >> 1;
      72                 :             :     value |= value >> 2;
      73                 :             :     value |= value >> 4;
      74                 :             :     value |= value >> 8;
      75                 :             :     value |= value >> 16;
      76                 :             : #if SIZE_MAX > 0xFFFFFFFFU
      77                 :             :     value |= value >> 32;
      78                 :             : #endif
      79                 :             : 
      80                 :             :     return ++value;
      81                 :             : }
      82                 :             : 
      83                 :             : /**
      84                 :             :  * @brief Sets sharing the same key format, collapsed to a single BPF map.
      85                 :             :  *
      86                 :             :  * For hash-keyed sets, one `bf_set_group` exists for every unique key
      87                 :             :  * format among a chain's non-empty sets. The sets list preserves insertion
      88                 :             :  * order; a set's position is its bit index within the group's bitmask
      89                 :             :  * value.
      90                 :             :  *
      91                 :             :  * LPM trie sets are never grouped together: each non-empty trie set gets
      92                 :             :  * its own group of size 1. See `_bf_program_build_set_groups()` for the
      93                 :             :  * rationale.
      94                 :             :  */
      95                 :             : struct bf_set_group
      96                 :             : {
      97                 :             :     /** Non-empty sets that map to the same BPF map. For hash-keyed groups,
      98                 :             :      * all sets share the same key format; LPM trie groups always hold a
      99                 :             :      * single set. Non-owning pointers into the chain's `bf_set` list.
     100                 :             :      * Never empty. */
     101                 :             :     bf_list sets;
     102                 :             : 
     103                 :             :     /** Backing BPF map. Populated during `bf_program_load()`; the map is
     104                 :             :      * owned by `bf_program->handle->sets`. */
     105                 :             :     struct bf_map *map;
     106                 :             : };
     107                 :             : 
     108                 :             : #define _free_bf_set_group_ __attribute__((__cleanup__(_bf_set_group_free)))
     109                 :             : 
     110                 :         903 : static void _bf_set_group_free(struct bf_set_group **group)
     111                 :             : {
     112                 :             :     assert(group);
     113                 :             : 
     114         [ +  + ]:         903 :     if (!*group)
     115                 :             :         return;
     116                 :             : 
     117                 :         301 :     bf_list_clean(&(*group)->sets);
     118                 :             :     freep((void *)group);
     119                 :             : }
     120                 :             : 
     121                 :         301 : static int _bf_set_group_new(struct bf_set_group **group)
     122                 :             : {
     123                 :         301 :     _free_bf_set_group_ struct bf_set_group *_group = NULL;
     124                 :             : 
     125                 :             :     assert(group);
     126                 :             : 
     127                 :         301 :     _group = calloc(1, sizeof(*_group));
     128         [ +  - ]:         301 :     if (!_group)
     129                 :             :         return -ENOMEM;
     130                 :             : 
     131                 :             :     /* The list holds non-owning const struct bf_set * pointers; no free
     132                 :             :      * callback. Groups are temporary (not serialized), so no pack callback
     133                 :             :      * either. */
     134                 :         301 :     _group->sets = bf_list_default(NULL, NULL);
     135                 :             : 
     136                 :         301 :     *group = TAKE_PTR(_group);
     137                 :             : 
     138                 :         301 :     return 0;
     139                 :             : }
     140                 :             : 
     141                 :             : static struct bf_set_group *
     142                 :         275 : _bf_program_find_set_group(const struct bf_program *program,
     143                 :             :                            const struct bf_set *set)
     144                 :             : {
     145                 :             :     assert(program);
     146                 :             : 
     147         [ -  + ]:         275 :     if (!set)
     148                 :             :         return NULL;
     149                 :             : 
     150   [ +  -  +  -  :         752 :     bf_list_foreach (&program->set_groups, group_node) {
                   -  + ]
     151                 :             :         struct bf_set_group *group = bf_list_node_get_data(group_node);
     152   [ +  -  +  +  :         943 :         bf_list_foreach (&group->sets, set_node) {
                   +  + ]
     153         [ +  + ]:         421 :             if (bf_list_node_get_data(set_node) == set)
     154                 :             :                 return group;
     155                 :             :         }
     156                 :             :     }
     157                 :             : 
     158                 :             :     return NULL;
     159                 :             : }
     160                 :             : 
     161                 :        1310 : static int _bf_program_build_set_groups(struct bf_program *program)
     162                 :             : {
     163                 :             :     assert(program);
     164                 :             : 
     165                 :        1310 :     bf_list_clean(&program->set_groups);
     166                 :        1310 :     program->set_groups = bf_list_default(_bf_set_group_free, NULL);
     167                 :             : 
     168   [ +  +  +  +  :        3260 :     bf_list_foreach (&program->runtime.chain->sets, set_node) {
                   +  + ]
     169                 :             :         struct bf_set *set = bf_list_node_get_data(set_node);
     170                 :             :         struct bf_set_group *match = NULL;
     171                 :             :         int r;
     172                 :             : 
     173         [ +  + ]:         320 :         if (bf_hashset_is_empty(&set->elems))
     174                 :           4 :             continue;
     175                 :             : 
     176                 :             :         /* LPM trie sets are not grouped: BPF LPM trie lookup always
     177                 :             :          * returns the longest-prefix match, so the read-modify-write
     178                 :             :          * step in _bf_program_load_sets_maps() can't preserve the
     179                 :             :          * per-set bitmask when prefixes overlap. */
     180         [ +  + ]:         316 :         if (!set->use_trie) {
     181   [ +  +  +  +  :         706 :             bf_list_foreach (&program->set_groups, group_node) {
                   +  + ]
     182                 :             :                 struct bf_set_group *group = bf_list_node_get_data(group_node);
     183                 :             :                 const struct bf_set *head =
     184                 :             :                     bf_list_node_get_data(bf_list_get_head(&group->sets));
     185                 :             : 
     186         [ +  + ]:         116 :                 if (bf_set_same_key(set, head)) {
     187                 :             :                     match = group;
     188                 :             :                     break;
     189                 :             :                 }
     190                 :             :             }
     191                 :             :         }
     192                 :             : 
     193         [ +  + ]:         252 :         if (match) {
     194                 :          15 :             r = bf_list_add_tail(&match->sets, set);
     195         [ -  + ]:          15 :             if (r)
     196         [ #  # ]:           0 :                 return bf_err_r(r, "failed to add set to existing group");
     197                 :             :         } else {
     198                 :         301 :             _free_bf_set_group_ struct bf_set_group *new_group = NULL;
     199                 :             : 
     200                 :         301 :             r = _bf_set_group_new(&new_group);
     201         [ -  + ]:         301 :             if (r)
     202         [ #  # ]:           0 :                 return bf_err_r(r, "failed to allocate set group");
     203                 :             : 
     204                 :         301 :             r = bf_list_add_tail(&new_group->sets, set);
     205         [ -  + ]:         301 :             if (r)
     206         [ #  # ]:           0 :                 return bf_err_r(r, "failed to seed set group");
     207                 :             : 
     208                 :         301 :             r = bf_list_push(&program->set_groups, (void **)&new_group);
     209         [ -  + ]:         301 :             if (r)
     210         [ #  # ]:           0 :                 return bf_err_r(r, "failed to register set group");
     211                 :             :         }
     212                 :             :     }
     213                 :             : 
     214                 :             :     return 0;
     215                 :             : }
     216                 :             : 
     217                 :         275 : int bf_program_set_bit_index(const struct bf_program *program,
     218                 :             :                              const struct bf_set *set, size_t *bit_index)
     219                 :             : {
     220                 :             :     assert(program);
     221                 :             :     assert(set);
     222                 :             :     assert(bit_index);
     223                 :             : 
     224   [ +  -  +  -  :         752 :     bf_list_foreach (&program->set_groups, group_node) {
                   +  - ]
     225                 :             :         struct bf_set_group *group = bf_list_node_get_data(group_node);
     226                 :             :         size_t i = 0;
     227                 :             : 
     228   [ +  -  +  + ]:         943 :         bf_list_foreach (&group->sets, set_node) {
     229         [ +  + ]:         421 :             if (bf_list_node_get_data(set_node) == set) {
     230                 :         275 :                 *bit_index = i;
     231                 :         275 :                 return 0;
     232                 :             :             }
     233         [ +  + ]:         146 :             ++i;
     234                 :             :         }
     235                 :             :     }
     236                 :             : 
     237                 :             :     return -ENOENT;
     238                 :             : }
     239                 :             : 
     240                 :             : static const struct bf_flavor_ops *bf_flavor_ops_get(enum bf_flavor flavor)
     241                 :             : {
     242                 :             :     static const struct bf_flavor_ops *flavor_ops[] = {
     243                 :             :         [BF_FLAVOR_TC] = &bf_flavor_ops_tc,
     244                 :             :         [BF_FLAVOR_NF] = &bf_flavor_ops_nf,
     245                 :             :         [BF_FLAVOR_XDP] = &bf_flavor_ops_xdp,
     246                 :             :         [BF_FLAVOR_CGROUP_SKB] = &bf_flavor_ops_cgroup_skb,
     247                 :             :         [BF_FLAVOR_CGROUP_SOCK_ADDR] = &bf_flavor_ops_cgroup_sock_addr,
     248                 :             :     };
     249                 :             : 
     250                 :             :     static_assert_enum_mapping(flavor_ops, _BF_FLAVOR_MAX);
     251                 :             : 
     252                 :        1310 :     return flavor_ops[flavor];
     253                 :             : }
     254                 :             : 
     255                 :        1310 : int bf_program_new(struct bf_program **program, const struct bf_chain *chain,
     256                 :             :                    struct bf_handle *handle)
     257                 :             : {
     258                 :        1310 :     _free_bf_program_ struct bf_program *_program = NULL;
     259                 :             :     int r;
     260                 :             : 
     261                 :             :     assert(program);
     262                 :             :     assert(chain);
     263                 :             :     assert(handle);
     264                 :             : 
     265                 :        1310 :     _program = calloc(1, sizeof(*_program));
     266         [ +  - ]:        1310 :     if (!_program)
     267                 :             :         return -ENOMEM;
     268                 :             : 
     269                 :        1310 :     _program->flavor = bf_hook_to_flavor(chain->hook);
     270                 :        1310 :     _program->runtime.ops = bf_flavor_ops_get(_program->flavor);
     271                 :        1310 :     _program->runtime.chain = chain;
     272                 :        1310 :     _program->img = bf_vector_default(sizeof(struct bpf_insn));
     273                 :        1310 :     _program->fixups = bf_list_default(bf_fixup_free, NULL);
     274                 :        1310 :     _program->set_groups = bf_list_default(_bf_set_group_free, NULL);
     275                 :        1310 :     _program->handle = handle;
     276                 :             : 
     277                 :        1310 :     r = bf_vector_reserve(&_program->img, 512);
     278         [ +  - ]:        1310 :     if (r)
     279                 :             :         return r;
     280                 :             : 
     281                 :        1310 :     r = bf_printer_new(&_program->printer);
     282         [ +  - ]:        1310 :     if (r)
     283                 :             :         return r;
     284                 :             : 
     285                 :        1310 :     *program = TAKE_PTR(_program);
     286                 :             : 
     287                 :        1310 :     return 0;
     288                 :             : }
     289                 :             : 
     290                 :        2620 : void bf_program_free(struct bf_program **program)
     291                 :             : {
     292         [ +  + ]:        2620 :     if (!*program)
     293                 :             :         return;
     294                 :             : 
     295                 :        1310 :     bf_list_clean(&(*program)->fixups);
     296                 :        1310 :     bf_list_clean(&(*program)->set_groups);
     297                 :        1310 :     bf_vector_clean(&(*program)->img);
     298                 :             : 
     299                 :        1310 :     bf_printer_free(&(*program)->printer);
     300                 :             : 
     301                 :        1310 :     free(*program);
     302                 :        1310 :     *program = NULL;
     303                 :             : }
     304                 :             : 
     305                 :           0 : void bf_program_dump(const struct bf_program *program, prefix_t *prefix)
     306                 :             : {
     307                 :             :     assert(program);
     308                 :             :     assert(prefix);
     309                 :             : 
     310         [ #  # ]:           0 :     DUMP(prefix, "struct bf_program at %p", program);
     311                 :             : 
     312                 :           0 :     bf_dump_prefix_push(prefix);
     313                 :             : 
     314         [ #  # ]:           0 :     DUMP(prefix, "handle: struct bf_handle *");
     315                 :           0 :     bf_dump_prefix_push(prefix);
     316                 :           0 :     bf_handle_dump(program->handle, bf_dump_prefix_last(prefix));
     317                 :           0 :     bf_dump_prefix_pop(prefix);
     318                 :             : 
     319         [ #  # ]:           0 :     DUMP(prefix, "printer: struct bf_printer *");
     320                 :           0 :     bf_dump_prefix_push(prefix);
     321                 :           0 :     bf_printer_dump(program->printer, prefix);
     322                 :           0 :     bf_dump_prefix_pop(prefix);
     323                 :             : 
     324         [ #  # ]:           0 :     DUMP(prefix, "img: %p", program->img.data);
     325         [ #  # ]:           0 :     DUMP(prefix, "img.size: %lu", program->img.size);
     326         [ #  # ]:           0 :     DUMP(prefix, "img.cap: %lu", program->img.cap);
     327                 :             : 
     328         [ #  # ]:           0 :     DUMP(prefix, "fixups: bf_list<struct bf_fixup>[%lu]",
     329                 :             :          bf_list_size(&program->fixups));
     330                 :           0 :     bf_dump_prefix_push(prefix);
     331   [ #  #  #  #  :           0 :     bf_list_foreach (&program->fixups, fixup_node) {
                   #  # ]
     332                 :             :         struct bf_fixup *fixup = bf_list_node_get_data(fixup_node);
     333                 :             : 
     334         [ #  # ]:           0 :         if (bf_list_is_tail(&program->fixups, fixup_node))
     335                 :           0 :             bf_dump_prefix_last(prefix);
     336                 :             : 
     337                 :           0 :         bf_fixup_dump(fixup, prefix);
     338                 :             :     }
     339                 :           0 :     bf_dump_prefix_pop(prefix);
     340                 :             : 
     341         [ #  # ]:           0 :     DUMP(prefix, "groups: bf_list<struct bf_set_group>[%lu]",
     342                 :             :          bf_list_size(&program->set_groups));
     343                 :           0 :     bf_dump_prefix_push(prefix);
     344   [ #  #  #  #  :           0 :     bf_list_foreach (&program->set_groups, group_node) {
                   #  # ]
     345                 :             :         const struct bf_set_group *group = bf_list_node_get_data(group_node);
     346                 :             :         size_t i = 0;
     347                 :             : 
     348         [ #  # ]:           0 :         if (bf_list_is_tail(&program->set_groups, group_node))
     349                 :           0 :             bf_dump_prefix_last(prefix);
     350                 :             : 
     351         [ #  # ]:           0 :         DUMP(prefix, "struct bf_set_group at %p (%lu set(s), map=%p)", group,
     352                 :             :              bf_list_size(&group->sets), (void *)group->map);
     353                 :           0 :         bf_dump_prefix_push(prefix);
     354   [ #  #  #  # ]:           0 :         bf_list_foreach (&group->sets, set_node) {
     355                 :             :             const struct bf_set *set = bf_list_node_get_data(set_node);
     356                 :             : 
     357         [ #  # ]:           0 :             if (bf_list_is_tail(&group->sets, set_node))
     358                 :           0 :                 bf_dump_prefix_last(prefix);
     359   [ #  #  #  # ]:           0 :             DUMP(prefix, "bit %lu: bf_set '%s' (%lu element(s))", i,
     360                 :             :                  set->name ?: "<anonymous>", bf_hashset_size(&set->elems));
     361         [ #  # ]:           0 :             ++i;
     362                 :             :         }
     363                 :           0 :         bf_dump_prefix_pop(prefix);
     364                 :             :     }
     365                 :           0 :     bf_dump_prefix_pop(prefix);
     366                 :             : 
     367         [ #  # ]:           0 :     DUMP(bf_dump_prefix_last(prefix), "runtime: <anonymous>");
     368                 :           0 :     bf_dump_prefix_push(prefix);
     369         [ #  # ]:           0 :     DUMP(bf_dump_prefix_last(prefix), "ops: %p", program->runtime.ops);
     370                 :           0 :     bf_dump_prefix_pop(prefix);
     371                 :             : 
     372                 :           0 :     bf_dump_prefix_pop(prefix);
     373                 :           0 : }
     374                 :             : 
     375                 :       21613 : static void _bf_program_fixup_insn(struct bpf_insn *insn,
     376                 :             :                                    enum bf_fixup_insn type, int32_t value)
     377                 :             : {
     378      [ +  +  - ]:       21613 :     switch (type) {
     379                 :        4672 :     case BF_FIXUP_INSN_OFF:
     380                 :             :         assert(!insn->off);
     381                 :             :         assert(value < SHRT_MAX);
     382                 :        4672 :         insn->off = (int16_t)value;
     383                 :        4672 :         break;
     384                 :       16941 :     case BF_FIXUP_INSN_IMM:
     385                 :             :         assert(!insn->imm);
     386                 :       16941 :         insn->imm = value;
     387                 :       16941 :         break;
     388                 :           0 :     default:
     389         [ #  # ]:           0 :         bf_abort(
     390                 :             :             "unsupported fixup instruction type, this should not happen: %d",
     391                 :             :             type);
     392                 :             :         break;
     393                 :             :     }
     394                 :       21613 : }
     395                 :             : 
     396                 :        6821 : static int _bf_program_fixup(struct bf_program *program,
     397                 :             :                              enum bf_fixup_type type)
     398                 :             : {
     399                 :             :     assert(program);
     400                 :             :     assert(type >= 0 && type < _BF_FIXUP_TYPE_MAX);
     401                 :             : 
     402   [ +  -  +  +  :      138834 :     bf_list_foreach (&program->fixups, fixup_node) {
                   +  + ]
     403                 :             :         enum bf_fixup_insn insn_type = _BF_FIXUP_INSN_MAX;
     404                 :             :         int32_t value;
     405                 :             :         size_t offset;
     406                 :             :         struct bf_fixup *fixup = bf_list_node_get_data(fixup_node);
     407                 :             :         struct bpf_insn *insn;
     408                 :             : 
     409         [ +  + ]:       62596 :         if (type != fixup->type)
     410                 :       40983 :             continue;
     411                 :             : 
     412                 :       21613 :         insn = bf_vector_get(&program->img, fixup->insn);
     413         [ -  + ]:       21613 :         if (!insn) {
     414         [ #  # ]:           0 :             return bf_err_r(-EINVAL,
     415                 :             :                             "fixup references invalid instruction index %lu",
     416                 :             :                             fixup->insn);
     417                 :             :         }
     418                 :             : 
     419   [ +  +  +  +  :       21613 :         switch (type) {
                +  +  - ]
     420                 :        4672 :         case BF_FIXUP_TYPE_JMP_NEXT_RULE:
     421                 :             :             insn_type = BF_FIXUP_INSN_OFF;
     422                 :        4672 :             value = (int)(program->img.size - fixup->insn - 1U);
     423                 :        4672 :             break;
     424                 :        6994 :         case BF_FIXUP_TYPE_COUNTERS_MAP_FD:
     425                 :             :             insn_type = BF_FIXUP_INSN_IMM;
     426                 :        6994 :             value = program->handle->cmap->fd;
     427                 :        6994 :             break;
     428                 :        1337 :         case BF_FIXUP_TYPE_PRINTER_MAP_FD:
     429                 :             :             insn_type = BF_FIXUP_INSN_IMM;
     430                 :        1337 :             value = program->handle->pmap->fd;
     431                 :        1337 :             break;
     432                 :          30 :         case BF_FIXUP_TYPE_LOG_MAP_FD:
     433                 :             :             insn_type = BF_FIXUP_INSN_IMM;
     434                 :          30 :             value = program->handle->lmap->fd;
     435                 :          30 :             break;
     436                 :         275 :         case BF_FIXUP_TYPE_SET_MAP_FD: {
     437                 :             :             const struct bf_set_group *group =
     438                 :         275 :                 _bf_program_find_set_group(program, fixup->attr.set_ptr);
     439   [ +  -  -  + ]:         275 :             if (!group || !group->map) {
     440   [ #  #  #  #  :           0 :                 return bf_err_r(
                   #  # ]
     441                 :             :                     -ENOENT, "set map fixup: set '%s' not in any loaded group",
     442                 :             :                     fixup->attr.set_ptr ?
     443                 :             :                         (fixup->attr.set_ptr->name ?: "<anonymous>") :
     444                 :             :                         "(null)");
     445                 :             :             }
     446                 :             :             insn_type = BF_FIXUP_INSN_IMM;
     447                 :         275 :             value = group->map->fd;
     448                 :         275 :             break;
     449                 :             :         }
     450                 :        8305 :         case BF_FIXUP_ELFSTUB_CALL:
     451                 :             :             insn_type = BF_FIXUP_INSN_IMM;
     452                 :        8305 :             offset = program->elfstubs_location[fixup->attr.elfstub_id] -
     453                 :        8305 :                      fixup->insn - 1;
     454         [ -  + ]:        8305 :             if (offset >= INT_MAX)
     455         [ #  # ]:           0 :                 return bf_err_r(-EINVAL, "invalid ELF stub call offset");
     456                 :        8305 :             value = (int32_t)offset;
     457                 :        8305 :             break;
     458                 :           0 :         default:
     459         [ #  # ]:           0 :             bf_abort("unsupported fixup type, this should not happen: %d",
     460                 :             :                      type);
     461                 :             :             break;
     462                 :             :         }
     463                 :             : 
     464                 :       21613 :         _bf_program_fixup_insn(insn, insn_type, value);
     465                 :       21613 :         bf_list_delete(&program->fixups, fixup_node);
     466                 :             :     }
     467                 :             : 
     468                 :             :     return 0;
     469                 :             : }
     470                 :             : 
     471                 :        2767 : static int _bf_program_check_proto(struct bf_program *program,
     472                 :             :                                    enum bf_matcher_type type,
     473                 :             :                                    uint32_t *checked_layers)
     474                 :             : {
     475                 :             :     const struct bf_matcher_meta *meta;
     476                 :             : 
     477                 :             :     assert(program);
     478                 :             :     assert(checked_layers);
     479                 :             : 
     480                 :        2767 :     meta = bf_matcher_get_meta(type);
     481         [ -  + ]:        2767 :     if (!meta)
     482         [ #  # ]:           0 :         return bf_err_r(-EINVAL, "missing meta for matcher type %d", type);
     483                 :             : 
     484         [ +  + ]:        2767 :     if (*checked_layers & BF_FLAG(meta->layer))
     485                 :             :         return 0;
     486                 :             : 
     487                 :        1875 :     if (meta->layer == BF_MATCHER_LAYER_2 ||
     488         [ +  + ]:        1875 :         meta->layer == BF_MATCHER_LAYER_3 ||
     489                 :             :         meta->layer == BF_MATCHER_LAYER_4) {
     490                 :        1228 :         int r = bf_stub_rule_check_protocol(program, meta);
     491         [ +  - ]:        1228 :         if (r)
     492                 :             :             return r;
     493                 :        1228 :         *checked_layers |= BF_FLAG(meta->layer);
     494                 :             :     }
     495                 :             : 
     496                 :             :     return 0;
     497                 :             : }
     498                 :             : 
     499                 :        1579 : static int _bf_program_generate_rule(struct bf_program *program,
     500                 :             :                                      struct bf_rule *rule)
     501                 :             : {
     502                 :        1579 :     uint32_t checked_layers = 0;
     503                 :             :     int ret_code;
     504                 :             :     int r = 0;
     505                 :             : 
     506                 :             :     assert(program);
     507                 :             :     assert(rule);
     508                 :             :     assert(program->runtime.ops->gen_inline_matcher);
     509                 :             :     assert(program->runtime.ops->gen_inline_log);
     510                 :             : 
     511         [ +  + ]:        1579 :     if (rule->disabled)
     512                 :             :         return 0;
     513                 :             : 
     514   [ +  -  +  +  :        8648 :     bf_list_foreach (&rule->matchers, matcher_node) {
                   +  + ]
     515                 :             :         struct bf_matcher *matcher = bf_list_node_get_data(matcher_node);
     516                 :             : 
     517         [ +  + ]:        2758 :         if (bf_matcher_get_type(matcher) == BF_MATCHER_SET) {
     518                 :             :             const struct bf_set *set =
     519                 :         275 :                 bf_chain_get_set_for_matcher(program->runtime.chain, matcher);
     520                 :             : 
     521         [ -  + ]:         275 :             if (!set) {
     522         [ #  # ]:           0 :                 return bf_err_r(-ENOENT, "rule %u references non-existent set",
     523                 :             :                                 rule->index);
     524                 :             :             }
     525                 :             : 
     526   [ +  +  +  - ]:         559 :             for (size_t i = 0; i < set->n_comps && !r; ++i) {
     527                 :         284 :                 r = _bf_program_check_proto(program, set->key[i],
     528                 :             :                                             &checked_layers);
     529                 :             :             }
     530                 :             :         } else {
     531                 :        2483 :             r = _bf_program_check_proto(program, bf_matcher_get_type(matcher),
     532                 :             :                                         &checked_layers);
     533                 :             :         }
     534                 :             : 
     535         [ +  - ]:        2758 :         if (r)
     536                 :             :             return r;
     537                 :             :     }
     538                 :             : 
     539   [ +  -  +  +  :        8648 :     bf_list_foreach (&rule->matchers, matcher_node) {
                   +  + ]
     540                 :             :         struct bf_matcher *matcher = bf_list_node_get_data(matcher_node);
     541                 :             : 
     542                 :        2758 :         r = program->runtime.ops->gen_inline_matcher(program, matcher);
     543         [ +  - ]:        2758 :         if (r)
     544                 :             :             return r;
     545                 :             :     }
     546                 :             : 
     547         [ +  + ]:        1566 :     if (bf_rule_mark_is_set(rule)) {
     548         [ -  + ]:          10 :         if (!program->runtime.ops->gen_inline_set_mark) {
     549         [ #  # ]:           0 :             return bf_err_r(-ENOTSUP, "set mark is not supported by %s",
     550                 :             :                             program->runtime.chain->name);
     551                 :             :         }
     552                 :             : 
     553                 :          10 :         r = program->runtime.ops->gen_inline_set_mark(program,
     554                 :             :                                                       bf_rule_mark_get(rule));
     555         [ -  + ]:          10 :         if (r) {
     556         [ #  # ]:           0 :             return bf_err_r(r,
     557                 :             :                             "failed to generate bytecode to set mark for '%s'",
     558                 :             :                             program->runtime.chain->name);
     559                 :             :         }
     560                 :             :     }
     561                 :             : 
     562         [ +  + ]:        1566 :     if (rule->log) {
     563                 :          42 :         r = program->runtime.ops->gen_inline_log(program, rule);
     564         [ +  - ]:          42 :         if (r)
     565                 :             :             return r;
     566                 :             :     }
     567                 :             : 
     568         [ +  + ]:        1566 :     if (rule->has_counters) {
     569         [ +  - ]:        1510 :         EMIT(program, BPF_MOV64_REG(BPF_REG_1, BPF_REG_10));
     570         [ +  - ]:        1510 :         EMIT(program, BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, BF_PROG_CTX_OFF(arg)));
     571   [ +  -  +  - ]:        3020 :         EMIT_LOAD_COUNTERS_FD_FIXUP(program, BPF_REG_2);
     572         [ +  - ]:        1510 :         EMIT(program, BPF_MOV32_IMM(BPF_REG_3, rule->index));
     573         [ +  - ]:        1510 :         EMIT_FIXUP_ELFSTUB(program, BF_ELFSTUB_UPDATE_COUNTERS);
     574                 :             :     }
     575                 :             : 
     576   [ +  +  -  + ]:        1566 :     switch (rule->verdict) {
     577                 :        1514 :     case BF_VERDICT_ACCEPT:
     578                 :             :     case BF_VERDICT_DROP:
     579                 :             :     case BF_VERDICT_NEXT:
     580                 :        1514 :         r = program->runtime.ops->get_verdict(rule->verdict, &ret_code);
     581         [ +  - ]:        1514 :         if (r)
     582                 :             :             return r;
     583         [ +  - ]:        1514 :         EMIT(program, BPF_MOV64_IMM(BPF_REG_0, ret_code));
     584         [ +  - ]:        1514 :         EMIT(program, BPF_EXIT_INSN());
     585                 :             :         break;
     586                 :          12 :     case BF_VERDICT_REDIRECT:
     587         [ +  + ]:          12 :         if (!program->runtime.ops->gen_inline_redirect) {
     588         [ +  - ]:           2 :             return bf_err_r(-ENOTSUP, "redirect is not supported by %s hook",
     589                 :             :                             bf_hook_to_str(program->runtime.chain->hook));
     590                 :             :         }
     591                 :          10 :         r = program->runtime.ops->gen_inline_redirect(
     592                 :             :             program, rule->redirect_ifindex, rule->redirect_dir);
     593         [ +  + ]:          10 :         if (r)
     594                 :             :             return r;
     595                 :             :         break;
     596                 :             :     case BF_VERDICT_CONTINUE:
     597                 :             :         // Fall through to next rule or default chain policy.
     598                 :             :         break;
     599                 :           0 :     default:
     600         [ #  # ]:           0 :         bf_abort("unsupported verdict, this should not happen: %d",
     601                 :             :                  rule->verdict);
     602                 :             :         break;
     603                 :             :     }
     604                 :             : 
     605                 :        1563 :     r = _bf_program_fixup(program, BF_FIXUP_TYPE_JMP_NEXT_RULE);
     606         [ +  - ]:        1563 :     if (r)
     607         [ #  # ]:           0 :         return bf_err_r(r, "failed to generate next rule fixups");
     608                 :             : 
     609                 :             :     return 0;
     610                 :             : }
     611                 :             : 
     612                 :        1307 : static int _bf_program_generate_elfstubs(struct bf_program *program)
     613                 :             : {
     614                 :             :     const struct bf_elfstub *elfstub;
     615                 :             :     size_t start_at;
     616                 :             :     int r;
     617                 :             : 
     618                 :             :     assert(program);
     619                 :             : 
     620   [ +  -  +  +  :       36488 :     bf_list_foreach (&program->fixups, fixup_node) {
                   +  + ]
     621                 :             :         struct bf_fixup *fixup = bf_list_node_get_data(fixup_node);
     622                 :       16937 :         size_t off = program->img.size;
     623                 :             : 
     624         [ +  + ]:       16937 :         if (fixup->type != BF_FIXUP_ELFSTUB_CALL)
     625                 :        8632 :             continue;
     626                 :             : 
     627                 :             :         // Only generate each ELF stub once
     628         [ +  + ]:        8305 :         if (program->elfstubs_location[fixup->attr.elfstub_id])
     629                 :        5699 :             continue;
     630                 :             : 
     631         [ -  + ]:        2606 :         bf_dbg("generate ELF stub for ID %d", fixup->attr.elfstub_id);
     632                 :             : 
     633                 :        2606 :         elfstub = bf_ctx_get_elfstub(fixup->attr.elfstub_id);
     634         [ -  + ]:        2606 :         if (!elfstub) {
     635         [ #  # ]:           0 :             return bf_err_r(-ENOENT, "no ELF stub found for ID %d",
     636                 :             :                             fixup->attr.elfstub_id);
     637                 :             :         }
     638                 :             : 
     639                 :        2606 :         start_at = program->img.size;
     640                 :             : 
     641         [ +  + ]:       98598 :         for (size_t i = 0; i < elfstub->ninsns; ++i) {
     642                 :       95992 :             r = bf_program_emit(program, elfstub->insns[i]);
     643         [ -  + ]:       95992 :             if (r)
     644         [ #  # ]:           0 :                 return bf_err_r(r, "failed to insert ELF stub instruction");
     645                 :             :         }
     646                 :             : 
     647   [ +  +  -  +  :        7886 :         bf_list_foreach (&elfstub->strs, pstr_node) {
                   +  + ]
     648                 :        1337 :             _free_bf_fixup_ struct bf_fixup *fixup = NULL;
     649                 :             :             struct bf_printk_str *pstr = bf_list_node_get_data(pstr_node);
     650                 :        1337 :             size_t insn_idx = start_at + pstr->insn_idx;
     651                 :             :             const struct bf_printer_msg *msg =
     652                 :        1337 :                 bf_printer_add_msg(program->printer, pstr->str);
     653                 :        1337 :             struct bpf_insn ld_insn[2] = {
     654                 :             :                 BPF_LD_MAP_FD(BPF_REG_1, 0),
     655                 :             :             };
     656                 :             : 
     657                 :        1337 :             ld_insn[0].src_reg = BPF_PSEUDO_MAP_VALUE;
     658                 :        1337 :             ld_insn[1].imm = (int)bf_printer_msg_offset(msg);
     659                 :             : 
     660                 :        1337 :             r = bf_vector_set(&program->img, insn_idx, &ld_insn[0]);
     661         [ -  + ]:        1337 :             if (r) {
     662         [ #  # ]:           0 :                 return bf_err_r(
     663                 :             :                     r, "failed to set ELF stub instruction at index %lu",
     664                 :             :                     insn_idx);
     665                 :             :             }
     666                 :        1337 :             r = bf_vector_set(&program->img, insn_idx + 1, &ld_insn[1]);
     667         [ -  + ]:        1337 :             if (r) {
     668         [ #  # ]:           0 :                 return bf_err_r(
     669                 :             :                     r, "failed to set ELF stub instruction at index %lu",
     670                 :             :                     insn_idx + 1);
     671                 :             :             }
     672                 :             : 
     673                 :        1337 :             r = bf_fixup_new(&fixup, BF_FIXUP_TYPE_PRINTER_MAP_FD, insn_idx,
     674                 :             :                              NULL);
     675         [ +  - ]:        1337 :             if (r)
     676                 :             :                 return r;
     677                 :             : 
     678                 :        1337 :             r = bf_list_add_tail(&program->fixups, fixup);
     679         [ +  - ]:        1337 :             if (r)
     680                 :             :                 return r;
     681                 :             : 
     682                 :        1337 :             TAKE_PTR(fixup);
     683                 :             :         }
     684                 :             : 
     685                 :        2606 :         program->elfstubs_location[fixup->attr.elfstub_id] = off;
     686                 :             :     }
     687                 :             : 
     688                 :             :     return 0;
     689                 :             : }
     690                 :             : 
     691                 :        4187 : int bf_program_emit_kfunc_call(struct bf_program *program, const char *name)
     692                 :             : {
     693                 :             :     int r;
     694                 :             : 
     695                 :             :     assert(program);
     696                 :             :     assert(name);
     697                 :             : 
     698                 :        4187 :     r = bf_btf_get_id(name);
     699         [ +  - ]:        4187 :     if (r < 0)
     700                 :             :         return r;
     701                 :             : 
     702                 :        4187 :     EMIT(program, ((struct bpf_insn) {.code = BPF_JMP | BPF_CALL,
     703                 :             :                                       .dst_reg = 0,
     704                 :             :                                       .src_reg = BPF_PSEUDO_KFUNC_CALL,
     705                 :             :                                       .off = 0,
     706                 :             :                                       .imm = r}));
     707                 :             : 
     708                 :             :     return 0;
     709                 :             : }
     710                 :             : 
     711                 :       11987 : int bf_program_emit_fixup(struct bf_program *program, enum bf_fixup_type type,
     712                 :             :                           struct bpf_insn insn, const union bf_fixup_attr *attr)
     713                 :             : {
     714                 :       23974 :     _free_bf_fixup_ struct bf_fixup *fixup = NULL;
     715                 :             :     int r;
     716                 :             : 
     717                 :             :     assert(program);
     718                 :             : 
     719         [ +  - ]:       11987 :     EMIT(program, insn);
     720                 :             : 
     721                 :       11987 :     r = bf_fixup_new(&fixup, type, program->img.size - 1, attr);
     722         [ +  - ]:       11987 :     if (r)
     723                 :             :         return r;
     724                 :             : 
     725                 :       11987 :     r = bf_list_add_tail(&program->fixups, fixup);
     726         [ +  - ]:       11987 :     if (r)
     727                 :             :         return r;
     728                 :             : 
     729                 :       11987 :     TAKE_PTR(fixup);
     730                 :             : 
     731                 :       11987 :     return 0;
     732                 :             : }
     733                 :             : 
     734                 :        8318 : int bf_program_emit_fixup_elfstub(struct bf_program *program,
     735                 :             :                                   enum bf_elfstub_id id)
     736                 :             : {
     737                 :       16636 :     _free_bf_fixup_ struct bf_fixup *fixup = NULL;
     738                 :             :     int r;
     739                 :             : 
     740                 :             :     assert(program);
     741                 :             : 
     742         [ +  - ]:        8318 :     EMIT(program, BPF_CALL_REL(0));
     743                 :             : 
     744                 :        8318 :     r = bf_fixup_new(&fixup, BF_FIXUP_ELFSTUB_CALL, program->img.size - 1,
     745                 :             :                      NULL);
     746         [ +  - ]:        8318 :     if (r)
     747                 :             :         return r;
     748                 :             : 
     749                 :        8318 :     fixup->attr.elfstub_id = id;
     750                 :             : 
     751                 :        8318 :     r = bf_list_add_tail(&program->fixups, fixup);
     752         [ +  - ]:        8318 :     if (r)
     753                 :             :         return r;
     754                 :             : 
     755                 :        8318 :     TAKE_PTR(fixup);
     756                 :             : 
     757                 :        8318 :     return 0;
     758                 :             : }
     759                 :             : 
     760                 :        1310 : int bf_program_generate(struct bf_program *program)
     761                 :             : {
     762                 :        1310 :     const struct bf_chain *chain = program->runtime.chain;
     763                 :             :     int ret_code;
     764                 :             :     int r;
     765                 :             : 
     766                 :        1310 :     r = _bf_program_build_set_groups(program);
     767         [ -  + ]:        1310 :     if (r)
     768         [ #  # ]:           0 :         return bf_err_r(r, "failed to build set groups");
     769                 :             : 
     770                 :             :     // Save the program's argument into the context.
     771         [ +  - ]:        1310 :     EMIT(program,
     772                 :             :          BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_1, BF_PROG_CTX_OFF(arg)));
     773                 :             : 
     774                 :             :     // Reset the protocol ID registers
     775         [ +  - ]:        1310 :     EMIT(program, BPF_MOV64_IMM(BPF_REG_7, 0));
     776         [ +  - ]:        1310 :     EMIT(program, BPF_MOV64_IMM(BPF_REG_8, 0));
     777                 :             : 
     778                 :             :     // If at least one rule logs the matched packets, populate ctx->log_map
     779         [ +  + ]:        1310 :     if (program->runtime.chain->flags & BF_FLAG(BF_CHAIN_LOG)) {
     780   [ +  -  +  - ]:          60 :         EMIT_LOAD_LOG_FD_FIXUP(program, BPF_REG_2);
     781         [ +  - ]:          30 :         EMIT(program, BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_2,
     782                 :             :                                   BF_PROG_CTX_OFF(log_map)));
     783                 :             :     }
     784                 :             : 
     785                 :             :     // Zeroing IPv6 extension headers
     786         [ +  + ]:        1310 :     if (program->runtime.chain->flags & BF_FLAG(BF_CHAIN_STORE_NEXTHDR)) {
     787         [ +  - ]:          30 :         EMIT(program, BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_7,
     788                 :             :                                   BF_PROG_CTX_OFF(ipv6_eh)));
     789                 :             :     }
     790                 :             : 
     791                 :        1310 :     r = program->runtime.ops->gen_inline_prologue(program);
     792         [ +  - ]:        1310 :     if (r)
     793                 :             :         return r;
     794                 :             : 
     795   [ +  +  +  +  :        5772 :     bf_list_foreach (&chain->rules, rule_node) {
                   +  + ]
     796                 :        1579 :         r = _bf_program_generate_rule(program,
     797                 :             :                                       bf_list_node_get_data(rule_node));
     798         [ +  + ]:        1579 :         if (r)
     799                 :             :             return r;
     800                 :             :     }
     801                 :             : 
     802                 :        1307 :     r = program->runtime.ops->gen_inline_epilogue(program);
     803         [ +  - ]:        1307 :     if (r)
     804                 :             :         return r;
     805                 :             : 
     806                 :             :     // Call the update counters function
     807                 :             :     /// @todo Allow chains to have no counters at all.
     808         [ +  - ]:        1307 :     EMIT(program, BPF_MOV64_REG(BPF_REG_1, BPF_REG_10));
     809         [ +  - ]:        1307 :     EMIT(program, BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, BF_PROG_CTX_OFF(arg)));
     810   [ +  -  +  - ]:        2614 :     EMIT_LOAD_COUNTERS_FD_FIXUP(program, BPF_REG_2);
     811         [ +  - ]:        1307 :     EMIT(program,
     812                 :             :          BPF_MOV32_IMM(BPF_REG_3, bf_program_chain_counter_idx(program)));
     813         [ +  - ]:        1307 :     EMIT_FIXUP_ELFSTUB(program, BF_ELFSTUB_UPDATE_COUNTERS);
     814                 :             : 
     815                 :        1307 :     r = program->runtime.ops->get_verdict(chain->policy, &ret_code);
     816         [ +  - ]:        1307 :     if (r)
     817                 :             :         return r;
     818         [ +  - ]:        1307 :     EMIT(program, BPF_MOV64_IMM(BPF_REG_0, ret_code));
     819         [ +  - ]:        1307 :     EMIT(program, BPF_EXIT_INSN());
     820                 :             : 
     821                 :        1307 :     r = _bf_program_generate_elfstubs(program);
     822         [ +  - ]:        1307 :     if (r)
     823                 :             :         return r;
     824                 :             : 
     825                 :        1307 :     r = _bf_program_fixup(program, BF_FIXUP_ELFSTUB_CALL);
     826         [ -  + ]:        1307 :     if (r)
     827         [ #  # ]:           0 :         return bf_err_r(r, "failed to generate ELF stub call fixups");
     828                 :             : 
     829                 :             :     return 0;
     830                 :             : }
     831                 :             : 
     832                 :        1307 : static int _bf_program_load_printer_map(struct bf_program *program)
     833                 :             : {
     834                 :        1307 :     _cleanup_free_ void *pstr = NULL;
     835                 :             :     size_t pstr_len;
     836                 :        1307 :     uint32_t key = 0;
     837                 :             :     int r;
     838                 :             : 
     839                 :             :     assert(program);
     840                 :             : 
     841                 :        1307 :     r = bf_printer_assemble(program->printer, &pstr, &pstr_len);
     842         [ -  + ]:        1307 :     if (r)
     843         [ #  # ]:           0 :         return bf_err_r(r, "failed to assemble printer map string");
     844                 :             : 
     845                 :        1307 :     r = bf_map_new(&program->handle->pmap, _BF_PRINTER_MAP_NAME,
     846                 :             :                    BF_MAP_TYPE_PRINTER, sizeof(uint32_t), pstr_len, 1);
     847         [ -  + ]:        1307 :     if (r)
     848         [ #  # ]:           0 :         return bf_err_r(r, "failed to create the printer bf_map object");
     849                 :             : 
     850                 :        1307 :     r = bf_map_set_elem(program->handle->pmap, &key, pstr);
     851         [ -  + ]:        1307 :     if (r)
     852         [ #  # ]:           0 :         return bf_err_r(r, "failed to set print map elem");
     853                 :             : 
     854                 :        1307 :     r = _bf_program_fixup(program, BF_FIXUP_TYPE_PRINTER_MAP_FD);
     855         [ -  + ]:        1307 :     if (r)
     856         [ #  # ]:           0 :         return bf_err_r(r, "failed to fixup printer map FD");
     857                 :             : 
     858                 :             :     return 0;
     859                 :             : }
     860                 :             : 
     861                 :        1307 : static int _bf_program_load_counters_map(struct bf_program *program)
     862                 :             : {
     863                 :             :     int r;
     864                 :             : 
     865                 :             :     assert(program);
     866                 :             : 
     867                 :        1307 :     r = bf_map_new(&program->handle->cmap, _BF_COUNTER_MAP_NAME,
     868                 :             :                    BF_MAP_TYPE_COUNTERS, sizeof(uint32_t),
     869                 :             :                    sizeof(struct bf_counter),
     870                 :        1307 :                    bf_list_size(&program->runtime.chain->rules) + 2);
     871         [ -  + ]:        1307 :     if (r)
     872         [ #  # ]:           0 :         return bf_err_r(r, "failed to create the counters bf_map object");
     873                 :             : 
     874                 :        1307 :     r = _bf_program_fixup(program, BF_FIXUP_TYPE_COUNTERS_MAP_FD);
     875         [ -  + ]:        1307 :     if (r)
     876         [ #  # ]:           0 :         return bf_err_r(r, "failed to fixup counters map FD");
     877                 :             : 
     878                 :             :     return 0;
     879                 :             : }
     880                 :             : 
     881                 :        1307 : static int _bf_program_load_log_map(struct bf_program *program)
     882                 :             : {
     883                 :             :     int r;
     884                 :             : 
     885                 :             :     assert(program);
     886                 :             : 
     887                 :             :     // Do not create a log map if it's unused in the chain
     888         [ +  + ]:        1307 :     if (!(program->runtime.chain->flags & BF_FLAG(BF_CHAIN_LOG)))
     889                 :             :         return 0;
     890                 :             : 
     891                 :          30 :     r = bf_map_new(&program->handle->lmap, _BF_LOG_MAP_NAME, BF_MAP_TYPE_LOG, 0,
     892                 :             :                    0, _BF_LOG_MAP_SIZE);
     893         [ -  + ]:          30 :     if (r)
     894         [ #  # ]:           0 :         return bf_err_r(r, "failed to create the log bf_map object");
     895                 :             : 
     896                 :          30 :     r = _bf_program_fixup(program, BF_FIXUP_TYPE_LOG_MAP_FD);
     897         [ +  - ]:          30 :     if (r)
     898         [ #  # ]:           0 :         return bf_err_r(r, "failed to fixup log map FD");
     899                 :             : 
     900                 :             :     return 0;
     901                 :             : }
     902                 :             : 
     903                 :             : /**
     904                 :             :  * @brief Load set maps, one BPF map per `bf_set_group`.
     905                 :             :  *
     906                 :             :  * Hash-keyed sets that share the same key format have already been
     907                 :             :  * grouped by `_bf_program_build_set_groups()`; LPM trie sets each occupy
     908                 :             :  * their own single-set group. Each group collapses to one BPF map whose
     909                 :             :  * value is a bitmask: bit `i` of byte `i / CHAR_BIT` identifies the `i`-th
     910                 :             :  * set in the group.
     911                 :             :  *
     912                 :             :  * Group ownership of the created maps is transferred to `handle->sets`;
     913                 :             :  * the `bf_set_group::map` pointer is a non-owning back-reference used by
     914                 :             :  * `_bf_program_fixup()` when resolving `BF_FIXUP_TYPE_SET_MAP_FD` fixups.
     915                 :             :  */
     916                 :        1307 : static int _bf_program_load_sets_maps(struct bf_program *new_prog)
     917                 :             : {
     918                 :             :     char name[BPF_OBJ_NAME_LEN];
     919                 :             :     size_t map_idx = 0;
     920                 :             :     int r;
     921                 :             : 
     922                 :             :     assert(new_prog);
     923                 :             : 
     924   [ +  +  +  +  :        3216 :     bf_list_foreach (&new_prog->set_groups, group_node) {
                   +  + ]
     925                 :             :         struct bf_set_group *group = bf_list_node_get_data(group_node);
     926                 :             :         const struct bf_set *key_set =
     927                 :             :             bf_list_node_get_data(bf_list_get_head(&group->sets));
     928                 :             :         size_t n_sets = bf_list_size(&group->sets);
     929                 :         301 :         size_t value_size = (n_sets + CHAR_BIT - 1) / CHAR_BIT;
     930                 :             :         size_t total_elems = 0;
     931                 :             :         size_t bit_idx = 0;
     932                 :         301 :         _free_bf_map_ struct bf_map *new_map = NULL;
     933                 :             :         _cleanup_free_ uint8_t *value = NULL;
     934                 :             :         struct bf_map *map_ref;
     935                 :             : 
     936                 :             :         /* Keys present in multiple sets will share a single map entry, so
     937                 :             :          * the actual entry count may be smaller, but we can err on the
     938                 :             :          * safe side. */
     939         [ +  + ]:         632 :         bf_list_foreach (&group->sets, set_node) {
     940                 :             :             const struct bf_set *set = bf_list_node_get_data(set_node);
     941         [ +  + ]:         316 :             total_elems += bf_hashset_size(&set->elems);
     942                 :             :         }
     943                 :             : 
     944                 :         301 :         (void)snprintf(name, BPF_OBJ_NAME_LEN, _BF_SET_MAP_PREFIX "%04x",
     945                 :         301 :                        (uint16_t)map_idx++);
     946                 :             : 
     947                 :         301 :         r = bf_map_new_from_set(&new_map, name, key_set, total_elems,
     948                 :             :                                 value_size);
     949         [ +  - ]:         301 :         if (r)
     950                 :             :             return r;
     951                 :             : 
     952                 :         301 :         value = malloc(value_size);
     953         [ +  - ]:         301 :         if (!value)
     954                 :             :             return -ENOMEM;
     955                 :             : 
     956   [ +  -  +  + ]:         933 :         bf_list_foreach (&group->sets, set_node) {
     957                 :             :             const struct bf_set *set = bf_list_node_get_data(set_node);
     958                 :             : 
     959   [ +  -  +  +  :        1974 :             bf_hashset_foreach (&set->elems, elem) {
                   +  + ]
     960                 :         671 :                 memset(value, 0, value_size);
     961                 :         671 :                 (void)bf_bpf_map_lookup_elem(new_map->fd, elem->data, value);
     962                 :         671 :                 value[bit_idx / CHAR_BIT] |=
     963                 :         671 :                     (uint8_t)(1U << (bit_idx % CHAR_BIT));
     964                 :         671 :                 r = bf_map_set_elem(new_map, elem->data, value);
     965         [ -  + ]:         671 :                 if (r)
     966         [ #  # ]:           0 :                     return bf_err_r(r, "failed to add set element to the map");
     967                 :             :             }
     968         [ +  + ]:         316 :             ++bit_idx;
     969                 :             :         }
     970                 :             : 
     971                 :         301 :         map_ref = new_map;
     972                 :         301 :         r = bf_list_push(&new_prog->handle->sets, (void **)&new_map);
     973         [ +  - ]:         301 :         if (r)
     974                 :             :             return r;
     975                 :         301 :         group->map = map_ref;
     976                 :             :     }
     977                 :             : 
     978                 :        1307 :     return _bf_program_fixup(new_prog, BF_FIXUP_TYPE_SET_MAP_FD);
     979                 :             : }
     980                 :             : 
     981                 :        1307 : int bf_program_load(struct bf_program *prog)
     982                 :             : {
     983                 :             :     _cleanup_free_ char *log_buf = NULL;
     984                 :             :     int r;
     985                 :             : 
     986                 :             :     assert(prog);
     987                 :             : 
     988                 :        1307 :     r = _bf_program_load_sets_maps(prog);
     989         [ -  + ]:        1307 :     if (r)
     990         [ #  # ]:           0 :         return bf_err_r(r, "failed to load the sets map");
     991                 :             : 
     992                 :        1307 :     r = _bf_program_load_counters_map(prog);
     993         [ -  + ]:        1307 :     if (r)
     994         [ #  # ]:           0 :         return bf_err_r(r, "failed to load the counter map");
     995                 :             : 
     996                 :        1307 :     r = _bf_program_load_printer_map(prog);
     997         [ -  + ]:        1307 :     if (r)
     998         [ #  # ]:           0 :         return bf_err_r(r, "failed to load the printer map");
     999                 :             : 
    1000                 :        1307 :     r = _bf_program_load_log_map(prog);
    1001         [ -  + ]:        1307 :     if (r)
    1002         [ #  # ]:           0 :         return bf_err_r(r, "failed to load the log map");
    1003                 :             : 
    1004         [ +  + ]:        1307 :     if (bf_ctx_is_verbose(BF_VERBOSE_DEBUG)) {
    1005                 :           2 :         log_buf = malloc(_BF_LOG_BUF_SIZE);
    1006         [ -  + ]:           2 :         if (!log_buf) {
    1007         [ #  # ]:           0 :             return bf_err_r(-ENOMEM,
    1008                 :             :                             "failed to allocate BPF_PROG_LOAD logs buffer");
    1009                 :             :         }
    1010                 :             :     }
    1011                 :             : 
    1012         [ -  + ]:        1307 :     if (bf_ctx_is_verbose(BF_VERBOSE_BYTECODE))
    1013                 :           0 :         bf_program_dump_bytecode(prog);
    1014                 :             : 
    1015         [ +  + ]:        2614 :     r = bf_bpf_prog_load(prog->handle->prog_name,
    1016                 :        1307 :                          bf_hook_to_bpf_prog_type(prog->runtime.chain->hook),
    1017                 :             :                          prog->img.data, prog->img.size,
    1018                 :        1307 :                          bf_hook_to_bpf_attach_type(prog->runtime.chain->hook),
    1019                 :             :                          log_buf, log_buf ? _BF_LOG_BUF_SIZE : 0,
    1020                 :        1307 :                          bf_ctx_token(), &prog->handle->prog_fd);
    1021         [ -  + ]:        1307 :     if (r) {
    1022   [ #  #  #  # ]:           0 :         return bf_err_r(r, "failed to load bf_program (%lu insns):\n%s\nerrno:",
    1023                 :             :                         prog->img.size, log_buf ? log_buf : "<NO LOG BUFFER>");
    1024                 :             :     }
    1025                 :             : 
    1026                 :             :     return r;
    1027                 :             : }
    1028                 :             : 
    1029                 :           0 : int bf_program_get_counter(const struct bf_program *program,
    1030                 :             :                            uint32_t counter_idx, struct bf_counter *counter)
    1031                 :             : {
    1032                 :             :     assert(program);
    1033                 :             :     assert(counter);
    1034                 :             : 
    1035                 :           0 :     return bf_handle_get_counter(program->handle, counter_idx, counter);
    1036                 :             : }
    1037                 :             : 
    1038                 :           0 : int bf_cgen_set_counters(struct bf_program *program,
    1039                 :             :                          const struct bf_counter *counters)
    1040                 :             : {
    1041                 :             :     (void)program;
    1042                 :             :     (void)counters;
    1043                 :             : 
    1044                 :           0 :     return -ENOTSUP;
    1045                 :             : }
    1046                 :             : 
    1047                 :        1307 : size_t bf_program_chain_counter_idx(const struct bf_program *program)
    1048                 :             : {
    1049                 :        1307 :     return bf_list_size(&program->runtime.chain->rules);
    1050                 :             : }
    1051                 :             : 
    1052                 :        4187 : size_t bf_program_error_counter_idx(const struct bf_program *program)
    1053                 :             : {
    1054                 :        4187 :     return bf_list_size(&program->runtime.chain->rules) + 1;
    1055                 :             : }
        

Generated by: LCOV version 2.0-1