Commit b6b5333f94 for frr

commit b6b5333f945973c293f73fe64091d160821c7561
Author: Harini Nattamai Subramanian <hnattamaisub@nvidia.com>
Date:   Sun Oct 25 23:28:49 2026 -0700

    bgpd: [EVPN] show command to display prefixes suppressed by skip-evpn-imported

    Added a new show command via vtysh to display the suppressed prefix
    due to "skip-evpn-imported"

    Fix:
    1)Adds a new per-path flag BGP_PATH_EVPN_TYPE5_SKIP_IMPORTED (bit 23)
    in bgp_route.h that marks a path whose Type-5 export was suppressed
    by skip-evpn-imported.

    2)It is set in two places:
       is_route_injectable_into_evpn_non_supp =>steady-state suppression decision
       bgp_evpn_withdraw_imported_type5_leaked_routes => for routes withdraw
    retroactively when the knob is first enabled.

    3)Unset is done in is_route_injectable_into_evpn_non_supp

    4)New command "show bgp vrf VRFNAME <ipv4|ipv6> unicast PREFIX
    skip-evpn-imported [json]" does an exact-prefix lookup and displays the
    paths carrying the flag, reusing route_vty_out_detail_header() and
    route_vty_out_detail() so the output matches the regular per-prefix show.
    Paths marked BGP_PATH_REMOVED are skipped.

    5)JSON output reports prefix, pathCount and paths, and is emitted through
    the common vty_json()/vty_json_empty() helpers so the json_object is
    freed by them rather than by hand. An empty result prints "{}".

    The flag is display-only state: it is written by the suppression paths
    and read only by this show command, nothing in the export decision
    consults it.

    Logs:
    tor-11# show bgp vrf blue ipv4 unicast 198.18.82.1/32 skip-evpn-imported
    EVPN Type-5 export suppressed by skip-evpn-imported

    BGP routing table entry for 198.18.82.1/32, version 12
    Paths: (1 available, best #1, vrf blue)
      Not advertised to any peer
      Imported from 10.10.3.11:3:198.18.82.1/32
      Local
        10.10.3.13(tor-11) (metric 20) from 0.0.0.0 (10.10.3.11) vrf green(21)
          Origin incomplete, metric 0, localpref 100, valid, sourced, local, bestpath-from-AS Local, best (First path received)
          Originator: 10.10.3.11, Cluster list: 10.10.1.1
          Last update: Wed Sep 23 05:19:24 2026

    Displayed 1 suppressed path
    tor-11# show bgp vrf blue ipv4 unicast 198.18.82.2/32 skip-evpn-imported
    No paths for this prefix are suppressed by skip-evpn-imported
    tor-11#

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

diff --git a/bgpd/bgp_evpn.c b/bgpd/bgp_evpn.c
index 5325e39d51..1455f3ea3c 100644
--- a/bgpd/bgp_evpn.c
+++ b/bgpd/bgp_evpn.c
@@ -868,9 +868,14 @@ bool is_route_injectable_into_evpn_non_supp(struct bgp *bgp_vrf, afi_t afi, safi
 		if (BGP_DEBUG(vpn, VPN_LEAK_FROM_VRF) || BGP_DEBUG(vpn, VPN_LEAK_TO_VRF))
 			zlog_debug("vrf %s: skip EVPN re-export of EVPN-derived prefix %pFX",
 				   bgp_vrf->name_pretty, bgp_dest_get_prefix(pi->net));
+		SET_FLAG(pi->flags, BGP_PATH_EVPN_TYPE5_SKIP_IMPORTED);
 		return false;
 	}

+	/* Not suppressed - clear any stale mark */
+	if (CHECK_FLAG(pi->flags, BGP_PATH_EVPN_TYPE5_SKIP_IMPORTED))
+		UNSET_FLAG(pi->flags, BGP_PATH_EVPN_TYPE5_SKIP_IMPORTED);
+
 	if (safi == SAFI_MPLS_VPN) {
 		if (pi->peer != bgp_vrf->peer_self)
 			return false;
@@ -6508,6 +6513,7 @@ void bgp_evpn_withdraw_imported_type5_leaked_routes(struct bgp *bgp_vrf, afi_t a
 					   addpath_id);
 			bgp_evpn_withdraw_type5_route(bgp_vrf, src_pi, bgp_dest_get_prefix(dest),
 						      afi, SAFI_UNICAST, addpath_id);
+			SET_FLAG(src_pi->flags, BGP_PATH_EVPN_TYPE5_SKIP_IMPORTED);
 		}
 	}
 }
diff --git a/bgpd/bgp_evpn_vty.c b/bgpd/bgp_evpn_vty.c
index fae02e8d0f..1bbab26ba2 100644
--- a/bgpd/bgp_evpn_vty.c
+++ b/bgpd/bgp_evpn_vty.c
@@ -4716,6 +4716,123 @@ DEFPY (no_bgp_evpn_advertise_type5,
 	return CMD_SUCCESS;
 }

