]> git.proxmox.com Git - mirror_frr.git/blobdiff - bfdd/bfd.c
Merge pull request #3403 from opensourcerouting/bfd-fix-mhop-bsd
[mirror_frr.git] / bfdd / bfd.c
index 8592f6e3cb828646b7bdf67fd9b7e9e72c851889..814366f32060ad19735d537f04facd616000464d 100644 (file)
 
 #include <zebra.h>
 
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <sys/uio.h>
-#include <netinet/in.h>
-#include <net/if.h>
-#include <arpa/inet.h>
-#include <sys/ioctl.h>
-
-#include <err.h>
-#include <errno.h>
-#include <stdio.h>
-#include <stdbool.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <netdb.h>
-#include <time.h>
-#include <signal.h>
-
-#include "lib/hash.h"
 #include "lib/jhash.h"
 
 #include "bfd.h"
@@ -97,7 +78,7 @@ struct bfd_session *bs_peer_find(struct bfd_peer_cfg *bpc)
        } else {
                memset(&shop, 0, sizeof(shop));
                shop.peer = bpc->bpc_peer;
-               if (!bpc->bpc_has_vxlan && bpc->bpc_has_localif)
+               if (bpc->bpc_has_localif)
                        strlcpy(shop.port_name, bpc->bpc_localif,
                                sizeof(shop.port_name));
 
@@ -176,7 +157,8 @@ void ptm_bfd_echo_stop(struct bfd_session *bfd, int polling)
 void ptm_bfd_echo_start(struct bfd_session *bfd)
 {
        bfd->echo_detect_TO = (bfd->remote_detect_mult * bfd->echo_xmt_TO);
-       ptm_bfd_echo_xmt_TO(bfd);
+       if (bfd->echo_detect_TO > 0)
+               ptm_bfd_echo_xmt_TO(bfd);
 
        bfd->polling = 1;
        bfd->new_timers.desired_min_tx = bfd->up_min_tx;
@@ -186,6 +168,8 @@ void ptm_bfd_echo_start(struct bfd_session *bfd)
 
 void ptm_bfd_ses_up(struct bfd_session *bfd)
 {
+       int old_state = bfd->ses_state;
+
        bfd->local_diag = 0;
        bfd->ses_state = PTM_BFD_UP;
        bfd->polling = 1;
@@ -202,8 +186,12 @@ void ptm_bfd_ses_up(struct bfd_session *bfd)
 
        control_notify(bfd);
 
-       INFOLOG("Session 0x%x up peer %s", bfd->discrs.my_discr,
-               satostr(&bfd->shop.peer));
+       if (old_state != bfd->ses_state) {
+               bfd->stats.session_up++;
+               log_info("state-change: [%s] %s -> %s", bs_to_string(bfd),
+                        state_list[old_state].str,
+                        state_list[bfd->ses_state].str);
+       }
 }
 
 void ptm_bfd_ses_dn(struct bfd_session *bfd, uint8_t diag)
@@ -223,13 +211,17 @@ void ptm_bfd_ses_dn(struct bfd_session *bfd, uint8_t diag)
        if (old_state == PTM_BFD_UP)
                control_notify(bfd);
 
-       INFOLOG("Session 0x%x down peer %s Rsn %s prev st %s",
-               bfd->discrs.my_discr, satostr(&bfd->shop.peer),
-               get_diag_str(bfd->local_diag), state_list[old_state].str);
-
        /* Stop echo packet transmission if they are active */
        if (BFD_CHECK_FLAG(bfd->flags, BFD_SESS_FLAG_ECHO_ACTIVE))
                ptm_bfd_echo_stop(bfd, 0);
+
+       if (old_state != bfd->ses_state) {
+               bfd->stats.session_down++;
+               log_info("state-change: [%s] %s -> %s reason:%s",
+                        bs_to_string(bfd), state_list[old_state].str,
+                        state_list[bfd->ses_state].str,
+                        get_diag_str(bfd->local_diag));
+       }
 }
 
 static int ptm_bfd_get_vrf_name(char *port_name, char *vrf_name)
@@ -301,7 +293,8 @@ struct bfd_session *ptm_bfd_sess_find(struct bfd_pkt *cp, char *port_name,
                } else if (port_name && port_name[0]) {
                        memset(vrf_buf, 0, sizeof(vrf_buf));
                        if (ptm_bfd_get_vrf_name(port_name, vrf_buf) != -1)
-                               strlcpy(mhop.vrf_name, vrf_buf, sizeof(mhop.vrf_name));
+                               strlcpy(mhop.vrf_name, vrf_buf,
+                                       sizeof(mhop.vrf_name));
                }
 
                l_bfd = bfd_mhop_lookup(mhop);
@@ -309,7 +302,8 @@ struct bfd_session *ptm_bfd_sess_find(struct bfd_pkt *cp, char *port_name,
                memset(&shop, 0, sizeof(shop));
                shop.peer = *peer;
                if (port_name && port_name[0])
-                       strlcpy(shop.port_name, port_name, sizeof(shop.port_name));
+                       strlcpy(shop.port_name, port_name,
+                               sizeof(shop.port_name));
 
                l_bfd = bfd_shop_lookup(shop);
        }
@@ -318,33 +312,6 @@ struct bfd_session *ptm_bfd_sess_find(struct bfd_pkt *cp, char *port_name,
        return l_bfd;
 }
 
-#if 0  /* TODO VxLAN Support */
-static void
-_update_vxlan_sess_parms(struct bfd_session *bfd, bfd_sess_parms *sess_parms)
-{
-       struct bfd_session_vxlan_info *vxlan_info = &bfd->vxlan_info;
-       bfd_parms_list *parms = &sess_parms->parms;
-
-       vxlan_info->vnid = parms->vnid;
-       vxlan_info->check_tnl_key = parms->check_tnl_key;
-       vxlan_info->forwarding_if_rx = parms->forwarding_if_rx;
-       vxlan_info->cpath_down = parms->cpath_down;
-       vxlan_info->decay_min_rx = parms->decay_min_rx;
-
-       inet_aton(parms->local_dst_ip, &vxlan_info->local_dst_ip);
-       inet_aton(parms->remote_dst_ip, &vxlan_info->peer_dst_ip);
-
-       memcpy(vxlan_info->local_dst_mac, parms->local_dst_mac, ETH_ALEN);
-       memcpy(vxlan_info->peer_dst_mac, parms->remote_dst_mac, ETH_ALEN);
-
-       /* The interface may change for Vxlan BFD sessions, so update
-        * the local mac and ifindex
-        */
-       bfd->ifindex = sess_parms->ifindex;
-       memcpy(bfd->local_mac, sess_parms->local_mac, sizeof(bfd->local_mac));
-}
-#endif /* VxLAN support */
-
 int bfd_xmt_cb(struct thread *t)
 {
        struct bfd_session *bs = THREAD_ARG(t);
@@ -358,7 +325,8 @@ int bfd_echo_xmt_cb(struct thread *t)
 {
        struct bfd_session *bs = THREAD_ARG(t);
 
-       ptm_bfd_echo_xmt_TO(bs);
+       if (bs->echo_xmt_TO > 0)
+               ptm_bfd_echo_xmt_TO(bs);
 
        return 0;
 }
@@ -367,17 +335,11 @@ int bfd_echo_xmt_cb(struct thread *t)
 int bfd_recvtimer_cb(struct thread *t)
 {
        struct bfd_session *bs = THREAD_ARG(t);
-       uint8_t old_state;
-
-       old_state = bs->ses_state;
 
        switch (bs->ses_state) {
        case PTM_BFD_INIT:
        case PTM_BFD_UP:
-               ptm_bfd_ses_dn(bs, BFD_DIAGDETECTTIME);
-               INFOLOG("%s Detect timeout on session 0x%x with peer %s, in state %d",
-                       __func__, bs->discrs.my_discr, satostr(&bs->shop.peer),
-                       bs->ses_state);
+               ptm_bfd_ses_dn(bs, BD_CONTROL_EXPIRED);
                bfd_recvtimer_update(bs);
                break;
 
@@ -389,12 +351,6 @@ int bfd_recvtimer_cb(struct thread *t)
                break;
        }
 
-       if (old_state != bs->ses_state) {
-               DLOG("BFD Sess %d [%s] Old State [%s] : New State [%s]",
-                    bs->discrs.my_discr, satostr(&bs->shop.peer),
-                    state_list[old_state].str, state_list[bs->ses_state].str);
-       }
-
        return 0;
 }
 
@@ -402,26 +358,14 @@ int bfd_recvtimer_cb(struct thread *t)
 int bfd_echo_recvtimer_cb(struct thread *t)
 {
        struct bfd_session *bs = THREAD_ARG(t);
-       uint8_t old_state;
-
-       old_state = bs->ses_state;
 
        switch (bs->ses_state) {
        case PTM_BFD_INIT:
        case PTM_BFD_UP:
-               ptm_bfd_ses_dn(bs, BFD_DIAGDETECTTIME);
-               INFOLOG("%s Detect timeout on session 0x%x with peer %s, in state %d",
-                       __func__, bs->discrs.my_discr, satostr(&bs->shop.peer),
-                       bs->ses_state);
+               ptm_bfd_ses_dn(bs, BD_ECHO_FAILED);
                break;
        }
 
-       if (old_state != bs->ses_state) {
-               DLOG("BFD Sess %d [%s] Old State [%s] : New State [%s]",
-                    bs->discrs.my_discr, satostr(&bs->shop.peer),
-                    state_list[old_state].str, state_list[bs->ses_state].str);
-       }
-
        return 0;
 }
 
@@ -566,8 +510,6 @@ static int bfd_session_update(struct bfd_session *bs, struct bfd_peer_cfg *bpc)
 
        _bfd_session_update(bs, bpc);
 
-       /* TODO add VxLAN support. */
-
        control_notify_config(BCM_NOTIFY_CONFIG_UPDATE, bs);
 
        return 0;
@@ -617,25 +559,18 @@ struct bfd_session *ptm_bfd_sess_new(struct bfd_peer_cfg *bpc)
         */
        if (bpc->bpc_ipv4) {
                psock = bp_peer_socket(bpc);
-               if (psock == -1) {
-                       ERRLOG("Can't get socket for new session: %s",
-                              strerror(errno));
+               if (psock == -1)
                        return NULL;
-               }
        } else {
                psock = bp_peer_socketv6(bpc);
-               if (psock == -1) {
-                       ERRLOG("Can't get IPv6 socket for new session: %s",
-                              strerror(errno));
+               if (psock == -1)
                        return NULL;
-               }
        }
 
        /* Get memory */
        bfd = bfd_session_new(psock);
        if (bfd == NULL) {
-               ERRLOG("Can't malloc memory for new session: %s",
-                      strerror(errno));
+               log_error("session-new: allocation failed");
                return NULL;
        }
 
@@ -644,12 +579,16 @@ struct bfd_session *ptm_bfd_sess_new(struct bfd_peer_cfg *bpc)
                ptm_bfd_fetch_local_mac(bpc->bpc_localif, bfd->local_mac);
        }
 
-       if (bpc->bpc_has_vxlan)
-               BFD_SET_FLAG(bfd->flags, BFD_SESS_FLAG_VXLAN);
-
-       if (bpc->bpc_ipv4 == false)
+       if (bpc->bpc_ipv4 == false) {
                BFD_SET_FLAG(bfd->flags, BFD_SESS_FLAG_IPV6);
 
+               /* Set the IPv6 scope id for link-local addresses. */
+               if (IN6_IS_ADDR_LINKLOCAL(&bpc->bpc_local.sa_sin6.sin6_addr))
+                       bpc->bpc_local.sa_sin6.sin6_scope_id = bfd->ifindex;
+               if (IN6_IS_ADDR_LINKLOCAL(&bpc->bpc_peer.sa_sin6.sin6_addr))
+                       bpc->bpc_peer.sa_sin6.sin6_scope_id = bfd->ifindex;
+       }
+
        /* Initialize the session */
        bfd->ses_state = PTM_BFD_DOWN;
        bfd->discrs.my_discr = ptm_bfd_gen_ID();
@@ -675,30 +614,13 @@ struct bfd_session *ptm_bfd_sess_new(struct bfd_peer_cfg *bpc)
                bfd_mhop_insert(bfd);
        } else {
                bfd->shop.peer = bpc->bpc_peer;
-               if (!bpc->bpc_has_vxlan && bpc->bpc_has_localif)
+               if (bpc->bpc_has_localif)
                        strlcpy(bfd->shop.port_name, bpc->bpc_localif,
                                sizeof(bfd->shop.port_name));
 
                bfd_shop_insert(bfd);
        }
 
