summaryrefslogtreecommitdiffstats
path: root/bgpd/bgp_mplsvpn.c
diff options
context:
space:
mode:
Diffstat (limited to 'bgpd/bgp_mplsvpn.c')
-rw-r--r--bgpd/bgp_mplsvpn.c84
1 files changed, 73 insertions, 11 deletions
diff --git a/bgpd/bgp_mplsvpn.c b/bgpd/bgp_mplsvpn.c
index 08748d2eb..66eef1aa5 100644
--- a/bgpd/bgp_mplsvpn.c
+++ b/bgpd/bgp_mplsvpn.c
@@ -42,6 +42,7 @@
#include "bgpd/bgp_packet.h"
#include "bgpd/bgp_vty.h"
#include "bgpd/bgp_vpn.h"
+#include "bgpd/bgp_community.h"
#include "bgpd/bgp_ecommunity.h"
#include "bgpd/bgp_zebra.h"
#include "bgpd/bgp_nexthop.h"
@@ -996,6 +997,9 @@ leak_update(struct bgp *to_bgp, struct bgp_dest *bn,
if (nexthop_self_flag)
bgp_path_info_set_flag(bn, bpi, BGP_PATH_ANNC_NH_SELF);
+ if (CHECK_FLAG(source_bpi->flags, BGP_PATH_ACCEPT_OWN))
+ bgp_path_info_set_flag(bn, bpi, BGP_PATH_ACCEPT_OWN);
+
if (leak_update_nexthop_valid(to_bgp, bn, new_attr, afi, safi,
source_bpi, bpi, bgp_orig, p,
debug))
@@ -1036,6 +1040,9 @@ leak_update(struct bgp *to_bgp, struct bgp_dest *bn,
if (nexthop_self_flag)
bgp_path_info_set_flag(bn, new, BGP_PATH_ANNC_NH_SELF);
+ if (CHECK_FLAG(source_bpi->flags, BGP_PATH_ACCEPT_OWN))
+ bgp_path_info_set_flag(bn, new, BGP_PATH_ACCEPT_OWN);
+
bgp_path_info_extra_get(new);
/*
@@ -1217,6 +1224,8 @@ void vpn_leak_from_vrf_update(struct bgp *to_bgp, /* to */
XFREE(MTYPE_ECOMMUNITY_STR, s);
}
+ community_strip_accept_own(&static_attr);
+
/* Nexthop */
/* if policy nexthop not set, use 0 */
if (CHECK_FLAG(from_bgp->vpn_policy[afi].flags,
@@ -1362,7 +1371,7 @@ void vpn_leak_from_vrf_update(struct bgp *to_bgp, /* to */
* because of loop checking.
*/
if (new_info)
- vpn_leak_to_vrf_update(from_bgp, new_info);
+ vpn_leak_to_vrf_update(from_bgp, new_info, NULL);
}
void vpn_leak_from_vrf_withdraw(struct bgp *to_bgp, /* to */
@@ -1518,10 +1527,40 @@ void vpn_leak_from_vrf_update_all(struct bgp *to_bgp, struct bgp *from_bgp,
}
}
-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 */
+static struct bgp *bgp_lookup_by_rd(struct bgp_path_info *bpi,
+ struct prefix_rd *rd, afi_t afi)
+{
+ struct listnode *node, *nnode;
+ struct bgp *bgp;
+
+ if (!rd)
+ return NULL;
+
+ /* If ACCEPT_OWN is not enabled for this path - return. */
+ if (!CHECK_FLAG(bpi->flags, BGP_PATH_ACCEPT_OWN))
+ return NULL;
+
+ for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp)) {
+ if (bgp->inst_type != BGP_INSTANCE_TYPE_VRF)
+ continue;
+
+ if (!CHECK_FLAG(bgp->vpn_policy[afi].flags,
+ BGP_VPN_POLICY_TOVPN_RD_SET))
+ continue;
+
+ /* Check if we have source VRF by RD value */
+ if (memcmp(&bgp->vpn_policy[afi].tovpn_rd.val, rd->val,
+ ECOMMUNITY_SIZE) == 0)
+ return bgp;
+ }
+
+ return NULL;
+}
+
+static bool vpn_leak_to_vrf_update_onevrf(struct bgp *to_bgp, /* to */
+ struct bgp *from_bgp, /* from */
+ struct bgp_path_info *path_vpn,
+ struct prefix_rd *prd)
{
const struct prefix *p = bgp_dest_get_prefix(path_vpn->net);
afi_t afi = family2afi(p->family);
@@ -1558,9 +1597,22 @@ vpn_leak_to_vrf_update_onevrf(struct bgp *to_bgp, /* to */
return false;
}
+ /* A route MUST NOT ever be accepted back into its source VRF, even if
+ * it carries one or more RTs that match that VRF.
+ */
+ if (prd && memcmp(&prd->val, &to_bgp->vpn_policy[afi].tovpn_rd.val,
+ ECOMMUNITY_SIZE) == 0) {
+ if (debug)
+ zlog_debug(
+ "%s: skipping import, match RD (%pRD) of src VRF (%s) and the prefix (%pFX)",
+ __func__, prd, to_bgp->name_pretty, p);
+
+ return false;
+ }
+
if (debug)
- zlog_debug("%s: updating %pFX to vrf %s", __func__, p,
- to_bgp->name_pretty);
+ zlog_debug("%s: updating RD %pRD, %pFX to vrf %s", __func__,
+ prd, p, to_bgp->name_pretty);
/* shallow copy */
static_attr = *path_vpn->attr;
@@ -1585,6 +1637,8 @@ vpn_leak_to_vrf_update_onevrf(struct bgp *to_bgp, /* to */
ecommunity_free(&old_ecom);
}
+ community_strip_accept_own(&static_attr);
+
/*
* Nexthop: stash and clear
*
@@ -1711,9 +1765,16 @@ vpn_leak_to_vrf_update_onevrf(struct bgp *to_bgp, /* to */
/*
* For VRF-2-VRF route-leaking,
* the source will be the originating VRF.
+ *
+ * If ACCEPT_OWN mechanism is enabled, then we SHOULD(?)
+ * get the source VRF (BGP) by looking at the RD.
*/
+ struct bgp *src_bgp = bgp_lookup_by_rd(path_vpn, prd, afi);
+
if (path_vpn->extra && path_vpn->extra->bgp_orig)
src_vrf = path_vpn->extra->bgp_orig;
+ else if (src_bgp)
+ src_vrf = src_bgp;
else
src_vrf = from_bgp;
@@ -1723,8 +1784,9 @@ vpn_leak_to_vrf_update_onevrf(struct bgp *to_bgp, /* to */
return true;
}
-bool vpn_leak_to_vrf_update(struct bgp *from_bgp, /* from */
- struct bgp_path_info *path_vpn) /* route */
+bool vpn_leak_to_vrf_update(struct bgp *from_bgp,
+ struct bgp_path_info *path_vpn,
+ struct prefix_rd *prd)
{
struct listnode *mnode, *mnnode;
struct bgp *bgp;
@@ -1741,7 +1803,7 @@ bool vpn_leak_to_vrf_update(struct bgp *from_bgp, /* from */
if (!path_vpn->extra
|| path_vpn->extra->bgp_orig != bgp) { /* no loop */
leak_success |= vpn_leak_to_vrf_update_onevrf(
- bgp, from_bgp, path_vpn);
+ bgp, from_bgp, path_vpn, prd);
}
}
return leak_success;
@@ -1897,7 +1959,7 @@ void vpn_leak_to_vrf_update_all(struct bgp *to_bgp, struct bgp *vpn_from,
continue;
vpn_leak_to_vrf_update_onevrf(to_bgp, vpn_from,
- bpi);
+ bpi, NULL);
}
}
}