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;