LCOV - code coverage report
Current view: top level - bpfilter - main.c (source / functions) Coverage Total Hit
Test: coverage.lcov Lines: 79.6 % 196 156
Test Date: 2026-02-10 17:55:44 Functions: 100.0 % 8 8
Branches: 46.6 % 206 96

             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                 :          25 : void _bf_sig_handler(int sig)
      55                 :             : {
      56                 :             :     (void)sig;
      57                 :             : 
      58                 :          25 :     _bf_stop_received = 1;
      59                 :          25 : }
      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                 :          26 : static int _bf_load(const char *path)
      74                 :             : {
      75                 :          26 :     _free_bf_rpack_ bf_rpack_t *pack = NULL;
      76                 :          26 :     _cleanup_free_ void *data = NULL;
      77                 :             :     bf_rpack_node_t child, array_node;
      78                 :             :     size_t data_len;
      79                 :             :     int r;
      80                 :             : 
      81                 :             :     assert(path);
      82                 :             : 
      83         [ +  + ]:          26 :     if (access(ctx_path, F_OK)) {
      84         [ -  + ]:          23 :         if (errno != ENOENT) {
      85         [ #  # ]:           0 :             return bf_info_r(errno, "failed test access to context file: %s",
      86                 :             :                              path);
      87                 :             :         }
      88                 :             : 
      89         [ +  - ]:          23 :         bf_info("no serialized context found on disk, "
      90                 :             :                 "a new context will be created");
      91                 :             : 
      92                 :          23 :         return 0;
      93                 :             :     }
      94                 :             : 
      95                 :           3 :     r = bf_read_file(path, &data, &data_len);
      96         [ +  - ]:           3 :     if (r < 0)
      97                 :             :         return r;
      98                 :             : 
      99                 :           3 :     r = bf_rpack_new(&pack, data, data_len);
     100         [ +  - ]:           3 :     if (r)
     101                 :             :         return r;
     102                 :             : 
     103                 :           3 :     r = bf_rpack_kv_obj(bf_rpack_root(pack), "ctx", &child);
     104         [ +  - ]:           3 :     if (r)
     105                 :             :         return r;
     106                 :             : 
     107                 :           3 :     r = bf_ctx_load(child);
     108         [ +  - ]:           3 :     if (r < 0)
     109                 :             :         return r;
     110                 :             : 
     111                 :           3 :     r = bf_rpack_kv_array(bf_rpack_root(pack), "cache", &child);
     112         [ +  - ]:           3 :     if (r)
     113                 :             :         return r;
     114   [ +  -  +  +  :          24 :     bf_rpack_array_foreach (child, array_node) {
                   +  + ]
     115         [ -  + ]:           9 :         if (bf_rpack_is_nil(array_node))
     116                 :           0 :             continue;
     117                 :             : 
     118                 :           9 :         r = bf_front_ops_get(i)->unpack(array_node);
     119         [ -  + ]:           9 :         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         [ +  - ]:           3 :     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                 :         152 : static int _bf_save(const char *path)
     137                 :             : {
     138                 :         152 :     _free_bf_wpack_ bf_wpack_t *pack = NULL;
     139                 :             :     const void *data;
     140                 :             :     size_t data_len;
     141                 :             :     int r;
     142                 :             : 
     143                 :             :     assert(path);
     144                 :             : 
     145         [ +  + ]:         152 :     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                 :          46 :         unlink(path);
     149                 :          46 :         return 0;
     150                 :             :     }
     151                 :             : 
     152                 :         106 :     r = bf_wpack_new(&pack);
     153         [ +  - ]:         106 :     if (r)
     154                 :             :         return r;
     155                 :             : 
     156                 :         106 :     bf_wpack_open_object(pack, "ctx");
     157                 :         106 :     r = bf_ctx_save(pack);
     158         [ +  - ]:         106 :     if (r)
     159                 :             :         return r;
     160                 :         106 :     bf_wpack_close_object(pack);
     161                 :             : 
     162                 :             :     /** @todo Front packing should be name-based to avoid relying on the
     163                 :             :      * enumeration order. */
     164                 :         106 :     bf_wpack_open_array(pack, "cache");
     165         [ +  + ]:         424 :     for (int i = 0; i < _BF_FRONT_MAX; ++i) {
     166         [ +  - ]:         318 :         if (bf_opts_is_front_enabled(i)) {
     167                 :         318 :             bf_wpack_open_object(pack, NULL);
     168                 :         318 :             r = bf_front_ops_get(i)->pack(pack);
     169         [ +  - ]:         318 :             if (r < 0)
     170                 :             :                 return r;
     171                 :         318 :             bf_wpack_close_object(pack);
     172                 :             :         } else {
     173                 :           0 :             bf_wpack_nil(pack);
     174                 :             :         }
     175                 :             :     }
     176                 :         106 :     bf_wpack_close_array(pack);
     177                 :             : 
     178                 :         106 :     r = bf_wpack_get_data(pack, &data, &data_len);
     179         [ +  - ]:         106 :     if (r)
     180                 :             :         return r;
     181                 :             : 
     182                 :         106 :     r = bf_write_file(path, data, data_len);
     183         [ +  - ]:         106 :     if (r < 0)
     184                 :             :         return r;
     185                 :             : 
     186         [ -  + ]:         106 :     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                 :          26 : static int _bf_init(int argc, char *argv[])
     208                 :             : {
     209                 :          26 :     struct sigaction sighandler = {.sa_handler = _bf_sig_handler};
     210                 :             :     int r = 0;
     211                 :             : 
     212         [ -  + ]:          26 :     if (sigaction(SIGINT, &sighandler, NULL) < 0)
     213         [ #  # ]:           0 :         return bf_err_r(errno, "can't override handler for SIGINT");
     214                 :             : 
     215         [ -  + ]:          26 :     if (sigaction(SIGTERM, &sighandler, NULL) < 0)
     216         [ #  # ]:           0 :         return bf_err_r(errno, "can't override handler for SIGTERM");
     217                 :             : 
     218         [ +  - ]:          26 :     bf_info("starting bpfilter version %s", BF_VERSION);
     219                 :             : 
     220                 :          26 :     r = bf_opts_init(argc, argv);
     221         [ -  + ]:          26 :     if (r < 0)
     222         [ #  # ]:           0 :         return bf_err_r(r, "failed to parse command line arguments");
     223                 :             : 
     224                 :          26 :     r = bf_ensure_dir(BF_RUNTIME_DIR);
     225         [ -  + ]:          26 :     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         [ +  - ]:          26 :     if (!bf_opts_transient()) {
     230                 :          26 :         r = _bf_load(ctx_path);
     231         [ -  + ]:          26 :         if (r < 0)
     232         [ #  # ]:           0 :             return bf_err_r(r, "failed to restore bpfilter context");
     233                 :             :     }
     234                 :             : 
     235   [ +  -  +  + ]:          26 :     if (bf_opts_transient() || r == 0) {
     236                 :          23 :         r = bf_ctx_setup();
     237         [ -  + ]:          23 :         if (r < 0)
     238         [ #  # ]:           0 :             return bf_err_r(r, "failed to setup context");
     239                 :             :     }
     240                 :             : 
     241                 :          26 :     bf_ctx_dump(EMPTY_PREFIX);
     242                 :             : 
     243         [ +  + ]:         104 :     for (enum bf_front front = 0; front < _BF_FRONT_MAX; ++front) {
     244         [ -  + ]:          78 :         if (!bf_opts_is_front_enabled(front))
     245                 :           0 :             continue;
     246                 :             : 
     247                 :          78 :         r = bf_front_ops_get(front)->setup();
     248         [ -  + ]:          78 :         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         [ +  - ]:          78 :         bf_dbg("completed setup for %s", bf_front_to_str(front));
     254                 :             :     }
     255                 :             : 
     256         [ +  - ]:          26 :     if (!bf_opts_transient()) {
     257                 :          26 :         r = _bf_save(ctx_path);
     258         [ +  - ]:          26 :         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                 :          25 : static int _bf_clean(void)
     272                 :             : {
     273                 :          25 :     _cleanup_close_ int pindir_fd = -1;
     274                 :             :     int r;
     275                 :             : 
     276         [ +  + ]:         100 :     for (enum bf_front front = 0; front < _BF_FRONT_MAX; ++front) {
     277         [ -  + ]:          75 :         if (!bf_opts_is_front_enabled(front))
     278                 :           0 :             continue;
     279                 :             : 
     280                 :          75 :         r = bf_front_ops_get(front)->teardown();
     281         [ -  + ]:          75 :         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                 :          25 :     bf_ctx_teardown(bf_opts_transient());
     288                 :             : 
     289                 :          25 :     r = bf_ctx_rm_pindir();
     290   [ -  +  -  - ]:          25 :     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                 :         161 : 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                 :             :     assert(request);
     321                 :             :     assert(response);
     322                 :             : 
     323         [ -  + ]:         322 :     if (bf_request_front(request) < 0 ||
     324                 :         161 :         bf_request_front(request) >= _BF_FRONT_MAX) {
     325         [ #  # ]:           0 :         bf_warn("received a request from front %d, unknown front, ignoring",
     326                 :             :                 bf_request_front(request));
     327                 :           0 :         return bf_response_new_failure(response, -EINVAL);
     328                 :             :     }
     329                 :             : 
     330         [ -  + ]:         322 :     if (bf_request_cmd(request) < 0 ||
     331                 :         161 :         bf_request_cmd(request) >= _BF_REQ_CMD_MAX) {
     332         [ #  # ]:           0 :         bf_warn("received a request with command %d, unknown command, ignoring",
     333                 :             :                 bf_request_cmd(request));
     334                 :           0 :         return bf_response_new_failure(response, -EINVAL);
     335                 :             :     }
     336                 :             : 
     337         [ -  + ]:         161 :     if (!bf_opts_is_front_enabled(bf_request_front(request))) {
     338         [ #  # ]:           0 :         bf_warn("received a request from %s, but front is disabled, ignoring",
     339                 :             :                 bf_front_to_str(bf_request_front(request)));
     340                 :           0 :         return bf_response_new_failure(response, -ENOTSUP);
     341                 :             :     }
     342                 :             : 
     343         [ +  - ]:         161 :     bf_info("processing request %s from %s",
     344                 :             :             bf_request_cmd_to_str(bf_request_cmd(request)),
     345                 :             :             bf_front_to_str(bf_request_front(request)));
     346                 :             : 
     347                 :         161 :     ops = bf_front_ops_get(bf_request_front(request));
     348                 :         161 :     r = ops->request_handler(request, response);
     349         [ -  + ]:         161 :     if (r) {
     350                 :             :         /* We failed to process the request, so we need to generate an
     351                 :             :          * error. If the error response is successfully generated, then we
     352                 :             :          * return 0, otherwise we return the error code. */
     353                 :           0 :         r = bf_response_new_failure(response, r);
     354                 :             :     }
     355                 :             : 
     356   [ +  -  +  + ]:         322 :     if (!bf_opts_transient() &&
     357         [ +  + ]:         316 :         (bf_request_cmd(request) == BF_REQ_RULESET_FLUSH ||
     358         [ +  + ]:         302 :          bf_request_cmd(request) == BF_REQ_RULESET_SET ||
     359         [ +  + ]:         236 :          bf_request_cmd(request) == BF_REQ_CHAIN_SET ||
     360         [ +  + ]:         166 :          bf_request_cmd(request) == BF_REQ_CHAIN_LOAD ||
     361         [ +  + ]:         144 :          bf_request_cmd(request) == BF_REQ_CHAIN_ATTACH ||
     362         [ +  + ]:         128 :          bf_request_cmd(request) == BF_REQ_CHAIN_UPDATE ||
     363         [ +  + ]:         116 :          bf_request_cmd(request) == BF_REQ_CHAIN_UPDATE_SET ||
     364                 :          55 :          bf_request_cmd(request) == BF_REQ_CHAIN_FLUSH))
     365                 :         126 :         r = _bf_save(ctx_path);
     366                 :             : 
     367                 :             :     return r;
     368                 :             : }
     369                 :             : 
     370                 :             : /**
     371                 :             :  * Loop and process requests.
     372                 :             :  *
     373                 :             :  * Create a socket and perform blocking accept() calls. For each connection,
     374                 :             :  * receive a request, process it, and send the response back.
     375                 :             :  *
     376                 :             :  * If a signal is received, @ref _bf_stop_received will be set to 1 by @ref
     377                 :             :  * _bf_sig_handler and blocking call to `accept()` will be interrupted.
     378                 :             :  *
     379                 :             :  * @return 0 on success, negative error code on failure.
     380                 :             :  */
     381                 :          26 : static int _bf_run(void)
     382                 :             : {
     383                 :          26 :     _cleanup_close_ int fd = -1;
     384                 :          26 :     _cleanup_close_ int lock = -1;
     385                 :          26 :     struct sockaddr_un addr = {};
     386                 :             :     struct ucred peer_cred;
     387                 :          26 :     socklen_t peer_cred_len = sizeof(peer_cred);
     388                 :             :     int r;
     389                 :             : 
     390                 :          26 :     lock = bf_acquire_lock(BF_LOCK_PATH);
     391         [ +  + ]:          26 :     if (lock < 0) {
     392         [ +  - ]:           1 :         return bf_err_r(
     393                 :             :             lock,
     394                 :             :             "failed to acquire the daemon lock, is the daemon already running? Error");
     395                 :             :     }
     396                 :             : 
     397                 :          25 :     fd = socket(AF_UNIX, SOCK_STREAM, 0);
     398         [ -  + ]:          25 :     if (fd < 0)
     399         [ #  # ]:           0 :         return bf_err_r(errno, "failed to create socket");
     400                 :             : 
     401                 :             :     // We have a lock on the lock file, so no other daemon is running, we can
     402                 :             :     // remove the socket file (if any).
     403                 :          25 :     unlink(BF_SOCKET_PATH);
     404                 :          25 :     addr.sun_family = AF_UNIX;
     405                 :          25 :     strncpy(addr.sun_path, BF_SOCKET_PATH, sizeof(addr.sun_path) - 1);
     406                 :             : 
     407                 :          25 :     r = bind(fd, (struct sockaddr *)&addr, sizeof(addr));
     408         [ -  + ]:          25 :     if (r < 0) {
     409         [ #  # ]:           0 :         return bf_err_r(errno, "failed to bind socket to %s", BF_SOCKET_PATH);
     410                 :             :     }
     411                 :             : 
     412                 :          25 :     r = listen(fd, 1);
     413         [ -  + ]:          25 :     if (r < 0)
     414         [ #  # ]:           0 :         return bf_err_r(errno, "listen() failed");
     415                 :             : 
     416         [ +  - ]:          25 :     bf_info("waiting for requests...");
     417                 :             : 
     418         [ +  + ]:         211 :     while (!_bf_stop_received) {
     419                 :         186 :         _cleanup_close_ int client_fd = -1;
     420                 :         186 :         _free_bf_request_ struct bf_request *request = NULL;
     421                 :         186 :         _free_bf_response_ struct bf_response *response = NULL;
     422                 :         186 :         _clean_bf_ns_ struct bf_ns ns = bf_ns_default();
     423                 :             : 
     424                 :         186 :         client_fd = accept(fd, NULL, NULL);
     425         [ +  + ]:         186 :         if (client_fd < 0) {
     426         [ +  - ]:          25 :             if (_bf_stop_received) {
     427         [ +  - ]:          25 :                 bf_info("received stop signal, exiting...");
     428                 :          25 :                 continue;
     429                 :             :             }
     430                 :             : 
     431         [ #  # ]:           0 :             bf_err_r(errno, "failed to accept connection, ignoring");
     432                 :           0 :             continue;
     433                 :             :         }
     434                 :             : 
     435                 :             :         // NOLINTNEXTLINE: SOL_SOCKET and SO_PEERCRED can't be directly included
     436                 :         161 :         r = getsockopt(client_fd, SOL_SOCKET, SO_PEERCRED, &peer_cred,
     437                 :             :                        &peer_cred_len);
     438         [ -  + ]:         161 :         if (r) {
     439         [ #  # ]:           0 :             bf_err_r(errno,
     440                 :             :                      "failed to read the client's credentials, ignoring");
     441                 :           0 :             continue;
     442                 :             :         }
     443                 :             : 
     444                 :         161 :         r = bf_ns_init(&ns, peer_cred.pid);
     445         [ -  + ]:         161 :         if (r) {
     446         [ #  # ]:           0 :             bf_err_r(r, "failed to open the client's namespaces, ignoring");
     447                 :           0 :             continue;
     448                 :             :         }
     449                 :             : 
     450                 :         161 :         r = bf_recv_request(client_fd, &request);
     451         [ -  + ]:         161 :         if (r) {
     452         [ #  # ]:           0 :             bf_err_r(r, "failed to receive request, ignoring");
     453                 :           0 :             continue;
     454                 :             :         }
     455                 :             : 
     456                 :         161 :         bf_request_set_ns(request, &ns);
     457                 :         161 :         bf_request_set_fd(request, client_fd);
     458                 :             : 
     459                 :         161 :         r = _bf_process_request(request, &response);
     460         [ -  + ]:         161 :         if (r) {
     461         [ #  # ]:           0 :             bf_err_r(r, "failed to process request, ignoring");
     462                 :           0 :             continue;
     463                 :             :         }
     464                 :             : 
     465                 :         161 :         r = bf_send_response(client_fd, response);
     466         [ -  + ]:         161 :         if (r) {
     467         [ #  # ]:           0 :             bf_err_r(r, "failed to send response, ignoring");
     468                 :           0 :             continue;
     469                 :             :         }
     470                 :             :     }
     471                 :             : 
     472                 :             :     return 0;
     473                 :             : }
     474                 :             : 
     475                 :          26 : int main(int argc, char *argv[])
     476                 :             : {
     477                 :             :     int r;
     478                 :             : 
     479                 :          26 :     bf_logger_setup();
     480                 :             : 
     481                 :          26 :     argp_program_version = "bpfilter version " BF_VERSION;
     482                 :          26 :     argp_program_bug_address = BF_CONTACT;
     483                 :             : 
     484                 :          26 :     r = bf_btf_setup();
     485         [ -  + ]:          26 :     if (r < 0)
     486         [ #  # ]:           0 :         return bf_err_r(r, "failed to setup BTF module");
     487                 :             : 
     488                 :          26 :     r = _bf_init(argc, argv);
     489         [ -  + ]:          26 :     if (r < 0)
     490         [ #  # ]:           0 :         return bf_err_r(r, "failed to initialize bpfilter");
     491                 :             : 
     492                 :          26 :     r = _bf_run();
     493         [ +  + ]:          26 :     if (r < 0)
     494         [ +  - ]:           1 :         return bf_err_r(r, "run() failed");
     495                 :             : 
     496                 :          25 :     _bf_clean();
     497                 :          25 :     bf_btf_teardown();
     498                 :             : 
     499                 :          25 :     return r;
     500                 :             : }
        

Generated by: LCOV version 2.0-1