LCOV - code coverage report
Current view: top level - bpfilter - main.c (source / functions) Coverage Total Hit
Test: coverage.lcov Lines: 79.5 % 195 155
Test Date: 2025-11-24 12:34:34 Functions: 100.0 % 8 8
Branches: 46.1 % 204 94

             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                 :             : #define _GNU_SOURCE
       7                 :             : 
       8                 :             : #include <argp.h>
       9                 :             : #include <errno.h>
      10                 :             : #include <signal.h>
      11                 :             : #include <string.h>
      12                 :             : #include <sys/socket.h>
      13                 :             : #include <sys/un.h>
      14                 :             : #include <unistd.h>
      15                 :             : 
      16                 :             : #include <bpfilter/btf.h>
      17                 :             : #include <bpfilter/dump.h>
      18                 :             : #include <bpfilter/front.h>
      19                 :             : #include <bpfilter/helper.h>
      20                 :             : #include <bpfilter/io.h>
      21                 :             : #include <bpfilter/logger.h>
      22                 :             : #include <bpfilter/ns.h>
      23                 :             : #include <bpfilter/pack.h>
      24                 :             : #include <bpfilter/request.h>
      25                 :             : #include <bpfilter/response.h>
      26                 :             : #include <bpfilter/version.h>
      27                 :             : 
      28                 :             : #include "ctx.h"
      29                 :             : #include "opts.h"
      30                 :             : #include "xlate/front.h"
      31                 :             : 
      32                 :             : /**
      33                 :             :  * Global flag to indicate whether the daemon should stop.
      34                 :             :  */
      35                 :             : static volatile sig_atomic_t _bf_stop_received = 0;
      36                 :             : 
      37                 :             : /**
      38                 :             :  * Path to bpfilter's runtime context file.
      39                 :             :  *
      40                 :             :  * bpfilter will periodically save its internal context back to disk, to prevent
      41                 :             :  * spurious service interruption to lose information about the current state of
      42                 :             :  * the daemon.
      43                 :             :  *
      44                 :             :  * This runtime context is read back when the daemon is restarted, so bpfilter
      45                 :             :  * can manage the BPF programs that survived the daemon reboot.
      46                 :             :  */
      47                 :             : static const char *ctx_path = BF_RUNTIME_DIR "/data.bin";
      48                 :             : 
      49                 :             : /**
      50                 :             :  * Set atomic flag to stop the daemon if specific signals are received.
      51                 :             :  *
      52                 :             :  * @param sig Signal number.
      53                 :             :  */
      54                 :          19 : void _bf_sig_handler(int sig)
      55                 :             : {
      56                 :             :     UNUSED(sig);
      57                 :             : 
      58                 :          19 :     _bf_stop_received = 1;
      59                 :          19 : }
      60                 :             : 
      61                 :             : /**
      62                 :             :  * Load bpfilter's runtime context from disk.
      63                 :             :  *
      64                 :             :  * Read the daemon's runtime context from @p path and initialize the internal
      65                 :             :  * context with it.
      66                 :             :  *
      67                 :             :  * @param path Path to the context file.
      68                 :             :  * @return This function will return:
      69                 :             :  *         - 1 if the runtime context has been succesfully restored from the disk.
      70                 :             :  *         - 0 if no serialized context has been found on the disk.
      71                 :             :  *         - < 0 on error.
      72                 :             :  */
      73                 :          20 : static int _bf_load(const char *path)
      74                 :             : {
      75                 :          20 :     _free_bf_rpack_ bf_rpack_t *pack = NULL;
      76                 :          20 :     _cleanup_free_ void *data = NULL;
      77                 :             :     bf_rpack_node_t child, array_node;
      78                 :             :     size_t data_len;
      79                 :             :     int r;
      80                 :             : 
      81                 :             :     bf_assert(path);
      82                 :             : 
      83         [ +  + ]:          20 :     if (access(ctx_path, F_OK)) {
      84         [ -  + ]:          18 :         if (errno != ENOENT) {
      85         [ #  # ]:           0 :             return bf_info_r(errno, "failed test access to context file: %s",
      86                 :             :                              path);
      87                 :             :         }
      88                 :             : 
      89         [ +  - ]:          18 :         bf_info("no serialized context found on disk, "
      90                 :             :                 "a new context will be created");
      91                 :             : 
      92                 :          18 :         return 0;
      93                 :             :     }
      94                 :             : 
      95                 :           2 :     r = bf_read_file(path, &data, &data_len);
      96         [ +  - ]:           2 :     if (r < 0)
      97                 :             :         return r;
      98                 :             : 
      99                 :           2 :     r = bf_rpack_new(&pack, data, data_len);
     100         [ +  - ]:           2 :     if (r)
     101                 :             :         return r;
     102                 :             : 
     103                 :           2 :     r = bf_rpack_kv_obj(bf_rpack_root(pack), "ctx", &child);
     104         [ +  - ]:           2 :     if (r)
     105                 :             :         return r;
     106                 :             : 
     107                 :           2 :     r = bf_ctx_load(child);
     108         [ +  - ]:           2 :     if (r < 0)
     109                 :             :         return r;
     110                 :             : 
     111                 :           2 :     r = bf_rpack_kv_array(bf_rpack_root(pack), "cache", &child);
     112         [ +  - ]:           2 :     if (r)
     113                 :             :         return r;
     114   [ +  -  +  +  :          16 :     bf_rpack_array_foreach (child, array_node) {
                   +  + ]
     115         [ -  + ]:           6 :         if (bf_rpack_is_nil(array_node))
     116                 :           0 :             continue;
     117                 :             : 
     118                 :           6 :         r = bf_front_ops_get(i)->unpack(array_node);
     119         [ -  + ]:           6 :         if (r < 0) {
     120         [ #  # ]:           0 :             return bf_err_r(r, "failed to restore context for %s",
     121                 :             :                             bf_front_to_str(i));
     122                 :             :         }
     123                 :             :     }
     124                 :             : 
     125         [ +  - ]:           2 :     bf_dbg("loaded serialized context from %s", path);
     126                 :             : 
     127                 :             :     return 1;
     128                 :             : }
     129                 :             : 
     130                 :             : /**
     131                 :             :  * Save bpfilter's runtime context to disk.
     132                 :             :  *
     133                 :             :  * @param path Path to the context file.
     134                 :             :  * @return 0 on success, negative error code on failure.
     135                 :             :  */
     136                 :         108 : static int _bf_save(const char *path)
     137                 :             : {
     138                 :         108 :     _free_bf_wpack_ bf_wpack_t *pack = NULL;
     139                 :             :     const void *data;
     140                 :             :     size_t data_len;
     141                 :             :     int r;
     142                 :             : 
     143                 :             :     bf_assert(path);
     144                 :             : 
     145         [ +  + ]:         108 :     if (bf_ctx_is_empty()) {
     146                 :             :         /* If the context is empty, we don't need to save it and we can remove
     147                 :             :          * the existing save. */
     148                 :          31 :         unlink(path);
     149                 :          31 :         return 0;
     150                 :             :     }
     151                 :             : 
     152                 :          77 :     r = bf_wpack_new(&pack);
     153         [ +  - ]:          77 :     if (r)
     154                 :             :         return r;
     155                 :             : 
     156                 :          77 :     bf_wpack_open_object(pack, "ctx");
     157                 :          77 :     r = bf_ctx_save(pack);
     158         [ +  - ]:          77 :     if (r)
     159                 :             :         return r;
     160                 :          77 :     bf_wpack_close_object(pack);
     161                 :             : 
     162                 :             :     /** @todo Front packing should be name-based to avoid relying on the
     163                 :             :      * enumeration order. */
     164                 :          77 :     bf_wpack_open_array(pack, "cache");
     165         [ +  + ]:         308 :     for (int i = 0; i < _BF_FRONT_MAX; ++i) {
     166         [ +  - ]:         231 :         if (bf_opts_is_front_enabled(i)) {
     167                 :         231 :             bf_wpack_open_object(pack, NULL);
     168                 :         231 :             r = bf_front_ops_get(i)->pack(pack);
     169         [ +  - ]:         231 :             if (r < 0)
     170                 :             :                 return r;
     171                 :         231 :             bf_wpack_close_object(pack);
     172                 :             :         } else {
     173                 :           0 :             bf_wpack_nil(pack);
     174                 :             :         }
     175                 :             :     }
     176                 :          77 :     bf_wpack_close_array(pack);
     177                 :             : 
     178                 :          77 :     r = bf_wpack_get_data(pack, &data, &data_len);
     179         [ +  - ]:          77 :     if (r)
     180                 :             :         return r;
     181                 :             : 
     182                 :          77 :     r = bf_write_file(path, data, data_len);
     183         [ +  - ]:          77 :     if (r < 0)
     184                 :             :         return r;
     185                 :             : 
     186         [ -  + ]:          77 :     bf_dbg("saved serialized context to %s", path);
     187                 :             : 
     188                 :             :     return 0;
     189                 :             : }
     190                 :             : 
     191                 :             : /**
     192                 :             :  * Initialize bpfilter's daemon runtime.
     193                 :             :  *
     194                 :             :  * Setup signal handler (for graceful shutdown), load context from disk, and
     195                 :             :  * initialise various front-ends.
     196                 :             :  *
     197                 :             :  * If no context can be loaded, a new one is initialized from scratch.
     198                 :             :  *
     199                 :             :  * Front-ends' @p init function is called every time. They are responsible for
     200                 :             :  * checking whether they need to perform any initialization or not, depending
     201                 :             :  * on the loaded runtime context.
     202                 :             :  *
     203                 :             :  * Updated context is saved back to disk.
     204                 :             :  *
     205                 :             :  * @return 0 on success, negative error code on failure.
     206                 :             :  */
     207                 :          20 : static int _bf_init(int argc, char *argv[])
     208                 :             : {
     209                 :          20 :     struct sigaction sighandler = {.sa_handler = _bf_sig_handler};
     210                 :             :     int r = 0;
     211                 :             : 
     212         [ -  + ]:          20 :     if (sigaction(SIGINT, &sighandler, NULL) < 0)
     213         [ #  # ]:           0 :         return bf_err_r(errno, "can't override handler for SIGINT");
     214                 :             : 
     215         [ -  + ]:          20 :     if (sigaction(SIGTERM, &sighandler, NULL) < 0)
     216         [ #  # ]:           0 :         return bf_err_r(errno, "can't override handler for SIGTERM");
     217                 :             : 
     218         [ +  - ]:          20 :     bf_info("starting bpfilter version %s", BF_VERSION);
     219                 :             : 
     220                 :          20 :     r = bf_opts_init(argc, argv);
     221         [ -  + ]:          20 :     if (r < 0)
     222         [ #  # ]:           0 :         return bf_err_r(r, "failed to parse command line arguments");
     223                 :             : 
     224                 :          20 :     r = bf_ensure_dir(BF_RUNTIME_DIR);
     225         [ -  + ]:          20 :     if (r)
     226         [ #  # ]:           0 :         return bf_err_r(r, "failed to ensure runtime directory exists");
     227                 :             : 
     228                 :             :     // Either load context, or initialize it from scratch.
     229         [ +  - ]:          20 :     if (!bf_opts_transient()) {
     230                 :          20 :         r = _bf_load(ctx_path);
     231         [ -  + ]:          20 :         if (r < 0)
     232         [ #  # ]:           0 :             return bf_err_r(r, "failed to restore bpfilter context");
     233                 :             :     }
     234                 :             : 
     235   [ +  -  +  + ]:          20 :     if (bf_opts_transient() || r == 0) {
     236                 :          18 :         r = bf_ctx_setup();
     237         [ -  + ]:          18 :         if (r < 0)
     238         [ #  # ]:           0 :             return bf_err_r(r, "failed to setup context");
     239                 :             :     }
     240                 :             : 
     241                 :          20 :     bf_ctx_dump(EMPTY_PREFIX);
     242                 :             : 
     243         [ +  + ]:          80 :     for (enum bf_front front = 0; front < _BF_FRONT_MAX; ++front) {
     244         [ -  + ]:          60 :         if (!bf_opts_is_front_enabled(front))
     245                 :           0 :             continue;
     246                 :             : 
     247                 :          60 :         r = bf_front_ops_get(front)->setup();
     248         [ -  + ]:          60 :         if (r < 0) {
     249         [ #  # ]:           0 :             return bf_err_r(r, "failed to setup front-end %s",
     250                 :             :                             bf_front_to_str(front));
     251                 :             :         }
     252                 :             : 
     253         [ +  - ]:          60 :         bf_dbg("completed setup for %s", bf_front_to_str(front));
     254                 :             :     }
     255                 :             : 
     256         [ +  - ]:          20 :     if (!bf_opts_transient()) {
     257                 :          20 :         r = _bf_save(ctx_path);
     258         [ +  - ]:          20 :         if (r < 0) {
     259         [ #  # ]:           0 :             return bf_err_r(r, "failed to backup context at %s", ctx_path);
     260                 :             :         }
     261                 :             :     }
     262                 :             : 
     263                 :             :     return 0;
     264                 :             : }
     265                 :             : 
     266                 :             : /**
     267                 :             :  * Clean up bpfilter's daemon runtime.
     268                 :             :  *
     269                 :             :  * @return 0 on success, negative error code on failure.
     270                 :             :  */
     271                 :          19 : static int _bf_clean(void)
     272                 :             : {
     273                 :          19 :     _cleanup_close_ int pindir_fd = -1;
     274                 :             :     int r;
     275                 :             : 
     276         [ +  + ]:          76 :     for (enum bf_front front = 0; front < _BF_FRONT_MAX; ++front) {
     277         [ -  + ]:          57 :         if (!bf_opts_is_front_enabled(front))
     278                 :           0 :             continue;
     279                 :             : 
     280                 :          57 :         r = bf_front_ops_get(front)->teardown();
     281         [ -  + ]:          57 :         if (r < 0) {
     282         [ #  # ]:           0 :             bf_warn_r(r, "failed to teardown front-end %s, continuing",
     283                 :             :                       bf_front_to_str(front));
     284                 :             :         }
     285                 :             :     }
     286                 :             : 
     287                 :          19 :     bf_ctx_teardown(bf_opts_transient());
     288                 :             : 
     289                 :          19 :     r = bf_ctx_rm_pindir();
     290   [ -  +  -  - ]:          19 :     if (r < 0 && r != -ENOENT && errno != -ENOTEMPTY)
     291         [ #  # ]:           0 :         return bf_err_r(r, "failed to remove pin directory");
     292                 :             : 
     293                 :             :     return 0;
     294                 :             : }
     295                 :             : 
     296                 :             : /**
     297                 :             :  * Process a request.
     298                 :             :  *
     299                 :             :  * The handler corresponding to @p bf_request_front(request) will be called (if any).
     300                 :             :  * If the handler returns 0, @p response is expected to be filled, and ready
     301                 :             :  * to be returned to the client.
     302                 :             :  * If the handler returns a negative error code, @p response is filled by @ref
     303                 :             :  * _bf_process_request with a generated error response and 0 is returned. If
     304                 :             :  * generating the error response fails, then 0 is returned.
     305                 :             :  *
     306                 :             :  * In other words, if 0 is returned, @p response is ready to be sent back, if
     307                 :             :  * a negative error code is returned, an error occured during @p request
     308                 :             :  * processing, and no response is available.
     309                 :             :  *
     310                 :             :  * @param request Request to process. Can't be NULL.
     311                 :             :  * @param response Response to fill. Can't be NULL.
     312                 :             :  * @return 0 on success, negative error code on failure.
     313                 :             :  */
     314                 :         101 : static int _bf_process_request(struct bf_request *request,
     315                 :             :                                struct bf_response **response)
     316                 :             : {
     317                 :             :     const struct bf_front_ops *ops;
     318                 :             :     int r;
     319                 :             : 
     320                 :             :     bf_assert(request && response);
     321                 :             : 
     322         [ -  + ]:         202 :     if (bf_request_front(request) < 0 ||
     323                 :         101 :         bf_request_front(request) >= _BF_FRONT_MAX) {
     324         [ #  # ]:           0 :         bf_warn("received a request from front %d, unknown front, ignoring",
     325                 :             :                 bf_request_front(request));
     326                 :           0 :         return bf_response_new_failure(response, -EINVAL);
     327                 :             :     }
     328                 :             : 
     329         [ -  + ]:         202 :     if (bf_request_cmd(request) < 0 ||
     330                 :         101 :         bf_request_cmd(request) >= _BF_REQ_CMD_MAX) {
     331         [ #  # ]:           0 :         bf_warn("received a request with command %d, unknown command, ignoring",
     332                 :             :                 bf_request_cmd(request));
     333                 :           0 :         return bf_response_new_failure(response, -EINVAL);
     334                 :             :     }
     335                 :             : 
     336         [ -  + ]:         101 :     if (!bf_opts_is_front_enabled(bf_request_front(request))) {
     337         [ #  # ]:           0 :         bf_warn("received a request from %s, but front is disabled, ignoring",
     338                 :             :                 bf_front_to_str(bf_request_front(request)));
     339                 :           0 :         return bf_response_new_failure(response, -ENOTSUP);
     340                 :             :     }
     341                 :             : 
     342         [ +  - ]:         101 :     bf_info("processing request %s from %s",
     343                 :             :             bf_request_cmd_to_str(bf_request_cmd(request)),
     344                 :             :             bf_front_to_str(bf_request_front(request)));
     345                 :             : 
     346                 :         101 :     ops = bf_front_ops_get(bf_request_front(request));
     347                 :         101 :     r = ops->request_handler(request, response);
     348         [ -  + ]:         101 :     if (r) {
     349                 :             :         /* We failed to process the request, so we need to generate an
     350                 :             :          * error. If the error response is successfully generated, then we
     351                 :             :          * return 0, otherwise we return the error code. */
     352                 :           0 :         r = bf_response_new_failure(response, r);
     353                 :             :     }
     354                 :             : 
     355   [ +  -  +  + ]:         202 :     if (!bf_opts_transient() &&
     356         [ +  + ]:         200 :         (bf_request_cmd(request) == BF_REQ_RULESET_FLUSH ||
     357         [ +  + ]:         190 :          bf_request_cmd(request) == BF_REQ_RULESET_SET ||
     358         [ +  + ]:         149 :          bf_request_cmd(request) == BF_REQ_CHAIN_SET ||
     359         [ +  + ]:         104 :          bf_request_cmd(request) == BF_REQ_CHAIN_LOAD ||
     360         [ +  + ]:          82 :          bf_request_cmd(request) == BF_REQ_CHAIN_ATTACH ||
     361         [ +  + ]:          67 :          bf_request_cmd(request) == BF_REQ_CHAIN_UPDATE ||
     362                 :          31 :          bf_request_cmd(request) == BF_REQ_CHAIN_FLUSH))
     363                 :          88 :         r = _bf_save(ctx_path);
     364                 :             : 
     365                 :             :     return r;
     366                 :             : }
     367                 :             : 
     368                 :             : /**
     369                 :             :  * Loop and process requests.
     370                 :             :  *
     371                 :             :  * Create a socket and perform blocking accept() calls. For each connection,
     372                 :             :  * receive a request, process it, and send the response back.
     373                 :             :  *
     374                 :             :  * If a signal is received, @ref _bf_stop_received will be set to 1 by @ref
     375                 :             :  * _bf_sig_handler and blocking call to `accept()` will be interrupted.
     376                 :             :  *
     377                 :             :  * @return 0 on success, negative error code on failure.
     378                 :             :  */
     379                 :          20 : static int _bf_run(void)
     380                 :             : {
     381                 :          20 :     _cleanup_close_ int fd = -1;
     382                 :          20 :     _cleanup_close_ int lock = -1;
     383                 :          20 :     struct sockaddr_un addr = {};
     384                 :             :     struct ucred peer_cred;
     385                 :          20 :     socklen_t peer_cred_len = sizeof(peer_cred);
     386                 :             :     int r;
     387                 :             : 
     388                 :          20 :     lock = bf_acquire_lock(BF_LOCK_PATH);
     389         [ +  + ]:          20 :     if (lock < 0) {
     390         [ +  - ]:           1 :         return bf_err_r(
     391                 :             :             lock,
     392                 :             :             "failed to acquire the daemon lock, is the daemon already running? Error");
     393                 :             :     }
     394                 :             : 
     395                 :          19 :     fd = socket(AF_UNIX, SOCK_STREAM, 0);
     396         [ -  + ]:          19 :     if (fd < 0)
     397         [ #  # ]:           0 :         return bf_err_r(errno, "failed to create socket");
     398                 :             : 
     399                 :             :     // We have a lock on the lock file, so no other daemon is running, we can
     400                 :             :     // remove the socket file (if any).
     401                 :          19 :     unlink(BF_SOCKET_PATH);
     402                 :          19 :     addr.sun_family = AF_UNIX;
     403                 :          19 :     strncpy(addr.sun_path, BF_SOCKET_PATH, sizeof(addr.sun_path) - 1);
     404                 :             : 
     405                 :          19 :     r = bind(fd, (struct sockaddr *)&addr, sizeof(addr));
     406         [ -  + ]:          19 :     if (r < 0) {
     407         [ #  # ]:           0 :         return bf_err_r(errno, "failed to bind socket to %s", BF_SOCKET_PATH);
     408                 :             :     }
     409                 :             : 
     410                 :          19 :     r = listen(fd, 1);
     411         [ -  + ]:          19 :     if (r < 0)
     412         [ #  # ]:           0 :         return bf_err_r(errno, "listen() failed");
     413                 :             : 
     414         [ +  - ]:          19 :     bf_info("waiting for requests...");
     415                 :             : 
     416         [ +  + ]:         139 :     while (!_bf_stop_received) {
     417                 :         120 :         _cleanup_close_ int client_fd = -1;
     418                 :         120 :         _free_bf_request_ struct bf_request *request = NULL;
     419                 :         120 :         _free_bf_response_ struct bf_response *response = NULL;
     420                 :         120 :         _clean_bf_ns_ struct bf_ns ns = bf_ns_default();
     421                 :             : 
     422                 :         120 :         client_fd = accept(fd, NULL, NULL);
     423         [ +  + ]:         120 :         if (client_fd < 0) {
     424         [ +  - ]:          19 :             if (_bf_stop_received) {
     425         [ +  - ]:          19 :                 bf_info("received stop signal, exiting...");
     426                 :          19 :                 continue;
     427                 :             :             }
     428                 :             : 
     429         [ #  # ]:           0 :             bf_err_r(errno, "failed to accept connection, ignoring");
     430                 :           0 :             continue;
     431                 :             :         }
     432                 :             : 
     433                 :             :         // NOLINTNEXTLINE: SOL_SOCKET and SO_PEERCRED can't be directly included
     434                 :         101 :         r = getsockopt(client_fd, SOL_SOCKET, SO_PEERCRED, &peer_cred,
     435                 :             :                        &peer_cred_len);
     436         [ -  + ]:         101 :         if (r) {
     437         [ #  # ]:           0 :             bf_err_r(errno,
     438                 :             :                      "failed to read the client's credentials, ignoring");
     439                 :           0 :             continue;
     440                 :             :         }
     441                 :             : 
     442                 :         101 :         r = bf_ns_init(&ns, peer_cred.pid);
     443         [ -  + ]:         101 :         if (r) {
     444         [ #  # ]:           0 :             bf_err_r(r, "failed to open the client's namespaces, ignoring");
     445                 :           0 :             continue;
     446                 :             :         }
     447                 :             : 
     448                 :         101 :         r = bf_recv_request(client_fd, &request);
     449         [ -  + ]:         101 :         if (r) {
     450         [ #  # ]:           0 :             bf_err_r(r, "failed to receive request, ignoring");
     451                 :           0 :             continue;
     452                 :             :         }
     453                 :             : 
     454                 :         101 :         bf_request_set_ns(request, &ns);
     455                 :         101 :         bf_request_set_fd(request, client_fd);
     456                 :             : 
     457                 :         101 :         r = _bf_process_request(request, &response);
     458         [ -  + ]:         101 :         if (r) {
     459         [ #  # ]:           0 :             bf_err_r(r, "failed to process request, ignoring");
     460                 :           0 :             continue;
     461                 :             :         }
     462                 :             : 
     463                 :         101 :         r = bf_send_response(client_fd, response);
     464         [ -  + ]:         101 :         if (r) {
     465         [ #  # ]:           0 :             bf_err_r(r, "failed to send response, ignoring");
     466                 :           0 :             continue;
     467                 :             :         }
     468                 :             :     }
     469                 :             : 
     470                 :             :     return 0;
     471                 :             : }
     472                 :             : 
     473                 :          20 : int main(int argc, char *argv[])
     474                 :             : {
     475                 :             :     int r;
     476                 :             : 
     477                 :          20 :     bf_logger_setup();
     478                 :             : 
     479                 :          20 :     argp_program_version = "bpfilter version " BF_VERSION;
     480                 :          20 :     argp_program_bug_address = BF_CONTACT;
     481                 :             : 
     482                 :          20 :     r = bf_btf_setup();
     483         [ -  + ]:          20 :     if (r < 0)
     484         [ #  # ]:           0 :         return bf_err_r(r, "failed to setup BTF module");
     485                 :             : 
     486                 :          20 :     r = _bf_init(argc, argv);
     487         [ -  + ]:          20 :     if (r < 0)
     488         [ #  # ]:           0 :         return bf_err_r(r, "failed to initialize bpfilter");
     489                 :             : 
     490                 :          20 :     r = _bf_run();
     491         [ +  + ]:          20 :     if (r < 0)
     492         [ +  - ]:           1 :         return bf_err_r(r, "run() failed");
     493                 :             : 
     494                 :          19 :     _bf_clean();
     495                 :          19 :     bf_btf_teardown();
     496                 :             : 
     497                 :          19 :     return r;
     498                 :             : }
        

Generated by: LCOV version 2.0-1