LCOV - code coverage report
Current view: top level - bpfilter/cgen - program.c (source / functions) Coverage Total Hit
Test: coverage.lcov Lines: 81.1 % 339 275
Test Date: 2026-03-14 18:46:56 Functions: 87.0 % 23 20
Branches: 49.4 % 356 176

             Branch data     Line data    Source code
       1                 :             : /* SPDX-License-Identifier: GPL-2.0-only */
       2                 :             : /*
       3                 :             :  * Copyright (c) 2023 Meta Platforms, Inc. and affiliates.
       4                 :             :  */
       5                 :             : 
       6                 :             : #include "cgen/program.h"
       7                 :             : 
       8                 :             : #include <linux/bpf.h>
       9                 :             : #include <linux/bpf_common.h>
      10                 :             : #include <linux/limits.h>
      11                 :             : 
      12                 :             : #include <errno.h>
      13                 :             : #include <fcntl.h>
      14                 :             : #include <limits.h>
      15                 :             : #include <stddef.h>
      16                 :             : #include <stdint.h>
      17                 :             : #include <stdio.h>
      18                 :             : #include <stdlib.h>
      19                 :             : #include <string.h>
      20                 :             : #include <unistd.h>
      21                 :             : 
      22                 :             : #include <bpfilter/bpf.h>
      23                 :             : #include <bpfilter/btf.h>
      24                 :             : #include <bpfilter/chain.h>
      25                 :             : #include <bpfilter/counter.h>
      26                 :             : #include <bpfilter/dump.h>
      27                 :             : #include <bpfilter/flavor.h>
      28                 :             : #include <bpfilter/helper.h>
      29                 :             : #include <bpfilter/hook.h>
      30                 :             : #include <bpfilter/io.h>
      31                 :             : #include <bpfilter/list.h>
      32                 :             : #include <bpfilter/logger.h>
      33                 :             : #include <bpfilter/matcher.h>
      34                 :             : #include <bpfilter/pack.h>
      35                 :             : #include <bpfilter/rule.h>
      36                 :             : #include <bpfilter/set.h>
      37                 :             : #include <bpfilter/verdict.h>
      38                 :             : 
      39                 :             : #include "cgen/cgroup_skb.h"
      40                 :             : #include "cgen/dump.h"
      41                 :             : #include "cgen/fixup.h"
      42                 :             : #include "cgen/handle.h"
      43                 :             : #include "cgen/jmp.h"
      44                 :             : #include "cgen/matcher/packet.h"
      45                 :             : #include "cgen/nf.h"
      46                 :             : #include "cgen/printer.h"
      47                 :             : #include "cgen/prog/link.h"
      48                 :             : #include "cgen/prog/map.h"
      49                 :             : #include "cgen/stub.h"
      50                 :             : #include "cgen/tc.h"
      51                 :             : #include "cgen/xdp.h"
      52                 :             : #include "ctx.h"
      53                 :             : #include "filter.h"
      54                 :             : 
      55                 :             : #define _BF_LOG_BUF_SIZE                                                       \
      56                 :             :     (UINT32_MAX >> 8) /* verifier maximum in kernels <= 5.1 */
      57                 :             : #define _BF_PROGRAM_DEFAULT_IMG_SIZE (1 << 6)
      58                 :             : #define _BF_LOG_MAP_N_ENTRIES 1000
      59                 :             : #define _BF_LOG_MAP_SIZE                                                       \
      60                 :             :     _bf_round_next_power_of_2(sizeof(struct bf_log) * _BF_LOG_MAP_N_ENTRIES)
      61                 :             : #define _BF_SET_MAP_PREFIX "bf_set_"
      62                 :             : #define _BF_COUNTER_MAP_NAME "bf_cmap"
      63                 :             : #define _BF_PRINTER_MAP_NAME "bf_pmap"
      64                 :             : #define _BF_LOG_MAP_NAME "bf_lmap"
      65                 :             : 
      66                 :         243 : static inline size_t _bf_round_next_power_of_2(size_t value)
      67                 :             : {
      68                 :         243 :     value--;
      69                 :         243 :     value |= value >> 1;
      70                 :         243 :     value |= value >> 2;
      71                 :         243 :     value |= value >> 4;
      72                 :         243 :     value |= value >> 8;
      73                 :         243 :     value |= value >> 16;
      74                 :             : 
      75                 :         243 :     return ++value;
      76                 :             : }
      77                 :             : 
      78                 :             : static const struct bf_flavor_ops *bf_flavor_ops_get(enum bf_flavor flavor)
      79                 :             : {
      80                 :             :     static const struct bf_flavor_ops *flavor_ops[] = {
      81                 :             :         [BF_FLAVOR_TC] = &bf_flavor_ops_tc,
      82                 :             :         [BF_FLAVOR_NF] = &bf_flavor_ops_nf,
      83                 :             :         [BF_FLAVOR_XDP] = &bf_flavor_ops_xdp,
      84                 :             :         [BF_FLAVOR_CGROUP_SKB] = &bf_flavor_ops_cgroup_skb,
      85                 :             :     };
      86                 :             : 
      87                 :             :     static_assert_enum_mapping(flavor_ops, _BF_FLAVOR_MAX);
      88                 :             : 
      89                 :         100 :     return flavor_ops[flavor];
      90                 :             : }
      91                 :             : 
      92                 :         100 : int bf_program_new(struct bf_program **program, const struct bf_chain *chain,
      93                 :             :                    struct bf_handle *handle)
      94                 :             : {
      95                 :         100 :     _free_bf_program_ struct bf_program *_program = NULL;
      96                 :             :     int r;
      97                 :             : 
      98                 :             :     assert(program);
      99                 :             :     assert(chain);
     100                 :             :     assert(handle);
     101                 :             : 
     102                 :         100 :     _program = calloc(1, sizeof(*_program));
     103         [ +  - ]:         100 :     if (!_program)
     104                 :             :         return -ENOMEM;
     105                 :             : 
     106                 :         100 :     _program->flavor = bf_hook_to_flavor(chain->hook);
     107                 :         100 :     _program->runtime.ops = bf_flavor_ops_get(_program->flavor);
     108                 :         100 :     _program->runtime.chain = chain;
     109                 :         100 :     _program->fixups = bf_list_default(bf_fixup_free, NULL);
     110                 :         100 :     _program->handle = handle;
     111                 :             : 
     112                 :         100 :     r = bf_printer_new(&_program->printer);
     113         [ +  - ]:         100 :     if (r)
     114                 :             :         return r;
     115                 :             : 
     116                 :         100 :     *program = TAKE_PTR(_program);
     117                 :             : 
     118                 :         100 :     return 0;
     119                 :             : }
     120                 :             : 
     121                 :         200 : void bf_program_free(struct bf_program **program)
     122                 :             : {
     123         [ +  + ]:         200 :     if (!*program)
     124                 :             :         return;
     125                 :             : 
     126                 :         100 :     bf_list_clean(&(*program)->fixups);
     127                 :         100 :     free((*program)->img);
     128                 :             : 
     129                 :         100 :     bf_printer_free(&(*program)->printer);
     130                 :             : 
     131                 :         100 :     free(*program);
     132                 :         100 :     *program = NULL;
     133                 :             : }
     134                 :             : 
     135                 :           0 : void bf_program_dump(const struct bf_program *program, prefix_t *prefix)
     136                 :             : {
     137                 :             :     assert(program);
     138                 :             :     assert(prefix);
     139                 :             : 
     140         [ #  # ]:           0 :     DUMP(prefix, "struct bf_program at %p", program);
     141                 :             : 
     142                 :           0 :     bf_dump_prefix_push(prefix);
     143                 :             : 
     144         [ #  # ]:           0 :     DUMP(prefix, "handle: struct bf_handle *");
     145                 :           0 :     bf_dump_prefix_push(prefix);
     146                 :           0 :     bf_handle_dump(program->handle, bf_dump_prefix_last(prefix));
     147                 :           0 :     bf_dump_prefix_pop(prefix);
     148                 :             : 
     149         [ #  # ]:           0 :     DUMP(prefix, "printer: struct bf_printer *");
     150                 :           0 :     bf_dump_prefix_push(prefix);
     151                 :           0 :     bf_printer_dump(program->printer, prefix);
     152                 :           0 :     bf_dump_prefix_pop(prefix);
     153                 :             : 
     154         [ #  # ]:           0 :     DUMP(prefix, "img: %p", program->img);
     155         [ #  # ]:           0 :     DUMP(prefix, "img_size: %lu", program->img_size);
     156         [ #  # ]:           0 :     DUMP(prefix, "img_cap: %lu", program->img_cap);
     157                 :             : 
     158         [ #  # ]:           0 :     DUMP(prefix, "fixups: bf_list<struct bf_fixup>[%lu]",
     159                 :             :          bf_list_size(&program->fixups));
     160                 :           0 :     bf_dump_prefix_push(prefix);
     161   [ #  #  #  #  :           0 :     bf_list_foreach (&program->fixups, fixup_node) {
                   #  # ]
     162                 :             :         struct bf_fixup *fixup = bf_list_node_get_data(fixup_node);
     163                 :             : 
     164         [ #  # ]:           0 :         if (bf_list_is_tail(&program->fixups, fixup_node))
     165                 :           0 :             bf_dump_prefix_last(prefix);
     166                 :             : 
     167                 :           0 :         bf_fixup_dump(fixup, prefix);
     168                 :             :     }
     169                 :           0 :     bf_dump_prefix_pop(prefix);
     170                 :             : 
     171         [ #  # ]:           0 :     DUMP(bf_dump_prefix_last(prefix), "runtime: <anonymous>");
     172                 :           0 :     bf_dump_prefix_push(prefix);
     173         [ #  # ]:           0 :     DUMP(bf_dump_prefix_last(prefix), "ops: %p", program->runtime.ops);
     174                 :           0 :     bf_dump_prefix_pop(prefix);
     175                 :             : 
     176                 :           0 :     bf_dump_prefix_pop(prefix);
     177                 :           0 : }
     178                 :             : 
     179                 :         343 : int bf_program_grow_img(struct bf_program *program)
     180                 :             : {
     181                 :             :     size_t new_cap = _BF_PROGRAM_DEFAULT_IMG_SIZE;
     182                 :             :     int r;
     183                 :             : 
     184                 :             :     assert(program);
     185                 :             : 
     186         [ +  + ]:         343 :     if (program->img)
     187                 :         243 :         new_cap = _bf_round_next_power_of_2(program->img_cap << 1);
     188                 :             : 
     189                 :         343 :     r = bf_realloc((void **)&program->img, new_cap * sizeof(struct bpf_insn));
     190         [ -  + ]:         343 :     if (r < 0) {
     191         [ #  # ]:           0 :         return bf_err_r(r, "failed to grow program img from %lu to %lu insn",
     192                 :             :                         program->img_cap, new_cap);
     193                 :             :     }
     194                 :             : 
     195                 :         343 :     program->img_cap = new_cap;
     196                 :             : 
     197                 :         343 :     return 0;
     198                 :             : }
     199                 :             : 
     200                 :        5001 : static void _bf_program_fixup_insn(struct bpf_insn *insn,
     201                 :             :                                    enum bf_fixup_insn type, int32_t value)
     202                 :             : {
     203      [ +  +  - ]:        5001 :     switch (type) {
     204                 :        3060 :     case BF_FIXUP_INSN_OFF:
     205                 :             :         assert(!insn->off);
     206                 :             :         assert(value < SHRT_MAX);
     207                 :        3060 :         insn->off = (int16_t)value;
     208                 :        3060 :         break;
     209                 :        1941 :     case BF_FIXUP_INSN_IMM:
     210                 :             :         assert(!insn->imm);
     211                 :        1941 :         insn->imm = value;
     212                 :        1941 :         break;
     213                 :           0 :     default:
     214         [ #  # ]:           0 :         bf_abort(
     215                 :             :             "unsupported fixup instruction type, this should not happen: %d",
     216                 :             :             type);
     217                 :             :         break;
     218                 :             :     }
     219                 :        5001 : }
     220                 :             : 
     221                 :         755 : static int _bf_program_fixup(struct bf_program *program,
     222                 :             :                              enum bf_fixup_type type)
     223                 :             : {
     224                 :             :     assert(program);
     225                 :             :     assert(type >= 0 && type < _BF_FIXUP_TYPE_MAX);
     226                 :             : 
     227   [ +  -  +  +  :       39076 :     bf_list_foreach (&program->fixups, fixup_node) {
                   +  + ]
     228                 :             :         enum bf_fixup_insn insn_type = _BF_FIXUP_INSN_MAX;
     229                 :             :         int32_t value;
     230                 :             :         size_t offset;
     231                 :             :         struct bf_fixup *fixup = bf_list_node_get_data(fixup_node);
     232                 :       18783 :         struct bpf_insn *insn = &program->img[fixup->insn];
     233                 :             :         struct bf_map *map;
     234                 :             : 
     235         [ +  + ]:       18783 :         if (type != fixup->type)
     236                 :       13782 :             continue;
     237                 :             : 
     238   [ +  +  +  +  :        5001 :         switch (type) {
                +  +  - ]
     239                 :        3060 :         case BF_FIXUP_TYPE_JMP_NEXT_RULE:
     240                 :             :             insn_type = BF_FIXUP_INSN_OFF;
     241                 :        3060 :             value = (int)(program->img_size - fixup->insn - 1U);
     242                 :        3060 :             break;
     243                 :         782 :         case BF_FIXUP_TYPE_COUNTERS_MAP_FD:
     244                 :             :             insn_type = BF_FIXUP_INSN_IMM;
     245                 :         782 :             value = program->handle->cmap->fd;
     246                 :         782 :             break;
     247                 :         121 :         case BF_FIXUP_TYPE_PRINTER_MAP_FD:
     248                 :             :             insn_type = BF_FIXUP_INSN_IMM;
     249                 :         121 :             value = program->handle->pmap->fd;
     250                 :         121 :             break;
     251                 :          24 :         case BF_FIXUP_TYPE_LOG_MAP_FD:
     252                 :             :             insn_type = BF_FIXUP_INSN_IMM;
     253                 :          24 :             value = program->handle->lmap->fd;
     254                 :          24 :             break;
     255                 :         102 :         case BF_FIXUP_TYPE_SET_MAP_FD:
     256                 :         102 :             map = bf_list_get_at(&program->handle->sets, fixup->attr.set_index);
     257         [ -  + ]:         102 :             if (!map) {
     258         [ #  # ]:           0 :                 return bf_err_r(-ENOENT, "can't find set map at index %lu",
     259                 :             :                                 fixup->attr.set_index);
     260                 :             :             }
     261                 :             :             insn_type = BF_FIXUP_INSN_IMM;
     262                 :         102 :             value = map->fd;
     263                 :         102 :             break;
     264                 :         912 :         case BF_FIXUP_ELFSTUB_CALL:
     265                 :             :             insn_type = BF_FIXUP_INSN_IMM;
     266                 :         912 :             offset = program->elfstubs_location[fixup->attr.elfstub_id] -
     267                 :             :                      fixup->insn - 1;
     268         [ -  + ]:         912 :             if (offset >= INT_MAX)
     269         [ #  # ]:           0 :                 return bf_err_r(-EINVAL, "invalid ELF stub call offset");
     270                 :         912 :             value = (int32_t)offset;
     271                 :         912 :             break;
     272                 :           0 :         default:
     273         [ #  # ]:           0 :             bf_abort("unsupported fixup type, this should not happen: %d",
     274                 :             :                      type);
     275                 :             :             break;
     276                 :             :         }
     277                 :             : 
     278                 :        5001 :         _bf_program_fixup_insn(insn, insn_type, value);
     279                 :        5001 :         bf_list_delete(&program->fixups, fixup_node);
     280                 :             :     }
     281                 :             : 
     282                 :             :     return 0;
     283                 :             : }
     284                 :             : 
     285                 :         349 : static int _bf_program_generate_rule(struct bf_program *program,
     286                 :             :                                      struct bf_rule *rule)
     287                 :             : {
     288                 :             :     int r;
     289                 :             : 
     290                 :             :     assert(program);
     291                 :             :     assert(rule);
     292                 :             : 
     293         [ +  + ]:         349 :     if (rule->disabled)
     294                 :             :         return 0;
     295                 :             : 
     296                 :             :     assert(program->runtime.ops->gen_inline_matcher);
     297                 :             : 
     298   [ +  -  +  +  :        3704 :     bf_list_foreach (&rule->matchers, matcher_node) {
                   +  + ]
     299                 :             :         struct bf_matcher *matcher = bf_list_node_get_data(matcher_node);
     300                 :             : 
     301                 :        1506 :         r = program->runtime.ops->gen_inline_matcher(program, matcher);
     302         [ +  - ]:        1506 :         if (r)
     303                 :             :             return r;
     304                 :             :     }
     305                 :             : 
     306         [ +  + ]:         346 :     if (bf_rule_mark_is_set(rule)) {
     307         [ -  + ]:          10 :         if (!program->runtime.ops->gen_inline_set_mark) {
     308         [ #  # ]:           0 :             return bf_err_r(-ENOTSUP, "set mark is not supported by %s",
     309                 :             :                             program->runtime.chain->name);
     310                 :             :         }
     311                 :             : 
     312                 :          10 :         r = program->runtime.ops->gen_inline_set_mark(program,
     313                 :             :                                                       bf_rule_mark_get(rule));
     314         [ -  + ]:          10 :         if (r) {
     315         [ #  # ]:           0 :             return bf_err_r(r,
     316                 :             :                             "failed to generate bytecode to set mark for '%s'",
     317                 :             :                             program->runtime.chain->name);
     318                 :             :         }
     319                 :             :     }
     320                 :             : 
     321         [ +  + ]:         346 :     if (rule->log) {
     322         [ -  + ]:          33 :         EMIT(program, BPF_MOV64_REG(BPF_REG_1, BPF_REG_10));
     323         [ -  + ]:          33 :         EMIT(program, BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, BF_PROG_CTX_OFF(arg)));
     324         [ -  + ]:          33 :         EMIT(program, BPF_MOV64_IMM(BPF_REG_2, rule->index));
     325         [ -  + ]:          33 :         EMIT(program, BPF_MOV64_IMM(BPF_REG_3, rule->log));
     326         [ -  + ]:          33 :         EMIT(program, BPF_MOV64_IMM(BPF_REG_4, rule->verdict));
     327                 :             : 
     328                 :             :         // Pack l3_proto and l4_proto
     329         [ -  + ]:          33 :         EMIT(program, BPF_MOV64_REG(BPF_REG_5, BPF_REG_7));
     330         [ -  + ]:          33 :         EMIT(program, BPF_ALU64_IMM(BPF_LSH, BPF_REG_5, 16));
     331         [ -  + ]:          33 :         EMIT(program, BPF_ALU64_REG(BPF_OR, BPF_REG_5, BPF_REG_8));
     332                 :             : 
     333         [ +  - ]:          33 :         EMIT_FIXUP_ELFSTUB(program, BF_ELFSTUB_LOG);
     334                 :             :     }
     335                 :             : 
     336         [ +  + ]:         346 :     if (rule->counters) {
     337         [ -  + ]:         316 :         EMIT(program, BPF_MOV64_REG(BPF_REG_1, BPF_REG_10));
     338         [ -  + ]:         316 :         EMIT(program, BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, BF_PROG_CTX_OFF(arg)));
     339   [ +  -  +  - ]:         316 :         EMIT_LOAD_COUNTERS_FD_FIXUP(program, BPF_REG_2);
     340         [ -  + ]:         316 :         EMIT(program, BPF_MOV32_IMM(BPF_REG_3, rule->index));
     341         [ +  - ]:         316 :         EMIT_FIXUP_ELFSTUB(program, BF_ELFSTUB_UPDATE_COUNTERS);
     342                 :             :     }
     343                 :             : 
     344   [ +  +  -  + ]:         346 :     switch (rule->verdict) {
     345                 :         294 :     case BF_VERDICT_ACCEPT:
     346                 :             :     case BF_VERDICT_DROP:
     347                 :         294 :         r = program->runtime.ops->get_verdict(rule->verdict);
     348         [ +  - ]:         294 :         if (r < 0)
     349                 :             :             return r;
     350         [ -  + ]:         294 :         EMIT(program, BPF_MOV64_IMM(BPF_REG_0, r));
     351         [ -  + ]:         294 :         EMIT(program, BPF_EXIT_INSN());
     352                 :         294 :         break;
     353                 :          12 :     case BF_VERDICT_REDIRECT:
     354         [ +  + ]:          12 :         if (!program->runtime.ops->gen_inline_redirect) {
     355         [ +  - ]:           2 :             return bf_err_r(-ENOTSUP, "redirect is not supported by %s hook",
     356                 :             :                             bf_hook_to_str(program->runtime.chain->hook));
     357                 :             :         }
     358                 :          10 :         r = program->runtime.ops->gen_inline_redirect(
     359                 :             :             program, rule->redirect_ifindex, rule->redirect_dir);
     360         [ +  + ]:          10 :         if (r)
     361                 :             :             return r;
     362                 :             :         break;
     363                 :             :     case BF_VERDICT_CONTINUE:
     364                 :             :         // Fall through to next rule or default chain policy.
     365                 :             :         break;
     366                 :           0 :     default:
     367         [ #  # ]:           0 :         bf_abort("unsupported verdict, this should not happen: %d",
     368                 :             :                  rule->verdict);
     369                 :             :         break;
     370                 :             :     }
     371                 :             : 
     372                 :         343 :     r = _bf_program_fixup(program, BF_FIXUP_TYPE_JMP_NEXT_RULE);
     373         [ +  - ]:         343 :     if (r)
     374         [ #  # ]:           0 :         return bf_err_r(r, "failed to generate next rule fixups");
     375                 :             : 
     376                 :             :     return 0;
     377                 :             : }
     378                 :             : 
     379                 :          97 : static int _bf_program_generate_elfstubs(struct bf_program *program)
     380                 :             : {
     381                 :             :     const struct bf_elfstub *elfstub;
     382                 :             :     size_t start_at;
     383                 :             :     int r;
     384                 :             : 
     385                 :             :     assert(program);
     386                 :             : 
     387   [ +  -  +  +  :        4076 :     bf_list_foreach (&program->fixups, fixup_node) {
                   +  + ]
     388                 :             :         struct bf_fixup *fixup = bf_list_node_get_data(fixup_node);
     389                 :        1941 :         size_t off = program->img_size;
     390                 :             : 
     391         [ +  + ]:        1941 :         if (fixup->type != BF_FIXUP_ELFSTUB_CALL)
     392                 :        1029 :             continue;
     393                 :             : 
     394                 :             :         // Only generate each ELF stub once
     395         [ +  + ]:         912 :         if (program->elfstubs_location[fixup->attr.elfstub_id])
     396                 :         694 :             continue;
     397                 :             : 
     398         [ +  - ]:         218 :         bf_dbg("generate ELF stub for ID %d", fixup->attr.elfstub_id);
     399                 :             : 
     400                 :         218 :         elfstub = bf_ctx_get_elfstub(fixup->attr.elfstub_id);
     401         [ -  + ]:         218 :         if (!elfstub) {
     402         [ #  # ]:           0 :             return bf_err_r(-ENOENT, "no ELF stub found for ID %d",
     403                 :             :                             fixup->attr.elfstub_id);
     404                 :             :         }
     405                 :             : 
     406                 :         218 :         start_at = program->img_size;
     407                 :             : 
     408         [ +  + ]:        9416 :         for (size_t i = 0; i < elfstub->ninsns; ++i) {
     409                 :        9198 :             r = bf_program_emit(program, elfstub->insns[i]);
     410         [ -  + ]:        9198 :             if (r)
     411         [ #  # ]:           0 :                 return bf_err_r(r, "failed to insert ELF stub instruction");
     412                 :             :         }
     413                 :             : 
     414   [ +  +  -  +  :         678 :         bf_list_foreach (&elfstub->strs, pstr_node) {
                   +  + ]
     415                 :         121 :             _free_bf_fixup_ struct bf_fixup *fixup = NULL;
     416                 :             :             struct bf_printk_str *pstr = bf_list_node_get_data(pstr_node);
     417                 :         121 :             size_t insn_idx = start_at + pstr->insn_idx;
     418                 :             :             const struct bf_printer_msg *msg =
     419                 :         121 :                 bf_printer_add_msg(program->printer, pstr->str);
     420                 :             :             struct bpf_insn ld_insn[2] = {
     421                 :             :                 BPF_LD_MAP_FD(BPF_REG_1, 0),
     422                 :             :             };
     423                 :             : 
     424                 :             :             ld_insn[0].src_reg = BPF_PSEUDO_MAP_VALUE;
     425                 :         121 :             ld_insn[1].imm = (int)bf_printer_msg_offset(msg);
     426                 :             : 
     427                 :         121 :             program->img[insn_idx] = ld_insn[0];
     428                 :         121 :             program->img[insn_idx + 1] = ld_insn[1];
     429                 :             : 
     430                 :         121 :             r = bf_fixup_new(&fixup, BF_FIXUP_TYPE_PRINTER_MAP_FD, insn_idx,
     431                 :             :                              NULL);
     432         [ +  - ]:         121 :             if (r)
     433                 :             :                 return r;
     434                 :             : 
     435                 :         121 :             r = bf_list_add_tail(&program->fixups, fixup);
     436         [ +  - ]:         121 :             if (r)
     437                 :             :                 return r;
     438                 :             : 
     439                 :         121 :             TAKE_PTR(fixup);
     440                 :             :         }
     441                 :             : 
     442                 :         218 :         program->elfstubs_location[fixup->attr.elfstub_id] = off;
     443                 :             :     }
     444                 :             : 
     445                 :             :     return 0;
     446                 :             : }
     447                 :             : 
     448                 :       36240 : int bf_program_emit(struct bf_program *program, struct bpf_insn insn)
     449                 :             : {
     450                 :             :     int r;
     451                 :             : 
     452                 :             :     assert(program);
     453                 :             : 
     454         [ +  + ]:       36240 :     if (program->img_size == program->img_cap) {
     455                 :         261 :         r = bf_program_grow_img(program);
     456         [ +  - ]:         261 :         if (r)
     457                 :             :             return r;
     458                 :             :     }
     459                 :             : 
     460                 :       36240 :     program->img[program->img_size++] = insn;
     461                 :             : 
     462                 :       36240 :     return 0;
     463                 :             : }
     464                 :             : 
     465                 :         379 : int bf_program_emit_kfunc_call(struct bf_program *program, const char *name)
     466                 :             : {
     467                 :             :     int r;
     468                 :             : 
     469                 :             :     assert(program);
     470                 :             :     assert(name);
     471                 :             : 
     472                 :         379 :     r = bf_btf_get_id(name);
     473         [ +  - ]:         379 :     if (r < 0)
     474                 :             :         return r;
     475                 :             : 
     476         [ -  + ]:         379 :     EMIT(program, ((struct bpf_insn) {.code = BPF_JMP | BPF_CALL,
     477                 :             :                                       .dst_reg = 0,
     478                 :             :                                       .src_reg = BPF_PSEUDO_KFUNC_CALL,
     479                 :             :                                       .off = 0,
     480                 :             :                                       .imm = r}));
     481                 :             : 
     482                 :         379 :     return 0;
     483                 :             : }
     484                 :             : 
     485                 :        3984 : int bf_program_emit_fixup(struct bf_program *program, enum bf_fixup_type type,
     486                 :             :                           struct bpf_insn insn, const union bf_fixup_attr *attr)
     487                 :             : {
     488                 :        3984 :     _free_bf_fixup_ struct bf_fixup *fixup = NULL;
     489                 :             :     int r;
     490                 :             : 
     491                 :             :     assert(program);
     492                 :             : 
     493         [ +  + ]:        3984 :     if (program->img_size == program->img_cap) {
     494                 :          18 :         r = bf_program_grow_img(program);
     495         [ +  - ]:          18 :         if (r)
     496                 :             :             return r;
     497                 :             :     }
     498                 :             : 
     499                 :        3984 :     r = bf_fixup_new(&fixup, type, program->img_size, attr);
     500         [ +  - ]:        3984 :     if (r)
     501                 :             :         return r;
     502                 :             : 
     503                 :        3984 :     r = bf_list_add_tail(&program->fixups, fixup);
     504         [ +  - ]:        3984 :     if (r)
     505                 :             :         return r;
     506                 :             : 
     507                 :        3984 :     TAKE_PTR(fixup);
     508                 :             : 
     509                 :             :     /* This call could fail and return an error, in which case it is not
     510                 :             :      * properly handled. However, this shouldn't be an issue as we previously
     511                 :             :      * test whether enough room is available in cgen.img, which is currently
     512                 :             :      * the only reason for EMIT() to fail. */
     513                 :        3984 :     EMIT(program, insn);
     514                 :             : 
     515                 :             :     return 0;
     516                 :             : }
     517                 :             : 
     518                 :         925 : int bf_program_emit_fixup_elfstub(struct bf_program *program,
     519                 :             :                                   enum bf_elfstub_id id)
     520                 :             : {
     521                 :         925 :     _free_bf_fixup_ struct bf_fixup *fixup = NULL;
     522                 :             :     int r;
     523                 :             : 
     524                 :             :     assert(program);
     525                 :             : 
     526         [ +  + ]:         925 :     if (program->img_size == program->img_cap) {
     527                 :          64 :         r = bf_program_grow_img(program);
     528         [ +  - ]:          64 :         if (r)
     529                 :             :             return r;
     530                 :             :     }
     531                 :             : 
     532                 :         925 :     r = bf_fixup_new(&fixup, BF_FIXUP_ELFSTUB_CALL, program->img_size, NULL);
     533         [ +  - ]:         925 :     if (r)
     534                 :             :         return r;
     535                 :             : 
     536                 :         925 :     fixup->attr.elfstub_id = id;
     537                 :             : 
     538                 :         925 :     r = bf_list_add_tail(&program->fixups, fixup);
     539         [ +  - ]:         925 :     if (r)
     540                 :             :         return r;
     541                 :             : 
     542                 :         925 :     TAKE_PTR(fixup);
     543                 :             : 
     544         [ -  + ]:         925 :     EMIT(program, BPF_CALL_REL(0));
     545                 :             : 
     546                 :         925 :     return 0;
     547                 :             : }
     548                 :             : 
     549                 :         100 : int bf_program_generate(struct bf_program *program)
     550                 :             : {
     551                 :         100 :     const struct bf_chain *chain = program->runtime.chain;
     552                 :             :     int r;
     553                 :             : 
     554                 :             :     // Save the program's argument into the context.
     555         [ -  + ]:         100 :     EMIT(program,
     556                 :             :          BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_1, BF_PROG_CTX_OFF(arg)));
     557                 :             : 
     558                 :             :     // Reset the protocol ID registers
     559         [ -  + ]:         100 :     EMIT(program, BPF_MOV64_IMM(BPF_REG_7, 0));
     560         [ -  + ]:         100 :     EMIT(program, BPF_MOV64_IMM(BPF_REG_8, 0));
     561                 :             : 
     562                 :             :     // If at least one rule logs the matched packets, populate ctx->log_map
     563         [ +  + ]:         100 :     if (program->runtime.chain->flags & BF_FLAG(BF_CHAIN_LOG)) {
     564   [ +  -  +  - ]:          24 :         EMIT_LOAD_LOG_FD_FIXUP(program, BPF_REG_2);
     565         [ -  + ]:          24 :         EMIT(program, BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_2,
     566                 :             :                                   BF_PROG_CTX_OFF(log_map)));
     567                 :             :     }
     568                 :             : 
     569                 :             :     // Zeroing IPv6 extension headers
     570         [ +  + ]:         100 :     if (program->runtime.chain->flags & BF_FLAG(BF_CHAIN_STORE_NEXTHDR)) {
     571         [ -  + ]:          10 :         EMIT(program, BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_7,
     572                 :             :                                   BF_PROG_CTX_OFF(ipv6_eh)));
     573                 :             :     }
     574                 :             : 
     575                 :         100 :     r = program->runtime.ops->gen_inline_prologue(program);
     576         [ +  - ]:         100 :     if (r)
     577                 :             :         return r;
     578                 :             : 
     579   [ +  +  +  +  :         892 :     bf_list_foreach (&chain->rules, rule_node) {
                   +  + ]
     580                 :         349 :         r = _bf_program_generate_rule(program,
     581                 :             :                                       bf_list_node_get_data(rule_node));
     582         [ +  + ]:         349 :         if (r)
     583                 :             :             return r;
     584                 :             :     }
     585                 :             : 
     586                 :          97 :     r = program->runtime.ops->gen_inline_epilogue(program);
     587         [ +  - ]:          97 :     if (r)
     588                 :             :         return r;
     589                 :             : 
     590                 :             :     // Call the update counters function
     591                 :             :     /// @todo Allow chains to have no counters at all.
     592         [ -  + ]:          97 :     EMIT(program, BPF_MOV64_REG(BPF_REG_1, BPF_REG_10));
     593         [ -  + ]:          97 :     EMIT(program, BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, BF_PROG_CTX_OFF(arg)));
     594   [ +  -  +  - ]:          97 :     EMIT_LOAD_COUNTERS_FD_FIXUP(program, BPF_REG_2);
     595         [ -  + ]:          97 :     EMIT(program,
     596                 :             :          BPF_MOV32_IMM(BPF_REG_3, bf_program_chain_counter_idx(program)));
     597         [ +  - ]:          97 :     EMIT_FIXUP_ELFSTUB(program, BF_ELFSTUB_UPDATE_COUNTERS);
     598                 :             : 
     599                 :          97 :     r = program->runtime.ops->get_verdict(chain->policy);
     600         [ +  - ]:          97 :     if (r < 0)
     601                 :             :         return r;
     602         [ -  + ]:          97 :     EMIT(program, BPF_MOV64_IMM(BPF_REG_0, r));
     603         [ -  + ]:          97 :     EMIT(program, BPF_EXIT_INSN());
     604                 :             : 
     605                 :          97 :     r = _bf_program_generate_elfstubs(program);
     606         [ +  - ]:          97 :     if (r)
     607                 :             :         return r;
     608                 :             : 
     609                 :          97 :     r = _bf_program_fixup(program, BF_FIXUP_ELFSTUB_CALL);
     610         [ -  + ]:          97 :     if (r)
     611         [ #  # ]:           0 :         return bf_err_r(r, "failed to generate ELF stub call fixups");
     612                 :             : 
     613                 :             :     return 0;
     614                 :             : }
     615                 :             : 
     616                 :          97 : static int _bf_program_load_printer_map(struct bf_program *program)
     617                 :             : {
     618                 :          97 :     _cleanup_free_ void *pstr = NULL;
     619                 :             :     size_t pstr_len;
     620                 :          97 :     uint32_t key = 0;
     621                 :             :     int r;
     622                 :             : 
     623                 :             :     assert(program);
     624                 :             : 
     625                 :          97 :     r = bf_printer_assemble(program->printer, &pstr, &pstr_len);
     626         [ -  + ]:          97 :     if (r)
     627         [ #  # ]:           0 :         return bf_err_r(r, "failed to assemble printer map string");
     628                 :             : 
     629                 :          97 :     r = bf_map_new(&program->handle->pmap, _BF_PRINTER_MAP_NAME,
     630                 :             :                    BF_MAP_TYPE_PRINTER, sizeof(uint32_t), pstr_len, 1);
     631         [ -  + ]:          97 :     if (r)
     632         [ #  # ]:           0 :         return bf_err_r(r, "failed to create the printer bf_map object");
     633                 :             : 
     634                 :          97 :     r = bf_map_set_elem(program->handle->pmap, &key, pstr);
     635         [ -  + ]:          97 :     if (r)
     636         [ #  # ]:           0 :         return bf_err_r(r, "failed to set print map elem");
     637                 :             : 
     638                 :          97 :     r = _bf_program_fixup(program, BF_FIXUP_TYPE_PRINTER_MAP_FD);
     639         [ -  + ]:          97 :     if (r)
     640         [ #  # ]:           0 :         return bf_err_r(r, "failed to fixup printer map FD");
     641                 :             : 
     642                 :             :     return 0;
     643                 :             : }
     644                 :             : 
     645                 :          97 : static int _bf_program_load_counters_map(struct bf_program *program)
     646                 :             : {
     647                 :             :     int r;
     648                 :             : 
     649                 :             :     assert(program);
     650                 :             : 
     651                 :          97 :     r = bf_map_new(&program->handle->cmap, _BF_COUNTER_MAP_NAME,
     652                 :             :                    BF_MAP_TYPE_COUNTERS, sizeof(uint32_t),
     653                 :             :                    sizeof(struct bf_counter),
     654                 :          97 :                    bf_list_size(&program->runtime.chain->rules) + 2);
     655         [ -  + ]:          97 :     if (r)
     656         [ #  # ]:           0 :         return bf_err_r(r, "failed to create the counters bf_map object");
     657                 :             : 
     658                 :          97 :     r = _bf_program_fixup(program, BF_FIXUP_TYPE_COUNTERS_MAP_FD);
     659         [ -  + ]:          97 :     if (r)
     660         [ #  # ]:           0 :         return bf_err_r(r, "failed to fixup counters map FD");
     661                 :             : 
     662                 :             :     return 0;
     663                 :             : }
     664                 :             : 
     665                 :          97 : static int _bf_program_load_log_map(struct bf_program *program)
     666                 :             : {
     667                 :             :     int r;
     668                 :             : 
     669                 :             :     assert(program);
     670                 :             : 
     671                 :             :     // Do not create a log map if it's unused in the chain
     672         [ +  + ]:          97 :     if (!(program->runtime.chain->flags & BF_FLAG(BF_CHAIN_LOG)))
     673                 :             :         return 0;
     674                 :             : 
     675                 :          24 :     r = bf_map_new(&program->handle->lmap, _BF_LOG_MAP_NAME, BF_MAP_TYPE_LOG, 0,
     676                 :             :                    0, _BF_LOG_MAP_SIZE);
     677         [ -  + ]:          24 :     if (r)
     678         [ #  # ]:           0 :         return bf_err_r(r, "failed to create the log bf_map object");
     679                 :             : 
     680                 :          24 :     r = _bf_program_fixup(program, BF_FIXUP_TYPE_LOG_MAP_FD);
     681         [ +  - ]:          24 :     if (r)
     682         [ #  # ]:           0 :         return bf_err_r(r, "failed to fixup log map FD");
     683                 :             : 
     684                 :             :     return 0;
     685                 :             : }
     686                 :             : 
     687                 :          97 : static int _bf_program_load_sets_maps(struct bf_program *new_prog)
     688                 :             : {
     689                 :             :     char name[BPF_OBJ_NAME_LEN];
     690                 :             :     size_t set_idx = 0;
     691                 :             :     int r;
     692                 :             : 
     693                 :             :     assert(new_prog);
     694                 :             : 
     695   [ +  +  +  +  :         406 :     bf_list_foreach (&new_prog->runtime.chain->sets, set_node) {
                   +  + ]
     696                 :             :         struct bf_set *set = bf_list_node_get_data(set_node);
     697         [ +  + ]:         208 :         _free_bf_map_ struct bf_map *map = NULL;
     698                 :             :         _cleanup_free_ uint8_t *values = NULL;
     699                 :             :         _cleanup_free_ uint8_t *keys = NULL;
     700                 :             :         size_t nelems = bf_list_size(&set->elems);
     701                 :             :         size_t idx = 0;
     702                 :             : 
     703         [ +  + ]:         110 :         if (!nelems) {
     704                 :           4 :             r = bf_list_add_tail(&new_prog->handle->sets, NULL);
     705         [ +  - ]:           4 :             if (r)
     706                 :             :                 return r;
     707                 :             :             continue;
     708                 :             :         }
     709                 :             : 
     710                 :         102 :         (void)snprintf(name, BPF_OBJ_NAME_LEN, _BF_SET_MAP_PREFIX "%04x",
     711                 :         102 :                        (uint8_t)set_idx++);
     712                 :         102 :         r = bf_map_new_from_set(&map, name, set);
     713         [ +  - ]:         102 :         if (r)
     714                 :             :             return r;
     715                 :             : 
     716                 :         102 :         values = malloc(nelems);
     717         [ -  + ]:         102 :         if (!values)
     718         [ #  # ]:           0 :             return bf_err_r(-errno, "failed to allocate map values");
     719                 :             : 
     720                 :         102 :         keys = malloc(set->elem_size * nelems);
     721         [ -  + ]:         102 :         if (!keys)
     722         [ #  # ]:           0 :             return bf_err_r(errno, "failed to allocate map keys");
     723                 :             : 
     724   [ +  -  +  + ]:         612 :         bf_list_foreach (&set->elems, elem_node) {
     725                 :             :             void *elem = bf_list_node_get_data(elem_node);
     726                 :             : 
     727                 :         255 :             memcpy(keys + (idx * set->elem_size), elem, set->elem_size);
     728                 :         255 :             values[idx] = 1;
     729         [ +  + ]:         255 :             ++idx;
     730                 :             :         }
     731                 :             : 
     732                 :         102 :         r = bf_bpf_map_update_batch(map->fd, keys, values, nelems, BPF_ANY);
     733         [ -  + ]:         102 :         if (r)
     734         [ #  # ]:           0 :             return bf_err_r(r, "failed to add set elements to the map");
     735                 :             : 
     736                 :         102 :         r = bf_list_push(&new_prog->handle->sets, (void **)&map);
     737         [ +  - ]:         102 :         if (r)
     738                 :             :             return r;
     739                 :             :     };
     740                 :             : 
     741                 :          97 :     r = _bf_program_fixup(new_prog, BF_FIXUP_TYPE_SET_MAP_FD);
     742                 :             :     if (r)
     743                 :             :         return r;
     744                 :             : 
     745                 :             :     return 0;
     746                 :             : }
     747                 :             : 
     748                 :          97 : int bf_program_load(struct bf_program *prog)
     749                 :             : {
     750                 :             :     _cleanup_free_ char *log_buf = NULL;
     751                 :             :     int r;
     752                 :             : 
     753                 :             :     assert(prog);
     754                 :             : 
     755                 :          97 :     r = _bf_program_load_sets_maps(prog);
     756         [ -  + ]:          97 :     if (r)
     757         [ #  # ]:           0 :         return bf_err_r(r, "failed to load the sets map");
     758                 :             : 
     759                 :          97 :     r = _bf_program_load_counters_map(prog);
     760         [ -  + ]:          97 :     if (r)
     761         [ #  # ]:           0 :         return bf_err_r(r, "failed to load the counter map");
     762                 :             : 
     763                 :          97 :     r = _bf_program_load_printer_map(prog);
     764         [ -  + ]:          97 :     if (r)
     765         [ #  # ]:           0 :         return bf_err_r(r, "failed to load the printer map");
     766                 :             : 
     767                 :          97 :     r = _bf_program_load_log_map(prog);
     768         [ -  + ]:          97 :     if (r)
     769         [ #  # ]:           0 :         return bf_err_r(r, "failed to load the log map");
     770                 :             : 
     771         [ +  - ]:          97 :     if (bf_ctx_is_verbose(BF_VERBOSE_DEBUG)) {
     772                 :          97 :         log_buf = malloc(_BF_LOG_BUF_SIZE);
     773         [ -  + ]:          97 :         if (!log_buf) {
     774         [ #  # ]:           0 :             return bf_err_r(-ENOMEM,
     775                 :             :                             "failed to allocate BPF_PROG_LOAD logs buffer");
     776                 :             :         }
     777                 :             :     }
     778                 :             : 
     779         [ -  + ]:          97 :     if (bf_ctx_is_verbose(BF_VERBOSE_BYTECODE))
     780                 :           0 :         bf_program_dump_bytecode(prog);
     781                 :             : 
     782         [ -  + ]:         194 :     r = bf_bpf_prog_load(prog->handle->prog_name,
     783                 :          97 :                          bf_hook_to_bpf_prog_type(prog->runtime.chain->hook),
     784                 :          97 :                          prog->img, prog->img_size,
     785                 :          97 :                          bf_hook_to_bpf_attach_type(prog->runtime.chain->hook),
     786                 :             :                          log_buf, log_buf ? _BF_LOG_BUF_SIZE : 0,
     787                 :          97 :                          bf_ctx_token(), &prog->handle->prog_fd);
     788         [ -  + ]:          97 :     if (r) {
     789   [ #  #  #  # ]:           0 :         return bf_err_r(r, "failed to load bf_program (%lu bytes):\n%s\nerrno:",
     790                 :             :                         prog->img_size, log_buf ? log_buf : "<NO LOG BUFFER>");
     791                 :             :     }
     792                 :             : 
     793                 :             :     return r;
     794                 :             : }
     795                 :             : 
     796                 :           0 : int bf_program_get_counter(const struct bf_program *program,
     797                 :             :                            uint32_t counter_idx, struct bf_counter *counter)
     798                 :             : {
     799                 :             :     assert(program);
     800                 :             :     assert(counter);
     801                 :             : 
     802                 :           0 :     return bf_handle_get_counter(program->handle, counter_idx, counter);
     803                 :             : }
     804                 :             : 
     805                 :           0 : int bf_cgen_set_counters(struct bf_program *program,
     806                 :             :                          const struct bf_counter *counters)
     807                 :             : {
     808                 :             :     (void)program;
     809                 :             :     (void)counters;
     810                 :             : 
     811                 :           0 :     return -ENOTSUP;
     812                 :             : }
     813                 :             : 
     814                 :          97 : size_t bf_program_chain_counter_idx(const struct bf_program *program)
     815                 :             : {
     816                 :          97 :     return bf_list_size(&program->runtime.chain->rules);
     817                 :             : }
     818                 :             : 
     819                 :         379 : size_t bf_program_error_counter_idx(const struct bf_program *program)
     820                 :             : {
     821                 :         379 :     return bf_list_size(&program->runtime.chain->rules) + 1;
     822                 :             : }
        

Generated by: LCOV version 2.0-1