LCOV - code coverage report
Current view: top level - bpfilter/cgen - handle.c (source / functions) Coverage Total Hit
Test: coverage.lcov Lines: 82.5 % 211 174
Test Date: 2026-02-21 16:24:52 Functions: 100.0 % 11 11
Branches: 50.5 % 212 107

             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/handle.h"
       7                 :             : 
       8                 :             : #include <assert.h>
       9                 :             : #include <errno.h>
      10                 :             : #include <stdlib.h>
      11                 :             : #include <string.h>
      12                 :             : #include <unistd.h>
      13                 :             : 
      14                 :             : #include <bpfilter/bpf.h>
      15                 :             : #include <bpfilter/counter.h>
      16                 :             : #include <bpfilter/dump.h>
      17                 :             : #include <bpfilter/helper.h>
      18                 :             : #include <bpfilter/hook.h>
      19                 :             : #include <bpfilter/list.h>
      20                 :             : #include <bpfilter/logger.h>
      21                 :             : #include <bpfilter/pack.h>
      22                 :             : 
      23                 :             : #include "cgen/prog/link.h"
      24                 :             : #include "cgen/prog/map.h"
      25                 :             : 
      26                 :             : #define _BF_LINK_NAME "bf_link"
      27                 :             : 
      28                 :         100 : int bf_handle_new(struct bf_handle **handle, const char *prog_name)
      29                 :             : {
      30                 :         100 :     _free_bf_handle_ struct bf_handle *_handle = NULL;
      31                 :             : 
      32                 :             :     assert(handle);
      33                 :             :     assert(prog_name);
      34                 :             : 
      35                 :         100 :     _handle = calloc(1, sizeof(*_handle));
      36         [ +  - ]:         100 :     if (!_handle)
      37                 :             :         return -ENOMEM;
      38                 :             : 
      39                 :         100 :     (void)snprintf(_handle->prog_name, BPF_OBJ_NAME_LEN, "%s", prog_name);
      40                 :         100 :     _handle->prog_fd = -1;
      41                 :         100 :     _handle->sets = bf_list_default(bf_map_free, bf_map_pack);
      42                 :             : 
      43                 :         100 :     *handle = TAKE_PTR(_handle);
      44                 :             : 
      45                 :         100 :     return 0;
      46                 :             : }
      47                 :             : 
      48                 :           5 : int bf_handle_new_from_pack(struct bf_handle **handle, int dir_fd,
      49                 :             :                             bf_rpack_node_t node)
      50                 :             : {
      51                 :           5 :     _free_bf_handle_ struct bf_handle *_handle = NULL;
      52                 :           5 :     _cleanup_free_ char *name = NULL;
      53                 :             :     bf_rpack_node_t child, array_node;
      54                 :             :     int r;
      55                 :             : 
      56                 :             :     assert(handle);
      57                 :             : 
      58         [ -  + ]:           5 :     if (dir_fd < 0)
      59         [ #  # ]:           0 :         return bf_err_r(-EBADFD, "invalid directory FD");
      60                 :             : 
      61                 :           5 :     r = bf_rpack_kv_str(node, "prog_name", &name);
      62         [ -  + ]:           5 :     if (r)
      63         [ #  # ]:           0 :         return bf_rpack_key_err(r, "bf_handle.name");
      64                 :             : 
      65                 :           5 :     r = bf_handle_new(&_handle, name);
      66         [ +  - ]:           5 :     if (r)
      67                 :             :         return r;
      68                 :             : 
      69                 :           5 :     r = bf_bpf_obj_get(_handle->prog_name, dir_fd, &_handle->prog_fd);
      70         [ -  + ]:           5 :     if (r < 0)
      71         [ #  # ]:           0 :         return bf_err_r(r, "failed to restore bf_handle.prog_fd from pin");
      72                 :             : 
      73                 :           5 :     r = bf_rpack_kv_node(node, "link", &child);
      74         [ -  + ]:           5 :     if (r)
      75         [ #  # ]:           0 :         return bf_rpack_key_err(r, "bf_handle.link");
      76         [ +  + ]:           5 :     if (!bf_rpack_is_nil(child)) {
      77                 :           3 :         r = bf_link_new_from_pack(&_handle->link, dir_fd, child);
      78         [ -  + ]:           3 :         if (r)
      79         [ #  # ]:           0 :             return bf_rpack_key_err(r, "bf_handle.link");
      80                 :             :     }
      81                 :             : 
      82                 :           5 :     r = bf_rpack_kv_node(node, "cmap", &child);
      83         [ -  + ]:           5 :     if (r)
      84         [ #  # ]:           0 :         return bf_rpack_key_err(r, "bf_handle.cmap");
      85         [ +  - ]:           5 :     if (!bf_rpack_is_nil(child)) {
      86                 :           5 :         r = bf_map_new_from_pack(&_handle->cmap, dir_fd, child);
      87         [ -  + ]:           5 :         if (r)
      88         [ #  # ]:           0 :             return bf_rpack_key_err(r, "bf_handle.cmap");
      89                 :             :     }
      90                 :             : 
      91                 :           5 :     r = bf_rpack_kv_node(node, "pmap", &child);
      92         [ -  + ]:           5 :     if (r)
      93         [ #  # ]:           0 :         return bf_rpack_key_err(r, "bf_handle.pmap");
      94         [ +  - ]:           5 :     if (!bf_rpack_is_nil(child)) {
      95                 :           5 :         r = bf_map_new_from_pack(&_handle->pmap, dir_fd, child);
      96         [ -  + ]:           5 :         if (r)
      97         [ #  # ]:           0 :             return bf_rpack_key_err(r, "bf_handle.pmap");
      98                 :             :     }
      99                 :             : 
     100                 :           5 :     r = bf_rpack_kv_node(node, "lmap", &child);
     101         [ -  + ]:           5 :     if (r)
     102         [ #  # ]:           0 :         return bf_rpack_key_err(r, "bf_handle.lmap");
     103         [ -  + ]:           5 :     if (!bf_rpack_is_nil(child)) {
     104                 :           0 :         r = bf_map_new_from_pack(&_handle->lmap, dir_fd, child);
     105         [ #  # ]:           0 :         if (r)
     106         [ #  # ]:           0 :             return bf_rpack_key_err(r, "bf_handle.lmap");
     107                 :             :     }
     108                 :             : 
     109                 :           5 :     r = bf_rpack_kv_array(node, "sets", &child);
     110         [ -  + ]:           5 :     if (r)
     111         [ #  # ]:           0 :         return bf_rpack_key_err(r, "bf_handle.sets");
     112   [ +  +  +  +  :          18 :     bf_rpack_array_foreach (child, array_node) {
                   +  + ]
     113                 :           0 :         _free_bf_map_ struct bf_map *map = NULL;
     114                 :             : 
     115         [ +  + ]:           6 :         if (bf_rpack_is_nil(array_node)) {
     116                 :           2 :             r = bf_list_add_tail(&_handle->sets, NULL);
     117         [ +  - ]:           2 :             if (r)
     118                 :             :                 return r;
     119                 :             :             continue;
     120                 :             :         }
     121                 :             : 
     122   [ +  -  +  -  :           2 :         r = bf_list_emplace(&_handle->sets, bf_map_new_from_pack, map, dir_fd,
             -  -  -  - ]
     123                 :             :                             array_node);
     124                 :             :         if (r)
     125         [ #  # ]:           0 :             return bf_err_r(r, "failed to unpack bf_map into bf_handle.sets");
     126                 :             :     }
     127                 :             : 
     128                 :           5 :     *handle = TAKE_PTR(_handle);
     129                 :             : 
     130                 :           5 :     return 0;
     131                 :             : }
     132                 :             : 
     133                 :         205 : void bf_handle_free(struct bf_handle **handle)
     134                 :             : {
     135                 :             :     assert(handle);
     136                 :             : 
     137         [ +  + ]:         205 :     if (!*handle)
     138                 :             :         return;
     139                 :             : 
     140                 :         100 :     closep(&(*handle)->prog_fd);
     141                 :             : 
     142                 :         100 :     bf_link_free(&(*handle)->link);
     143                 :         100 :     bf_map_free(&(*handle)->cmap);
     144                 :         100 :     bf_map_free(&(*handle)->pmap);
     145                 :         100 :     bf_map_free(&(*handle)->lmap);
     146                 :         100 :     bf_list_clean(&(*handle)->sets);
     147                 :             : 
     148                 :         100 :     free(*handle);
     149                 :         100 :     *handle = NULL;
     150                 :             : }
     151                 :             : 
     152                 :         201 : int bf_handle_pack(const struct bf_handle *handle, bf_wpack_t *pack)
     153                 :             : {
     154                 :             :     assert(handle);
     155                 :             :     assert(pack);
     156                 :             : 
     157                 :         201 :     bf_wpack_kv_str(pack, "prog_name", handle->prog_name);
     158                 :             : 
     159         [ +  + ]:         201 :     if (handle->link) {
     160                 :          83 :         bf_wpack_open_object(pack, "link");
     161                 :          83 :         bf_link_pack(handle->link, pack);
     162                 :          83 :         bf_wpack_close_object(pack);
     163                 :             :     } else {
     164                 :             :         bf_wpack_kv_nil(pack, "link");
     165                 :             :     }
     166                 :             : 
     167         [ +  - ]:         201 :     if (handle->cmap) {
     168                 :         201 :         bf_wpack_open_object(pack, "cmap");
     169                 :         201 :         bf_map_pack(handle->cmap, pack);
     170                 :         201 :         bf_wpack_close_object(pack);
     171                 :             :     } else {
     172                 :             :         bf_wpack_kv_nil(pack, "cmap");
     173                 :             :     }
     174                 :             : 
     175         [ +  - ]:         201 :     if (handle->pmap) {
     176                 :         201 :         bf_wpack_open_object(pack, "pmap");
     177                 :         201 :         bf_map_pack(handle->pmap, pack);
     178                 :         201 :         bf_wpack_close_object(pack);
     179                 :             :     } else {
     180                 :             :         bf_wpack_kv_nil(pack, "pmap");
     181                 :             :     }
     182                 :             : 
     183         [ +  + ]:         201 :     if (handle->lmap) {
     184                 :          76 :         bf_wpack_open_object(pack, "lmap");
     185                 :          76 :         bf_map_pack(handle->lmap, pack);
     186                 :          76 :         bf_wpack_close_object(pack);
     187                 :             :     } else {
     188                 :             :         bf_wpack_kv_nil(pack, "lmap");
     189                 :             :     }
     190                 :             : 
     191                 :         201 :     bf_wpack_kv_list(pack, "sets", &handle->sets);
     192                 :             : 
     193         [ -  + ]:         201 :     return bf_wpack_is_valid(pack) ? 0 : -EINVAL;
     194                 :             : }
     195                 :             : 
     196                 :          17 : void bf_handle_dump(const struct bf_handle *handle, prefix_t *prefix)
     197                 :             : {
     198                 :             :     assert(handle);
     199                 :             :     assert(prefix);
     200                 :             : 
     201         [ +  - ]:          17 :     DUMP(prefix, "struct bf_handle at %p", handle);
     202                 :             : 
     203                 :          17 :     bf_dump_prefix_push(prefix);
     204                 :             : 
     205         [ +  - ]:          17 :     DUMP(prefix, "prog_name: %s", handle->prog_name);
     206         [ +  - ]:          17 :     DUMP(prefix, "prog_fd: %d", handle->prog_fd);
     207                 :             : 
     208         [ +  + ]:          17 :     if (handle->link) {
     209         [ +  - ]:           3 :         DUMP(prefix, "link: struct bf_link *");
     210                 :           3 :         bf_dump_prefix_push(prefix);
     211                 :           3 :         bf_link_dump(handle->link, bf_dump_prefix_last(prefix));
     212                 :           3 :         bf_dump_prefix_pop(prefix);
     213                 :             :     } else {
     214         [ +  - ]:          14 :         DUMP(prefix, "link: struct bf_link * (NULL)");
     215                 :             :     }
     216                 :             : 
     217         [ +  - ]:          17 :     if (handle->cmap) {
     218         [ +  - ]:          17 :         DUMP(prefix, "cmap: struct bf_map *");
     219                 :          17 :         bf_dump_prefix_push(prefix);
     220                 :          17 :         bf_map_dump(handle->cmap, bf_dump_prefix_last(prefix));
     221                 :          17 :         bf_dump_prefix_pop(prefix);
     222                 :             :     } else {
     223         [ #  # ]:           0 :         DUMP(prefix, "cmap: struct bf_map * (NULL)");
     224                 :             :     }
     225                 :             : 
     226         [ +  - ]:          17 :     if (handle->pmap) {
     227         [ +  - ]:          17 :         DUMP(prefix, "pmap: struct bf_map *");
     228                 :          17 :         bf_dump_prefix_push(prefix);
     229                 :          17 :         bf_map_dump(handle->pmap, bf_dump_prefix_last(prefix));
     230                 :          17 :         bf_dump_prefix_pop(prefix);
     231                 :             :     } else {
     232         [ #  # ]:           0 :         DUMP(prefix, "pmap: struct bf_map * (NULL)");
     233                 :             :     }
     234                 :             : 
     235         [ +  + ]:          17 :     if (handle->lmap) {
     236         [ +  - ]:           3 :         DUMP(prefix, "lmap: struct bf_map *");
     237                 :           3 :         bf_dump_prefix_push(prefix);
     238                 :           3 :         bf_map_dump(handle->lmap, bf_dump_prefix_last(prefix));
     239                 :           3 :         bf_dump_prefix_pop(prefix);
     240                 :             :     } else {
     241         [ +  - ]:          14 :         DUMP(prefix, "lmap: struct bf_map * (NULL)");
     242                 :             :     }
     243                 :             : 
     244         [ +  - ]:          17 :     DUMP(bf_dump_prefix_last(prefix), "sets: bf_list<bf_map>[%lu]",
     245                 :             :          bf_list_size(&handle->sets));
     246                 :          17 :     bf_dump_prefix_push(prefix);
     247   [ +  +  +  +  :          42 :     bf_list_foreach (&handle->sets, map_node) {
                   +  + ]
     248                 :             :         struct bf_map *map = bf_list_node_get_data(map_node);
     249                 :             : 
     250         [ +  + ]:           4 :         if (bf_list_is_tail(&handle->sets, map_node))
     251                 :           2 :             bf_dump_prefix_last(prefix);
     252                 :             : 
     253         [ +  + ]:           4 :         if (!map) {
     254         [ +  - ]:           2 :             DUMP(prefix, "struct bf_map * (NULL)");
     255                 :           2 :             continue;
     256                 :             :         }
     257                 :             : 
     258                 :           2 :         bf_map_dump(map, prefix);
     259                 :             :     }
     260                 :          17 :     bf_dump_prefix_pop(prefix);
     261                 :             : 
     262                 :          17 :     bf_dump_prefix_pop(prefix);
     263                 :          17 : }
     264                 :             : 
     265                 :          90 : int bf_handle_pin(struct bf_handle *handle, int dir_fd)
     266                 :             : {
     267                 :             :     int r;
     268                 :             : 
     269                 :             :     assert(handle);
     270                 :             : 
     271                 :          90 :     r = bf_bpf_obj_pin(handle->prog_name, handle->prog_fd, dir_fd);
     272         [ -  + ]:          90 :     if (r) {
     273         [ #  # ]:           0 :         bf_err_r(r, "failed to pin BPF program");
     274                 :           0 :         goto err_unpin_all;
     275                 :             :     }
     276                 :             : 
     277         [ +  - ]:          90 :     if (handle->cmap) {
     278                 :          90 :         r = bf_map_pin(handle->cmap, dir_fd);
     279         [ -  + ]:          90 :         if (r) {
     280         [ #  # ]:           0 :             bf_err_r(r, "failed to pin BPF counters map");
     281                 :           0 :             goto err_unpin_all;
     282                 :             :         }
     283                 :             :     }
     284                 :             : 
     285         [ +  - ]:          90 :     if (handle->pmap) {
     286                 :          90 :         r = bf_map_pin(handle->pmap, dir_fd);
     287         [ -  + ]:          90 :         if (r) {
     288         [ #  # ]:           0 :             bf_err_r(r, "failed to pin BPF printer map");
     289                 :           0 :             goto err_unpin_all;
     290                 :             :         }
     291                 :             :     }
     292                 :             : 
     293         [ +  + ]:          90 :     if (handle->lmap) {
     294                 :          22 :         r = bf_map_pin(handle->lmap, dir_fd);
     295         [ -  + ]:          22 :         if (r) {
     296         [ #  # ]:           0 :             bf_err_r(r, "failed to pin BPF log map");
     297                 :           0 :             goto err_unpin_all;
     298                 :             :         }
     299                 :             :     }
     300                 :             : 
     301   [ +  +  +  +  :         386 :     bf_list_foreach (&handle->sets, set_node) {
                   +  + ]
     302                 :             :         struct bf_map *map = bf_list_node_get_data(set_node);
     303                 :             : 
     304         [ +  + ]:         103 :         if (!map)
     305                 :           4 :             continue;
     306                 :             : 
     307                 :          99 :         r = bf_map_pin(map, dir_fd);
     308         [ -  + ]:          99 :         if (r) {
     309         [ #  # ]:           0 :             bf_err_r(r, "failed to pin BPF set map");
     310                 :           0 :             goto err_unpin_all;
     311                 :             :         }
     312                 :             :     }
     313                 :             : 
     314         [ +  + ]:          90 :     if (handle->link) {
     315                 :          45 :         r = bf_link_pin(handle->link, dir_fd);
     316         [ +  - ]:          45 :         if (r) {
     317         [ #  # ]:           0 :             bf_err_r(r, "failed to pin BPF link");
     318                 :           0 :             goto err_unpin_all;
     319                 :             :         }
     320                 :             :     }
     321                 :             : 
     322                 :             :     return 0;
     323                 :             : 
     324                 :           0 : err_unpin_all:
     325                 :           0 :     bf_handle_unpin(handle, dir_fd);
     326                 :           0 :     return r;
     327                 :             : }
     328                 :             : 
     329                 :          68 : void bf_handle_unpin(struct bf_handle *handle, int dir_fd)
     330                 :             : {
     331                 :             :     assert(handle);
     332                 :             : 
     333         [ +  - ]:          68 :     if (handle->cmap)
     334                 :          68 :         bf_map_unpin(handle->cmap, dir_fd);
     335         [ +  - ]:          68 :     if (handle->pmap)
     336                 :          68 :         bf_map_unpin(handle->pmap, dir_fd);
     337         [ +  + ]:          68 :     if (handle->lmap)
     338                 :          10 :         bf_map_unpin(handle->lmap, dir_fd);
     339                 :             : 
     340   [ +  +  -  +  :         164 :     bf_list_foreach (&handle->sets, set_node) {
                   +  + ]
     341                 :             :         struct bf_map *map = bf_list_node_get_data(set_node);
     342                 :             : 
     343         [ -  + ]:          14 :         if (!map)
     344                 :           0 :             continue;
     345                 :             : 
     346                 :          14 :         bf_map_unpin(map, dir_fd);
     347                 :             :     }
     348                 :             : 
     349         [ +  + ]:          68 :     if (handle->link)
     350                 :          45 :         bf_link_unpin(handle->link, dir_fd);
     351                 :             : 
     352                 :          68 :     unlinkat(dir_fd, handle->prog_name, 0);
     353                 :          68 : }
     354                 :             : 
     355                 :         108 : int bf_handle_get_counter(const struct bf_handle *handle, uint32_t counter_idx,
     356                 :             :                           struct bf_counter *counter)
     357                 :             : {
     358                 :             :     int r;
     359                 :             : 
     360                 :             :     assert(handle);
     361                 :             :     assert(counter);
     362                 :             : 
     363         [ -  + ]:         108 :     if (!handle->cmap)
     364         [ #  # ]:           0 :         return bf_err_r(-ENOENT, "handle has no counters map");
     365                 :             : 
     366                 :         108 :     r = bf_bpf_map_lookup_elem(handle->cmap->fd, &counter_idx, counter);
     367         [ -  + ]:         108 :     if (r < 0)
     368         [ #  # ]:           0 :         return bf_err_r(r, "failed to lookup counters map");
     369                 :             : 
     370                 :             :     return 0;
     371                 :             : }
     372                 :             : 
     373                 :          48 : int bf_handle_attach(struct bf_handle *handle, enum bf_hook hook,
     374                 :             :                      struct bf_hookopts **hookopts)
     375                 :             : {
     376                 :             :     int r;
     377                 :             : 
     378                 :             :     assert(handle);
     379                 :             :     assert(hookopts);
     380                 :             : 
     381         [ -  + ]:          48 :     if (handle->link)
     382         [ #  # ]:           0 :         return bf_err_r(-EEXIST, "program is already attached");
     383                 :             : 
     384                 :          48 :     r = bf_link_new(&handle->link, _BF_LINK_NAME, hook, hookopts,
     385                 :             :                     handle->prog_fd);
     386         [ +  + ]:          48 :     if (r)
     387         [ +  - ]:           4 :         return bf_err_r(r, "failed to attach bf_link");
     388                 :             : 
     389                 :             :     return 0;
     390                 :             : }
     391                 :             : 
     392                 :          57 : void bf_handle_detach(struct bf_handle *handle)
     393                 :             : {
     394                 :             :     assert(handle);
     395                 :             : 
     396         [ +  + ]:          57 :     if (handle->link) {
     397                 :          36 :         (void)bf_bpf_link_detach(handle->link->fd);
     398         [ +  + ]:          36 :         if (handle->link->fd_extra >= 0)
     399                 :           6 :             (void)bf_bpf_link_detach(handle->link->fd_extra);
     400                 :             :     }
     401                 :             : 
     402                 :          57 :     bf_link_free(&handle->link);
     403                 :          57 : }
     404                 :             : 
     405                 :          57 : void bf_handle_unload(struct bf_handle *handle)
     406                 :             : {
     407                 :             :     assert(handle);
     408                 :             : 
     409                 :          57 :     closep(&handle->prog_fd);
     410                 :             : 
     411                 :             :     /* Explicitly detach the BPF link before closing it. Relying solely on
     412                 :             :      * close() is not sufficient when the link is pinned (the pin holds a
     413                 :             :      * kernel reference that keeps the link alive). Using BPF_LINK_DETACH
     414                 :             :      * ensures the program is removed from the hook immediately. */
     415                 :          57 :     bf_handle_detach(handle);
     416                 :             : 
     417                 :          57 :     bf_link_free(&handle->link);
     418                 :          57 :     bf_map_free(&handle->cmap);
     419                 :          57 :     bf_map_free(&handle->pmap);
     420                 :          57 :     bf_map_free(&handle->lmap);
     421                 :          57 :     bf_list_clean(&handle->sets);
     422                 :          57 : }
        

Generated by: LCOV version 2.0-1