]> git.proxmox.com Git - mirror_frr.git/commitdiff
bgpd: Implement vrf - vrf route leaking cli
authorDonald Sharp <sharpd@cumulusnetworks.com>
Mon, 19 Mar 2018 19:41:17 +0000 (15:41 -0400)
committerDonald Sharp <sharpd@cumulusnetworks.com>
Wed, 25 Apr 2018 16:39:16 +0000 (12:39 -0400)
add the `import vrf XXXX` command

router bgp 4 vrf DONNA
  <config>
!

router bgp 4 vrf EVA
  <config>
  address-family ipv4 uni
    import vrf DONNA
  !
!

This command will allow for vrf EVA to specify that it would like
to receive the routes from vrf DONNA into it's table.

Signed-off-by: Donald Sharp <sharpd@cumulusnetworks.com>
bgpd/bgp_mplsvpn.c
bgpd/bgp_mplsvpn.h
bgpd/bgp_vty.c
bgpd/bgpd.c
bgpd/bgpd.h

index 01068d17f41c07b22ddf0e8688b42287a07b1570..5a12e12c774cff07c0ef0282a68b8b55bc9ec44e 100644 (file)
@@ -640,8 +640,8 @@ void vpn_leak_from_vrf_update(struct bgp *bgp_vpn,       /* to */
                char *s = ecommunity_ecom2str(info_vrf->attr->ecommunity,
                                              ECOMMUNITY_FORMAT_ROUTE_MAP, 0);
 
-               zlog_debug("%s: info_vrf->type=%d, EC{%s}", __func__,
-                          info_vrf->type, s);
+               zlog_debug("%s: %s info_vrf->type=%d, EC{%s}", __func__,
+                          bgp_vrf->name, info_vrf->type, s);
                XFREE(MTYPE_ECOMMUNITY_STR, s);
        }
 
@@ -661,7 +661,8 @@ void vpn_leak_from_vrf_update(struct bgp *bgp_vpn,       /* to */
 
        if (!vpn_leak_to_vpn_active(bgp_vrf, afi, &debugmsg)) {
                if (debug)
-                       zlog_debug("%s: skipping: %s", __func__, debugmsg);
+                       zlog_debug("%s: %s skipping: %s", __func__,
+                                  bgp_vrf->name, debugmsg);
                return;
        }
 
@@ -737,9 +738,9 @@ void vpn_leak_from_vrf_update(struct bgp *bgp_vpn,       /* to */
        /* if policy nexthop not set, use 0 */
        if (CHECK_FLAG(bgp_vrf->vpn_policy[afi].flags,
                       BGP_VPN_POLICY_TOVPN_NEXTHOP_SET)) {
-
                struct prefix *nexthop =
                        &bgp_vrf->vpn_policy[afi].tovpn_nexthop;
+
                switch (nexthop->family) {
                case AF_INET:
                        /* prevent mp_nexthop_global_in <- self in bgp_route.c
@@ -759,12 +760,31 @@ void vpn_leak_from_vrf_update(struct bgp *bgp_vpn,       /* to */
                        assert(0);
                }
        } else {
-               if (afi == AFI_IP) {
-                       /* For ipv4, copy to multiprotocol nexthop field */
-                       static_attr.mp_nexthop_global_in = static_attr.nexthop;
-                       static_attr.mp_nexthop_len = 4;
-                       /* XXX Leave static_attr.nexthop intact for NHT */
-                       static_attr.flag &= ~ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP);
+               if (!CHECK_FLAG(bgp_vrf->af_flags[afi][SAFI_UNICAST],
+                               BGP_CONFIG_VRF_TO_VRF_EXPORT)) {
+                       if (afi == AFI_IP) {
+                               /* For ipv4, copy to multiprotocol nexthop field */
+                               static_attr.mp_nexthop_global_in = static_attr.nexthop;
+                               static_attr.mp_nexthop_len = 4;
+                               /* XXX Leave static_attr.nexthop intact for NHT */
+                               static_attr.flag &= ~ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP);
+                       }
+               } else {
+                       switch (afi) {
+                       case AFI_IP:
+                               static_attr.mp_nexthop_global_in.s_addr =
+                                       static_attr.nexthop.s_addr;
+                               static_attr.mp_nexthop_len = 4;
+                               static_attr.flag |=
+                                       ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP);
+                               break;
+                       case AFI_IP6:
+                               break;
+                       case AFI_L2VPN:
+                       case AFI_MAX:
+                               assert(!"Unexpected AFI to process");
+                               break;
+                       }
                }
                nexthop_self_flag = 1;
        }
