Commit b9ff57d378 for frr

commit b9ff57d3782eaddf2c400b3c6054ea1baef3b10d
Author: Nageswara Soma <nsoma@cisco.com>
Date:   Tue Oct 13 15:31:26 2026 -0700

    bgpd: Refresh peer nexthop on address changes

    peer->nexthop, including the outgoing interface, is
    computed only when the session is set up. If an
    interface address is later added or removed so that
    the local address resolves to a different interface,
    the peer keeps the stale interface, its BFD session
    stays bound to the old one, and routes already
    advertised keep the old next-hop addresses.

    Recompute the nexthop of each connected peer when a
    connected address is added or deleted. When the
    interface changes, update the BFD source, and force
    route announcements if the next-hop addresses
    changed, so the peer learns the new next hops
    without a session reset. Log the change under
    "debug bgp zebra".

    Signed-off-by: Nageswara Soma <nsoma@cisco.com>

diff --git a/bgpd/bgp_nexthop.c b/bgpd/bgp_nexthop.c
index ea8a7a6392..4bed396b33 100644
--- a/bgpd/bgp_nexthop.c
+++ b/bgpd/bgp_nexthop.c
@@ -33,6 +33,7 @@
 #include "bgpd/bgp_rd.h"
 #include "bgpd/bgp_mplsvpn.h"
 #include "bgpd/bgp_bfd.h"
+#include "bgpd/bgp_zebra.h"

 DEFINE_MTYPE_STATIC(BGPD, MARTIAN_STRING, "BGP Martian Addr Intf String");

@@ -378,6 +379,49 @@ static void bgp_address_del(struct bgp *bgp, struct connected *ifc,
 	}
 }

+static void bgp_connected_peer_nexthop_update(struct bgp *bgp)
+{
+	struct listnode *node, *nnode;
+	struct peer *peer;
+	afi_t afi;
+	safi_t safi;
+
+	for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) {
+		struct bgp_nexthop nexthop, old;
+		bool addr_changed;
+
+		if (!peer->connection || !peer->connection->su_local ||
+		    !peer->connection->su_remote)
+			continue;
+
+		if (!bgp_zebra_nexthop_set(peer->connection->su_local,
+					   peer->connection->su_remote,
+					   &nexthop, peer))
+			continue;
+
+		if (peer->nexthop.ifp == nexthop.ifp)
+			continue;
+
+		old = peer->nexthop;
+		addr_changed = !IPV4_ADDR_SAME(&old.v4, &nexthop.v4) ||
+			       !IPV6_ADDR_SAME(&old.v6_global, &nexthop.v6_global) ||
+			       !IPV6_ADDR_SAME(&old.v6_local, &nexthop.v6_local);
+
+		peer->nexthop = nexthop;
+		bgp_peer_bfd_update_source(peer);
+
+		if (BGP_DEBUG(zebra, ZEBRA))
+			zlog_debug("%pBP nexthop changed: ifp %s -> %s, v4 %pI4 -> %pI4, global %pI6 -> %pI6, local %pI6 -> %pI6%s",
+				   peer, old.ifp ? old.ifp->name : "(none)",
+				   nexthop.ifp ? nexthop.ifp->name : "(none)", &old.v4,
+				   &nexthop.v4, &old.v6_global, &nexthop.v6_global, &old.v6_local,
+				   &nexthop.v6_local, addr_changed ? ", reannouncing routes" : "");
+
+		if (addr_changed)
+			FOREACH_AFI_SAFI (afi, safi)
+				bgp_announce_route(peer, afi, safi, true);
+	}
+}

 struct bgp_connected_ref {
 	unsigned int refcnt;
@@ -439,10 +483,10 @@ void bgp_connected_add(struct bgp *bgp, struct connected *ifc)
 		}
 	}

-	/*
-	 * Iterate over all the peers and attempt to set the bfd session
-	 * data and if it's a bgp unnumbered get her flowing if necessary
-	 */
+	/* Refresh peer interfaces after connected addresses change. */
+	bgp_connected_peer_nexthop_update(bgp);
+
+	/* If it's a BGP unnumbered get her flowing if necessary. */
 	for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) {
 		bgp_peer_bfd_update_source(peer);
 		if (peer->conf_if && (strcmp(peer->conf_if, ifc->ifp->name) == 0) &&
@@ -472,6 +516,7 @@ void bgp_connected_delete(struct bgp *bgp, struct connected *ifc)
 			return;

 		bgp_address_del(bgp, ifc, addr);
+		bgp_connected_peer_nexthop_update(bgp);

 		dest = bgp_node_lookup(bgp->connected_table[AFI_IP], &p);
 	} else if (addr->family == AF_INET6) {
@@ -482,6 +527,7 @@ void bgp_connected_delete(struct bgp *bgp, struct connected *ifc)
 			return;

 		bgp_address_del(bgp, ifc, addr);
+		bgp_connected_peer_nexthop_update(bgp);

 		dest = bgp_node_lookup(bgp->connected_table[AFI_IP6], &p);
 	}