bfdd: change session lookup data structure

Use simplier data structure key to avoid having to do complex and
error-prone key building (e.g. avoid expecting caller to know IPv6
scope id, interface index, vrf index etc...).

Signed-off-by: Rafael Zalamena <rzalamena@opensourcerouting.org>
This commit is contained in:
Rafael Zalamena 2019-03-11 15:09:15 -03:00
parent 2435b7defe
commit 79b4a6fceb
6 changed files with 340 additions and 533 deletions

View File

@ -36,7 +36,9 @@ DEFINE_QOBJ_TYPE(bfd_session);
/*
* Prototypes
*/
static struct bfd_session *bs_peer_waiting_find(struct bfd_peer_cfg *bpc);
void gen_bfd_key(struct bfd_key *key, struct sockaddr_any *peer,
struct sockaddr_any *local, bool mhop, const char *ifname,
const char *vrfname);
static uint32_t ptm_bfd_gen_ID(void);
static void ptm_bfd_echo_xmt_TO(struct bfd_session *bfd);
@ -52,66 +54,47 @@ static void bs_down_handler(struct bfd_session *bs, int nstate);
static void bs_init_handler(struct bfd_session *bs, int nstate);
static void bs_up_handler(struct bfd_session *bs, int nstate);
/* Zeroed array with the size of an IPv6 address. */
struct in6_addr zero_addr;
/*
* Functions
*/
static struct bfd_session *bs_peer_waiting_find(struct bfd_peer_cfg *bpc)
void gen_bfd_key(struct bfd_key *key, struct sockaddr_any *peer,
struct sockaddr_any *local, bool mhop, const char *ifname,
const char *vrfname)
{
struct bfd_session_observer *bso;
struct bfd_session *bs = NULL;
bool is_shop, is_ipv4;
TAILQ_FOREACH(bso, &bglobal.bg_obslist, bso_entry) {
bs = bso->bso_bs;
is_shop = !BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH);
is_ipv4 = !BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_IPV6);
/* Quick checks first. */
if (is_shop != (!bpc->bpc_mhop))
continue;
if (is_ipv4 != bpc->bpc_ipv4)
continue;
/*
* Slow lookup without hash because we don't have all
* information yet.
*/
if (is_shop) {
if (strcmp(bs->ifname, bpc->bpc_localif))
continue;
if (memcmp(&bs->shop.peer, &bpc->bpc_peer,
sizeof(bs->shop.peer)))
continue;
break;
}
if (strcmp(bs->vrfname, bpc->bpc_vrfname))
continue;
if (memcmp(&bs->mhop.peer, &bpc->bpc_peer,
sizeof(bs->mhop.peer)))
continue;
if (memcmp(&bs->mhop.local, &bpc->bpc_local,
sizeof(bs->mhop.local)))
continue;
memset(key, 0, sizeof(*key));
switch (peer->sa_sin.sin_family) {
case AF_INET:
key->family = AF_INET;
memcpy(&key->peer, &peer->sa_sin.sin_addr,
sizeof(peer->sa_sin.sin_addr));
memcpy(&key->local, &local->sa_sin.sin_addr,
sizeof(local->sa_sin.sin_addr));
break;
case AF_INET6:
key->family = AF_INET6;
memcpy(&key->peer, &peer->sa_sin6.sin6_addr,
sizeof(peer->sa_sin6.sin6_addr));
memcpy(&key->local, &local->sa_sin6.sin6_addr,
sizeof(local->sa_sin6.sin6_addr));
break;
}
if (bso == NULL)
bs = NULL;
return bs;
key->mhop = mhop;
if (ifname && ifname[0])
strlcpy(key->ifname, ifname, sizeof(key->ifname));
if (vrfname && vrfname[0])
strlcpy(key->vrfname, vrfname, sizeof(key->vrfname));
}
struct bfd_session *bs_peer_find(struct bfd_peer_cfg *bpc)
{
struct bfd_session *bs;
struct peer_label *pl;
struct interface *ifp;
struct vrf *vrf;
struct bfd_mhop_key mhop;
struct bfd_shop_key shop;
struct bfd_key key;
/* Try to find label first. */
if (bpc->bpc_has_label) {
@ -123,38 +106,10 @@ struct bfd_session *bs_peer_find(struct bfd_peer_cfg *bpc)
}
/* Otherwise fallback to peer/local hash lookup. */
if (bpc->bpc_mhop) {
memset(&mhop, 0, sizeof(mhop));
mhop.peer = bpc->bpc_peer;
mhop.local = bpc->bpc_local;
if (bpc->bpc_has_vrfname) {
vrf = vrf_lookup_by_name(bpc->bpc_vrfname);
if (vrf == NULL)
return NULL;
gen_bfd_key(&key, &bpc->bpc_peer, &bpc->bpc_local, bpc->bpc_mhop,
bpc->bpc_localif, bpc->bpc_vrfname);
mhop.vrfid = vrf->vrf_id;
}
bs = bfd_mhop_lookup(mhop);
} else {
memset(&shop, 0, sizeof(shop));
shop.peer = bpc->bpc_peer;
if (bpc->bpc_has_localif) {
ifp = if_lookup_by_name_all_vrf(bpc->bpc_localif);
if (ifp == NULL)
return NULL;
shop.ifindex = ifp->ifindex;
}
bs = bfd_shop_lookup(shop);
}
if (bs != NULL)
return bs;
/* Search for entries that are incomplete. */
return bs_peer_waiting_find(bpc);
return bfd_key_lookup(key);
}
/*
@ -165,7 +120,6 @@ struct bfd_session *bs_peer_find(struct bfd_peer_cfg *bpc)
*/
int bfd_session_enable(struct bfd_session *bs)
{
struct sockaddr_in6 *sin6;
struct interface *ifp = NULL;
struct vrf *vrf = NULL;
int psock;
@ -174,8 +128,8 @@ int bfd_session_enable(struct bfd_session *bs)
* If the interface or VRF doesn't exist, then we must register
* the session but delay its start.
*/
if (bs->ifname[0] != 0) {
ifp = if_lookup_by_name_all_vrf(bs->ifname);
if (bs->key.ifname[0]) {
ifp = if_lookup_by_name_all_vrf(bs->key.ifname);
if (ifp == NULL) {
log_error(
"session-enable: specified interface doesn't exists.");
@ -184,15 +138,17 @@ int bfd_session_enable(struct bfd_session *bs)
vrf = vrf_lookup_by_id(ifp->vrf_id);
if (vrf == NULL) {
log_error("session-enable: specified VRF doesn't exists.");
log_error(
"session-enable: specified VRF doesn't exists.");
return 0;
}
}
if (bs->vrfname[0] != 0) {
vrf = vrf_lookup_by_name(bs->vrfname);
if (bs->key.vrfname[0]) {
vrf = vrf_lookup_by_name(bs->key.vrfname);
if (vrf == NULL) {
log_error("session-enable: specified VRF doesn't exists.");
log_error(
"session-enable: specified VRF doesn't exists.");
return 0;
}
}
@ -202,32 +158,10 @@ int bfd_session_enable(struct bfd_session *bs)
if (bs->vrf == NULL)
bs->vrf = vrf_lookup_by_id(VRF_DEFAULT);
if (bs->ifname[0] != 0 &&
BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH) == 0)
if (bs->key.ifname[0]
&& BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH) == 0)
bs->ifp = ifp;
/* Set the IPv6 scope id for link-local addresses. */
if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_IPV6)) {
sin6 = (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH))
? &bs->mhop.peer.sa_sin6
: &bs->shop.peer.sa_sin6;
if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr))
sin6->sin6_scope_id = bs->ifp != NULL
? bs->ifp->ifindex
: IFINDEX_INTERNAL;
sin6 = (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH))
? &bs->mhop.local.sa_sin6
: &bs->local_address.sa_sin6;
if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr))
sin6->sin6_scope_id = bs->ifp != NULL
? bs->ifp->ifindex
: IFINDEX_INTERNAL;
bs->local_ip.sa_sin6 = *sin6;
bs->local_address.sa_sin6 = *sin6;
}
/*
* Get socket for transmitting control packets. Note that if we
* could use the destination port (3784) for the source
@ -251,25 +185,6 @@ int bfd_session_enable(struct bfd_session *bs)
bfd_recvtimer_update(bs);
ptm_bfd_start_xmt_timer(bs, false);
/* Registrate session into data structures. */
bs->discrs.my_discr = ptm_bfd_gen_ID();
bfd_id_insert(bs);
if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH)) {
if (vrf != NULL)
bs->mhop.vrfid = vrf->vrf_id;
else
bs->mhop.vrfid = VRF_DEFAULT;
bfd_mhop_insert(bs);
} else {
if (ifp != NULL)
bs->shop.ifindex = ifp->ifindex;
else
bs->shop.ifindex = IFINDEX_INTERNAL;
bfd_shop_insert(bs);
}
return 0;
}
@ -292,13 +207,6 @@ void bfd_session_disable(struct bfd_session *bs)
bfd_echo_recvtimer_delete(bs);
bfd_xmttimer_delete(bs);
bfd_echo_xmttimer_delete(bs);
/* Unregister session from hashes to avoid unwanted activation. */
bfd_id_delete(bs->discrs.my_discr);
if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH))
bfd_mhop_delete(bs->mhop);
else
bfd_shop_delete(bs->shop);
}
static uint32_t ptm_bfd_gen_ID(void)
@ -442,21 +350,20 @@ static struct bfd_session *bfd_find_disc(struct sockaddr_any *sa,
if (bs == NULL)
return NULL;
/* Remove unused fields. */
switch (sa->sa_sin.sin_family) {
switch (bs->key.family) {
case AF_INET:
sa->sa_sin.sin_port = 0;
if (memcmp(sa, &bs->shop.peer, sizeof(sa->sa_sin)) == 0)
return bs;
if (memcmp(&sa->sa_sin.sin_addr, &bs->key.peer,
sizeof(sa->sa_sin.sin_addr)))
return NULL;
break;
case AF_INET6:
sa->sa_sin6.sin6_port = 0;
if (memcmp(sa, &bs->shop.peer, sizeof(sa->sa_sin6)) == 0)
return bs;
if (memcmp(&sa->sa_sin6.sin6_addr, &bs->key.peer,
sizeof(sa->sa_sin6.sin6_addr)))
return NULL;
break;
}
return NULL;
return bs;
}
struct bfd_session *ptm_bfd_sess_find(struct bfd_pkt *cp,
@ -465,32 +372,30 @@ struct bfd_session *ptm_bfd_sess_find(struct bfd_pkt *cp,
ifindex_t ifindex, vrf_id_t vrfid,
bool is_mhop)
{
struct bfd_session *l_bfd = NULL;
struct bfd_mhop_key mhop;
struct bfd_shop_key shop;
struct interface *ifp;
struct vrf *vrf;
struct bfd_key key;
/* Find our session using the ID signaled by the remote end. */
if (cp->discrs.remote_discr)
return bfd_find_disc(peer, ntohl(cp->discrs.remote_discr));
/* Search for session without using discriminator. */
if (is_mhop) {
memset(&mhop, 0, sizeof(mhop));
mhop.peer = *peer;
mhop.local = *local;
mhop.vrfid = vrfid;
ifp = if_lookup_by_index(ifindex, vrfid);
if (vrfid == VRF_DEFAULT) {
/*
* Don't use the default vrf, otherwise we won't find
* sessions that doesn't specify it.
*/
vrf = NULL;
} else
vrf = vrf_lookup_by_id(vrfid);
l_bfd = bfd_mhop_lookup(mhop);
} else {
memset(&shop, 0, sizeof(shop));
shop.peer = *peer;
shop.ifindex = ifindex;
l_bfd = bfd_shop_lookup(shop);
}
gen_bfd_key(&key, peer, local, is_mhop, ifp ? ifp->name : NULL,
vrf ? vrf->name : NULL);
/* XXX maybe remoteDiscr should be checked for remoteHeard cases. */
return l_bfd;
return bfd_key_lookup(key);
}
int bfd_xmt_cb(struct thread *t)
@ -705,6 +610,9 @@ static void bfd_session_free(struct bfd_session *bs)
bfd_session_disable(bs);
bfd_key_delete(bs->key);
bfd_id_delete(bs->discrs.my_discr);
/* Remove observer if any. */
TAILQ_FOREACH(bso, &bglobal.bg_obslist, bso_entry) {
if (bso->bso_bs != bs)
@ -747,29 +655,51 @@ struct bfd_session *ptm_bfd_sess_new(struct bfd_peer_cfg *bpc)
* start. See `bfd_session_enable` for more information.
*/
if (bpc->bpc_has_localif)
strlcpy(bfd->ifname, bpc->bpc_localif, sizeof(bfd->ifname));
strlcpy(bfd->key.ifname, bpc->bpc_localif,
sizeof(bfd->key.ifname));
if (bpc->bpc_has_vrfname)
strlcpy(bfd->vrfname, bpc->bpc_vrfname, sizeof(bfd->vrfname));
strlcpy(bfd->key.vrfname, bpc->bpc_vrfname,
sizeof(bfd->key.vrfname));
/* Add observer if we have moving parts. */
if (bfd->ifname[0] || bfd->vrfname[0])
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);
if (bpc->bpc_mhop) {
BFD_SET_FLAG(bfd->flags, BFD_SESS_FLAG_MH);
bfd->mhop.peer = bpc->bpc_peer;
bfd->mhop.local = bpc->bpc_local;
} else {
bfd->shop.peer = bpc->bpc_peer;
bfd->key.family = (bpc->bpc_ipv4) ? AF_INET : AF_INET6;
switch (bfd->key.family) {
case AF_INET:
memcpy(&bfd->key.peer, &bpc->bpc_peer.sa_sin.sin_addr,
sizeof(bpc->bpc_peer.sa_sin.sin_addr));
memcpy(&bfd->key.local, &bpc->bpc_local.sa_sin.sin_addr,
sizeof(bpc->bpc_local.sa_sin.sin_addr));
break;
case AF_INET6:
memcpy(&bfd->key.peer, &bpc->bpc_peer.sa_sin6.sin6_addr,
sizeof(bpc->bpc_peer.sa_sin6.sin6_addr));
memcpy(&bfd->key.local, &bpc->bpc_local.sa_sin6.sin6_addr,
sizeof(bpc->bpc_local.sa_sin6.sin6_addr));
break;
default:
assert(1);
break;
}
bfd->local_ip = bpc->bpc_local;
bfd->local_address = bpc->bpc_local;
if (bpc->bpc_mhop)
BFD_SET_FLAG(bfd->flags, BFD_SESS_FLAG_MH);
bfd->key.mhop = bpc->bpc_mhop;
/* Registrate session into data structures. */
bfd_key_insert(bfd);
bfd->discrs.my_discr = ptm_bfd_gen_ID();
bfd_id_insert(bfd);
/* Try to enable session and schedule for packet receive/send. */
if (bfd_session_enable(bfd) == -1) {
@ -1223,35 +1153,26 @@ 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)
const char *bs_to_string(const struct bfd_session *bs)
{
static char buf[256];
char addr_buf[INET6_ADDRSTRLEN];
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.vrfid != VRF_DEFAULT)
snprintf(buf + pos, sizeof(buf) - pos, " vrf:%u",
bs->mhop.vrfid);
} 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.ifindex)
snprintf(buf + pos, sizeof(buf) - pos, " ifindex:%u",
bs->shop.ifindex);
}
pos += snprintf(buf + pos, sizeof(buf) - pos, " peer:%s",
inet_ntop(bs->key.family, &bs->key.peer, addr_buf,
sizeof(addr_buf)));
pos += snprintf(buf + pos, sizeof(buf) - pos, " local:%s",
inet_ntop(bs->key.family, &bs->key.local, addr_buf,
sizeof(addr_buf)));
if (bs->key.vrfname[0])
pos += snprintf(buf + pos, sizeof(buf) - pos, " vrf:%s",
bs->key.vrfname);
if (bs->key.ifname[0])
pos += snprintf(buf + pos, sizeof(buf) - pos, " ifname:%s",
bs->key.ifname);
return buf;
}
@ -1263,10 +1184,10 @@ int bs_observer_add(struct bfd_session *bs)
bso->bso_bs = bs;
bso->bso_isinterface = !BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH);
if (bso->bso_isinterface)
strlcpy(bso->bso_entryname, bs->ifname,
strlcpy(bso->bso_entryname, bs->key.ifname,
sizeof(bso->bso_entryname));
else
strlcpy(bso->bso_entryname, bs->vrfname,
strlcpy(bso->bso_entryname, bs->key.vrfname,
sizeof(bso->bso_entryname));
TAILQ_INSERT_TAIL(&bglobal.bg_obslist, bso, bso_entry);
@ -1280,21 +1201,59 @@ void bs_observer_del(struct bfd_session_observer *bso)
XFREE(MTYPE_BFDD_SESSION_OBSERVER, bso);
}
void bs_to_bpc(struct bfd_session *bs, struct bfd_peer_cfg *bpc)
{
memset(bpc, 0, sizeof(*bpc));
bpc->bpc_ipv4 = (bs->key.family == AF_INET);
bpc->bpc_mhop = bs->key.mhop;
switch (bs->key.family) {
case AF_INET:
bpc->bpc_peer.sa_sin.sin_family = AF_INET;
memcpy(&bpc->bpc_peer.sa_sin.sin_addr, &bs->key.peer,
sizeof(bpc->bpc_peer.sa_sin.sin_addr));
if (memcmp(&bs->key.local, &zero_addr, sizeof(bs->key.local))) {
bpc->bpc_local.sa_sin.sin_family = AF_INET6;
memcpy(&bpc->bpc_local.sa_sin.sin_addr, &bs->key.peer,
sizeof(bpc->bpc_local.sa_sin.sin_addr));
}
break;
case AF_INET6:
bpc->bpc_peer.sa_sin.sin_family = AF_INET6;
memcpy(&bpc->bpc_peer.sa_sin6.sin6_addr, &bs->key.peer,
sizeof(bpc->bpc_peer.sa_sin6.sin6_addr));
bpc->bpc_local.sa_sin6.sin6_family = AF_INET6;
memcpy(&bpc->bpc_local.sa_sin6.sin6_addr, &bs->key.peer,
sizeof(bpc->bpc_local.sa_sin6.sin6_addr));
break;
}
if (bs->key.ifname[0]) {
bpc->bpc_has_localif = true;
strlcpy(bpc->bpc_localif, bs->key.ifname,
sizeof(bpc->bpc_localif));
}
if (bs->key.vrfname[0]) {
bpc->bpc_has_vrfname = true;
strlcpy(bpc->bpc_vrfname, bs->key.vrfname,
sizeof(bpc->bpc_vrfname));
}
}
/*
* BFD hash data structures to find sessions.
*/
static struct hash *bfd_id_hash;
static struct hash *bfd_shop_hash;
static struct hash *bfd_mhop_hash;
static struct hash *bfd_key_hash;
static unsigned int bfd_id_hash_do(void *p);
static unsigned int bfd_shop_hash_do(void *p);
static unsigned int bfd_mhop_hash_do(void *p);
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);
static void _mhop_key(struct bfd_session *bs, const struct bfd_mhop_key *mhop);
static unsigned int bfd_key_hash_do(void *p);
static void _bfd_free(struct hash_bucket *hb,
void *arg __attribute__((__unused__)));
@ -1315,73 +1274,20 @@ static bool bfd_id_hash_cmp(const void *n1, const void *n2)
}
/* BFD hash for single hop. */
static unsigned int bfd_shop_hash_do(void *p)
static unsigned int bfd_key_hash_do(void *p)
{
struct bfd_session *bs = p;
return jhash(&bs->shop, sizeof(bs->shop), 0);
return jhash(&bs->key, sizeof(bs->key), 0);
}
static bool bfd_shop_hash_cmp(const void *n1, const void *n2)
static bool bfd_key_hash_cmp(const void *n1, const void *n2)
{
const struct bfd_session *bs1 = n1, *bs2 = n2;
return memcmp(&bs1->shop, &bs2->shop, sizeof(bs1->shop)) == 0;
return memcmp(&bs1->key, &bs2->key, sizeof(bs1->key)) == 0;
}
/* BFD hash for multi hop. */
static unsigned int bfd_mhop_hash_do(void *p)
{
struct bfd_session *bs = p;
return jhash(&bs->mhop, sizeof(bs->mhop), 0);
}
static bool bfd_mhop_hash_cmp(const void *n1, const void *n2)
{
const struct bfd_session *bs1 = n1, *bs2 = n2;
return memcmp(&bs1->mhop, &bs2->mhop, sizeof(bs1->mhop)) == 0;
}
/* Helper functions */
static void _shop_key(struct bfd_session *bs, const struct bfd_shop_key *shop)
{
bs->shop = *shop;
/* Remove unused fields. */
switch (bs->shop.peer.sa_sin.sin_family) {
case AF_INET:
bs->shop.peer.sa_sin.sin_port = 0;
break;
case AF_INET6:
bs->shop.peer.sa_sin6.sin6_port = 0;
break;
}
}
static void _shop_key2(struct bfd_session *bs, const struct bfd_shop_key *shop)
{
_shop_key(bs, shop);
bs->shop.ifindex = IFINDEX_INTERNAL;
}
static void _mhop_key(struct bfd_session *bs, const struct bfd_mhop_key *mhop)
{
bs->mhop = *mhop;
/* Remove unused fields. */
switch (bs->mhop.peer.sa_sin.sin_family) {
case AF_INET:
bs->mhop.peer.sa_sin.sin_port = 0;
bs->mhop.local.sa_sin.sin_port = 0;
break;
case AF_INET6:
bs->mhop.peer.sa_sin6.sin6_port = 0;
bs->mhop.local.sa_sin6.sin6_port = 0;
break;
}
}
/*
* Hash public interface / exported functions.
@ -1397,34 +1303,35 @@ struct bfd_session *bfd_id_lookup(uint32_t id)
return hash_lookup(bfd_id_hash, &bs);
}
struct bfd_session *bfd_shop_lookup(struct bfd_shop_key shop)
struct bfd_session *bfd_key_lookup(struct bfd_key key)
{
struct bfd_session bs, *bsp;
_shop_key(&bs, &shop);
bs.key = key;
bsp = hash_lookup(bfd_key_hash, &bs);
bsp = hash_lookup(bfd_shop_hash, &bs);
if (bsp == NULL && bs.shop.ifindex != 0) {
/*
* Since the local interface spec is optional, try
* searching the key without it as well.
*/
_shop_key2(&bs, &shop);
bsp = hash_lookup(bfd_shop_hash, &bs);
/* Handle cases where local-address is optional. */
if (bsp == NULL && bs.key.family == AF_INET) {
memset(&bs.key.local, 0, sizeof(bs.key.local));
bsp = hash_lookup(bfd_key_hash, &bs);
}
/* Handle cases where ifname is optional. */
bs.key = key;
if (bsp == NULL && bs.key.ifname[0]) {
memset(bs.key.ifname, 0, sizeof(bs.key.ifname));
bsp = hash_lookup(bfd_key_hash, &bs);
/* Handle cases where local-address and ifname are optional. */
if (bsp == NULL && bs.key.family == AF_INET) {
memset(&bs.key.local, 0, sizeof(bs.key.local));
bsp = hash_lookup(bfd_key_hash, &bs);
}
}
return bsp;
}
struct bfd_session *bfd_mhop_lookup(struct bfd_mhop_key mhop)
{
struct bfd_session bs;
_mhop_key(&bs, &mhop);
return hash_lookup(bfd_mhop_hash, &bs);
}
/*
* Delete functions.
*
@ -1444,31 +1351,18 @@ struct bfd_session *bfd_id_delete(uint32_t id)
return hash_release(bfd_id_hash, &bs);
}
struct bfd_session *bfd_shop_delete(struct bfd_shop_key shop)
struct bfd_session *bfd_key_delete(struct bfd_key key)
{
struct bfd_session bs, *bsp;
_shop_key(&bs, &shop);
bsp = hash_release(bfd_shop_hash, &bs);
if (bsp == NULL && shop.ifindex != 0) {
/*
* Since the local interface spec is optional, try
* searching the key without it as well.
*/
_shop_key2(&bs, &shop);
bsp = hash_release(bfd_shop_hash, &bs);
bs.key = key;
bsp = hash_lookup(bfd_key_hash, &bs);
if (bsp == NULL && key.ifname[0]) {
memset(bs.key.ifname, 0, sizeof(bs.key.ifname));
bsp = hash_lookup(bfd_key_hash, &bs);
}
return bsp;
}
struct bfd_session *bfd_mhop_delete(struct bfd_mhop_key mhop)
{
struct bfd_session bs;
_mhop_key(&bs, &mhop);
return hash_release(bfd_mhop_hash, &bs);
return hash_release(bfd_key_hash, bsp);
}
/* Iteration functions. */
@ -1477,14 +1371,9 @@ void bfd_id_iterate(hash_iter_func hif, void *arg)
hash_iterate(bfd_id_hash, hif, arg);
}
void bfd_shop_iterate(hash_iter_func hif, void *arg)
void bfd_key_iterate(hash_iter_func hif, void *arg)
{
hash_iterate(bfd_shop_hash, hif, arg);
}
void bfd_mhop_iterate(hash_iter_func hif, void *arg)
{
hash_iterate(bfd_mhop_hash, hif, arg);
hash_iterate(bfd_key_hash, hif, arg);
}
/*
@ -1498,24 +1387,17 @@ bool bfd_id_insert(struct bfd_session *bs)
return (hash_get(bfd_id_hash, bs, hash_alloc_intern) == bs);
}
bool bfd_shop_insert(struct bfd_session *bs)
bool bfd_key_insert(struct bfd_session *bs)
{
return (hash_get(bfd_shop_hash, bs, hash_alloc_intern) == bs);
}
bool bfd_mhop_insert(struct bfd_session *bs)
{
return (hash_get(bfd_mhop_hash, bs, hash_alloc_intern) == bs);
return (hash_get(bfd_key_hash, bs, hash_alloc_intern) == bs);
}
void bfd_initialize(void)
{
bfd_id_hash = hash_create(bfd_id_hash_do, bfd_id_hash_cmp,
"BFD discriminator hash");
bfd_shop_hash = hash_create(bfd_shop_hash_do, bfd_shop_hash_cmp,
"BFD single hop hash");
bfd_mhop_hash = hash_create(bfd_mhop_hash_do, bfd_mhop_hash_cmp,
"BFD multihop hop hash");
"BFD session discriminator hash");
bfd_key_hash = hash_create(bfd_key_hash_do, bfd_key_hash_cmp,
"BFD session hash");
}
static void _bfd_free(struct hash_bucket *hb,
@ -1536,11 +1418,9 @@ void bfd_shutdown(void)
* assert() here to make sure it really happened.
*/
bfd_id_iterate(_bfd_free, NULL);
assert(bfd_shop_hash->count == 0);
assert(bfd_mhop_hash->count == 0);
assert(bfd_key_hash->count == 0);
/* Now free the hashes themselves. */
hash_free(bfd_id_hash);
hash_free(bfd_shop_hash);
hash_free(bfd_mhop_hash);
hash_free(bfd_key_hash);
}

