Hello BIRD team,
This patch (for master branch / 2.18) fixes the link-local next hop handling in
BGP UPDATE messages sent by BIRD.
Currently BIRD includes the link-local address in the IPv6 next hop field
unconditionally whenever it is available (on single-hop sessions where the peer
is on a directly connected subnet). This affects any address family that
carries an IPv6 next hop: IPv6, VPNv6, as well as IPv4 and VPNv4 when using
Extended Next Hop encoding (RFC 5549). RFC 2545 Section 3 specifies:
"The link-local address shall be included in the Next Hop field if
and only if the BGP speaker shares a common subnet with the entity
identified by the global IPv6 address carried in the Network Address
of Next Hop field and the peer the route is being advertised to."
In practice this causes problems on single-hop sessions where the peer is on a
directly connected subnet but the next hop is set to a non-connected address
(e.g. a loopback address): some routers reject the UPDATE and close the session
when they receive a route carrying a link-local next hop whose global address
is not on the shared subnet. This behavior was observed with Cisco IOS XR with
VPN SRv6 routes.
The fix checks whether the global next hop falls within the connected prefix of
the neighbor interface before including the link-local address.
Thanks!
--
SébastienFrom 80ed4b8d79f27f5c1711cce0e7ec40a40a38a17b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?S=C3=A9bastien=20Parisot?= <[email protected]>
Date: Tue, 10 Feb 2026 07:53:11 +0000
Subject: [PATCH] bgp: suppress link-local next hop based on RFC 2545
shared-subnet rule
Only include the link-local IPv6 address in the next hop field if the
global next hop address is on the subnet shared with the peer, as
required by RFC 2545 Section 3 and RFC 4659 Section 3.2.1.1.
Previously the link-local was included unconditionally whenever it was
available (single-hop sessions). This caused some routers (e.g. Cisco
IOS XR) to close the BGP session when receiving a VPN route with a
link-local next hop, since in typical PE-to-PE iBGP the next hop is a
loopback address not on the shared subnet.
---
proto/bgp/packets.c | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/proto/bgp/packets.c b/proto/bgp/packets.c
index fcaff74..b5d241d 100644
--- a/proto/bgp/packets.c
+++ b/proto/bgp/packets.c
@@ -1277,7 +1277,11 @@ bgp_update_next_hop_ip(struct bgp_export_state *s, eattr *a, ea_list **to)
else
{
ip_addr nh[2] = { s->channel->next_hop_addr, s->channel->link_addr };
- bgp_set_attr_data(to, s->pool, BA_NEXT_HOP, 0, nh, ipa_nonzero(nh[1]) ? 32 : 16);
+
+ /* Include link-local next hop iff the global next hop address is on
+ * the subnet shared with the peer (RFC 2545 Section 3, RFC 4659 Section 3.2.1.1) */
+ int shared_subnet = s->proto->neigh && s->proto->neigh->ifa && ipa_in_netX(nh[0], &s->proto->neigh->ifa->prefix);
+ bgp_set_attr_data(to, s->pool, BA_NEXT_HOP, 0, nh, (ipa_nonzero(nh[1]) && shared_subnet) ? 32 : 16);
s->local_next_hop = 1;
if (s->mpls)
--
2.47.3