Commit 5ce1c40445 for frr

commit 5ce1c40445f40a88df7dd8ee3c47548f03ee21ee
Author: Harini Nattamai Subramanian <hnattamaisub@nvidia.com>
Date:   Thu Oct 22 21:07:04 2026 -0700

    bgpd: trigger inbound policy re-evaluation on prefix-list changes

    Rootcause:
    peer_prefix_list_update() re-resolves the cached prefix-list pointer for
    every peer when a prefix-list is created, modified or deleted, but only
    re-evaluates already received routes for peers that negotiated ORF.
    Refreshing the pointer governs updates received from then on; routes
    already held in Adj-RIB-In keep the verdict reached under the previous
    state of the list.

    If user attaches an inbound prefix-list to a peer before the
    list itself is defined. The binding briefly resolves to NULL, which
    prefix_list_apply() treats as deny, so soft reconfiguration withdraws
    every prefix learnt from those peers. When the list is created a moment
    later the pointer is fixed up, but the withdrawals are never revisited:
    the peers stay at zero accepted prefixes with their sessions
    Established and both NVUE and FRR showing the intended configuration.
    The state persists until 'clear bgp <afi> <safi> * soft in' is run by
    hand.

    Fix:
    Call peer_on_policy_change() for peers whose inbound prefix-list names
    the list that changed, so stored routes are filtered again as soon as
    the list exists. Peer-group members are covered because the binding is
    copied into each member's own filter. ORF peers are left on their
    existing path, which already pushes the new list to the sender.

    Peers that also have an inbound route-map matching the same prefix-list
    are skipped, since the route-map delay timer re-evaluates them and doing
    both would ignore the configured delay. route_map_depends_on() is added
    to report that dependency.

    The same gap was fixed for AS-path access-lists in commit 6b5828d651
    ("bgpd: trigger inbound policy re-evaluation on AS-path list changes").

    Signed-off-by: Harini Nattamai Subramanian <hnattamaisub@nvidia.com>

diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c
index e5d6403a15..b98acd4231 100644
--- a/bgpd/bgpd.c
+++ b/bgpd/bgpd.c
@@ -8286,6 +8286,22 @@ int peer_prefix_list_unset(struct peer *peer, afi_t afi, safi_t safi,
 	return 0;
 }

+/*
+ * True if this peer's inbound route-map depends on the changed prefix-list and
+ * the route-map delay timer is enabled.
+ */
+static bool peer_inbound_rmap_with_delay_timer_depends_on_plist(
+	struct peer *peer, afi_t afi, safi_t safi, struct prefix_list *plist)
+{
+	struct bgp_filter *filter = &peer->filter[afi][safi];
+
+	if (!bm->rmap_update_timer || !filter->map[RMAP_IN].name)
+		return false;
+
+	return route_map_depends_on(RMAP_EVENT_PLIST_ADDED, prefix_list_name(plist),
+				    filter->map[RMAP_IN].name);
+}
+
 /* Update prefix-list list. */
 static void peer_prefix_list_update(struct prefix_list *plist)
 {
@@ -8336,6 +8352,13 @@ static void peer_prefix_list_update(struct prefix_list *plist)
 					peer_clear_soft(
 						peer, afi, safi,
 						BGP_CLEAR_SOFT_IN_ORF_PREFIX);
+				else if (plist && prefix_list_afi(plist) == afi &&
+					 filter->plist[FILTER_IN].name &&
+					 strmatch(filter->plist[FILTER_IN].name,
+						  prefix_list_name(plist)) &&
+						 !peer_inbound_rmap_with_delay_timer_depends_on_plist(
+							 peer, afi, safi, plist))
+					peer_on_policy_change(peer, afi, safi, 0);
 			}
 		}
 		for (ALL_LIST_ELEMENTS(bgp->group, node, nnode, group)) {
diff --git a/lib/routemap.c b/lib/routemap.c
index 69c3558388..62635c1f38 100644
--- a/lib/routemap.c
+++ b/lib/routemap.c
@@ -3121,6 +3121,30 @@ void route_map_upd8_dependency(route_map_event_t type, const char *arg,
 	}
 }

+/*
+ * Answers whether `rmap_name' depends on `dep_name', using the same lookup
+ * route_map_notify_dependencies() does.
+ */
+bool route_map_depends_on(route_map_event_t event, const char *dep_name, const char *rmap_name)
+{
+	struct route_map_dep_data tmp_dep_data = { .rname = (char *)rmap_name };
+	struct route_map_dep *dep;
+	struct hash *upd8_hash;
+
+	if (!dep_name || !rmap_name)
+		return false;
+
+	upd8_hash = route_map_get_dep_hash(event);
+	if (!upd8_hash)
+		return false;
+
+	dep = hash_lookup(upd8_hash, (void *)dep_name);
+	if (!dep)
+		return false;
+
+	return hash_lookup(dep->dep_rmap_hash, &tmp_dep_data) != NULL;
+}
+
 void route_map_notify_dependencies(const char *affected_name,
 				   route_map_event_t event)
 {
diff --git a/lib/routemap.h b/lib/routemap.h
index 0dbe90df86..835f99dbf4 100644
--- a/lib/routemap.h
+++ b/lib/routemap.h
@@ -552,6 +552,8 @@ extern void
 route_map_notify_pentry_dependencies(const char *affected_name,
 				     struct prefix_list_entry *pentry,
 				     route_map_event_t event);
+extern bool route_map_depends_on(route_map_event_t event, const char *dep_name,
+				 const char *rmap_name);
 extern int generic_match_add(struct route_map_index *index,
 			     const char *command, const char *arg,
 			     route_map_event_t type,