LCOV - code coverage report
Current view: top level - libbpfilter/cgen - program.c (source / functions) Coverage Total Hit
Test: coverage.lcov Lines: 81.6 % 499 407
Test Date: 2026-11-06 17:47:37 Functions: 93.5 % 31 29
Branches: 52.4 % 609 319

             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/if_ether.h>
      11                 :             : #include <linux/in.h> // NOLINT
      12                 :             : #include <linux/limits.h>
      13                 :             : 
      14                 :             : #include <endian.h>
      15                 :             : #include <errno.h>
      16                 :             : #include <fcntl.h>
      17                 :             : #include <limits.h>
      18                 :             : #include <stdbool.h>
      19                 :             : #include <stddef.h>
      20                 :             : #include <stdint.h>
      21                 :             : #include <stdio.h>
      22                 :             : #include <stdlib.h>
      23                 :             : #include <string.h>
      24                 :             : #include <unistd.h>
      25                 :             : 
      26                 :             : #include <bpfilter/bpf.h>
      27                 :             : #include <bpfilter/btf.h>
      28                 :             : #include <bpfilter/chain.h>
      29                 :             : #include <bpfilter/core/hashset.h>
      30                 :             : #include <bpfilter/core/list.h>
      31                 :             : #include <bpfilter/counter.h>
      32                 :             : #include <bpfilter/ctx.h>
      33                 :             : #include <bpfilter/dump.h>
      34                 :             : #include <bpfilter/flavor.h>
      35                 :             : #include <bpfilter/helper.h>
      36                 :             : #include <bpfilter/hook.h>
      37                 :             : #include <bpfilter/io.h>
      38                 :             : #include <bpfilter/logger.h>
      39                 :             : #include <bpfilter/matcher.h>
      40                 :             : #include <bpfilter/pack.h>
      41                 :             : #include <bpfilter/rule.h>
      42                 :             : #include <bpfilter/set.h>
      43                 :             : #include <bpfilter/verdict.h>
      44                 :             : 
      45                 :             : #include "cgen/cgroup_skb.h"
      46                 :             : #include "cgen/cgroup_sock_addr.h"
      47                 :             : #include "cgen/dump.h"
      48                 :             : #include "cgen/fixup.h"
      49                 :             : #include "cgen/handle.h"
      50                 :             : #include "cgen/jmp.h"
      51                 :             : #include "cgen/nf.h"
      52                 :             : #include "cgen/printer.h"
      53                 :             : #include "cgen/prog/link.h"
      54                 :             : #include "cgen/prog/map.h"
      55                 :             : #include "cgen/stub.h"
      56                 :             : #include "cgen/tc.h"
      57                 :             : #include "cgen/xdp.h"
      58                 :             : #include "filter.h"
      59                 :             : 
      60                 :             : #define _BF_LOG_BUF_SIZE                                                       \
      61                 :             :     (UINT32_MAX >> 8) /* verifier maximum in kernels <= 5.1 */
      62                 :             : #define _BF_LOG_MAP_N_ENTRIES 1000
      63                 :             : #define _BF_LOG_MAP_SIZE                                                       \
      64                 :             :     _bf_round_next_power_of_2(sizeof(struct bf_log) * _BF_LOG_MAP_N_ENTRIES)
      65                 :             : #define _BF_SET_MAP_PREFIX "bf_set_"
      66                 :             : #define _BF_COUNTER_MAP_NAME "bf_cmap"
      67                 :             : #define _BF_PRINTER_MAP_NAME "bf_pmap"
      68                 :             : #define _BF_LOG_MAP_NAME "bf_lmap"
      69                 :             : #define _BF_STATE_MAP_NAME "bf_smap"
      70                 :             : 
      71                 :             : static inline size_t _bf_round_next_power_of_2(size_t value)
      72                 :             : {
      73                 :             :     if (value == 0)
      74                 :             :         return 1;
      75                 :             : 
      76                 :             :     value--;
      77                 :             :     value |= value >> 1;
      78                 :             :     value |= value >> 2;
      79                 :             :     value |= value >> 4;
      80                 :             :     value |= value >> 8;
      81                 :             :     value |= value >> 16;
      82                 :             : #if SIZE_MAX > 0xFFFFFFFFU
      83                 :             :     value |= value >> 32;
      84                 :             : #endif
      85                 :             : 
      86                 :             :     return ++value;
      87                 :             : }
      88                 :             : 
      89                 :             : /**
      90                 :             :  * @brief Sets sharing the same key format, collapsed to a single BPF map.
      91                 :             :  *
      92                 :             :  * For hash-keyed sets, one `bf_set_group` exists for every unique key
      93                 :             :  * format among a chain's non-empty sets. The sets list preserves insertion
      94                 :             :  * order; a set's position is its bit index within the group's bitmask
      95                 :             :  * value.
      96                 :             :  *
      97                 :             :  * LPM trie sets are never grouped together: each non-empty trie set gets
      98                 :             :  * its own group of size 1. See `_bf_program_build_set_groups()` for the
      99                 :             :  * rationale.
     100                 :             :  */
     101                 :             : struct bf_set_group
     102                 :             : {
     103                 :             :     /** Non-empty sets that map to the same BPF map. For hash-keyed groups,
     104                 :             :      * all sets share the same key format; LPM trie groups always hold a
     105                 :             :      * single set. Non-owning pointers into the chain's `bf_set` list.
     106                 :             :      * Never empty. */
     107                 :             :     bf_list sets;
     108                 :             : 
     109                 :             :     /** Backing BPF map. Populated during `bf_program_load()`; the map is
     110                 :             :      * owned by `bf_program->handle->sets`. */
     111                 :             :     struct bf_map *map;
     112                 :             : };
     113                 :             : 
     114                 :             : #define _free_bf_set_group_ __attribute__((__cleanup__(_bf_set_group_free)))
     115                 :             : 
     116                 :        1139 : static void _bf_set_group_free(struct bf_set_group **group)
     117                 :             : {
     118                 :             :     assert(group);
     119                 :             : 
     120         [ +  + ]:        1139 :     if (!*group)
     121                 :             :         return;
     122                 :             : 
     123                 :         363 :     bf_list_clean(&(*group)->sets);
     124                 :         363 :     BF_FREEP(group);
     125                 :             : }
     126                 :             : 
     127                 :         363 : static int _bf_set_group_new(struct bf_set_group **group)
     128                 :             : {
     129                 :         363 :     _free_bf_set_group_ struct bf_set_group *_group = NULL;
     130                 :             : 
     131                 :             :     assert(group);
     132                 :             : 
     133                 :         363 :     _group = calloc(1, sizeof(*_group));
     134         [ +  - ]:         363 :     if (!_group)
     135                 :             :         return -ENOMEM;
     136                 :             : 
     137                 :             :     /* The list holds non-owning const struct bf_set * pointers; no free
     138                 :             :      * callback. Groups are temporary (not serialized), so no pack callback
     139                 :             :      * either. */
     140                 :         363 :     _group->sets = bf_list_default(NULL, NULL);
     141                 :             : 
     142                 :         363 :     *group = TAKE_PTR(_group);
     143                 :             : 
     144                 :         363 :     return 0;
     145                 :             : }
     146                 :             : 
     147                 :             : static struct bf_set_group *
     148                 :         340 : _bf_program_find_set_group(const struct bf_program *program,
     149                 :             :                            const struct bf_set *set)
     150                 :             : {
     151                 :             :     assert(program);
     152                 :             : 
     153         [ +  - ]:         340 :     if (!set)
     154                 :             :         return NULL;
     155                 :             : 
     156   [ +  -  +  -  :         882 :     bf_list_foreach (&program->set_groups, group_node) {
                   +  - ]
     157                 :             :         struct bf_set_group *group = bf_list_node_get_data(group_node);
     158   [ +  -  +  +  :        1202 :         bf_list_foreach (&group->sets, set_node) {
                   +  + ]
     159         [ +  + ]:         500 :             if (bf_list_node_get_data(set_node) == set)
     160                 :             :                 return group;
     161                 :             :         }
     162                 :             :     }
     163                 :             : 
     164                 :             :     return NULL;
     165                 :             : }
     166                 :             : 
     167                 :         413 : static int _bf_program_add_set_to_group(struct bf_program *program,
     168                 :             :                                         const struct bf_set *set)
     169                 :             : {
     170                 :         413 :     _free_bf_set_group_ struct bf_set_group *group = NULL;
     171                 :             :     int r;
     172                 :             : 
     173                 :             :     assert(program);
     174                 :             :     assert(set);
     175                 :             : 
     176         [ +  + ]:         413 :     if (bf_hashset_is_empty(&set->elems))
     177                 :             :         return 0;
     178                 :             : 
     179                 :             :     /* If a group with a matching key already exists, reuse it. For LPM trie,
     180                 :             :      * sets can't be grouped (as we can't define which rule matches on which
     181                 :             :      * prefix), so they always are the sole member of their group. */
     182         [ +  + ]:         391 :     if (!set->use_trie) {
     183   [ +  +  +  +  :         854 :         bf_list_foreach (&program->set_groups, group_node) {
                   +  + ]
     184                 :             :             struct bf_set_group *group = bf_list_node_get_data(group_node);
     185                 :             :             const struct bf_set *head =
     186                 :             :                 bf_list_node_get_data(bf_list_get_head(&group->sets));
     187                 :             : 
     188         [ +  + ]:         129 :             if (bf_set_same_key(set, head)) {
     189                 :          28 :                 r = bf_list_add_tail(&group->sets, (void *)set);
     190         [ -  + ]:          28 :                 if (r)
     191         [ #  # ]:           0 :                     return bf_err_r(r, "failed to add set to existing group");
     192                 :             : 
     193                 :             :                 return 0;
     194                 :             :             }
     195                 :             :         }
     196                 :             :     }
     197                 :             : 
     198                 :         363 :     r = _bf_set_group_new(&group);
     199         [ -  + ]:         363 :     if (r)
     200         [ #  # ]:           0 :         return bf_err_r(r, "failed to allocate set group");
     201                 :             : 
     202                 :         363 :     r = bf_list_add_tail(&group->sets, (void *)set);
     203         [ -  + ]:         363 :     if (r)
     204         [ #  # ]:           0 :         return bf_err_r(r, "failed to seed set group");
     205                 :             : 
     206                 :         363 :     r = bf_list_push(&program->set_groups, (void **)&group);
     207         [ -  + ]:         363 :     if (r)
     208         [ #  # ]:           0 :         return bf_err_r(r, "failed to register set group");
     209                 :             : 
     210                 :             :     return 0;
     211                 :             : }
     212                 :             : 
     213                 :        1471 : static int _bf_program_build_set_groups(struct bf_program *program)
     214                 :             : {
     215                 :             :     assert(program);
     216                 :             : 
     217                 :        1471 :     bf_list_clean(&program->set_groups);
     218                 :        1471 :     program->set_groups = bf_list_default(_bf_set_group_free, NULL);
     219                 :             : 
     220   [ +  +  +  +  :        3108 :     bf_hashset_foreach (&program->runtime.chain->sets, set_node) {
                   +  + ]
     221                 :          83 :         int r = _bf_program_add_set_to_group(program, set_node->data);
     222         [ +  - ]:          83 :         if (r)
     223                 :             :             return r;
     224                 :             :     }
     225                 :             : 
     226   [ +  +  +  +  :        6432 :     bf_list_foreach (&program->runtime.chain->rules, rule_node) {
                   +  + ]
     227                 :             :         const struct bf_rule *rule = bf_list_node_get_data(rule_node);
     228                 :             : 
     229   [ +  -  +  +  :        9452 :         bf_list_foreach (&rule->matchers, matcher_node) {
                   +  + ]
     230                 :             :             const struct bf_matcher *matcher =
     231                 :             :                 bf_list_node_get_data(matcher_node);
     232                 :             :             const struct bf_set *set;
     233                 :             :             int r;
     234                 :             : 
     235         [ +  + ]:        2981 :             if (bf_matcher_get_type(matcher) != BF_MATCHER_SET)
     236                 :        2578 :                 continue;
     237                 :             : 
     238                 :         403 :             memcpy(&set, bf_matcher_payload(matcher), sizeof(struct bf_set *));
     239         [ +  + ]:         403 :             if (!bf_set_is_anonymous(set))
     240                 :          73 :                 continue;
     241                 :             : 
     242                 :         330 :             r = _bf_program_add_set_to_group(program, set);
     243         [ +  - ]:         330 :             if (r)
     244                 :             :                 return r;
     245                 :             :         }
     246                 :             :     }
     247                 :             : 
     248                 :             :     return 0;
     249                 :             : }
     250                 :             : 
     251                 :         340 : int bf_program_set_bit_index(const struct bf_program *program,
     252                 :             :                              const struct bf_set *set, size_t *bit_index)
     253                 :             : {
     254                 :             :     assert(program);
     255                 :             :     assert(set);
     256                 :             :     assert(bit_index);
     257                 :             : 
     258   [ +  -  +  -  :         882 :     bf_list_foreach (&program->set_groups, group_node) {
                   +  - ]
     259                 :             :         struct bf_set_group *group = bf_list_node_get_data(group_node);
     260                 :             :         size_t i = 0;
     261                 :             : 
     262   [ +  -  +  + ]:        1101 :         bf_list_foreach (&group->sets, set_node) {
     263         [ +  + ]:         500 :             if (bf_list_node_get_data(set_node) == set) {
     264                 :         340 :                 *bit_index = i;
     265                 :         340 :                 return 0;
     266                 :             :             }
     267         [ +  + ]:         160 :             ++i;
     268                 :             :         }
     269                 :             :     }
     270                 :             : 
     271                 :             :     return -ENOENT;
     272                 :             : }
     273                 :             : 
     274                 :             : static const struct bf_flavor_ops *bf_flavor_ops_get(enum bf_flavor flavor)
     275                 :             : {
     276                 :             :     static const struct bf_flavor_ops *flavor_ops[] = {
     277                 :             :         [BF_FLAVOR_TC] = &bf_flavor_ops_tc,
     278                 :             :         [BF_FLAVOR_NF] = &bf_flavor_ops_nf,
     279                 :             :         [BF_FLAVOR_XDP] = &bf_flavor_ops_xdp,
     280                 :             :         [BF_FLAVOR_CGROUP_SKB] = &bf_flavor_ops_cgroup_skb,
     281                 :             :         [BF_FLAVOR_CGROUP_SOCK_ADDR] = &bf_flavor_ops_cgroup_sock_addr,
     282                 :             :     };
     283                 :             : 
     284                 :             :     static_assert_enum_mapping(flavor_ops, _BF_FLAVOR_MAX);
     285                 :             : 
     286                 :        1471 :     return flavor_ops[flavor];
     287                 :             : }
     288                 :             : 
     289                 :        1471 : int bf_program_new(struct bf_program **program, const struct bf_chain *chain,
     290                 :             :                    struct bf_handle *handle)
     291                 :             : {
     292                 :        1471 :     _free_bf_program_ struct bf_program *_program = NULL;
     293                 :             :     int r;
     294                 :             : 
     295                 :             :     assert(program);
     296                 :             :     assert(chain);
     297                 :             :     assert(handle);
     298                 :             : 
     299                 :        1471 :     _program = calloc(1, sizeof(*_program));
     300         [ +  - ]:        1471 :     if (!_program)
     301                 :             :         return -ENOMEM;
     302                 :             : 
     303                 :        1471 :     _program->flavor = bf_hook_to_flavor(chain->hook);
     304                 :        1471 :     _program->runtime.ops = bf_flavor_ops_get(_program->flavor);
     305                 :        1471 :     _program->runtime.chain = chain;
     306                 :        1471 :     _program->img = bf_vector_default(sizeof(struct bpf_insn));
     307                 :        1471 :     _program->fixups = bf_list_default(bf_fixup_free, NULL);
     308                 :        1471 :     _program->set_groups = bf_list_default(_bf_set_group_free, NULL);
     309                 :        1471 :     _program->handle = handle;
     310                 :             : 
     311                 :        1471 :     r = bf_vector_reserve(&_program->img, 512);
     312         [ +  - ]:        1471 :     if (r)
     313                 :             :         return r;
     314                 :             : 
     315                 :        1471 :     r = bf_printer_new(&_program->printer);
     316         [ +  - ]:        1471 :     if (r)
     317                 :             :         return r;
     318                 :             : 
     319                 :        1471 :     *program = TAKE_PTR(_program);
     320                 :             : 
     321                 :        1471 :     return 0;
     322                 :             : }
     323                 :             : 
     324                 :        2942 : void bf_program_free(struct bf_program **program)
     325                 :             : {
     326                 :             :     assert(program);
     327                 :             : 
     328         [ +  + ]:        2942 :     if (!*program)
     329                 :             :         return;
     330                 :             : 
     331                 :        1471 :     bf_list_clean(&(*program)->fixups);
     332                 :        1471 :     bf_list_clean(&(*program)->set_groups);
     333                 :        1471 :     bf_vector_clean(&(*program)->img);
     334                 :             : 
     335                 :        1471 :     bf_printer_free(&(*program)->printer);
     336                 :             : 
     337                 :        1471 :     free(*program);
     338                 :        1471 :     *program = NULL;
     339                 :             : }
     340                 :             : 
     341                 :           0 : void bf_program_dump(const struct bf_program *program, prefix_t *prefix)
     342                 :             : {
     343                 :             :     assert(program);
     344                 :             :     assert(prefix);
     345                 :             : 
     346         [ #  # ]:           0 :     DUMP(prefix, "struct bf_program at %p", program);
     347                 :             : 
     348                 :           0 :     bf_dump_prefix_push(prefix);
     349                 :             : 
     350         [ #  # ]:           0 :     DUMP(prefix, "handle: struct bf_handle *");
     351                 :           0 :     bf_dump_prefix_push(prefix);
     352                 :           0 :     bf_handle_dump(program->handle, bf_dump_prefix_last(prefix));
     353                 :           0 :     bf_dump_prefix_pop(prefix);
     354                 :             : 
     355         [ #  # ]:           0 :     DUMP(prefix, "printer: struct bf_printer *");
     356                 :           0 :     bf_dump_prefix_push(prefix);
     357                 :           0 :     bf_printer_dump(program->printer, prefix);
     358                 :           0 :     bf_dump_prefix_pop(prefix);
     359                 :             : 
     360         [ #  # ]:           0 :     DUMP(prefix, "img: %p", program->img.data);
     361         [ #  # ]:           0 :     DUMP(prefix, "img.size: %lu", program->img.size);
     362         [ #  # ]:           0 :     DUMP(prefix, "img.cap: %lu", program->img.cap);
     363                 :             : 
     364         [ #  # ]:           0 :     DUMP(prefix, "fixups: bf_list<struct bf_fixup>[%lu]",
     365                 :             :          bf_list_size(&program->fixups));
     366                 :           0 :     bf_dump_prefix_push(prefix);
     367   [ #  #  #  #  :           0 :     bf_list_foreach (&program->fixups, fixup_node) {
                   #  # ]
     368                 :             :         struct bf_fixup *fixup = bf_list_node_get_data(fixup_node);
     369                 :             : 
     370         [ #  # ]:           0 :         if (bf_list_is_tail(&program->fixups, fixup_node))
     371                 :           0 :             bf_dump_prefix_last(prefix);
     372                 :             : 
     373                 :           0 :         bf_fixup_dump(fixup, prefix);
     374                 :             :     }
     375                 :           0 :     bf_dump_prefix_pop(prefix);
     376                 :             : 
     377         [ #  # ]:           0 :     DUMP(prefix, "groups: bf_list<struct bf_set_group>[%lu]",
     378                 :             :          bf_list_size(&program->set_groups));
     379                 :           0 :     bf_dump_prefix_push(prefix);
     380   [ #  #  #  #  :           0 :     bf_list_foreach (&program->set_groups, group_node) {
                   #  # ]
     381                 :             :         const struct bf_set_group *group = bf_list_node_get_data(group_node);
     382                 :             :         size_t i = 0;
     383                 :             : 
     384         [ #  # ]:           0 :         if (bf_list_is_tail(&program->set_groups, group_node))
     385                 :           0 :             bf_dump_prefix_last(prefix);
     386                 :             : 
     387         [ #  # ]:           0 :         DUMP(prefix, "struct bf_set_group at %p (%lu set(s), map=%p)", group,
     388                 :             :              bf_list_size(&group->sets), (void *)group->map);
     389                 :           0 :         bf_dump_prefix_push(prefix);
     390   [ #  #  #  # ]:           0 :         bf_list_foreach (&group->sets, set_node) {
     391                 :             :             const struct bf_set *set = bf_list_node_get_data(set_node);
     392                 :             : 
     393         [ #  # ]:           0 :             if (bf_list_is_tail(&group->sets, set_node))
     394                 :           0 :                 bf_dump_prefix_last(prefix);
     395   [ #  #  #  # ]:           0 :             DUMP(prefix, "bit %lu: bf_set '%s' (%lu element(s))", i,
     396                 :             :                  set->name ?: "<anonymous>", bf_hashset_size(&set->elems));
     397         [ #  # ]:           0 :             ++i;
     398                 :             :         }
     399                 :           0 :         bf_dump_prefix_pop(prefix);
     400                 :             :     }
     401                 :           0 :     bf_dump_prefix_pop(prefix);
     402                 :             : 
     403         [ #  # ]:           0 :     DUMP(bf_dump_prefix_last(prefix), "runtime: <anonymous>");
     404                 :           0 :     bf_dump_prefix_push(prefix);
     405         [ #  # ]:           0 :     DUMP(bf_dump_prefix_last(prefix), "ops: %p", program->runtime.ops);
     406                 :           0 :     bf_dump_prefix_pop(prefix);
     407                 :             : 
     408                 :           0 :     bf_dump_prefix_pop(prefix);
     409                 :           0 : }
     410                 :             : 
     411                 :       23856 : static void _bf_program_fixup_insn(struct bpf_insn *insn,
     412                 :             :                                    enum bf_fixup_insn type, int32_t value)
     413                 :             : {
     414      [ +  +  - ]:       23856 :     switch (type) {
     415                 :        4941 :     case BF_FIXUP_INSN_OFF:
     416                 :             :         assert(!insn->off);
     417                 :             :         assert(value < SHRT_MAX);
     418                 :        4941 :         insn->off = (int16_t)value;
     419                 :        4941 :         break;
     420                 :       18915 :     case BF_FIXUP_INSN_IMM:
     421                 :             :         assert(!insn->imm);
     422                 :       18915 :         insn->imm = value;
     423                 :       18915 :         break;
     424                 :           0 :     default:
     425         [ #  # ]:           0 :         bf_abort(
     426                 :             :             "unsupported fixup instruction type, this should not happen: %d",
     427                 :             :             type);
     428                 :             :         break;
     429                 :             :     }
     430                 :       23856 : }
     431                 :             : 
     432                 :        7643 : static int _bf_program_fixup(struct bf_program *program,
     433                 :             :                              enum bf_fixup_type type)
     434                 :             : {
     435                 :             :     assert(program);
     436                 :             :     assert(type >= 0 && type < _BF_FIXUP_TYPE_MAX);
     437                 :             : 
     438   [ +  -  +  +  :      152334 :     bf_list_foreach (&program->fixups, fixup_node) {
                   +  + ]
     439                 :             :         enum bf_fixup_insn insn_type = _BF_FIXUP_INSN_MAX;
     440                 :             :         int32_t value;
     441                 :             :         size_t offset;
     442                 :             :         struct bf_fixup *fixup = bf_list_node_get_data(fixup_node);
     443                 :             :         struct bpf_insn *insn;
     444                 :             : 
     445         [ +  + ]:       68524 :         if (type != fixup->type)
     446                 :       44668 :             continue;
     447                 :             : 
     448                 :       23856 :         insn = bf_vector_get(&program->img, fixup->insn);
     449         [ -  + ]:       23856 :         if (!insn) {
     450         [ #  # ]:           0 :             return bf_err_r(-EINVAL,
     451                 :             :                             "fixup references invalid instruction index %lu",
     452                 :             :                             fixup->insn);
     453                 :             :         }
     454                 :             : 
     455   [ +  +  +  +  :       23856 :         switch (type) {
             +  +  +  - ]
     456                 :        4941 :         case BF_FIXUP_TYPE_JMP_NEXT_RULE:
     457                 :             :             insn_type = BF_FIXUP_INSN_OFF;
     458                 :        4941 :             value = (int)(program->img.size - fixup->insn - 1U);
     459                 :        4941 :             break;
     460                 :        7793 :         case BF_FIXUP_TYPE_COUNTERS_MAP_FD:
     461                 :             :             insn_type = BF_FIXUP_INSN_IMM;
     462                 :        7793 :             value = program->handle->cmap->fd;
     463                 :        7793 :             break;
     464                 :        1478 :         case BF_FIXUP_TYPE_PRINTER_MAP_FD:
     465                 :             :             insn_type = BF_FIXUP_INSN_IMM;
     466                 :        1478 :             value = program->handle->pmap->fd;
     467                 :        1478 :             break;
     468                 :          43 :         case BF_FIXUP_TYPE_LOG_MAP_FD:
     469                 :             :             insn_type = BF_FIXUP_INSN_IMM;
     470                 :          43 :             value = program->handle->lmap->fd;
     471                 :          43 :             break;
     472                 :           4 :         case BF_FIXUP_TYPE_STATE_MAP_FD:
     473                 :             :             insn_type = BF_FIXUP_INSN_IMM;
     474                 :           4 :             value = program->handle->smap->fd;
     475                 :           4 :             break;
     476                 :         340 :         case BF_FIXUP_TYPE_SET_MAP_FD: {
     477                 :             :             const struct bf_set_group *group =
     478                 :         340 :                 _bf_program_find_set_group(program, fixup->attr.set_ptr);
     479   [ +  -  -  + ]:         340 :             if (!group || !group->map) {
     480   [ #  #  #  #  :           0 :                 return bf_err_r(
                   #  # ]
     481                 :             :                     -ENOENT, "set map fixup: set '%s' not in any loaded group",
     482                 :             :                     fixup->attr.set_ptr ?
     483                 :             :                         (fixup->attr.set_ptr->name ?: "<anonymous>") :
     484                 :             :                         "(null)");
     485                 :             :             }
     486                 :             :             insn_type = BF_FIXUP_INSN_IMM;
     487                 :         340 :             value = group->map->fd;
     488                 :         340 :             break;
     489                 :             :         }
     490                 :        9257 :         case BF_FIXUP_ELFSTUB_CALL:
     491                 :             :             insn_type = BF_FIXUP_INSN_IMM;
     492                 :        9257 :             offset = program->elfstubs_location[fixup->attr.elfstub_id] -
     493                 :        9257 :                      fixup->insn - 1;
     494         [ -  + ]:        9257 :             if (offset >= INT_MAX)
     495         [ #  # ]:           0 :                 return bf_err_r(-EINVAL, "invalid ELF stub call offset");
     496                 :        9257 :             value = (int32_t)offset;
     497                 :        9257 :             break;
     498                 :           0 :         default:
     499         [ #  # ]:           0 :             bf_abort("unsupported fixup type, this should not happen: %d",
     500                 :             :                      type);
     501                 :             :             break;
     502                 :             :         }
     503                 :             : 
     504                 :       23856 :         _bf_program_fixup_insn(insn, insn_type, value);
     505                 :       23856 :         bf_list_delete(&program->fixups, fixup_node);
     506                 :             :     }
     507                 :             : 
     508                 :             :     return 0;
     509                 :             : }
     510                 :             : 
     511                 :        2976 : static int _bf_program_check_proto(struct bf_program *program,
     512                 :             :                                    enum bf_matcher_type type,
     513                 :             :                                    uint32_t *checked_layers)
     514                 :             : {
     515                 :             :     const struct bf_matcher_meta *meta;
     516                 :             : 
     517                 :             :     assert(program);
     518                 :             :     assert(checked_layers);
     519                 :             : 
     520                 :        2976 :     meta = bf_matcher_get_meta(type);
     521         [ -  + ]:        2976 :     if (!meta)
     522         [ #  # ]:           0 :         return bf_err_r(-EINVAL, "missing meta for matcher type %d", type);
     523                 :             : 
     524         [ +  + ]:        2976 :     if (*checked_layers & BF_FLAG(meta->layer))
     525                 :             :         return 0;
     526                 :             : 
     527                 :        2077 :     if (meta->layer == BF_MATCHER_LAYER_2 ||
     528         [ +  + ]:        2077 :         meta->layer == BF_MATCHER_LAYER_3 ||
     529                 :             :         meta->layer == BF_MATCHER_LAYER_4) {
     530                 :        1310 :         int r = bf_stub_rule_check_protocol(program, meta);
     531         [ +  - ]:        1310 :         if (r)
     532                 :             :             return r;
     533                 :        1310 :         *checked_layers |= BF_FLAG(meta->layer);
     534                 :             :     }
     535                 :             : 
     536                 :             :     return 0;
     537                 :             : }
     538                 :             : 
     539                 :        1727 : static int _bf_program_generate_log(struct bf_program *program,
     540                 :             :                                     const struct bf_rule *rule)
     541                 :             : {
     542                 :        1727 :     _clean_bf_jmpctx_ struct bf_jmpctx l3_ctx = bf_jmpctx_default();
     543                 :        1727 :     _clean_bf_jmpctx_ struct bf_jmpctx l4_ctx = bf_jmpctx_default();
     544                 :        1727 :     _clean_bf_jmpctx_ struct bf_jmpctx null_ctx = bf_jmpctx_default();
     545                 :        1727 :     _clean_bf_jmpctx_ struct bf_jmpctx rate_ctx = bf_jmpctx_default();
     546                 :             :     int r;
     547                 :             : 
     548                 :             :     assert(program);
     549                 :             :     assert(rule);
     550                 :             : 
     551         [ +  + ]:        1727 :     if (!rule->log)
     552                 :             :         return 0;
     553                 :             : 
     554         [ +  + ]:          55 :     if (rule->log == BF_FLAG(BF_LOG_OPT_5_TUPLE)) {
     555                 :             :         /* A 5-tuple is only complete for IPv4/IPv6 packets using TCP/UDP.
     556                 :             :          * Skip only the log action for other packets, leaving the rule's
     557                 :             :          * remaining actions and verdict unchanged. */
     558         [ +  - ]:           3 :         EMIT(program, BPF_JMP_IMM(BPF_JEQ, BPF_REG_7, htobe16(ETH_P_IP), 2));
     559         [ +  - ]:           3 :         EMIT(program, BPF_JMP_IMM(BPF_JEQ, BPF_REG_7, htobe16(ETH_P_IPV6), 1));
     560         [ +  - ]:           3 :         l3_ctx = bf_jmpctx_get(program, BPF_JMP_A(0));
     561                 :             : 
     562         [ +  - ]:           3 :         EMIT(program, BPF_JMP_IMM(BPF_JEQ, BPF_REG_8, IPPROTO_TCP, 2));
     563         [ +  - ]:           3 :         EMIT(program, BPF_JMP_IMM(BPF_JEQ, BPF_REG_8, IPPROTO_UDP, 1));
     564         [ +  - ]:           3 :         l4_ctx = bf_jmpctx_get(program, BPF_JMP_A(0));
     565                 :             :     }
     566                 :             : 
     567         [ +  + ]:          55 :     if (rule->log_rate_ns) {
     568                 :           7 :         const struct bpf_insn rate_insn[2] = {
     569                 :           7 :             BPF_LD_IMM64(BPF_REG_1, rule->log_rate_ns),
     570                 :             :         };
     571                 :             : 
     572                 :             :         /* Rate-limited log: check last_log_ts in the state map before logging.
     573                 :             :          *
     574                 :             :          * R9 (callee-saved) holds the pointer to this rule's state entry
     575                 :             :          * across the bpf_ktime_get_ns() call. */
     576         [ +  - ]:           7 :         EMIT(program, BPF_LDX_MEM(BPF_DW, BPF_REG_9, BPF_REG_10,
     577                 :             :                                   BF_PROG_CTX_OFF(state_map)));
     578                 :             : 
     579                 :             :         /* Skip the log if state_map is NULL. This shouldn't happen at runtime,
     580                 :             :          * but the verifier requires the NULL check. */
     581                 :           7 :         null_ctx =
     582         [ +  - ]:           7 :             bf_jmpctx_get(program, BPF_JMP_IMM(BPF_JEQ, BPF_REG_9, 0, 0));
     583                 :             : 
     584         [ +  + ]:           7 :         if (rule->index > 0) {
     585         [ +  - ]:           5 :             EMIT(program, BPF_ALU64_IMM(BPF_ADD, BPF_REG_9,
     586                 :             :                                         (int)(rule->index *
     587                 :             :                                               sizeof(struct bf_rule_state))));
     588                 :             :         }
     589                 :             : 
     590         [ +  - ]:           7 :         EMIT(program, BPF_EMIT_CALL(BPF_FUNC_ktime_get_ns));
     591                 :             : 
     592         [ +  - ]:           7 :         EMIT(program, BPF_LDX_MEM(BPF_DW, BPF_REG_1, BPF_REG_9, 0));
     593         [ +  - ]:           7 :         EMIT(program, BPF_MOV64_REG(BPF_REG_2, BPF_REG_0));
     594         [ +  - ]:           7 :         EMIT(program, BPF_ALU64_REG(BPF_SUB, BPF_REG_2, BPF_REG_1));
     595                 :             : 
     596                 :             :         // Load log_rate_ns as a 64-bit immediate into R1.
     597         [ +  - ]:           7 :         EMIT(program, rate_insn[0]);
     598         [ +  - ]:           7 :         EMIT(program, rate_insn[1]);
     599                 :             : 
     600                 :             :         // Skip the log while delta is smaller than log_rate_ns.
     601         [ +  - ]:           7 :         rate_ctx = bf_jmpctx_get(program,
     602                 :             :                                  BPF_JMP_REG(BPF_JLT, BPF_REG_2, BPF_REG_1, 0));
     603                 :             : 
     604         [ +  - ]:           7 :         EMIT(program, BPF_STX_MEM(BPF_DW, BPF_REG_9, BPF_REG_0, 0));
     605                 :             :     }
     606                 :             : 
     607                 :          55 :     r = program->runtime.ops->gen_inline_log(program, rule);
     608         [ +  - ]:          55 :     if (r)
     609                 :             :         return r;
     610                 :             : 
     611         [ +  + ]:          55 :     if (bf_ctx_is_verbose(BF_VERBOSE_BPF)) {
     612                 :           2 :         _clean_bf_jmpctx_ struct bf_jmpctx _ =
     613         [ +  - ]:           2 :             bf_jmpctx_get(program, BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 0));
     614                 :             : 
     615   [ +  -  +  -  :           6 :         EMIT_PRINT(program, "failed to reserve a log entry in the ring buffer");
             +  -  +  - ]
     616                 :             :     }
     617                 :             : 
     618                 :             :     return 0;
     619                 :             : }
     620                 :             : 
     621                 :             : /**
     622                 :             :  * @brief Check whether a matcher needs no bytecode.
     623                 :             :  *
     624                 :             :  * A matcher needs no bytecode if it matches every packet the rule applies
     625                 :             :  * to. The protocol checks derived from the matcher are still generated.
     626                 :             :  *
     627                 :             :  * @param program Program to generate the matcher for. Can't be NULL.
     628                 :             :  * @param matcher Matcher to check. Can't be NULL.
     629                 :             :  * @return True if no bytecode is needed for the matcher, false otherwise.
     630                 :             :  */
     631                 :        2927 : static bool _bf_program_matcher_is_noop(const struct bf_program *program,
     632                 :             :                                         const struct bf_matcher *matcher)
     633                 :             : {
     634                 :             :     assert(program);
     635                 :             :     assert(matcher);
     636                 :             : 
     637         [ +  + ]:        2927 :     if (bf_matcher_get_type(matcher) == BF_MATCHER_SET) {
     638                 :             :         const struct bf_set *set =
     639                 :         352 :             bf_chain_get_set_for_matcher(program->runtime.chain, matcher);
     640                 :             : 
     641                 :             :         /* ... not in {} will match every packet, so no need to generate the
     642                 :             :          * bytecode for it. */
     643         [ +  + ]:         352 :         if (bf_set_is_empty(set) && bf_matcher_get_negate(matcher))
     644                 :             :             return true;
     645                 :             :     }
     646                 :             : 
     647                 :             :     return false;
     648                 :             : }
     649                 :             : 
     650                 :        1745 : static int _bf_program_generate_rule(struct bf_program *program,
     651                 :             :                                      struct bf_rule *rule)
     652                 :             : {
     653                 :        1745 :     uint32_t checked_layers = 0;
     654                 :             :     int ret_code;
     655                 :             :     int r = 0;
     656                 :             : 
     657                 :             :     assert(program);
     658                 :             :     assert(rule);
     659                 :             :     assert(program->runtime.ops->gen_inline_matcher);
     660                 :             :     assert(program->runtime.ops->gen_inline_log);
     661                 :             : 
     662         [ +  + ]:        1745 :     if (rule->disabled)
     663                 :             :         return 0;
     664                 :             : 
     665   [ +  -  +  +  :        9308 :     bf_list_foreach (&rule->matchers, matcher_node) {
                   +  + ]
     666                 :             :         struct bf_matcher *matcher = bf_list_node_get_data(matcher_node);
     667                 :             : 
     668         [ +  + ]:        2927 :         if (bf_matcher_get_type(matcher) == BF_MATCHER_SET) {
     669                 :             :             const struct bf_set *set =
     670                 :         352 :                 bf_chain_get_set_for_matcher(program->runtime.chain, matcher);
     671                 :             : 
     672         [ -  + ]:         352 :             if (!set) {
     673         [ #  # ]:           0 :                 return bf_err_r(-ENOENT, "rule %u references non-existent set",
     674                 :             :                                 rule->index);
     675                 :             :             }
     676                 :             : 
     677   [ +  +  +  - ]:         753 :             for (size_t i = 0; i < set->n_comps && !r; ++i) {
     678                 :         401 :                 r = _bf_program_check_proto(program, set->key[i],
     679                 :             :                                             &checked_layers);
     680                 :             :             }
     681                 :             :         } else {
     682                 :        2575 :             r = _bf_program_check_proto(program, bf_matcher_get_type(matcher),
     683                 :             :                                         &checked_layers);
     684                 :             :         }
     685                 :             : 
     686         [ +  - ]:        2927 :         if (r)
     687                 :             :             return r;
     688                 :             :     }
     689                 :             : 
     690   [ +  -  +  +  :        9308 :     bf_list_foreach (&rule->matchers, matcher_node) {
                   +  + ]
     691                 :             :         struct bf_matcher *matcher = bf_list_node_get_data(matcher_node);
     692                 :             : 
     693         [ +  + ]:        2927 :         if (_bf_program_matcher_is_noop(program, matcher))
     694                 :          12 :             continue;
     695                 :             : 
     696                 :        2915 :         r = program->runtime.ops->gen_inline_matcher(program, matcher);
     697         [ +  - ]:        2915 :         if (r)
     698                 :             :             return r;
     699                 :             :     }
     700                 :             : 
     701         [ +  + ]:        1727 :     if (bf_rule_mark_is_set(rule)) {
     702         [ -  + ]:          10 :         if (!program->runtime.ops->gen_inline_set_mark) {
     703         [ #  # ]:           0 :             return bf_err_r(-ENOTSUP, "set mark is not supported by %s",
     704                 :             :                             program->runtime.chain->name);
     705                 :             :         }
     706                 :             : 
     707                 :          10 :         r = program->runtime.ops->gen_inline_set_mark(program,
     708                 :             :                                                       bf_rule_mark_get(rule));
     709         [ -  + ]:          10 :         if (r) {
     710         [ #  # ]:           0 :             return bf_err_r(r,
     711                 :             :                             "failed to generate bytecode to set mark for '%s'",
     712                 :             :                             program->runtime.chain->name);
     713                 :             :         }
     714                 :             :     }
     715                 :             : 
     716                 :        1727 :     r = _bf_program_generate_log(program, rule);
     717         [ +  - ]:        1727 :     if (r)
     718                 :             :         return r;
     719                 :             : 
     720         [ +  + ]:        1727 :     if (rule->has_counters) {
     721         [ +  - ]:        1663 :         EMIT(program, BPF_MOV64_REG(BPF_REG_1, BPF_REG_10));
     722         [ +  - ]:        1663 :         EMIT(program, BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, BF_PROG_CTX_OFF(arg)));
     723   [ +  -  +  - ]:        3326 :         EMIT_LOAD_COUNTERS_FD_FIXUP(program, BPF_REG_2);
     724         [ +  - ]:        1663 :         EMIT(program, BPF_MOV32_IMM(BPF_REG_3, rule->index));
     725         [ +  - ]:        1663 :         EMIT_FIXUP_ELFSTUB(program, BF_ELFSTUB_UPDATE_COUNTERS);
     726                 :             :     }
     727                 :             : 
     728   [ +  +  -  + ]:        1727 :     switch (rule->verdict) {
     729                 :        1675 :     case BF_VERDICT_ACCEPT:
     730                 :             :     case BF_VERDICT_DROP:
     731                 :             :     case BF_VERDICT_NEXT:
     732                 :        1675 :         r = program->runtime.ops->get_verdict(rule->verdict, &ret_code);
     733         [ +  - ]:        1675 :         if (r)
     734                 :             :             return r;
     735         [ +  - ]:        1675 :         EMIT(program, BPF_MOV64_IMM(BPF_REG_0, ret_code));
     736         [ +  - ]:        1675 :         EMIT(program, BPF_EXIT_INSN());
     737                 :             :         break;
     738                 :          12 :     case BF_VERDICT_REDIRECT:
     739         [ +  + ]:          12 :         if (!program->runtime.ops->gen_inline_redirect) {
     740         [ +  - ]:           2 :             return bf_err_r(-ENOTSUP, "redirect is not supported by %s hook",
     741                 :             :                             bf_hook_to_str(program->runtime.chain->hook));
     742                 :             :         }
     743                 :          10 :         r = program->runtime.ops->gen_inline_redirect(
     744                 :             :             program, rule->redirect_ifindex, rule->redirect_dir);
     745         [ +  + ]:          10 :         if (r)
     746                 :             :             return r;
     747                 :             :         break;
     748                 :             :     case BF_VERDICT_CONTINUE:
     749                 :             :         // Fall through to next rule or default chain policy.
     750                 :             :         break;
     751                 :           0 :     default:
     752         [ #  # ]:           0 :         bf_abort("unsupported verdict, this should not happen: %d",
     753                 :             :                  rule->verdict);
     754                 :             :         break;
     755                 :             :     }
     756                 :             : 
     757                 :        1724 :     r = _bf_program_fixup(program, BF_FIXUP_TYPE_JMP_NEXT_RULE);
     758         [ -  + ]:        1724 :     if (r)
     759         [ #  # ]:           0 :         return bf_err_r(r, "failed to generate next rule fixups");
     760                 :             : 
     761                 :             :     return 0;
     762                 :             : }
     763                 :             : 
     764                 :        1468 : static int _bf_program_generate_elfstubs(struct bf_program *program)
     765                 :             : {
     766                 :             :     const struct bf_elfstub *elfstub;
     767                 :             :     size_t start_at;
     768                 :             :     int r;
     769                 :             : 
     770                 :             :     assert(program);
     771                 :             : 
     772   [ +  -  +  +  :       40758 :     bf_list_foreach (&program->fixups, fixup_node) {
                   +  + ]
     773                 :             :         struct bf_fixup *fixup = bf_list_node_get_data(fixup_node);
     774                 :       18911 :         size_t off = program->img.size;
     775                 :             : 
     776         [ +  + ]:       18911 :         if (fixup->type != BF_FIXUP_ELFSTUB_CALL)
     777                 :        9654 :             continue;
     778                 :             : 
     779                 :             :         // Only generate each ELF stub once
     780         [ +  + ]:        9257 :         if (program->elfstubs_location[fixup->attr.elfstub_id])
     781                 :        6337 :             continue;
     782                 :             : 
     783         [ -  + ]:        2920 :         bf_dbg("generate ELF stub for ID %d", fixup->attr.elfstub_id);
     784                 :             : 
     785                 :        2920 :         elfstub = bf_ctx_get_elfstub(fixup->attr.elfstub_id);
     786         [ -  + ]:        2920 :         if (!elfstub) {
     787         [ #  # ]:           0 :             return bf_err_r(-ENOENT, "no ELF stub found for ID %d",
     788                 :             :                             fixup->attr.elfstub_id);
     789                 :             :         }
     790                 :             : 
     791                 :        2920 :         start_at = program->img.size;
     792                 :             : 
     793         [ +  + ]:      109580 :         for (size_t i = 0; i < elfstub->ninsns; ++i) {
     794                 :      106660 :             r = bf_program_emit(program, elfstub->insns[i]);
     795         [ -  + ]:      106660 :             if (r)
     796         [ #  # ]:           0 :                 return bf_err_r(r, "failed to insert ELF stub instruction");
     797                 :             :         }
     798                 :             : 
     799   [ +  +  -  +  :        8776 :         bf_list_foreach (&elfstub->strs, pstr_node) {
                   +  + ]
     800                 :        1468 :             _free_bf_fixup_ struct bf_fixup *fixup = NULL;
     801                 :             :             struct bf_printk_str *pstr = bf_list_node_get_data(pstr_node);
     802                 :        1468 :             size_t insn_idx = start_at + pstr->insn_idx;
     803                 :             :             const struct bf_printer_msg *msg =
     804                 :        1468 :                 bf_printer_add_msg(program->printer, pstr->str);
     805                 :        1468 :             struct bpf_insn ld_insn[2] = {
     806                 :             :                 BPF_LD_MAP_FD(BPF_REG_1, 0),
     807                 :             :             };
     808                 :             : 
     809                 :        1468 :             ld_insn[0].src_reg = BPF_PSEUDO_MAP_VALUE;
     810                 :        1468 :             ld_insn[1].imm = (int)bf_printer_msg_offset(msg);
     811                 :             : 
     812                 :        1468 :             r = bf_vector_set(&program->img, insn_idx, &ld_insn[0]);
     813         [ -  + ]:        1468 :             if (r) {
     814         [ #  # ]:           0 :                 return bf_err_r(
     815                 :             :                     r, "failed to set ELF stub instruction at index %lu",
     816                 :             :                     insn_idx);
     817                 :             :             }
     818                 :        1468 :             r = bf_vector_set(&program->img, insn_idx + 1, &ld_insn[1]);
     819         [ -  + ]:        1468 :             if (r) {
     820         [ #  # ]:           0 :                 return bf_err_r(
     821                 :             :                     r, "failed to set ELF stub instruction at index %lu",
     822                 :             :                     insn_idx + 1);
     823                 :             :             }
     824                 :             : 
     825                 :        1468 :             r = bf_fixup_new(&fixup, BF_FIXUP_TYPE_PRINTER_MAP_FD, insn_idx,
     826                 :             :                              NULL);
     827         [ +  - ]:        1468 :             if (r)
     828                 :             :                 return r;
     829                 :             : 
     830                 :        1468 :             r = bf_list_add_tail(&program->fixups, fixup);
     831         [ +  - ]:        1468 :             if (r)
     832                 :             :                 return r;
     833                 :             : 
     834                 :        1468 :             TAKE_PTR(fixup);
     835                 :             :         }
     836                 :             : 
     837                 :        2920 :         program->elfstubs_location[fixup->attr.elfstub_id] = off;
     838                 :             :     }
     839                 :             : 
     840                 :             :     return 0;
     841                 :             : }
     842                 :             : 
     843                 :        4672 : int bf_program_emit_kfunc_call(struct bf_program *program, const char *name)
     844                 :             : {
     845                 :             :     int r;
     846                 :             : 
     847                 :             :     assert(program);
     848                 :             :     assert(name);
     849                 :             : 
     850                 :        4672 :     r = bf_btf_get_id(name);
     851         [ +  - ]:        4672 :     if (r < 0)
     852                 :             :         return r;
     853                 :             : 
     854                 :        4672 :     EMIT(program, ((struct bpf_insn) {.code = BPF_JMP | BPF_CALL,
     855                 :             :                                       .dst_reg = 0,
     856                 :             :                                       .src_reg = BPF_PSEUDO_KFUNC_CALL,
     857                 :             :                                       .off = 0,
     858                 :             :                                       .imm = r}));
     859                 :             : 
     860                 :             :     return 0;
     861                 :             : }
     862                 :             : 
     863                 :       13147 : int bf_program_emit_fixup(struct bf_program *program, enum bf_fixup_type type,
     864                 :             :                           struct bpf_insn insn, const union bf_fixup_attr *attr)
     865                 :             : {
     866                 :       26294 :     _free_bf_fixup_ struct bf_fixup *fixup = NULL;
     867                 :             :     int r;
     868                 :             : 
     869                 :             :     assert(program);
     870                 :             : 
     871         [ +  - ]:       13147 :     EMIT(program, insn);
     872                 :             : 
     873                 :       13147 :     r = bf_fixup_new(&fixup, type, program->img.size - 1, attr);
     874         [ +  - ]:       13147 :     if (r)
     875                 :             :         return r;
     876                 :             : 
     877                 :       13147 :     r = bf_list_add_tail(&program->fixups, fixup);
     878         [ +  - ]:       13147 :     if (r)
     879                 :             :         return r;
     880                 :             : 
     881                 :       13147 :     TAKE_PTR(fixup);
     882                 :             : 
     883                 :       13147 :     return 0;
     884                 :             : }
     885                 :             : 
     886                 :        9270 : int bf_program_emit_fixup_elfstub(struct bf_program *program,
     887                 :             :                                   enum bf_elfstub_id id)
     888                 :             : {
     889                 :       18540 :     _free_bf_fixup_ struct bf_fixup *fixup = NULL;
     890                 :             :     int r;
     891                 :             : 
     892                 :             :     assert(program);
     893                 :             : 
     894         [ +  - ]:        9270 :     EMIT(program, BPF_CALL_REL(0));
     895                 :             : 
     896                 :        9270 :     r = bf_fixup_new(&fixup, BF_FIXUP_ELFSTUB_CALL, program->img.size - 1,
     897                 :             :                      NULL);
     898         [ +  - ]:        9270 :     if (r)
     899                 :             :         return r;
     900                 :             : 
     901                 :        9270 :     fixup->attr.elfstub_id = id;
     902                 :             : 
     903                 :        9270 :     r = bf_list_add_tail(&program->fixups, fixup);
     904         [ +  - ]:        9270 :     if (r)
     905                 :             :         return r;
     906                 :             : 
     907                 :        9270 :     TAKE_PTR(fixup);
     908                 :             : 
     909                 :        9270 :     return 0;
     910                 :             : }
     911                 :             : 
     912                 :        1471 : int bf_program_generate(struct bf_program *program)
     913                 :             : {
     914                 :        1471 :     const struct bf_chain *chain = program->runtime.chain;
     915                 :             :     int ret_code;
     916                 :             :     int r;
     917                 :             : 
     918                 :        1471 :     r = _bf_program_build_set_groups(program);
     919         [ -  + ]:        1471 :     if (r)
     920         [ #  # ]:           0 :         return bf_err_r(r, "failed to build set groups");
     921                 :             : 
     922                 :             :     // Save the program's argument into the context.
     923         [ +  - ]:        1471 :     EMIT(program,
     924                 :             :          BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_1, BF_PROG_CTX_OFF(arg)));
     925                 :             : 
     926                 :             :     // Reset the protocol ID registers
     927         [ +  - ]:        1471 :     EMIT(program, BPF_MOV64_IMM(BPF_REG_7, 0));
     928         [ +  - ]:        1471 :     EMIT(program, BPF_MOV64_IMM(BPF_REG_8, 0));
     929                 :             : 
     930                 :             :     // If at least one rule logs the matched packets, populate ctx->log_map
     931         [ +  + ]:        1471 :     if (program->runtime.chain->flags & BF_FLAG(BF_CHAIN_LOG)) {
     932   [ +  -  +  - ]:          86 :         EMIT_LOAD_LOG_FD_FIXUP(program, BPF_REG_2);
     933         [ +  - ]:          43 :         EMIT(program, BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_2,
     934                 :             :                                   BF_PROG_CTX_OFF(log_map)));
     935                 :             :     }
     936                 :             : 
     937                 :             :     // Zeroing IPv6 extension headers
     938         [ +  + ]:        1471 :     if (program->runtime.chain->flags & BF_FLAG(BF_CHAIN_STORE_NEXTHDR)) {
     939         [ +  - ]:          30 :         EMIT(program, BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_7,
     940                 :             :                                   BF_PROG_CTX_OFF(ipv6_eh)));
     941                 :             :     }
     942                 :             : 
     943                 :        1471 :     r = program->runtime.ops->gen_inline_prologue(program);
     944         [ +  - ]:        1471 :     if (r)
     945                 :             :         return r;
     946                 :             : 
     947                 :             :     // Populate ctx->state_map with the base pointer from the single-entry
     948                 :             :     // state map. The key (0) is written to scratch[0..3] temporarily.
     949                 :             :     // Placed after gen_inline_prologue so R1-R5 are free: the helper call
     950                 :             :     // does not need to be followed by a ctx restore.
     951         [ +  + ]:        1471 :     if (program->runtime.chain->flags & BF_FLAG(BF_CHAIN_LOG_RATELIMIT)) {
     952         [ +  - ]:           4 :         EMIT(program, BPF_ST_MEM(BPF_W, BPF_REG_10, BF_PROG_SCR_OFF(0), 0));
     953   [ +  -  +  - ]:           8 :         EMIT_LOAD_STATE_FD_FIXUP(program, BPF_REG_1);
     954         [ +  - ]:           4 :         EMIT(program, BPF_MOV64_REG(BPF_REG_2, BPF_REG_10));
     955         [ +  - ]:           4 :         EMIT(program, BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, BF_PROG_SCR_OFF(0)));
     956         [ +  - ]:           4 :         EMIT(program, BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem));
     957         [ +  - ]:           4 :         EMIT(program, BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_0,
     958                 :             :                                   BF_PROG_CTX_OFF(state_map)));
     959                 :             :     }
     960                 :             : 
     961   [ +  +  +  +  :        6426 :     bf_list_foreach (&chain->rules, rule_node) {
                   +  + ]
     962                 :        1745 :         r = _bf_program_generate_rule(program,
     963                 :             :                                       bf_list_node_get_data(rule_node));
     964         [ +  + ]:        1745 :         if (r)
     965                 :             :             return r;
     966                 :             :     }
     967                 :             : 
     968                 :        1468 :     r = program->runtime.ops->gen_inline_epilogue(program);
     969         [ +  - ]:        1468 :     if (r)
     970                 :             :         return r;
     971                 :             : 
     972                 :             :     // Call the update counters function
     973                 :             :     /// @todo Allow chains to have no counters at all.
     974         [ +  - ]:        1468 :     EMIT(program, BPF_MOV64_REG(BPF_REG_1, BPF_REG_10));
     975         [ +  - ]:        1468 :     EMIT(program, BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, BF_PROG_CTX_OFF(arg)));
     976   [ +  -  +  - ]:        2936 :     EMIT_LOAD_COUNTERS_FD_FIXUP(program, BPF_REG_2);
     977         [ +  - ]:        1468 :     EMIT(program,
     978                 :             :          BPF_MOV32_IMM(BPF_REG_3, bf_program_chain_counter_idx(program)));
     979         [ +  - ]:        1468 :     EMIT_FIXUP_ELFSTUB(program, BF_ELFSTUB_UPDATE_COUNTERS);
     980                 :             : 
     981                 :        1468 :     r = program->runtime.ops->get_verdict(chain->policy, &ret_code);
     982         [ +  - ]:        1468 :     if (r)
     983                 :             :         return r;
     984         [ +  - ]:        1468 :     EMIT(program, BPF_MOV64_IMM(BPF_REG_0, ret_code));
     985         [ +  - ]:        1468 :     EMIT(program, BPF_EXIT_INSN());
     986                 :             : 
     987                 :        1468 :     r = _bf_program_generate_elfstubs(program);
     988         [ +  - ]:        1468 :     if (r)
     989                 :             :         return r;
     990                 :             : 
     991                 :        1468 :     r = _bf_program_fixup(program, BF_FIXUP_ELFSTUB_CALL);
     992         [ -  + ]:        1468 :     if (r)
     993         [ #  # ]:           0 :         return bf_err_r(r, "failed to generate ELF stub call fixups");
     994                 :             : 
     995                 :             :     return 0;
     996                 :             : }
     997                 :             : 
     998                 :        1468 : static int _bf_program_load_printer_map(struct bf_program *program)
     999                 :             : {
    1000                 :        1468 :     _cleanup_free_ void *pstr = NULL;
    1001                 :             :     size_t pstr_len;
    1002                 :        1468 :     uint32_t key = 0;
    1003                 :             :     int r;
    1004                 :             : 
    1005                 :             :     assert(program);
    1006                 :             : 
    1007                 :        1468 :     r = bf_printer_assemble(program->printer, &pstr, &pstr_len);
    1008         [ -  + ]:        1468 :     if (r)
    1009         [ #  # ]:           0 :         return bf_err_r(r, "failed to assemble printer map string");
    1010                 :             : 
    1011                 :        1468 :     r = bf_map_new(&program->handle->pmap, _BF_PRINTER_MAP_NAME,
    1012                 :             :                    BF_MAP_TYPE_PRINTER, sizeof(uint32_t), pstr_len, 1);
    1013         [ -  + ]:        1468 :     if (r)
    1014         [ #  # ]:           0 :         return bf_err_r(r, "failed to create the printer bf_map object");
    1015                 :             : 
    1016                 :        1468 :     r = bf_map_set_elem(program->handle->pmap, &key, pstr);
    1017         [ -  + ]:        1468 :     if (r)
    1018         [ #  # ]:           0 :         return bf_err_r(r, "failed to set print map elem");
    1019                 :             : 
    1020                 :        1468 :     r = _bf_program_fixup(program, BF_FIXUP_TYPE_PRINTER_MAP_FD);
    1021         [ -  + ]:        1468 :     if (r)
    1022         [ #  # ]:           0 :         return bf_err_r(r, "failed to fixup printer map FD");
    1023                 :             : 
    1024                 :             :     return 0;
    1025                 :             : }
    1026                 :             : 
    1027                 :        1468 : static int _bf_program_load_counters_map(struct bf_program *program)
    1028                 :             : {
    1029                 :             :     int r;
    1030                 :             : 
    1031                 :             :     assert(program);
    1032                 :             : 
    1033                 :        1468 :     r = bf_map_new(&program->handle->cmap, _BF_COUNTER_MAP_NAME,
    1034                 :             :                    BF_MAP_TYPE_COUNTERS, sizeof(uint32_t),
    1035                 :             :                    sizeof(struct bf_counter),
    1036                 :        1468 :                    bf_list_size(&program->runtime.chain->rules) + 2);
    1037         [ -  + ]:        1468 :     if (r)
    1038         [ #  # ]:           0 :         return bf_err_r(r, "failed to create the counters bf_map object");
    1039                 :             : 
    1040                 :        1468 :     r = _bf_program_fixup(program, BF_FIXUP_TYPE_COUNTERS_MAP_FD);
    1041         [ -  + ]:        1468 :     if (r)
    1042         [ #  # ]:           0 :         return bf_err_r(r, "failed to fixup counters map FD");
    1043                 :             : 
    1044                 :             :     return 0;
    1045                 :             : }
    1046                 :             : 
    1047                 :        1468 : static int _bf_program_load_log_map(struct bf_program *program)
    1048                 :             : {
    1049                 :             :     int r;
    1050                 :             : 
    1051                 :             :     assert(program);
    1052                 :             : 
    1053                 :             :     // Do not create a log map if it's unused in the chain
    1054         [ +  + ]:        1468 :     if (!(program->runtime.chain->flags & BF_FLAG(BF_CHAIN_LOG)))
    1055                 :             :         return 0;
    1056                 :             : 
    1057                 :             :     // The handle might already reuse the log map of the program it replaces
    1058         [ +  + ]:          43 :     if (!program->handle->lmap) {
    1059                 :          41 :         r = bf_map_new(&program->handle->lmap, _BF_LOG_MAP_NAME,
    1060                 :             :                        BF_MAP_TYPE_LOG, 0, 0, _BF_LOG_MAP_SIZE);
    1061         [ -  + ]:          41 :         if (r)
    1062         [ #  # ]:           0 :             return bf_err_r(r, "failed to create the log bf_map object");
    1063                 :             :     }
    1064                 :             : 
    1065                 :          43 :     r = _bf_program_fixup(program, BF_FIXUP_TYPE_LOG_MAP_FD);
    1066         [ -  + ]:          43 :     if (r)
    1067         [ #  # ]:           0 :         return bf_err_r(r, "failed to fixup log map FD");
    1068                 :             : 
    1069                 :             :     return 0;
    1070                 :             : }
    1071                 :             : 
    1072                 :        1468 : static int _bf_program_load_state_map(struct bf_program *program)
    1073                 :             : {
    1074                 :             :     size_t n_rules;
    1075                 :             :     int r;
    1076                 :             : 
    1077                 :             :     assert(program);
    1078                 :             : 
    1079         [ +  + ]:        1468 :     if (!(program->runtime.chain->flags & BF_FLAG(BF_CHAIN_LOG_RATELIMIT)))
    1080                 :             :         return 0;
    1081                 :             : 
    1082                 :             :     n_rules = bf_list_size(&program->runtime.chain->rules);
    1083         [ +  - ]:           4 :     if (n_rules == 0)
    1084                 :             :         return 0;
    1085                 :             : 
    1086                 :           4 :     r = bf_map_new(&program->handle->smap, _BF_STATE_MAP_NAME,
    1087                 :             :                    BF_MAP_TYPE_STATE, sizeof(uint32_t),
    1088                 :           4 :                    n_rules * sizeof(struct bf_rule_state), 1);
    1089         [ -  + ]:           4 :     if (r)
    1090         [ #  # ]:           0 :         return bf_err_r(r, "failed to create the state bf_map object");
    1091                 :             : 
    1092                 :           4 :     r = _bf_program_fixup(program, BF_FIXUP_TYPE_STATE_MAP_FD);
    1093         [ -  + ]:           4 :     if (r)
    1094         [ #  # ]:           0 :         return bf_err_r(r, "failed to fixup state map FD");
    1095                 :             : 
    1096                 :             :     return 0;
    1097                 :             : }
    1098                 :             : 
    1099                 :         762 : static uint64_t _bf_dedup_hash(const void *data, void *ctx)
    1100                 :             : {
    1101                 :         762 :     return bf_fnv1a(data, *(const size_t *)ctx, bf_fnv1a_init());
    1102                 :             : }
    1103                 :             : 
    1104                 :          42 : static bool _bf_dedup_equal(const void *lhs, const void *rhs, void *ctx)
    1105                 :             : {
    1106                 :          42 :     return memcmp(lhs, rhs, *(const size_t *)ctx) == 0;
    1107                 :             : }
    1108                 :             : 
    1109                 :             : /**
    1110                 :             :  * @brief Load set maps, one BPF map per `bf_set_group`.
    1111                 :             :  *
    1112                 :             :  * Hash-keyed sets that share the same key format have already been
    1113                 :             :  * grouped by `_bf_program_build_set_groups()`; LPM trie sets each occupy
    1114                 :             :  * their own single-set group. Each group collapses to one BPF map whose
    1115                 :             :  * value is a bitmask: bit `i` of byte `i / CHAR_BIT` identifies the `i`-th
    1116                 :             :  * set in the group.
    1117                 :             :  *
    1118                 :             :  * Per-group keys and bitmask values are prepared in user space so a single
    1119                 :             :  * `bf_bpf_map_update_batch()` call populates the map on the kernel side.
    1120                 :             :  *
    1121                 :             :  * The map is created with room for `max(bf_set.min_size, element count)`
    1122                 :             :  * entries for each set in the group: a set that outgrows its `min_size`
    1123                 :             :  * grows the map on its own, it never borrows the room reserved for another
    1124                 :             :  * set of the group. Shared elements are stored once but counted once per
    1125                 :             :  * set, so the map over-reserves when grouped sets overlap; this is the cost
    1126                 :             :  * of keeping per-set reservations independent.
    1127                 :             :  * For each group, we calculate:
    1128                 :             :  * - `n_total_elems`: sum of `set.n_elems` for each sets of a group. Will count
    1129                 :             :  *   duplicates if any.
    1130                 :             :  * - `n_unique_elems`: same as `n_total_elems`, but doesn't count duplicate
    1131                 :             :  *   elements.
    1132                 :             :  * - `n_map_elems`: number of elements that we should have room for in the map,
    1133                 :             :  *   sum of `max(set.min_size, set.n_elems)` for each set in the group.
    1134                 :             :  *
    1135                 :             :  * Empty sets are not part of any group (see `_bf_program_build_set_groups()`),
    1136                 :             :  * so they get no map whatever their `min_size`: their reservation only takes
    1137                 :             :  * effect once they become non-empty and the program is regenerated.
    1138                 :             :  *
    1139                 :             :  * Group ownership of the created maps is transferred to `handle->sets`;
    1140                 :             :  * the `bf_set_group::map` pointer is a non-owning back-reference used by
    1141                 :             :  * `_bf_program_fixup()` when resolving `BF_FIXUP_TYPE_SET_MAP_FD` fixups.
    1142                 :             :  */
    1143                 :        1468 : static int _bf_program_load_sets_maps(struct bf_program *new_prog)
    1144                 :             : {
    1145                 :             :     char name[BPF_OBJ_NAME_LEN];
    1146                 :             :     size_t map_idx = 0;
    1147                 :             :     int r;
    1148                 :             : 
    1149                 :             :     assert(new_prog);
    1150                 :             : 
    1151   [ +  +  +  +  :        3662 :     bf_list_foreach (&new_prog->set_groups, group_node) {
                   +  + ]
    1152                 :             :         struct bf_set_group *group = bf_list_node_get_data(group_node);
    1153                 :             :         const struct bf_set *key_set =
    1154                 :             :             bf_list_node_get_data(bf_list_get_head(&group->sets));
    1155                 :             :         size_t n_sets = bf_list_size(&group->sets);
    1156                 :             :         size_t i = 0;
    1157                 :             :         _cleanup_free_ uint8_t *keys = NULL;
    1158                 :         363 :         size_t key_size = key_set->elem_size;
    1159                 :             :         _cleanup_free_ uint8_t *values = NULL;
    1160                 :         363 :         size_t value_size = (n_sets + CHAR_BIT - 1) / CHAR_BIT;
    1161                 :             :         const bf_hashset_ops dedup_ops = {
    1162                 :             :             .hash = _bf_dedup_hash,
    1163                 :             :             .equal = _bf_dedup_equal,
    1164                 :             :             // The dedup hashset borrows elements from `bf_set`s.
    1165                 :             :             .free = NULL,
    1166                 :             :         };
    1167                 :         363 :         _clean_bf_hashset_ bf_hashset unique_elements =
    1168                 :             :             bf_hashset_default(&dedup_ops, &key_size);
    1169                 :             :         size_t n_total_elems = 0;
    1170                 :             :         size_t n_unique_elems;
    1171                 :             :         size_t n_map_elems = 0;
    1172                 :           0 :         _free_bf_map_ struct bf_map *new_map = NULL;
    1173                 :             :         struct bf_map *map_ref;
    1174                 :             : 
    1175                 :             :         /* Upper-bound the set capacity to avoid incremental rehashing, and
    1176                 :             :          * size the BPF map so every set is guaranteed room for
    1177                 :             :          * max(min_size, element count) entries, independently of the other
    1178                 :             :          * sets in the group. */
    1179         [ +  + ]:         782 :         bf_list_foreach (&group->sets, set_node) {
    1180                 :             :             const struct bf_set *set = bf_list_node_get_data(set_node);
    1181                 :             : 
    1182                 :         391 :             n_total_elems += bf_hashset_size(&set->elems);
    1183         [ +  + ]:         391 :             n_map_elems += bf_max(set->min_size, bf_hashset_size(&set->elems));
    1184                 :             :         }
    1185                 :             : 
    1186                 :         363 :         r = bf_hashset_reserve(&unique_elements, n_total_elems);
    1187         [ -  + ]:         363 :         if (r)
    1188         [ #  # ]:           0 :             return bf_err_r(r, "failed to reserve dedup hashset capacity");
    1189                 :             : 
    1190                 :             :         // Find all unique elements across all sets in this group.
    1191   [ +  -  +  +  :        1508 :         bf_list_foreach (&group->sets, set_node) {
                   +  + ]
    1192                 :             :             const struct bf_set *set = bf_list_node_get_data(set_node);
    1193                 :             : 
    1194   [ +  -  +  +  :        2306 :             bf_hashset_foreach (&set->elems, elem) {
                   +  + ]
    1195                 :         762 :                 void *to_add = elem->data;
    1196                 :         762 :                 r = bf_hashset_add(&unique_elements, &to_add);
    1197         [ -  + ]:         762 :                 if (r && r != -EEXIST)
    1198         [ #  # ]:           0 :                     return bf_err_r(r, "failed to dedup element");
    1199                 :             :             }
    1200                 :             :         }
    1201                 :         363 :         n_unique_elems = bf_hashset_size(&unique_elements);
    1202                 :             : 
    1203                 :             :         // Compute bf_map keys and values for batch insertion.
    1204                 :         363 :         keys = calloc(n_unique_elems, key_size);
    1205         [ -  + ]:         363 :         if (!keys)
    1206         [ #  # ]:           0 :             return bf_err_r(-ENOMEM, "failed to allocate map keys");
    1207                 :             : 
    1208                 :         363 :         values = calloc(n_unique_elems, value_size);
    1209         [ -  + ]:         363 :         if (!values)
    1210         [ #  # ]:           0 :             return bf_err_r(-ENOMEM, "failed to allocate map values");
    1211                 :             : 
    1212   [ +  -  +  + ]:        1865 :         bf_hashset_foreach (&unique_elements, hentry) {
    1213                 :             :             size_t bit_idx = 0;
    1214                 :             : 
    1215                 :             :             // Compute the key.
    1216                 :         751 :             memcpy(keys + (i * key_size), hentry->data, key_size);
    1217                 :             : 
    1218                 :             :             // Compute the value (bitmask).
    1219   [ +  -  +  + ]:        2529 :             bf_list_foreach (&group->sets, set_node) {
    1220                 :             :                 const struct bf_set *set = bf_list_node_get_data(set_node);
    1221                 :             : 
    1222         [ +  + ]:         889 :                 if (bf_hashset_contains(&set->elems, hentry->data)) {
    1223                 :         762 :                     values[(i * value_size) + (bit_idx / CHAR_BIT)] |=
    1224                 :         762 :                         (uint8_t)(1U << (bit_idx % CHAR_BIT));
    1225                 :             :                 }
    1226         [ +  + ]:         889 :                 ++bit_idx;
    1227                 :             :             }
    1228         [ +  + ]:         751 :             ++i;
    1229                 :             :         }
    1230                 :             : 
    1231                 :             :         // Create the BPF map from the computed keys and values.
    1232                 :         363 :         (void)snprintf(name, BPF_OBJ_NAME_LEN, _BF_SET_MAP_PREFIX "%04x",
    1233                 :         363 :                        (uint16_t)map_idx++);
    1234                 :             : 
    1235                 :         363 :         r = bf_map_new_from_set(&new_map, name, key_set, n_map_elems,
    1236                 :             :                                 value_size);
    1237         [ +  - ]:         363 :         if (r)
    1238                 :             :             return r;
    1239                 :             : 
    1240                 :         363 :         r = bf_bpf_map_update_batch(new_map->fd, keys, values, n_unique_elems,
    1241                 :             :                                     BPF_ANY);
    1242         [ -  + ]:         363 :         if (r)
    1243         [ #  # ]:           0 :             return bf_err_r(r, "failed to add set elements to the map");
    1244                 :             : 
    1245                 :         363 :         map_ref = new_map;
    1246                 :         363 :         r = bf_list_push(&new_prog->handle->sets, (void **)&new_map);
    1247         [ +  - ]:         363 :         if (r)
    1248                 :             :             return r;
    1249                 :         363 :         group->map = map_ref;
    1250                 :             :     }
    1251                 :             : 
    1252                 :        1468 :     return _bf_program_fixup(new_prog, BF_FIXUP_TYPE_SET_MAP_FD);
    1253                 :             : }
    1254                 :             : 
    1255                 :        1468 : int bf_program_load(struct bf_program *prog)
    1256                 :             : {
    1257                 :             :     _cleanup_free_ char *log_buf = NULL;
    1258                 :        1468 :     bool log_enabled = bf_ctx_is_verbose(BF_VERBOSE_DEBUG);
    1259                 :             :     int r;
    1260                 :             : 
    1261                 :             :     assert(prog);
    1262                 :             : 
    1263                 :        1468 :     r = _bf_program_load_sets_maps(prog);
    1264         [ -  + ]:        1468 :     if (r)
    1265         [ #  # ]:           0 :         return bf_err_r(r, "failed to load the sets map");
    1266                 :             : 
    1267                 :        1468 :     r = _bf_program_load_counters_map(prog);
    1268         [ -  + ]:        1468 :     if (r)
    1269         [ #  # ]:           0 :         return bf_err_r(r, "failed to load the counter map");
    1270                 :             : 
    1271                 :        1468 :     r = _bf_program_load_printer_map(prog);
    1272         [ -  + ]:        1468 :     if (r)
    1273         [ #  # ]:           0 :         return bf_err_r(r, "failed to load the printer map");
    1274                 :             : 
    1275                 :        1468 :     r = _bf_program_load_log_map(prog);
    1276         [ -  + ]:        1468 :     if (r)
    1277         [ #  # ]:           0 :         return bf_err_r(r, "failed to load the log map");
    1278                 :             : 
    1279                 :        1468 :     r = _bf_program_load_state_map(prog);
    1280         [ -  + ]:        1468 :     if (r)
    1281         [ #  # ]:           0 :         return bf_err_r(r, "failed to load the state map");
    1282                 :             : 
    1283         [ +  - ]:        1468 :     if (bf_ctx_is_verbose(BF_VERBOSE_BYTECODE))
    1284                 :           0 :         bf_program_dump_bytecode(prog);
    1285                 :             : 
    1286                 :        1468 : retry_load:
    1287         [ +  + ]:        1468 :     if (log_enabled) {
    1288                 :           2 :         log_buf = malloc(_BF_LOG_BUF_SIZE);
    1289         [ -  + ]:           2 :         if (!log_buf) {
    1290         [ #  # ]:           0 :             return bf_err_r(-ENOMEM,
    1291                 :             :                             "failed to allocate BPF_PROG_LOAD logs buffer");
    1292                 :             :         }
    1293                 :           2 :         log_buf[0] = '\0';
    1294                 :             :     }
    1295                 :             : 
    1296         [ +  + ]:        2936 :     r = bf_bpf_prog_load(prog->handle->prog_name,
    1297                 :        1468 :                          bf_hook_to_bpf_prog_type(prog->runtime.chain->hook),
    1298                 :             :                          prog->img.data, prog->img.size,
    1299                 :        1468 :                          bf_hook_to_bpf_attach_type(prog->runtime.chain->hook),
    1300                 :             :                          log_buf, log_buf ? _BF_LOG_BUF_SIZE : 0,
    1301                 :        1468 :                          bf_ctx_token(), &prog->handle->prog_fd);
    1302         [ -  + ]:        1468 :     if (r && !log_enabled) {
    1303                 :             :         log_enabled = true;
    1304                 :           0 :         goto retry_load;
    1305                 :             :     }
    1306                 :             : 
    1307         [ -  + ]:        1468 :     if (r) {
    1308   [ #  #  #  # ]:           0 :         return bf_err_r(r, "failed to load bf_program (%lu insns):\n%s\nerrno:",
    1309                 :             :                         prog->img.size, log_buf ? log_buf : "<NO LOG BUFFER>");
    1310                 :             :     }
    1311                 :             : 
    1312                 :             :     return r;
    1313                 :             : }
    1314                 :             : 
    1315                 :           0 : int bf_program_get_counter(const struct bf_program *program,
    1316                 :             :                            uint32_t counter_idx, struct bf_counter *counter)
    1317                 :             : {
    1318                 :             :     assert(program);
    1319                 :             :     assert(counter);
    1320                 :             : 
    1321                 :           0 :     return bf_handle_get_counter(program->handle, counter_idx, counter);
    1322                 :             : }
    1323                 :             : 
    1324                 :        1468 : size_t bf_program_chain_counter_idx(const struct bf_program *program)
    1325                 :             : {
    1326                 :        1468 :     return bf_list_size(&program->runtime.chain->rules);
    1327                 :             : }
    1328                 :             : 
    1329                 :        4672 : size_t bf_program_error_counter_idx(const struct bf_program *program)
    1330                 :             : {
    1331                 :        4672 :     return bf_list_size(&program->runtime.chain->rules) + 1;
    1332                 :             : }
        

Generated by: LCOV version 2.0-1