diff --git a/bgpd/bgp_nht.c b/bgpd/bgp_nht.c index 1af9be46f1..cc208a8190 100644 --- a/bgpd/bgp_nht.c +++ b/bgpd/bgp_nht.c @@ -873,7 +873,7 @@ void bgp_nht_register_nexthops(struct bgp *bgp) } } -void bgp_nht_register_enhe_capability_interfaces(struct peer *peer) +void bgp_nht_reg_enhe_cap_intfs(struct peer *peer) { struct bgp *bgp; struct bgp_node *rn; @@ -891,9 +891,8 @@ void bgp_nht_register_enhe_capability_interfaces(struct peer *peer) return; if (!sockunion2hostprefix(&peer->su, &p)) { - if (BGP_DEBUG(nht, NHT)) - zlog_debug("%s: Unable to convert prefix to sockunion", - __func__); + zlog_warn("%s: Unable to convert sockunion to prefix for %s", + __func__, peer->host); return; } @@ -922,3 +921,48 @@ void bgp_nht_register_enhe_capability_interfaces(struct peer *peer) BGP_UNNUM_DEFAULT_RA_INTERVAL); } } + +void bgp_nht_dereg_enhe_cap_intfs(struct peer *peer) +{ + struct bgp *bgp; + struct bgp_node *rn; + struct bgp_nexthop_cache *bnc; + struct nexthop *nhop; + struct interface *ifp; + struct prefix p; + + if (peer->ifp) + return; + + bgp = peer->bgp; + + if (!bgp->nexthop_cache_table[AFI_IP6]) + return; + + if (!sockunion2hostprefix(&peer->su, &p)) { + zlog_warn("%s: Unable to convert sockunion to prefix for %s", + __func__, peer->host); + return; + } + + if (p.family != AF_INET6) + return; + + rn = bgp_node_lookup(bgp->nexthop_cache_table[AFI_IP6], &p); + if (!rn) + return; + + bnc = bgp_node_get_bgp_nexthop_info(rn); + if (!bnc) + return; + + if (peer != bnc->nht_info) + return; + + for (nhop = bnc->nexthop; nhop; nhop = nhop->next) { + ifp = if_lookup_by_index(nhop->ifindex, nhop->vrf_id); + + zclient_send_interface_radv_req(zclient, nhop->vrf_id, ifp, 0, + 0); + } +} diff --git a/bgpd/bgp_nht.h b/bgpd/bgp_nht.h index e39d55567a..4e015e4aae 100644 --- a/bgpd/bgp_nht.h +++ b/bgpd/bgp_nht.h @@ -87,6 +87,7 @@ extern void bgp_nht_register_nexthops(struct bgp *bgp); * this code can walk the registered nexthops and * register the important ones with zebra for RA. */ -extern void bgp_nht_register_enhe_capability_interfaces(struct peer *peer); +extern void bgp_nht_reg_enhe_cap_intfs(struct peer *peer); +extern void bgp_nht_dereg_enhe_cap_intfs(struct peer *peer); #endif /* _BGP_NHT_H */ diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index d7c18ee0ad..4f36073e9a 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -3822,6 +3822,10 @@ DEFUN (no_neighbor, } other = peer->doppelganger; + + if (CHECK_FLAG(peer->flags, PEER_FLAG_CAPABILITY_ENHE)) + bgp_zebra_terminate_radv(peer->bgp, peer); + peer_notify_unconfig(peer); peer_delete(peer); if (other && other->status != Deleted) { @@ -4242,6 +4246,9 @@ DEFUN (no_neighbor_set_peer_group, return CMD_WARNING_CONFIG_FAILED; } + if (CHECK_FLAG(peer->flags, PEER_FLAG_CAPABILITY_ENHE)) + bgp_zebra_terminate_radv(peer->bgp, peer); + peer_notify_unconfig(peer); ret = peer_delete(peer); diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index 4f54bc81fb..cca3f4aaa3 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -1939,8 +1939,14 @@ void bgp_zebra_initiate_radv(struct bgp *bgp, struct peer *peer) zlog_debug("%u: Initiating RA for peer %s", bgp->vrf_id, peer->host); - zclient_send_interface_radv_req(zclient, bgp->vrf_id, peer->ifp, 1, - ra_interval); + /* + * If unnumbered peer (peer->ifp) call thru zapi to start RAs. + * If we don't have an ifp pointer, call function to find the + * ifps for a numbered enhe peer to turn RAs on. + */ + peer->ifp ? zclient_send_interface_radv_req(zclient, bgp->vrf_id, + peer->ifp, 1, ra_interval) + : bgp_nht_reg_enhe_cap_intfs(peer); } void bgp_zebra_terminate_radv(struct bgp *bgp, struct peer *peer) @@ -1953,7 +1959,14 @@ void bgp_zebra_terminate_radv(struct bgp *bgp, struct peer *peer) zlog_debug("%u: Terminating RA for peer %s", bgp->vrf_id, peer->host); - zclient_send_interface_radv_req(zclient, bgp->vrf_id, peer->ifp, 0, 0); + /* + * If unnumbered peer (peer->ifp) call thru zapi to stop RAs. + * If we don't have an ifp pointer, call function to find the + * ifps for a numbered enhe peer to turn RAs off. + */ + peer->ifp ? zclient_send_interface_radv_req(zclient, bgp->vrf_id, + peer->ifp, 0, 0) + : bgp_nht_dereg_enhe_cap_intfs(peer); } int bgp_zebra_advertise_subnet(struct bgp *bgp, int advertise, vni_t vni) diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index 5d28b138d6..cf6335d373 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -2490,6 +2490,11 @@ static void peer_group2peer_config_copy(struct peer_group *group, : BGP_DEFAULT_EBGP_ROUTEADV; } + /* capability extended-nexthop apply */ + if (!CHECK_FLAG(peer->flags_override, PEER_FLAG_CAPABILITY_ENHE)) + if (CHECK_FLAG(conf->flags, PEER_FLAG_CAPABILITY_ENHE)) + SET_FLAG(peer->flags, PEER_FLAG_CAPABILITY_ENHE); + /* password apply */ if (!CHECK_FLAG(peer->flags_override, PEER_FLAG_PASSWORD)) PEER_STR_ATTR_INHERIT(peer, group, password, @@ -2577,6 +2582,10 @@ int peer_group_delete(struct peer_group *group) for (ALL_LIST_ELEMENTS(group->peer, node, nnode, peer)) { other = peer->doppelganger; + + if (CHECK_FLAG(peer->flags, PEER_FLAG_CAPABILITY_ENHE)) + bgp_zebra_terminate_radv(bgp, peer); + peer_delete(peer); if (other && other->status != Deleted) { other->group = NULL; @@ -2621,6 +2630,9 @@ int peer_group_remote_as_delete(struct peer_group *group) for (ALL_LIST_ELEMENTS(group->peer, node, nnode, peer)) { other = peer->doppelganger; + if (CHECK_FLAG(peer->flags, PEER_FLAG_CAPABILITY_ENHE)) + bgp_zebra_terminate_radv(peer->bgp, peer); + peer_delete(peer); if (other && other->status != Deleted) { @@ -4065,8 +4077,22 @@ static int peer_flag_modify(struct peer *peer, uint32_t flag, int set) /* Update flag override state accordingly. */ COND_FLAG(peer->flags_override, flag, set != invert); - if (set && flag == PEER_FLAG_CAPABILITY_ENHE) - bgp_nht_register_enhe_capability_interfaces(peer); + /* + * For the extended next-hop encoding flag we need to turn RAs + * on if flag is being set, but only turn RAs off if the flag + * is being unset on this peer and if this peer is a member of a + * peer-group, the peer-group also doesn't have the flag set. + */ + if (flag == PEER_FLAG_CAPABILITY_ENHE) { + if (set) { + bgp_zebra_initiate_radv(peer->bgp, peer); + } else if (peer_group_active(peer)) { + if (!CHECK_FLAG(peer->group->conf->flags, flag)) + bgp_zebra_terminate_radv(peer->bgp, + peer); + } else + bgp_zebra_terminate_radv(peer->bgp, peer); + } /* Execute flag action on peer. */ if (action.type == peer_change_reset) @@ -4099,8 +4125,9 @@ static int peer_flag_modify(struct peer *peer, uint32_t flag, int set) /* Update flag on peer-group member. */ COND_FLAG(member->flags, flag, set != member_invert); - if (set && flag == PEER_FLAG_CAPABILITY_ENHE) - bgp_nht_register_enhe_capability_interfaces(member); + if (flag == PEER_FLAG_CAPABILITY_ENHE) + set ? bgp_zebra_initiate_radv(member->bgp, member) + : bgp_zebra_terminate_radv(member->bgp, member); /* Execute flag action on peer-group member. */ if (action.type == peer_change_reset)