]> git.proxmox.com Git - mirror_frr.git/commitdiff
bgpd: implement retain route-target all behaviour
authorPhilippe Guibert <philippe.guibert@6wind.com>
Fri, 1 Jul 2022 12:50:40 +0000 (14:50 +0200)
committerPhilippe Guibert <philippe.guibert@6wind.com>
Mon, 18 Jul 2022 06:57:19 +0000 (08:57 +0200)
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>
bgpd/bgp_mplsvpn.c
bgpd/bgp_mplsvpn.h
bgpd/bgp_route.c
bgpd/bgp_vty.c
bgpd/bgp_vty.h
bgpd/bgpd.c
bgpd/bgpd.h
doc/user/bgp.rst

index 52180b3e48d32440f8952651ea31502095dad99a..6c294f1d1ec01523a10e5db645a3464a4fd908a5 100644 (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 */
index fcabb164354a758226dc700a715af98f75b25871..8b081807df3fbc431cc04af0e64041da99e96cc1 100644 (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 !=
index b35cbeb21f6b3eef26db041c282c60e4c1f80bf1..0639dba622224d8e4c80193617726a2c7b960e15 100644 (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;
 
index 19901792ea456d70c855ca8c7f760fbd1b746c7a..0858ca5c11014a370f4fe196d3883b5e5f3b3127 100644 (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);
 
index 143d3c1ac5f02efc2bd602508afbe0b829d60e0c..bdaa62054969270f6da1ffa76c7a36c5d2963da2 100644 (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);
index 122830343ca568ac7ebe8a8a8b2ca40cc7d02bda..bfbf959e7f92f74094fad20b5a2f438eb442605a 100644 (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);
index 7f3d240b8ea20d713ad24b3322b11b73fc201f6a..a7ac923326d6d25e0a042047a185a4263f093e47 100644 (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];
index 28f59f205fb59781ce2b985f3b0a3a28d0fdbe69..daaf80ae073aff2499b5da26f05f5629bf6a3e89 100644 (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