LCOV - code coverage report
Current view: top level - libbpfilter/cgen - cgen.c (source / functions) Coverage Total Hit
Test: coverage.lcov Lines: 73.2 % 250 183
Test Date: 2026-11-06 17:47:37 Functions: 87.5 % 16 14
Branches: 41.1 % 246 101

             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/cgen.h"
       7                 :             : 
       8                 :             : #include <errno.h>
       9                 :             : #include <stddef.h>
      10                 :             : #include <stdint.h>
      11                 :             : #include <stdio.h>
      12                 :             : #include <stdlib.h>
      13                 :             : #include <string.h>
      14                 :             : #include <sys/types.h>
      15                 :             : #include <unistd.h>
      16                 :             : 
      17                 :             : #include <bpfilter/bpf.h>
      18                 :             : #include <bpfilter/chain.h>
      19                 :             : #include <bpfilter/core/list.h>
      20                 :             : #include <bpfilter/counter.h>
      21                 :             : #include <bpfilter/dump.h>
      22                 :             : #include <bpfilter/helper.h>
      23                 :             : #include <bpfilter/hook.h>
      24                 :             : #include <bpfilter/logger.h>
      25                 :             : #include <bpfilter/pack.h>
      26                 :             : #include <bpfilter/rule.h>
      27                 :             : 
      28                 :             : #include "cgen/dump.h"
      29                 :             : #include "cgen/handle.h"
      30                 :             : #include "cgen/prog/link.h"
      31                 :             : #include "cgen/prog/map.h"
      32                 :             : #include "cgen/program.h"
      33                 :             : #include "core/lock.h"
      34                 :             : 
      35                 :             : #define _BF_PROG_NAME "bf_prog"
      36                 :             : #define _BF_CTX_PIN_NAME "bf_ctx"
      37                 :             : #define _BF_CTX_TMP_PIN_NAME "bf_ctx_tmp"
      38                 :             : 
      39                 :             : /**
      40                 :             :  * @brief Persist the codegen state to a BPF context map in bpffs.
      41                 :             :  *
      42                 :             :  * Serializes the cgen, creates a `BPF_MAP_TYPE_ARRAY` map with 1 entry
      43                 :             :  * containing the serialized data, pins it as `bf_ctx_tmp`, then atomically
      44                 :             :  * renames to `bf_ctx`. The map fd is closed after pinning - this is a
      45                 :             :  * one-shot operation.
      46                 :             :  *
      47                 :             :  * @param cgen Codegen to persist. Can't be NULL.
      48                 :             :  * @param dir_fd File descriptor of the chain's bpffs pin directory. Must be
      49                 :             :  *        valid.
      50                 :             :  * @return 0 on success, or negative errno value on failure.
      51                 :             :  */
      52                 :        1502 : static int _bf_cgen_persist(const struct bf_cgen *cgen, int dir_fd)
      53                 :             : {
      54                 :        1502 :     _free_bf_wpack_ bf_wpack_t *pack = NULL;
      55                 :        1502 :     _free_bf_map_ struct bf_map *map = NULL;
      56                 :             :     const void *data;
      57                 :             :     size_t data_len;
      58                 :        1502 :     uint32_t key = 0;
      59                 :             :     int r;
      60                 :             : 
      61                 :             :     assert(cgen);
      62                 :             : 
      63                 :        1502 :     r = bf_wpack_new(&pack);
      64         [ -  + ]:        1502 :     if (r)
      65         [ #  # ]:           0 :         return bf_err_r(r, "failed to create wpack for bf_cgen");
      66                 :             : 
      67                 :        1502 :     r = bf_cgen_pack(cgen, pack);
      68         [ -  + ]:        1502 :     if (r)
      69         [ #  # ]:           0 :         return bf_err_r(r, "failed to pack bf_cgen");
      70                 :             : 
      71                 :        1502 :     r = bf_wpack_get_data(pack, &data, &data_len);
      72         [ -  + ]:        1502 :     if (r)
      73         [ #  # ]:           0 :         return bf_err_r(r, "failed to get data from bf_cgen wpack");
      74                 :             : 
      75                 :        1502 :     r = bf_map_new(&map, _BF_CTX_PIN_NAME, BF_MAP_TYPE_CTX, sizeof(uint32_t),
      76                 :             :                    data_len, 1);
      77         [ -  + ]:        1502 :     if (r)
      78         [ #  # ]:           0 :         return bf_err_r(r, "failed to create context map");
      79                 :             : 
      80                 :        1502 :     r = bf_map_set_elem(map, &key, (void *)data);
      81         [ -  + ]:        1502 :     if (r)
      82         [ #  # ]:           0 :         return bf_err_r(r, "failed to write context to map");
      83                 :             : 
      84                 :             :     // Remove stale temporary pin if present.
      85                 :        1502 :     unlinkat(dir_fd, _BF_CTX_TMP_PIN_NAME, 0);
      86                 :             : 
      87                 :        1502 :     r = bf_bpf_obj_pin(_BF_CTX_TMP_PIN_NAME, map->fd, dir_fd);
      88         [ -  + ]:        1502 :     if (r)
      89         [ #  # ]:           0 :         return bf_err_r(r, "failed to pin context map");
      90                 :             : 
      91                 :        1502 :     r = renameat(dir_fd, _BF_CTX_TMP_PIN_NAME, dir_fd, _BF_CTX_PIN_NAME);
      92         [ -  + ]:        1502 :     if (r) {
      93                 :           0 :         r = -errno;
      94                 :           0 :         unlinkat(dir_fd, _BF_CTX_TMP_PIN_NAME, 0);
      95         [ #  # ]:           0 :         return bf_err_r(r, "failed to atomically replace context map pin");
      96                 :             :     }
      97                 :             : 
      98                 :             :     return 0;
      99                 :             : }
     100                 :             : 
     101                 :        5813 : static int _bf_cgen_new_from_pack(struct bf_cgen **cgen, struct bf_lock *lock,
     102                 :             :                                   bf_rpack_node_t node)
     103                 :             : {
     104                 :        5813 :     _free_bf_cgen_ struct bf_cgen *_cgen = NULL;
     105                 :             :     bf_rpack_node_t child;
     106                 :             :     int r;
     107                 :             : 
     108                 :             :     assert(cgen);
     109                 :             :     assert(lock);
     110                 :             : 
     111                 :        5813 :     _cgen = calloc(1, sizeof(*_cgen));
     112         [ +  - ]:        5813 :     if (!_cgen)
     113                 :             :         return -ENOMEM;
     114                 :             : 
     115                 :        5813 :     r = bf_rpack_kv_obj(node, "chain", &child);
     116         [ -  + ]:        5813 :     if (r)
     117         [ #  # ]:           0 :         return bf_rpack_key_err(r, "bf_cgen.chain");
     118                 :             : 
     119                 :        5813 :     r = bf_chain_new_from_pack(&_cgen->chain, child);
     120         [ -  + ]:        5813 :     if (r)
     121         [ #  # ]:           0 :         return bf_rpack_key_err(r, "bf_cgen.chain");
     122                 :             : 
     123                 :        5813 :     r = bf_rpack_kv_node(node, "handle", &child);
     124         [ -  + ]:        5813 :     if (r)
     125         [ #  # ]:           0 :         return bf_rpack_key_err(r, "bf_cgen.handle");
     126                 :             : 
     127                 :        5813 :     r = bf_handle_new_from_pack(&_cgen->handle, lock, child);
     128         [ +  - ]:        5813 :     if (r)
     129                 :             :         return r;
     130                 :             : 
     131                 :        5813 :     *cgen = TAKE_PTR(_cgen);
     132                 :             : 
     133                 :        5813 :     return 0;
     134                 :             : }
     135                 :             : 
     136                 :        5816 : int bf_cgen_new_from_dir_fd(struct bf_cgen **cgen, struct bf_lock *lock)
     137                 :             : {
     138                 :        5816 :     _free_bf_rpack_ bf_rpack_t *pack = NULL;
     139                 :        5816 :     _cleanup_close_ int map_fd = -1;
     140                 :             :     _cleanup_free_ void *data = NULL;
     141                 :             :     struct bpf_map_info info;
     142                 :        5816 :     uint32_t key = 0;
     143                 :             :     int r;
     144                 :             : 
     145                 :             :     assert(cgen);
     146                 :             :     assert(lock);
     147                 :             : 
     148                 :        5816 :     r = bf_bpf_obj_get(_BF_CTX_PIN_NAME, lock->chain_fd, &map_fd);
     149         [ +  + ]:        5816 :     if (r < 0)
     150         [ +  - ]:           3 :         return bf_err_r(r, "failed to open pinned context map");
     151                 :             : 
     152                 :        5813 :     r = bf_bpf_map_get_info(map_fd, &info);
     153         [ -  + ]:        5813 :     if (r)
     154         [ #  # ]:           0 :         return bf_err_r(r, "failed to get context map info");
     155                 :             : 
     156         [ -  + ]:        5813 :     if (info.value_size == 0)
     157         [ #  # ]:           0 :         return bf_err_r(-EINVAL, "invalid serialized context size");
     158                 :             : 
     159                 :        5813 :     data = malloc(info.value_size);
     160         [ +  - ]:        5813 :     if (!data)
     161                 :             :         return -ENOMEM;
     162                 :             : 
     163                 :        5813 :     r = bf_bpf_map_lookup_elem(map_fd, &key, data);
     164         [ -  + ]:        5813 :     if (r)
     165         [ #  # ]:           0 :         return bf_err_r(r, "failed to read context from map");
     166                 :             : 
     167                 :        5813 :     r = bf_rpack_new(&pack, data, info.value_size);
     168         [ -  + ]:        5813 :     if (r)
     169         [ #  # ]:           0 :         return bf_err_r(r, "failed to create rpack for bf_cgen");
     170                 :             : 
     171                 :        5813 :     r = _bf_cgen_new_from_pack(cgen, lock, bf_rpack_root(pack));
     172         [ -  + ]:        5813 :     if (r)
     173         [ #  # ]:           0 :         return bf_err_r(r, "failed to deserialize cgen from context map");
     174                 :             : 
     175                 :             :     return 0;
     176                 :             : }
     177                 :             : 
     178                 :        1445 : int bf_cgen_new(struct bf_cgen **cgen, struct bf_chain **chain)
     179                 :             : {
     180                 :        1445 :     _free_bf_cgen_ struct bf_cgen *_cgen = NULL;
     181                 :             :     int r;
     182                 :             : 
     183                 :             :     assert(cgen);
     184                 :             :     assert(chain);
     185                 :             : 
     186                 :        1445 :     _cgen = calloc(1, sizeof(*_cgen));
     187         [ +  - ]:        1445 :     if (!_cgen)
     188                 :             :         return -ENOMEM;
     189                 :             : 
     190                 :        1445 :     _cgen->chain = TAKE_PTR(*chain);
     191                 :             : 
     192                 :        1445 :     r = bf_handle_new(&_cgen->handle, _BF_PROG_NAME);
     193         [ +  - ]:        1445 :     if (r)
     194                 :             :         return r;
     195                 :             : 
     196                 :        1445 :     *cgen = TAKE_PTR(_cgen);
     197                 :             : 
     198                 :        1445 :     return 0;
     199                 :             : }
     200                 :             : 
     201                 :       24737 : void bf_cgen_free(struct bf_cgen **cgen)
     202                 :             : {
     203                 :             :     assert(cgen);
     204                 :             : 
     205         [ +  + ]:       24737 :     if (!*cgen)
     206                 :             :         return;
     207                 :             : 
     208                 :        7258 :     bf_handle_free(&(*cgen)->handle);
     209                 :        7258 :     bf_chain_free(&(*cgen)->chain);
     210                 :             : 
     211                 :        7258 :     free(*cgen);
     212                 :        7258 :     *cgen = NULL;
     213                 :             : }
     214                 :             : 
     215                 :        1502 : int bf_cgen_pack(const struct bf_cgen *cgen, bf_wpack_t *pack)
     216                 :             : {
     217                 :             :     assert(cgen);
     218                 :             :     assert(pack);
     219                 :             : 
     220                 :        1502 :     bf_wpack_open_object(pack, "chain");
     221                 :        1502 :     bf_chain_pack(cgen->chain, pack);
     222                 :        1502 :     bf_wpack_close_object(pack);
     223                 :             : 
     224                 :        1502 :     bf_wpack_open_object(pack, "handle");
     225                 :        1502 :     bf_handle_pack(cgen->handle, pack);
     226                 :        1502 :     bf_wpack_close_object(pack);
     227                 :             : 
     228         [ -  + ]:        1502 :     return bf_wpack_is_valid(pack) ? 0 : -EINVAL;
     229                 :             : }
     230                 :             : 
     231                 :           0 : void bf_cgen_dump(const struct bf_cgen *cgen, prefix_t *prefix)
     232                 :             : {
     233                 :             :     assert(cgen);
     234                 :             :     assert(prefix);
     235                 :             : 
     236         [ #  # ]:           0 :     DUMP(prefix, "struct bf_cgen at %p", cgen);
     237                 :             : 
     238                 :           0 :     bf_dump_prefix_push(prefix);
     239                 :             : 
     240                 :             :     // Chain
     241         [ #  # ]:           0 :     DUMP(prefix, "chain: struct bf_chain *");
     242                 :           0 :     bf_dump_prefix_push(prefix);
     243                 :           0 :     bf_chain_dump(cgen->chain, bf_dump_prefix_last(prefix));
     244                 :           0 :     bf_dump_prefix_pop(prefix);
     245                 :             : 
     246         [ #  # ]:           0 :     DUMP(bf_dump_prefix_last(prefix), "handle: struct bf_handle *");
     247                 :           0 :     bf_dump_prefix_push(prefix);
     248                 :           0 :     bf_handle_dump(cgen->handle, bf_dump_prefix_last(prefix));
     249                 :           0 :     bf_dump_prefix_pop(prefix);
     250                 :             : 
     251                 :           0 :     bf_dump_prefix_pop(prefix);
     252                 :           0 : }
     253                 :             : 
     254                 :        1260 : int bf_cgen_load_counters(struct bf_cgen *cgen)
     255                 :             : {
     256                 :             :     int r;
     257                 :             : 
     258                 :             :     assert(cgen);
     259                 :             : 
     260   [ +  +  +  +  :        5042 :     bf_list_foreach (&cgen->chain->rules, rule_node) {
                   +  + ]
     261                 :             :         struct bf_rule *rule = bf_list_node_get_data(rule_node);
     262                 :             : 
     263         [ +  + ]:        1261 :         if (!rule->has_counters)
     264                 :          14 :             continue;
     265                 :             : 
     266                 :        1247 :         r = bf_cgen_get_counter(cgen, rule->index, &rule->counters);
     267         [ -  + ]:        1247 :         if (r) {
     268         [ #  # ]:           0 :             return bf_err_r(r, "failed to load counter for rule %u",
     269                 :             :                             rule->index);
     270                 :             :         }
     271                 :             :     }
     272                 :             : 
     273                 :        1260 :     r = bf_cgen_get_counter(cgen, BF_COUNTER_POLICY,
     274                 :        1260 :                             &cgen->chain->policy_counters);
     275         [ -  + ]:        1260 :     if (r) {
     276         [ #  # ]:           0 :         return bf_err_r(r, "failed to load policy counters for '%s'",
     277                 :             :                         cgen->chain->name);
     278                 :             :     }
     279                 :             : 
     280                 :        1260 :     r = bf_cgen_get_counter(cgen, BF_COUNTER_ERRORS,
     281                 :        1260 :                             &cgen->chain->error_counters);
     282         [ -  + ]:        1260 :     if (r) {
     283         [ #  # ]:           0 :         return bf_err_r(r, "failed to load error counters for '%s'",
     284                 :             :                         cgen->chain->name);
     285                 :             :     }
     286                 :             : 
     287                 :             :     return 0;
     288                 :             : }
     289                 :             : 
     290                 :        3767 : int bf_cgen_get_counter(const struct bf_cgen *cgen,
     291                 :             :                         enum bf_counter_type counter_idx,
     292                 :             :                         struct bf_counter *counter)
     293                 :             : {
     294                 :             :     assert(cgen);
     295                 :             :     assert(counter);
     296                 :             : 
     297                 :             :     /* There are two more counter than rules. The special counters must
     298                 :             :      * be accessed via the specific values, to avoid confusion. */
     299         [ +  + ]:        3767 :     enum bf_counter_type rule_count = bf_list_size(&cgen->chain->rules);
     300         [ +  + ]:        3767 :     if (counter_idx == BF_COUNTER_POLICY) {
     301                 :             :         counter_idx = rule_count;
     302         [ +  + ]:        2507 :     } else if (counter_idx == BF_COUNTER_ERRORS) {
     303                 :        1260 :         counter_idx = rule_count + 1;
     304         [ +  - ]:        1247 :     } else if (counter_idx < 0 || counter_idx >= rule_count) {
     305                 :             :         return -EINVAL;
     306                 :             :     }
     307                 :             : 
     308                 :        3767 :     return bf_handle_get_counter(cgen->handle, counter_idx, counter);
     309                 :             : }
     310                 :             : 
     311                 :        1428 : int bf_cgen_set(struct bf_cgen *cgen, struct bf_hookopts **hookopts,
     312                 :             :                 struct bf_lock *lock)
     313                 :             : {
     314                 :        1428 :     _free_bf_program_ struct bf_program *prog = NULL;
     315                 :             :     int r;
     316                 :             : 
     317                 :             :     assert(cgen);
     318                 :             :     assert(lock);
     319                 :             : 
     320                 :        1428 :     r = bf_program_new(&prog, cgen->chain, cgen->handle);
     321         [ +  - ]:        1428 :     if (r < 0)
     322                 :             :         return r;
     323                 :             : 
     324                 :        1428 :     r = bf_program_generate(prog);
     325         [ +  + ]:        1428 :     if (r < 0)
     326         [ +  - ]:           3 :         return bf_err_r(r, "failed to generate bf_program");
     327                 :             : 
     328                 :        1425 :     r = bf_program_load(prog);
     329         [ -  + ]:        1425 :     if (r < 0)
     330         [ #  # ]:           0 :         return bf_err_r(r, "failed to load the chain");
     331                 :             : 
     332         [ +  + ]:        1425 :     if (hookopts) {
     333                 :         140 :         r = bf_handle_attach(cgen->handle, cgen->chain->hook, hookopts);
     334         [ +  + ]:         140 :         if (r < 0)
     335         [ +  - ]:           2 :             return bf_err_r(r, "failed to load and attach the chain");
     336                 :             :     }
     337                 :             : 
     338                 :        1423 :     r = bf_handle_pin(cgen->handle, lock);
     339         [ +  + ]:        1423 :     if (r)
     340                 :             :         return r;
     341                 :             : 
     342                 :        1422 :     r = _bf_cgen_persist(cgen, lock->chain_fd);
     343         [ -  + ]:        1422 :     if (r) {
     344                 :           0 :         bf_handle_unpin(cgen->handle, lock);
     345         [ #  # ]:           0 :         return bf_err_r(r, "failed to persist cgen for '%s'",
     346                 :             :                         cgen->chain->name);
     347                 :             :     }
     348                 :             : 
     349                 :             :     return 0;
     350                 :             : }
     351                 :             : 
     352                 :          17 : int bf_cgen_load(struct bf_cgen *cgen, struct bf_lock *lock)
     353                 :             : {
     354                 :          17 :     _free_bf_program_ struct bf_program *prog = NULL;
     355                 :             :     int r;
     356                 :             : 
     357                 :             :     assert(cgen);
     358                 :             :     assert(lock);
     359                 :             : 
     360                 :          17 :     r = bf_program_new(&prog, cgen->chain, cgen->handle);
     361         [ +  - ]:          17 :     if (r < 0)
     362                 :             :         return r;
     363                 :             : 
     364                 :          17 :     r = bf_program_generate(prog);
     365         [ -  + ]:          17 :     if (r < 0)
     366         [ #  # ]:           0 :         return bf_err_r(r, "failed to generate bf_program");
     367                 :             : 
     368                 :          17 :     r = bf_program_load(prog);
     369         [ -  + ]:          17 :     if (r < 0)
     370         [ #  # ]:           0 :         return bf_err_r(r, "failed to load the chain");
     371                 :             : 
     372                 :          17 :     r = bf_handle_pin(cgen->handle, lock);
     373         [ +  + ]:          17 :     if (r)
     374                 :             :         return r;
     375                 :             : 
     376                 :          16 :     r = _bf_cgen_persist(cgen, lock->chain_fd);
     377         [ -  + ]:          16 :     if (r) {
     378                 :           0 :         bf_handle_unpin(cgen->handle, lock);
     379         [ #  # ]:           0 :         return bf_err_r(r, "failed to persist cgen for '%s'",
     380                 :             :                         cgen->chain->name);
     381                 :             :     }
     382                 :             : 
     383         [ +  - ]:          16 :     bf_info("load %s", cgen->chain->name);
     384                 :             : 
     385         [ -  + ]:          16 :     if (bf_log_get_level() == BF_LOG_DBG)
     386                 :           0 :         bf_cgen_dump(cgen, EMPTY_PREFIX);
     387                 :             : 
     388                 :             :     return 0;
     389                 :             : }
     390                 :             : 
     391                 :          14 : int bf_cgen_attach(struct bf_cgen *cgen, struct bf_hookopts **hookopts,
     392                 :             :                    struct bf_lock *lock)
     393                 :             : {
     394                 :             :     int r;
     395                 :             : 
     396                 :             :     assert(cgen);
     397                 :             :     assert(hookopts);
     398                 :             :     assert(lock);
     399                 :             : 
     400         [ +  - ]:          14 :     bf_info("attaching %s to %s", cgen->chain->name,
     401                 :             :             bf_hook_to_str(cgen->chain->hook));
     402                 :          14 :     bf_hookopts_dump(*hookopts, EMPTY_PREFIX);
     403                 :             : 
     404                 :          14 :     r = bf_handle_attach(cgen->handle, cgen->chain->hook, hookopts);
     405         [ +  + ]:          14 :     if (r < 0)
     406         [ +  - ]:           2 :         return bf_err_r(r, "failed to attach chain '%s'", cgen->chain->name);
     407                 :             : 
     408                 :          12 :     r = bf_link_pin(cgen->handle->link, lock);
     409         [ -  + ]:          12 :     if (r) {
     410                 :           0 :         bf_handle_detach(cgen->handle);
     411                 :           0 :         return r;
     412                 :             :     }
     413                 :             : 
     414                 :          12 :     r = _bf_cgen_persist(cgen, lock->chain_fd);
     415         [ -  + ]:          12 :     if (r) {
     416                 :           0 :         bf_link_unpin(cgen->handle->link, lock);
     417                 :           0 :         bf_handle_detach(cgen->handle);
     418         [ #  # ]:           0 :         return bf_err_r(r, "failed to persist cgen for '%s'",
     419                 :             :                         cgen->chain->name);
     420                 :             :     }
     421                 :             : 
     422                 :             :     return r;
     423                 :             : }
     424                 :             : 
     425                 :             : /**
     426                 :             :  * @brief Transfer all counters from old handle to new handle.
     427                 :             :  *
     428                 :             :  * Copies counter values 1:1 for all rule counters plus policy and error
     429                 :             :  * counters. The old and new chains must have the same number of rules.
     430                 :             :  * Both handles must be loaded.
     431                 :             :  *
     432                 :             :  * @param old_handle Handle with the source counter map. Can't be NULL.
     433                 :             :  * @param new_handle Handle with the destination counter map. Can't be NULL.
     434                 :             :  * @param n_rules Number of rules in the chain.
     435                 :             :  * @return 0 on success, or a negative errno value on failure.
     436                 :             :  */
     437                 :          20 : static int _bf_cgen_transfer_counters(const struct bf_handle *old_handle,
     438                 :             :                                       struct bf_handle *new_handle,
     439                 :             :                                       size_t n_rules)
     440                 :             : {
     441                 :             :     int r;
     442                 :             : 
     443                 :             :     assert(old_handle);
     444                 :             :     assert(new_handle);
     445                 :             : 
     446   [ +  -  -  + ]:          20 :     if (!old_handle->cmap || !new_handle->cmap)
     447         [ #  # ]:           0 :         return bf_err_r(-ENOENT, "missing counter map for counter transfer");
     448                 :             : 
     449                 :             :     // n_rules entries for rules, +1 for policy, +1 for errors.
     450         [ +  + ]:          82 :     for (uint32_t i = 0; i < n_rules + 2; ++i) {
     451                 :             :         struct bf_counter counter;
     452                 :             : 
     453                 :          62 :         r = bf_handle_get_counter(old_handle, i, &counter);
     454         [ -  + ]:          62 :         if (r)
     455         [ #  # ]:           0 :             return bf_err_r(r, "failed to read counter %u", i);
     456                 :             : 
     457   [ +  +  +  - ]:          62 :         if (!counter.count && !counter.size)
     458                 :          47 :             continue;
     459                 :             : 
     460                 :          15 :         r = bf_handle_set_counter(new_handle, i, &counter);
     461         [ -  + ]:          15 :         if (r)
     462         [ #  # ]:           0 :             return bf_err_r(r, "failed to write counter %u", i);
     463                 :             :     }
     464                 :             : 
     465                 :             :     return 0;
     466                 :             : }
     467                 :             : 
     468                 :          26 : int bf_cgen_update(struct bf_cgen *cgen, struct bf_chain **new_chain,
     469                 :             :                    uint32_t flags, struct bf_lock *lock)
     470                 :             : {
     471                 :          26 :     _free_bf_program_ struct bf_program *new_prog = NULL;
     472                 :          26 :     _free_bf_handle_ struct bf_handle *new_handle = NULL;
     473                 :             :     struct bf_handle *old_handle;
     474                 :             :     int r;
     475                 :             : 
     476                 :             :     assert(cgen);
     477                 :             :     assert(new_chain);
     478                 :             :     assert(lock);
     479                 :             : 
     480         [ -  + ]:          26 :     if (flags & ~BF_FLAGS_MASK(_BF_CGEN_UPDATE_MAX))
     481         [ #  # ]:           0 :         return bf_err_r(-EINVAL, "unknown update flags: 0x%x", flags);
     482                 :             : 
     483                 :          26 :     old_handle = cgen->handle;
     484                 :             : 
     485                 :          26 :     r = bf_handle_new(&new_handle, _BF_PROG_NAME);
     486         [ +  - ]:          26 :     if (r)
     487                 :             :         return r;
     488                 :             : 
     489                 :          26 :     r = bf_program_new(&new_prog, *new_chain, new_handle);
     490         [ -  + ]:          26 :     if (r < 0)
     491         [ #  # ]:           0 :         return bf_err_r(r, "failed to create a new bf_program");
     492                 :             : 
     493                 :          26 :     r = bf_program_generate(new_prog);
     494         [ -  + ]:          26 :     if (r < 0) {
     495         [ #  # ]:           0 :         return bf_err_r(r,
     496                 :             :                         "failed to generate the bytecode for a new bf_program");
     497                 :             :     }
     498                 :             : 
     499   [ +  +  +  + ]:          26 :     if ((flags & BF_FLAG(BF_CGEN_UPDATE_PRESERVE_LOGS)) && old_handle->lmap) {
     500                 :           3 :         r = bf_map_dup(&new_handle->lmap, old_handle->lmap);
     501         [ -  + ]:           3 :         if (r)
     502         [ #  # ]:           0 :             return bf_err_r(r, "failed to reuse the log map");
     503                 :             :     }
     504                 :             : 
     505                 :          26 :     r = bf_program_load(new_prog);
     506         [ -  + ]:          26 :     if (r)
     507         [ #  # ]:           0 :         return bf_err_r(r, "failed to load new program");
     508                 :             : 
     509         [ +  + ]:          26 :     if (flags & BF_FLAG(BF_CGEN_UPDATE_PRESERVE_COUNTERS)) {
     510         [ -  + ]:          20 :         if (bf_list_size(&cgen->chain->rules) !=
     511         [ -  + ]:          20 :             bf_list_size(&(*new_chain)->rules)) {
     512         [ #  # ]:           0 :             return bf_err_r(-EINVAL,
     513                 :             :                             "rule count mismatch for counter transfer");
     514                 :             :         }
     515                 :             : 
     516                 :          20 :         r = _bf_cgen_transfer_counters(old_handle, new_handle,
     517                 :             :                                        bf_list_size(&(*new_chain)->rules));
     518         [ -  + ]:          20 :         if (r)
     519         [ #  # ]:           0 :             return bf_err_r(r, "failed to transfer counters");
     520                 :             :     }
     521                 :             : 
     522                 :          26 :     bf_handle_unpin(old_handle, lock);
     523                 :             : 
     524         [ +  + ]:          26 :     if (old_handle->link) {
     525                 :          19 :         r = bf_link_update(old_handle->link, new_handle->prog_fd);
     526         [ -  + ]:          19 :         if (r) {
     527         [ #  # ]:           0 :             bf_err_r(r, "failed to update bf_link object with new program");
     528         [ #  # ]:           0 :             if (bf_handle_pin(old_handle, lock) < 0)
     529         [ #  # ]:           0 :                 bf_err("failed to repin old handle, ignoring");
     530                 :             :             return r;
     531                 :             :         }
     532                 :             : 
     533                 :             :         // We updated the old link, we need to store it in the new handle
     534                 :          19 :         bf_swap(new_handle->link, old_handle->link);
     535                 :             :     }
     536                 :             : 
     537                 :          26 :     bf_swap(cgen->handle, new_handle);
     538                 :             : 
     539                 :          26 :     r = bf_handle_pin(cgen->handle, lock);
     540         [ -  + ]:          26 :     if (r)
     541         [ #  # ]:           0 :         return bf_err_r(r, "failed to pin new handle");
     542                 :             : 
     543                 :          26 :     r = _bf_cgen_persist(cgen, lock->chain_fd);
     544         [ -  + ]:          26 :     if (r) {
     545                 :           0 :         bf_handle_unpin(cgen->handle, lock);
     546         [ #  # ]:           0 :         return bf_err_r(r, "failed to persist cgen for '%s'",
     547                 :             :                         cgen->chain->name);
     548                 :             :     }
     549                 :             : 
     550                 :          26 :     bf_chain_free(&cgen->chain);
     551                 :          26 :     cgen->chain = TAKE_PTR(*new_chain);
     552                 :             : 
     553                 :          26 :     r = _bf_cgen_persist(cgen, lock->chain_fd);
     554         [ -  + ]:          26 :     if (r) {
     555                 :           0 :         bf_handle_unpin(cgen->handle, lock);
     556         [ #  # ]:           0 :         return bf_err_r(r, "failed to persist cgen for '%s'",
     557                 :             :                         cgen->chain->name);
     558                 :             :     }
     559                 :             : 
     560                 :             :     return 0;
     561                 :             : }
     562                 :             : 
     563                 :           0 : void bf_cgen_detach(struct bf_cgen *cgen)
     564                 :             : {
     565                 :             :     assert(cgen);
     566                 :             : 
     567                 :           0 :     bf_handle_detach(cgen->handle);
     568                 :           0 : }
     569                 :             : 
     570                 :        1412 : void bf_cgen_unload(struct bf_cgen *cgen, struct bf_lock *lock)
     571                 :             : {
     572                 :             :     assert(cgen);
     573                 :             :     assert(lock);
     574                 :             : 
     575                 :             :     /* The chain's pin directory will be removed by bf_lock_release_chain()
     576                 :             :      * if a `BF_LOCK_WRITE` lock is held. */
     577                 :        1412 :     unlinkat(lock->chain_fd, _BF_CTX_PIN_NAME, 0);
     578                 :        1412 :     bf_handle_unpin(cgen->handle, lock);
     579                 :        1412 :     bf_handle_unload(cgen->handle);
     580                 :        1412 : }
        

Generated by: LCOV version 2.0-1