View File

@ -173,15 +173,13 @@ enum bfd_session_flags {
#define BFD_CHECK_FLAG(field, flag) (field & flag)
/* BFD session hash keys */
struct bfd_shop_key {
struct sockaddr_any peer;
ifindex_t ifindex;
};
struct bfd_mhop_key {
struct sockaddr_any peer;
struct sockaddr_any local;
vrf_id_t vrfid;
struct bfd_key {
uint16_t family;
uint8_t mhop;
struct in6_addr peer;
struct in6_addr local;
char ifname[MAXNAMELEN];
char vrfname[MAXNAMELEN];
};
struct bfd_session_stats {
@ -227,19 +225,14 @@ struct bfd_session {
uint8_t polling;
/* This and the localDiscr are the keys to state info */
struct bfd_key key;
struct peer_label *pl;
union {
struct bfd_shop_key shop;
struct bfd_mhop_key mhop;
};
int sock;
struct sockaddr_any local_address;
struct sockaddr_any local_ip;
struct interface *ifp;
struct vrf *vrf;
char ifname[MAXNAMELEN];
char vrfname[MAXNAMELEN];
int sock;
/* BFD session flags */
enum bfd_session_flags flags;
@ -531,38 +524,28 @@ const char *satostr(struct sockaddr_any *sa);
const char *diag2str(uint8_t diag);
int strtosa(const char *addr, struct sockaddr_any *sa);
void integer2timestr(uint64_t time, char *buf, size_t buflen);
const char *bs_to_string(struct bfd_session *bs);
const char *bs_to_string(const struct bfd_session *bs);
int bs_observer_add(struct bfd_session *bs);
void bs_observer_del(struct bfd_session_observer *bso);
void bs_to_bpc(struct bfd_session *bs, struct bfd_peer_cfg *bpc);
/* BFD hash data structures interface */
void bfd_initialize(void);
void bfd_shutdown(void);
struct bfd_session *bfd_id_lookup(uint32_t id);
struct bfd_session *bfd_shop_lookup(struct bfd_shop_key shop);
struct bfd_session *bfd_mhop_lookup(struct bfd_mhop_key mhop);
struct bfd_vrf *bfd_vrf_lookup(int vrf_id);
struct bfd_iface *bfd_iface_lookup(const char *ifname);
struct bfd_session *bfd_key_lookup(struct bfd_key key);
struct bfd_session *bfd_id_delete(uint32_t id);
struct bfd_session *bfd_shop_delete(struct bfd_shop_key shop);
struct bfd_session *bfd_mhop_delete(struct bfd_mhop_key mhop);
struct bfd_vrf *bfd_vrf_delete(int vrf_id);
struct bfd_iface *bfd_iface_delete(const char *ifname);
struct bfd_session *bfd_key_delete(struct bfd_key key);
bool bfd_id_insert(struct bfd_session *bs);
bool bfd_shop_insert(struct bfd_session *bs);
bool bfd_mhop_insert(struct bfd_session *bs);
bool bfd_vrf_insert(struct bfd_vrf *vrf);
bool bfd_iface_insert(struct bfd_iface *iface);
bool bfd_key_insert(struct bfd_session *bs);
typedef void (*hash_iter_func)(struct hash_bucket *hb, void *arg);
void bfd_id_iterate(hash_iter_func hif, void *arg);
void bfd_shop_iterate(hash_iter_func hif, void *arg);
void bfd_mhop_iterate(hash_iter_func hif, void *arg);
void bfd_vrf_iterate(hash_iter_func hif, void *arg);
void bfd_iface_iterate(hash_iter_func hif, void *arg);
void bfd_key_iterate(hash_iter_func hif, void *arg);
/* Export callback functions for `event.c`. */
extern struct thread_master *master;
@ -572,6 +555,8 @@ int bfd_echo_recvtimer_cb(struct thread *t);
int bfd_xmt_cb(struct thread *t);
int bfd_echo_xmt_cb(struct thread *t);
extern struct in6_addr zero_addr;
/*
* bfdd_vty.c

View File

@ -79,7 +79,10 @@ int _ptm_bfd_send(struct bfd_session *bs, uint16_t *port, const void *data,
if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_IPV6)) {
memset(&sin6, 0, sizeof(sin6));
sin6.sin6_family = AF_INET6;
sin6.sin6_addr = bs->shop.peer.sa_sin6.sin6_addr;
memcpy(&sin6.sin6_addr, &bs->key.peer, sizeof(sin6.sin6_addr));
if (IN6_IS_ADDR_LINKLOCAL(&sin6.sin6_addr))
sin6.sin6_scope_id = bs->ifp->ifindex;
sin6.sin6_port =
(port) ? *port
: (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH))
@ -92,7 +95,7 @@ int _ptm_bfd_send(struct bfd_session *bs, uint16_t *port, const void *data,
} else {
memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_addr = bs->shop.peer.sa_sin.sin_addr;
memcpy(&sin.sin_addr, &bs->key.peer, sizeof(sin.sin_addr));
sin.sin_port =
(port) ? *port
: (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH))
@ -120,7 +123,7 @@ int _ptm_bfd_send(struct bfd_session *bs, uint16_t *port, const void *data,
void ptm_bfd_echo_snd(struct bfd_session *bfd)
{
struct sockaddr_any *sa;
struct sockaddr *sa;
socklen_t salen;
int sd;
struct bfd_echo_pkt bep;
@ -135,31 +138,34 @@ void ptm_bfd_echo_snd(struct bfd_session *bfd)
bep.len = BFD_ECHO_PKT_LEN;
bep.my_discr = htonl(bfd->discrs.my_discr);
sa = BFD_CHECK_FLAG(bfd->flags, BFD_SESS_FLAG_MH) ? &bfd->mhop.peer
: &bfd->shop.peer;
if (BFD_CHECK_FLAG(bfd->flags, BFD_SESS_FLAG_IPV6)) {
sd = bglobal.bg_echov6;
sin6 = sa->sa_sin6;
memset(&sin6, 0, sizeof(sin6));
memcpy(&sin6.sin6_addr, &bfd->key.peer, sizeof(sin6.sin6_addr));
if (bfd->ifp && IN6_IS_ADDR_LINKLOCAL(&sin6.sin6_addr))
sin6.sin6_scope_id = bfd->ifp->ifindex;
sin6.sin6_port = htons(BFD_DEF_ECHO_PORT);
#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
sin6.sin6_len = sizeof(sin6);
#endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */
sa = (struct sockaddr_any *)&sin6;
sa = (struct sockaddr *)&sin6;
salen = sizeof(sin6);
} else {
sd = bglobal.bg_echo;
sin = sa->sa_sin;
memset(&sin6, 0, sizeof(sin6));
memcpy(&sin.sin_addr, &bfd->key.peer, sizeof(sin.sin_addr));
sin.sin_port = htons(BFD_DEF_ECHO_PORT);
#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
sin.sin_len = sizeof(sin);
#endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */
sa = (struct sockaddr_any *)&sin;
sa = (struct sockaddr *)&sin;
salen = sizeof(sin);
}
if (bp_udp_send(sd, BFD_TTL_VAL, (uint8_t *)&bep, sizeof(bep),
(struct sockaddr *)sa, salen)
if (bp_udp_send(sd, BFD_TTL_VAL, (uint8_t *)&bep, sizeof(bep), sa,
salen)
== -1)
return;
@ -602,8 +608,8 @@ int bfd_recv_cb(struct thread *t)
bfd->mh_ttl, BFD_TTL_VAL);
return 0;
}
} else if (bfd->local_ip.sa_sin.sin_family == AF_UNSPEC) {
bfd->local_ip = local;
} else if (bfd->local_address.sa_sin.sin_family == AF_UNSPEC) {
bfd->local_address = local;
}
/*
@ -917,25 +923,26 @@ int bp_peer_socket(const struct bfd_session *bs)
return -1;
}
if (bs->shop.ifindex != IFINDEX_INTERNAL) {
if (bp_bind_dev(sd, bs->ifp->name) != 0) {
if (bs->key.ifname[0]) {
if (bp_bind_dev(sd, bs->key.ifname) != 0) {
close(sd);
return -1;
}
} else if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH) &&
bs->mhop.vrfid != VRF_DEFAULT) {
if (bp_bind_dev(sd, bs->vrf->name) != 0) {
} else if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH)
&& bs->key.vrfname[0]) {
if (bp_bind_dev(sd, bs->key.vrfname) != 0) {
close(sd);
return -1;
}
}
/* Find an available source port in the proper range */
sin = bs->local_ip.sa_sin;
memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
sin.sin_len = sizeof(sin);
#endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */
memcpy(&sin.sin_addr, &bs->key.local, sizeof(sin.sin_addr));
if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH) == 0)
sin.sin_addr.s_addr = INADDR_ANY;
@ -987,20 +994,23 @@ int bp_peer_socketv6(const struct bfd_session *bs)
}
/* Find an available source port in the proper range */
sin6 = bs->local_ip.sa_sin6;
memset(&sin6, 0, sizeof(sin6));
sin6.sin6_family = AF_INET6;
#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
sin6.sin6_len = sizeof(sin6);
#endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */
memcpy(&sin6.sin6_addr, &bs->key.local, sizeof(sin6.sin6_addr));
if (IN6_IS_ADDR_LINKLOCAL(&sin6.sin6_addr))
sin6.sin6_scope_id = bs->ifp->ifindex;
if (bs->shop.ifindex != IFINDEX_INTERNAL) {
if (bp_bind_dev(sd, bs->ifp->name) != 0) {
if (bs->key.ifname[0]) {
if (bp_bind_dev(sd, bs->key.ifname) != 0) {
close(sd);
return -1;
}
} else if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH) &&
bs->mhop.vrfid != VRF_DEFAULT) {
if (bp_bind_dev(sd, bs->vrf->name) != 0) {
} else if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH)
&& bs->key.vrfname[0]) {
if (bp_bind_dev(sd, bs->key.vrfname) != 0) {
close(sd);
return -1;
}

View File

@ -79,7 +79,6 @@ _find_peer_or_error(struct vty *vty, int argc, struct cmd_token **argv,
const char *local_str, const char *ifname,
const char *vrfname);
/*
* Commands definition.
*/
@ -369,22 +368,25 @@ DEFPY(bfd_no_peer, bfd_no_peer_cmd,
*/
static void _display_peer_header(struct vty *vty, struct bfd_session *bs)
{
if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH)) {
vty_out(vty, "\tpeer %s", satostr(&bs->mhop.peer));
char addr_buf[INET6_ADDRSTRLEN];
vty_out(vty, "\tpeer %s",
inet_ntop(bs->key.family, &bs->key.peer, addr_buf,
sizeof(addr_buf)));
if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH))
vty_out(vty, " multihop");
vty_out(vty, " local-address %s", satostr(&bs->mhop.local));
if (bs->vrfname[0])
vty_out(vty, " vrf %s", bs->vrfname);
vty_out(vty, "\n");
} else {
vty_out(vty, "\tpeer %s", satostr(&bs->shop.peer));
if (bs->local_address.sa_sin.sin_family != AF_UNSPEC)
vty_out(vty, " local-address %s",
satostr(&bs->local_address));
if (bs->ifname[0])
vty_out(vty, " interface %s", bs->ifname);
vty_out(vty, "\n");
}
if (memcmp(&bs->key.local, &zero_addr, sizeof(bs->key.local)))
vty_out(vty, " local-address %s",
inet_ntop(bs->key.family, &bs->key.local, addr_buf,
sizeof(addr_buf)));
if (bs->key.vrfname[0])
vty_out(vty, " vrf %s", bs->key.vrfname);
if (bs->key.ifname[0])
vty_out(vty, " interface %s", bs->key.ifname);
vty_out(vty, "\n");
if (bs->pl)
vty_out(vty, "\t\tlabel: %s\n", bs->pl->pl_label);
@ -453,22 +455,25 @@ static void _display_peer(struct vty *vty, struct bfd_session *bs)
static struct json_object *_peer_json_header(struct bfd_session *bs)
{
struct json_object *jo = json_object_new_object();
char addr_buf[INET6_ADDRSTRLEN];
if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH)) {
if (bs->key.mhop)
json_object_boolean_true_add(jo, "multihop");
json_object_string_add(jo, "peer", satostr(&bs->mhop.peer));
json_object_string_add(jo, "local", satostr(&bs->mhop.local));
if (bs->vrfname[0])
json_object_string_add(jo, "vrf", bs->vrfname);
} else {
else
json_object_boolean_false_add(jo, "multihop");
json_object_string_add(jo, "peer", satostr(&bs->shop.peer));
if (bs->local_address.sa_sin.sin_family != AF_UNSPEC)
json_object_string_add(jo, "local",
satostr(&bs->local_address));
if (bs->ifname[0])
json_object_string_add(jo, "interface", bs->ifname);
}
json_object_string_add(jo, "peer",
inet_ntop(bs->key.family, &bs->key.peer,
addr_buf, sizeof(addr_buf)));
if (memcmp(&bs->key.local, &zero_addr, sizeof(bs->key.local)))
json_object_string_add(jo, "local",
inet_ntop(bs->key.family, &bs->key.local,
addr_buf, sizeof(addr_buf)));
if (bs->key.vrfname[0])
json_object_string_add(jo, "vrf", bs->key.vrfname);
if (bs->key.ifname[0])
json_object_string_add(jo, "interface", bs->key.ifname);
if (bs->pl)
json_object_string_add(jo, "label", bs->pl->pl_label);
@ -916,22 +921,25 @@ static int bfdd_write_config(struct vty *vty)
static void _bfdd_peer_write_config(struct vty *vty, struct bfd_session *bs)
{
if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH)) {
vty_out(vty, " peer %s", satostr(&bs->mhop.peer));
char addr_buf[INET6_ADDRSTRLEN];
vty_out(vty, " peer %s",
inet_ntop(bs->key.family, &bs->key.peer, addr_buf,
sizeof(addr_buf)));
if (bs->key.mhop)
vty_out(vty, " multihop");
vty_out(vty, " local-address %s", satostr(&bs->mhop.local));
if (bs->vrfname[0])
vty_out(vty, " vrf %s", bs->vrfname);
vty_out(vty, "\n");
} else {
vty_out(vty, " peer %s", satostr(&bs->shop.peer));
if (bs->local_address.sa_sin.sin_family != AF_UNSPEC)
vty_out(vty, " local-address %s",
satostr(&bs->local_address));
if (bs->ifname[0])
vty_out(vty, " interface %s", bs->ifname);
vty_out(vty, "\n");
}
if (memcmp(&bs->key.local, &zero_addr, sizeof(bs->key.local)))
vty_out(vty, " local-address %s",
inet_ntop(bs->key.family, &bs->key.local, addr_buf,
sizeof(addr_buf)));
if (bs->key.vrfname[0])
vty_out(vty, " vrf %s", bs->key.vrfname);
if (bs->key.ifname[0])
vty_out(vty, " interface %s", bs->key.ifname);
vty_out(vty, "\n");
if (bs->sock == -1)
vty_out(vty, " ! vrf or interface doesn't exist\n");
@ -980,16 +988,7 @@ static void _bfdd_peer_write_config_iter(struct hash_bucket *hb, void *arg)
static int bfdd_peer_write_config(struct vty *vty)
{
struct bfd_session_observer *bso;
bfd_id_iterate(_bfdd_peer_write_config_iter, vty);
TAILQ_FOREACH(bso, &bglobal.bg_obslist, bso_entry) {
/* Only print disabled sessions here. */
if (bso->bso_bs->sock != -1)
continue;
_bfdd_peer_write_config(vty, bso->bso_bs);
}
return 1;
}

