bgpd: Add an ability to disable link-local capability per peer

Even if we have unnumbered peering, let's respect `no neighbor X capability link-local`
and disable it per-neighbor on demand.

Fixes: db853cc97e ("bgpd: Implement Link-Local Next Hop capability")

Signed-off-by: Donatas Abraitis <donatas@opensourcerouting.org>
This commit is contained in:
Donatas Abraitis 2025-02-11 15:24:12 +02:00
parent 28c337de18
commit ca24f56a5c
5 changed files with 14 additions and 18 deletions

View file

@ -2450,8 +2450,7 @@ int bgp_mp_reach_parse(struct bgp_attr_parser_args *args,
if (!peer->nexthop.ifp) {
zlog_warn("%s sent a v6 global attribute but address is a V6 LL and there's no peer interface information. Hence, withdrawing",
peer->host);
if (CHECK_FLAG(peer->cap, PEER_CAP_LINK_LOCAL_ADV) &&
CHECK_FLAG(peer->cap, PEER_CAP_LINK_LOCAL_RCV))
if (PEER_HAS_LINK_LOCAL_CAPABILITY(peer))
bgp_notify_send(peer->connection, BGP_NOTIFY_UPDATE_ERR,
BGP_NOTIFY_UPDATE_UNREACH_NEXT_HOP);
return BGP_ATTR_PARSE_WITHDRAW;
@ -4215,8 +4214,7 @@ size_t bgp_packet_mpattr_start(struct stream *s, struct peer *peer, afi_t afi,
IPV6_MAX_BYTELEN);
} else {
stream_putc(s, IPV6_MAX_BYTELEN);
if (CHECK_FLAG(peer->cap, PEER_CAP_LINK_LOCAL_ADV) &&
CHECK_FLAG(peer->cap, PEER_CAP_LINK_LOCAL_RCV))
if (PEER_HAS_LINK_LOCAL_CAPABILITY(peer))
stream_put(s, &attr->mp_nexthop_local, IPV6_MAX_BYTELEN);
else
stream_put(s, &attr->mp_nexthop_global, IPV6_MAX_BYTELEN);

View file

@ -1102,8 +1102,7 @@ static bool make_prefix(int afi, struct bgp_path_info *pi, struct prefix *p)
/* If we receive MP_REACH with GUA as LL, we should
* check if we have Link-Local Next Hop capability also.
*/
if (!(CHECK_FLAG(peer->cap, PEER_CAP_LINK_LOCAL_ADV) &&
CHECK_FLAG(peer->cap, PEER_CAP_LINK_LOCAL_RCV))) {
if (!PEER_HAS_LINK_LOCAL_CAPABILITY(peer)) {
zlog_warn("%s: received IPv6 global next-hop as Link-Local, but no capability exchanged",
__func__);
p->u.prefix6 = attr->mp_nexthop_global;

View file

@ -2512,8 +2512,7 @@ bool subgroup_announce_check(struct bgp_dest *dest, struct bgp_path_info *pi,
* length of the Next Hop field to 16 and include only the IPv6 link-local
* address in the Next Hop field.
*/
if (!(CHECK_FLAG(peer->cap, PEER_CAP_LINK_LOCAL_ADV) &&
CHECK_FLAG(peer->cap, PEER_CAP_LINK_LOCAL_RCV)))
if (!PEER_HAS_LINK_LOCAL_CAPABILITY(peer))
global_and_ll = true;
}
@ -9728,8 +9727,7 @@ void route_vty_out(struct vty *vty, const struct prefix *p,
bgp_nexthop_hostname(path->peer, path->nexthop);
char esi_buf[ESI_STR_LEN];
bool ll_nexthop_only = attr->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL &&
!!CHECK_FLAG(path->peer->cap, PEER_CAP_LINK_LOCAL_ADV) &&
!!CHECK_FLAG(path->peer->cap, PEER_CAP_LINK_LOCAL_RCV);
PEER_HAS_LINK_LOCAL_CAPABILITY(path->peer);
if (json_paths)
json_path = json_object_new_object();
@ -10842,8 +10840,7 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn,
bgp_get_imported_bpi_ultimate(path);
struct bgp_route_evpn *bre = bgp_attr_get_evpn_overlay(attr);
bool ll_nexthop_only = attr->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL &&
!!CHECK_FLAG(path->peer->cap, PEER_CAP_LINK_LOCAL_ADV) &&
!!CHECK_FLAG(path->peer->cap, PEER_CAP_LINK_LOCAL_RCV);
PEER_HAS_LINK_LOCAL_CAPABILITY(path->peer);
if (json_paths) {
json_path = json_object_new_object();

View file

@ -447,8 +447,7 @@ struct stream *bpacket_reformat_for_peer(struct bpacket *pkt,
int gnh_modified, lnh_modified;
size_t offset_nhglobal = vec->offset + 1;
size_t offset_nhlocal = vec->offset + 1;
bool ll_nexthop_only = !!CHECK_FLAG(peer->cap, PEER_CAP_LINK_LOCAL_ADV) &&
!!CHECK_FLAG(peer->cap, PEER_CAP_LINK_LOCAL_RCV);
bool ll_nexthop_only = PEER_HAS_LINK_LOCAL_CAPABILITY(peer);
gnh_modified = lnh_modified = 0;
mod_v6nhg = &v6nhglobal;
@ -538,8 +537,7 @@ struct stream *bpacket_reformat_for_peer(struct bpacket *pkt,
}
if (nhlen == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL ||
nhlen == BGP_ATTR_NHLEN_VPNV6_GLOBAL_AND_LL ||
(nhlen == BGP_ATTR_NHLEN_IPV6_GLOBAL && ll_nexthop_only)) {
nhlen == BGP_ATTR_NHLEN_VPNV6_GLOBAL_AND_LL || ll_nexthop_only) {
stream_get_from(&v6nhlocal, s, offset_nhlocal,
IPV6_MAX_BYTELEN);
if (IN6_IS_ADDR_UNSPECIFIED(&v6nhlocal)) {
@ -559,8 +557,7 @@ struct stream *bpacket_reformat_for_peer(struct bpacket *pkt,
if (bgp_debug_update(peer, NULL, NULL, 0)) {
if (nhlen == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL ||
nhlen == BGP_ATTR_NHLEN_VPNV6_GLOBAL_AND_LL ||
(nhlen == BGP_ATTR_NHLEN_IPV6_GLOBAL && ll_nexthop_only))
nhlen == BGP_ATTR_NHLEN_VPNV6_GLOBAL_AND_LL || ll_nexthop_only)
zlog_debug(
"u%" PRIu64 ":s%" PRIu64
" %s send UPDATE w/ mp_nexthops %pI6, %pI6%s",

View file

@ -2921,4 +2921,9 @@ extern void bgp_session_reset_safe(struct peer *peer, struct listnode **nnode);
!(_afi == AFI_IP && _safi == SAFI_MPLS_VPN) && \
!(_afi == AFI_IP6 && _safi == SAFI_MPLS_VPN))
#define PEER_HAS_LINK_LOCAL_CAPABILITY(_peer) \
(CHECK_FLAG(_peer->flags, PEER_FLAG_CAPABILITY_LINK_LOCAL) && \
CHECK_FLAG(_peer->cap, PEER_CAP_LINK_LOCAL_ADV) && \
CHECK_FLAG(_peer->cap, PEER_CAP_LINK_LOCAL_RCV))
#endif /* _QUAGGA_BGPD_H */