diff options
Diffstat (limited to 'bfdd/ptm_adapter.c')
| -rw-r--r-- | bfdd/ptm_adapter.c | 131 |
1 files changed, 61 insertions, 70 deletions
diff --git a/bfdd/ptm_adapter.c b/bfdd/ptm_adapter.c index 5610c352fb..8d80b9468d 100644 --- a/bfdd/ptm_adapter.c +++ b/bfdd/ptm_adapter.c @@ -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) @@ -670,6 +613,8 @@ static int bfdd_interface_update(int cmd, struct zclient *zc, bfdd_sessions_disable_interface(ifp); + if_set_index(ifp, IFINDEX_INTERNAL); + return 0; } @@ -691,6 +636,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); @@ -713,6 +700,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) |