View File

@ -309,24 +309,7 @@ static int parse_peer_label_config(struct json_object *jo,
log_debug("\tpeer-label: %s", sval);
/* Translate the label into BFD address keys. */
bpc->bpc_ipv4 = !BFD_CHECK_FLAG(pl->pl_bs->flags, BFD_SESS_FLAG_IPV6);
bpc->bpc_mhop = BFD_CHECK_FLAG(pl->pl_bs->flags, BFD_SESS_FLAG_MH);
if (bpc->bpc_mhop) {
bpc->bpc_peer = pl->pl_bs->mhop.peer;
bpc->bpc_local = pl->pl_bs->mhop.local;
if (pl->pl_bs->mhop.vrfid != VRF_DEFAULT) {
bpc->bpc_has_vrfname = true;
strlcpy(bpc->bpc_vrfname, pl->pl_bs->vrf->name,
sizeof(bpc->bpc_vrfname));
}
} else {
bpc->bpc_peer = pl->pl_bs->shop.peer;
if (pl->pl_bs->ifname[0]) {
bpc->bpc_has_localif = true;
strlcpy(bpc->bpc_localif, pl->pl_bs->ifname,
sizeof(bpc->bpc_localif));
}
}
bs_to_bpc(pl->pl_bs, bpc);
return 0;
}
@ -519,6 +502,8 @@ int config_notify_request(struct bfd_control_socket *bcs, const char *jsonstr,
static int json_object_add_peer(struct json_object *jo, struct bfd_session *bs)
{
char addr_buf[INET6_ADDRSTRLEN];
/* Add peer 'key' information. */
if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_IPV6))
json_object_boolean_true_add(jo, "ipv6");
@ -528,21 +513,26 @@ static int json_object_add_peer(struct json_object *jo, struct bfd_session *bs)
if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH)) {
json_object_boolean_true_add(jo, "multihop");
json_object_string_add(jo, "peer-address",
satostr(&bs->mhop.peer));
inet_ntop(bs->key.family, &bs->key.peer,
addr_buf, sizeof(addr_buf)));
json_object_string_add(jo, "local-address",
satostr(&bs->mhop.local));
if (bs->vrfname[0])
json_object_string_add(jo, "vrf-name", bs->vrfname);
inet_ntop(bs->key.family, &bs->key.local,
addr_buf, sizeof(addr_buf)));
if (bs->key.vrfname[0])
json_object_string_add(jo, "vrf-name", bs->key.vrfname);
} else {
json_object_boolean_false_add(jo, "multihop");
json_object_string_add(jo, "peer-address",
satostr(&bs->shop.peer));
if (bs->local_address.sa_sin.sin_family != AF_UNSPEC)
json_object_string_add(jo, "local-address",
satostr(&bs->local_address));
if (bs->ifname[0])
inet_ntop(bs->key.family, &bs->key.peer,
addr_buf, sizeof(addr_buf)));
if (memcmp(&bs->key.local, &zero_addr, sizeof(bs->key.local)))
json_object_string_add(
jo, "local-address",
inet_ntop(bs->key.family, &bs->key.local,
addr_buf, sizeof(addr_buf)));
if (bs->key.ifname[0])
json_object_string_add(jo, "local-interface",
bs->ifname);
bs->key.ifname);
}
if (bs->pl)

