From a486300b2679ff80a13d800ed76e1236edfcaa2b Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Fri, 1 Jul 2022 14:50:40 +0200 Subject: [PATCH] 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 --- bgpd/bgp_mplsvpn.c | 16 +++++++---- bgpd/bgp_mplsvpn.h | 13 +++++++-- bgpd/bgp_route.c | 21 +++++++++++--- bgpd/bgp_vty.c | 70 ++++++++++++++++++++++++++++++++++++++++++---- bgpd/bgp_vty.h | 1 + bgpd/bgpd.c | 2 ++ bgpd/bgpd.h | 2 ++ doc/user/bgp.rst | 8 ++++++ 8 files changed, 114 insertions(+), 19 deletions(-) diff --git a/bgpd/bgp_mplsvpn.c b/bgpd/bgp_mplsvpn.c index 52180b3e48..6c294f1d1e 100644 --- a/bgpd/bgp_mplsvpn.c +++ b/bgpd/bgp_mplsvpn.c @@ -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 */ diff --git a/bgpd/bgp_mplsvpn.h b/bgpd/bgp_mplsvpn.h index fcabb16435..8b081807df 100644 --- a/bgpd/bgp_mplsvpn.h +++ b/bgpd/bgp_mplsvpn.h @@ -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 != diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index b35cbeb21f..0639dba622 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -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; diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index 19901792ea..0858ca5c11 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -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); diff --git a/bgpd/bgp_vty.h b/bgpd/bgp_vty.h index 143d3c1ac5..bdaa620549 100644 --- a/bgpd/bgp_vty.h +++ b/bgpd/bgp_vty.h @@ -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); diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index 122830343c..bfbf959e7f 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -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); diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index 7f3d240b8e..a7ac923326 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -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]; diff --git a/doc/user/bgp.rst b/doc/user/bgp.rst index 28f59f205f..daaf80ae07 100644 --- a/doc/user/bgp.rst +++ b/doc/user/bgp.rst @@ -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 -- 2.39.5