back to topotato report
topotato coverage report
Current view: top level - bfdd - ptm_adapter.c (source / functions) Hit Total Coverage
Test: test_pim_bfd.py::PIMBFDTest Lines: 260 430 60.5 %
Date: 2023-02-24 18:39:40 Functions: 24 30 80.0 %

          Line data    Source code
       1             : /*
       2             :  * BFD PTM adapter 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 "lib/libfrr.h"
      24             : #include "lib/queue.h"
      25             : #include "lib/stream.h"
      26             : #include "lib/zclient.h"
      27             : #include "lib/printfrr.h"
      28             : 
      29             : #include "lib/bfd.h"
      30             : 
      31             : #include "bfd.h"
      32             : 
      33             : /*
      34             :  * Data structures
      35             :  */
      36             : struct ptm_client_notification {
      37             :         struct bfd_session *pcn_bs;
      38             :         struct ptm_client *pcn_pc;
      39             : 
      40             :         TAILQ_ENTRY(ptm_client_notification) pcn_entry;
      41             : };
      42             : TAILQ_HEAD(pcnqueue, ptm_client_notification);
      43             : 
      44             : struct ptm_client {
      45             :         uint32_t pc_pid;
      46             :         struct pcnqueue pc_pcnqueue;
      47             : 
      48             :         TAILQ_ENTRY(ptm_client) pc_entry;
      49             : };
      50             : TAILQ_HEAD(pcqueue, ptm_client);
      51             : 
      52             : static struct pcqueue pcqueue;
      53             : static struct zclient *zclient;
      54             : 
      55             : 
      56             : /*
      57             :  * Prototypes
      58             :  */
      59             : static int _ptm_msg_address(struct stream *msg, int family, const void *addr);
      60             : 
      61             : static void _ptm_msg_read_address(struct stream *msg, struct sockaddr_any *sa);
      62             : static int _ptm_msg_read(struct stream *msg, int command, vrf_id_t vrf_id,
      63             :                          struct bfd_peer_cfg *bpc, struct ptm_client **pc);
      64             : 
      65             : static struct ptm_client *pc_lookup(uint32_t pid);
      66             : static struct ptm_client *pc_new(uint32_t pid);
      67             : static void pc_free(struct ptm_client *pc);
      68             : static void pc_free_all(void);
      69             : static struct ptm_client_notification *pcn_new(struct ptm_client *pc,
      70             :                                                struct bfd_session *bs);
      71             : static struct ptm_client_notification *pcn_lookup(struct ptm_client *pc,
      72             :                                                   struct bfd_session *bs);
      73             : static void pcn_free(struct ptm_client_notification *pcn);
      74             : 
      75             : 
      76             : static void bfdd_dest_register(struct stream *msg, vrf_id_t vrf_id);
      77             : static void bfdd_dest_deregister(struct stream *msg, vrf_id_t vrf_id);
      78             : static void bfdd_client_register(struct stream *msg);
      79             : static void bfdd_client_deregister(struct stream *msg);
      80             : 
      81             : /*
      82             :  * Functions
      83             :  */
      84             : PRINTFRR(2, 3)
      85          13 : static void debug_printbpc(const struct bfd_peer_cfg *bpc, const char *fmt, ...)
      86             : {
      87          13 :         char timers[3][128] = {};
      88          13 :         char minttl_str[32] = {};
      89          13 :         char addr[3][128] = {};
      90          13 :         char profile[128] = {};
      91          13 :         char cbit_str[32];
      92          13 :         char msgbuf[512];
      93          13 :         va_list vl;
      94             : 
      95             :         /* Avoid debug calculations if it's disabled. */
      96          13 :         if (bglobal.debug_zebra == false)
      97          13 :                 return;
      98             : 
      99           0 :         snprintf(addr[0], sizeof(addr[0]), "peer:%s", satostr(&bpc->bpc_peer));
     100           0 :         if (bpc->bpc_local.sa_sin.sin_family)
     101           0 :                 snprintf(addr[1], sizeof(addr[1]), " local:%s",
     102             :                          satostr(&bpc->bpc_local));
     103             : 
     104           0 :         if (bpc->bpc_has_localif)
     105           0 :                 snprintf(addr[2], sizeof(addr[2]), " ifname:%s",
     106           0 :                          bpc->bpc_localif);
     107             : 
     108           0 :         if (bpc->bpc_has_vrfname)
     109           0 :                 snprintf(addr[2], sizeof(addr[2]), " vrf:%s", bpc->bpc_vrfname);
     110             : 
     111           0 :         if (bpc->bpc_has_recvinterval)
     112           0 :                 snprintfrr(timers[0], sizeof(timers[0]), " rx:%" PRIu64,
     113           0 :                            bpc->bpc_recvinterval);
     114             : 
     115           0 :         if (bpc->bpc_has_txinterval)
     116           0 :                 snprintfrr(timers[1], sizeof(timers[1]), " tx:%" PRIu64,
     117           0 :                            bpc->bpc_recvinterval);
     118             : 
     119           0 :         if (bpc->bpc_has_detectmultiplier)
     120           0 :                 snprintf(timers[2], sizeof(timers[2]), " detect-multiplier:%d",
     121           0 :                          bpc->bpc_detectmultiplier);
     122             : 
     123           0 :         snprintf(cbit_str, sizeof(cbit_str), " cbit:0x%02x", bpc->bpc_cbit);
     124             : 
     125           0 :         if (bpc->bpc_has_minimum_ttl)
     126           0 :                 snprintf(minttl_str, sizeof(minttl_str), " minimum-ttl:%d",
     127           0 :                          bpc->bpc_minimum_ttl);
     128             : 
     129           0 :         if (bpc->bpc_has_profile)
     130           0 :                 snprintf(profile, sizeof(profile), " profile:%s",
     131           0 :                          bpc->bpc_profile);
     132             : 
     133           0 :         va_start(vl, fmt);
     134           0 :         vsnprintf(msgbuf, sizeof(msgbuf), fmt, vl);
     135           0 :         va_end(vl);
     136             : 
     137           0 :         zlog_debug("%s [mhop:%s %s%s%s%s%s%s%s%s%s]", msgbuf,
     138             :                    bpc->bpc_mhop ? "yes" : "no", addr[0], addr[1], addr[2],
     139             :                    timers[0], timers[1], timers[2], cbit_str, minttl_str,
     140             :                    profile);
     141             : }
     142             : 
     143           8 : static void _ptm_bfd_session_del(struct bfd_session *bs, uint8_t diag)
     144             : {
     145           8 :         if (bglobal.debug_peer_event)
     146           0 :                 zlog_debug("session-delete: %s", bs_to_string(bs));
     147             : 
     148             :         /* Change state and notify peer. */
     149           8 :         bs->ses_state = PTM_BFD_DOWN;
     150           8 :         bs->local_diag = diag;
     151           8 :         ptm_bfd_snd(bs, 0);
     152             : 
     153             :         /* Session reached refcount == 0, lets delete it. */
     154           8 :         if (bs->refcount == 0) {
     155             :                 /*
     156             :                  * Sanity check: if there is a refcount bug, we can't delete
     157             :                  * the session a user configured manually. Lets leave a
     158             :                  * message here so we can catch the bug if it exists.
     159             :                  */
     160           8 :                 if (CHECK_FLAG(bs->flags, BFD_SESS_FLAG_CONFIG)) {
     161           0 :                         zlog_err(
     162             :                                 "ptm-del-session: [%s] session refcount is zero but it was configured by CLI",
     163             :                                 bs_to_string(bs));
     164             :                 } else {
     165           8 :                         control_notify_config(BCM_NOTIFY_CONFIG_DELETE, bs);
     166           8 :                         bfd_session_free(bs);
     167             :                 }
     168             :         }
     169           8 : }
     170             : 
     171          34 : static int _ptm_msg_address(struct stream *msg, int family, const void *addr)
     172             : {
     173          34 :         stream_putc(msg, family);
     174             : 
     175          34 :         switch (family) {
     176          34 :         case AF_INET:
     177          34 :                 stream_put(msg, addr, sizeof(struct in_addr));
     178          34 :                 stream_putc(msg, 32);
     179          34 :                 break;
     180             : 
     181           0 :         case AF_INET6:
     182           0 :                 stream_put(msg, addr, sizeof(struct in6_addr));
     183           0 :                 stream_putc(msg, 128);
     184           0 :                 break;
     185             : 
     186             :         default:
     187           0 :                 assert(0);
     188             :                 break;
     189             :         }
     190             : 
     191          34 :         return 0;
     192             : }
     193             : 
     194          17 : int ptm_bfd_notify(struct bfd_session *bs, uint8_t notify_state)
     195             : {
     196          17 :         struct stream *msg;
     197             : 
     198          17 :         bs->stats.znotification++;
     199             : 
     200             :         /*
     201             :          * Message format:
     202             :          * - header: command, vrf
     203             :          * - l: interface index
     204             :          * - c: family
     205             :          *   - AF_INET:
     206             :          *     - 4 bytes: ipv4
     207             :          *   - AF_INET6:
     208             :          *     - 16 bytes: ipv6
     209             :          *   - c: prefix length
     210             :          * - l: bfd status
     211             :          * - c: family
     212             :          *   - AF_INET:
     213             :          *     - 4 bytes: ipv4
     214             :          *   - AF_INET6:
     215             :          *     - 16 bytes: ipv6
     216             :          *   - c: prefix length
     217             :          * - c: cbit
     218             :          *
     219             :          * Commands: ZEBRA_BFD_DEST_REPLAY
     220             :          *
     221             :          * q(64), l(32), w(16), c(8)
     222             :          */
     223          17 :         msg = zclient->obuf;
     224          17 :         stream_reset(msg);
     225             : 
     226             :         /* TODO: VRF handling */
     227          17 :         if (bs->vrf)
     228          17 :                 zclient_create_header(msg, ZEBRA_BFD_DEST_REPLAY, bs->vrf->vrf_id);
     229             :         else
     230           0 :                 zclient_create_header(msg, ZEBRA_BFD_DEST_REPLAY, VRF_DEFAULT);
     231             : 
     232             :         /* This header will be handled by `zebra_ptm.c`. */
     233          17 :         stream_putl(msg, ZEBRA_INTERFACE_BFD_DEST_UPDATE);
     234             : 
     235             :         /* NOTE: Interface is a shortcut to avoid comparing source address. */
     236          17 :         if (!CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH) && bs->ifp != NULL)
     237          17 :                 stream_putl(msg, bs->ifp->ifindex);
     238             :         else
     239           0 :                 stream_putl(msg, IFINDEX_INTERNAL);
     240             : 
     241             :         /* BFD destination prefix information. */
     242          17 :         _ptm_msg_address(msg, bs->key.family, &bs->key.peer);
     243             : 
     244             :         /* BFD status */
     245          17 :         switch (notify_state) {
     246           6 :         case PTM_BFD_UP:
     247           6 :                 stream_putl(msg, BFD_STATUS_UP);
     248           6 :                 break;
     249             : 
     250           0 :         case PTM_BFD_ADM_DOWN:
     251           0 :                 stream_putl(msg, BFD_STATUS_ADMIN_DOWN);
     252           0 :                 break;
     253             : 
     254          11 :         case PTM_BFD_DOWN:
     255             :         case PTM_BFD_INIT:
     256          11 :                 stream_putl(msg, BFD_STATUS_DOWN);
     257          11 :                 break;
     258             : 
     259           0 :         default:
     260           0 :                 stream_putl(msg, BFD_STATUS_UNKNOWN);
     261           0 :                 break;
     262             :         }
     263             : 
     264             :         /* BFD source prefix information. */
     265          17 :         _ptm_msg_address(msg, bs->key.family, &bs->key.local);
     266             : 
     267          17 :         stream_putc(msg, bs->remote_cbit);
     268             : 
     269             :         /* Write packet size. */
     270          17 :         stream_putw_at(msg, 0, stream_get_endp(msg));
     271             : 
     272          17 :         return zclient_send_message(zclient);
     273             : }
     274             : 
     275          26 : static void _ptm_msg_read_address(struct stream *msg, struct sockaddr_any *sa)
     276             : {
     277          26 :         uint16_t family;
     278             : 
     279          26 :         STREAM_GETW(msg, family);
     280             : 
     281          26 :         switch (family) {
     282          26 :         case AF_INET:
     283          26 :                 sa->sa_sin.sin_family = family;
     284          26 :                 STREAM_GET(&sa->sa_sin.sin_addr, msg,
     285             :                            sizeof(sa->sa_sin.sin_addr));
     286             : #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
     287             :                 sa->sa_sin.sin_len = sizeof(sa->sa_sin);
     288             : #endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */
     289             :                 return;
     290             : 
     291           0 :         case AF_INET6:
     292           0 :                 sa->sa_sin6.sin6_family = family;
     293           0 :                 STREAM_GET(&sa->sa_sin6.sin6_addr, msg,
     294             :                            sizeof(sa->sa_sin6.sin6_addr));
     295             : #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
     296             :                 sa->sa_sin6.sin6_len = sizeof(sa->sa_sin6);
     297             : #endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */
     298             :                 return;
     299             : 
     300           0 :         default:
     301           0 :                 zlog_warn("ptm-read-address: invalid family: %d", family);
     302           0 :                 break;
     303             :         }
     304             : 
     305           0 : stream_failure:
     306           0 :         memset(sa, 0, sizeof(*sa));
     307             : }
     308             : 
     309          13 : static int _ptm_msg_read(struct stream *msg, int command, vrf_id_t vrf_id,
     310             :                          struct bfd_peer_cfg *bpc, struct ptm_client **pc)
     311             : {
     312          13 :         uint32_t pid;
     313          13 :         size_t ifnamelen;
     314             : 
     315             :         /*
     316             :          * Register/Deregister/Update Message format:
     317             :          *
     318             :          * Old format (being used by PTM BFD).
     319             :          * - header: Command, VRF
     320             :          * - l: pid
     321             :          * - w: family
     322             :          *   - AF_INET:
     323             :          *     - l: destination ipv4
     324             :          *   - AF_INET6:
     325             :          *     - 16 bytes: destination IPv6
     326             :          * - command != ZEBRA_BFD_DEST_DEREGISTER
     327             :          *   - l: min_rx
     328             :          *   - l: min_tx
     329             :          *   - c: detect multiplier
     330             :          * - c: is_multihop?
     331             :          *   - multihop:
     332             :          *     - w: family
     333             :          *       - AF_INET:
     334             :          *         - l: source IPv4 address
     335             :          *       - AF_INET6:
     336             :          *         - 16 bytes: source IPv6 address
     337             :          *     - c: ttl
     338             :          *   - no multihop
     339             :          *     - AF_INET6:
     340             :          *       - w: family
     341             :          *       - 16 bytes: source IPv6 address
     342             :          *     - c: ifname length
     343             :          *     - X bytes: interface name
     344             :          *
     345             :          * New format:
     346             :          * - header: Command, VRF
     347             :          * - l: pid
     348             :          * - w: family
     349             :          *   - AF_INET:
     350             :          *     - l: destination IPv4 address
     351             :          *   - AF_INET6:
     352             :          *     - 16 bytes: destination IPv6 address
     353             :          * - l: min_rx
     354             :          * - l: min_tx
     355             :          * - c: detect multiplier
     356             :          * - c: is_multihop?
     357             :          * - w: family
     358             :          *   - AF_INET:
     359             :          *     - l: source IPv4 address
     360             :          *   - AF_INET6:
     361             :          *     - 16 bytes: source IPv6 address
     362             :          * - c: ttl
     363             :          * - c: ifname length
     364             :          * - X bytes: interface name
     365             :          * - c: bfd_cbit
     366             :          * - c: profile name length.
     367             :          * - X bytes: profile name.
     368             :          *
     369             :          * q(64), l(32), w(16), c(8)
     370             :          */
     371             : 
     372             :         /* Initialize parameters return values. */
     373          13 :         memset(bpc, 0, sizeof(*bpc));
     374          13 :         *pc = NULL;
     375             : 
     376             :         /* Find or allocate process context data. */
     377          13 :         STREAM_GETL(msg, pid);
     378             : 
     379          13 :         *pc = pc_new(pid);
     380             : 
     381             :         /* Register/update peer information. */
     382          13 :         _ptm_msg_read_address(msg, &bpc->bpc_peer);
     383             : 
     384             :         /* Determine IP type from peer destination. */
     385          13 :         bpc->bpc_ipv4 = (bpc->bpc_peer.sa_sin.sin_family == AF_INET);
     386             : 
     387             :         /* Get peer configuration. */
     388          13 :         STREAM_GETL(msg, bpc->bpc_recvinterval);
     389          13 :         bpc->bpc_has_recvinterval =
     390          13 :                 (bpc->bpc_recvinterval != BPC_DEF_RECEIVEINTERVAL);
     391             : 
     392          13 :         STREAM_GETL(msg, bpc->bpc_txinterval);
     393          13 :         bpc->bpc_has_txinterval =
     394          13 :                 (bpc->bpc_txinterval != BPC_DEF_TRANSMITINTERVAL);
     395             : 
     396          13 :         STREAM_GETC(msg, bpc->bpc_detectmultiplier);
     397          13 :         bpc->bpc_has_detectmultiplier =
     398          13 :                 (bpc->bpc_detectmultiplier != BPC_DEF_DETECTMULTIPLIER);
     399             : 
     400             :         /* Read (single|multi)hop and its options. */
     401          13 :         STREAM_GETC(msg, bpc->bpc_mhop);
     402             : 
     403             :         /* Read multihop source address and TTL. */
     404          13 :         _ptm_msg_read_address(msg, &bpc->bpc_local);
     405             : 
     406             :         /* Read the minimum TTL (0 means unset or invalid). */
     407          13 :         STREAM_GETC(msg, bpc->bpc_minimum_ttl);
     408          13 :         if (bpc->bpc_minimum_ttl == 0) {
     409           0 :                 bpc->bpc_minimum_ttl = BFD_DEF_MHOP_TTL;
     410           0 :                 bpc->bpc_has_minimum_ttl = false;
     411             :         } else {
     412          13 :                 bpc->bpc_minimum_ttl = (BFD_TTL_VAL + 1) - bpc->bpc_minimum_ttl;
     413          13 :                 bpc->bpc_has_minimum_ttl = true;
     414             :         }
     415             : 
     416             :         /*
     417             :          * Read interface name and make sure it fits our data
     418             :          * structure, otherwise fail.
     419             :          */
     420          13 :         STREAM_GETC(msg, ifnamelen);
     421          13 :         if (ifnamelen >= sizeof(bpc->bpc_localif)) {
     422           0 :                 zlog_err("ptm-read: interface name is too big");
     423           0 :                 return -1;
     424             :         }
     425             : 
     426          13 :         bpc->bpc_has_localif = ifnamelen > 0;
     427          13 :         if (bpc->bpc_has_localif) {
     428          13 :                 STREAM_GET(bpc->bpc_localif, msg, ifnamelen);
     429          13 :                 bpc->bpc_localif[ifnamelen] = 0;
     430             :         }
     431             : 
     432          13 :         if (vrf_id != VRF_DEFAULT) {
     433           0 :                 struct vrf *vrf;
     434             : 
     435           0 :                 vrf = vrf_lookup_by_id(vrf_id);
     436           0 :                 if (vrf) {
     437           0 :                         bpc->bpc_has_vrfname = true;
     438           0 :                         strlcpy(bpc->bpc_vrfname, vrf->name, sizeof(bpc->bpc_vrfname));
     439             :                 } else {
     440           0 :                         zlog_err("ptm-read: vrf id %u could not be identified",
     441             :                                  vrf_id);
     442           0 :                         return -1;
     443             :                 }
     444             :         } else {
     445          13 :                 bpc->bpc_has_vrfname = true;
     446          13 :                 strlcpy(bpc->bpc_vrfname, VRF_DEFAULT_NAME, sizeof(bpc->bpc_vrfname));
     447             :         }
     448             : 
     449             :         /* Read control plane independant configuration. */
     450          13 :         STREAM_GETC(msg, bpc->bpc_cbit);
     451             : 
     452             :         /* Handle profile names. */
     453          13 :         STREAM_GETC(msg, ifnamelen);
     454          13 :         bpc->bpc_has_profile = ifnamelen > 0;
     455          13 :         if (bpc->bpc_has_profile) {
     456           1 :                 STREAM_GET(bpc->bpc_profile, msg, ifnamelen);
     457           1 :                 bpc->bpc_profile[ifnamelen] = 0;
     458             :         }
     459             : 
     460             :         /* Sanity check: peer and local address must match IP types. */
     461          13 :         if (bpc->bpc_local.sa_sin.sin_family != AF_UNSPEC
     462          13 :             && (bpc->bpc_local.sa_sin.sin_family
     463          13 :                 != bpc->bpc_peer.sa_sin.sin_family)) {
     464           0 :                 zlog_warn("ptm-read: peer family doesn't match local type");
     465           0 :                 return -1;
     466             :         }
     467             : 
     468             :         return 0;
     469             : 
     470             : stream_failure:
     471             :         return -1;
     472             : }
     473             : 
     474           8 : static void bfdd_dest_register(struct stream *msg, vrf_id_t vrf_id)
     475             : {
     476           8 :         struct ptm_client *pc;
     477           8 :         struct bfd_session *bs;
     478           8 :         struct bfd_peer_cfg bpc;
     479             : 
     480             :         /* Read the client context and peer data. */
     481           8 :         if (_ptm_msg_read(msg, ZEBRA_BFD_DEST_REGISTER, vrf_id, &bpc, &pc) == -1)
     482           0 :                 return;
     483             : 
     484           8 :         debug_printbpc(&bpc, "ptm-add-dest: register peer");
     485             : 
     486             :         /* Find or start new BFD session. */
     487           8 :         bs = bs_peer_find(&bpc);
     488           8 :         if (bs == NULL) {
     489           8 :                 bs = ptm_bfd_sess_new(&bpc);
     490           8 :                 if (bs == NULL) {
     491           0 :                         if (bglobal.debug_zebra)
     492           0 :                                 zlog_debug(
     493             :                                         "ptm-add-dest: failed to create BFD session");
     494           0 :                         return;
     495             :                 }
     496             :         } else {
     497             :                 /*
     498             :                  * BFD session was already created, we are just updating the
     499             :                  * current peer.
     500             :                  *
     501             :                  * `ptm-bfd` (or `HAVE_BFDD == 0`) is the only implementation
     502             :                  * that allow users to set peer specific timers via protocol.
     503             :                  * BFD daemon (this code) on the other hand only supports
     504             :                  * changing peer configuration manually (through `peer` node)
     505             :                  * or via profiles.
     506             :                  */
     507           0 :                 if (bpc.bpc_has_profile)
     508           0 :                         bfd_profile_apply(bpc.bpc_profile, bs);
     509             :         }
     510             : 
     511             :         /* Create client peer notification register. */
     512           8 :         pcn_new(pc, bs);
     513             : 
     514           8 :         ptm_bfd_notify(bs, bs->ses_state);
     515             : }
     516             : 
     517           5 : static void bfdd_dest_deregister(struct stream *msg, vrf_id_t vrf_id)
     518             : {
     519           5 :         struct ptm_client *pc;
     520           5 :         struct ptm_client_notification *pcn;
     521           5 :         struct bfd_session *bs;
     522           5 :         struct bfd_peer_cfg bpc;
     523             : 
     524             :         /* Read the client context and peer data. */
     525           5 :         if (_ptm_msg_read(msg, ZEBRA_BFD_DEST_DEREGISTER, vrf_id, &bpc, &pc) == -1)
     526           5 :                 return;
     527             : 
     528           5 :         debug_printbpc(&bpc, "ptm-del-dest: deregister peer");
     529             : 
     530             :         /* Find or start new BFD session. */
     531           5 :         bs = bs_peer_find(&bpc);
     532           5 :         if (bs == NULL) {
     533           0 :                 if (bglobal.debug_zebra)
     534           0 :                         zlog_debug("ptm-del-dest: failed to find BFD session");
     535           0 :                 return;
     536             :         }
     537             : 
     538             :         /* Unregister client peer notification. */
     539          10 :         pcn = pcn_lookup(pc, bs);
     540           5 :         if (pcn != NULL) {
     541           5 :                 pcn_free(pcn);
     542           5 :                 return;
     543             :         }
     544             : 
     545           0 :         if (bglobal.debug_zebra)
     546           0 :                 zlog_debug("ptm-del-dest: failed to find BFD session");
     547             : 
     548             :         /*
     549             :          * XXX: We either got a double deregistration or the daemon who
     550             :          * created this is no longer around. Lets try to delete it anyway
     551             :          * and the worst case is the refcount will detain us.
     552             :          */
     553           0 :         _ptm_bfd_session_del(bs, BD_NEIGHBOR_DOWN);
     554             : }
     555             : 
     556             : /*
     557             :  * header: command, VRF
     558             :  * l: pid
     559             :  */
     560           4 : static void bfdd_client_register(struct stream *msg)
     561             : {
     562           4 :         uint32_t pid;
     563             : 
     564             :         /* Find or allocate process context data. */
     565           4 :         STREAM_GETL(msg, pid);
     566             : 
     567           4 :         pc_new(pid);
     568             : 
     569           4 :         return;
     570             : 
     571           0 : stream_failure:
     572           0 :         zlog_err("ptm-add-client: failed to register client");
     573             : }
     574             : 
     575             : /*
     576             :  * header: command, VRF
     577             :  * l: pid
     578             :  */
     579           0 : static void bfdd_client_deregister(struct stream *msg)
     580             : {
     581           0 :         struct ptm_client *pc;
     582           0 :         uint32_t pid;
     583             : 
     584             :         /* Find or allocate process context data. */
     585           0 :         STREAM_GETL(msg, pid);
     586             : 
     587           0 :         pc = pc_lookup(pid);
     588           0 :         if (pc == NULL) {
     589           0 :                 if (bglobal.debug_zebra)
     590           0 :                         zlog_debug("ptm-del-client: failed to find client: %u",
     591             :                                    pid);
     592           0 :                 return;
     593             :         }
     594             : 
     595           0 :         if (bglobal.debug_zebra)
     596           0 :                 zlog_debug("ptm-del-client: client pid %u", pid);
     597             : 
     598           0 :         pc_free(pc);
     599             : 
     600           0 :         return;
     601             : 
     602           0 : stream_failure:
     603           0 :         zlog_err("ptm-del-client: failed to deregister client");
     604             : }
     605             : 
     606          17 : static int bfdd_replay(ZAPI_CALLBACK_ARGS)
     607             : {
     608          17 :         struct stream *msg = zclient->ibuf;
     609          17 :         uint32_t rcmd;
     610             : 
     611          17 :         STREAM_GETL(msg, rcmd);
     612             : 
     613          17 :         switch (rcmd) {
     614           8 :         case ZEBRA_BFD_DEST_REGISTER:
     615             :         case ZEBRA_BFD_DEST_UPDATE:
     616           8 :                 bfdd_dest_register(msg, vrf_id);
     617           8 :                 break;
     618           5 :         case ZEBRA_BFD_DEST_DEREGISTER:
     619           5 :                 bfdd_dest_deregister(msg, vrf_id);
     620           5 :                 break;
     621           4 :         case ZEBRA_BFD_CLIENT_REGISTER:
     622           4 :                 bfdd_client_register(msg);
     623           4 :                 break;
     624           0 :         case ZEBRA_BFD_CLIENT_DEREGISTER:
     625           0 :                 bfdd_client_deregister(msg);
     626           0 :                 break;
     627             : 
     628           0 :         default:
     629           0 :                 if (bglobal.debug_zebra)
     630           0 :                         zlog_debug("ptm-replay: invalid message type %u", rcmd);
     631             :                 return -1;
     632             :         }
     633             : 
     634             :         return 0;
     635             : 
     636           0 : stream_failure:
     637           0 :         zlog_err("ptm-replay: failed to find command");
     638           0 :         return -1;
     639             : }
     640             : 
     641           4 : static void bfdd_zebra_connected(struct zclient *zc)
     642             : {
     643           4 :         struct stream *msg = zc->obuf;
     644             : 
     645             :         /* Clean-up and free ptm clients data memory. */
     646           4 :         pc_free_all();
     647             : 
     648             :         /*
     649             :          * The replay is an empty message just to trigger client daemons
     650             :          * configuration replay.
     651             :          */
     652           4 :         stream_reset(msg);
     653           4 :         zclient_create_header(msg, ZEBRA_BFD_DEST_REPLAY, VRF_DEFAULT);
     654           4 :         stream_putl(msg, ZEBRA_BFD_DEST_REPLAY);
     655           4 :         stream_putw_at(msg, 0, stream_get_endp(msg));
     656             : 
     657             :         /* Ask for interfaces information. */
     658           4 :         zclient_create_header(msg, ZEBRA_INTERFACE_ADD, VRF_DEFAULT);
     659             : 
     660             :         /* Send requests. */
     661           4 :         zclient_send_message(zclient);
     662           4 : }
     663             : 
     664          24 : static void bfdd_sessions_enable_interface(struct interface *ifp)
     665             : {
     666          24 :         struct bfd_session_observer *bso;
     667          24 :         struct bfd_session *bs;
     668          24 :         struct vrf *vrf;
     669             : 
     670          24 :         vrf = ifp->vrf;
     671             : 
     672          24 :         TAILQ_FOREACH(bso, &bglobal.bg_obslist, bso_entry) {
     673           0 :                 bs = bso->bso_bs;
     674             :                 /* check vrf name */
     675           0 :                 if (bs->key.vrfname[0] &&
     676           0 :                     strcmp(vrf->name, bs->key.vrfname))
     677           0 :                         continue;
     678             : 
     679             :                 /* If Interface matches vrfname, then bypass iface check */
     680           0 :                 if (vrf_is_backend_netns() || strcmp(ifp->name, vrf->name)) {
     681             :                         /* Interface name mismatch. */
     682           0 :                         if (bs->key.ifname[0] &&
     683           0 :                             strcmp(ifp->name, bs->key.ifname))
     684           0 :                                 continue;
     685             :                 }
     686             : 
     687             :                 /* Skip enabled sessions. */
     688           0 :                 if (bs->sock != -1)
     689           0 :                         continue;
     690             : 
     691             :                 /* Try to enable it. */
     692           0 :                 bfd_session_enable(bs);
     693             :         }
     694          24 : }
     695             : 
     696           4 : static void bfdd_sessions_disable_interface(struct interface *ifp)
     697             : {
     698           4 :         struct bfd_session_observer *bso;
     699           4 :         struct bfd_session *bs;
     700             : 
     701           7 :         TAILQ_FOREACH(bso, &bglobal.bg_obslist, bso_entry) {
     702           3 :                 bs = bso->bso_bs;
     703             : 
     704           3 :                 if (bs->ifp != ifp)
     705           3 :                         continue;
     706             : 
     707             :                 /* Skip disabled sessions. */
     708           0 :                 if (bs->sock == -1) {
     709           0 :                         bs->ifp = NULL;
     710           0 :                         continue;
     711             :                 }
     712             : 
     713           0 :                 bfd_session_disable(bs);
     714           0 :                 bs->ifp = NULL;
     715             :         }
     716           4 : }
     717             : 
     718           0 : void bfdd_sessions_enable_vrf(struct vrf *vrf)
     719             : {
     720           0 :         struct bfd_session_observer *bso;
     721           0 :         struct bfd_session *bs;
     722             : 
     723             :         /* it may affect configs without interfaces */
     724           0 :         TAILQ_FOREACH(bso, &bglobal.bg_obslist, bso_entry) {
     725           0 :                 bs = bso->bso_bs;
     726           0 :                 if (bs->vrf)
     727           0 :                         continue;
     728           0 :                 if (bs->key.vrfname[0] &&
     729           0 :                     strcmp(vrf->name, bs->key.vrfname))
     730           0 :                         continue;
     731             :                 /* need to update the vrf information on
     732             :                  * bs so that callbacks are handled
     733             :                  */
     734           0 :                 bs->vrf = vrf;
     735             :                 /* Skip enabled sessions. */
     736           0 :                 if (bs->sock != -1)
     737           0 :                         continue;
     738             :                 /* Try to enable it. */
     739           0 :                 bfd_session_enable(bs);
     740             :         }
     741           0 : }
     742             : 
     743           0 : void bfdd_sessions_disable_vrf(struct vrf *vrf)
     744             : {
     745           0 :         struct bfd_session_observer *bso;
     746           0 :         struct bfd_session *bs;
     747             : 
     748           0 :         TAILQ_FOREACH(bso, &bglobal.bg_obslist, bso_entry) {
     749           0 :                 bs = bso->bso_bs;
     750           0 :                 if (bs->key.vrfname[0] &&
     751           0 :                     strcmp(vrf->name, bs->key.vrfname))
     752           0 :                         continue;
     753             :                 /* Skip disabled sessions. */
     754           0 :                 if (bs->sock == -1)
     755           0 :                         continue;
     756             : 
     757           0 :                 bfd_session_disable(bs);
     758           0 :                 bs->vrf = NULL;
     759             :         }
     760           0 : }
     761             : 
     762           4 : static int bfd_ifp_destroy(struct interface *ifp)
     763             : {
     764           4 :         if (bglobal.debug_zebra)
     765           0 :                 zlog_debug("zclient: delete interface %s (VRF %s(%u))",
     766             :                            ifp->name, ifp->vrf->name, ifp->vrf->vrf_id);
     767             : 
     768           4 :         bfdd_sessions_disable_interface(ifp);
     769             : 
     770           4 :         return 0;
     771             : }
     772             : 
     773           0 : static int bfdd_interface_vrf_update(ZAPI_CALLBACK_ARGS)
     774             : {
     775           0 :         struct interface *ifp;
     776           0 :         vrf_id_t nvrfid;
     777             : 
     778           0 :         ifp = zebra_interface_vrf_update_read(zclient->ibuf, vrf_id, &nvrfid);
     779           0 :         if (ifp == NULL)
     780             :                 return 0;
     781             : 
     782           0 :         if_update_to_new_vrf(ifp, nvrfid);
     783             : 
     784           0 :         return 0;
     785             : }
     786             : 
     787          42 : static void bfdd_sessions_enable_address(struct connected *ifc)
     788             : {
     789          42 :         struct bfd_session_observer *bso;
     790          42 :         struct bfd_session *bs;
     791          42 :         struct prefix prefix;
     792             : 
     793          46 :         TAILQ_FOREACH(bso, &bglobal.bg_obslist, bso_entry) {
     794             :                 /* Skip enabled sessions. */
     795           4 :                 bs = bso->bso_bs;
     796           4 :                 if (bs->sock != -1)
     797           4 :                         continue;
     798             : 
     799             :                 /* Check address. */
     800           0 :                 prefix = bso->bso_addr;
     801           0 :                 prefix.prefixlen = ifc->address->prefixlen;
     802           0 :                 if (prefix_cmp(&prefix, ifc->address))
     803           0 :                         continue;
     804             : 
     805             :                 /* Try to enable it. */
     806           0 :                 bfd_session_enable(bs);
     807             :         }
     808          42 : }
     809             : 
     810          50 : static int bfdd_interface_address_update(ZAPI_CALLBACK_ARGS)
     811             : {
     812          50 :         struct connected *ifc;
     813             : 
     814          50 :         ifc = zebra_interface_address_read(cmd, zclient->ibuf, vrf_id);
     815          50 :         if (ifc == NULL)
     816             :                 return 0;
     817             : 
     818          50 :         if (bglobal.debug_zebra)
     819           0 :                 zlog_debug("zclient: %s local address %pFX (VRF %u)",
     820             :                            cmd == ZEBRA_INTERFACE_ADDRESS_ADD ? "add"
     821             :                                                               : "delete",
     822             :                            ifc->address, vrf_id);
     823             : 
     824          50 :         if (cmd == ZEBRA_INTERFACE_ADDRESS_ADD)
     825          42 :                 bfdd_sessions_enable_address(ifc);
     826             :         else
     827           8 :                 connected_free(&ifc);
     828             : 
     829             :         return 0;
     830             : }
     831             : 
     832          24 : static int bfd_ifp_create(struct interface *ifp)
     833             : {
     834          24 :         if (bglobal.debug_zebra)
     835           0 :                 zlog_debug("zclient: add interface %s (VRF %s(%u))", ifp->name,
     836             :                            ifp->vrf->name, ifp->vrf->vrf_id);
     837          24 :         bfdd_sessions_enable_interface(ifp);
     838             : 
     839          24 :         return 0;
     840             : }
     841             : 
     842             : static zclient_handler *const bfd_handlers[] = {
     843             :         /*
     844             :          * We'll receive all messages through replay, however it will
     845             :          * contain a special field with the real command inside so we
     846             :          * avoid having to create too many handlers.
     847             :          */
     848             :         [ZEBRA_BFD_DEST_REPLAY] = bfdd_replay,
     849             : 
     850             :         /* Learn about interface VRF. */
     851             :         [ZEBRA_INTERFACE_VRF_UPDATE] = bfdd_interface_vrf_update,
     852             : 
     853             :         /* Learn about new addresses being registered. */
     854             :         [ZEBRA_INTERFACE_ADDRESS_ADD] = bfdd_interface_address_update,
     855             :         [ZEBRA_INTERFACE_ADDRESS_DELETE] = bfdd_interface_address_update,
     856             : };
     857             : 
     858           4 : void bfdd_zclient_init(struct zebra_privs_t *bfdd_priv)
     859             : {
     860           4 :         if_zapi_callbacks(bfd_ifp_create, NULL, NULL, bfd_ifp_destroy);
     861           4 :         zclient = zclient_new(master, &zclient_options_default, bfd_handlers,
     862             :                               array_size(bfd_handlers));
     863           4 :         assert(zclient != NULL);
     864           4 :         zclient_init(zclient, ZEBRA_ROUTE_BFD, 0, bfdd_priv);
     865             : 
     866             :         /* Send replay request on zebra connect. */
     867           4 :         zclient->zebra_connected = bfdd_zebra_connected;
     868           4 : }
     869             : 
     870           0 : void bfdd_zclient_register(vrf_id_t vrf_id)
     871             : {
     872           0 :         if (!zclient || zclient->sock < 0)
     873             :                 return;
     874           0 :         zclient_send_reg_requests(zclient, vrf_id);
     875             : }
     876             : 
     877           0 : void bfdd_zclient_unregister(vrf_id_t vrf_id)
     878             : {
     879           0 :         if (!zclient || zclient->sock < 0)
     880             :                 return;
     881           0 :         zclient_send_dereg_requests(zclient, vrf_id);
     882             : }
     883             : 
     884           4 : void bfdd_zclient_stop(void)
     885             : {
     886           4 :         zclient_stop(zclient);
     887             : 
     888             :         /* Clean-up and free ptm clients data memory. */
     889           4 :         pc_free_all();
     890           4 : }
     891             : 
     892             : 
     893             : /*
     894             :  * Client handling.
     895             :  */
     896          17 : static struct ptm_client *pc_lookup(uint32_t pid)
     897             : {
     898          17 :         struct ptm_client *pc;
     899             : 
     900          17 :         TAILQ_FOREACH (pc, &pcqueue, pc_entry) {
     901          13 :                 if (pc->pc_pid != pid)
     902           0 :                         continue;
     903             : 
     904             :                 break;
     905             :         }
     906             : 
     907           0 :         return pc;
     908             : }
     909             : 
     910          17 : static struct ptm_client *pc_new(uint32_t pid)
     911             : {
     912          17 :         struct ptm_client *pc;
     913             : 
     914             :         /* Look up first, if not found create the client. */
     915          17 :         pc = pc_lookup(pid);
     916          17 :         if (pc != NULL)
     917             :                 return pc;
     918             : 
     919             :         /* Allocate the client data and save it. */
     920           4 :         pc = XCALLOC(MTYPE_BFDD_CONTROL, sizeof(*pc));
     921             : 
     922           4 :         pc->pc_pid = pid;
     923           4 :         TAILQ_INSERT_HEAD(&pcqueue, pc, pc_entry);
     924           4 :         return pc;
     925             : }
     926             : 
     927           4 : static void pc_free(struct ptm_client *pc)
     928             : {
     929           4 :         struct ptm_client_notification *pcn;
     930             : 
     931           4 :         TAILQ_REMOVE(&pcqueue, pc, pc_entry);
     932             : 
     933           7 :         while (!TAILQ_EMPTY(&pc->pc_pcnqueue)) {
     934           3 :                 pcn = TAILQ_FIRST(&pc->pc_pcnqueue);
     935           3 :                 pcn_free(pcn);
     936             :         }
     937             : 
     938           4 :         XFREE(MTYPE_BFDD_CONTROL, pc);
     939           4 : }
     940             : 
     941           8 : static void pc_free_all(void)
     942             : {
     943           8 :         struct ptm_client *pc;
     944             : 
     945          12 :         while (!TAILQ_EMPTY(&pcqueue)) {
     946           4 :                 pc = TAILQ_FIRST(&pcqueue);
     947           4 :                 pc_free(pc);
     948             :         }
     949           8 : }
     950             : 
     951           8 : static struct ptm_client_notification *pcn_new(struct ptm_client *pc,
     952             :                                                struct bfd_session *bs)
     953             : {
     954           8 :         struct ptm_client_notification *pcn;
     955             : 
     956             :         /* Try to find an existing pcn fist. */
     957          16 :         pcn = pcn_lookup(pc, bs);
     958           8 :         if (pcn != NULL)
     959             :                 return pcn;
     960             : 
     961             :         /* Save the client notification data. */
     962           8 :         pcn = XCALLOC(MTYPE_BFDD_NOTIFICATION, sizeof(*pcn));
     963             : 
     964           8 :         TAILQ_INSERT_HEAD(&pc->pc_pcnqueue, pcn, pcn_entry);
     965           8 :         pcn->pcn_pc = pc;
     966           8 :         pcn->pcn_bs = bs;
     967           8 :         bs->refcount++;
     968             : 
     969           8 :         return pcn;
     970             : }
     971             : 
     972          13 : static struct ptm_client_notification *pcn_lookup(struct ptm_client *pc,
     973             :                                                   struct bfd_session *bs)
     974             : {
     975          13 :         struct ptm_client_notification *pcn;
     976             : 
     977          20 :         TAILQ_FOREACH (pcn, &pc->pc_pcnqueue, pcn_entry) {
     978          12 :                 if (pcn->pcn_bs != bs)
     979           7 :                         continue;
     980             : 
     981             :                 break;
     982             :         }
     983             : 
     984          13 :         return pcn;
     985             : }
     986             : 
     987           8 : static void pcn_free(struct ptm_client_notification *pcn)
     988             : {
     989           8 :         struct ptm_client *pc;
     990           8 :         struct bfd_session *bs;
     991             : 
     992             :         /* Handle session de-registration. */
     993           8 :         bs = pcn->pcn_bs;
     994           8 :         pcn->pcn_bs = NULL;
     995           8 :         bs->refcount--;
     996             : 
     997             :         /* Log modification to users. */
     998           8 :         if (bglobal.debug_zebra)
     999           0 :                 zlog_debug("ptm-del-session: [%s] refcount=%" PRIu64,
    1000             :                            bs_to_string(bs), bs->refcount);
    1001             : 
    1002             :         /* Set session down. */
    1003           8 :         _ptm_bfd_session_del(bs, BD_NEIGHBOR_DOWN);
    1004             : 
    1005             :         /* Handle ptm_client deregistration. */
    1006           8 :         pc = pcn->pcn_pc;
    1007           8 :         pcn->pcn_pc = NULL;
    1008           8 :         TAILQ_REMOVE(&pc->pc_pcnqueue, pcn, pcn_entry);
    1009             : 
    1010           8 :         XFREE(MTYPE_BFDD_NOTIFICATION, pcn);
    1011           8 : }

Generated by: LCOV version v1.16-topotato