+DEFPY (show_bgp_vrf_unicast_skip_evpn_imported,
+       show_bgp_vrf_unicast_skip_evpn_imported_cmd,
+       "show bgp vrf VRFNAME$vrf_name <ipv4|ipv6>$afi_str unicast "
+       "<A.B.C.D/M|X:X::X:X/M>$prefix skip-evpn-imported [json$json]",
+       SHOW_STR
+       BGP_STR
+       "VRF\n"
+       "VRF name\n"
+       BGP_AFI_HELP_STR
+       "Unicast\n"
+       "IPv4 prefix\n"
+       "IPv6 prefix\n"
+       "Display paths suppressed by skip-evpn-imported\n"
+       JSON_STR)
+{
+	struct bgp *bgp_vrf;
+	struct bgp_table *table;
+	struct bgp_dest *dest;
+	struct bgp_path_info *pi;
+	json_object *json_out;
+	json_object *json_paths = NULL;
+	afi_t afi = strmatch(afi_str, "ipv4") ? AFI_IP : AFI_IP6;
+	unsigned int count = 0;
+	bool use_json = !!json;
+
+	if (family2afi(prefix->family) != afi) {
+		if (use_json)
+			vty_json_empty(vty, NULL);
+		else
+			vty_out(vty, "%% Invalid %s prefix\n", afi_str);
+		return CMD_WARNING;
+	}
+
+	bgp_vrf = strmatch(vrf_name, VRF_DEFAULT_NAME)
+			  ? bgp_get_default()
+			  : bgp_lookup_by_name(vrf_name);
+	if (!bgp_vrf || IS_BGP_INSTANCE_HIDDEN(bgp_vrf)) {
+		if (use_json)
+			vty_json_empty(vty, NULL);
+		else
+			vty_out(vty, "%% Specified BGP instance not found\n");
+		return CMD_WARNING;
+	}
+
+	/* If the feature knob itself is not enabled, nothing is suppressed by it. */
+	if (!CHECK_FLAG(bgp_vrf->af_flags[AFI_L2VPN][SAFI_EVPN],
+			afi == AFI_IP ? BGP_L2VPN_EVPN_SUPPRESS_IPV4_IMPORT_FROM_EVPN
+				      : BGP_L2VPN_EVPN_SUPPRESS_IPV6_IMPORT_FROM_EVPN))
+		goto not_suppressed;
+
+	table = bgp_vrf->rib[afi][SAFI_UNICAST];
+	if (!table)
+		goto not_suppressed;
+
+	/* Look up the exact prefix */
+	dest = bgp_node_lookup(table, prefix);
+	if (!dest || !bgp_dest_has_bgp_path_info_data(dest)) {
+		if (dest)
+			bgp_dest_unlock_node(dest);
+		if (use_json)
+			vty_json_empty(vty, NULL);
+		else
+			vty_out(vty, "%% Network not in table\n");
+		return CMD_SUCCESS;
+	}
+
+	for (pi = bgp_dest_get_bgp_path_info(dest); pi; pi = pi->next) {
+		if (!CHECK_FLAG(pi->flags, BGP_PATH_EVPN_TYPE5_SKIP_IMPORTED) ||
+		    CHECK_FLAG(pi->flags, BGP_PATH_REMOVED))
+			continue;
+
+		/* Allocate the array only once a path matches, so the no-match
+		 * case below has nothing to release.
+		 */
+		if (!count) {
+			if (use_json) {
+				json_paths = json_object_new_array();
+			} else {
+				vty_out(vty,
+					"EVPN Type-5 export suppressed by skip-evpn-imported\n\n");
+				route_vty_out_detail_header(vty, bgp_vrf, dest,
+							    bgp_dest_get_prefix(dest), NULL, afi,
+							    SAFI_UNICAST, NULL, false, false);
+			}
+		}
+		route_vty_out_detail(vty, bgp_vrf, dest,
+				     bgp_dest_get_prefix(dest), pi, afi, SAFI_UNICAST,
+				     RPKI_NOT_BEING_USED, json_paths, NULL, 0);
+		count++;
+	}
+
+	bgp_dest_unlock_node(dest);
+
+	if (!count)
+		goto not_suppressed;
+
+	if (use_json) {
+		json_out = json_object_new_object();
+		json_object_string_addf(json_out, "prefix", "%pFX", prefix);
+		json_object_int_add(json_out, "pathCount", count);
+		json_object_object_add(json_out, "paths", json_paths);
+		return vty_json(vty, json_out);
+	}
+
+	vty_out(vty, "\nDisplayed %u suppressed path%s\n", count,
+		count == 1 ? "" : "s");
+	return CMD_SUCCESS;
+
+not_suppressed:
+	if (use_json)
+		vty_json_empty(vty, NULL);
+	else
+		vty_out(vty,
+			"No paths for this prefix are suppressed by skip-evpn-imported\n");
+	return CMD_SUCCESS;
+}
+
 DEFPY (bgp_evpn_use_es_l3nhg,
        bgp_evpn_use_es_l3nhg_cmd,
        "[no$no] use-es-l3nhg",
@@ -8376,6 +8493,8 @@ void bgp_ethernetvpn_init(void)
 			&show_bgp_l2vpn_evpn_route_mac_ip_global_es_cmd);
 	install_element(VIEW_NODE, &show_bgp_l2vpn_evpn_import_rt_cmd);
 	install_element(VIEW_NODE, &show_bgp_l2vpn_evpn_vrf_import_rt_cmd);
+	install_element(VIEW_NODE,
+			&show_bgp_vrf_unicast_skip_evpn_imported_cmd);

 	/* "show bgp vni" commands. */
 	install_element(VIEW_NODE, &show_bgp_vni_all_cmd);
diff --git a/bgpd/bgp_route.h b/bgpd/bgp_route.h
index adeabe36bb..8d948ac28d 100644
--- a/bgpd/bgp_route.h
+++ b/bgpd/bgp_route.h
@@ -396,6 +396,8 @@ struct bgp_path_info {
 #define BGP_PATH_UPA                                                                              \
 	(1 << 22) /* Route has UPA marking (locally originated or received with UPA ExtCom) */
 #define BGP_PATH_UPA_DROP (1 << 23) /* UPA route has D-bit set (drop/blackhole) */
+/* Type-5 export was suppressed by skip-evpn-imported. */
+#define BGP_PATH_EVPN_TYPE5_SKIP_IMPORTED (1 << 24)

 	/* BGP route type.  This can be static, RIP, OSPF, BGP etc.  */
 	uint8_t type;