LCOV - code coverage report
Current view: top level - libbpfilter/cgen - cgen.c (source / functions) Coverage Total Hit
Test: coverage.lcov Lines: 78.6 % 248 195
Test Date: 2026-05-11 12:01:08 Functions: 93.8 % 16 15
Branches: 41.5 % 236 98

             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                 :        1329 : static int _bf_cgen_persist(const struct bf_cgen *cgen, int dir_fd)
      53                 :             : {
      54                 :        1329 :     _free_bf_wpack_ bf_wpack_t *pack = NULL;
      55                 :        1329 :     _free_bf_map_ struct bf_map *map = NULL;
      56                 :             :     const void *data;
      57                 :             :     size_t data_len;
      58                 :        1329 :     uint32_t key = 0;
      59                 :             :     int r;
      60                 :             : 
      61                 :             :     assert(cgen);
      62                 :             : 
      63                 :        1329 :     r = bf_wpack_new(&pack);
      64         [ -  + ]:        1329 :     if (r)
      65         [ #  # ]:           0 :         return bf_err_r(r, "failed to create wpack for bf_cgen");
      66                 :             : 
      67                 :        1329 :     r = bf_cgen_pack(cgen, pack);
      68         [ -  + ]:        1329 :     if (r)
      69         [ #  # ]:           0 :         return bf_err_r(r, "failed to pack bf_cgen");
      70                 :             : 
      71                 :        1329 :     r = bf_wpack_get_data(pack, &data, &data_len);
      72         [ -  + ]:        1329 :     if (r)
      73         [ #  # ]:           0 :         return bf_err_r(r, "failed to get data from bf_cgen wpack");
      74                 :             : 
      75                 :        1329 :     r = bf_map_new(&map, _BF_CTX_PIN_NAME, BF_MAP_TYPE_CTX, sizeof(uint32_t),
      76                 :             :                    data_len, 1);
      77         [ -  + ]:        1329 :     if (r)
      78         [ #  # ]:           0 :         return bf_err_r(r, "failed to create context map");
      79                 :             : 
      80                 :        1329 :     r = bf_map_set_elem(map, &key, (void *)data);
      81         [ -  + ]:        1329 :     if (r)
      82         [ #  # ]:           0 :         return bf_err_r(r, "failed to write context to map");
      83                 :             : 
      84                 :             :     // Remove stale temporary pin if present.
      85                 :        1329 :     unlinkat(dir_fd, _BF_CTX_TMP_PIN_NAME, 0);
      86                 :             : 
      87                 :        1329 :     r = bf_bpf_obj_pin(_BF_CTX_TMP_PIN_NAME, map->fd, dir_fd);
      88         [ -  + ]:        1329 :     if (r)
      89         [ #  # ]:           0 :         return bf_err_r(r, "failed to pin context map");
      90                 :             : 
      91                 :        1329 :     r = renameat(dir_fd, _BF_CTX_TMP_PIN_NAME, dir_fd, _BF_CTX_PIN_NAME);
      92         [ -  + ]:        1329 :     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                 :        5327 : static int _bf_cgen_new_from_pack(struct bf_cgen **cgen, struct bf_lock *lock,
     102                 :             :                                   bf_rpack_node_t node)
     103                 :             : {
     104                 :        5327 :     _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                 :        5327 :     _cgen = calloc(1, sizeof(*_cgen));
     112         [ +  - ]:        5327 :     if (!_cgen)
     113                 :             :         return -ENOMEM;
     114                 :             : 
     115                 :        5327 :     r = bf_rpack_kv_obj(node, "chain", &child);
     116         [ -  + ]:        5327 :     if (r)
     117         [ #  # ]:           0 :         return bf_rpack_key_err(r, "bf_cgen.chain");
     118                 :             : 
     119                 :        5327 :     r = bf_chain_new_from_pack(&_cgen->chain, child);
     120         [ -  + ]:        5327 :     if (r)
     121         [ #  # ]:           0 :         return bf_rpack_key_err(r, "bf_cgen.chain");
     122                 :             : 
     123                 :        5327 :     r = bf_rpack_kv_node(node, "handle", &child);
     124         [ -  + ]:        5327 :     if (r)
     125         [ #  # ]:           0 :         return bf_rpack_key_err(r, "bf_cgen.handle");
     126                 :             : 
     127                 :        5327 :     r = bf_handle_new_from_pack(&_cgen->handle, lock, child);
     128         [ +  - ]:        5327 :     if (r)
     129                 :             :         return r;
     130                 :             : 
     131                 :        5327 :     *cgen = TAKE_PTR(_cgen);
     132                 :             : 
     133                 :        5327 :     return 0;
     134                 :             : }
     135                 :             : 
     136                 :        5330 : int bf_cgen_new_from_dir_fd(struct bf_cgen **cgen, struct bf_lock *lock)
     137                 :             : {
     138                 :        5330 :     _free_bf_rpack_ bf_rpack_t *pack = NULL;
     139                 :        5330 :     _cleanup_close_ int map_fd = -1;
     140                 :             :     _cleanup_free_ void *data = NULL;
     141                 :             :     struct bpf_map_info info;
     142                 :        5330 :     uint32_t key = 0;
     143                 :             :     int r;
     144                 :             : 
     145                 :             :     assert(cgen);
     146                 :             :     assert(lock);
     147                 :             : 
     148                 :        5330 :     r = bf_bpf_obj_get(_BF_CTX_PIN_NAME, lock->chain_fd, &map_fd);
     149         [ +  + ]:        5330 :     if (r < 0)
     150         [ +  - ]:           3 :         return bf_err_r(r, "failed to open pinned context map");
     151                 :             : 
     152                 :        5327 :     r = bf_bpf_map_get_info(map_fd, &info);
     153         [ -  + ]:        5327 :     if (r)
     154         [ #  # ]:           0 :         return bf_err_r(r, "failed to get context map info");
     155                 :             : 
     156         [ -  + ]:        5327 :     if (info.value_size == 0)
     157         [ #  # ]:           0 :         return bf_err_r(-EINVAL, "invalid serialized context size");
     158                 :             : 
     159                 :        5327 :     data = malloc(info.value_size);
     160         [ +  - ]:        5327 :     if (!data)
     161                 :             :         return -ENOMEM;
     162                 :             : 
     163                 :        5327 :     r = bf_bpf_map_lookup_elem(map_fd, &key, data);
     164         [ -  + ]:        5327 :     if (r)
     165         [ #  # ]:           0 :         return bf_err_r(r, "failed to read context from map");
     166                 :             : 
     167                 :        5327 :     r = bf_rpack_new(&pack, data, info.value_size);
     168         [ -  + ]:        5327 :     if (r)
     169         [ #  # ]:           0 :         return bf_err_r(r, "failed to create rpack for bf_cgen");
     170                 :             : 
     171                 :        5327 :     r = _bf_cgen_new_from_pack(cgen, lock, bf_rpack_root(pack));
     172         [ -  + ]:        5327 :     if (r)
     173         [ #  # ]:           0 :         return bf_err_r(r, "failed to deserialize cgen from context map");
     174                 :             : 
     175                 :             :     return 0;
     176                 :             : }
     177                 :             : 
     178                 :        1296 : int bf_cgen_new(struct bf_cgen **cgen, struct bf_chain **chain)
     179                 :             : {
     180                 :        1296 :     _free_bf_cgen_ struct bf_cgen *_cgen = NULL;
     181                 :             :     int r;
     182                 :             : 
     183                 :             :     assert(cgen);
     184                 :             :     assert(chain);
     185                 :             : 
     186                 :        1296 :     _cgen = calloc(1, sizeof(*_cgen));
     187         [ +  - ]:        1296 :     if (!_cgen)
     188                 :             :         return -ENOMEM;
     189                 :             : 
     190                 :        1296 :     _cgen->chain = TAKE_PTR(*chain);
     191                 :             : 
     192                 :        1296 :     r = bf_handle_new(&_cgen->handle, _BF_PROG_NAME);
     193         [ +  - ]:        1296 :     if (r)
     194                 :             :         return r;
     195                 :             : 
     196                 :        1296 :     *cgen = TAKE_PTR(_cgen);
     197                 :             : 
     198                 :        1296 :     return 0;
     199                 :             : }
     200                 :             : 
     201                 :       22676 : void bf_cgen_free(struct bf_cgen **cgen)
     202                 :             : {
     203                 :             :     assert(cgen);
     204                 :             : 
     205         [ +  + ]:       22676 :     if (!*cgen)
     206                 :             :         return;
     207                 :             : 
     208                 :        6623 :     bf_handle_free(&(*cgen)->handle);
     209                 :        6623 :     bf_chain_free(&(*cgen)->chain);
     210                 :             : 
     211                 :        6623 :     free(*cgen);
     212                 :        6623 :     *cgen = NULL;
     213                 :             : }
     214                 :             : 
     215                 :        1329 : int bf_cgen_pack(const struct bf_cgen *cgen, bf_wpack_t *pack)
     216                 :             : {
     217                 :             :     assert(cgen);
     218                 :             :     assert(pack);
     219                 :             : 
     220                 :        1329 :     bf_wpack_open_object(pack, "chain");
     221                 :        1329 :     bf_chain_pack(cgen->chain, pack);
     222                 :        1329 :     bf_wpack_close_object(pack);
     223                 :             : 
     224                 :        1329 :     bf_wpack_open_object(pack, "handle");
     225                 :        1329 :     bf_handle_pack(cgen->handle, pack);
     226                 :        1329 :     bf_wpack_close_object(pack);
     227                 :             : 
     228         [ -  + ]:        1329 :     return bf_wpack_is_valid(pack) ? 0 : -EINVAL;
     229                 :             : }
     230                 :             : 
     231                 :          16 : void bf_cgen_dump(const struct bf_cgen *cgen, prefix_t *prefix)
     232                 :             : {
     233                 :             :     assert(cgen);
     234                 :             :     assert(prefix);
     235                 :             : 
     236         [ -  + ]:          16 :     DUMP(prefix, "struct bf_cgen at %p", cgen);
     237                 :             : 
     238                 :          16 :     bf_dump_prefix_push(prefix);
     239                 :             : 
     240                 :             :     // Chain
     241         [ -  + ]:          16 :     DUMP(prefix, "chain: struct bf_chain *");
     242                 :          16 :     bf_dump_prefix_push(prefix);
     243                 :          16 :     bf_chain_dump(cgen->chain, bf_dump_prefix_last(prefix));
     244                 :          16 :     bf_dump_prefix_pop(prefix);
     245                 :             : 
     246         [ -  + ]:          16 :     DUMP(bf_dump_prefix_last(prefix), "handle: struct bf_handle *");
     247                 :          16 :     bf_dump_prefix_push(prefix);
     248                 :          16 :     bf_handle_dump(cgen->handle, bf_dump_prefix_last(prefix));
     249                 :          16 :     bf_dump_prefix_pop(prefix);
     250                 :             : 
     251                 :          16 :     bf_dump_prefix_pop(prefix);
     252                 :          16 : }
     253                 :             : 
     254                 :        1155 : int bf_cgen_load_counters(struct bf_cgen *cgen)
     255                 :             : {
     256                 :             :     int r;
     257                 :             : 
     258                 :             :     assert(cgen);
     259                 :             : 
     260   [ +  +  +  +  :        4624 :     bf_list_foreach (&cgen->chain->rules, rule_node) {
                   +  + ]
     261                 :             :         struct bf_rule *rule = bf_list_node_get_data(rule_node);
     262                 :             : 
     263         [ +  + ]:        1157 :         if (!rule->has_counters)
     264                 :          14 :             continue;
     265                 :             : 
     266                 :        1143 :         r = bf_cgen_get_counter(cgen, rule->index, &rule->counters);
     267         [ -  + ]:        1143 :         if (r) {
     268         [ #  # ]:           0 :             return bf_err_r(r, "failed to load counter for rule %u",
     269                 :             :                             rule->index);
     270                 :             :         }
     271                 :             :     }
     272                 :             : 
     273                 :        1155 :     r = bf_cgen_get_counter(cgen, BF_COUNTER_POLICY,
     274                 :        1155 :                             &cgen->chain->policy_counters);
     275         [ -  + ]:        1155 :     if (r) {
     276         [ #  # ]:           0 :         return bf_err_r(r, "failed to load policy counters for '%s'",
     277                 :             :                         cgen->chain->name);
     278                 :             :     }
     279                 :             : 
     280                 :        1155 :     r = bf_cgen_get_counter(cgen, BF_COUNTER_ERRORS,
     281                 :        1155 :                             &cgen->chain->error_counters);
     282         [ -  + ]:        1155 :     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                 :        3453 : 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         [ +  + ]:        3453 :     enum bf_counter_type rule_count = bf_list_size(&cgen->chain->rules);
     300         [ +  + ]:        3453 :     if (counter_idx == BF_COUNTER_POLICY) {
     301                 :             :         counter_idx = rule_count;
     302         [ +  + ]:        2298 :     } else if (counter_idx == BF_COUNTER_ERRORS) {
     303                 :        1155 :         counter_idx = rule_count + 1;
     304         [ +  - ]:        1143 :     } else if (counter_idx < 0 || counter_idx >= rule_count) {
     305                 :             :         return -EINVAL;
     306                 :             :     }
     307                 :             : 
     308                 :        3453 :     return bf_handle_get_counter(cgen->handle, counter_idx, counter);
     309                 :             : }
     310                 :             : 
     311                 :        1279 : int bf_cgen_set(struct bf_cgen *cgen, struct bf_hookopts **hookopts,
     312                 :             :                 struct bf_lock *lock)
     313                 :             : {
     314                 :        1279 :     _free_bf_program_ struct bf_program *prog = NULL;
     315                 :             :     int r;
     316                 :             : 
     317                 :             :     assert(cgen);
     318                 :             :     assert(lock);
     319                 :             : 
     320                 :        1279 :     r = bf_program_new(&prog, cgen->chain, cgen->handle);
     321         [ +  - ]:        1279 :     if (r < 0)
     322                 :             :         return r;
     323                 :             : 
     324                 :        1279 :     r = bf_program_generate(prog);
     325         [ +  + ]:        1279 :     if (r < 0)
     326         [ +  - ]:           3 :         return bf_err_r(r, "failed to generate bf_program");
     327                 :             : 
     328                 :        1276 :     r = bf_program_load(prog);
     329         [ -  + ]:        1276 :     if (r < 0)
     330         [ #  # ]:           0 :         return bf_err_r(r, "failed to load the chain");
     331                 :             : 
     332         [ +  + ]:        1276 :     if (hookopts) {
     333                 :         109 :         r = bf_handle_attach(cgen->handle, cgen->chain->hook, hookopts);
     334         [ +  + ]:         109 :         if (r < 0)
     335         [ +  - ]:           2 :             return bf_err_r(r, "failed to load and attach the chain");
     336                 :             :     }
     337                 :             : 
     338                 :        1274 :     r = bf_handle_pin(cgen->handle, lock);
     339         [ +  + ]:        1274 :     if (r)
     340                 :             :         return r;
     341                 :             : 
     342                 :        1273 :     r = _bf_cgen_persist(cgen, lock->chain_fd);
     343         [ -  + ]:        1273 :     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                 :          16 :     bf_cgen_dump(cgen, EMPTY_PREFIX);
     385                 :             : 
     386                 :          16 :     return 0;
     387                 :             : }
     388                 :             : 
     389                 :          14 : int bf_cgen_attach(struct bf_cgen *cgen, struct bf_hookopts **hookopts,
     390                 :             :                    struct bf_lock *lock)
     391                 :             : {
     392                 :             :     int r;
     393                 :             : 
     394                 :             :     assert(cgen);
     395                 :             :     assert(hookopts);
     396                 :             :     assert(lock);
     397                 :             : 
     398         [ +  - ]:          14 :     bf_info("attaching %s to %s", cgen->chain->name,
     399                 :             :             bf_hook_to_str(cgen->chain->hook));
     400                 :          14 :     bf_hookopts_dump(*hookopts, EMPTY_PREFIX);
     401                 :             : 
     402                 :          14 :     r = bf_handle_attach(cgen->handle, cgen->chain->hook, hookopts);
     403         [ +  + ]:          14 :     if (r < 0)
     404         [ +  - ]:           2 :         return bf_err_r(r, "failed to attach chain '%s'", cgen->chain->name);
     405                 :             : 
     406                 :          12 :     r = bf_link_pin(cgen->handle->link, lock);
     407         [ -  + ]:          12 :     if (r) {
     408                 :           0 :         bf_handle_detach(cgen->handle);
     409                 :           0 :         return r;
     410                 :             :     }
     411                 :             : 
     412                 :          12 :     r = _bf_cgen_persist(cgen, lock->chain_fd);
     413         [ -  + ]:          12 :     if (r) {
     414                 :           0 :         bf_link_unpin(cgen->handle->link, lock);
     415                 :           0 :         bf_handle_detach(cgen->handle);
     416         [ #  # ]:           0 :         return bf_err_r(r, "failed to persist cgen for '%s'",
     417                 :             :                         cgen->chain->name);
     418                 :             :     }
     419                 :             : 
     420                 :             :     return r;
     421                 :             : }
     422                 :             : 
     423                 :             : /**
     424                 :             :  * @brief Transfer all counters from old handle to new handle.
     425                 :             :  *
     426                 :             :  * Copies counter values 1:1 for all rule counters plus policy and error
     427                 :             :  * counters. The old and new chains must have the same number of rules.
     428                 :             :  * Both handles must be loaded.
     429                 :             :  *
     430                 :             :  * @param old_handle Handle with the source counter map. Can't be NULL.
     431                 :             :  * @param new_handle Handle with the destination counter map. Can't be NULL.
     432                 :             :  * @param n_rules Number of rules in the chain.
     433                 :             :  * @return 0 on success, or a negative errno value on failure.
     434                 :             :  */
     435                 :           8 : static int _bf_cgen_transfer_counters(const struct bf_handle *old_handle,
     436                 :             :                                       struct bf_handle *new_handle,
     437                 :             :                                       size_t n_rules)
     438                 :             : {
     439                 :             :     int r;
     440                 :             : 
     441                 :             :     assert(old_handle);
     442                 :             :     assert(new_handle);
     443                 :             : 
     444   [ +  -  -  + ]:           8 :     if (!old_handle->cmap || !new_handle->cmap)
     445         [ #  # ]:           0 :         return bf_err_r(-ENOENT, "missing counter map for counter transfer");
     446                 :             : 
     447                 :             :     // n_rules entries for rules, +1 for policy, +1 for errors.
     448         [ +  + ]:          34 :     for (uint32_t i = 0; i < n_rules + 2; ++i) {
     449                 :             :         struct bf_counter counter;
     450                 :             : 
     451                 :          26 :         r = bf_handle_get_counter(old_handle, i, &counter);
     452         [ -  + ]:          26 :         if (r)
     453         [ #  # ]:           0 :             return bf_err_r(r, "failed to read counter %u", i);
     454                 :             : 
     455   [ +  +  +  - ]:          26 :         if (!counter.count && !counter.size)
     456                 :          21 :             continue;
     457                 :             : 
     458                 :           5 :         r = bf_map_set_elem(new_handle->cmap, &i, &counter);
     459         [ -  + ]:           5 :         if (r)
     460         [ #  # ]:           0 :             return bf_err_r(r, "failed to write counter %u", i);
     461                 :             :     }
     462                 :             : 
     463                 :           8 :     return 0;
     464                 :             : }
     465                 :             : 
     466                 :          14 : int bf_cgen_update(struct bf_cgen *cgen, struct bf_chain **new_chain,
     467                 :             :                    uint32_t flags, struct bf_lock *lock)
     468                 :             : {
     469                 :          14 :     _free_bf_program_ struct bf_program *new_prog = NULL;
     470                 :          14 :     _free_bf_handle_ struct bf_handle *new_handle = NULL;
     471                 :             :     struct bf_handle *old_handle;
     472                 :             :     int r;
     473                 :             : 
     474                 :             :     assert(cgen);
     475                 :             :     assert(new_chain);
     476                 :             :     assert(lock);
     477                 :             : 
     478         [ -  + ]:          14 :     if (flags & ~BF_FLAGS_MASK(_BF_CGEN_UPDATE_MAX))
     479         [ #  # ]:           0 :         return bf_err_r(-EINVAL, "unknown update flags: 0x%x", flags);
     480                 :             : 
     481                 :          14 :     old_handle = cgen->handle;
     482                 :             : 
     483                 :          14 :     r = bf_handle_new(&new_handle, _BF_PROG_NAME);
     484         [ +  - ]:          14 :     if (r)
     485                 :             :         return r;
     486                 :             : 
     487                 :          14 :     r = bf_program_new(&new_prog, *new_chain, new_handle);
     488         [ -  + ]:          14 :     if (r < 0)
     489         [ #  # ]:           0 :         return bf_err_r(r, "failed to create a new bf_program");
     490                 :             : 
     491                 :          14 :     r = bf_program_generate(new_prog);
     492         [ -  + ]:          14 :     if (r < 0) {
     493         [ #  # ]:           0 :         return bf_err_r(r,
     494                 :             :                         "failed to generate the bytecode for a new bf_program");
     495                 :             :     }
     496                 :             : 
     497                 :          14 :     r = bf_program_load(new_prog);
     498         [ -  + ]:          14 :     if (r)
     499         [ #  # ]:           0 :         return bf_err_r(r, "failed to load new program");
     500                 :             : 
     501         [ +  + ]:          14 :     if (flags & BF_FLAG(BF_CGEN_UPDATE_PRESERVE_COUNTERS)) {
     502         [ -  + ]:           8 :         if (bf_list_size(&cgen->chain->rules) !=
     503         [ -  + ]:           8 :             bf_list_size(&(*new_chain)->rules)) {
     504         [ #  # ]:           0 :             return bf_err_r(-EINVAL,
     505                 :             :                             "rule count mismatch for counter transfer");
     506                 :             :         }
     507                 :             : 
     508                 :           8 :         r = _bf_cgen_transfer_counters(old_handle, new_handle,
     509                 :             :                                        bf_list_size(&(*new_chain)->rules));
     510         [ -  + ]:           8 :         if (r)
     511         [ #  # ]:           0 :             return bf_err_r(r, "failed to transfer counters");
     512                 :             :     }
     513                 :             : 
     514                 :          14 :     bf_handle_unpin(old_handle, lock);
     515                 :             : 
     516         [ +  + ]:          14 :     if (old_handle->link) {
     517                 :          12 :         r = bf_link_update(old_handle->link, new_handle->prog_fd);
     518         [ -  + ]:          12 :         if (r) {
     519         [ #  # ]:           0 :             bf_err_r(r, "failed to update bf_link object with new program");
     520         [ #  # ]:           0 :             if (bf_handle_pin(old_handle, lock) < 0)
     521         [ #  # ]:           0 :                 bf_err("failed to repin old handle, ignoring");
     522                 :           0 :             return r;
     523                 :             :         }
     524                 :             : 
     525                 :             :         // We updated the old link, we need to store it in the new handle
     526                 :          12 :         bf_swap(new_handle->link, old_handle->link);
     527                 :             :     }
     528                 :             : 
     529                 :          14 :     bf_swap(cgen->handle, new_handle);
     530                 :             : 
     531                 :          14 :     r = bf_handle_pin(cgen->handle, lock);
     532         [ -  + ]:          14 :     if (r)
     533         [ #  # ]:           0 :         return bf_err_r(r, "failed to pin new handle");
     534                 :             : 
     535                 :          14 :     r = _bf_cgen_persist(cgen, lock->chain_fd);
     536         [ -  + ]:          14 :     if (r) {
     537                 :           0 :         bf_handle_unpin(cgen->handle, lock);
     538         [ #  # ]:           0 :         return bf_err_r(r, "failed to persist cgen for '%s'",
     539                 :             :                         cgen->chain->name);
     540                 :             :     }
     541                 :             : 
     542                 :          14 :     bf_chain_free(&cgen->chain);
     543                 :          14 :     cgen->chain = TAKE_PTR(*new_chain);
     544                 :             : 
     545                 :          14 :     r = _bf_cgen_persist(cgen, lock->chain_fd);
     546         [ -  + ]:          14 :     if (r) {
     547                 :           0 :         bf_handle_unpin(cgen->handle, lock);
     548         [ #  # ]:           0 :         return bf_err_r(r, "failed to persist cgen for '%s'",
     549                 :             :                         cgen->chain->name);
     550                 :             :     }
     551                 :             : 
     552                 :             :     return 0;
     553                 :             : }
     554                 :             : 
     555                 :           0 : void bf_cgen_detach(struct bf_cgen *cgen)
     556                 :             : {
     557                 :             :     assert(cgen);
     558                 :             : 
     559                 :           0 :     bf_handle_detach(cgen->handle);
     560                 :           0 : }
     561                 :             : 
     562                 :        1263 : void bf_cgen_unload(struct bf_cgen *cgen, struct bf_lock *lock)
     563                 :             : {
     564                 :             :     assert(cgen);
     565                 :             :     assert(lock);
     566                 :             : 
     567                 :             :     /* The chain's pin directory will be removed by bf_lock_release_chain()
     568                 :             :      * if a `BF_LOCK_WRITE` lock is held. */
     569                 :        1263 :     unlinkat(lock->chain_fd, _BF_CTX_PIN_NAME, 0);
     570                 :        1263 :     bf_handle_unpin(cgen->handle, lock);
     571                 :        1263 :     bf_handle_unload(cgen->handle);
     572                 :        1263 : }
        

Generated by: LCOV version 2.0-1