@@ -1036,22 +1056,36 @@ static void vpn_leak_to_vrf_update_onevrf(struct bgp *bgp_vrf,       /* to */
        nexthop_orig.family = nhfamily;
 
        switch (nhfamily) {
-
        case AF_INET:
                /* save */
                nexthop_orig.u.prefix4 = info_vpn->attr->mp_nexthop_global_in;
                nexthop_orig.prefixlen = 32;
+
+               if (CHECK_FLAG(bgp_vrf->af_flags[afi][safi],
+                              BGP_CONFIG_VRF_TO_VRF_IMPORT)) {
+                       static_attr.nexthop.s_addr =
+                               nexthop_orig.u.prefix4.s_addr;
+
+                       static_attr.mp_nexthop_global_in =
+                               info_vpn->attr->mp_nexthop_global_in;
+                       static_attr.mp_nexthop_len =
+                               info_vpn->attr->mp_nexthop_len;
+               }
                static_attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP);
                break;
-
        case AF_INET6:
                /* save */
                nexthop_orig.u.prefix6 = info_vpn->attr->mp_nexthop_global;
                nexthop_orig.prefixlen = 128;
+
+               if (CHECK_FLAG(bgp_vrf->af_flags[afi][safi],
+                              BGP_CONFIG_VRF_TO_VRF_IMPORT)) {
+                       static_attr.mp_nexthop_global = nexthop_orig.u.prefix6;
+                       static_attr.mp_nexthop_len = 16;
+               }
                break;
        }
 
-
        /*
         * route map handling
         */
