back to topotato report
topotato coverage report
Current view: top level - bfdd - bfdd.c (source / functions) Hit Total Coverage
Test: aggregated run ( view descriptions ) Lines: 47 145 32.4 %
Date: 2023-02-24 14:41:08 Functions: 11 15 73.3 %

          Line data    Source code
       1             : /*
       2             :  * BFD daemon code
       3             :  * Copyright (C) 2018 Network Device Education Foundation, Inc. ("NetDEF")
       4             :  *
       5             :  * FRR is free software; you can redistribute it and/or modify it
       6             :  * under the terms of the GNU General Public License as published by the
       7             :  * Free Software Foundation; either version 2, or (at your option) any
       8             :  * later version.
       9             :  *
      10             :  * FRR is distributed in the hope that it will be useful, but
      11             :  * WITHOUT ANY WARRANTY; without even the implied warranty of
      12             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      13             :  * General Public License for more details.
      14             :  *
      15             :  * You should have received a copy of the GNU General Public License
      16             :  * along with FRR; see the file COPYING.  If not, write to the Free
      17             :  * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
      18             :  * 02111-1307, USA.
      19             :  */
      20             : 
      21             : #include <zebra.h>
      22             : 
      23             : #include <arpa/inet.h>
      24             : #include <netinet/in.h>
      25             : #include <sys/socket.h>
      26             : #include <sys/un.h>
      27             : 
      28             : #include <err.h>
      29             : 
      30             : #include "filter.h"
      31             : #include "if.h"
      32             : #include "vrf.h"
      33             : 
      34             : #include "bfd.h"
      35             : #include "bfdd_nb.h"
      36             : #include "bfddp_packet.h"
      37             : #include "lib/version.h"
      38             : #include "lib/command.h"
      39             : 
      40             : 
      41             : /*
      42             :  * FRR related code.
      43             :  */
      44          24 : DEFINE_MGROUP(BFDD, "Bidirectional Forwarding Detection Daemon");
      45          24 : DEFINE_MTYPE(BFDD, BFDD_CONTROL, "long-lived control socket memory");
      46          24 : DEFINE_MTYPE(BFDD, BFDD_NOTIFICATION, "short-lived control notification data");
      47             : 
      48             : /* Master of threads. */
      49             : struct thread_master *master;
      50             : 
      51             : /* BFDd privileges */
      52             : static zebra_capabilities_t _caps_p[] = {ZCAP_BIND, ZCAP_SYS_ADMIN, ZCAP_NET_RAW};
      53             : 
      54             : /* BFD daemon information. */
      55             : static struct frr_daemon_info bfdd_di;
      56             : 
      57          64 : void socket_close(int *s)
      58             : {
      59          64 :         if (*s <= 0)
      60             :                 return;
      61             : 
      62          56 :         if (close(*s) != 0)
      63           0 :                 zlog_err("%s: close(%d): (%d) %s", __func__, *s, errno,
      64             :                          strerror(errno));
      65             : 
      66          56 :         *s = -1;
      67             : }
      68             : 
      69           0 : static void sigusr1_handler(void)
      70             : {
      71           0 :         zlog_rotate();
      72           0 : }
      73             : 
      74           8 : static void sigterm_handler(void)
      75             : {
      76           8 :         bglobal.bg_shutdown = true;
      77             : 
      78             :         /* Signalize shutdown. */
      79           8 :         frr_early_fini();
      80             : 
      81             :         /* Stop receiving message from zebra. */
      82           8 :         bfdd_zclient_stop();
      83             : 
      84             :         /* Shutdown controller to avoid receiving anymore commands. */
      85           8 :         control_shutdown();
      86             : 
      87             :         /* Shutdown and free all protocol related memory. */
      88           8 :         bfd_shutdown();
      89             : 
      90           8 :         bfd_vrf_terminate();
      91             : 
      92             :         /* Terminate and free() FRR related memory. */
      93           8 :         frr_fini();
      94             : 
      95           8 :         exit(0);
      96             : }
      97             : 
      98           0 : static void sighup_handler(void)
      99             : {
     100           0 :         zlog_info("SIGHUP received");
     101             : 
     102             :         /* Reload config file. */
     103           0 :         vty_read_config(NULL, bfdd_di.config_file, config_default);
     104           0 : }
     105             : 
     106             : static struct frr_signal_t bfd_signals[] = {
     107             :         {
     108             :                 .signal = SIGUSR1,
     109             :                 .handler = &sigusr1_handler,
     110             :         },
     111             :         {
     112             :                 .signal = SIGTERM,
     113             :                 .handler = &sigterm_handler,
     114             :         },
     115             :         {
     116             :                 .signal = SIGINT,
     117             :                 .handler = &sigterm_handler,
     118             :         },
     119             :         {
     120             :                 .signal = SIGHUP,
     121             :                 .handler = &sighup_handler,
     122             :         },
     123             : };
     124             : 
     125             : static const struct frr_yang_module_info *const bfdd_yang_modules[] = {
     126             :         &frr_filter_info,
     127             :         &frr_interface_info,
     128             :         &frr_bfdd_info,
     129             :         &frr_vrf_info,
     130             : };
     131             : 
     132           8 : FRR_DAEMON_INFO(bfdd, BFD, .vty_port = 2617,
     133             :                 .proghelp = "Implementation of the BFD protocol.",
     134             :                 .signals = bfd_signals, .n_signals = array_size(bfd_signals),
     135             :                 .privs = &bglobal.bfdd_privs,
     136             :                 .yang_modules = bfdd_yang_modules,
     137             :                 .n_yang_modules = array_size(bfdd_yang_modules),
     138             : );
     139             : 
     140             : #define OPTION_CTLSOCK 1001
     141             : #define OPTION_DPLANEADDR 2000
     142             : static const struct option longopts[] = {
     143             :         {"bfdctl", required_argument, NULL, OPTION_CTLSOCK},
     144             :         {"dplaneaddr", required_argument, NULL, OPTION_DPLANEADDR},
     145             :         {0}
     146             : };
     147             : 
     148             : 
     149             : /*
     150             :  * BFD daemon related code.
     151             :  */
     152             : struct bfd_global bglobal;
     153             : 
     154             : const struct bfd_diag_str_list diag_list[] = {
     155             :         {.str = "control-expired", .type = BD_CONTROL_EXPIRED},
     156             :         {.str = "echo-failed", .type = BD_ECHO_FAILED},
     157             :         {.str = "neighbor-down", .type = BD_NEIGHBOR_DOWN},
     158             :         {.str = "forwarding-reset", .type = BD_FORWARDING_RESET},
     159             :         {.str = "path-down", .type = BD_PATH_DOWN},
     160             :         {.str = "concatenated-path-down", .type = BD_CONCATPATH_DOWN},
     161             :         {.str = "administratively-down", .type = BD_ADMIN_DOWN},
     162             :         {.str = "reverse-concat-path-down", .type = BD_REVCONCATPATH_DOWN},
     163             :         {.str = NULL},
     164             : };
     165             : 
     166             : const struct bfd_state_str_list state_list[] = {
     167             :         {.str = "admin-down", .type = PTM_BFD_ADM_DOWN},
     168             :         {.str = "down", .type = PTM_BFD_DOWN},
     169             :         {.str = "init", .type = PTM_BFD_INIT},
     170             :         {.str = "up", .type = PTM_BFD_UP},
     171             :         {.str = NULL},
     172             : };
     173             : 
     174             : static uint16_t
     175           0 : parse_port(const char *str)
     176             : {
     177           0 :         char *nulbyte;
     178           0 :         long rv;
     179             : 
     180           0 :         errno = 0;
     181           0 :         rv = strtol(str, &nulbyte, 10);
     182             :         /* No conversion performed. */
     183           0 :         if (rv == 0 && errno == EINVAL) {
     184           0 :                 fprintf(stderr, "invalid BFD data plane address port: %s\n",
     185             :                         str);
     186           0 :                 exit(0);
     187             :         }
     188             :         /* Invalid number range. */
     189           0 :         if ((rv <= 0 || rv >= 65535) || errno == ERANGE) {
     190           0 :                 fprintf(stderr, "invalid BFD data plane port range: %s\n",
     191             :                         str);
     192           0 :                 exit(0);
     193             :         }
     194             :         /* There was garbage at the end of the string. */
     195           0 :         if (*nulbyte != 0) {
     196           0 :                 fprintf(stderr, "invalid BFD data plane port: %s\n",
     197             :                         str);
     198           0 :                 exit(0);
     199             :         }
     200             : 
     201           0 :         return (uint16_t)rv;
     202             : }
     203             : 
     204             : static void
     205           0 : distributed_bfd_init(const char *arg)
     206             : {
     207           0 :         char *sptr, *saux;
     208           0 :         bool is_client = false;
     209           0 :         size_t slen;
     210           0 :         socklen_t salen;
     211           0 :         char addr[64];
     212           0 :         char type[64];
     213           0 :         union {
     214             :                 struct sockaddr_in sin;
     215             :                 struct sockaddr_in6 sin6;
     216             :                 struct sockaddr_un sun;
     217             :         } sa;
     218             : 
     219             :         /* Basic parsing: find ':' to figure out type part and address part. */
     220           0 :         sptr = strchr(arg, ':');
     221           0 :         if (sptr == NULL) {
     222           0 :                 fprintf(stderr, "invalid BFD data plane socket: %s\n", arg);
     223           0 :                 exit(1);
     224             :         }
     225             : 
     226             :         /* Calculate type string length. */
     227           0 :         slen = (size_t)(sptr - arg);
     228             : 
     229             :         /* Copy the address part. */
     230           0 :         sptr++;
     231           0 :         strlcpy(addr, sptr, sizeof(addr));
     232             : 
     233             :         /* Copy type part. */
     234           0 :         strlcpy(type, arg, slen + 1);
     235             : 
     236             :         /* Reset address data. */
     237           0 :         memset(&sa, 0, sizeof(sa));
     238             : 
     239             :         /* Fill the address information. */
     240           0 :         if (strcmp(type, "unix") == 0 || strcmp(type, "unixc") == 0) {
     241           0 :                 if (strcmp(type, "unixc") == 0)
     242           0 :                         is_client = true;
     243             : 
     244           0 :                 salen = sizeof(sa.sun);
     245           0 :                 sa.sun.sun_family = AF_UNIX;
     246           0 :                 strlcpy(sa.sun.sun_path, addr, sizeof(sa.sun.sun_path));
     247           0 :         } else if (strcmp(type, "ipv4") == 0 || strcmp(type, "ipv4c") == 0) {
     248           0 :                 if (strcmp(type, "ipv4c") == 0)
     249           0 :                         is_client = true;
     250             : 
     251           0 :                 salen = sizeof(sa.sin);
     252           0 :                 sa.sin.sin_family = AF_INET;
     253             : 
     254             :                 /* Parse port if any. */
     255           0 :                 sptr = strchr(addr, ':');
     256           0 :                 if (sptr == NULL) {
     257           0 :                         sa.sin.sin_port = htons(BFD_DATA_PLANE_DEFAULT_PORT);
     258             :                 } else {
     259           0 :                         *sptr = 0;
     260           0 :                         sa.sin.sin_port = htons(parse_port(sptr + 1));
     261             :                 }
     262             : 
     263           0 :                 if (inet_pton(AF_INET, addr, &sa.sin.sin_addr) != 1)
     264           0 :                         errx(1, "%s: inet_pton: invalid address %s", __func__,
     265             :                              addr);
     266           0 :         } else if (strcmp(type, "ipv6") == 0 || strcmp(type, "ipv6c") == 0) {
     267           0 :                 if (strcmp(type, "ipv6c") == 0)
     268           0 :                         is_client = true;
     269             : 
     270           0 :                 salen = sizeof(sa.sin6);
     271           0 :                 sa.sin6.sin6_family = AF_INET6;
     272             : 
     273             :                 /* Check for IPv6 enclosures '[]' */
     274           0 :                 sptr = &addr[0];
     275           0 :                 if (*sptr != '[')
     276           0 :                         errx(1, "%s: invalid IPv6 address format: %s", __func__,
     277             :                              addr);
     278             : 
     279           0 :                 saux = strrchr(addr, ']');
     280           0 :                 if (saux == NULL)
     281           0 :                         errx(1, "%s: invalid IPv6 address format: %s", __func__,
     282             :                              addr);
     283             : 
     284             :                 /* Consume the '[]:' part. */
     285           0 :                 slen = saux - sptr;
     286           0 :                 memmove(addr, addr + 1, slen);
     287           0 :                 addr[slen - 1] = 0;
     288             : 
     289             :                 /* Parse port if any. */
     290           0 :                 saux++;
     291           0 :                 sptr = strrchr(saux, ':');
     292           0 :                 if (sptr == NULL) {
     293           0 :                         sa.sin6.sin6_port = htons(BFD_DATA_PLANE_DEFAULT_PORT);
     294             :                 } else {
     295           0 :                         *sptr = 0;
     296           0 :                         sa.sin6.sin6_port = htons(parse_port(sptr + 1));
     297             :                 }
     298             : 
     299           0 :                 if (inet_pton(AF_INET6, addr, &sa.sin6.sin6_addr) != 1)
     300           0 :                         errx(1, "%s: inet_pton: invalid address %s", __func__,
     301             :                              addr);
     302             :         } else {
     303           0 :                 fprintf(stderr, "invalid BFD data plane socket type: %s\n",
     304             :                         type);
     305           0 :                 exit(1);
     306             :         }
     307             : 
     308             :         /* Initialize BFD data plane listening socket. */
     309           0 :         bfd_dplane_init((struct sockaddr *)&sa, salen, is_client);
     310           0 : }
     311             : 
     312           8 : static void bg_init(void)
     313             : {
     314           8 :         struct zebra_privs_t bfdd_privs = {
     315             : #if defined(FRR_USER) && defined(FRR_GROUP)
     316             :                 .user = FRR_USER,
     317             :                 .group = FRR_GROUP,
     318             : #endif
     319             : #if defined(VTY_GROUP)
     320             :                 .vty_group = VTY_GROUP,
     321             : #endif
     322             :                 .caps_p = _caps_p,
     323             :                 .cap_num_p = array_size(_caps_p),
     324             :                 .cap_num_i = 0,
     325             :         };
     326             : 
     327           8 :         TAILQ_INIT(&bglobal.bg_bcslist);
     328           8 :         TAILQ_INIT(&bglobal.bg_obslist);
     329             : 
     330           8 :         memcpy(&bglobal.bfdd_privs, &bfdd_privs,
     331             :                sizeof(bfdd_privs));
     332           8 : }
     333             : 
     334           8 : int main(int argc, char *argv[])
     335             : {
     336           8 :         char ctl_path[512], dplane_addr[512];
     337           8 :         bool ctlsockused = false;
     338           8 :         int opt;
     339             : 
     340           8 :         bglobal.bg_use_dplane = false;
     341             : 
     342             :         /* Initialize system sockets. */
     343           8 :         bg_init();
     344             : 
     345           8 :         frr_preinit(&bfdd_di, argc, argv);
     346           8 :         frr_opt_add("", longopts,
     347             :                     "      --bfdctl       Specify bfdd control socket\n"
     348             :                     "      --dplaneaddr   Specify BFD data plane address\n");
     349             : 
     350           8 :         snprintf(ctl_path, sizeof(ctl_path), BFDD_CONTROL_SOCKET,
     351             :                  "", "");
     352           8 :         while (true) {
     353           8 :                 opt = frr_getopt(argc, argv, NULL);
     354           8 :                 if (opt == EOF)
     355             :                         break;
     356             : 
     357           0 :                 switch (opt) {
     358           0 :                 case OPTION_CTLSOCK:
     359           0 :                         strlcpy(ctl_path, optarg, sizeof(ctl_path));
     360           0 :                         ctlsockused = true;
     361           0 :                         break;
     362           0 :                 case OPTION_DPLANEADDR:
     363           0 :                         strlcpy(dplane_addr, optarg, sizeof(dplane_addr));
     364           0 :                         bglobal.bg_use_dplane = true;
     365           0 :                         break;
     366             : 
     367           0 :                 default:
     368           0 :                         frr_help_exit(1);
     369             :                 }
     370             :         }
     371             : 
     372           8 :         if (bfdd_di.pathspace && !ctlsockused)
     373           0 :                 snprintf(ctl_path, sizeof(ctl_path), BFDD_CONTROL_SOCKET,
     374             :                          "/", bfdd_di.pathspace);
     375             : 
     376             :         /* Initialize FRR infrastructure. */
     377           8 :         master = frr_init();
     378             : 
     379             :         /* Initialize control socket. */
     380           8 :         control_init(ctl_path);
     381             : 
     382             :         /* Initialize BFD data structures. */
     383           8 :         bfd_initialize();
     384             : 
     385           8 :         bfd_vrf_init();
     386             : 
     387           8 :         access_list_init();
     388             : 
     389             :         /* Initialize zebra connection. */
     390           8 :         bfdd_zclient_init(&bglobal.bfdd_privs);
     391             : 
     392           8 :         thread_add_read(master, control_accept, NULL, bglobal.bg_csock,
     393             :                         &bglobal.bg_csockev);
     394             : 
     395             :         /* Install commands. */
     396           8 :         bfdd_vty_init();
     397             : 
     398             :         /* read configuration file and daemonize  */
     399           8 :         frr_config_fork();
     400             : 
     401             :         /* Initialize BFD data plane listening socket. */
     402           8 :         if (bglobal.bg_use_dplane)
     403           0 :                 distributed_bfd_init(dplane_addr);
     404             : 
     405           8 :         frr_run(master);
     406             :         /* NOTREACHED */
     407             : 
     408           0 :         return 0;
     409             : }

Generated by: LCOV version v1.16-topotato