&& 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
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;
}
/*
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);
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);
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;
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;
};
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);
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);
/* 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)