@@ -1101,28 +1135,34 @@ static void vpn_leak_to_vrf_update_onevrf(struct bgp *bgp_vrf,       /* to */
         * labels for these routes enables the non-labeled nexthops
         * from the originating VRF to be considered valid for this route.
         */
+       if (!CHECK_FLAG(bgp_vrf->af_flags[afi][safi],
+                       BGP_CONFIG_VRF_TO_VRF_IMPORT)) {
+               /* work back to original route */
+               for (bi_ultimate = info_vpn;
+                    bi_ultimate->extra && bi_ultimate->extra->parent;
+                    bi_ultimate = bi_ultimate->extra->parent)
+                       ;
 
-       /* work back to original route */
-       for (bi_ultimate = info_vpn;
-               bi_ultimate->extra && bi_ultimate->extra->parent;
-               bi_ultimate = bi_ultimate->extra->parent)
-               ;
-
-       /* if original route was unicast, then it did not arrive over vpn */
-       if (bi_ultimate->net) {
-               struct bgp_table *table;
+               /*
+                * if original route was unicast,
+                * then it did not arrive over vpn
+                */
+               if (bi_ultimate->net) {
+                       struct bgp_table *table;
 
-               table = bgp_node_table(bi_ultimate->net);
-               if (table && (table->safi == SAFI_UNICAST))
-                       origin_local = 1;
-       }
+                       table = bgp_node_table(bi_ultimate->net);
+                       if (table && (table->safi == SAFI_UNICAST))
+                               origin_local = 1;
+               }
 
-       /* copy labels */
-       if (!origin_local && info_vpn->extra && info_vpn->extra->num_labels) {
-               num_labels = info_vpn->extra->num_labels;
-               if (num_labels > BGP_MAX_LABELS)
-                       num_labels = BGP_MAX_LABELS;
-               pLabels = info_vpn->extra->label;
+               /* copy labels */
+               if (!origin_local &&
+                   info_vpn->extra && info_vpn->extra->num_labels) {
+                       num_labels = info_vpn->extra->num_labels;
+                       if (num_labels > BGP_MAX_LABELS)
+                               num_labels = BGP_MAX_LABELS;
+                       pLabels = info_vpn->extra->label;
+               }
        }
 
        if (debug) {
index c13030c6c8c34c455325c36cf13f6ac73069b5fd..2882e1990fc0001e7bce389e8331af4e75b95248 100644 (file)
@@ -92,7 +92,9 @@ static inline int vpn_leak_to_vpn_active(struct bgp *bgp_vrf, afi_t afi,
 
        /* Is vrf configured to export to vpn? */
        if (!CHECK_FLAG(bgp_vrf->af_flags[afi][SAFI_UNICAST],
-                       BGP_CONFIG_VRF_TO_MPLSVPN_EXPORT)) {
+                       BGP_CONFIG_VRF_TO_MPLSVPN_EXPORT)
+           && !CHECK_FLAG(bgp_vrf->af_flags[afi][SAFI_UNICAST],
+                          BGP_CONFIG_VRF_TO_VRF_EXPORT)) {
                if (pmsg)
                        *pmsg = "export not set";
                return 0;
@@ -147,7 +149,9 @@ static inline int vpn_leak_from_vpn_active(struct bgp *bgp_vrf, afi_t afi,
 
        /* Is vrf configured to import from vpn? */
        if (!CHECK_FLAG(bgp_vrf->af_flags[afi][SAFI_UNICAST],
-                       BGP_CONFIG_MPLSVPN_TO_VRF_IMPORT)) {
+                       BGP_CONFIG_MPLSVPN_TO_VRF_IMPORT)
+           && !CHECK_FLAG(bgp_vrf->af_flags[afi][SAFI_UNICAST],
+                          BGP_CONFIG_VRF_TO_VRF_IMPORT)) {
                if (pmsg)
                        *pmsg = "import not set";
                return 0;
index 6bc50fb77e7a667f66b3bfba72c96d9001833282..361b5fb3c05b5e755305cc8374f6eec0def8d924 100644 (file)
@@ -6575,6 +6575,116 @@ ALIAS (af_route_map_vpn_imexport,
        "For routes leaked from vpn to current address-family\n"
        "For routes leaked from current address-family to vpn\n")
 
+DEFPY (bgp_imexport_vrf,
+       bgp_imexport_vrf_cmd,
+       "[no] import vrf NAME$import_name",
+       NO_STR
+       "Import routes from another VRF\n"
+       "VRF to import from\n"
+       "The name of the VRF\n")
+{
+       VTY_DECLVAR_CONTEXT(bgp, bgp);
+       struct listnode *node;
+       struct bgp *vrf_bgp;
+       bool remove = false;
+       int32_t idx = 0;
+       char *vname;
+       const char *export_name;
+       safi_t safi;
+       afi_t afi;
+
+       if (argv_find(argv, argc, "no", &idx))
+               remove = true;
+
+       afi = bgp_node_afi(vty);
+       safi = bgp_node_safi(vty);
+
+       vrf_bgp = bgp_lookup_by_name(import_name);
+       if (!vrf_bgp) {
+               vty_out(vty, "VRF %s is not configured as a bgp instance\n",
+                       import_name);
+               return CMD_WARNING;
+       }
+
+       export_name = bgp->name ? bgp->name : VRF_DEFAULT_NAME;
+
+       if (remove) {
+               for (ALL_LIST_ELEMENTS_RO(bgp->vpn_policy[afi].import_vrf, node,
+                                         vname)) {
+                       if (strcmp(vname, import_name) == 0)
+                               break;
+               }
+
+               if (!vname) {
+                       vty_out(vty,
+                               "Specified VRF %s was not imported, ignoring",
+                               import_name);
+                       return CMD_WARNING;
+               }
+
+               listnode_delete(bgp->vpn_policy[afi].import_vrf, vname);
+               XFREE(MTYPE_TMP, vname);
+
+               if (bgp->vpn_policy[afi].import_vrf->count == 0) {
+                       UNSET_FLAG(bgp->af_flags[afi][safi],
+                                  BGP_CONFIG_VRF_TO_VRF_IMPORT);
+
+                       ecommunity_free(
+                               &bgp->vpn_policy[afi]
+                                        .rtlist[BGP_VPN_POLICY_DIR_FROMVPN]);
+               }
+
+               for (ALL_LIST_ELEMENTS_RO(vrf_bgp->vpn_policy[afi].export_vrf,
+                                         node, vname)) {
+                       if (strcmp(vname, export_name) == 0)
+                               break;
+               }
+
+               listnode_delete(vrf_bgp->vpn_policy[afi].export_vrf, vname);
+               XFREE(MTYPE_TMP, vname);
+
+               UNSET_FLAG(vrf_bgp->af_flags[afi][safi],
+                          BGP_CONFIG_VRF_TO_VRF_EXPORT);
+               UNSET_FLAG(vrf_bgp->vpn_policy[afi].flags,
+                          BGP_VPN_POLICY_TOVPN_RD_SET);
+
+               ecommunity_free(&vrf_bgp->vpn_policy[afi]
+                                        .rtlist[BGP_VPN_POLICY_DIR_TOVPN]);
+               vpn_leak_prechange(BGP_VPN_POLICY_DIR_TOVPN, afi, bgp, vrf_bgp);
+       } else {
+               char buf[1000];
+
+               for (ALL_LIST_ELEMENTS_RO(bgp->vpn_policy[afi].import_vrf, node,
+                                         vname)) {
+                       if (strcmp(vname, import_name) == 0)
+                               return CMD_WARNING;
+               }
+
+               vname = XSTRDUP(MTYPE_TMP, import_name);
+               listnode_add(bgp->vpn_policy[afi].import_vrf, vname);
+
+               vname = XSTRDUP(MTYPE_TMP, export_name);
+               listnode_add(vrf_bgp->vpn_policy[afi].export_vrf, vname);
+
+               prefix_rd2str(&vrf_bgp->vrf_prd, buf, sizeof(buf));
+               vrf_bgp->vpn_policy[afi].rtlist[BGP_VPN_POLICY_DIR_TOVPN] =
+                       ecommunity_str2com(buf, ECOMMUNITY_ROUTE_TARGET, 0);
+               bgp->vpn_policy[afi].rtlist[BGP_VPN_POLICY_DIR_FROMVPN] =
+                       ecommunity_str2com(buf, ECOMMUNITY_ROUTE_TARGET, 0);
+
+               SET_FLAG(bgp->af_flags[afi][safi],
+                        BGP_CONFIG_VRF_TO_VRF_IMPORT);
+               SET_FLAG(vrf_bgp->af_flags[afi][safi],
+                        BGP_CONFIG_VRF_TO_VRF_EXPORT);
+               SET_FLAG(vrf_bgp->vpn_policy[afi].flags,
+                        BGP_VPN_POLICY_TOVPN_RD_SET);
+               vpn_leak_postchange(BGP_VPN_POLICY_DIR_TOVPN, afi, bgp,
+                                   vrf_bgp);
+       }
+
+       return CMD_SUCCESS;
+}
+
 /* This command is valid only in a bgp vrf instance or the default instance */
 DEFPY (bgp_imexport_vpn,
        bgp_imexport_vpn_cmd,
@@ -11744,6 +11854,12 @@ void bgp_vpn_policy_config_write_afi(struct vty *vty, struct bgp *bgp,
 {
        int indent = 2;
 
+       if (CHECK_FLAG(bgp->af_flags[afi][SAFI_UNICAST],
+                      BGP_CONFIG_VRF_TO_VRF_IMPORT)
+           || CHECK_FLAG(bgp->af_flags[afi][SAFI_UNICAST],
+                         BGP_CONFIG_VRF_TO_VRF_EXPORT))
+               return;
+
        if (CHECK_FLAG(bgp->vpn_policy[afi].flags,
                BGP_VPN_POLICY_TOVPN_LABEL_AUTO)) {
 
@@ -13063,6 +13179,9 @@ void bgp_vty_init(void)
        install_element(BGP_IPV4_NODE, &bgp_imexport_vpn_cmd);
        install_element(BGP_IPV6_NODE, &bgp_imexport_vpn_cmd);
 
+       install_element(BGP_IPV4_NODE, &bgp_imexport_vrf_cmd);
+       install_element(BGP_IPV6_NODE, &bgp_imexport_vrf_cmd);
+
        /* ttl_security commands */
        install_element(BGP_NODE, &neighbor_ttl_security_cmd);
        install_element(BGP_NODE, &no_neighbor_ttl_security_cmd);
index df0f1bd19cb5fecd3d3e79117eb0c66645926ac6..e18138584753aaa0e531ad73120428a51b429ff6 100644 (file)
@@ -2956,6 +2956,9 @@ static struct bgp *bgp_create(as_t *as, const char *name,
                bgp->vpn_policy[afi].tovpn_label = MPLS_LABEL_NONE;
                bgp->vpn_policy[afi].tovpn_zebra_vrf_label_last_sent =
                        MPLS_LABEL_NONE;
+
+               bgp->vpn_policy[afi].import_vrf = list_new();
+               bgp->vpn_policy[afi].export_vrf = list_new();
        }
        if (name) {
                bgp->name = XSTRDUP(MTYPE_BGP, name);
@@ -7194,6 +7197,16 @@ static void bgp_config_write_family(struct vty *vty, struct bgp *bgp, afi_t afi,
 
                        vty_out(vty, "  import vpn\n");
                }
+               if (CHECK_FLAG(bgp->af_flags[afi][safi],
+                              BGP_CONFIG_VRF_TO_VRF_IMPORT)) {
+                       struct listnode *node;
+                       char *name;
+
+                       for (ALL_LIST_ELEMENTS_RO(
+                                    bgp->vpn_policy[afi].import_vrf, node,
+                                    name))
+                               vty_out(vty, "  import vrf %s\n", name);
+               }
        }
 
        vty_endframe(vty, " exit-address-family\n");
index 680bac0214b576e672ec1e329d0b604c95727192..472c8056326952a7dae89cb12b2b29ceb46bcb92 100644 (file)
@@ -188,6 +188,10 @@ struct vpn_policy {
 #define BGP_VPN_POLICY_TOVPN_LABEL_AUTO        (1 << 0)
 #define BGP_VPN_POLICY_TOVPN_RD_SET            (1 << 1)
 #define BGP_VPN_POLICY_TOVPN_NEXTHOP_SET       (1 << 2)
+
+       /* If we are importing a vrf -> vrf keep a list of vrf names */
+       struct list *import_vrf;
+       struct list *export_vrf;
 };
 
 /*
@@ -345,6 +349,8 @@ struct bgp {
 #define BGP_CONFIG_DAMPENING              (1 << 0)
 #define BGP_CONFIG_VRF_TO_MPLSVPN_EXPORT  (1 << 1)
 #define BGP_CONFIG_MPLSVPN_TO_VRF_IMPORT  (1 << 2)
+#define BGP_CONFIG_VRF_TO_VRF_IMPORT      (1 << 3)
+#define BGP_CONFIG_VRF_TO_VRF_EXPORT      (1 << 4)
 
 /* l2vpn evpn flags - 1 << 0 is used for DAMPENNG */
 #define BGP_L2VPN_EVPN_ADVERTISE_IPV4_UNICAST      (1 << 1)