bgpd: implement retain route-target all behaviour

A new command is available under SAFI_MPLS_VPN:

With this command, the BGP vpnvx prefixes received are
not kept, if there are no VRF interested in importing
those vpn entries.

A soft refresh is performed if there is a change of
configuration: retain cmd, vrf import settings, or
route-map change.

Signed-off-by: Philippe Guibert <philippe.guibert@6wind.com>
This commit is contained in:
Philippe Guibert 2022-07-01 14:50:40 +02:00
parent 1004137bf3
commit a486300b26
8 changed files with 114 additions and 19 deletions

View file

@ -1472,7 +1472,7 @@ void vpn_leak_from_vrf_update_all(struct bgp *to_bgp, struct bgp *from_bgp,
}
}
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 */
@ -1498,7 +1498,7 @@ vpn_leak_to_vrf_update_onevrf(struct bgp *to_bgp, /* to */
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 */
@ -1509,7 +1509,7 @@ vpn_leak_to_vrf_update_onevrf(struct bgp *to_bgp, /* to */
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)
@ -1604,7 +1604,7 @@ vpn_leak_to_vrf_update_onevrf(struct bgp *to_bgp, /* to */
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
@ -1674,13 +1674,15 @@ vpn_leak_to_vrf_update_onevrf(struct bgp *to_bgp, /* to */
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);
@ -1692,9 +1694,11 @@ void vpn_leak_to_vrf_update(struct bgp *from_bgp, /* from */
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 */

View file

@ -25,6 +25,7 @@
#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) \
@ -70,7 +71,7 @@ extern void vpn_leak_to_vrf_withdraw_all(struct bgp *to_bgp, afi_t afi);
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,
@ -233,8 +234,14 @@ static inline void vpn_leak_postchange(enum vpn_policy_direction direction,
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 !=

View file

@ -3785,6 +3785,7 @@ int bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id,
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];
@ -4410,7 +4411,7 @@ int bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id,
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
@ -4425,7 +4426,13 @@ int bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id,
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
@ -4559,8 +4566,7 @@ int bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id,
}
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) {
@ -4574,6 +4580,13 @@ int bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id,
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;

View file

@ -951,14 +951,24 @@ static void bgp_clear_vty_error(struct vty *vty, struct peer *peer, afi_t afi,
{
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;
@ -1274,6 +1284,11 @@ static void bgp_clear_star_soft_out(struct vty *vty, const char *name)
}
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
@ -16315,6 +16330,34 @@ DEFUN(no_neighbor_tcp_mss, no_neighbor_tcp_mss_cmd,
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)
{
@ -17197,6 +17240,14 @@ static void bgp_config_write_peer_af(struct vty *vty, struct bgp *bgp,
}
}
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)
@ -17267,6 +17318,9 @@ static void bgp_config_write_family(struct vty *vty, struct bgp *bgp, afi_t afi,
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],
@ -19251,6 +19305,10 @@ void bgp_vty_init(void)
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);

View file

@ -152,6 +152,7 @@ struct bgp;
"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);

View file

@ -3240,6 +3240,8 @@ static struct bgp *bgp_create(as_t *as, const char *name,
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);

View file

@ -527,6 +527,8 @@ struct bgp {
/* 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];

View file

@ -2827,6 +2827,14 @@ address-family:
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