-       if (BFD_CHECK_FLAG(bfd->flags, BFD_SESS_FLAG_VXLAN)) {
-               static uint8_t bfd_def_vxlan_dmac[] = {0x00, 0x23, 0x20,
-                                                      0x00, 0x00, 0x01};
-               memcpy(bfd->peer_mac, bfd_def_vxlan_dmac,
-                      sizeof(bfd_def_vxlan_dmac));
-       }
-#if 0 /* TODO */
-       else if (event->rmac) {
-               if (sscanf(event->rmac, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx",
-                   &bfd->peer_mac[0], &bfd->peer_mac[1], &bfd->peer_mac[2],
-                   &bfd->peer_mac[3], &bfd->peer_mac[4], &bfd->peer_mac[5])
-                   != 6)
-                       DLOG("%s: Assigning remote mac = %s", __func__,
-                            event->rmac);
-       }
-#endif
-
        /*
         * XXX: session update triggers echo start, so we must have our
         * discriminator ID set first.
@@ -710,16 +632,7 @@ struct bfd_session *ptm_bfd_sess_new(struct bfd_peer_cfg *bpc)
 
        ptm_bfd_xmt_TO(bfd, 0);
 
-       if (bpc->bpc_mhop) {
-               INFOLOG("Created new session 0x%x with vrf %s peer %s local %s",
-                       bfd->discrs.my_discr,
-                       (bpc->bpc_has_vrfname) ? bfd->mhop.vrf_name : "N/A",
-                       satostr(&bfd->mhop.peer), satostr(&bfd->mhop.local));
-       } else {
-               INFOLOG("Created new session 0x%x with peer %s port %s",
-                       bfd->discrs.my_discr, satostr(&bfd->shop.peer),
-                       bfd->shop.port_name[0] ? bfd->shop.port_name : "N/A");
-       }
+       log_info("session-new: %s", bs_to_string(bfd));
 
        control_notify_config(BCM_NOTIFY_CONFIG_ADD, bfd);
 
@@ -737,22 +650,13 @@ int ptm_bfd_ses_del(struct bfd_peer_cfg *bpc)
 
        /* This pointer is being referenced, don't let it be deleted. */
        if (bs->refcount > 0) {
-               zlog_debug("%s: trying to free in-use session: %" PRIu64
-                          " references",
-                          __func__, bs->refcount);
+               log_error("session-delete: refcount failure: %" PRIu64
+                         " references",
+                         bs->refcount);
                return -1;
        }
 
