}
}
-static void
+static bool
vpn_leak_to_vrf_update_onevrf(struct bgp *to_bgp, /* to */
struct bgp *from_bgp, /* from */
struct bgp_path_info *path_vpn) /* route */
if (!vpn_leak_from_vpn_active(to_bgp, afi, &debugmsg)) {
if (debug)
zlog_debug("%s: skipping: %s", __func__, debugmsg);
- return;
+ return false;
}
/* Check for intersection of route targets */
zlog_debug(
"from vpn (%s) to vrf (%s), skipping after no intersection of route targets",
from_bgp->name_pretty, to_bgp->name_pretty);
- return;
+ return false;
}
if (debug)
to_bgp->vpn_policy[afi]
.rmap[BGP_VPN_POLICY_DIR_FROMVPN]
->name);
- return;
+ return false;
}
/*
* if route-map changed nexthop, don't nexthop-self on output
leak_update(to_bgp, bn, new_attr, afi, safi, path_vpn, pLabels,
num_labels, src_vrf, &nexthop_orig, nexthop_self_flag,
debug);
+ return true;
}
-void vpn_leak_to_vrf_update(struct bgp *from_bgp, /* from */
+bool vpn_leak_to_vrf_update(struct bgp *from_bgp, /* from */
struct bgp_path_info *path_vpn) /* route */
{
struct listnode *mnode, *mnnode;
struct bgp *bgp;
+ bool leak_success = false;
int debug = BGP_DEBUG(vpn, VPN_LEAK_TO_VRF);
if (!path_vpn->extra
|| path_vpn->extra->bgp_orig != bgp) { /* no loop */
- vpn_leak_to_vrf_update_onevrf(bgp, from_bgp, path_vpn);
+ leak_success |= vpn_leak_to_vrf_update_onevrf(
+ bgp, from_bgp, path_vpn);
}
}
+ return leak_success;
}
void vpn_leak_to_vrf_withdraw(struct bgp *from_bgp, /* from */
#include "bgpd/bgp_route.h"
#include "bgpd/bgp_rd.h"
#include "bgpd/bgp_zebra.h"
+#include "bgpd/bgp_vty.h"
#define MPLS_LABEL_IS_SPECIAL(label) ((label) <= MPLS_LABEL_EXTENSION)
#define MPLS_LABEL_IS_NULL(label) \
extern void vpn_leak_to_vrf_update_all(struct bgp *to_bgp, struct bgp *from_bgp,
afi_t afi);
-extern void vpn_leak_to_vrf_update(struct bgp *from_bgp,
+extern bool vpn_leak_to_vrf_update(struct bgp *from_bgp,
struct bgp_path_info *path_vpn);
extern void vpn_leak_to_vrf_withdraw(struct bgp *from_bgp,
if (!bgp_vpn)
return;
- if (direction == BGP_VPN_POLICY_DIR_FROMVPN)
- vpn_leak_to_vrf_update_all(bgp_vrf, bgp_vpn, afi);
+ if (direction == BGP_VPN_POLICY_DIR_FROMVPN) {
+ /* trigger a flush to re-sync with ADJ-RIB-in */
+ if (!CHECK_FLAG(bgp_vpn->af_flags[afi][SAFI_MPLS_VPN],
+ BGP_VPNVX_RETAIN_ROUTE_TARGET_ALL))
+ bgp_clear_soft_in(bgp_vpn, afi, SAFI_MPLS_VPN);
+ else
+ vpn_leak_to_vrf_update_all(bgp_vrf, bgp_vpn, afi);
+ }
if (direction == BGP_VPN_POLICY_DIR_TOVPN) {
if (bgp_vrf->vpn_policy[afi].tovpn_label !=
uint8_t pi_sub_type = 0;
bool force_evpn_import = false;
safi_t orig_safi = safi;
+ bool leak_success = true;
if (frrtrace_enabled(frr_bgp, process_update)) {
char pfxprint[PREFIX2STR_BUFFER];
if ((SAFI_MPLS_VPN == safi)
&& (bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT)) {
- vpn_leak_to_vrf_update(bgp, pi);
+ leak_success = vpn_leak_to_vrf_update(bgp, pi);
}
#ifdef ENABLE_BGP_VNC
type, sub_type, NULL);
}
#endif
-
+ if ((safi == SAFI_MPLS_VPN) &&
+ !CHECK_FLAG(bgp->af_flags[afi][safi],
+ BGP_VPNVX_RETAIN_ROUTE_TARGET_ALL) &&
+ !leak_success) {
+ bgp_unlink_nexthop(pi);
+ bgp_path_info_delete(dest, pi);
+ }
return 0;
} // End of implicit withdraw
}
if ((SAFI_MPLS_VPN == safi)
&& (bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT)) {
-
- vpn_leak_to_vrf_update(bgp, new);
+ leak_success = vpn_leak_to_vrf_update(bgp, new);
}
#ifdef ENABLE_BGP_VNC
if (SAFI_MPLS_VPN == safi) {
sub_type, NULL);
}
#endif
+ if ((safi == SAFI_MPLS_VPN) &&
+ !CHECK_FLAG(bgp->af_flags[afi][safi],
+ BGP_VPNVX_RETAIN_ROUTE_TARGET_ALL) &&
+ !leak_success) {
+ bgp_unlink_nexthop(new);
+ bgp_path_info_delete(dest, new);
+ }
return 0;
{
switch (error) {
case BGP_ERR_AF_UNCONFIGURED:
- vty_out(vty,
- "%% BGP: Enable %s address family for the neighbor %s\n",
- get_afi_safi_str(afi, safi, false), peer->host);
+ if (vty)
+ vty_out(vty,
+ "%% BGP: Enable %s address family for the neighbor %s\n",
+ get_afi_safi_str(afi, safi, false), peer->host);
+ else
+ zlog_warn(
+ "%% BGP: Enable %s address family for the neighbor %s\n",
+ get_afi_safi_str(afi, safi, false), peer->host);
break;
case BGP_ERR_SOFT_RECONFIG_UNCONFIGURED:
- vty_out(vty,
- "%% BGP: Inbound soft reconfig for %s not possible as it\n has neither refresh capability, nor inbound soft reconfig\n",
- peer->host);
+ if (vty)
+ vty_out(vty,
+ "%% BGP: Inbound soft reconfig for %s not possible as it\n has neither refresh capability, nor inbound soft reconfig\n",
+ peer->host);
+ else
+ zlog_warn(
+ "%% BGP: Inbound soft reconfig for %s not possible as it\n has neither refresh capability, nor inbound soft reconfig\n",
+ peer->host);
break;
default:
break;
}
+void bgp_clear_soft_in(struct bgp *bgp, afi_t afi, safi_t safi)
+{
+ bgp_clear(NULL, bgp, afi, safi, clear_all, BGP_CLEAR_SOFT_IN, NULL);
+}
+
#ifndef VTYSH_EXTRACT_PL
#include "bgpd/bgp_vty_clippy.c"
#endif
return peer_tcp_mss_vty(vty, argv[peer_index]->arg, NULL);
}
+DEFPY(bgp_retain_route_target, bgp_retain_route_target_cmd,
+ "[no$no] bgp retain route-target all",
+ NO_STR BGP_STR
+ "Retain BGP updates\n"
+ "Retain BGP updates based on route-target values\n"
+ "Retain all BGP updates\n")
+{
+ bool check;
+ struct bgp *bgp = VTY_GET_CONTEXT(bgp);
+
+ check = CHECK_FLAG(bgp->af_flags[bgp_node_afi(vty)][bgp_node_safi(vty)],
+ BGP_VPNVX_RETAIN_ROUTE_TARGET_ALL);
+ if (check != !no) {
+ if (!no)
+ SET_FLAG(bgp->af_flags[bgp_node_afi(vty)]
+ [bgp_node_safi(vty)],
+ BGP_VPNVX_RETAIN_ROUTE_TARGET_ALL);
+ else
+ UNSET_FLAG(bgp->af_flags[bgp_node_afi(vty)]
+ [bgp_node_safi(vty)],
+ BGP_VPNVX_RETAIN_ROUTE_TARGET_ALL);
+ /* trigger a flush to re-sync with ADJ-RIB-in */
+ bgp_clear(vty, bgp, bgp_node_afi(vty), bgp_node_safi(vty),
+ clear_all, BGP_CLEAR_SOFT_IN, NULL);
+ }
+ return CMD_SUCCESS;
+}
+
static void bgp_config_write_redistribute(struct vty *vty, struct bgp *bgp,
afi_t afi, safi_t safi)
{
}
}
+static void bgp_vpn_config_write(struct vty *vty, struct bgp *bgp, afi_t afi,
+ safi_t safi)
+{
+ if (!CHECK_FLAG(bgp->af_flags[afi][safi],
+ BGP_VPNVX_RETAIN_ROUTE_TARGET_ALL))
+ vty_out(vty, " no bgp retain route-target all\n");
+}
+
/* Address family based peer configuration display. */
static void bgp_config_write_family(struct vty *vty, struct bgp *bgp, afi_t afi,
safi_t safi)
if (safi == SAFI_FLOWSPEC)
bgp_fs_config_write_pbr(vty, bgp, afi, safi);
+ if (safi == SAFI_MPLS_VPN)
+ bgp_vpn_config_write(vty, bgp, afi, safi);
+
if (safi == SAFI_UNICAST) {
bgp_vpn_policy_config_write_afi(vty, bgp, afi);
if (CHECK_FLAG(bgp->af_flags[afi][safi],
install_element(BGP_FLOWSPECV6_NODE, &exit_address_family_cmd);
install_element(BGP_EVPN_NODE, &exit_address_family_cmd);
+ /* BGP retain all route-target */
+ install_element(BGP_VPNV4_NODE, &bgp_retain_route_target_cmd);
+ install_element(BGP_VPNV6_NODE, &bgp_retain_route_target_cmd);
+
/* "clear ip bgp commands" */
install_element(ENABLE_NODE, &clear_ip_bgp_all_cmd);
"endOfRibSentAfterUpdate"); \
} while (0)
+extern void bgp_clear_soft_in(struct bgp *bgp, afi_t afi, safi_t safi);
extern void bgp_vty_init(void);
extern void community_alias_vty(void);
extern const char *get_afi_safi_str(afi_t afi, safi_t safi, bool for_json);
bgp->vpn_policy[afi].export_vrf = list_new();
bgp->vpn_policy[afi].export_vrf->del =
bgp_vrf_string_name_delete;
+ SET_FLAG(bgp->af_flags[afi][SAFI_MPLS_VPN],
+ BGP_VPNVX_RETAIN_ROUTE_TARGET_ALL);
}
if (name)
bgp->name = XSTRDUP(MTYPE_BGP, name);
/* vrf-route leaking flags */
#define BGP_CONFIG_VRF_TO_VRF_IMPORT (1 << 9)
#define BGP_CONFIG_VRF_TO_VRF_EXPORT (1 << 10)
+/* vpnvx retain flag */
+#define BGP_VPNVX_RETAIN_ROUTE_TARGET_ALL (1 << 11)
/* BGP per AF peer count */
uint32_t af_peer_count[AFI_MAX][SAFI_MAX];
The CLI will disallow attempts to configure incompatible leaking
modes.
+.. clicmd:: bgp retain route-target all
+
+It is possible to retain or not VPN prefixes that are not imported by local
+VRF configuration. This can be done via the following command in the context
+of the global VPNv4/VPNv6 family. This command defaults to on and is not
+displayed.
+The `no bgp retain route-target all` form of the command is displayed.
+
.. _bgp-l3vpn-srv6:
L3VPN SRv6