back to topotato report
topotato coverage report
Current view: top level - zebra - zebra_ptm.c (source / functions) Hit Total Coverage
Test: test_pim_cbsr.py::PIMCandidateBSRTest Lines: 86 154 55.8 %
Date: 2023-02-16 02:09:14 Functions: 14 21 66.7 %

          Line data    Source code
       1             : /* Kernel routing table updates using netlink over GNU/Linux system.
       2             :  * Copyright (C) 1997, 98, 99 Kunihiro Ishiguro
       3             :  *
       4             :  * This file is part of GNU Zebra.
       5             :  *
       6             :  * GNU Zebra is free software; you can redistribute it and/or modify it
       7             :  * under the terms of the GNU General Public License as published by the
       8             :  * Free Software Foundation; either version 2, or (at your option) any
       9             :  * later version.
      10             :  *
      11             :  * GNU Zebra is distributed in the hope that it will be useful, but
      12             :  * WITHOUT ANY WARRANTY; without even the implied warranty of
      13             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      14             :  * General Public License for more details.
      15             :  *
      16             :  * You should have received a copy of the GNU General Public License along
      17             :  * with this program; see the file COPYING; if not, write to the Free Software
      18             :  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
      19             :  */
      20             : 
      21             : #include <zebra.h>
      22             : 
      23             : #include <sys/un.h> /* for sockaddr_un */
      24             : #include <net/if.h>
      25             : 
      26             : #include "bfd.h"
      27             : #include "buffer.h"
      28             : #include "command.h"
      29             : #include "if.h"
      30             : #include "network.h"
      31             : #include "ptm_lib.h"
      32             : #include "rib.h"
      33             : #include "stream.h"
      34             : #include "lib/version.h"
      35             : #include "vrf.h"
      36             : #include "vty.h"
      37             : #include "lib_errors.h"
      38             : 
      39             : #include "zebra/debug.h"
      40             : #include "zebra/interface.h"
      41             : #include "zebra/zebra_errors.h"
      42             : #include "zebra/zebra_ptm.h"
      43             : #include "zebra/zebra_ptm_redistribute.h"
      44             : #include "zebra/zebra_router.h"
      45             : #include "zebra_vrf.h"
      46             : 
      47             : /*
      48             :  * Choose the BFD implementation that we'll use.
      49             :  *
      50             :  * There are two implementations:
      51             :  * - PTM BFD: which uses an external daemon;
      52             :  * - bfdd: FRR's own BFD daemon;
      53             :  */
      54             : #if HAVE_BFDD == 0
      55             : 
      56             : #define ZEBRA_PTM_RECONNECT_TIME_INITIAL 1 /* initial reconnect is 1s */
      57             : #define ZEBRA_PTM_RECONNECT_TIME_MAX     300
      58             : 
      59             : #define PTM_MSG_LEN     4
      60             : #define PTM_HEADER_LEN  37
      61             : 
      62             : const char ZEBRA_PTM_GET_STATUS_CMD[] = "get-status";
      63             : const char ZEBRA_PTM_BFD_START_CMD[] = "start-bfd-sess";
      64             : const char ZEBRA_PTM_BFD_STOP_CMD[] = "stop-bfd-sess";
      65             : const char ZEBRA_PTM_BFD_CLIENT_REG_CMD[] = "reg-bfd-client";
      66             : const char ZEBRA_PTM_BFD_CLIENT_DEREG_CMD[] = "dereg-bfd-client";
      67             : 
      68             : const char ZEBRA_PTM_CMD_STR[] = "cmd";
      69             : const char ZEBRA_PTM_CMD_STATUS_STR[] = "cmd_status";
      70             : const char ZEBRA_PTM_PORT_STR[] = "port";
      71             : const char ZEBRA_PTM_CBL_STR[] = "cbl status";
      72             : const char ZEBRA_PTM_PASS_STR[] = "pass";
      73             : const char ZEBRA_PTM_FAIL_STR[] = "fail";
      74             : const char ZEBRA_PTM_BFDSTATUS_STR[] = "state";
      75             : const char ZEBRA_PTM_BFDSTATUS_UP_STR[] = "Up";
      76             : const char ZEBRA_PTM_BFDSTATUS_DOWN_STR[] = "Down";
      77             : const char ZEBRA_PTM_BFDDEST_STR[] = "peer";
      78             : const char ZEBRA_PTM_BFDSRC_STR[] = "local";
      79             : const char ZEBRA_PTM_BFDVRF_STR[] = "vrf";
      80             : const char ZEBRA_PTM_INVALID_PORT_NAME[] = "N/A";
      81             : const char ZEBRA_PTM_INVALID_SRC_IP[] = "N/A";
      82             : const char ZEBRA_PTM_INVALID_VRF[] = "N/A";
      83             : 
      84             : const char ZEBRA_PTM_BFD_DST_IP_FIELD[] = "dstIPaddr";
      85             : const char ZEBRA_PTM_BFD_SRC_IP_FIELD[] = "srcIPaddr";
      86             : const char ZEBRA_PTM_BFD_MIN_RX_FIELD[] = "requiredMinRx";
      87             : const char ZEBRA_PTM_BFD_MIN_TX_FIELD[] = "upMinTx";
      88             : const char ZEBRA_PTM_BFD_DETECT_MULT_FIELD[] = "detectMult";
      89             : const char ZEBRA_PTM_BFD_MULTI_HOP_FIELD[] = "multiHop";
      90             : const char ZEBRA_PTM_BFD_CLIENT_FIELD[] = "client";
      91             : const char ZEBRA_PTM_BFD_SEQID_FIELD[] = "seqid";
      92             : const char ZEBRA_PTM_BFD_IFNAME_FIELD[] = "ifName";
      93             : const char ZEBRA_PTM_BFD_MAX_HOP_CNT_FIELD[] = "maxHopCnt";
      94             : const char ZEBRA_PTM_BFD_SEND_EVENT[] = "sendEvent";
      95             : const char ZEBRA_PTM_BFD_VRF_NAME_FIELD[] = "vrfName";
      96             : const char ZEBRA_PTM_BFD_CBIT_FIELD[] = "bfdcbit";
      97             : 
      98             : static ptm_lib_handle_t *ptm_hdl;
      99             : 
     100             : struct zebra_ptm_cb ptm_cb;
     101             : 
     102             : static int zebra_ptm_socket_init(void);
     103             : void zebra_ptm_sock_read(struct thread *thread);
     104             : static void zebra_ptm_install_commands(void);
     105             : static int zebra_ptm_handle_msg_cb(void *arg, void *in_ctxt);
     106             : void zebra_bfd_peer_replay_req(void);
     107             : void zebra_ptm_send_status_req(void);
     108             : void zebra_ptm_reset_status(int ptm_disable);
     109             : static int zebra_ptm_bfd_client_deregister(struct zserv *client);
     110             : 
     111             : const char ZEBRA_PTM_SOCK_NAME[] = "\0/var/run/ptmd.socket";
     112             : 
     113             : void zebra_ptm_init(void)
     114             : {
     115             :         char buf[64];
     116             : 
     117             :         memset(&ptm_cb, 0, sizeof(ptm_cb));
     118             : 
     119             :         ptm_cb.out_data = calloc(1, ZEBRA_PTM_SEND_MAX_SOCKBUF);
     120             :         if (!ptm_cb.out_data) {
     121             :                 zlog_debug("%s: Allocation of send data failed", __func__);
     122             :                 return;
     123             :         }
     124             : 
     125             :         ptm_cb.in_data = calloc(1, ZEBRA_PTM_MAX_SOCKBUF);
     126             :         if (!ptm_cb.in_data) {
     127             :                 zlog_debug("%s: Allocation of recv data failed", __func__);
     128             :                 free(ptm_cb.out_data);
     129             :                 return;
     130             :         }
     131             : 
     132             :         ptm_cb.pid = getpid();
     133             :         zebra_ptm_install_commands();
     134             : 
     135             :         snprintf(buf, sizeof(buf), "%s", FRR_PTM_NAME);
     136             :         ptm_hdl = ptm_lib_register(buf, NULL, zebra_ptm_handle_msg_cb,
     137             :                                    zebra_ptm_handle_msg_cb);
     138             :         ptm_cb.wb = buffer_new(0);
     139             : 
     140             :         ptm_cb.reconnect_time = ZEBRA_PTM_RECONNECT_TIME_INITIAL;
     141             : 
     142             :         ptm_cb.ptm_sock = -1;
     143             : 
     144             :         hook_register(zserv_client_close, zebra_ptm_bfd_client_deregister);
     145             : }
     146             : 
     147             : void zebra_ptm_finish(void)
     148             : {
     149             :         buffer_flush_all(ptm_cb.wb, ptm_cb.ptm_sock);
     150             : 
     151             :         free(ptm_hdl);
     152             : 
     153             :         if (ptm_cb.out_data)
     154             :                 free(ptm_cb.out_data);
     155             : 
     156             :         if (ptm_cb.in_data)
     157             :                 free(ptm_cb.in_data);
     158             : 
     159             :         /* Cancel events. */
     160             :         THREAD_OFF(ptm_cb.t_read);
     161             :         THREAD_OFF(ptm_cb.t_write);
     162             :         THREAD_OFF(ptm_cb.t_timer);
     163             : 
     164             :         if (ptm_cb.wb)
     165             :                 buffer_free(ptm_cb.wb);
     166             : 
     167             :         if (ptm_cb.ptm_sock >= 0)
     168             :                 close(ptm_cb.ptm_sock);
     169             : }
     170             : 
     171             : static void zebra_ptm_flush_messages(struct thread *thread)
     172             : {
     173             :         ptm_cb.t_write = NULL;
     174             : 
     175             :         if (ptm_cb.ptm_sock == -1)
     176             :                 return;
     177             : 
     178             :         errno = 0;
     179             : 
     180             :         switch (buffer_flush_available(ptm_cb.wb, ptm_cb.ptm_sock)) {
     181             :         case BUFFER_ERROR:
     182             :                 flog_err_sys(EC_LIB_SOCKET, "%s ptm socket error: %s", __func__,
     183             :                              safe_strerror(errno));
     184             :                 close(ptm_cb.ptm_sock);
     185             :                 ptm_cb.ptm_sock = -1;
     186             :                 zebra_ptm_reset_status(0);
     187             :                 ptm_cb.t_timer = NULL;
     188             :                 thread_add_timer(zrouter.master, zebra_ptm_connect, NULL,
     189             :                                  ptm_cb.reconnect_time, &ptm_cb.t_timer);
     190             :                 return;
     191             :         case BUFFER_PENDING:
     192             :                 ptm_cb.t_write = NULL;
     193             :                 thread_add_write(zrouter.master, zebra_ptm_flush_messages, NULL,
     194             :                                  ptm_cb.ptm_sock, &ptm_cb.t_write);
     195             :                 break;
     196             :         case BUFFER_EMPTY:
     197             :                 break;
     198             :         }
     199             : }
     200             : 
     201             : static int zebra_ptm_send_message(char *data, int size)
     202             : {
     203             :         errno = 0;
     204             :         switch (buffer_write(ptm_cb.wb, ptm_cb.ptm_sock, data, size)) {
     205             :         case BUFFER_ERROR:
     206             :                 flog_err_sys(EC_LIB_SOCKET, "%s ptm socket error: %s", __func__,
     207             :                              safe_strerror(errno));
     208             :                 close(ptm_cb.ptm_sock);
     209             :                 ptm_cb.ptm_sock = -1;
     210             :                 zebra_ptm_reset_status(0);
     211             :                 ptm_cb.t_timer = NULL;
     212             :                 thread_add_timer(zrouter.master, zebra_ptm_connect, NULL,
     213             :                                  ptm_cb.reconnect_time, &ptm_cb.t_timer);
     214             :                 return -1;
     215             :         case BUFFER_EMPTY:
     216             :                 THREAD_OFF(ptm_cb.t_write);
     217             :                 break;
     218             :         case BUFFER_PENDING:
     219             :                 thread_add_write(zrouter.master, zebra_ptm_flush_messages, NULL,
     220             :                                  ptm_cb.ptm_sock, &ptm_cb.t_write);
     221             :                 break;
     222             :         }
     223             : 
     224             :         return 0;
     225             : }
     226             : 
     227             : void zebra_ptm_connect(struct thread *t)
     228             : {
     229             :         int init = 0;
     230             : 
     231             :         if (ptm_cb.ptm_sock == -1) {
     232             :                 zebra_ptm_socket_init();
     233             :                 init = 1;
     234             :         }
     235             : 
     236             :         if (ptm_cb.ptm_sock != -1) {
     237             :                 if (init) {
     238             :                         ptm_cb.t_read = NULL;
     239             :                         thread_add_read(zrouter.master, zebra_ptm_sock_read,
     240             :                                         NULL, ptm_cb.ptm_sock, &ptm_cb.t_read);
     241             :                         zebra_bfd_peer_replay_req();
     242             :                 }
     243             :                 zebra_ptm_send_status_req();
     244             :                 ptm_cb.reconnect_time = ZEBRA_PTM_RECONNECT_TIME_INITIAL;
     245             :         } else if (ptm_cb.reconnect_time < ZEBRA_PTM_RECONNECT_TIME_MAX) {
     246             :                 ptm_cb.reconnect_time *= 2;
     247             :                 if (ptm_cb.reconnect_time > ZEBRA_PTM_RECONNECT_TIME_MAX)
     248             :                         ptm_cb.reconnect_time = ZEBRA_PTM_RECONNECT_TIME_MAX;
     249             : 
     250             :                 ptm_cb.t_timer = NULL;
     251             :                 thread_add_timer(zrouter.master, zebra_ptm_connect, NULL,
     252             :                                  ptm_cb.reconnect_time, &ptm_cb.t_timer);
     253             :         } else if (ptm_cb.reconnect_time >= ZEBRA_PTM_RECONNECT_TIME_MAX) {
     254             :                 ptm_cb.reconnect_time = ZEBRA_PTM_RECONNECT_TIME_INITIAL;
     255             :         }
     256             : }
     257             : 
     258             : DEFUN (zebra_ptm_enable,
     259             :        zebra_ptm_enable_cmd,
     260             :        "ptm-enable",
     261             :        "Enable neighbor check with specified topology\n")
     262             : {
     263             :         struct vrf *vrf;
     264             :         struct interface *ifp;
     265             :         struct zebra_if *if_data;
     266             : 
     267             :         ptm_cb.ptm_enable = ZEBRA_IF_PTM_ENABLE_ON;
     268             : 
     269             :         RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name)
     270             :                 FOR_ALL_INTERFACES (vrf, ifp)
     271             :                         if (!ifp->ptm_enable) {
     272             :                                 if_data = (struct zebra_if *)ifp->info;
     273             :                                 if (if_data
     274             :                                     && (if_data->ptm_enable
     275             :                                         == ZEBRA_IF_PTM_ENABLE_UNSPEC)) {
     276             :                                         ifp->ptm_enable =
     277             :                                                 ZEBRA_IF_PTM_ENABLE_ON;
     278             :                                 }
     279             :                                 /* Assign a default unknown status */
     280             :                                 ifp->ptm_status = ZEBRA_PTM_STATUS_UNKNOWN;
     281             :                         }
     282             : 
     283             :         zebra_ptm_connect(NULL);
     284             : 
     285             :         return CMD_SUCCESS;
     286             : }
     287             : 
     288             : DEFUN (no_zebra_ptm_enable,
     289             :        no_zebra_ptm_enable_cmd,
     290             :        "no ptm-enable",
     291             :        NO_STR
     292             :        "Enable neighbor check with specified topology\n")
     293             : {
     294             :         ptm_cb.ptm_enable = ZEBRA_IF_PTM_ENABLE_OFF;
     295             :         zebra_ptm_reset_status(1);
     296             :         return CMD_SUCCESS;
     297             : }
     298             : 
     299             : DEFUN (zebra_ptm_enable_if,
     300             :        zebra_ptm_enable_if_cmd,
     301             :        "ptm-enable",
     302             :        "Enable neighbor check with specified topology\n")
     303             : {
     304             :         VTY_DECLVAR_CONTEXT(interface, ifp);
     305             :         struct zebra_if *if_data;
     306             :         int old_ptm_enable;
     307             :         int send_linkdown = 0;
     308             : 
     309             :         if_data = ifp->info;
     310             :         if_data->ptm_enable = ZEBRA_IF_PTM_ENABLE_UNSPEC;
     311             : 
     312             :         if (ifp->ifindex == IFINDEX_INTERNAL) {
     313             :                 return CMD_SUCCESS;
     314             :         }
     315             : 
     316             :         old_ptm_enable = ifp->ptm_enable;
     317             :         ifp->ptm_enable = ptm_cb.ptm_enable;
     318             : 
     319             :         if (if_is_no_ptm_operative(ifp))
     320             :                 send_linkdown = 1;
     321             : 
     322             :         if (!old_ptm_enable && ptm_cb.ptm_enable) {
     323             :                 if (!if_is_operative(ifp) && send_linkdown) {
     324             :                         if (IS_ZEBRA_DEBUG_EVENT)
     325             :                                 zlog_debug("%s: Bringing down interface %s",
     326             :                                            __func__, ifp->name);
     327             :                         if_down(ifp);
     328             :                 }
     329             :         }
     330             : 
     331             :         return CMD_SUCCESS;
     332             : }
     333             : 
     334             : DEFUN (no_zebra_ptm_enable_if,
     335             :        no_zebra_ptm_enable_if_cmd,
     336             :        "no ptm-enable",
     337             :        NO_STR
     338             :        "Enable neighbor check with specified topology\n")
     339             : {
     340             :         VTY_DECLVAR_CONTEXT(interface, ifp);
     341             :         int send_linkup = 0;
     342             :         struct zebra_if *if_data;
     343             : 
     344             :         if ((ifp->ifindex != IFINDEX_INTERNAL) && (ifp->ptm_enable)) {
     345             :                 if (!if_is_operative(ifp))
     346             :                         send_linkup = 1;
     347             : 
     348             :                 ifp->ptm_enable = ZEBRA_IF_PTM_ENABLE_OFF;
     349             :                 if (if_is_no_ptm_operative(ifp) && send_linkup) {
     350             :                         if (IS_ZEBRA_DEBUG_EVENT)
     351             :                                 zlog_debug("%s: Bringing up interface %s",
     352             :                                            __func__, ifp->name);
     353             :                         if_up(ifp, true);
     354             :                 }
     355             :         }
     356             : 
     357             :         if_data = ifp->info;
     358             :         if_data->ptm_enable = ZEBRA_IF_PTM_ENABLE_OFF;
     359             : 
     360             :         return CMD_SUCCESS;
     361             : }
     362             : 
     363             : 
     364             : void zebra_ptm_write(struct vty *vty)
     365             : {
     366             :         if (ptm_cb.ptm_enable)
     367             :                 vty_out(vty, "ptm-enable\n");
     368             : 
     369             :         return;
     370             : }
     371             : 
     372             : static int zebra_ptm_socket_init(void)
     373             : {
     374             :         int ret;
     375             :         int sock;
     376             :         struct sockaddr_un addr;
     377             : 
     378             :         ptm_cb.ptm_sock = -1;
     379             : 
     380             :         sock = socket(PF_UNIX, SOCK_STREAM, 0);
     381             :         if (sock < 0)
     382             :                 return -1;
     383             :         if (set_nonblocking(sock) < 0) {
     384             :                 if (IS_ZEBRA_DEBUG_EVENT)
     385             :                         zlog_debug("%s: Unable to set socket non blocking[%s]",
     386             :                                    __func__, safe_strerror(errno));
     387             :                 close(sock);
     388             :                 return -1;
     389             :         }
     390             : 
     391             :         /* Make server socket. */
     392             :         memset(&addr, 0, sizeof(addr));
     393             :         addr.sun_family = AF_UNIX;
     394             :         memcpy(&addr.sun_path, ZEBRA_PTM_SOCK_NAME,
     395             :                sizeof(ZEBRA_PTM_SOCK_NAME));
     396             : 
     397             :         ret = connect(sock, (struct sockaddr *)&addr,
     398             :                       sizeof(addr.sun_family) + sizeof(ZEBRA_PTM_SOCK_NAME)
     399             :                               - 1);
     400             :         if (ret < 0) {
     401             :                 if (IS_ZEBRA_DEBUG_EVENT)
     402             :                         zlog_debug("%s: Unable to connect to socket %s [%s]",
     403             :                                    __func__, ZEBRA_PTM_SOCK_NAME,
     404             :                                    safe_strerror(errno));
     405             :                 close(sock);
     406             :                 return -1;
     407             :         }
     408             :         ptm_cb.ptm_sock = sock;
     409             :         return sock;
     410             : }
     411             : 
     412             : static void zebra_ptm_install_commands(void)
     413             : {
     414             :         install_element(CONFIG_NODE, &zebra_ptm_enable_cmd);
     415             :         install_element(CONFIG_NODE, &no_zebra_ptm_enable_cmd);
     416             :         install_element(INTERFACE_NODE, &zebra_ptm_enable_if_cmd);
     417             :         install_element(INTERFACE_NODE, &no_zebra_ptm_enable_if_cmd);
     418             : }
     419             : 
     420             : /* BFD session goes down, send message to the protocols. */
     421             : static void if_bfd_session_update(struct interface *ifp, struct prefix *dp,
     422             :                                   struct prefix *sp, int status,
     423             :                                   vrf_id_t vrf_id)
     424             : {
     425             :         if (IS_ZEBRA_DEBUG_EVENT) {
     426             :                 char buf[2][INET6_ADDRSTRLEN];
     427             : 
     428             :                 if (ifp) {
     429             :                         zlog_debug(
     430             :                                 "MESSAGE: ZEBRA_INTERFACE_BFD_DEST_UPDATE %s/%d on %s %s event",
     431             :                                 inet_ntop(dp->family, &dp->u.prefix, buf[0],
     432             :                                           INET6_ADDRSTRLEN),
     433             :                                 dp->prefixlen, ifp->name,
     434             :                                 bfd_get_status_str(status));
     435             :                 } else {
     436             :                         struct vrf *vrf = vrf_lookup_by_id(vrf_id);
     437             : 
     438             :                         zlog_debug(
     439             :                                 "MESSAGE: ZEBRA_INTERFACE_BFD_DEST_UPDATE %s/%d with src %s/%d and vrf %s(%u) %s event",
     440             :                                 inet_ntop(dp->family, &dp->u.prefix, buf[0],
     441             :                                           INET6_ADDRSTRLEN),
     442             :                                 dp->prefixlen,
     443             :                                 inet_ntop(sp->family, &sp->u.prefix, buf[1],
     444             :                                           INET6_ADDRSTRLEN),
     445             :                                 sp->prefixlen, VRF_LOGNAME(vrf), vrf_id,
     446             :                                 bfd_get_status_str(status));
     447             :                 }
     448             :         }
     449             : 
     450             :         zebra_interface_bfd_update(ifp, dp, sp, status, vrf_id);
     451             : }
     452             : 
     453             : static int zebra_ptm_handle_bfd_msg(void *arg, void *in_ctxt,
     454             :                                     struct interface *ifp)
     455             : {
     456             :         char bfdst_str[32];
     457             :         char dest_str[64];
     458             :         char src_str[64];
     459             :         char vrf_str[64];
     460             :         struct prefix dest_prefix;
     461             :         struct prefix src_prefix;
     462             :         vrf_id_t vrf_id;
     463             : 
     464             :         ptm_lib_find_key_in_msg(in_ctxt, ZEBRA_PTM_BFDSTATUS_STR, bfdst_str);
     465             : 
     466             :         if (bfdst_str[0] == '\0') {
     467             :                 return -1;
     468             :         }
     469             : 
     470             :         ptm_lib_find_key_in_msg(in_ctxt, ZEBRA_PTM_BFDDEST_STR, dest_str);
     471             : 
     472             :         if (dest_str[0] == '\0') {
     473             :                 zlog_debug("%s: Key %s not found in PTM msg", __func__,
     474             :                            ZEBRA_PTM_BFDDEST_STR);
     475             :                 return -1;
     476             :         }
     477             : 
     478             :         ptm_lib_find_key_in_msg(in_ctxt, ZEBRA_PTM_BFDSRC_STR, src_str);
     479             : 
     480             :         if (src_str[0] == '\0') {
     481             :                 zlog_debug("%s: Key %s not found in PTM msg", __func__,
     482             :                            ZEBRA_PTM_BFDSRC_STR);
     483             :                 return -1;
     484             :         }
     485             : 
     486             :         ptm_lib_find_key_in_msg(in_ctxt, ZEBRA_PTM_BFDVRF_STR, vrf_str);
     487             : 
     488             :         if (vrf_str[0] == '\0') {
     489             :                 zlog_debug("%s: Key %s not found in PTM msg", __func__,
     490             :                            ZEBRA_PTM_BFDVRF_STR);
     491             :                 return -1;
     492             :         }
     493             : 
     494             :         if (IS_ZEBRA_DEBUG_EVENT)
     495             :                 zlog_debug(
     496             :                         "%s: Recv Port [%s] bfd status [%s] vrf [%s] peer [%s] local [%s]",
     497             :                         __func__, ifp ? ifp->name : "N/A", bfdst_str, vrf_str,
     498             :                         dest_str, src_str);
     499             : 
     500             :         if (str2prefix(dest_str, &dest_prefix) == 0) {
     501             :                 flog_err(EC_ZEBRA_PREFIX_PARSE_ERROR,
     502             :                          "%s: Peer addr %s not found", __func__, dest_str);
     503             :                 return -1;
     504             :         }
     505             : 
     506             :         memset(&src_prefix, 0, sizeof(src_prefix));
     507             :         if (strcmp(ZEBRA_PTM_INVALID_SRC_IP, src_str)) {
     508             :                 if (str2prefix(src_str, &src_prefix) == 0) {
     509             :                         flog_err(EC_ZEBRA_PREFIX_PARSE_ERROR,
     510             :                                  "%s: Local addr %s not found", __func__,
     511             :                                  src_str);
     512             :                         return -1;
     513             :                 }
     514             :         }
     515             : 
     516             :         if (!strcmp(ZEBRA_PTM_INVALID_VRF, vrf_str) && ifp) {
     517             :                 vrf_id = ifp->vrf->vrf_id;
     518             :         } else {
     519             :                 struct vrf *pVrf;
     520             : 
     521             :                 pVrf = vrf_lookup_by_name(vrf_str);
     522             :                 if (pVrf)
     523             :                         vrf_id = pVrf->vrf_id;
     524             :                 else
     525             :                         vrf_id = VRF_DEFAULT;
     526             :         }
     527             : 
     528             :         if (!strcmp(bfdst_str, ZEBRA_PTM_BFDSTATUS_DOWN_STR)) {
     529             :                 if_bfd_session_update(ifp, &dest_prefix, &src_prefix,
     530             :                                       BFD_STATUS_DOWN, vrf_id);
     531             :         } else {
     532             :                 if_bfd_session_update(ifp, &dest_prefix, &src_prefix,
     533             :                                       BFD_STATUS_UP, vrf_id);
     534             :         }
     535             : 
     536             :         return 0;
     537             : }
     538             : 
     539             : static int zebra_ptm_handle_cbl_msg(void *arg, void *in_ctxt,
     540             :                                     struct interface *ifp, char *cbl_str)
     541             : {
     542             :         int send_linkup = 0;
     543             : 
     544             :         if (IS_ZEBRA_DEBUG_EVENT)
     545             :                 zlog_debug("%s: Recv Port [%s] cbl status [%s]", __func__,
     546             :                            ifp->name, cbl_str);
     547             : 
     548             :         if (!strcmp(cbl_str, ZEBRA_PTM_PASS_STR)
     549             :             && (ifp->ptm_status != ZEBRA_PTM_STATUS_UP)) {
     550             : 
     551             :                 if (ifp->ptm_status == ZEBRA_PTM_STATUS_DOWN)
     552             :                         send_linkup = 1;
     553             :                 ifp->ptm_status = ZEBRA_PTM_STATUS_UP;
     554             :                 if (ifp->ptm_enable && if_is_no_ptm_operative(ifp)
     555             :                     && send_linkup)
     556             :                         if_up(ifp, true);
     557             :         } else if (!strcmp(cbl_str, ZEBRA_PTM_FAIL_STR)
     558             :                    && (ifp->ptm_status != ZEBRA_PTM_STATUS_DOWN)) {
     559             :                 ifp->ptm_status = ZEBRA_PTM_STATUS_DOWN;
     560             :                 if (ifp->ptm_enable && if_is_no_ptm_operative(ifp))
     561             :                         if_down(ifp);
     562             :         }
     563             : 
     564             :         return 0;
     565             : }
     566             : 
     567             : /*
     568             :  * zebra_ptm_handle_msg_cb - The purpose of this callback function is to handle
     569             :  *  all the command responses and notifications received from PTM.
     570             :  *
     571             :  * Command responses: Upon establishing connection with PTM, Zebra requests
     572             :  *  status of all interfaces using 'get-status' command if global ptm-enable
     573             :  *  knob is enabled. As a response to the get-status command PTM sends status
     574             :  *  of all the interfaces as command responses. All other type of command
     575             :  *  responses with cmd_status key word  are dropped. The sole purpose of
     576             :  *  registering this function as callback for the command responses is to
     577             :  *  handle the responses to get-status command.
     578             :  *
     579             :  * Notifications: Cable status and BFD session status changes are sent as
     580             :  *  notifications by PTM. So, this function is also the callback function for
     581             :  *  processing all the notifications from the PTM.
     582             :  *
     583             :  */
     584             : static int zebra_ptm_handle_msg_cb(void *arg, void *in_ctxt)
     585             : {
     586             :         struct interface *ifp = NULL;
     587             :         char port_str[128];
     588             :         char cbl_str[32];
     589             :         char cmd_status_str[32];
     590             : 
     591             :         ptm_lib_find_key_in_msg(in_ctxt, ZEBRA_PTM_CMD_STATUS_STR,
     592             :                                 cmd_status_str);
     593             : 
     594             :         /* Drop command response messages */
     595             :         if (cmd_status_str[0] != '\0') {
     596             :                 return 0;
     597             :         }
     598             : 
     599             :         ptm_lib_find_key_in_msg(in_ctxt, ZEBRA_PTM_PORT_STR, port_str);
     600             : 
     601             :         if (port_str[0] == '\0') {
     602             :                 zlog_debug("%s: Key %s not found in PTM msg", __func__,
     603             :                            ZEBRA_PTM_PORT_STR);
     604             :                 return -1;
     605             :         }
     606             : 
     607             :         if (strcmp(ZEBRA_PTM_INVALID_PORT_NAME, port_str)) {
     608             :                 struct vrf *vrf;
     609             :                 int count = 0;
     610             : 
     611             :                 RB_FOREACH (vrf, vrf_id_head, &vrfs_by_id) {
     612             :                         ifp = if_lookup_by_name_vrf(port_str, vrf);
     613             :                         if (ifp) {
     614             :                                 count++;
     615             :                                 if (!vrf_is_backend_netns())
     616             :                                         break;
     617             :                         }
     618             :                 }
     619             : 
     620             :                 if (!ifp) {
     621             :                         flog_warn(EC_ZEBRA_UNKNOWN_INTERFACE,
     622             :                                   "%s: %s not found in interface list",
     623             :                                   __func__, port_str);
     624             :                         return -1;
     625             :                 }
     626             :                 if (count > 1) {
     627             :                         flog_warn(EC_ZEBRA_UNKNOWN_INTERFACE,
     628             :                                   "%s: multiple interface with name %s",
     629             :                                   __func__, port_str);
     630             :                         return -1;
     631             :                 }
     632             :         }
     633             : 
     634             :         ptm_lib_find_key_in_msg(in_ctxt, ZEBRA_PTM_CBL_STR, cbl_str);
     635             : 
     636             :         if (cbl_str[0] == '\0') {
     637             :                 return zebra_ptm_handle_bfd_msg(arg, in_ctxt, ifp);
     638             :         } else {
     639             :                 if (ifp) {
     640             :                         return zebra_ptm_handle_cbl_msg(arg, in_ctxt, ifp,
     641             :                                                         cbl_str);
     642             :                 } else {
     643             :                         return -1;
     644             :                 }
     645             :         }
     646             : }
     647             : 
     648             : void zebra_ptm_sock_read(struct thread *thread)
     649             : {
     650             :         int sock;
     651             :         int rc;
     652             : 
     653             :         errno = 0;
     654             :         sock = THREAD_FD(thread);
     655             : 
     656             :         if (sock == -1)
     657             :                 return;
     658             : 
     659             :         /* PTM communicates in CSV format */
     660             :         do {
     661             :                 rc = ptm_lib_process_msg(ptm_hdl, sock, ptm_cb.in_data,
     662             :                                          ZEBRA_PTM_MAX_SOCKBUF, NULL);
     663             :         } while (rc > 0);
     664             : 
     665             :         if (((rc == 0) && !errno)
     666             :             || (errno && (errno != EWOULDBLOCK) && (errno != EAGAIN))) {
     667             :                 flog_err_sys(EC_LIB_SOCKET,
     668             :                              "%s routing socket error: %s(%d) bytes %d",
     669             :                              __func__, safe_strerror(errno), errno, rc);
     670             : 
     671             :                 close(ptm_cb.ptm_sock);
     672             :                 ptm_cb.ptm_sock = -1;
     673             :                 zebra_ptm_reset_status(0);
     674             :                 ptm_cb.t_timer = NULL;
     675             :                 thread_add_timer(zrouter.master, zebra_ptm_connect, NULL,
     676             :                                  ptm_cb.reconnect_time,
     677             :                                  &ptm_cb.t_timer);
     678             :                 return;
     679             :         }
     680             : 
     681             :         ptm_cb.t_read = NULL;
     682             :         thread_add_read(zrouter.master, zebra_ptm_sock_read, NULL,
     683             :                         ptm_cb.ptm_sock, &ptm_cb.t_read);
     684             : }
     685             : 
     686             : /* BFD peer/dst register/update */
     687             : void zebra_ptm_bfd_dst_register(ZAPI_HANDLER_ARGS)
     688             : {
     689             :         struct stream *s;
     690             :         struct prefix src_p;
     691             :         struct prefix dst_p;
     692             :         uint8_t multi_hop;
     693             :         uint8_t multi_hop_cnt;
     694             :         uint8_t detect_mul;
     695             :         unsigned int min_rx_timer;
     696             :         unsigned int min_tx_timer;
     697             :         char if_name[INTERFACE_NAMSIZ];
     698             :         uint8_t len;
     699             :         void *out_ctxt;
     700             :         char buf[INET6_ADDRSTRLEN];
     701             :         char tmp_buf[64];
     702             :         int data_len = ZEBRA_PTM_SEND_MAX_SOCKBUF;
     703             :         unsigned int pid;
     704             :         uint8_t cbit_set;
     705             : 
     706             :         if (hdr->command == ZEBRA_BFD_DEST_UPDATE)
     707             :                 client->bfd_peer_upd8_cnt++;
     708             :         else
     709             :                 client->bfd_peer_add_cnt++;
     710             : 
     711             :         if (IS_ZEBRA_DEBUG_EVENT)
     712             :                 zlog_debug("bfd_dst_register msg from client %s: length=%d",
     713             :                            zebra_route_string(client->proto), hdr->length);
     714             : 
     715             :         if (ptm_cb.ptm_sock == -1) {
     716             :                 ptm_cb.t_timer = NULL;
     717             :                 thread_add_timer(zrouter.master, zebra_ptm_connect, NULL,
     718             :                                  ptm_cb.reconnect_time, &ptm_cb.t_timer);
     719             :                 return;
     720             :         }
     721             : 
     722             :         ptm_lib_init_msg(ptm_hdl, 0, PTMLIB_MSG_TYPE_CMD, NULL, &out_ctxt);
     723             :         snprintf(tmp_buf, sizeof(tmp_buf), "%s", ZEBRA_PTM_BFD_START_CMD);
     724             :         ptm_lib_append_msg(ptm_hdl, out_ctxt, ZEBRA_PTM_CMD_STR, tmp_buf);
     725             :         snprintf(tmp_buf, sizeof(tmp_buf), "%s",
     726             :                  zebra_route_string(client->proto));
     727             :         ptm_lib_append_msg(ptm_hdl, out_ctxt, ZEBRA_PTM_BFD_CLIENT_FIELD,
     728             :                            tmp_buf);
     729             : 
     730             :         s = msg;
     731             : 
     732             :         STREAM_GETL(s, pid);
     733             :         snprintf(tmp_buf, sizeof(tmp_buf), "%d", pid);
     734             :         ptm_lib_append_msg(ptm_hdl, out_ctxt, ZEBRA_PTM_BFD_SEQID_FIELD,
     735             :                            tmp_buf);
     736             : 
     737             :         STREAM_GETW(s, dst_p.family);
     738             : 
     739             :         if (dst_p.family == AF_INET)
     740             :                 dst_p.prefixlen = IPV4_MAX_BYTELEN;
     741             :         else
     742             :                 dst_p.prefixlen = IPV6_MAX_BYTELEN;
     743             : 
     744             :         STREAM_GET(&dst_p.u.prefix, s, dst_p.prefixlen);
     745             :         if (dst_p.family == AF_INET) {
     746             :                 inet_ntop(AF_INET, &dst_p.u.prefix4, buf, sizeof(buf));
     747             :                 ptm_lib_append_msg(ptm_hdl, out_ctxt,
     748             :                                    ZEBRA_PTM_BFD_DST_IP_FIELD, buf);
     749             :         } else {
     750             :                 inet_ntop(AF_INET6, &dst_p.u.prefix6, buf, sizeof(buf));
     751             :                 ptm_lib_append_msg(ptm_hdl, out_ctxt,
     752             :                                    ZEBRA_PTM_BFD_DST_IP_FIELD, buf);
     753             :         }
     754             : 
     755             :         STREAM_GETL(s, min_rx_timer);
     756             :         snprintf(tmp_buf, sizeof(tmp_buf), "%d", min_rx_timer);
     757             :         ptm_lib_append_msg(ptm_hdl, out_ctxt, ZEBRA_PTM_BFD_MIN_RX_FIELD,
     758             :                            tmp_buf);
     759             :         STREAM_GETL(s, min_tx_timer);
     760             :         snprintf(tmp_buf, sizeof(tmp_buf), "%d", min_tx_timer);
     761             :         ptm_lib_append_msg(ptm_hdl, out_ctxt, ZEBRA_PTM_BFD_MIN_TX_FIELD,
     762             :                            tmp_buf);
     763             :         STREAM_GETC(s, detect_mul);
     764             :         snprintf(tmp_buf, sizeof(tmp_buf), "%d", detect_mul);
     765             :         ptm_lib_append_msg(ptm_hdl, out_ctxt, ZEBRA_PTM_BFD_DETECT_MULT_FIELD,
     766             :                            tmp_buf);
     767             : 
     768             :         STREAM_GETC(s, multi_hop);
     769             :         if (multi_hop) {
     770             :                 snprintf(tmp_buf, sizeof(tmp_buf), "%d", 1);
     771             :                 ptm_lib_append_msg(ptm_hdl, out_ctxt,
     772             :                                    ZEBRA_PTM_BFD_MULTI_HOP_FIELD, tmp_buf);
     773             :                 STREAM_GETW(s, src_p.family);
     774             : 
     775             :                 if (src_p.family == AF_INET)
     776             :                         src_p.prefixlen = IPV4_MAX_BYTELEN;
     777             :                 else
     778             :                         src_p.prefixlen = IPV6_MAX_BYTELEN;
     779             : 
     780             :                 STREAM_GET(&src_p.u.prefix, s, src_p.prefixlen);
     781             :                 if (src_p.family == AF_INET) {
     782             :                         inet_ntop(AF_INET, &src_p.u.prefix4, buf, sizeof(buf));
     783             :                         ptm_lib_append_msg(ptm_hdl, out_ctxt,
     784             :                                            ZEBRA_PTM_BFD_SRC_IP_FIELD, buf);
     785             :                 } else {
     786             :                         inet_ntop(AF_INET6, &src_p.u.prefix6, buf, sizeof(buf));
     787             :                         ptm_lib_append_msg(ptm_hdl, out_ctxt,
     788             :                                            ZEBRA_PTM_BFD_SRC_IP_FIELD, buf);
     789             :                 }
     790             : 
     791             :                 STREAM_GETC(s, multi_hop_cnt);
     792             :                 snprintf(tmp_buf, sizeof(tmp_buf), "%d", multi_hop_cnt);
     793             :                 ptm_lib_append_msg(ptm_hdl, out_ctxt,
     794             :                                    ZEBRA_PTM_BFD_MAX_HOP_CNT_FIELD, tmp_buf);
     795             : 
     796             :                 if (zvrf_id(zvrf) != VRF_DEFAULT)
     797             :                         ptm_lib_append_msg(ptm_hdl, out_ctxt,
     798             :                                            ZEBRA_PTM_BFD_VRF_NAME_FIELD,
     799             :                                            zvrf_name(zvrf));
     800             :         } else {
     801             :                 if (dst_p.family == AF_INET6) {
     802             :                         STREAM_GETW(s, src_p.family);
     803             : 
     804             :                         if (src_p.family == AF_INET)
     805             :                                 src_p.prefixlen = IPV4_MAX_BYTELEN;
     806             :                         else
     807             :                                 src_p.prefixlen = IPV6_MAX_BYTELEN;
     808             : 
     809             :                         STREAM_GET(&src_p.u.prefix, s, src_p.prefixlen);
     810             :                         if (src_p.family == AF_INET) {
     811             :                                 inet_ntop(AF_INET, &src_p.u.prefix4, buf,
     812             :                                           sizeof(buf));
     813             :                                 ptm_lib_append_msg(ptm_hdl, out_ctxt,
     814             :                                                    ZEBRA_PTM_BFD_SRC_IP_FIELD,
     815             :                                                    buf);
     816             :                         } else {
     817             :                                 inet_ntop(AF_INET6, &src_p.u.prefix6, buf,
     818             :                                           sizeof(buf));
     819             :                                 ptm_lib_append_msg(ptm_hdl, out_ctxt,
     820             :                                                    ZEBRA_PTM_BFD_SRC_IP_FIELD,
     821             :                                                    buf);
     822             :                         }
     823             :                 }
     824             :                 STREAM_GETC(s, len);
     825             :                 STREAM_GET(if_name, s, len);
     826             :                 if_name[len] = '\0';
     827             : 
     828             :                 ptm_lib_append_msg(ptm_hdl, out_ctxt,
     829             :                                    ZEBRA_PTM_BFD_IFNAME_FIELD, if_name);
     830             :         }
     831             :         STREAM_GETC(s, cbit_set);
     832             :         snprintf(tmp_buf, sizeof(tmp_buf), "%d", cbit_set);
     833             :         ptm_lib_append_msg(ptm_hdl, out_ctxt,
     834             :                            ZEBRA_PTM_BFD_CBIT_FIELD, tmp_buf);
     835             : 
     836             :         snprintf(tmp_buf, sizeof(tmp_buf), "%d", 1);
     837             :         ptm_lib_append_msg(ptm_hdl, out_ctxt, ZEBRA_PTM_BFD_SEND_EVENT,
     838             :                            tmp_buf);
     839             : 
     840             :         ptm_lib_complete_msg(ptm_hdl, out_ctxt, ptm_cb.out_data, &data_len);
     841             : 
     842             :         if (IS_ZEBRA_DEBUG_SEND)
     843             :                 zlog_debug("%s: Sent message (%d) %s", __func__, data_len,
     844             :                            ptm_cb.out_data);
     845             :         zebra_ptm_send_message(ptm_cb.out_data, data_len);
     846             : 
     847             :         return;
     848             : 
     849             : stream_failure:
     850             :         ptm_lib_cleanup_msg(ptm_hdl, out_ctxt);
     851             : }
     852             : 
     853             : /* BFD peer/dst deregister */
     854             : void zebra_ptm_bfd_dst_deregister(ZAPI_HANDLER_ARGS)
     855             : {
     856             :         struct stream *s;
     857             :         struct prefix src_p;
     858             :         struct prefix dst_p;
     859             :         uint8_t multi_hop;
     860             :         char if_name[INTERFACE_NAMSIZ];
     861             :         uint8_t len;
     862             :         char buf[INET6_ADDRSTRLEN];
     863             :         char tmp_buf[64];
     864             :         int data_len = ZEBRA_PTM_SEND_MAX_SOCKBUF;
     865             :         void *out_ctxt;
     866             :         unsigned int pid;
     867             : 
     868             :         client->bfd_peer_del_cnt++;
     869             : 
     870             :         if (IS_ZEBRA_DEBUG_EVENT)
     871             :                 zlog_debug("bfd_dst_deregister msg from client %s: length=%d",
     872             :                            zebra_route_string(client->proto), hdr->length);
     873             : 
     874             :         if (ptm_cb.ptm_sock == -1) {
     875             :                 ptm_cb.t_timer = NULL;
     876             :                 thread_add_timer(zrouter.master, zebra_ptm_connect, NULL,
     877             :                                  ptm_cb.reconnect_time, &ptm_cb.t_timer);
     878             :                 return;
     879             :         }
     880             : 
     881             :         ptm_lib_init_msg(ptm_hdl, 0, PTMLIB_MSG_TYPE_CMD, NULL, &out_ctxt);
     882             : 
     883             :         snprintf(tmp_buf, sizeof(tmp_buf), "%s", ZEBRA_PTM_BFD_STOP_CMD);
     884             :         ptm_lib_append_msg(ptm_hdl, out_ctxt, ZEBRA_PTM_CMD_STR, tmp_buf);
     885             : 
     886             :         snprintf(tmp_buf, sizeof(tmp_buf), "%s",
     887             :                  zebra_route_string(client->proto));
     888             :         ptm_lib_append_msg(ptm_hdl, out_ctxt, ZEBRA_PTM_BFD_CLIENT_FIELD,
     889             :                            tmp_buf);
     890             : 
     891             :         s = msg;
     892             : 
     893             :         STREAM_GETL(s, pid);
     894             :         snprintf(tmp_buf, sizeof(tmp_buf), "%d", pid);
     895             :         ptm_lib_append_msg(ptm_hdl, out_ctxt, ZEBRA_PTM_BFD_SEQID_FIELD,
     896             :                            tmp_buf);
     897             : 
     898             :         STREAM_GETW(s, dst_p.family);
     899             : 
     900             :         if (dst_p.family == AF_INET)
     901             :                 dst_p.prefixlen = IPV4_MAX_BYTELEN;
     902             :         else
     903             :                 dst_p.prefixlen = IPV6_MAX_BYTELEN;
     904             : 
     905             :         STREAM_GET(&dst_p.u.prefix, s, dst_p.prefixlen);
     906             :         if (dst_p.family == AF_INET)
     907             :                 inet_ntop(AF_INET, &dst_p.u.prefix4, buf, sizeof(buf));
     908             :         else
     909             :                 inet_ntop(AF_INET6, &dst_p.u.prefix6, buf, sizeof(buf));
     910             :         ptm_lib_append_msg(ptm_hdl, out_ctxt, ZEBRA_PTM_BFD_DST_IP_FIELD, buf);
     911             : 
     912             : 
     913             :         STREAM_GETC(s, multi_hop);
     914             :         if (multi_hop) {
     915             :                 snprintf(tmp_buf, sizeof(tmp_buf), "%d", 1);
     916             :                 ptm_lib_append_msg(ptm_hdl, out_ctxt,
     917             :                                    ZEBRA_PTM_BFD_MULTI_HOP_FIELD, tmp_buf);
     918             : 
     919             :                 STREAM_GETW(s, src_p.family);
     920             : 
     921             :                 if (src_p.family == AF_INET)
     922             :                         src_p.prefixlen = IPV4_MAX_BYTELEN;
     923             :                 else
     924             :                         src_p.prefixlen = IPV6_MAX_BYTELEN;
     925             : 
     926             :                 STREAM_GET(&src_p.u.prefix, s, src_p.prefixlen);
     927             :                 if (src_p.family == AF_INET)
     928             :                         inet_ntop(AF_INET, &src_p.u.prefix4, buf, sizeof(buf));
     929             :                 else
     930             :                         inet_ntop(AF_INET6, &src_p.u.prefix6, buf, sizeof(buf));
     931             :                 ptm_lib_append_msg(ptm_hdl, out_ctxt,
     932             :                                    ZEBRA_PTM_BFD_SRC_IP_FIELD, buf);
     933             : 
     934             :                 if (zvrf_id(zvrf) != VRF_DEFAULT)
     935             :                         ptm_lib_append_msg(ptm_hdl, out_ctxt,
     936             :                                            ZEBRA_PTM_BFD_VRF_NAME_FIELD,
     937             :                                            zvrf_name(zvrf));
     938             :         } else {
     939             :                 if (dst_p.family == AF_INET6) {
     940             :                         STREAM_GETW(s, src_p.family);
     941             : 
     942             :                         if (src_p.family == AF_INET)
     943             :                                 src_p.prefixlen = IPV4_MAX_BYTELEN;
     944             :                         else
     945             :                                 src_p.prefixlen = IPV6_MAX_BYTELEN;
     946             : 
     947             :                         STREAM_GET(&src_p.u.prefix, s, src_p.prefixlen);
     948             :                         if (src_p.family == AF_INET) {
     949             :                                 inet_ntop(AF_INET, &src_p.u.prefix4, buf,
     950             :                                           sizeof(buf));
     951             :                                 ptm_lib_append_msg(ptm_hdl, out_ctxt,
     952             :                                                    ZEBRA_PTM_BFD_SRC_IP_FIELD,
     953             :                                                    buf);
     954             :                         } else {
     955             :                                 inet_ntop(AF_INET6, &src_p.u.prefix6, buf,
     956             :                                           sizeof(buf));
     957             :                                 ptm_lib_append_msg(ptm_hdl, out_ctxt,
     958             :                                                    ZEBRA_PTM_BFD_SRC_IP_FIELD,
     959             :                                                    buf);
     960             :                         }
     961             :                 }
     962             : 
     963             :                 STREAM_GETC(s, len);
     964             :                 STREAM_GET(if_name, s, len);
     965             :                 if_name[len] = '\0';
     966             : 
     967             :                 ptm_lib_append_msg(ptm_hdl, out_ctxt,
     968             :                                    ZEBRA_PTM_BFD_IFNAME_FIELD, if_name);
     969             :         }
     970             : 
     971             :         ptm_lib_complete_msg(ptm_hdl, out_ctxt, ptm_cb.out_data, &data_len);
     972             :         if (IS_ZEBRA_DEBUG_SEND)
     973             :                 zlog_debug("%s: Sent message (%d) %s", __func__, data_len,
     974             :                            ptm_cb.out_data);
     975             : 
     976             :         zebra_ptm_send_message(ptm_cb.out_data, data_len);
     977             : 
     978             :         return;
     979             : 
     980             : stream_failure:
     981             :         ptm_lib_cleanup_msg(ptm_hdl, out_ctxt);
     982             : }
     983             : 
     984             : /* BFD client register */
     985             : void zebra_ptm_bfd_client_register(ZAPI_HANDLER_ARGS)
     986             : {
     987             :         struct stream *s;
     988             :         unsigned int pid;
     989             :         void *out_ctxt = NULL;
     990             :         char tmp_buf[64];
     991             :         int data_len = ZEBRA_PTM_SEND_MAX_SOCKBUF;
     992             : 
     993             :         client->bfd_client_reg_cnt++;
     994             : 
     995             :         if (IS_ZEBRA_DEBUG_EVENT)
     996             :                 zlog_debug("bfd_client_register msg from client %s: length=%d",
     997             :                            zebra_route_string(client->proto), hdr->length);
     998             : 
     999             :         s = msg;
    1000             :         STREAM_GETL(s, pid);
    1001             : 
    1002             :         if (ptm_cb.ptm_sock == -1) {
    1003             :                 ptm_cb.t_timer = NULL;
    1004             :                 thread_add_timer(zrouter.master, zebra_ptm_connect, NULL,
    1005             :                                  ptm_cb.reconnect_time, &ptm_cb.t_timer);
    1006             :                 return;
    1007             :         }
    1008             : 
    1009             :         ptm_lib_init_msg(ptm_hdl, 0, PTMLIB_MSG_TYPE_CMD, NULL, &out_ctxt);
    1010             : 
    1011             :         snprintf(tmp_buf, sizeof(tmp_buf), "%s", ZEBRA_PTM_BFD_CLIENT_REG_CMD);
    1012             :         ptm_lib_append_msg(ptm_hdl, out_ctxt, ZEBRA_PTM_CMD_STR, tmp_buf);
    1013             : 
    1014             :         snprintf(tmp_buf, sizeof(tmp_buf), "%s",
    1015             :                  zebra_route_string(client->proto));
    1016             :         ptm_lib_append_msg(ptm_hdl, out_ctxt, ZEBRA_PTM_BFD_CLIENT_FIELD,
    1017             :                            tmp_buf);
    1018             : 
    1019             :         snprintf(tmp_buf, sizeof(tmp_buf), "%d", pid);
    1020             :         ptm_lib_append_msg(ptm_hdl, out_ctxt, ZEBRA_PTM_BFD_SEQID_FIELD,
    1021             :                            tmp_buf);
    1022             : 
    1023             :         ptm_lib_complete_msg(ptm_hdl, out_ctxt, ptm_cb.out_data, &data_len);
    1024             : 
    1025             :         if (IS_ZEBRA_DEBUG_SEND)
    1026             :                 zlog_debug("%s: Sent message (%d) %s", __func__, data_len,
    1027             :                            ptm_cb.out_data);
    1028             :         zebra_ptm_send_message(ptm_cb.out_data, data_len);
    1029             : 
    1030             :         SET_FLAG(ptm_cb.client_flags[client->proto],
    1031             :                  ZEBRA_PTM_BFD_CLIENT_FLAG_REG);
    1032             : 
    1033             :         return;
    1034             : 
    1035             : stream_failure:
    1036             :         /*
    1037             :          * IF we ever add more STREAM_GETXXX functions after the out_ctxt
    1038             :          * is allocated then we need to add this code back in
    1039             :          *
    1040             :          * if (out_ctxt)
    1041             :          *      ptm_lib_cleanup_msg(ptm_hdl, out_ctxt);
    1042             :          */
    1043             :         return;
    1044             : }
    1045             : 
    1046             : /* BFD client deregister */
    1047             : int zebra_ptm_bfd_client_deregister(struct zserv *client)
    1048             : {
    1049             :         uint8_t proto = client->proto;
    1050             :         void *out_ctxt;
    1051             :         char tmp_buf[64];
    1052             :         int data_len = ZEBRA_PTM_SEND_MAX_SOCKBUF;
    1053             : 
    1054             :         if (!IS_BFD_ENABLED_PROTOCOL(proto))
    1055             :                 return 0;
    1056             : 
    1057             :         if (IS_ZEBRA_DEBUG_EVENT)
    1058             :                 zlog_debug("bfd_client_deregister msg for client %s",
    1059             :                            zebra_route_string(proto));
    1060             : 
    1061             :         if (ptm_cb.ptm_sock == -1) {
    1062             :                 ptm_cb.t_timer = NULL;
    1063             :                 thread_add_timer(zrouter.master, zebra_ptm_connect, NULL,
    1064             :                                  ptm_cb.reconnect_time, &ptm_cb.t_timer);
    1065             :                 return 0;
    1066             :         }
    1067             : 
    1068             :         ptm_lib_init_msg(ptm_hdl, 0, PTMLIB_MSG_TYPE_CMD, NULL, &out_ctxt);
    1069             : 
    1070             :         snprintf(tmp_buf, sizeof(tmp_buf), "%s",
    1071             :                  ZEBRA_PTM_BFD_CLIENT_DEREG_CMD);
    1072             :         ptm_lib_append_msg(ptm_hdl, out_ctxt, ZEBRA_PTM_CMD_STR, tmp_buf);
    1073             : 
    1074             :         snprintf(tmp_buf, sizeof(tmp_buf), "%s", zebra_route_string(proto));
    1075             :         ptm_lib_append_msg(ptm_hdl, out_ctxt, ZEBRA_PTM_BFD_CLIENT_FIELD,
    1076             :                            tmp_buf);
    1077             : 
    1078             :         ptm_lib_complete_msg(ptm_hdl, out_ctxt, ptm_cb.out_data, &data_len);
    1079             : 
    1080             :         if (IS_ZEBRA_DEBUG_SEND)
    1081             :                 zlog_debug("%s: Sent message (%d) %s", __func__, data_len,
    1082             :                            ptm_cb.out_data);
    1083             : 
    1084             :         zebra_ptm_send_message(ptm_cb.out_data, data_len);
    1085             :         UNSET_FLAG(ptm_cb.client_flags[proto], ZEBRA_PTM_BFD_CLIENT_FLAG_REG);
    1086             : 
    1087             :         return 0;
    1088             : }
    1089             : 
    1090             : int zebra_ptm_get_enable_state(void)
    1091             : {
    1092             :         return ptm_cb.ptm_enable;
    1093             : }
    1094             : 
    1095             : /*
    1096             :  * zebra_ptm_get_status_str - Convert status to a display string.
    1097             :  */
    1098             : static const char *zebra_ptm_get_status_str(int status)
    1099             : {
    1100             :         switch (status) {
    1101             :         case ZEBRA_PTM_STATUS_DOWN:
    1102             :                 return "fail";
    1103             :         case ZEBRA_PTM_STATUS_UP:
    1104             :                 return "pass";
    1105             :         case ZEBRA_PTM_STATUS_UNKNOWN:
    1106             :         default:
    1107             :                 return "n/a";
    1108             :         }
    1109             : }
    1110             : 
    1111             : void zebra_ptm_show_status(struct vty *vty, json_object *json,
    1112             :                            struct interface *ifp)
    1113             : {
    1114             :         const char *status;
    1115             : 
    1116             :         if (ifp->ptm_enable)
    1117             :                 status = zebra_ptm_get_status_str(ifp->ptm_status);
    1118             :         else
    1119             :                 status = "disabled";
    1120             : 
    1121             :         if (json)
    1122             :                 json_object_string_add(json, "ptmStatus", status);
    1123             :         else
    1124             :                 vty_out(vty, "  PTM status: %s\n", status);
    1125             : }
    1126             : 
    1127             : void zebra_ptm_send_status_req(void)
    1128             : {
    1129             :         void *out_ctxt;
    1130             :         int len = ZEBRA_PTM_SEND_MAX_SOCKBUF;
    1131             : 
    1132             :         if (ptm_cb.ptm_enable) {
    1133             :                 ptm_lib_init_msg(ptm_hdl, 0, PTMLIB_MSG_TYPE_CMD, NULL,
    1134             :                                  &out_ctxt);
    1135             :                 ptm_lib_append_msg(ptm_hdl, out_ctxt, ZEBRA_PTM_CMD_STR,
    1136             :                                    ZEBRA_PTM_GET_STATUS_CMD);
    1137             :                 ptm_lib_complete_msg(ptm_hdl, out_ctxt, ptm_cb.out_data, &len);
    1138             : 
    1139             :                 zebra_ptm_send_message(ptm_cb.out_data, len);
    1140             :         }
    1141             : }
    1142             : 
    1143             : void zebra_ptm_reset_status(int ptm_disable)
    1144             : {
    1145             :         struct vrf *vrf;
    1146             :         struct interface *ifp;
    1147             :         int send_linkup;
    1148             : 
    1149             :         RB_FOREACH (vrf, vrf_id_head, &vrfs_by_id)
    1150             :                 FOR_ALL_INTERFACES (vrf, ifp) {
    1151             :                         send_linkup = 0;
    1152             :                         if (ifp->ptm_enable) {
    1153             :                                 if (!if_is_operative(ifp))
    1154             :                                         send_linkup = 1;
    1155             : 
    1156             :                                 if (ptm_disable)
    1157             :                                         ifp->ptm_enable =
    1158             :                                                 ZEBRA_IF_PTM_ENABLE_OFF;
    1159             :                                 ifp->ptm_status = ZEBRA_PTM_STATUS_UNKNOWN;
    1160             : 
    1161             :                                 if (if_is_operative(ifp) && send_linkup) {
    1162             :                                         if (IS_ZEBRA_DEBUG_EVENT)
    1163             :                                                 zlog_debug(
    1164             :                                                         "%s: Bringing up interface %s",
    1165             :                                                         __func__, ifp->name);
    1166             :                                         if_up(ifp, true);
    1167             :                                 }
    1168             :                         }
    1169             :                 }
    1170             : }
    1171             : 
    1172             : void zebra_ptm_if_init(struct zebra_if *zebra_ifp)
    1173             : {
    1174             :         zebra_ifp->ptm_enable = ZEBRA_IF_PTM_ENABLE_UNSPEC;
    1175             : }
    1176             : 
    1177             : void zebra_ptm_if_set_ptm_state(struct interface *ifp,
    1178             :                                 struct zebra_if *zebra_ifp)
    1179             : {
    1180             :         if (zebra_ifp && zebra_ifp->ptm_enable != ZEBRA_IF_PTM_ENABLE_UNSPEC)
    1181             :                 ifp->ptm_enable = zebra_ifp->ptm_enable;
    1182             : }
    1183             : 
    1184             : void zebra_ptm_if_write(struct vty *vty, struct zebra_if *zebra_ifp)
    1185             : {
    1186             :         if (zebra_ifp->ptm_enable == ZEBRA_IF_PTM_ENABLE_OFF)
    1187             :                 vty_out(vty, " no ptm-enable\n");
    1188             : }
    1189             : 
    1190             : #else /* HAVE_BFDD */
    1191             : 
    1192             : /*
    1193             :  * Data structures.
    1194             :  */
    1195             : struct ptm_process {
    1196             :         struct zserv *pp_zs;
    1197             :         pid_t pp_pid;
    1198             : 
    1199             :         TAILQ_ENTRY(ptm_process) pp_entry;
    1200             : };
    1201             : TAILQ_HEAD(ppqueue, ptm_process) ppqueue;
    1202             : 
    1203           9 : DEFINE_MTYPE_STATIC(ZEBRA, ZEBRA_PTM_BFD_PROCESS,
    1204             :                     "PTM BFD process registration table.");
    1205             : 
    1206             : /*
    1207             :  * Prototypes.
    1208             :  */
    1209             : static struct ptm_process *pp_new(pid_t pid, struct zserv *zs);
    1210             : static struct ptm_process *pp_lookup_byzs(struct zserv *zs);
    1211             : static void pp_free(struct ptm_process *pp);
    1212             : static void pp_free_all(void);
    1213             : 
    1214             : static void zebra_ptm_send_bfdd(struct stream *msg);
    1215             : static void zebra_ptm_send_clients(struct stream *msg);
    1216             : static int _zebra_ptm_bfd_client_deregister(struct zserv *zs);
    1217             : static void _zebra_ptm_reroute(struct zserv *zs, struct zebra_vrf *zvrf,
    1218             :                                struct stream *msg, uint32_t command);
    1219             : 
    1220             : 
    1221             : /*
    1222             :  * Process PID registration.
    1223             :  */
    1224           3 : static struct ptm_process *pp_new(pid_t pid, struct zserv *zs)
    1225             : {
    1226           3 :         struct ptm_process *pp;
    1227             : 
    1228             : #ifdef PTM_DEBUG
    1229             :         /* Sanity check: more than one client can't have the same PID. */
    1230             :         TAILQ_FOREACH(pp, &ppqueue, pp_entry) {
    1231             :                 if (pp->pp_pid == pid && pp->pp_zs != zs)
    1232             :                         zlog_err("%s:%d pid and client pointer doesn't match",
    1233             :                                  __FILE__, __LINE__);
    1234             :         }
    1235             : #endif /* PTM_DEBUG */
    1236             : 
    1237             :         /* Lookup for duplicates. */
    1238           6 :         pp = pp_lookup_byzs(zs);
    1239           3 :         if (pp != NULL)
    1240             :                 return pp;
    1241             : 
    1242             :         /* Allocate and register new process. */
    1243           3 :         pp = XCALLOC(MTYPE_ZEBRA_PTM_BFD_PROCESS, sizeof(*pp));
    1244             : 
    1245           3 :         pp->pp_pid = pid;
    1246           3 :         pp->pp_zs = zs;
    1247           3 :         TAILQ_INSERT_HEAD(&ppqueue, pp, pp_entry);
    1248             : 
    1249           3 :         return pp;
    1250             : }
    1251             : 
    1252           9 : static struct ptm_process *pp_lookup_byzs(struct zserv *zs)
    1253             : {
    1254           9 :         struct ptm_process *pp;
    1255             : 
    1256          12 :         TAILQ_FOREACH(pp, &ppqueue, pp_entry) {
    1257           6 :                 if (pp->pp_zs != zs)
    1258           3 :                         continue;
    1259             : 
    1260             :                 break;
    1261             :         }
    1262             : 
    1263           3 :         return pp;
    1264             : }
    1265             : 
    1266           3 : static void pp_free(struct ptm_process *pp)
    1267             : {
    1268           3 :         if (pp == NULL)
    1269             :                 return;
    1270             : 
    1271           3 :         TAILQ_REMOVE(&ppqueue, pp, pp_entry);
    1272           3 :         XFREE(MTYPE_ZEBRA_PTM_BFD_PROCESS, pp);
    1273             : }
    1274             : 
    1275           3 : static void pp_free_all(void)
    1276             : {
    1277           3 :         struct ptm_process *pp;
    1278             : 
    1279           3 :         while (!TAILQ_EMPTY(&ppqueue)) {
    1280           0 :                 pp = TAILQ_FIRST(&ppqueue);
    1281           0 :                 pp_free(pp);
    1282             :         }
    1283           3 : }
    1284             : 
    1285             : 
    1286             : /*
    1287             :  * Use the FRR's internal daemon implementation.
    1288             :  */
    1289           6 : static void zebra_ptm_send_bfdd(struct stream *msg)
    1290             : {
    1291           6 :         struct listnode *node;
    1292           6 :         struct zserv *client;
    1293           6 :         struct stream *msgc;
    1294             : 
    1295             :         /* Create copy for replication. */
    1296           6 :         msgc = stream_dup(msg);
    1297             : 
    1298             :         /* Send message to all running BFDd daemons. */
    1299          24 :         for (ALL_LIST_ELEMENTS_RO(zrouter.client_list, node, client)) {
    1300          12 :                 if (client->proto != ZEBRA_ROUTE_BFD)
    1301          12 :                         continue;
    1302             : 
    1303           0 :                 zserv_send_message(client, msg);
    1304             : 
    1305             :                 /* Allocate more messages. */
    1306           0 :                 msg = stream_dup(msgc);
    1307             :         }
    1308             : 
    1309           6 :         stream_free(msgc);
    1310           6 :         stream_free(msg);
    1311           6 : }
    1312             : 
    1313           0 : static void zebra_ptm_send_clients(struct stream *msg)
    1314             : {
    1315           0 :         struct listnode *node;
    1316           0 :         struct zserv *client;
    1317           0 :         struct stream *msgc;
    1318             : 
    1319             :         /* Create copy for replication. */
    1320           0 :         msgc = stream_dup(msg);
    1321             : 
    1322             :         /* Send message to all running client daemons. */
    1323           0 :         for (ALL_LIST_ELEMENTS_RO(zrouter.client_list, node, client)) {
    1324           0 :                 if (!IS_BFD_ENABLED_PROTOCOL(client->proto))
    1325           0 :                         continue;
    1326             : 
    1327           0 :                 zserv_send_message(client, msg);
    1328             : 
    1329             :                 /* Allocate more messages. */
    1330           0 :                 msg = stream_dup(msgc);
    1331             :         }
    1332             : 
    1333           0 :         stream_free(msgc);
    1334           0 :         stream_free(msg);
    1335           0 : }
    1336             : 
    1337           9 : static int _zebra_ptm_bfd_client_deregister(struct zserv *zs)
    1338             : {
    1339           9 :         struct stream *msg;
    1340           9 :         struct ptm_process *pp;
    1341             : 
    1342           9 :         if (!IS_BFD_ENABLED_PROTOCOL(zs->proto))
    1343             :                 return 0;
    1344             : 
    1345             :         /* Find daemon pid by zebra connection pointer. */
    1346           6 :         pp = pp_lookup_byzs(zs);
    1347           6 :         if (pp == NULL) {
    1348           3 :                 zlog_err("%s:%d failed to find process pid registration",
    1349             :                          __FILE__, __LINE__);
    1350           3 :                 return -1;
    1351             :         }
    1352             : 
    1353             :         /* Generate, send message and free() daemon related data. */
    1354           3 :         msg = stream_new(ZEBRA_MAX_PACKET_SIZ);
    1355           3 :         if (msg == NULL) {
    1356           0 :                 zlog_debug("%s: not enough memory", __func__);
    1357           0 :                 return 0;
    1358             :         }
    1359             : 
    1360             :         /*
    1361             :          * The message type will be ZEBRA_BFD_DEST_REPLAY so we can use only
    1362             :          * one callback at the `bfdd` side, however the real command
    1363             :          * number will be included right after the zebra header.
    1364             :          */
    1365           3 :         zclient_create_header(msg, ZEBRA_BFD_DEST_REPLAY, 0);
    1366           3 :         stream_putl(msg, ZEBRA_BFD_CLIENT_DEREGISTER);
    1367             : 
    1368             :         /* Put process PID. */
    1369           3 :         stream_putl(msg, pp->pp_pid);
    1370             : 
    1371             :         /* Update the data pointers. */
    1372           3 :         stream_putw_at(msg, 0, stream_get_endp(msg));
    1373             : 
    1374           3 :         zebra_ptm_send_bfdd(msg);
    1375             : 
    1376           3 :         pp_free(pp);
    1377             : 
    1378           3 :         return 0;
    1379             : }
    1380             : 
    1381           3 : void zebra_ptm_init(void)
    1382             : {
    1383             :         /* Initialize the ptm process information list. */
    1384           3 :         TAILQ_INIT(&ppqueue);
    1385             : 
    1386             :         /*
    1387             :          * Send deregistration messages to BFD daemon when some other
    1388             :          * daemon closes. This will help avoid sending daemons
    1389             :          * unnecessary notification messages.
    1390             :          */
    1391           3 :         hook_register(zserv_client_close, _zebra_ptm_bfd_client_deregister);
    1392           3 : }
    1393             : 
    1394           3 : void zebra_ptm_finish(void)
    1395             : {
    1396             :         /* Remove the client disconnect hook and free all memory. */
    1397           3 :         hook_unregister(zserv_client_close, _zebra_ptm_bfd_client_deregister);
    1398           3 :         pp_free_all();
    1399           3 : }
    1400             : 
    1401             : 
    1402             : /*
    1403             :  * Message handling.
    1404             :  */
    1405           3 : static void _zebra_ptm_reroute(struct zserv *zs, struct zebra_vrf *zvrf,
    1406             :                                struct stream *msg, uint32_t command)
    1407             : {
    1408           3 :         struct stream *msgc;
    1409           3 :         char buf[ZEBRA_MAX_PACKET_SIZ];
    1410           3 :         pid_t ppid;
    1411             : 
    1412             :         /* Create BFD header */
    1413           3 :         msgc = stream_new(ZEBRA_MAX_PACKET_SIZ);
    1414           3 :         zclient_create_header(msgc, ZEBRA_BFD_DEST_REPLAY, zvrf->vrf->vrf_id);
    1415           3 :         stream_putl(msgc, command);
    1416             : 
    1417           3 :         if (STREAM_READABLE(msg) > STREAM_WRITEABLE(msgc)) {
    1418           0 :                 zlog_warn("Cannot fit extended BFD header plus original message contents into ZAPI packet; dropping message");
    1419           0 :                 goto stream_failure;
    1420             :         }
    1421             : 
    1422             :         /* Copy original message, excluding header, into new message */
    1423           3 :         stream_get_from(buf, msg, stream_get_getp(msg), STREAM_READABLE(msg));
    1424           3 :         stream_put(msgc, buf, STREAM_READABLE(msg));
    1425             : 
    1426             :         /* Update length field */
    1427           3 :         stream_putw_at(msgc, 0, STREAM_READABLE(msgc));
    1428             : 
    1429           3 :         zebra_ptm_send_bfdd(msgc);
    1430           3 :         msgc = NULL;
    1431             : 
    1432             :         /* Registrate process PID for shutdown hook. */
    1433           3 :         STREAM_GETL(msg, ppid);
    1434           3 :         pp_new(ppid, zs);
    1435             : 
    1436           3 :         return;
    1437             : 
    1438           0 : stream_failure:
    1439           0 :         if (msgc)
    1440           0 :                 stream_free(msgc);
    1441           0 :         zlog_err("%s:%d failed to registrate client pid", __FILE__, __LINE__);
    1442             : }
    1443             : 
    1444           0 : void zebra_ptm_bfd_dst_register(ZAPI_HANDLER_ARGS)
    1445             : {
    1446           0 :         if (IS_ZEBRA_DEBUG_EVENT)
    1447           0 :                 zlog_debug("bfd_dst_register msg from client %s: length=%d",
    1448             :                            zebra_route_string(client->proto), hdr->length);
    1449             : 
    1450           0 :         _zebra_ptm_reroute(client, zvrf, msg, ZEBRA_BFD_DEST_REGISTER);
    1451           0 : }
    1452             : 
    1453           0 : void zebra_ptm_bfd_dst_deregister(ZAPI_HANDLER_ARGS)
    1454             : {
    1455           0 :         if (IS_ZEBRA_DEBUG_EVENT)
    1456           0 :                 zlog_debug("bfd_dst_deregister msg from client %s: length=%d",
    1457             :                            zebra_route_string(client->proto), hdr->length);
    1458             : 
    1459           0 :         _zebra_ptm_reroute(client, zvrf, msg, ZEBRA_BFD_DEST_DEREGISTER);
    1460           0 : }
    1461             : 
    1462           3 : void zebra_ptm_bfd_client_register(ZAPI_HANDLER_ARGS)
    1463             : {
    1464           3 :         if (IS_ZEBRA_DEBUG_EVENT)
    1465           0 :                 zlog_debug("bfd_client_register msg from client %s: length=%d",
    1466             :                            zebra_route_string(client->proto), hdr->length);
    1467             : 
    1468           3 :         _zebra_ptm_reroute(client, zvrf, msg, ZEBRA_BFD_CLIENT_REGISTER);
    1469           3 : }
    1470             : 
    1471           0 : void zebra_ptm_bfd_dst_replay(ZAPI_HANDLER_ARGS)
    1472             : {
    1473           0 :         struct stream *msgc;
    1474           0 :         size_t zmsglen, zhdrlen;
    1475           0 :         uint32_t cmd;
    1476             : 
    1477             :         /*
    1478             :          * NOTE:
    1479             :          * Replay messages with HAVE_BFDD are meant to be replayed to
    1480             :          * the client daemons. These messages are composed and
    1481             :          * originated from the `bfdd` daemon.
    1482             :          */
    1483           0 :         if (IS_ZEBRA_DEBUG_EVENT)
    1484           0 :                 zlog_debug("bfd_dst_update msg from client %s: length=%d",
    1485             :                            zebra_route_string(client->proto), hdr->length);
    1486             : 
    1487             :         /*
    1488             :          * Client messages must be re-routed, otherwise do the `bfdd`
    1489             :          * special treatment.
    1490             :          */
    1491           0 :         if (client->proto != ZEBRA_ROUTE_BFD) {
    1492           0 :                 _zebra_ptm_reroute(client, zvrf, msg, ZEBRA_BFD_DEST_REPLAY);
    1493           0 :                 return;
    1494             :         }
    1495             : 
    1496             :         /* Figure out if this is an DEST_UPDATE or DEST_REPLAY. */
    1497           0 :         if (stream_getl2(msg, &cmd) == false) {
    1498           0 :                 zlog_err("%s: expected at least 4 bytes (command)", __func__);
    1499           0 :                 return;
    1500             :         }
    1501             : 
    1502             :         /*
    1503             :          * Don't modify message in the zebra API. In order to do that we
    1504             :          * need to allocate a new message stream and copy the message
    1505             :          * provided by zebra.
    1506             :          */
    1507           0 :         msgc = stream_new(ZEBRA_MAX_PACKET_SIZ);
    1508           0 :         if (msgc == NULL) {
    1509           0 :                 zlog_debug("%s: not enough memory", __func__);
    1510           0 :                 return;
    1511             :         }
    1512             : 
    1513             :         /* Calculate our header size plus the message contents. */
    1514           0 :         if (cmd != ZEBRA_BFD_DEST_REPLAY) {
    1515           0 :                 zhdrlen = ZEBRA_HEADER_SIZE;
    1516           0 :                 zmsglen = msg->endp - msg->getp;
    1517           0 :                 memcpy(msgc->data + zhdrlen, msg->data + msg->getp, zmsglen);
    1518             : 
    1519           0 :                 zclient_create_header(msgc, cmd, zvrf_id(zvrf));
    1520             : 
    1521           0 :                 msgc->getp = 0;
    1522           0 :                 msgc->endp = zhdrlen + zmsglen;
    1523             :         } else
    1524           0 :                 zclient_create_header(msgc, cmd, zvrf_id(zvrf));
    1525             : 
    1526             :         /* Update the data pointers. */
    1527           0 :         stream_putw_at(msgc, 0, stream_get_endp(msgc));
    1528             : 
    1529           0 :         zebra_ptm_send_clients(msgc);
    1530             : }
    1531             : 
    1532             : /*
    1533             :  * Unused functions.
    1534             :  */
    1535           9 : void zebra_ptm_if_init(struct zebra_if *zifp __attribute__((__unused__)))
    1536             : {
    1537             :         /* NOTHING */
    1538           9 : }
    1539             : 
    1540           9 : int zebra_ptm_get_enable_state(void)
    1541             : {
    1542           9 :         return 0;
    1543             : }
    1544             : 
    1545           0 : void zebra_ptm_show_status(struct vty *vty __attribute__((__unused__)),
    1546             :                            json_object *json __attribute__((__unused__)),
    1547             :                            struct interface *ifp __attribute__((__unused__)))
    1548             : {
    1549             :         /* NOTHING */
    1550           0 : }
    1551             : 
    1552           0 : void zebra_ptm_write(struct vty *vty __attribute__((__unused__)))
    1553             : {
    1554             :         /* NOTHING */
    1555           0 : }
    1556             : 
    1557           0 : void zebra_ptm_if_write(struct vty *vty __attribute__((__unused__)),
    1558             :                         struct zebra_if *zifp __attribute__((__unused__)))
    1559             : {
    1560             :         /* NOTHING */
    1561           0 : }
    1562           9 : void zebra_ptm_if_set_ptm_state(struct interface *i __attribute__((__unused__)),
    1563             :                                 struct zebra_if *zi __attribute__((__unused__)))
    1564             : {
    1565             :         /* NOTHING */
    1566           9 : }
    1567             : 
    1568             : #endif /* HAVE_BFDD */

Generated by: LCOV version v1.16-topotato