bfdd: don't enable sessions without local-address

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>
This commit is contained in:
Rafael Zalamena 2019-03-11 21:26:13 -03:00
parent 79b4a6fceb
commit 261e0ba94d
4 changed files with 74 additions and 8 deletions

View 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;

View 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;
};

View 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);

View 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)