Commit a3734e45da for frr

commit a3734e45daf2ce99216cf56e4696c5324ac951d3
Author: Sougata Barik <sougatab@nvidia.com>
Date:   Wed Nov 4 13:12:17 2026 +0530

    bgpd: key a single-hop BFD session on the longest connected match

    Problem:
    With overlapping connected subnets, a single-hop BGP BFD session can be
    keyed on a different interface than the one BGP uses.  With 10.0.0.1/16
    on eth0 and 10.0.1.1/24 on eth1, a peer at 10.0.1.2 is reached over
    eth1, but the session is installed on eth0.  bfdd binds the session to
    eth0, nobody answers there, and BFD stays Down; with bfd strict BGP
    never comes up.

    RCA:
    bgp_peer_bfd_egress_ifp() resolves the egress interface from the
    connected routes with if_lookup_by_ipv4()/if_lookup_by_ipv6(), which
    return the first interface whose connected prefix holds the address, not
    the most specific one.  The result is preferred over p->nexthop.ifp, so
    it is not corrected when TCP connects.

    Fix:
    Use if_lookup_address(), which returns the longest match.  It still
    only depends on the connected routes, so the interface is the same
    before and after TCP connects.

    Ticket: #5391569

    Signed-off-by: Sougata Barik <sougatab@nvidia.com>

diff --git a/bgpd/bgp_bfd.c b/bgpd/bgp_bfd.c
index a4601ceb68..2d13ba58c4 100644
--- a/bgpd/bgp_bfd.c
+++ b/bgpd/bgp_bfd.c
@@ -207,10 +207,17 @@ static struct interface *bgp_peer_bfd_egress_ifp(struct peer *p)
 		ifp = if_lookup_by_name(p->update_if, vrf_id);
 	else if (ifname)
 		ifp = if_lookup_by_name(ifname, vrf_id);
-	else if (su->sa.sa_family == AF_INET)
-		ifp = if_lookup_by_ipv4(&su->sin.sin_addr, vrf_id);
-	else
-		ifp = if_lookup_by_ipv6(&su->sin6.sin6_addr, 0, vrf_id);
+	else {
+		/* Longest match: with overlapping subnets the first one can be the wrong link. */
+		struct connected *c;
+
+		if (su->sa.sa_family == AF_INET)
+			c = if_lookup_address(&su->sin.sin_addr, AF_INET, vrf_id);
+		else
+			c = if_lookup_address(&su->sin6.sin6_addr, AF_INET6, vrf_id);
+		if (c)
+			ifp = c->ifp;
+	}

 	return ifp ? ifp : p->nexthop.ifp;
 }