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ébastien
From 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

Reply via email to