-       if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH)) {
-               INFOLOG("Deleting session 0x%x with vrf %s peer %s local %s",
-                       bs->discrs.my_discr,
-                       bpc->bpc_has_vrfname ? bpc->bpc_vrfname : "N/A",
-                       satostr(&bs->mhop.peer), satostr(&bs->mhop.local));
-       } else {
-               INFOLOG("Deleting session 0x%x with peer %s port %s",
-                       bs->discrs.my_discr, satostr(&bs->shop.peer),
-                       bs->shop.port_name);
-       }
+       log_info("session-delete: %s", bs_to_string(bs));
 
        control_notify_config(BCM_NOTIFY_CONFIG_DELETE, bs);
 
@@ -914,6 +818,38 @@ void integer2timestr(uint64_t time, char *buf, size_t buflen)
        snprintf(buf, buflen, "%u second(s)", second);
 }
 
+const char *bs_to_string(struct bfd_session *bs)
+{
+       static char buf[256];
+       int pos;
+       bool is_mhop = BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH);
+
+       pos = snprintf(buf, sizeof(buf), "mhop:%s", is_mhop ? "yes" : "no");
+       if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH)) {
+               pos += snprintf(buf + pos, sizeof(buf) - pos,
+                               " peer:%s local:%s", satostr(&bs->mhop.peer),
+                               satostr(&bs->mhop.local));
+
+               if (bs->mhop.vrf_name[0])
+                       snprintf(buf + pos, sizeof(buf) - pos, " vrf:%s",
+                                bs->mhop.vrf_name);
+       } else {
+               pos += snprintf(buf + pos, sizeof(buf) - pos, " peer:%s",
+                               satostr(&bs->shop.peer));
+
+               if (bs->local_address.sa_sin.sin_family)
+                       pos += snprintf(buf + pos, sizeof(buf) - pos,
+                                       " local:%s",
+                                       satostr(&bs->local_address));
+
+               if (bs->shop.port_name[0])
+                       snprintf(buf + pos, sizeof(buf) - pos, " interface:%s",
+                                bs->shop.port_name);
+       }
+
+       return buf;
+}
+
 
 /*
  * BFD hash data structures to find sessions.
@@ -925,15 +861,10 @@ static struct hash *bfd_vrf_hash;
 static struct hash *bfd_iface_hash;
 
 static unsigned int bfd_id_hash_do(void *p);
-static int bfd_id_hash_cmp(const void *n1, const void *n2);
 static unsigned int bfd_shop_hash_do(void *p);
-static int bfd_shop_hash_cmp(const void *n1, const void *n2);
 static unsigned int bfd_mhop_hash_do(void *p);
-static int bfd_mhop_hash_cmp(const void *n1, const void *n2);
 static unsigned int bfd_vrf_hash_do(void *p);
-static int bfd_vrf_hash_cmp(const void *n1, const void *n2);
 static unsigned int bfd_iface_hash_do(void *p);
-static int bfd_iface_hash_cmp(const void *n1, const void *n2);
 
 static void _shop_key(struct bfd_session *bs, const struct bfd_shop_key *shop);
 static void _shop_key2(struct bfd_session *bs, const struct bfd_shop_key *shop);
@@ -953,7 +884,7 @@ static unsigned int bfd_id_hash_do(void *p)
        return jhash_1word(bs->discrs.my_discr, 0);
 }
 
-static int bfd_id_hash_cmp(const void *n1, const void *n2)
+static bool bfd_id_hash_cmp(const void *n1, const void *n2)
 {
        const struct bfd_session *bs1 = n1, *bs2 = n2;
 
@@ -968,7 +899,7 @@ static unsigned int bfd_shop_hash_do(void *p)
        return jhash(&bs->shop, sizeof(bs->shop), 0);
 }
 
-static int bfd_shop_hash_cmp(const void *n1, const void *n2)
+static bool bfd_shop_hash_cmp(const void *n1, const void *n2)
 {
        const struct bfd_session *bs1 = n1, *bs2 = n2;
 
@@ -983,7 +914,7 @@ static unsigned int bfd_mhop_hash_do(void *p)
        return jhash(&bs->mhop, sizeof(bs->mhop), 0);
 }
 
-static int bfd_mhop_hash_cmp(const void *n1, const void *n2)
+static bool bfd_mhop_hash_cmp(const void *n1, const void *n2)
 {
        const struct bfd_session *bs1 = n1, *bs2 = n2;
 
@@ -998,7 +929,7 @@ static unsigned int bfd_vrf_hash_do(void *p)
        return jhash_1word(vrf->vrf_id, 0);
 }
 
-static int bfd_vrf_hash_cmp(const void *n1, const void *n2)
+static bool bfd_vrf_hash_cmp(const void *n1, const void *n2)
 {
        const struct bfd_vrf *v1 = n1, *v2 = n2;
 
@@ -1013,7 +944,7 @@ static unsigned int bfd_iface_hash_do(void *p)
        return string_hash_make(iface->ifname);
 }
 
-static int bfd_iface_hash_cmp(const void *n1, const void *n2)
+static bool bfd_iface_hash_cmp(const void *n1, const void *n2)
 {
        const struct bfd_iface *i1 = n1, *i2 = n2;
 
@@ -1070,7 +1001,6 @@ static int _iface_key(struct bfd_iface *iface, const char *ifname)
        return 0;
 }
 
-
 /*
  * Hash public interface / exported functions.
  */
@@ -1110,7 +1040,7 @@ struct bfd_session *bfd_mhop_lookup(struct bfd_mhop_key mhop)
 
        _mhop_key(&bs, &mhop);
 
-       return hash_lookup(bfd_shop_hash, &bs);
+       return hash_lookup(bfd_mhop_hash, &bs);
 }
 
 struct bfd_vrf *bfd_vrf_lookup(int vrf_id)