]> git.proxmox.com Git - mirror_frr.git/commitdiff
bfdd: don't enable sessions without local-address
authorRafael Zalamena <rzalamena@opensourcerouting.org>
Tue, 12 Mar 2019 00:26:13 +0000 (21:26 -0300)
committerRafael Zalamena <rzalamena@opensourcerouting.org>
Tue, 12 Mar 2019 01:03:29 +0000 (22:03 -0300)
When the local-address configured by the peer doesn't exist, then we
must observe the session until the mentioned address comes up.

Signed-off-by: Rafael Zalamena <rzalamena@opensourcerouting.org>
bfdd/bfd.c
bfdd/bfd.h
bfdd/bfdd_vty.c
bfdd/ptm_adapter.c

index ea059cc1c25fb6602664566e87035430602ce351..c8adf82a83140e30c136fbdfbb1bd1ed1c520dfa 100644 (file)
@@ -162,6 +162,13 @@ int bfd_session_enable(struct bfd_session *bs)
            && BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH) == 0)
                bs->ifp = ifp;
 
+       /* Sanity check: don't leak open sockets. */
+       if (bs->sock != -1) {
+               zlog_debug("session-enable: previous socket open");
+               close(bs->sock);
+               bs->sock = -1;
+       }
+
        /*
         * Get socket for transmitting control packets.  Note that if we
         * could use the destination port (3784) for the source
@@ -170,11 +177,11 @@ int bfd_session_enable(struct bfd_session *bs)
        if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_IPV6) == 0) {
                psock = bp_peer_socket(bs);
                if (psock == -1)
-                       return -1;
+                       return 0;
        } else {
                psock = bp_peer_socketv6(bs);
                if (psock == -1)
-                       return -1;
+                       return 0;
        }
 
        /*
@@ -662,10 +669,6 @@ struct bfd_session *ptm_bfd_sess_new(struct bfd_peer_cfg *bpc)
                strlcpy(bfd->key.vrfname, bpc->bpc_vrfname,
                        sizeof(bfd->key.vrfname));
 
-       /* Add observer if we have moving parts. */
-       if (bfd->key.ifname[0] || bfd->key.vrfname[0])
-               bs_observer_add(bfd);
-
        /* Copy remaining data. */
        if (bpc->bpc_ipv4 == false)
                BFD_SET_FLAG(bfd->flags, BFD_SESS_FLAG_IPV6);
@@ -708,6 +711,10 @@ struct bfd_session *ptm_bfd_sess_new(struct bfd_peer_cfg *bpc)
                return NULL;
        }
 
+       /* Add observer if we have moving parts. */
+       if (bfd->key.ifname[0] || bfd->key.vrfname[0] || bfd->sock == -1)
+               bs_observer_add(bfd);
+
        /* Apply other configurations. */
        _bfd_session_update(bfd, bpc);
 
@@ -1190,6 +1197,14 @@ int bs_observer_add(struct bfd_session *bs)
                strlcpy(bso->bso_entryname, bs->key.vrfname,
                        sizeof(bso->bso_entryname));
 
+       /* Handle socket binding failures caused by missing local addresses. */
+       if (bs->sock == -1) {
+               bso->bso_isaddress = true;
+               bso->bso_addr.family = bs->key.family;
+               memcpy(&bso->bso_addr.u.prefix, &bs->key.local,
+                      sizeof(bs->key.local));
+       }
+
        TAILQ_INSERT_TAIL(&bglobal.bg_obslist, bso, bso_entry);
 
        return 0;
index 15560122965d5cb07dde5c2b5dab5b300af1bcc8..a69ff9a1a7b9a33b7756d6ef6305a125904220d2 100644 (file)
@@ -274,7 +274,11 @@ struct bfd_state_str_list {
 struct bfd_session_observer {
        struct bfd_session *bso_bs;
        bool bso_isinterface;
-       char bso_entryname[MAXNAMELEN];
+       bool bso_isaddress;
+       union {
+               char bso_entryname[MAXNAMELEN];
+               struct prefix bso_addr;
+       };
 
        TAILQ_ENTRY(bfd_session_observer) bso_entry;
 };
index f4f38c7f1d4180e426965a4b49235ce45838dfe0..c13949207642fe1e81673269291b48a957afda2f 100644 (file)
@@ -942,7 +942,8 @@ static void _bfdd_peer_write_config(struct vty *vty, struct bfd_session *bs)
        vty_out(vty, "\n");
 
        if (bs->sock == -1)
-               vty_out(vty, "  ! vrf or interface doesn't exist\n");
+               vty_out(vty,
+                       "  ! vrf, interface or local-address doesn't exist\n");
 
        if (bs->detect_mult != BPC_DEF_DETECTMULTIPLIER)
                vty_out(vty, "  detect-multiplier %d\n", bs->detect_mult);
index d85bd2670501bbc1480b0cc9d94bb4dd0d726512..b44d13f132a34b67df5216cccc19b8d3e587a4ab 100644 (file)
@@ -634,6 +634,48 @@ static int bfdd_interface_vrf_update(int command __attribute__((__unused__)),
        return 0;
 }
 
+static void bfdd_sessions_enable_address(struct connected *ifc)
+{
+       struct bfd_session_observer *bso;
+       struct bfd_session *bs;
+       struct prefix prefix;
+
+       TAILQ_FOREACH(bso, &bglobal.bg_obslist, bso_entry) {
+               if (bso->bso_isaddress == false)
+                       continue;
+
+               /* Skip enabled sessions. */
+               bs = bso->bso_bs;
+               if (bs->sock != -1)
+                       continue;
+
+               /* Check address. */
+               prefix = bso->bso_addr;
+               prefix.prefixlen = ifc->address->prefixlen;
+               if (prefix_cmp(&prefix, ifc->address))
+                       continue;
+
+               /* Try to enable it. */
+               bfd_session_enable(bs);
+       }
+}
+
+static int bfdd_interface_address_update(int cmd, struct zclient *zc,
+                                        zebra_size_t len
+                                        __attribute__((__unused__)),
+                                        vrf_id_t vrfid)
+{
+       struct connected *ifc;
+
+       ifc = zebra_interface_address_read(cmd, zc->ibuf, vrfid);
+       if (ifc == NULL)
+               return 0;
+
+       bfdd_sessions_enable_address(ifc);
+
+       return 0;
+}
+
 void bfdd_zclient_init(struct zebra_privs_t *bfdd_priv)
 {
        zclient = zclient_new(master, &zclient_options_default);
@@ -656,6 +698,10 @@ void bfdd_zclient_init(struct zebra_privs_t *bfdd_priv)
 
        /* Learn about interface VRF. */
        zclient->interface_vrf_update = bfdd_interface_vrf_update;
+
+       /* Learn about new addresses being registered. */
+       zclient->interface_address_add = bfdd_interface_address_update;
+       zclient->interface_address_delete = bfdd_interface_address_update;
 }
 
 void bfdd_zclient_stop(void)