View File

@ -55,7 +55,7 @@ static struct zclient *zclient;
/*
* Prototypes
*/
static int _ptm_msg_address(struct stream *msg, struct sockaddr_any *sa);
static int _ptm_msg_address(struct stream *msg, int family, const void *addr);
static void _ptm_msg_read_address(struct stream *msg, struct sockaddr_any *sa);
static int _ptm_msg_read(struct stream *msg, int command,
@ -127,24 +127,24 @@ static void debug_printbpc(const char *func, unsigned int line,
#define DEBUG_PRINTBPC(bpc)
#endif /* BFD_DEBUG */
static int _ptm_msg_address(struct stream *msg, struct sockaddr_any *sa)
static int _ptm_msg_address(struct stream *msg, int family, const void *addr)
{
switch (sa->sa_sin.sin_family) {
stream_putc(msg, family);
switch (family) {
case AF_INET:
stream_putc(msg, sa->sa_sin.sin_family);
stream_put_in_addr(msg, &sa->sa_sin.sin_addr);
stream_put(msg, addr, sizeof(struct in_addr));
stream_putc(msg, 32);
break;
case AF_INET6:
stream_putc(msg, sa->sa_sin6.sin6_family);
stream_put(msg, &sa->sa_sin6.sin6_addr,
sizeof(sa->sa_sin6.sin6_addr));
stream_put(msg, addr, sizeof(struct in6_addr));
stream_putc(msg, 128);
break;
default:
return -1;
assert(0);
break;
}
return 0;
@ -153,7 +153,6 @@ static int _ptm_msg_address(struct stream *msg, struct sockaddr_any *sa)
int ptm_bfd_notify(struct bfd_session *bs)
{
struct stream *msg;
struct sockaddr_any sac;
bs->stats.znotification++;
@ -195,10 +194,7 @@ int ptm_bfd_notify(struct bfd_session *bs)
stream_putl(msg, IFINDEX_INTERNAL);
/* BFD destination prefix information. */
if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH))
_ptm_msg_address(msg, &bs->mhop.peer);
else
_ptm_msg_address(msg, &bs->shop.peer);
_ptm_msg_address(msg, bs->key.family, &bs->key.peer);
/* BFD status */
switch (bs->ses_state) {
@ -218,34 +214,7 @@ int ptm_bfd_notify(struct bfd_session *bs)
}
/* BFD source prefix information. */
if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH)) {
_ptm_msg_address(msg, &bs->mhop.local);
} else {
if (bs->local_address.sa_sin.sin_family)
_ptm_msg_address(msg, &bs->local_address);
else if (bs->local_address.sa_sin.sin_family)
_ptm_msg_address(msg, &bs->local_ip);
else {
sac = bs->shop.peer;
switch (sac.sa_sin.sin_family) {
case AF_INET:
memset(&sac.sa_sin.sin_addr, 0,
sizeof(sac.sa_sin.sin_family));
break;
case AF_INET6:
memset(&sac.sa_sin6.sin6_addr, 0,
sizeof(sac.sa_sin6.sin6_family));
break;
default:
assert(false);
break;
}
/* No local address found yet, so send zeroes. */
_ptm_msg_address(msg, &sac);
}
}
_ptm_msg_address(msg, bs->key.family, &bs->key.local);
/* Write packet size. */
stream_putw_at(msg, 0, stream_get_endp(msg));
@ -290,7 +259,6 @@ stream_failure:
static int _ptm_msg_read(struct stream *msg, int command,
struct bfd_peer_cfg *bpc, struct ptm_client **pc)
{
struct interface *ifp;
uint32_t pid;
uint8_t ttl __attribute__((unused));
size_t ifnamelen;
@ -385,31 +353,6 @@ static int _ptm_msg_read(struct stream *msg, int command,
if (bpc->bpc_has_localif) {
STREAM_GET(bpc->bpc_localif, msg, ifnamelen);
bpc->bpc_localif[ifnamelen] = 0;
/*
* IPv6 link-local addresses must use scope id,
* otherwise the session lookup will always fail
* and we'll have multiple sessions showing up.
*
* This problem only happens with single hop
* since it is not possible to have link-local
* address for multi hop sessions.
*/
if (bpc->bpc_ipv4 == false
&& IN6_IS_ADDR_LINKLOCAL(
&bpc->bpc_peer.sa_sin6.sin6_addr)) {
ifp = if_lookup_by_name_all_vrf(
bpc->bpc_localif);
if (ifp == NULL) {
log_error(
"ptm-read: interface %s doesn't exists",
bpc->bpc_localif);
return -1;
}
bpc->bpc_peer.sa_sin6.sin6_scope_id =
ifp->ifindex;
}
}
}
@ -608,7 +551,7 @@ static void bfdd_sessions_enable_interface(struct interface *ifp)
/* Interface name mismatch. */
bs = bso->bso_bs;
if (strcmp(ifp->name, bs->ifname))
if (strcmp(ifp->name, bs->key.ifname))
continue;
/* Skip enabled sessions. */
if (bs->sock != -1)
@ -630,7 +573,7 @@ static void bfdd_sessions_disable_interface(struct interface *ifp)
/* Interface name mismatch. */
bs = bso->bso_bs;
if (strcmp(ifp->name, bs->ifname))
if (strcmp(ifp->name, bs->key.ifname))
continue;
/* Skip disabled sessions. */
if (bs->sock == -1)