#include "bgpd/bgp_ecommunity.h"
#include "bgpd/bgp_zebra.h"
#include "bgpd/bgp_nexthop.h"
+#include "bgpd/bgp_nht.h"
#if ENABLE_BGP_VNC
#include "bgpd/rfapi/rfapi_backend.h"
return ret;
}
-u_int32_t decode_label(mpls_label_t *label_pnt)
+uint32_t decode_label(mpls_label_t *label_pnt)
{
- u_int32_t l;
- u_char *pnt = (u_char *)label_pnt;
+ uint32_t l;
+ uint8_t *pnt = (uint8_t *)label_pnt;
- l = ((u_int32_t)*pnt++ << 12);
- l |= (u_int32_t)*pnt++ << 4;
- l |= (u_int32_t)((*pnt & 0xf0) >> 4);
+ l = ((uint32_t)*pnt++ << 12);
+ l |= (uint32_t)*pnt++ << 4;
+ l |= (uint32_t)((*pnt & 0xf0) >> 4);
return l;
}
void encode_label(mpls_label_t label, mpls_label_t *label_pnt)
{
- u_char *pnt = (u_char *)label_pnt;
+ uint8_t *pnt = (uint8_t *)label_pnt;
if (pnt == NULL)
return;
+ if (label == BGP_PREVENT_VRF_2_VRF_LEAK) {
+ *label_pnt = label;
+ return;
+ }
*pnt++ = (label >> 12) & 0xff;
*pnt++ = (label >> 4) & 0xff;
*pnt++ = ((label << 4) + 1) & 0xff; /* S=1 */
int bgp_nlri_parse_vpn(struct peer *peer, struct attr *attr,
struct bgp_nlri *packet)
{
- u_char *pnt;
- u_char *lim;
+ uint8_t *pnt;
+ uint8_t *lim;
struct prefix p;
int psize = 0;
int prefixlen;
- u_int16_t type;
+ uint16_t type;
struct rd_as rd_as;
struct rd_ip rd_ip;
struct prefix_rd prd;
afi_t afi;
safi_t safi;
int addpath_encoded;
- u_int32_t addpath_id;
+ uint32_t addpath_id;
/* Make prefix_rd */
prd.family = AF_UNSPEC;
void vpn_leak_zebra_vrf_label_update(struct bgp *bgp, afi_t afi)
{
mpls_label_t label = MPLS_LABEL_NONE;
- const char *name = "default";
int debug = BGP_DEBUG(vpn, VPN_LEAK_LABEL);
- if (debug && (bgp->inst_type != BGP_INSTANCE_TYPE_DEFAULT)) {
- name = bgp->name;
- }
-
if (bgp->vrf_id == VRF_UNKNOWN) {
if (debug) {
zlog_debug(
"%s: vrf %s: afi %s: vrf_id not set, "
"can't set zebra vrf label",
- __func__, name, afi2str(afi));
+ __func__, bgp->name_pretty, afi2str(afi));
}
return;
}
if (debug) {
zlog_debug("%s: vrf %s: afi %s: setting label %d for vrf id %d",
- __func__, name, afi2str(afi), label, bgp->vrf_id);
+ __func__, bgp->name_pretty, afi2str(afi), label,
+ bgp->vrf_id);
}
zclient_send_vrf_label(zclient, bgp->vrf_id, afi, label, ZEBRA_LSP_BGP);
if (debug) {
zlog_debug("%s: deleting label for vrf %s (id=%d)", __func__,
- (bgp->name ? bgp->name : "default"), bgp->vrf_id);
+ bgp->name_pretty, bgp->vrf_id);
}
zclient_send_vrf_label(zclient, bgp->vrf_id, afi, label, ZEBRA_LSP_BGP);
bgp->vpn_policy[afi].tovpn_zebra_vrf_label_last_sent = label;
}
+int vpn_leak_label_callback(
+ mpls_label_t label,
+ void *labelid,
+ bool allocated)
+{
+ struct vpn_policy *vp = (struct vpn_policy *)labelid;
+ int debug = BGP_DEBUG(vpn, VPN_LEAK_LABEL);
+
+ if (debug)
+ zlog_debug("%s: label=%u, allocated=%d",
+ __func__, label, allocated);
+
+ if (!allocated) {
+ /*
+ * previously-allocated label is now invalid
+ */
+ if (CHECK_FLAG(vp->flags, BGP_VPN_POLICY_TOVPN_LABEL_AUTO) &&
+ (vp->tovpn_label != MPLS_LABEL_NONE)) {
+
+ vpn_leak_prechange(BGP_VPN_POLICY_DIR_TOVPN,
+ vp->afi, bgp_get_default(), vp->bgp);
+ vp->tovpn_label = MPLS_LABEL_NONE;
+ vpn_leak_postchange(BGP_VPN_POLICY_DIR_TOVPN,
+ vp->afi, bgp_get_default(), vp->bgp);
+ }
+ return 0;
+ }
+
+ /*
+ * New label allocation
+ */
+ if (!CHECK_FLAG(vp->flags, BGP_VPN_POLICY_TOVPN_LABEL_AUTO)) {
+
+ /*
+ * not currently configured for auto label, reject allocation
+ */
+ return -1;
+ }
+
+ if (vp->tovpn_label != MPLS_LABEL_NONE) {
+ if (label == vp->tovpn_label) {
+ /* already have same label, accept but do nothing */
+ return 0;
+ }
+ /* Shouldn't happen: different label allocation */
+ zlog_err("%s: %s had label %u but got new assignment %u",
+ __func__, vp->bgp->name_pretty, vp->tovpn_label, label);
+ /* use new one */
+ }
+
+ vpn_leak_prechange(BGP_VPN_POLICY_DIR_TOVPN,
+ vp->afi, bgp_get_default(), vp->bgp);
+ vp->tovpn_label = label;
+ vpn_leak_postchange(BGP_VPN_POLICY_DIR_TOVPN,
+ vp->afi, bgp_get_default(), vp->bgp);
+
+ return 0;
+}
+
static int ecom_intersect(struct ecommunity *e1, struct ecommunity *e2)
{
int i;
return 0;
}
+static bool labels_same(struct bgp_info *bi, mpls_label_t *label, uint32_t n)
+{
+ uint32_t i;
+
+ if (!bi->extra) {
+ if (!n)
+ return true;
+ else
+ return false;
+ }
+
+ if (n != bi->extra->num_labels)
+ return false;
+
+ for (i = 0; i < n; ++i) {
+ if (label[i] != bi->extra->label[i])
+ return false;
+ }
+ return true;
+}
+
+/*
+ * make encoded route labels match specified encoded label set
+ */
+static void setlabels(
+ struct bgp_info *bi,
+ mpls_label_t *label, /* array of labels */
+ uint32_t num_labels)
+{
+ if (num_labels)
+ assert(label);
+ assert(num_labels <= BGP_MAX_LABELS);
+
+ if (!num_labels) {
+ if (bi->extra)
+ bi->extra->num_labels = 0;
+ return;
+ }
+
+ struct bgp_info_extra *extra = bgp_info_extra_get(bi);
+ uint32_t i;
+
+ for (i = 0; i < num_labels; ++i) {
+ extra->label[i] = label[i];
+ if (!bgp_is_valid_label(&label[i])) {
+ bgp_set_valid_label(&extra->label[i]);
+ }
+ }
+ extra->num_labels = num_labels;
+}
+
/*
* returns pointer to new bgp_info upon success
*/
static struct bgp_info *
-leak_update(struct bgp *bgp, /* destination bgp instance */
- struct bgp_node *bn, struct attr *new_attr, /* already interned */
- afi_t afi, safi_t safi, struct bgp_info *source_bi, u_char type,
- u_char sub_type, mpls_label_t *label, int num_labels, void *parent,
- struct bgp *bgp_orig, struct prefix *nexthop_orig, int debug)
+leak_update(
+ struct bgp *bgp, /* destination bgp instance */
+ struct bgp_node *bn,
+ struct attr *new_attr, /* already interned */
+ afi_t afi,
+ safi_t safi,
+ struct bgp_info *source_bi,
+ mpls_label_t *label,
+ uint32_t num_labels,
+ void *parent,
+ struct bgp *bgp_orig,
+ struct prefix *nexthop_orig,
+ int nexthop_self_flag,
+ int debug)
{
struct prefix *p = &bn->p;
struct bgp_info *bi;
struct bgp_info *new;
char buf_prefix[PREFIX_STRLEN];
- const char *pDestInstanceName = "default";
if (debug) {
prefix2str(&bn->p, buf_prefix, sizeof(buf_prefix));
- if (bgp->name)
- pDestInstanceName = bgp->name;
+ zlog_debug("%s: entry: leak-to=%s, p=%s, type=%d, sub_type=%d",
+ __func__, bgp->name_pretty, buf_prefix,
+ source_bi->type, source_bi->sub_type);
}
/*
}
if (bi) {
+ bool labelssame = labels_same(bi, label, num_labels);
+
if (attrhash_cmp(bi->attr, new_attr)
+ && labelssame
&& !CHECK_FLAG(bi->flags, BGP_INFO_REMOVED)) {
bgp_attr_unintern(&new_attr);
if (debug)
zlog_debug(
"%s: ->%s: %s: Found route, no change",
- __func__, pDestInstanceName,
+ __func__, bgp->name_pretty,
buf_prefix);
return NULL;
}
bi->attr = new_attr;
bi->uptime = bgp_clock();
+ /*
+ * rewrite labels
+ */
+ if (!labelssame)
+ setlabels(bi, label, num_labels);
+
+ if (nexthop_self_flag)
+ bgp_info_set_flag(bn, bi, BGP_INFO_ANNC_NH_SELF);
+
+ struct bgp *bgp_nexthop = bgp;
+ int nh_valid;
+
+ if (bi->extra && bi->extra->bgp_orig)
+ bgp_nexthop = bi->extra->bgp_orig;
+
+ /* No nexthop tracking for redistributed routes */
+ if (source_bi->sub_type == BGP_ROUTE_REDISTRIBUTE)
+ nh_valid = 1;
+ else
+ /*
+ * TBD do we need to do anything about the
+ * 'connected' parameter?
+ */
+ nh_valid = bgp_find_or_add_nexthop(
+ bgp, bgp_nexthop,
+ afi, bi, NULL, 0);
+
+ if (debug)
+ zlog_debug("%s: nexthop is %svalid (in vrf %s)",
+ __func__, (nh_valid ? "" : "not "),
+ bgp_nexthop->name_pretty);
+
+ if (nh_valid)
+ bgp_info_set_flag(bn, bi, BGP_INFO_VALID);
+
/* Process change. */
bgp_aggregate_increment(bgp, p, bi, afi, safi);
bgp_process(bgp, bn, afi, safi);
if (debug)
zlog_debug("%s: ->%s: %s Found route, changed attr",
- __func__, pDestInstanceName, buf_prefix);
+ __func__, bgp->name_pretty, buf_prefix);
return NULL;
}
- new = info_make(type, sub_type, 0, bgp->peer_self, new_attr, bn);
- SET_FLAG(new->flags, BGP_INFO_VALID);
+ new = info_make(ZEBRA_ROUTE_BGP, BGP_ROUTE_IMPORTED, 0,
+ bgp->peer_self, new_attr, bn);
+
+ if (nexthop_self_flag)
+ bgp_info_set_flag(bn, new, BGP_INFO_ANNC_NH_SELF);
+
+ if (num_labels)
+ setlabels(new, label, num_labels);
bgp_info_extra_get(new);
- if (label) {
- int i;
-
- for (i = 0; i < num_labels; ++i) {
- new->extra->label[i] = label[i];
- if (!bgp_is_valid_label(&label[i])) {
- if (debug) {
- zlog_debug(
- "%s: %s: marking label %d valid",
- __func__, buf_prefix, i);
- }
- bgp_set_valid_label(&new->extra->label[i]);
- }
- }
- new->extra->num_labels = num_labels;
- }
new->extra->parent = parent;
if (bgp_orig)
if (nexthop_orig)
new->extra->nexthop_orig = *nexthop_orig;
+ /*
+ * nexthop tracking for unicast routes
+ */
+ struct bgp *bgp_nexthop = bgp;
+ int nh_valid;
+
+ if (new->extra && new->extra->bgp_orig)
+ bgp_nexthop = new->extra->bgp_orig;
+
+ /*
+ * No nexthop tracking for redistributed routes because
+ * their originating protocols will do the tracking and
+ * withdraw those routes if the nexthops become unreachable
+ */
+ if (source_bi->sub_type == BGP_ROUTE_REDISTRIBUTE)
+ nh_valid = 1;
+ else
+ /*
+ * TBD do we need to do anything about the
+ * 'connected' parameter?
+ */
+ nh_valid = bgp_find_or_add_nexthop(bgp, bgp_nexthop,
+ afi, new, NULL, 0);
+
+ if (debug)
+ zlog_debug("%s: nexthop is %svalid (in vrf %s)",
+ __func__, (nh_valid ? "" : "not "),
+ bgp_nexthop->name_pretty);
+ if (nh_valid)
+ bgp_info_set_flag(bn, new, BGP_INFO_VALID);
+
bgp_aggregate_increment(bgp, p, new, afi, safi);
bgp_info_add(bn, new);
if (debug)
zlog_debug("%s: ->%s: %s: Added new route", __func__,
- pDestInstanceName, buf_prefix);
+ bgp->name_pretty, buf_prefix);
return new;
}
mpls_label_t label;
struct bgp_node *bn;
const char *debugmsg;
+ int nexthop_self_flag = 0;
+
+ if (debug)
+ zlog_debug("%s: from vrf %s", __func__, bgp_vrf->name_pretty);
if (debug && info_vrf->attr->ecommunity) {
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);
}
return;
}
- /* loop check */
- if (info_vrf->extra && info_vrf->extra->bgp_orig == bgp_vpn)
+ /* loop check - should not be an imported route. */
+ if (info_vrf->extra && info_vrf->extra->bgp_orig)
return;
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;
}
if (debug)
zlog_debug(
"%s: vrf %s route map \"%s\" says DENY, returning",
- __func__, bgp_vrf->name,
+ __func__, bgp_vrf->name_pretty,
bgp_vrf->vpn_policy[afi]
.rmap[BGP_VPN_POLICY_DIR_TOVPN]
->name);
/* 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
assert(0);
}
} else {
- switch (afi) {
- case AFI_IP:
- default:
- /* Clear ipv4 */
- static_attr.mp_nexthop_global_in.s_addr = 0;
- static_attr.mp_nexthop_len = 4;
- static_attr.nexthop.s_addr = 0; /* self */
- static_attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP);
- break;
-
- case AFI_IP6:
- /* Clear ipv6 */
- memset(&static_attr.mp_nexthop_global, 0,
- sizeof(static_attr.mp_nexthop_global));
- static_attr.mp_nexthop_len = 16; /* bytes */
- break;
+ 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 {
+ /* Update based on next-hop family to account for
+ * RFC 5549 (BGP unnumbered) scenario. Note that
+ * specific action is only needed for the case of
+ * IPv4 nexthops as the attr has been copied
+ * otherwise.
+ */
+ if (afi == AFI_IP &&
+ !BGP_ATTR_NEXTHOP_AFI_IP6(info_vrf->attr)) {
+ 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);
+ }
}
+ nexthop_self_flag = 1;
}
label_val = bgp_vrf->vpn_policy[afi].tovpn_label;
if (label_val == MPLS_LABEL_NONE) {
- /* TBD get from label manager */
- label = MPLS_LABEL_IMPLICIT_NULL;
+ encode_label(MPLS_LABEL_IMPLICIT_NULL, &label);
} else {
encode_label(label_val, &label);
}
struct bgp_info *new_info;
new_info = leak_update(bgp_vpn, bn, new_attr, afi, safi, info_vrf,
- ZEBRA_ROUTE_BGP, BGP_ROUTE_IMPORTED, &label, 1,
- info_vrf, bgp_vrf, NULL, debug);
+ &label, 1, info_vrf, bgp_vrf, NULL,
+ nexthop_self_flag, debug);
/*
* Routes actually installed in the vpn RIB must also be
struct bgp_info *bi;
struct bgp_node *bn;
const char *debugmsg;
+ char buf_prefix[PREFIX_STRLEN];
- if (info_vrf->type != ZEBRA_ROUTE_BGP) {
- if (debug)
- zlog_debug("%s: wrong type %d", __func__,
- info_vrf->type);
- return;
+ if (debug) {
+ prefix2str(p, buf_prefix, sizeof(buf_prefix));
+ zlog_debug(
+ "%s: entry: leak-from=%s, p=%s, type=%d, sub_type=%d",
+ __func__, bgp_vrf->name_pretty, buf_prefix,
+ info_vrf->type, info_vrf->sub_type);
}
+
if (info_vrf->sub_type != BGP_ROUTE_NORMAL
- && info_vrf->sub_type != BGP_ROUTE_STATIC) {
+ && info_vrf->sub_type != BGP_ROUTE_STATIC
+ && info_vrf->sub_type != BGP_ROUTE_REDISTRIBUTE) {
if (debug)
zlog_debug("%s: wrong sub_type %d", __func__,
if (debug)
zlog_debug("%s: entry, afi=%d, vrf=%s", __func__, afi,
- bgp_vrf->name);
+ bgp_vrf->name_pretty);
for (bn = bgp_table_top(bgp_vrf->rib[afi][SAFI_UNICAST]); bn;
bn = bgp_route_next(bn)) {
const char *debugmsg;
struct prefix nexthop_orig;
mpls_label_t *pLabels = NULL;
- int num_labels = 0;
+ uint32_t num_labels = 0;
+ int nexthop_self_flag = 1;
+ struct bgp_info *bi_ultimate = NULL;
+ int origin_local = 0;
+ struct bgp *src_vrf;
int debug = BGP_DEBUG(vpn, VPN_LEAK_TO_VRF);
}
if (debug)
- zlog_debug("%s: updating to vrf %s", __func__, bgp_vrf->name);
+ zlog_debug("%s: updating to vrf %s", __func__,
+ bgp_vrf->name_pretty);
bgp_attr_dup(&static_attr, info_vpn->attr); /* shallow copy */
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;
- static_attr.nexthop.s_addr = 0; /* self */
- static_attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP);
+ 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;
- memset(&static_attr.mp_nexthop_global, 0,
- sizeof(static_attr.mp_nexthop_global)); /* clear */
- static_attr.mp_nexthop_len = 16; /* bytes */
+ if (CHECK_FLAG(bgp_vrf->af_flags[afi][safi],
+ BGP_CONFIG_VRF_TO_VRF_IMPORT)) {
+ static_attr.mp_nexthop_global = nexthop_orig.u.prefix6;
+ }
break;
}
-
/*
* route map handling
*/
if (debug)
zlog_debug(
"%s: vrf %s vpn-policy route map \"%s\" says DENY, returning",
- __func__, bgp_vrf->name,
+ __func__, bgp_vrf->name_pretty,
bgp_vrf->vpn_policy[afi]
.rmap[BGP_VPN_POLICY_DIR_FROMVPN]
->name);
return;
}
+ /*
+ * if route-map changed nexthop, don't nexthop-self on output
+ */
+ if (!CHECK_FLAG(static_attr.rmap_change_flags,
+ BATTR_RMAP_NEXTHOP_UNCHANGED))
+ nexthop_self_flag = 0;
}
new_attr = bgp_attr_intern(&static_attr);
/*
* ensure labels are copied
+ *
+ * However, there is a special case: if the route originated in
+ * another local VRF (as opposed to arriving via VPN), then the
+ * nexthop is reached by hairpinning through this router (me)
+ * using IP forwarding only (no LSP). Therefore, the route
+ * imported to the VRF should not have labels attached. Note
+ * that nexthop tracking is also involved: eliminating the
+ * labels for these routes enables the non-labeled nexthops
+ * from the originating VRF to be considered valid for this route.
*/
- if (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 (!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)
+ ;
+
+ /*
+ * 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;
+ }
+
+ /* 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) {
char buf_prefix[PREFIX_STRLEN];
prefix2str(p, buf_prefix, sizeof(buf_prefix));
num_labels);
}
- leak_update(bgp_vrf, bn, new_attr, afi, safi, info_vpn, ZEBRA_ROUTE_BGP,
- BGP_ROUTE_IMPORTED, pLabels, num_labels,
- info_vpn, /* parent */
- bgp_vpn, &nexthop_orig, debug);
+ /*
+ * For VRF-2-VRF route-leaking,
+ * the source will be the originating VRF.
+ */
+ if (info_vpn->extra && info_vpn->extra->bgp_orig)
+ src_vrf = info_vpn->extra->bgp_orig;
+ else
+ src_vrf = bgp_vpn;
+
+ leak_update(bgp_vrf, bn, new_attr, afi, safi, info_vpn,
+ pLabels, num_labels,
+ info_vpn, /* parent */
+ src_vrf, &nexthop_orig, nexthop_self_flag, debug);
}
void vpn_leak_to_vrf_update(struct bgp *bgp_vpn, /* from */
struct bgp_node *bn;
struct bgp_info *bi;
const char *debugmsg;
+ char buf_prefix[PREFIX_STRLEN];
int debug = BGP_DEBUG(vpn, VPN_LEAK_TO_VRF);
+ if (debug) {
+ prefix2str(&info_vpn->net->p, buf_prefix, sizeof(buf_prefix));
+ zlog_debug("%s: entry: p=%s, type=%d, sub_type=%d",
+ __func__, buf_prefix,
+ info_vpn->type, info_vpn->sub_type);
+ }
+
if (debug)
zlog_debug("%s: start (info_vpn=%p)", __func__, info_vpn);
if (debug)
zlog_debug("%s: withdrawing from vrf %s", __func__,
- bgp->name);
+ bgp->name_pretty);
bn = bgp_afi_node_get(bgp->rib[afi][safi], afi, safi, p, NULL);
for (bi = (bn ? bn->info : NULL); bi; bi = bi->next) {
struct bgp_info *bi;
safi_t safi = SAFI_UNICAST;
int debug = BGP_DEBUG(vpn, VPN_LEAK_TO_VRF);
- struct bgp *bgp_vpn = bgp_get_default();
if (debug)
zlog_debug("%s: entry", __func__);
/*
- * Walk vrf table, delete bi with bgp_orig == bgp_vpn
+ * Walk vrf table, delete bi with bgp_orig in a different vrf
*/
for (bn = bgp_table_top(bgp_vrf->rib[afi][safi]); bn;
bn = bgp_route_next(bn)) {
for (bi = bn->info; bi; bi = bi->next) {
- if (bi->extra && bi->extra->bgp_orig == bgp_vpn) {
+ if (bi->extra && bi->extra->bgp_orig != bgp_vrf) {
/* delete route */
bgp_aggregate_decrement(bgp_vrf, &bn->p, bi,
}
}
+/*
+ * This function is called for definition/deletion/change to a route-map
+ */
static void vpn_policy_routemap_update(struct bgp *bgp, const char *rmap_name)
{
int debug = BGP_DEBUG(vpn, VPN_LEAK_RMAP_EVENT);
for (afi = 0; afi < AFI_MAX; ++afi) {
- if (vpn_leak_to_vpn_active(bgp, afi, NULL)
- && bgp->vpn_policy[afi].rmap_name[BGP_VPN_POLICY_DIR_TOVPN]
- && !strcmp(rmap_name,
+ if (bgp->vpn_policy[afi].rmap_name[BGP_VPN_POLICY_DIR_TOVPN]
+ && !strcmp(rmap_name,
bgp->vpn_policy[afi]
.rmap_name[BGP_VPN_POLICY_DIR_TOVPN])) {
zlog_debug("%s: after vpn_leak_prechange",
__func__);
- if (!rmap)
- bgp->vpn_policy[afi]
- .rmap[BGP_VPN_POLICY_DIR_TOVPN] = NULL;
+ /* in case of definition/deletion */
+ bgp->vpn_policy[afi].rmap[BGP_VPN_POLICY_DIR_TOVPN] =
+ rmap;
vpn_leak_postchange(BGP_VPN_POLICY_DIR_TOVPN, afi,
bgp_get_default(), bgp);
+
if (debug)
zlog_debug("%s: after vpn_leak_postchange",
__func__);
}
- char *mapname = bgp->vpn_policy[afi]
- .rmap_name[BGP_VPN_POLICY_DIR_FROMVPN];
-
- if (vpn_leak_from_vpn_active(bgp, afi, NULL) &&
- mapname &&
- !strcmp(rmap_name, mapname)) {
+ if (bgp->vpn_policy[afi].rmap_name[BGP_VPN_POLICY_DIR_FROMVPN]
+ && !strcmp(rmap_name,
+ bgp->vpn_policy[afi]
+ .rmap_name[BGP_VPN_POLICY_DIR_FROMVPN])) {
if (debug) {
zlog_debug("%s: rmap \"%s\" matches vrf-policy fromvpn for as %d afi %s",
vpn_leak_prechange(BGP_VPN_POLICY_DIR_FROMVPN, afi,
bgp_get_default(), bgp);
- if (!rmap) {
- bgp->vpn_policy[afi]
- .rmap[BGP_VPN_POLICY_DIR_FROMVPN] =
- NULL;
- }
+ /* in case of definition/deletion */
+ bgp->vpn_policy[afi].rmap[BGP_VPN_POLICY_DIR_FROMVPN] =
+ rmap;
vpn_leak_postchange(BGP_VPN_POLICY_DIR_FROMVPN, afi,
bgp_get_default(), bgp);
vpn_policy_routemap_update(bgp, rmap_name);
}
+void vrf_import_from_vrf(struct bgp *to_bgp, struct bgp *from_bgp,
+ afi_t afi, safi_t safi)
+{
+ const char *export_name;
+ vpn_policy_direction_t idir, edir;
+ char *vname;
+ char buf[1000];
+ struct ecommunity *ecom;
+ bool first_export = false;
+
+ export_name = to_bgp->name ? to_bgp->name : BGP_DEFAULT_NAME;
+ idir = BGP_VPN_POLICY_DIR_FROMVPN;
+ edir = BGP_VPN_POLICY_DIR_TOVPN;
+
+ /*
+ * Cross-ref both VRFs. Also, note if this is the first time
+ * any VRF is importing from "import_vrf".
+ */
+ vname = (from_bgp->name ? XSTRDUP(MTYPE_TMP, from_bgp->name)
+ : XSTRDUP(MTYPE_TMP, BGP_DEFAULT_NAME));
+
+ listnode_add(to_bgp->vpn_policy[afi].import_vrf, vname);
+
+ if (!listcount(from_bgp->vpn_policy[afi].export_vrf))
+ first_export = true;
+ vname = XSTRDUP(MTYPE_TMP, export_name);
+ listnode_add(from_bgp->vpn_policy[afi].export_vrf, vname);
+
+ /* Update import RT for current VRF using export RT of the VRF we're
+ * importing from. First though, make sure "import_vrf" has that
+ * set.
+ */
+ if (first_export) {
+ form_auto_rd(from_bgp->router_id, from_bgp->vrf_rd_id,
+ &from_bgp->vrf_prd_auto);
+ from_bgp->vpn_policy[afi].tovpn_rd = from_bgp->vrf_prd_auto;
+ SET_FLAG(from_bgp->vpn_policy[afi].flags,
+ BGP_VPN_POLICY_TOVPN_RD_SET);
+ prefix_rd2str(&from_bgp->vpn_policy[afi].tovpn_rd,
+ buf, sizeof(buf));
+ from_bgp->vpn_policy[afi].rtlist[edir] =
+ ecommunity_str2com(buf, ECOMMUNITY_ROUTE_TARGET, 0);
+ SET_FLAG(from_bgp->af_flags[afi][safi],
+ BGP_CONFIG_VRF_TO_VRF_EXPORT);
+ from_bgp->vpn_policy[afi].tovpn_label =
+ BGP_PREVENT_VRF_2_VRF_LEAK;
+ }
+ ecom = from_bgp->vpn_policy[afi].rtlist[edir];
+ if (to_bgp->vpn_policy[afi].rtlist[idir])
+ to_bgp->vpn_policy[afi].rtlist[idir] =
+ ecommunity_merge(to_bgp->vpn_policy[afi]
+ .rtlist[idir], ecom);
+ else
+ to_bgp->vpn_policy[afi].rtlist[idir] = ecommunity_dup(ecom);
+ SET_FLAG(to_bgp->af_flags[afi][safi], BGP_CONFIG_VRF_TO_VRF_IMPORT);
+
+ /* Does "import_vrf" first need to export its routes or that
+ * is already done and we just need to import those routes
+ * from the global table?
+ */
+ if (first_export)
+ vpn_leak_postchange(edir, afi, bgp_get_default(), from_bgp);
+ else
+ vpn_leak_postchange(idir, afi, bgp_get_default(), to_bgp);
+}
+
+void vrf_unimport_from_vrf(struct bgp *to_bgp, struct bgp *from_bgp,
+ afi_t afi, safi_t safi)
+{
+ const char *export_name, *tmp_name;
+ vpn_policy_direction_t idir, edir;
+ char *vname;
+ struct ecommunity *ecom;
+ struct listnode *node;
+
+ export_name = to_bgp->name ? to_bgp->name : BGP_DEFAULT_NAME;
+ tmp_name = from_bgp->name ? from_bgp->name : BGP_DEFAULT_NAME;
+ idir = BGP_VPN_POLICY_DIR_FROMVPN;
+ edir = BGP_VPN_POLICY_DIR_TOVPN;
+
+ /* Were we importing from "import_vrf"? */
+ for (ALL_LIST_ELEMENTS_RO(to_bgp->vpn_policy[afi].import_vrf, node,
+ vname)) {
+ if (strcmp(vname, tmp_name) == 0)
+ break;
+ }
+
+ /*
+ * We do not check in the cli if the passed in bgp
+ * instance is actually imported into us before
+ * we call this function. As such if we do not
+ * find this in the import_vrf list than
+ * we just need to return safely.
+ */
+ if (!vname)
+ return;
+
+ /* Remove "import_vrf" from our import list. */
+ listnode_delete(to_bgp->vpn_policy[afi].import_vrf, vname);
+ XFREE(MTYPE_TMP, vname);
+
+ /* Remove routes imported from "import_vrf". */
+ /* TODO: In the current logic, we have to first remove all
+ * imported routes and then (if needed) import back routes
+ */
+ vpn_leak_prechange(idir, afi, bgp_get_default(), to_bgp);
+
+ if (to_bgp->vpn_policy[afi].import_vrf->count == 0) {
+ UNSET_FLAG(to_bgp->af_flags[afi][safi],
+ BGP_CONFIG_VRF_TO_VRF_IMPORT);
+ ecommunity_free(&to_bgp->vpn_policy[afi].rtlist[idir]);
+ } else {
+ ecom = from_bgp->vpn_policy[afi].rtlist[edir];
+ ecommunity_del_val(to_bgp->vpn_policy[afi].rtlist[idir],
+ (struct ecommunity_val *)ecom->val);
+ vpn_leak_postchange(idir, afi, bgp_get_default(), to_bgp);
+ }
+
+ /*
+ * What?
+ * So SA is assuming that since the ALL_LIST_ELEMENTS_RO
+ * below is checking for NULL that export_vrf can be
+ * NULL, consequently it is complaining( like a cabbage )
+ * that we could dereference and crash in the listcount(..)
+ * check below.
+ * So make it happy, under protest, with liberty and justice
+ * for all.
+ */
+ assert(from_bgp->vpn_policy[afi].export_vrf);
+
+ /* Remove us from "import_vrf's" export list. If no other VRF
+ * is importing from "import_vrf", cleanup appropriately.
+ */
+ for (ALL_LIST_ELEMENTS_RO(from_bgp->vpn_policy[afi].export_vrf,
+ node, vname)) {
+ if (strcmp(vname, export_name) == 0)
+ break;
+ }
+
+ /*
+ * If we have gotten to this point then the vname must
+ * exist. If not, we are in a world of trouble and
+ * have slag sitting around.
+ *
+ * import_vrf and export_vrf must match in having
+ * the in/out names as appropriate.
+ */
+ assert(vname);
+
+ listnode_delete(from_bgp->vpn_policy[afi].export_vrf, vname);
+ XFREE(MTYPE_TMP, vname);
+
+ if (!listcount(from_bgp->vpn_policy[afi].export_vrf)) {
+ vpn_leak_prechange(edir, afi, bgp_get_default(), from_bgp);
+ ecommunity_free(&from_bgp->vpn_policy[afi].rtlist[edir]);
+ UNSET_FLAG(from_bgp->af_flags[afi][safi],
+ BGP_CONFIG_VRF_TO_VRF_EXPORT);
+ memset(&from_bgp->vpn_policy[afi].tovpn_rd, 0,
+ sizeof(struct prefix_rd));
+ UNSET_FLAG(from_bgp->vpn_policy[afi].flags,
+ BGP_VPN_POLICY_TOVPN_RD_SET);
+ from_bgp->vpn_policy[afi].tovpn_label = MPLS_LABEL_NONE;
+
+ }
+}
+
/* For testing purpose, static route of MPLS-VPN. */
DEFUN (vpnv4_network,
vpnv4_network_cmd,
int bgp_show_mpls_vpn(struct vty *vty, afi_t afi, struct prefix_rd *prd,
enum bgp_show_type type, void *output_arg, int tags,
- u_char use_json)
+ uint8_t use_json)
{
struct bgp *bgp;
struct bgp_table *table;
union sockunion su;
struct peer *peer;
int ret;
- u_char uj = use_json(argc, argv);
+ uint8_t uj = use_json(argc, argv);
afi_t afi;
int idx = 0;
union sockunion su;
struct peer *peer;
struct prefix_rd prd;
- u_char uj = use_json(argc, argv);
+ uint8_t uj = use_json(argc, argv);
afi_t afi;
int idx = 0;
int ret;
struct peer *peer;
union sockunion su;
- u_char uj = use_json(argc, argv);
+ uint8_t uj = use_json(argc, argv);
afi_t afi;
int idx = 0;
struct peer *peer;
struct prefix_rd prd;
union sockunion su;
- u_char uj = use_json(argc, argv);
+ uint8_t uj = use_json(argc, argv);
afi_t afi;
int idx = 0;
&show_ip_bgp_vpn_rd_neighbor_advertised_routes_cmd);
#endif /* KEEP_OLD_VPN_COMMANDS */
}
+
+vrf_id_t get_first_vrf_for_redirect_with_rt(struct ecommunity *eckey)
+{
+ struct listnode *mnode, *mnnode;
+ struct bgp *bgp;
+
+ for (ALL_LIST_ELEMENTS(bm->bgp, mnode, mnnode, bgp)) {
+ struct ecommunity *ec;
+
+ if (bgp->inst_type != BGP_INSTANCE_TYPE_VRF)
+ continue;
+
+ ec = bgp->vpn_policy[AFI_IP].import_redirect_rtlist;
+
+ if (ecom_intersect(ec, eckey))
+ return bgp->vrf_id;
+ }
+ return VRF_UNKNOWN;
+}