LCOV - code coverage report
Current view: top level - bpfilter/cgen - program.c (source / functions) Coverage Total Hit
Test: lcov.out Lines: 9.4 % 586 55
Test Date: 2025-09-30 16:37:25 Functions: 16.1 % 31 5

            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.h"
      40              : #include "cgen/dump.h"
      41              : #include "cgen/fixup.h"
      42              : #include "cgen/jmp.h"
      43              : #include "cgen/matcher/icmp.h"
      44              : #include "cgen/matcher/ip4.h"
      45              : #include "cgen/matcher/ip6.h"
      46              : #include "cgen/matcher/meta.h"
      47              : #include "cgen/matcher/set.h"
      48              : #include "cgen/matcher/tcp.h"
      49              : #include "cgen/matcher/udp.h"
      50              : #include "cgen/nf.h"
      51              : #include "cgen/printer.h"
      52              : #include "cgen/prog/link.h"
      53              : #include "cgen/prog/map.h"
      54              : #include "cgen/stub.h"
      55              : #include "cgen/tc.h"
      56              : #include "cgen/xdp.h"
      57              : #include "ctx.h"
      58              : #include "filter.h"
      59              : #include "opts.h"
      60              : 
      61              : #define _BF_LOG_BUF_SIZE                                                       \
      62              :     (UINT32_MAX >> 8) /* verifier maximum in kernels <= 5.1 */
      63              : #define _BF_PROGRAM_DEFAULT_IMG_SIZE (1 << 6)
      64              : #define _BF_LOG_MAP_N_ENTRIES 1000
      65              : #define _BF_LOG_MAP_SIZE                                                       \
      66              :     _bf_round_next_power_of_2(sizeof(struct bf_log) * _BF_LOG_MAP_N_ENTRIES)
      67              : 
      68            0 : static inline size_t _bf_round_next_power_of_2(size_t value)
      69              : {
      70            0 :     value--;
      71            0 :     value |= value >> 1;
      72            0 :     value |= value >> 2;
      73            0 :     value |= value >> 4;
      74            0 :     value |= value >> 8;
      75            0 :     value |= value >> 16;
      76              : 
      77            0 :     return ++value;
      78              : }
      79              : 
      80            7 : static const struct bf_flavor_ops *bf_flavor_ops_get(enum bf_flavor flavor)
      81              : {
      82              :     static const struct bf_flavor_ops *flavor_ops[] = {
      83              :         [BF_FLAVOR_TC] = &bf_flavor_ops_tc,
      84              :         [BF_FLAVOR_NF] = &bf_flavor_ops_nf,
      85              :         [BF_FLAVOR_XDP] = &bf_flavor_ops_xdp,
      86              :         [BF_FLAVOR_CGROUP] = &bf_flavor_ops_cgroup,
      87              :     };
      88              : 
      89              :     static_assert(ARRAY_SIZE(flavor_ops) == _BF_FLAVOR_MAX,
      90              :                   "missing entries in bf_flavor_ops array");
      91              : 
      92            7 :     return flavor_ops[flavor];
      93              : }
      94              : 
      95            3 : int bf_program_new(struct bf_program **program, const struct bf_chain *chain)
      96              : {
      97            3 :     _free_bf_program_ struct bf_program *_program = NULL;
      98              :     char name[BPF_OBJ_NAME_LEN];
      99              :     uint32_t set_idx = 0;
     100              :     int r;
     101              : 
     102            3 :     bf_assert(program && chain);
     103              : 
     104            3 :     _program = calloc(1, sizeof(*_program));
     105            3 :     if (!_program)
     106              :         return -ENOMEM;
     107              : 
     108            3 :     _program->flavor = bf_hook_to_flavor(chain->hook);
     109            3 :     _program->runtime.prog_fd = -1;
     110            3 :     _program->runtime.ops = bf_flavor_ops_get(_program->flavor);
     111            3 :     _program->runtime.chain = chain;
     112              : 
     113            3 :     (void)snprintf(_program->prog_name, BPF_OBJ_NAME_LEN, "%s", "bf_prog");
     114              : 
     115            3 :     r = bf_map_new(&_program->cmap, "counters_map", BF_MAP_TYPE_COUNTERS,
     116              :                    sizeof(uint32_t), sizeof(struct bf_counter), 1);
     117            3 :     if (r < 0)
     118            0 :         return bf_err_r(r, "failed to create the counters bf_map object");
     119              : 
     120            3 :     r = bf_map_new(&_program->pmap, "printer_map", BF_MAP_TYPE_PRINTER,
     121              :                    sizeof(uint32_t), BF_MAP_VALUE_SIZE_UNKNOWN, 1);
     122            3 :     if (r < 0)
     123            0 :         return bf_err_r(r, "failed to create the printer bf_map object");
     124              : 
     125            3 :     r = bf_map_new(&_program->lmap, "log_map", BF_MAP_TYPE_LOG, 0, 0,
     126              :                    _BF_LOG_MAP_SIZE);
     127            3 :     if (r < 0)
     128            0 :         return bf_err_r(r, "failed to create the log bf_map object");
     129              : 
     130            3 :     _program->sets = bf_list_default(bf_map_free, bf_map_pack);
     131            6 :     bf_list_foreach (&chain->sets, set_node) {
     132            0 :         struct bf_set *set = bf_list_node_get_data(set_node);
     133            0 :         _free_bf_map_ struct bf_map *map = NULL;
     134              : 
     135            0 :         (void)snprintf(name, BPF_OBJ_NAME_LEN, "set_%04x", (uint8_t)set_idx++);
     136            0 :         r = bf_map_new_from_set(&map, name, set);
     137            0 :         if (r < 0)
     138              :             return r;
     139              : 
     140            0 :         r = bf_list_add_tail(&_program->sets, map);
     141            0 :         if (r < 0)
     142              :             return r;
     143            0 :         TAKE_PTR(map);
     144              :     };
     145              : 
     146            3 :     r = bf_link_new(&_program->link, "bf_link");
     147            3 :     if (r)
     148              :         return r;
     149              : 
     150            3 :     r = bf_printer_new(&_program->printer);
     151            3 :     if (r)
     152              :         return r;
     153              : 
     154            3 :     bf_list_init(&_program->fixups,
     155            3 :                  (bf_list_ops[]) {{.free = (bf_list_ops_free)bf_fixup_free}});
     156              : 
     157            3 :     *program = TAKE_PTR(_program);
     158              : 
     159            3 :     return 0;
     160              : }
     161              : 
     162            0 : int bf_program_new_from_pack(struct bf_program **program,
     163              :                              const struct bf_chain *chain, int dir_fd,
     164              :                              bf_rpack_node_t node)
     165              : {
     166            0 :     _free_bf_program_ struct bf_program *_program = NULL;
     167            0 :     _free_bf_link_ struct bf_link *link = NULL;
     168              :     const void *img;
     169              :     size_t img_len;
     170              :     bf_rpack_node_t child, array_node;
     171              :     int r;
     172              : 
     173            0 :     bf_assert(program);
     174            0 :     bf_assert(chain);
     175              : 
     176            0 :     r = bf_program_new(&_program, chain);
     177            0 :     if (r < 0)
     178              :         return r;
     179              : 
     180            0 :     bf_map_free(&_program->cmap);
     181            0 :     r = bf_rpack_kv_obj(node, "cmap", &child);
     182            0 :     if (r)
     183            0 :         return bf_rpack_key_err(r, "bf_program.cmap");
     184            0 :     r = bf_map_new_from_pack(&_program->cmap, dir_fd, child);
     185            0 :     if (r)
     186              :         return r;
     187              : 
     188            0 :     bf_map_free(&_program->pmap);
     189            0 :     r = bf_rpack_kv_obj(node, "pmap", &child);
     190            0 :     if (r)
     191            0 :         return bf_rpack_key_err(r, "bf_program.pmap");
     192            0 :     r = bf_map_new_from_pack(&_program->pmap, dir_fd, child);
     193            0 :     if (r)
     194              :         return r;
     195              : 
     196            0 :     bf_map_free(&_program->lmap);
     197            0 :     r = bf_rpack_kv_obj(node, "lmap", &child);
     198            0 :     if (r)
     199            0 :         return bf_rpack_key_err(r, "bf_program.lmap");
     200            0 :     r = bf_map_new_from_pack(&_program->lmap, dir_fd, child);
     201            0 :     if (r)
     202              :         return r;
     203              : 
     204            0 :     bf_list_clean(&_program->sets);
     205            0 :     _program->sets = bf_list_default(bf_map_free, bf_map_pack);
     206            0 :     r = bf_rpack_kv_array(node, "sets", &child);
     207            0 :     if (r)
     208            0 :         return bf_rpack_key_err(r, "bf_program.sets");
     209            0 :     bf_rpack_array_foreach (child, array_node) {
     210            0 :         _free_bf_map_ struct bf_map *map = NULL;
     211              : 
     212            0 :         r = bf_list_emplace(&_program->sets, bf_map_new_from_pack, map, dir_fd,
     213              :                             array_node);
     214              :         if (r)
     215            0 :             return bf_err_r(r, "failed to unpack bf_map into bf_program.sets");
     216              :     }
     217              : 
     218              :     /* Try to restore the link: on success, replace the program's link with the
     219              :      * restored on. If -ENOENT is returned, the link doesn't exist, meaning the
     220              :      * program is not attached. Otherwise, return an error. */
     221            0 :     r = bf_rpack_kv_obj(node, "link", &child);
     222            0 :     if (r)
     223            0 :         return bf_rpack_key_err(r, "bf_program.link");
     224            0 :     r = bf_link_new_from_pack(&link, dir_fd, child);
     225            0 :     if (!r)
     226            0 :         bf_swap(_program->link, link);
     227            0 :     else if (r != -ENOENT)
     228            0 :         return bf_err_r(r, "failed to restore bf_program.link");
     229              : 
     230            0 :     bf_printer_free(&_program->printer);
     231            0 :     r = bf_rpack_kv_obj(node, "printer", &child);
     232            0 :     if (r)
     233            0 :         return bf_rpack_key_err(r, "bf_program.printer");
     234            0 :     r = bf_printer_new_from_pack(&_program->printer, child);
     235            0 :     if (r)
     236              :         return r;
     237              : 
     238            0 :     r = bf_rpack_kv_bin(node, "img", &img, &img_len);
     239            0 :     if (r)
     240            0 :         return bf_rpack_key_err(r, "bf_program.img");
     241            0 :     _program->img = bf_memdup(img, img_len);
     242            0 :     if (!_program->img)
     243            0 :         return bf_rpack_key_err(-ENOMEM, "bf_program.img");
     244            0 :     _program->img_size = img_len / sizeof(struct bpf_insn);
     245            0 :     _program->img_cap = _program->img_size;
     246              : 
     247            0 :     r = bf_bpf_obj_get(_program->prog_name, dir_fd, &_program->runtime.prog_fd);
     248            0 :     if (r < 0)
     249            0 :         return bf_err_r(r, "failed to restore bf_program.fd");
     250              : 
     251            0 :     *program = TAKE_PTR(_program);
     252              : 
     253            0 :     return 0;
     254              : }
     255              : 
     256           14 : void bf_program_free(struct bf_program **program)
     257              : {
     258           14 :     if (!*program)
     259              :         return;
     260              : 
     261            3 :     bf_list_clean(&(*program)->fixups);
     262            3 :     free((*program)->img);
     263              : 
     264              :     /* Close the file descriptors if they are still open. If --transient is
     265              :      * used, then the file descriptors are already closed (as
     266              :      * bf_program_unload() has been called). Otherwise, bf_program_unload()
     267              :      * won't be called, but the programs are pinned, so they can be closed
     268              :      * safely. */
     269            3 :     closep(&(*program)->runtime.prog_fd);
     270              : 
     271            3 :     bf_map_free(&(*program)->cmap);
     272            3 :     bf_map_free(&(*program)->pmap);
     273            3 :     bf_map_free(&(*program)->lmap);
     274            3 :     bf_list_clean(&(*program)->sets);
     275            3 :     bf_link_free(&(*program)->link);
     276            3 :     bf_printer_free(&(*program)->printer);
     277              : 
     278            3 :     free(*program);
     279            3 :     *program = NULL;
     280              : }
     281              : 
     282            0 : int bf_program_pack(const struct bf_program *program, bf_wpack_t *pack)
     283              : {
     284            0 :     bf_assert(program);
     285            0 :     bf_assert(pack);
     286              : 
     287            0 :     bf_wpack_open_object(pack, "cmap");
     288            0 :     bf_map_pack(program->cmap, pack);
     289            0 :     bf_wpack_close_object(pack);
     290              : 
     291            0 :     bf_wpack_open_object(pack, "pmap");
     292            0 :     bf_map_pack(program->pmap, pack);
     293            0 :     bf_wpack_close_object(pack);
     294              : 
     295            0 :     bf_wpack_open_object(pack, "lmap");
     296            0 :     bf_map_pack(program->lmap, pack);
     297            0 :     bf_wpack_close_object(pack);
     298              : 
     299            0 :     bf_wpack_kv_list(pack, "sets", &program->sets);
     300              : 
     301            0 :     bf_wpack_open_object(pack, "link");
     302            0 :     bf_link_pack(program->link, pack);
     303            0 :     bf_wpack_close_object(pack);
     304              : 
     305            0 :     bf_wpack_open_object(pack, "printer");
     306            0 :     bf_printer_pack(program->printer, pack);
     307            0 :     bf_wpack_close_object(pack);
     308              : 
     309            0 :     bf_wpack_kv_bin(pack, "img", program->img,
     310            0 :                     program->img_size * sizeof(struct bpf_insn));
     311              : 
     312            0 :     return bf_wpack_is_valid(pack) ? 0 : -EINVAL;
     313              : }
     314              : 
     315            0 : void bf_program_dump(const struct bf_program *program, prefix_t *prefix)
     316              : {
     317            0 :     bf_assert(program);
     318            0 :     bf_assert(prefix);
     319              : 
     320            0 :     DUMP(prefix, "struct bf_program at %p", program);
     321              : 
     322            0 :     bf_dump_prefix_push(prefix);
     323              : 
     324            0 :     DUMP(prefix, "prog_name: %s", program->prog_name);
     325              : 
     326            0 :     DUMP(prefix, "cmap: struct bf_map *");
     327            0 :     bf_dump_prefix_push(prefix);
     328            0 :     bf_map_dump(program->cmap, bf_dump_prefix_last(prefix));
     329            0 :     bf_dump_prefix_pop(prefix);
     330              : 
     331            0 :     DUMP(prefix, "pmap: struct bf_map *");
     332            0 :     bf_dump_prefix_push(prefix);
     333            0 :     bf_map_dump(program->pmap, bf_dump_prefix_last(prefix));
     334            0 :     bf_dump_prefix_pop(prefix);
     335              : 
     336            0 :     DUMP(prefix, "lmap: struct bf_map *");
     337            0 :     bf_dump_prefix_push(prefix);
     338            0 :     bf_map_dump(program->lmap, bf_dump_prefix_last(prefix));
     339            0 :     bf_dump_prefix_pop(prefix);
     340              : 
     341            0 :     DUMP(prefix, "sets: bf_list<bf_map>[%lu]", bf_list_size(&program->sets));
     342            0 :     bf_dump_prefix_push(prefix);
     343            0 :     bf_list_foreach (&program->sets, map_node) {
     344            0 :         struct bf_map *map = bf_list_node_get_data(map_node);
     345              : 
     346            0 :         if (bf_list_is_tail(&program->sets, map_node))
     347            0 :             bf_dump_prefix_last(prefix);
     348              : 
     349            0 :         bf_map_dump(map, prefix);
     350              :     }
     351            0 :     bf_dump_prefix_pop(prefix);
     352              : 
     353            0 :     DUMP(prefix, "link: struct bf_link *");
     354            0 :     bf_dump_prefix_push(prefix);
     355            0 :     bf_link_dump(program->link, prefix);
     356            0 :     bf_dump_prefix_pop(prefix);
     357              : 
     358            0 :     DUMP(prefix, "printer: struct bf_printer *");
     359            0 :     bf_dump_prefix_push(prefix);
     360            0 :     bf_printer_dump(program->printer, prefix);
     361            0 :     bf_dump_prefix_pop(prefix);
     362              : 
     363            0 :     DUMP(prefix, "img: %p", program->img);
     364            0 :     DUMP(prefix, "img_size: %lu", program->img_size);
     365            0 :     DUMP(prefix, "img_cap: %lu", program->img_cap);
     366              : 
     367            0 :     DUMP(prefix, "fixups: bf_list<struct bf_fixup>[%lu]",
     368              :          bf_list_size(&program->fixups));
     369            0 :     bf_dump_prefix_push(prefix);
     370            0 :     bf_list_foreach (&program->fixups, fixup_node) {
     371            0 :         struct bf_fixup *fixup = bf_list_node_get_data(fixup_node);
     372              : 
     373            0 :         if (bf_list_is_tail(&program->fixups, fixup_node))
     374            0 :             bf_dump_prefix_last(prefix);
     375              : 
     376            0 :         bf_fixup_dump(fixup, prefix);
     377              :     }
     378            0 :     bf_dump_prefix_pop(prefix);
     379              : 
     380            0 :     DUMP(bf_dump_prefix_last(prefix), "runtime: <anonymous>");
     381            0 :     bf_dump_prefix_push(prefix);
     382            0 :     DUMP(prefix, "prog_fd: %d", program->runtime.prog_fd);
     383            0 :     DUMP(bf_dump_prefix_last(prefix), "ops: %p", program->runtime.ops);
     384            0 :     bf_dump_prefix_pop(prefix);
     385              : 
     386            0 :     bf_dump_prefix_pop(prefix);
     387            0 : }
     388              : 
     389            3 : int bf_program_grow_img(struct bf_program *program)
     390              : {
     391              :     size_t new_cap = _BF_PROGRAM_DEFAULT_IMG_SIZE;
     392              :     int r;
     393              : 
     394            3 :     bf_assert(program);
     395              : 
     396            3 :     if (program->img)
     397            0 :         new_cap = _bf_round_next_power_of_2(program->img_cap << 1);
     398              : 
     399            3 :     r = bf_realloc((void **)&program->img, new_cap * sizeof(struct bpf_insn));
     400            3 :     if (r < 0) {
     401            0 :         return bf_err_r(r, "failed to grow program img from %lu to %lu insn",
     402              :                         program->img_cap, new_cap);
     403              :     }
     404              : 
     405            3 :     program->img_cap = new_cap;
     406              : 
     407            3 :     return 0;
     408              : }
     409              : 
     410            0 : static void _bf_program_fixup_insn(struct bpf_insn *insn,
     411              :                                    enum bf_fixup_insn type, int32_t value)
     412              : {
     413            0 :     switch (type) {
     414            0 :     case BF_FIXUP_INSN_OFF:
     415            0 :         bf_assert(!insn->off);
     416            0 :         bf_assert(value < SHRT_MAX);
     417            0 :         insn->off = (int16_t)value;
     418            0 :         break;
     419            0 :     case BF_FIXUP_INSN_IMM:
     420            0 :         bf_assert(!insn->imm);
     421            0 :         insn->imm = value;
     422            0 :         break;
     423            0 :     default:
     424            0 :         bf_abort(
     425              :             "unsupported fixup instruction type, this should not happen: %d",
     426              :             type);
     427              :         break;
     428              :     }
     429            0 : }
     430              : 
     431            0 : static int _bf_program_fixup(struct bf_program *program,
     432              :                              enum bf_fixup_type type)
     433              : {
     434            0 :     bf_assert(program);
     435            0 :     bf_assert(type >= 0 && type < _BF_FIXUP_TYPE_MAX);
     436              : 
     437            0 :     bf_list_foreach (&program->fixups, fixup_node) {
     438              :         enum bf_fixup_insn insn_type = _BF_FIXUP_INSN_MAX;
     439              :         int32_t value;
     440              :         size_t offset;
     441            0 :         struct bf_fixup *fixup = bf_list_node_get_data(fixup_node);
     442            0 :         struct bpf_insn *insn = &program->img[fixup->insn];
     443              :         struct bf_map *map;
     444              : 
     445            0 :         if (type != fixup->type)
     446            0 :             continue;
     447              : 
     448            0 :         switch (type) {
     449            0 :         case BF_FIXUP_TYPE_JMP_NEXT_RULE:
     450              :             insn_type = BF_FIXUP_INSN_OFF;
     451            0 :             value = (int)(program->img_size - fixup->insn - 1U);
     452            0 :             break;
     453            0 :         case BF_FIXUP_TYPE_COUNTERS_MAP_FD:
     454              :             insn_type = BF_FIXUP_INSN_IMM;
     455            0 :             value = program->cmap->fd;
     456            0 :             break;
     457            0 :         case BF_FIXUP_TYPE_PRINTER_MAP_FD:
     458              :             insn_type = BF_FIXUP_INSN_IMM;
     459            0 :             value = program->pmap->fd;
     460            0 :             break;
     461            0 :         case BF_FIXUP_TYPE_LOG_MAP_FD:
     462              :             insn_type = BF_FIXUP_INSN_IMM;
     463            0 :             value = program->lmap->fd;
     464            0 :             break;
     465            0 :         case BF_FIXUP_TYPE_SET_MAP_FD:
     466            0 :             map = bf_list_get_at(&program->sets, fixup->attr.set_index);
     467            0 :             if (!map) {
     468            0 :                 return bf_err_r(-ENOENT, "can't find set map at index %lu",
     469              :                                 fixup->attr.set_index);
     470              :             }
     471              :             insn_type = BF_FIXUP_INSN_IMM;
     472            0 :             value = map->fd;
     473            0 :             break;
     474            0 :         case BF_FIXUP_ELFSTUB_CALL:
     475              :             insn_type = BF_FIXUP_INSN_IMM;
     476            0 :             offset = program->elfstubs_location[fixup->attr.elfstub_id] -
     477              :                      fixup->insn - 1;
     478            0 :             if (offset >= INT_MAX)
     479            0 :                 return bf_err_r(-EINVAL, "invalid ELF stub call offset");
     480            0 :             value = (int32_t)offset;
     481            0 :             break;
     482            0 :         default:
     483            0 :             bf_abort("unsupported fixup type, this should not happen: %d",
     484              :                      type);
     485              :             break;
     486              :         }
     487              : 
     488            0 :         _bf_program_fixup_insn(insn, insn_type, value);
     489            0 :         bf_list_delete(&program->fixups, fixup_node);
     490              :     }
     491              : 
     492              :     return 0;
     493              : }
     494              : 
     495            0 : static int _bf_program_generate_rule(struct bf_program *program,
     496              :                                      struct bf_rule *rule)
     497              : {
     498              :     int r;
     499              : 
     500            0 :     bf_assert(program);
     501            0 :     bf_assert(rule);
     502              : 
     503            0 :     bf_list_foreach (&rule->matchers, matcher_node) {
     504            0 :         struct bf_matcher *matcher = bf_list_node_get_data(matcher_node);
     505              : 
     506            0 :         switch (bf_matcher_get_type(matcher)) {
     507            0 :         case BF_MATCHER_META_IFACE:
     508              :         case BF_MATCHER_META_L3_PROTO:
     509              :         case BF_MATCHER_META_L4_PROTO:
     510              :         case BF_MATCHER_META_PROBABILITY:
     511              :         case BF_MATCHER_META_SPORT:
     512              :         case BF_MATCHER_META_DPORT:
     513              :         case BF_MATCHER_META_MARK:
     514            0 :             r = bf_matcher_generate_meta(program, matcher);
     515            0 :             if (r)
     516              :                 return r;
     517              :             break;
     518            0 :         case BF_MATCHER_IP4_SADDR:
     519              :         case BF_MATCHER_IP4_SNET:
     520              :         case BF_MATCHER_IP4_DADDR:
     521              :         case BF_MATCHER_IP4_DNET:
     522              :         case BF_MATCHER_IP4_PROTO:
     523            0 :             r = bf_matcher_generate_ip4(program, matcher);
     524            0 :             if (r)
     525              :                 return r;
     526              :             break;
     527            0 :         case BF_MATCHER_IP6_SADDR:
     528              :         case BF_MATCHER_IP6_SNET:
     529              :         case BF_MATCHER_IP6_DADDR:
     530              :         case BF_MATCHER_IP6_DNET:
     531              :         case BF_MATCHER_IP6_NEXTHDR:
     532            0 :             r = bf_matcher_generate_ip6(program, matcher);
     533            0 :             if (r)
     534              :                 return r;
     535              :             break;
     536            0 :         case BF_MATCHER_TCP_SPORT:
     537              :         case BF_MATCHER_TCP_DPORT:
     538              :         case BF_MATCHER_TCP_FLAGS:
     539            0 :             r = bf_matcher_generate_tcp(program, matcher);
     540            0 :             if (r)
     541              :                 return r;
     542              :             break;
     543            0 :         case BF_MATCHER_UDP_SPORT:
     544              :         case BF_MATCHER_UDP_DPORT:
     545            0 :             r = bf_matcher_generate_udp(program, matcher);
     546            0 :             if (r)
     547              :                 return r;
     548              :             break;
     549            0 :         case BF_MATCHER_ICMP_TYPE:
     550              :         case BF_MATCHER_ICMP_CODE:
     551              :         case BF_MATCHER_ICMPV6_TYPE:
     552              :         case BF_MATCHER_ICMPV6_CODE:
     553            0 :             r = bf_matcher_generate_icmp(program, matcher);
     554            0 :             if (r)
     555              :                 return r;
     556              :             break;
     557            0 :         case BF_MATCHER_SET:
     558            0 :             r = bf_matcher_generate_set(program, matcher);
     559            0 :             if (r)
     560              :                 return r;
     561              :             break;
     562            0 :         default:
     563            0 :             return bf_err_r(-EINVAL, "unknown matcher type %d",
     564              :                             bf_matcher_get_type(matcher));
     565              :         };
     566              :     }
     567              : 
     568            0 :     if (bf_rule_mark_is_set(rule)) {
     569            0 :         if (!program->runtime.ops->gen_inline_set_mark) {
     570            0 :             return bf_err_r(-ENOTSUP, "set mark is not supported by %s",
     571              :                             program->runtime.chain->name);
     572              :         }
     573              : 
     574            0 :         r = program->runtime.ops->gen_inline_set_mark(program,
     575              :                                                       bf_rule_mark_get(rule));
     576            0 :         if (r) {
     577            0 :             return bf_err_r(r,
     578              :                             "failed to generate bytecode to set mark for '%s'",
     579              :                             program->runtime.chain->name);
     580              :         }
     581              :     }
     582              : 
     583            0 :     if (rule->log) {
     584            0 :         EMIT(program, BPF_MOV64_REG(BPF_REG_1, BPF_REG_10));
     585            0 :         EMIT(program, BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, BF_PROG_CTX_OFF(arg)));
     586            0 :         EMIT(program, BPF_MOV64_IMM(BPF_REG_2, rule->index));
     587            0 :         EMIT(program, BPF_MOV64_IMM(BPF_REG_3, rule->log));
     588            0 :         EMIT(program, BPF_MOV64_REG(BPF_REG_4, BPF_REG_7));
     589            0 :         EMIT(program, BPF_MOV64_REG(BPF_REG_5, BPF_REG_8));
     590              : 
     591            0 :         EMIT_FIXUP_ELFSTUB(program, BF_ELFSTUB_LOG);
     592              :     }
     593              : 
     594            0 :     if (rule->counters) {
     595            0 :         EMIT(program, BPF_MOV64_REG(BPF_REG_1, BPF_REG_10));
     596            0 :         EMIT(program, BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, BF_PROG_CTX_OFF(arg)));
     597            0 :         EMIT_LOAD_COUNTERS_FD_FIXUP(program, BPF_REG_2);
     598            0 :         EMIT(program, BPF_MOV32_IMM(BPF_REG_3, rule->index));
     599            0 :         EMIT_FIXUP_ELFSTUB(program, BF_ELFSTUB_UPDATE_COUNTERS);
     600              :     }
     601              : 
     602            0 :     switch (rule->verdict) {
     603            0 :     case BF_VERDICT_ACCEPT:
     604              :     case BF_VERDICT_DROP:
     605            0 :         EMIT(program,
     606              :              BPF_MOV64_IMM(BPF_REG_0,
     607              :                            program->runtime.ops->get_verdict(rule->verdict)));
     608            0 :         EMIT(program, BPF_EXIT_INSN());
     609            0 :         break;
     610              :     case BF_VERDICT_CONTINUE:
     611              :         // Fall through to next rule or default chain policy.
     612              :         break;
     613            0 :     default:
     614            0 :         bf_abort("unsupported verdict, this should not happen: %d",
     615              :                  rule->verdict);
     616              :         break;
     617              :     }
     618              : 
     619            0 :     r = _bf_program_fixup(program, BF_FIXUP_TYPE_JMP_NEXT_RULE);
     620            0 :     if (r)
     621            0 :         return bf_err_r(r, "failed to generate next rule fixups");
     622              : 
     623              :     return 0;
     624              : }
     625              : 
     626            0 : static int _bf_program_generate_elfstubs(struct bf_program *program)
     627              : {
     628              :     const struct bf_elfstub *elfstub;
     629              :     size_t start_at;
     630              :     int r;
     631              : 
     632            0 :     bf_assert(program);
     633              : 
     634            0 :     bf_list_foreach (&program->fixups, fixup_node) {
     635            0 :         struct bf_fixup *fixup = bf_list_node_get_data(fixup_node);
     636            0 :         size_t off = program->img_size;
     637              : 
     638            0 :         if (fixup->type != BF_FIXUP_ELFSTUB_CALL)
     639            0 :             continue;
     640              : 
     641              :         // Only generate each ELF stub once
     642            0 :         if (program->elfstubs_location[fixup->attr.elfstub_id])
     643            0 :             continue;
     644              : 
     645            0 :         bf_dbg("generate ELF stub for ID %d", fixup->attr.elfstub_id);
     646              : 
     647            0 :         elfstub = bf_ctx_get_elfstub(fixup->attr.elfstub_id);
     648            0 :         if (!elfstub) {
     649            0 :             return bf_err_r(-ENOENT, "no ELF stub found for ID %d",
     650              :                             fixup->attr.elfstub_id);
     651              :         }
     652              : 
     653            0 :         start_at = program->img_size;
     654              : 
     655            0 :         for (size_t i = 0; i < elfstub->ninsns; ++i) {
     656            0 :             r = bf_program_emit(program, elfstub->insns[i]);
     657            0 :             if (r)
     658            0 :                 return bf_err_r(r, "failed to insert ELF stub instruction");
     659              :         }
     660              : 
     661            0 :         bf_list_foreach (&elfstub->strs, pstr_node) {
     662            0 :             _free_bf_fixup_ struct bf_fixup *fixup = NULL;
     663            0 :             struct bf_printk_str *pstr = bf_list_node_get_data(pstr_node);
     664            0 :             size_t insn_idx = start_at + pstr->insn_idx;
     665              :             const struct bf_printer_msg *msg =
     666            0 :                 bf_printer_add_msg(program->printer, pstr->str);
     667              :             struct bpf_insn ld_insn[2] = {
     668              :                 BPF_LD_MAP_FD(BPF_REG_1, 0),
     669              :             };
     670              : 
     671              :             ld_insn[0].src_reg = BPF_PSEUDO_MAP_VALUE;
     672            0 :             ld_insn[1].imm = (int)bf_printer_msg_offset(msg);
     673              : 
     674            0 :             program->img[insn_idx] = ld_insn[0];
     675            0 :             program->img[insn_idx + 1] = ld_insn[1];
     676              : 
     677            0 :             r = bf_fixup_new(&fixup, BF_FIXUP_TYPE_PRINTER_MAP_FD, insn_idx,
     678              :                              NULL);
     679            0 :             if (r)
     680              :                 return r;
     681              : 
     682            0 :             r = bf_list_add_tail(&program->fixups, fixup);
     683            0 :             if (r)
     684              :                 return r;
     685              : 
     686            0 :             TAKE_PTR(fixup);
     687              :         }
     688              : 
     689            0 :         program->elfstubs_location[fixup->attr.elfstub_id] = off;
     690              :     }
     691              : 
     692              :     return 0;
     693              : }
     694              : 
     695           40 : int bf_program_emit(struct bf_program *program, struct bpf_insn insn)
     696              : {
     697              :     int r;
     698              : 
     699           40 :     bf_assert(program);
     700              : 
     701           40 :     if (program->img_size == program->img_cap) {
     702            3 :         r = bf_program_grow_img(program);
     703            3 :         if (r)
     704              :             return r;
     705              :     }
     706              : 
     707           40 :     program->img[program->img_size++] = insn;
     708              : 
     709           40 :     return 0;
     710              : }
     711              : 
     712            0 : int bf_program_emit_kfunc_call(struct bf_program *program, const char *name)
     713              : {
     714              :     int r;
     715              : 
     716            0 :     bf_assert(program);
     717            0 :     bf_assert(name);
     718              : 
     719            0 :     r = bf_btf_get_id(name);
     720            0 :     if (r < 0)
     721              :         return r;
     722              : 
     723            0 :     EMIT(program, ((struct bpf_insn) {.code = BPF_JMP | BPF_CALL,
     724              :                                       .dst_reg = 0,
     725              :                                       .src_reg = BPF_PSEUDO_KFUNC_CALL,
     726              :                                       .off = 0,
     727              :                                       .imm = r}));
     728              : 
     729            0 :     return 0;
     730              : }
     731              : 
     732            0 : int bf_program_emit_fixup(struct bf_program *program, enum bf_fixup_type type,
     733              :                           struct bpf_insn insn, const union bf_fixup_attr *attr)
     734              : {
     735            0 :     _free_bf_fixup_ struct bf_fixup *fixup = NULL;
     736              :     int r;
     737              : 
     738            0 :     bf_assert(program);
     739              : 
     740            0 :     if (program->img_size == program->img_cap) {
     741            0 :         r = bf_program_grow_img(program);
     742            0 :         if (r)
     743              :             return r;
     744              :     }
     745              : 
     746            0 :     r = bf_fixup_new(&fixup, type, program->img_size, attr);
     747            0 :     if (r)
     748              :         return r;
     749              : 
     750            0 :     r = bf_list_add_tail(&program->fixups, fixup);
     751            0 :     if (r)
     752              :         return r;
     753              : 
     754            0 :     TAKE_PTR(fixup);
     755              : 
     756              :     /* This call could fail and return an error, in which case it is not
     757              :      * properly handled. However, this shouldn't be an issue as we previously
     758              :      * test whether enough room is available in cgen.img, which is currently
     759              :      * the only reason for EMIT() to fail. */
     760            0 :     EMIT(program, insn);
     761              : 
     762              :     return 0;
     763              : }
     764              : 
     765            0 : int bf_program_emit_fixup_elfstub(struct bf_program *program,
     766              :                                   enum bf_elfstub_id id)
     767              : {
     768            0 :     _free_bf_fixup_ struct bf_fixup *fixup = NULL;
     769              :     int r;
     770              : 
     771            0 :     bf_assert(program);
     772              : 
     773            0 :     if (program->img_size == program->img_cap) {
     774            0 :         r = bf_program_grow_img(program);
     775            0 :         if (r)
     776              :             return r;
     777              :     }
     778              : 
     779            0 :     r = bf_fixup_new(&fixup, BF_FIXUP_ELFSTUB_CALL, program->img_size, NULL);
     780            0 :     if (r)
     781              :         return r;
     782              : 
     783            0 :     fixup->attr.elfstub_id = id;
     784              : 
     785            0 :     r = bf_list_add_tail(&program->fixups, fixup);
     786            0 :     if (r)
     787              :         return r;
     788              : 
     789            0 :     TAKE_PTR(fixup);
     790              : 
     791            0 :     EMIT(program, BPF_CALL_REL(0));
     792              : 
     793            0 :     return 0;
     794              : }
     795              : 
     796            0 : int bf_program_generate(struct bf_program *program)
     797              : {
     798            0 :     const struct bf_chain *chain = program->runtime.chain;
     799              :     int r;
     800              : 
     801              :     // Save the program's argument into the context.
     802            0 :     EMIT(program,
     803              :          BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_1, BF_PROG_CTX_OFF(arg)));
     804              : 
     805              :     // Reset the protocol ID registers
     806            0 :     EMIT(program, BPF_MOV64_IMM(BPF_REG_7, 0));
     807            0 :     EMIT(program, BPF_MOV64_IMM(BPF_REG_8, 0));
     808              : 
     809              :     // If at least one rule logs the matched packets, populate ctx->log_map
     810            0 :     if (program->runtime.chain->flags & BF_FLAG(BF_CHAIN_LOG)) {
     811            0 :         EMIT_LOAD_LOG_FD_FIXUP(program, BPF_REG_2);
     812            0 :         EMIT(program, BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_2,
     813              :                                   BF_PROG_CTX_OFF(log_map)));
     814              :     }
     815              : 
     816              :     // Zeroing IPv6 extension headers
     817            0 :     if (program->runtime.chain->flags & BF_FLAG(BF_CHAIN_STORE_NEXTHDR)) {
     818            0 :         EMIT(program, BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_7,
     819              :                                   BF_PROG_CTX_OFF(ipv6_eh)));
     820              :     }
     821              : 
     822            0 :     r = program->runtime.ops->gen_inline_prologue(program);
     823            0 :     if (r)
     824              :         return r;
     825              : 
     826            0 :     bf_list_foreach (&chain->rules, rule_node) {
     827            0 :         r = _bf_program_generate_rule(program,
     828            0 :                                       bf_list_node_get_data(rule_node));
     829            0 :         if (r)
     830              :             return r;
     831              :     }
     832              : 
     833            0 :     r = program->runtime.ops->gen_inline_epilogue(program);
     834            0 :     if (r)
     835              :         return r;
     836              : 
     837              :     // Call the update counters function
     838              :     /// @todo Allow chains to have no counters at all.
     839            0 :     EMIT(program, BPF_MOV64_REG(BPF_REG_1, BPF_REG_10));
     840            0 :     EMIT(program, BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, BF_PROG_CTX_OFF(arg)));
     841            0 :     EMIT_LOAD_COUNTERS_FD_FIXUP(program, BPF_REG_2);
     842            0 :     EMIT(program,
     843              :          BPF_MOV32_IMM(BPF_REG_3, bf_program_chain_counter_idx(program)));
     844            0 :     EMIT_FIXUP_ELFSTUB(program, BF_ELFSTUB_UPDATE_COUNTERS);
     845              : 
     846            0 :     EMIT(program, BPF_MOV64_IMM(BPF_REG_0, program->runtime.ops->get_verdict(
     847              :                                                chain->policy)));
     848            0 :     EMIT(program, BPF_EXIT_INSN());
     849              : 
     850            0 :     r = _bf_program_generate_elfstubs(program);
     851            0 :     if (r)
     852              :         return r;
     853              : 
     854            0 :     r = _bf_program_fixup(program, BF_FIXUP_ELFSTUB_CALL);
     855            0 :     if (r)
     856            0 :         return bf_err_r(r, "failed to generate ELF stub call fixups");
     857              : 
     858              :     return 0;
     859              : }
     860              : 
     861            0 : static int _bf_program_load_printer_map(struct bf_program *program)
     862              : {
     863            0 :     _cleanup_free_ void *pstr = NULL;
     864              :     size_t pstr_len;
     865            0 :     uint32_t key = 0;
     866              :     int r;
     867              : 
     868            0 :     bf_assert(program);
     869              : 
     870            0 :     r = bf_printer_assemble(program->printer, &pstr, &pstr_len);
     871            0 :     if (r)
     872            0 :         return bf_err_r(r, "failed to assemble printer map string");
     873              : 
     874            0 :     r = bf_map_set_value_size(program->pmap, pstr_len);
     875            0 :     if (r < 0)
     876              :         return r;
     877              : 
     878            0 :     r = bf_map_create(program->pmap);
     879            0 :     if (r < 0)
     880              :         return r;
     881              : 
     882            0 :     r = bf_map_set_elem(program->pmap, &key, pstr);
     883            0 :     if (r)
     884              :         return r;
     885              : 
     886            0 :     r = _bf_program_fixup(program, BF_FIXUP_TYPE_PRINTER_MAP_FD);
     887            0 :     if (r) {
     888            0 :         bf_map_destroy(program->pmap);
     889            0 :         return bf_err_r(r, "failed to fixup printer map FD");
     890              :     }
     891              : 
     892              :     return 0;
     893              : }
     894              : 
     895            0 : static int _bf_program_load_counters_map(struct bf_program *program)
     896              : {
     897            0 :     _cleanup_close_ int _fd = -1;
     898              :     int r;
     899              : 
     900            0 :     bf_assert(program);
     901              : 
     902            0 :     r = bf_map_set_n_elems(program->cmap,
     903            0 :                            bf_list_size(&program->runtime.chain->rules) + 2);
     904            0 :     if (r < 0)
     905              :         return r;
     906              : 
     907            0 :     r = bf_map_create(program->cmap);
     908            0 :     if (r < 0)
     909              :         return r;
     910              : 
     911            0 :     r = _bf_program_fixup(program, BF_FIXUP_TYPE_COUNTERS_MAP_FD);
     912            0 :     if (r < 0) {
     913            0 :         bf_map_destroy(program->cmap);
     914            0 :         return bf_err_r(r, "failed to fixup counters map FD");
     915              :     }
     916              : 
     917              :     return 0;
     918              : }
     919              : 
     920            0 : static int _bf_program_load_log_map(struct bf_program *program)
     921              : {
     922            0 :     _cleanup_close_ int _fd = -1;
     923              :     int r;
     924              : 
     925            0 :     bf_assert(program);
     926              : 
     927            0 :     r = bf_map_create(program->lmap);
     928            0 :     if (r < 0)
     929              :         return r;
     930              : 
     931            0 :     r = _bf_program_fixup(program, BF_FIXUP_TYPE_LOG_MAP_FD);
     932            0 :     if (r < 0) {
     933            0 :         bf_map_destroy(program->lmap);
     934            0 :         return bf_err_r(r, "failed to fixup log map FD");
     935              :     }
     936              : 
     937              :     return 0;
     938              : }
     939              : 
     940            0 : static int _bf_program_load_sets_maps(struct bf_program *new_prog)
     941              : {
     942              :     const bf_list_node *set_node;
     943              :     const bf_list_node *map_node;
     944              :     int r;
     945              : 
     946            0 :     bf_assert(new_prog);
     947              : 
     948            0 :     set_node = bf_list_get_head(&new_prog->runtime.chain->sets);
     949            0 :     map_node = bf_list_get_head(&new_prog->sets);
     950              : 
     951              :     // Fill the bf_map with the sets content
     952            0 :     while (set_node && map_node) {
     953              :         _cleanup_free_ uint8_t *values = NULL;
     954              :         _cleanup_free_ uint8_t *keys = NULL;
     955            0 :         struct bf_set *set = bf_list_node_get_data(set_node);
     956            0 :         struct bf_map *map = bf_list_node_get_data(map_node);
     957            0 :         size_t nelems = bf_list_size(&set->elems);
     958              :         size_t idx = 0;
     959              : 
     960            0 :         r = bf_map_create(map);
     961            0 :         if (r < 0) {
     962            0 :             r = bf_err_r(r, "failed to create BPF map for set");
     963            0 :             goto err_destroy_maps;
     964              :         }
     965              : 
     966            0 :         values = malloc(nelems);
     967            0 :         if (!values) {
     968            0 :             r = bf_err_r(errno, "failed to allocate map values");
     969            0 :             goto err_destroy_maps;
     970              :         }
     971              : 
     972            0 :         keys = malloc(set->elem_size * nelems);
     973            0 :         if (!keys) {
     974            0 :             r = bf_err_r(errno, "failed to allocate map keys");
     975            0 :             goto err_destroy_maps;
     976              :         }
     977              : 
     978            0 :         bf_list_foreach (&set->elems, elem_node) {
     979            0 :             void *elem = bf_list_node_get_data(elem_node);
     980              : 
     981            0 :             memcpy(keys + (idx * set->elem_size), elem, set->elem_size);
     982            0 :             values[idx] = 1;
     983            0 :             ++idx;
     984              :         }
     985              : 
     986            0 :         r = bf_bpf_map_update_batch(map->fd, keys, values, nelems, BPF_ANY);
     987            0 :         if (r < 0) {
     988            0 :             bf_err_r(r, "failed to add set elements to the map");
     989            0 :             goto err_destroy_maps;
     990              :         }
     991              : 
     992            0 :         set_node = bf_list_node_next(set_node);
     993            0 :         map_node = bf_list_node_next(map_node);
     994              :     }
     995              : 
     996            0 :     r = _bf_program_fixup(new_prog, BF_FIXUP_TYPE_SET_MAP_FD);
     997            0 :     if (r < 0)
     998            0 :         goto err_destroy_maps;
     999              : 
    1000              :     return 0;
    1001              : 
    1002            0 : err_destroy_maps:
    1003            0 :     bf_list_foreach (&new_prog->sets, map_node)
    1004            0 :         bf_map_destroy(bf_list_node_get_data(map_node));
    1005              :     return r;
    1006              : }
    1007              : 
    1008            0 : int bf_program_load(struct bf_program *prog)
    1009              : {
    1010              :     _cleanup_free_ char *log_buf = NULL;
    1011              :     int r;
    1012              : 
    1013            0 :     bf_assert(prog && prog->img);
    1014              : 
    1015            0 :     r = _bf_program_load_sets_maps(prog);
    1016            0 :     if (r)
    1017              :         return r;
    1018              : 
    1019            0 :     r = _bf_program_load_counters_map(prog);
    1020            0 :     if (r)
    1021              :         return r;
    1022              : 
    1023            0 :     r = _bf_program_load_printer_map(prog);
    1024            0 :     if (r)
    1025              :         return r;
    1026              : 
    1027            0 :     r = _bf_program_load_log_map(prog);
    1028            0 :     if (r)
    1029              :         return r;
    1030              : 
    1031            0 :     if (bf_opts_is_verbose(BF_VERBOSE_DEBUG)) {
    1032            0 :         log_buf = malloc(_BF_LOG_BUF_SIZE);
    1033            0 :         if (!log_buf) {
    1034            0 :             return bf_err_r(-ENOMEM,
    1035              :                             "failed to allocate BPF_PROG_LOAD logs buffer");
    1036              :         }
    1037              :     }
    1038              : 
    1039            0 :     if (bf_opts_is_verbose(BF_VERBOSE_BYTECODE))
    1040            0 :         bf_program_dump_bytecode(prog);
    1041              : 
    1042            0 :     r = bf_bpf_prog_load(
    1043            0 :         prog->prog_name, bf_hook_to_bpf_prog_type(prog->runtime.chain->hook),
    1044            0 :         prog->img, prog->img_size,
    1045            0 :         bf_hook_to_bpf_attach_type(prog->runtime.chain->hook), log_buf,
    1046              :         log_buf ? _BF_LOG_BUF_SIZE : 0, bf_ctx_token(), &prog->runtime.prog_fd);
    1047            0 :     if (r) {
    1048            0 :         return bf_err_r(r, "failed to load bf_program (%lu bytes):\n%s\nerrno:",
    1049              :                         prog->img_size, log_buf ? log_buf : "<NO LOG BUFFER>");
    1050              :     }
    1051              : 
    1052              :     return r;
    1053              : }
    1054              : 
    1055            0 : int bf_program_attach(struct bf_program *prog, struct bf_hookopts **hookopts)
    1056              : {
    1057              :     int r;
    1058              : 
    1059            0 :     bf_assert(prog && hookopts);
    1060              : 
    1061            0 :     r = bf_link_attach(prog->link, prog->runtime.chain->hook, hookopts,
    1062              :                        prog->runtime.prog_fd);
    1063            0 :     if (r) {
    1064            0 :         return bf_err_r(r, "failed to attach bf_link for %s program",
    1065              :                         bf_flavor_to_str(prog->flavor));
    1066              :     }
    1067              : 
    1068              :     return r;
    1069              : }
    1070              : 
    1071            0 : void bf_program_detach(struct bf_program *prog)
    1072              : {
    1073            0 :     bf_assert(prog);
    1074              : 
    1075            0 :     bf_link_detach(prog->link);
    1076            0 : }
    1077              : 
    1078            0 : void bf_program_unload(struct bf_program *prog)
    1079              : {
    1080            0 :     bf_assert(prog);
    1081              : 
    1082            0 :     closep(&prog->runtime.prog_fd);
    1083            0 :     bf_link_detach(prog->link);
    1084            0 :     bf_map_destroy(prog->cmap);
    1085            0 :     bf_map_destroy(prog->pmap);
    1086            0 :     bf_map_destroy(prog->lmap);
    1087            0 :     bf_list_foreach (&prog->sets, map_node)
    1088            0 :         bf_map_destroy(bf_list_node_get_data(map_node));
    1089            0 : }
    1090              : 
    1091            0 : int bf_program_get_counter(const struct bf_program *program,
    1092              :                            uint32_t counter_idx, struct bf_counter *counter)
    1093              : {
    1094            0 :     bf_assert(program);
    1095            0 :     bf_assert(counter);
    1096              : 
    1097              :     int r;
    1098              : 
    1099            0 :     r = bf_bpf_map_lookup_elem(program->cmap->fd, &counter_idx, counter);
    1100            0 :     if (r < 0)
    1101            0 :         return bf_err_r(errno, "failed to lookup counters map");
    1102              : 
    1103              :     return 0;
    1104              : }
    1105              : 
    1106            0 : int bf_cgen_set_counters(struct bf_program *program,
    1107              :                          const struct bf_counter *counters)
    1108              : {
    1109              :     UNUSED(program);
    1110              :     UNUSED(counters);
    1111              : 
    1112            0 :     return -ENOTSUP;
    1113              : }
    1114              : 
    1115            0 : int bf_program_pin(struct bf_program *prog, int dir_fd)
    1116              : {
    1117              :     const char *name;
    1118              :     int r;
    1119              : 
    1120            0 :     bf_assert(prog);
    1121              : 
    1122            0 :     name = prog->runtime.chain->name;
    1123              : 
    1124            0 :     r = bf_bpf_obj_pin(prog->prog_name, prog->runtime.prog_fd, dir_fd);
    1125            0 :     if (r) {
    1126            0 :         bf_err_r(r, "failed to pin BPF program for '%s'", name);
    1127            0 :         goto err_unpin_all;
    1128              :     }
    1129              : 
    1130            0 :     r = bf_map_pin(prog->cmap, dir_fd);
    1131            0 :     if (r) {
    1132            0 :         bf_err_r(r, "failed to pin BPF counters map for '%s'", name);
    1133            0 :         goto err_unpin_all;
    1134              :     }
    1135              : 
    1136            0 :     r = bf_map_pin(prog->pmap, dir_fd);
    1137            0 :     if (r) {
    1138            0 :         bf_err_r(r, "failed to pin BPF printer map for '%s'", name);
    1139            0 :         goto err_unpin_all;
    1140              :     }
    1141              : 
    1142            0 :     r = bf_map_pin(prog->lmap, dir_fd);
    1143            0 :     if (r) {
    1144            0 :         bf_err_r(r, "failed to pin BPF log map for '%s'", name);
    1145            0 :         goto err_unpin_all;
    1146              :     }
    1147              : 
    1148            0 :     bf_list_foreach (&prog->sets, set_node) {
    1149            0 :         r = bf_map_pin(bf_list_node_get_data(set_node), dir_fd);
    1150            0 :         if (r) {
    1151            0 :             bf_err_r(r, "failed to pin BPF set map for '%s'", name);
    1152            0 :             goto err_unpin_all;
    1153              :         }
    1154              :     }
    1155              : 
    1156              :     // If a link exists, pin it too.
    1157            0 :     if (prog->link->hookopts) {
    1158            0 :         r = bf_link_pin(prog->link, dir_fd);
    1159            0 :         if (r) {
    1160            0 :             bf_err_r(r, "failed to pin BPF link for '%s'", name);
    1161            0 :             goto err_unpin_all;
    1162              :         }
    1163              :     }
    1164              : 
    1165              :     return 0;
    1166              : 
    1167            0 : err_unpin_all:
    1168            0 :     bf_program_unpin(prog, dir_fd);
    1169            0 :     return r;
    1170              : }
    1171              : 
    1172            0 : void bf_program_unpin(struct bf_program *prog, int dir_fd)
    1173              : {
    1174            0 :     bf_assert(prog);
    1175              : 
    1176            0 :     bf_map_unpin(prog->cmap, dir_fd);
    1177            0 :     bf_map_unpin(prog->pmap, dir_fd);
    1178            0 :     bf_map_unpin(prog->lmap, dir_fd);
    1179              : 
    1180            0 :     bf_list_foreach (&prog->sets, set_node)
    1181            0 :         bf_map_unpin(bf_list_node_get_data(set_node), dir_fd);
    1182              : 
    1183            0 :     bf_link_unpin(prog->link, dir_fd);
    1184              : 
    1185            0 :     unlinkat(dir_fd, prog->prog_name, 0);
    1186            0 : }
    1187              : 
    1188            0 : size_t bf_program_chain_counter_idx(const struct bf_program *program)
    1189              : {
    1190            0 :     return bf_list_size(&program->runtime.chain->rules);
    1191              : }
    1192              : 
    1193            0 : size_t bf_program_error_counter_idx(const struct bf_program *program)
    1194              : {
    1195            0 :     return bf_list_size(&program->runtime.chain->rules) + 1;
    1196              : }
        

Generated by: LCOV version 2.0-1