summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bgpd/bgp_debug.c139
-rw-r--r--bgpd/bgp_debug.h6
-rw-r--r--bgpd/bgp_main.c6
-rw-r--r--bgpd/bgp_mplsvpn.c986
-rw-r--r--bgpd/bgp_mplsvpn.h119
-rw-r--r--bgpd/bgp_route.c185
-rw-r--r--bgpd/bgp_route.h25
-rw-r--r--bgpd/bgp_routemap.c11
-rw-r--r--bgpd/bgp_updgrp_adv.c8
-rw-r--r--bgpd/bgp_vty.c719
-rw-r--r--bgpd/bgp_vty.h1
-rw-r--r--bgpd/bgp_zebra.c141
-rw-r--r--bgpd/bgpd.c13
-rw-r--r--bgpd/bgpd.h23
-rw-r--r--bgpd/rfapi/bgp_rfapi_cfg.c5
-rw-r--r--bgpd/rfapi/vnc_export_bgp.c6
-rw-r--r--isisd/isis_redist.c4
-rw-r--r--lib/command.c8
-rw-r--r--lib/command.h136
-rw-r--r--lib/log.c4
-rw-r--r--lib/route_types.txt4
-rw-r--r--lib/zclient.c2
-rw-r--r--ospfd/ospf_zebra.c10
-rw-r--r--ospfd/ospfd.c27
-rw-r--r--vtysh/vtysh.c39
-rw-r--r--zebra/redistribute.c16
-rw-r--r--zebra/zebra_rib.c1
-rw-r--r--zebra/zserv.c83
28 files changed, 2622 insertions, 105 deletions
diff --git a/bgpd/bgp_debug.c b/bgpd/bgp_debug.c
index 2580d2e5a5..f867266956 100644
--- a/bgpd/bgp_debug.c
+++ b/bgpd/bgp_debug.c
@@ -55,6 +55,7 @@ unsigned long conf_bgp_debug_zebra;
unsigned long conf_bgp_debug_allow_martians;
unsigned long conf_bgp_debug_nht;
unsigned long conf_bgp_debug_update_groups;
+unsigned long conf_bgp_debug_vpn;
unsigned long term_bgp_debug_as4;
unsigned long term_bgp_debug_neighbor_events;
@@ -68,6 +69,7 @@ unsigned long term_bgp_debug_zebra;
unsigned long term_bgp_debug_allow_martians;
unsigned long term_bgp_debug_nht;
unsigned long term_bgp_debug_update_groups;
+unsigned long term_bgp_debug_vpn;
struct list *bgp_debug_neighbor_events_peers = NULL;
struct list *bgp_debug_keepalive_peers = NULL;
@@ -1560,6 +1562,96 @@ DEFUN (no_debug_bgp_update_groups,
return CMD_SUCCESS;
}
+DEFUN (debug_bgp_vpn,
+ debug_bgp_vpn_cmd,
+ "debug bgp vpn <leak-from-vrf|leak-to-vrf|rmap-event|label>",
+ DEBUG_STR
+ BGP_STR
+ "VPN routes\n"
+ "leaked from vrf to vpn\n"
+ "leaked to vrf from vpn\n"
+ "route-map updates\n"
+ "labels\n")
+{
+ int idx = 3;
+
+ if (argv_find(argv, argc, "leak-from-vrf", &idx)) {
+ if (vty->node == CONFIG_NODE)
+ DEBUG_ON(vpn, VPN_LEAK_FROM_VRF);
+ else
+ TERM_DEBUG_ON(vpn, VPN_LEAK_FROM_VRF);
+ } else if (argv_find(argv, argc, "leak-to-vrf", &idx)) {
+ if (vty->node == CONFIG_NODE)
+ DEBUG_ON(vpn, VPN_LEAK_TO_VRF);
+ else
+ TERM_DEBUG_ON(vpn, VPN_LEAK_TO_VRF);
+ } else if (argv_find(argv, argc, "rmap-event", &idx)) {
+ if (vty->node == CONFIG_NODE)
+ DEBUG_ON(vpn, VPN_LEAK_RMAP_EVENT);
+ else
+ TERM_DEBUG_ON(vpn, VPN_LEAK_RMAP_EVENT);
+ } else if (argv_find(argv, argc, "label", &idx)) {
+ if (vty->node == CONFIG_NODE)
+ DEBUG_ON(vpn, VPN_LEAK_LABEL);
+ else
+ TERM_DEBUG_ON(vpn, VPN_LEAK_LABEL);
+ } else {
+ vty_out(vty, "%% unknown debug bgp vpn keyword\n");
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+
+ if (vty->node != CONFIG_NODE)
+ vty_out(vty, "enabled debug bgp vpn %s\n", argv[idx]->text);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_debug_bgp_vpn,
+ no_debug_bgp_vpn_cmd,
+ "no debug bgp vpn <leak-from-vrf|leak-to-vrf|rmap-event|label>",
+ NO_STR
+ DEBUG_STR
+ BGP_STR
+ "VPN routes\n"
+ "leaked from vrf to vpn\n"
+ "leaked to vrf from vpn\n"
+ "route-map updates\n"
+ "labels\n")
+{
+ int idx = 4;
+
+ if (argv_find(argv, argc, "leak-from-vrf", &idx)) {
+ if (vty->node == CONFIG_NODE)
+ DEBUG_OFF(vpn, VPN_LEAK_FROM_VRF);
+ else
+ TERM_DEBUG_OFF(vpn, VPN_LEAK_FROM_VRF);
+
+ } else if (argv_find(argv, argc, "leak-to-vrf", &idx)) {
+ if (vty->node == CONFIG_NODE)
+ DEBUG_OFF(vpn, VPN_LEAK_TO_VRF);
+ else
+ TERM_DEBUG_OFF(vpn, VPN_LEAK_TO_VRF);
+ } else if (argv_find(argv, argc, "rmap-event", &idx)) {
+ if (vty->node == CONFIG_NODE)
+ DEBUG_OFF(vpn, VPN_LEAK_RMAP_EVENT);
+ else
+ TERM_DEBUG_OFF(vpn, VPN_LEAK_RMAP_EVENT);
+ } else if (argv_find(argv, argc, "label", &idx)) {
+ if (vty->node == CONFIG_NODE)
+ DEBUG_OFF(vpn, VPN_LEAK_LABEL);
+ else
+ TERM_DEBUG_OFF(vpn, VPN_LEAK_LABEL);
+ } else {
+ vty_out(vty, "%% unknown debug bgp vpn keyword\n");
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+
+ if (vty->node != CONFIG_NODE)
+ vty_out(vty, "disabled debug bgp vpn %s\n", argv[idx]->text);
+
+ return CMD_SUCCESS;
+}
+
DEFUN (no_debug_bgp,
no_debug_bgp_cmd,
"no debug bgp",
@@ -1592,6 +1684,10 @@ DEFUN (no_debug_bgp,
TERM_DEBUG_OFF(zebra, ZEBRA);
TERM_DEBUG_OFF(allow_martians, ALLOW_MARTIANS);
TERM_DEBUG_OFF(nht, NHT);
+ TERM_DEBUG_OFF(vpn, VPN_LEAK_FROM_VRF);
+ TERM_DEBUG_OFF(vpn, VPN_LEAK_TO_VRF);
+ TERM_DEBUG_OFF(vpn, VPN_LEAK_RMAP_EVENT);
+ TERM_DEBUG_OFF(vpn, VPN_LEAK_LABEL);
vty_out(vty, "All possible debugging has been turned off\n");
return CMD_SUCCESS;
@@ -1651,6 +1747,18 @@ DEFUN_NOSH (show_debugging_bgp,
if (BGP_DEBUG(allow_martians, ALLOW_MARTIANS))
vty_out(vty, " BGP allow martian next hop debugging is on\n");
+
+ if (BGP_DEBUG(vpn, VPN_LEAK_FROM_VRF))
+ vty_out(vty,
+ " BGP route leak from vrf to vpn debugging is on\n");
+ if (BGP_DEBUG(vpn, VPN_LEAK_TO_VRF))
+ vty_out(vty,
+ " BGP route leak to vrf from vpn debugging is on\n");
+ if (BGP_DEBUG(vpn, VPN_LEAK_RMAP_EVENT))
+ vty_out(vty, " BGP vpn route-map event debugging is on\n");
+ if (BGP_DEBUG(vpn, VPN_LEAK_LABEL))
+ vty_out(vty, " BGP vpn label event debugging is on\n");
+
vty_out(vty, "\n");
return CMD_SUCCESS;
}
@@ -1695,6 +1803,15 @@ int bgp_debug_count(void)
if (BGP_DEBUG(allow_martians, ALLOW_MARTIANS))
ret++;
+ if (BGP_DEBUG(vpn, VPN_LEAK_FROM_VRF))
+ ret++;
+ if (BGP_DEBUG(vpn, VPN_LEAK_TO_VRF))
+ ret++;
+ if (BGP_DEBUG(vpn, VPN_LEAK_RMAP_EVENT))
+ ret++;
+ if (BGP_DEBUG(vpn, VPN_LEAK_LABEL))
+ ret++;
+
return ret;
}
@@ -1771,6 +1888,23 @@ static int bgp_config_write_debug(struct vty *vty)
write++;
}
+ if (CONF_BGP_DEBUG(vpn, VPN_LEAK_FROM_VRF)) {
+ vty_out(vty, "debug bgp vpn leak-from-vrf\n");
+ write++;
+ }
+ if (CONF_BGP_DEBUG(vpn, VPN_LEAK_TO_VRF)) {
+ vty_out(vty, "debug bgp vpn leak-to-vrf\n");
+ write++;
+ }
+ if (CONF_BGP_DEBUG(vpn, VPN_LEAK_RMAP_EVENT)) {
+ vty_out(vty, "debug bgp vpn rmap-event\n");
+ write++;
+ }
+ if (CONF_BGP_DEBUG(vpn, VPN_LEAK_LABEL)) {
+ vty_out(vty, "debug bgp vpn label\n");
+ write++;
+ }
+
return write;
}
@@ -1864,6 +1998,11 @@ void bgp_debug_init(void)
install_element(CONFIG_NODE, &no_debug_bgp_bestpath_cmd);
install_element(ENABLE_NODE, &no_debug_bgp_bestpath_prefix_cmd);
install_element(CONFIG_NODE, &no_debug_bgp_bestpath_prefix_cmd);
+
+ install_element(ENABLE_NODE, &debug_bgp_vpn_cmd);
+ install_element(CONFIG_NODE, &debug_bgp_vpn_cmd);
+ install_element(ENABLE_NODE, &no_debug_bgp_vpn_cmd);
+ install_element(CONFIG_NODE, &no_debug_bgp_vpn_cmd);
}
/* Return true if this prefix is on the per_prefix_list of prefixes to debug
diff --git a/bgpd/bgp_debug.h b/bgpd/bgp_debug.h
index 10a1e3159f..fe7ca8c46a 100644
--- a/bgpd/bgp_debug.h
+++ b/bgpd/bgp_debug.h
@@ -72,6 +72,7 @@ extern unsigned long conf_bgp_debug_zebra;
extern unsigned long conf_bgp_debug_allow_martians;
extern unsigned long conf_bgp_debug_nht;
extern unsigned long conf_bgp_debug_update_groups;
+extern unsigned long conf_bgp_debug_vpn;
extern unsigned long term_bgp_debug_as4;
extern unsigned long term_bgp_debug_neighbor_events;
@@ -83,6 +84,7 @@ extern unsigned long term_bgp_debug_zebra;
extern unsigned long term_bgp_debug_allow_martians;
extern unsigned long term_bgp_debug_nht;
extern unsigned long term_bgp_debug_update_groups;
+extern unsigned long term_bgp_debug_vpn;
extern struct list *bgp_debug_neighbor_events_peers;
extern struct list *bgp_debug_keepalive_peers;
@@ -111,6 +113,10 @@ struct bgp_debug_filter {
#define BGP_DEBUG_ALLOW_MARTIANS 0x01
#define BGP_DEBUG_NHT 0x01
#define BGP_DEBUG_UPDATE_GROUPS 0x01
+#define BGP_DEBUG_VPN_LEAK_FROM_VRF 0x01
+#define BGP_DEBUG_VPN_LEAK_TO_VRF 0x02
+#define BGP_DEBUG_VPN_LEAK_RMAP_EVENT 0x04
+#define BGP_DEBUG_VPN_LEAK_LABEL 0x08
#define BGP_DEBUG_PACKET_SEND 0x01
#define BGP_DEBUG_PACKET_SEND_DETAIL 0x02
diff --git a/bgpd/bgp_main.c b/bgpd/bgp_main.c
index 7039786014..bf60f9c118 100644
--- a/bgpd/bgp_main.c
+++ b/bgpd/bgp_main.c
@@ -265,6 +265,8 @@ static int bgp_vrf_enable(struct vrf *vrf)
if (old_vrf_id != bgp->vrf_id)
bgp_update_redist_vrf_bitmaps(bgp, old_vrf_id);
bgp_instance_up(bgp);
+ vpn_leak_zebra_vrf_label_update(bgp, AFI_IP);
+ vpn_leak_zebra_vrf_label_update(bgp, AFI_IP6);
}
return 0;
@@ -283,6 +285,10 @@ static int bgp_vrf_disable(struct vrf *vrf)
bgp = bgp_lookup_by_name(vrf->name);
if (bgp) {
+
+ vpn_leak_zebra_vrf_label_withdraw(bgp, AFI_IP);
+ vpn_leak_zebra_vrf_label_withdraw(bgp, AFI_IP6);
+
old_vrf_id = bgp->vrf_id;
bgp_handle_socket(bgp, vrf, VRF_UNKNOWN, false);
/* We have instance configured, unlink from VRF and make it
diff --git a/bgpd/bgp_mplsvpn.c b/bgpd/bgp_mplsvpn.c
index ec4989de8f..d87f78a783 100644
--- a/bgpd/bgp_mplsvpn.c
+++ b/bgpd/bgp_mplsvpn.c
@@ -27,9 +27,12 @@
#include "stream.h"
#include "queue.h"
#include "filter.h"
+#include "mpls.h"
#include "lib/json.h"
+#include "lib/zclient.h"
#include "bgpd/bgpd.h"
+#include "bgpd/bgp_debug.h"
#include "bgpd/bgp_table.h"
#include "bgpd/bgp_route.h"
#include "bgpd/bgp_attr.h"
@@ -38,11 +41,19 @@
#include "bgpd/bgp_packet.h"
#include "bgpd/bgp_vty.h"
#include "bgpd/bgp_vpn.h"
+#include "bgpd/bgp_ecommunity.h"
+#include "bgpd/bgp_zebra.h"
+#include "bgpd/bgp_nexthop.h"
#if ENABLE_BGP_VNC
#include "bgpd/rfapi/rfapi_backend.h"
#endif
+/*
+ * Definitions and external declarations.
+ */
+extern struct zclient *zclient;
+
extern int argv_find_and_parse_vpnvx(struct cmd_token **argv, int argc,
int *index, afi_t *afi)
{
@@ -92,7 +103,7 @@ int bgp_nlri_parse_vpn(struct peer *peer, struct attr *attr,
struct rd_as rd_as;
struct rd_ip rd_ip;
struct prefix_rd prd;
- mpls_label_t label;
+ mpls_label_t label = {0};
afi_t afi;
safi_t safi;
int addpath_encoded;
@@ -233,6 +244,979 @@ int bgp_nlri_parse_vpn(struct peer *peer, struct attr *attr,
#undef VPN_PREFIXLEN_MIN_BYTES
}
+/*
+ * This function informs zebra of the label this vrf sets on routes
+ * leaked to VPN. Zebra should install this label in the kernel with
+ * an action of "pop label and then use this vrf's IP FIB to route the PDU."
+ *
+ * Sending this vrf-label association is qualified by a) whether vrf->vpn
+ * exporting is active ("export vpn" is enabled, vpn-policy RD and RT list
+ * are set) and b) whether vpn-policy label is set.
+ *
+ * If any of these conditions do not hold, then we send MPLS_LABEL_NONE
+ * for this vrf, which zebra interprets to mean "delete this vrf-label
+ * association."
+ */
+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));
+ }
+ return;
+ }
+
+ if (vpn_leak_to_vpn_active(bgp, afi, NULL)) {
+ label = bgp->vpn_policy[afi].tovpn_label;
+ }
+
+ if (debug) {
+ zlog_debug("%s: vrf %s: afi %s: setting label %d for vrf id %d",
+ __func__, name, afi2str(afi), label, 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;
+}
+
+/*
+ * If zebra tells us vrf has become unconfigured, tell zebra not to
+ * use this label to forward to the vrf anymore
+ */
+void vpn_leak_zebra_vrf_label_withdraw(struct bgp *bgp, afi_t afi)
+{
+ mpls_label_t label = MPLS_LABEL_NONE;
+ int debug = BGP_DEBUG(vpn, VPN_LEAK_LABEL);
+
+ if (bgp->vrf_id == VRF_UNKNOWN) {
+ if (debug) {
+ zlog_debug(
+ "%s: vrf_id not set, can't delete zebra vrf label",
+ __func__);
+ }
+ return;
+ }
+
+ if (debug) {
+ zlog_debug("%s: deleting label for vrf %s (id=%d)", __func__,
+ (bgp->name ? bgp->name : "default"), 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;
+}
+
+static int ecom_intersect(struct ecommunity *e1, struct ecommunity *e2)
+{
+ int i;
+ int j;
+
+ if (!e1 || !e2)
+ return 0;
+
+ for (i = 0; i < e1->size; ++i) {
+ for (j = 0; j < e2->size; ++j) {
+ if (!memcmp(e1->val + (i * ECOMMUNITY_SIZE),
+ e2->val + (j * ECOMMUNITY_SIZE),
+ ECOMMUNITY_SIZE)) {
+
+ return 1;
+ }
+ }
+ }
+ return 0;
+}
+
+/*
+ * 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)
+{
+ 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;
+ }
+
+ /*
+ * match parent
+ */
+ for (bi = bn->info; bi; bi = bi->next) {
+ if (bi->extra && bi->extra->parent == parent)
+ break;
+ }
+
+ if (bi) {
+ if (attrhash_cmp(bi->attr, new_attr)
+ && !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,
+ buf_prefix);
+ return NULL;
+ }
+
+ /* attr is changed */
+ bgp_info_set_flag(bn, bi, BGP_INFO_ATTR_CHANGED);
+
+ /* Rewrite BGP route information. */
+ if (CHECK_FLAG(bi->flags, BGP_INFO_REMOVED))
+ bgp_info_restore(bn, bi);
+ else
+ bgp_aggregate_decrement(bgp, p, bi, afi, safi);
+ bgp_attr_unintern(&bi->attr);
+ bi->attr = new_attr;
+ bi->uptime = bgp_clock();
+
+ /* Process change. */
+ bgp_aggregate_increment(bgp, p, bi, afi, safi);
+ bgp_process(bgp, bn, afi, safi);
+ bgp_unlock_node(bn);
+
+ if (debug)
+ zlog_debug("%s: ->%s: %s Found route, changed attr",
+ __func__, pDestInstanceName, buf_prefix);
+
+ return NULL;
+ }
+
+ new = info_make(type, sub_type, 0, bgp->peer_self, new_attr, bn);
+ SET_FLAG(new->flags, BGP_INFO_VALID);
+
+ 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)
+ new->extra->bgp_orig = bgp_orig;
+ if (nexthop_orig)
+ new->extra->nexthop_orig = *nexthop_orig;
+
+ bgp_aggregate_increment(bgp, p, new, afi, safi);
+ bgp_info_add(bn, new);
+
+ bgp_unlock_node(bn);
+ bgp_process(bgp, bn, afi, safi);
+
+ if (debug)
+ zlog_debug("%s: ->%s: %s: Added new route", __func__,
+ pDestInstanceName, buf_prefix);
+
+ return new;
+}
+
+/* cf vnc_import_bgp_add_route_mode_nvegroup() and add_vnc_route() */
+void vpn_leak_from_vrf_update(struct bgp *bgp_vpn, /* to */
+ struct bgp *bgp_vrf, /* from */
+ struct bgp_info *info_vrf) /* route */
+{
+ int debug = BGP_DEBUG(vpn, VPN_LEAK_FROM_VRF);
+ struct prefix *p = &info_vrf->net->p;
+ afi_t afi = family2afi(p->family);
+ struct attr static_attr = {0};
+ struct attr *new_attr = NULL;
+ safi_t safi = SAFI_MPLS_VPN;
+ mpls_label_t label_val;
+ mpls_label_t label;
+ struct bgp_node *bn;
+ const char *debugmsg;
+
+ if (debug) {
+ const char *s = "";
+
+ if (info_vrf->attr && info_vrf->attr->ecommunity) {
+ 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);
+ }
+
+ if (!bgp_vpn)
+ return;
+
+ if (!afi) {
+ if (debug)
+ zlog_debug("%s: can't get afi of prefix", __func__);
+ return;
+ }
+
+ /* loop check */
+ if (info_vrf->extra && info_vrf->extra->bgp_orig == bgp_vpn)
+ return;
+
+
+ if (!vpn_leak_to_vpn_active(bgp_vrf, afi, &debugmsg)) {
+ if (debug)
+ zlog_debug("%s: skipping: %s", __func__, debugmsg);
+ return;
+ }
+
+ bgp_attr_dup(&static_attr, info_vrf->attr); /* shallow copy */
+
+ /*
+ * route map handling
+ */
+ if (bgp_vrf->vpn_policy[afi].rmap[BGP_VPN_POLICY_DIR_TOVPN]) {
+ struct bgp_info info;
+ route_map_result_t ret;
+
+ memset(&info, 0, sizeof(info));
+ info.peer = bgp_vpn->peer_self;
+ info.attr = &static_attr;
+ ret = route_map_apply(
+ bgp_vrf->vpn_policy[afi].rmap[BGP_VPN_POLICY_DIR_TOVPN],
+ p, RMAP_BGP, &info);
+ if (RMAP_DENYMATCH == ret) {
+ bgp_attr_flush(&static_attr); /* free any added parts */
+ if (debug)
+ zlog_debug(
+ "%s: vrf %s route map \"%s\" says DENY, returning",
+ __func__, bgp_vrf->name,
+ bgp_vrf->vpn_policy[afi]
+ .rmap[BGP_VPN_POLICY_DIR_TOVPN]
+ ->name);
+ return;
+ }
+ }
+
+ if (debug) {
+ const char *s = "";
+
+ if (static_attr.ecommunity) {
+ s = ecommunity_ecom2str(static_attr.ecommunity,
+ ECOMMUNITY_FORMAT_ROUTE_MAP, 0);
+ }
+ zlog_debug("%s: post route map static_attr.ecommunity{%s}",
+ __func__, s);
+ }
+
+ /*
+ * Add the vpn-policy rt-list
+ */
+ struct ecommunity *old_ecom;
+ struct ecommunity *new_ecom;
+
+ old_ecom = static_attr.ecommunity;
+ if (old_ecom) {
+ new_ecom = ecommunity_merge(
+ ecommunity_dup(old_ecom),
+ bgp_vrf->vpn_policy[afi]
+ .rtlist[BGP_VPN_POLICY_DIR_TOVPN]);
+ if (!old_ecom->refcnt)
+ ecommunity_free(&old_ecom);
+ } else {
+ new_ecom = ecommunity_dup(
+ bgp_vrf->vpn_policy[afi]
+ .rtlist[BGP_VPN_POLICY_DIR_TOVPN]);
+ }
+ static_attr.ecommunity = new_ecom;
+ SET_FLAG(static_attr.flag, ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES));
+
+ if (debug) {
+ const char *s = "";
+
+ if (static_attr.ecommunity) {
+ s = ecommunity_ecom2str(static_attr.ecommunity,
+ ECOMMUNITY_FORMAT_ROUTE_MAP, 0);
+ }
+ zlog_debug("%s: post merge static_attr.ecommunity{%s}",
+ __func__, s);
+ }
+
+ /* Nexthop */
+ /* 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
+ */
+ static_attr.nexthop.s_addr = nexthop->u.prefix4.s_addr;
+
+ static_attr.mp_nexthop_global_in = nexthop->u.prefix4;
+ static_attr.mp_nexthop_len = 4;
+ break;
+
+ case AF_INET6:
+ static_attr.mp_nexthop_global = nexthop->u.prefix6;
+ static_attr.mp_nexthop_len = 16;
+ break;
+
+ default:
+ 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;
+ }
+ }
+
+ 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;
+ } else {
+ encode_label(label_val, &label);
+ }
+
+ /* Set originator ID to "me" */
+ SET_FLAG(static_attr.flag, ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID));
+ static_attr.originator_id = bgp_vpn->router_id;
+
+
+ new_attr = bgp_attr_intern(
+ &static_attr); /* hashed refcounted everything */
+ bgp_attr_flush(&static_attr); /* free locally-allocated parts */
+
+ if (debug) {
+ const char *s = "";
+
+ if (new_attr->ecommunity) {
+ s = ecommunity_ecom2str(new_attr->ecommunity,
+ ECOMMUNITY_FORMAT_ROUTE_MAP, 0);
+ }
+ zlog_debug("%s: new_attr->ecommunity{%s}", __func__, s);
+ }
+
+ /* Now new_attr is an allocated interned attr */
+
+ bn = bgp_afi_node_get(bgp_vpn->rib[afi][safi], afi, safi, p,
+ &(bgp_vrf->vpn_policy[afi].tovpn_rd));
+
+ 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);
+
+ /*
+ * Routes actually installed in the vpn RIB must also be
+ * offered to all vrfs (because now they originate from
+ * the vpn RIB).
+ *
+ * Acceptance into other vrfs depends on rt-lists.
+ * Originating vrf will not accept the looped back route
+ * because of loop checking.
+ */
+ if (new_info)
+ vpn_leak_to_vrf_update(bgp_vrf, new_info);
+}
+
+void vpn_leak_from_vrf_withdraw(struct bgp *bgp_vpn, /* to */
+ struct bgp *bgp_vrf, /* from */
+ struct bgp_info *info_vrf) /* route */
+{
+ int debug = BGP_DEBUG(vpn, VPN_LEAK_FROM_VRF);
+ struct prefix *p = &info_vrf->net->p;
+ afi_t afi = family2afi(p->family);
+ safi_t safi = SAFI_MPLS_VPN;
+ struct bgp_info *bi;
+ struct bgp_node *bn;
+ const char *debugmsg;
+
+ if (info_vrf->type != ZEBRA_ROUTE_BGP) {
+ if (debug)
+ zlog_debug("%s: wrong type %d", __func__,
+ info_vrf->type);
+ return;
+ }
+ if (info_vrf->sub_type != BGP_ROUTE_NORMAL
+ && info_vrf->sub_type != BGP_ROUTE_STATIC) {
+
+ if (debug)
+ zlog_debug("%s: wrong sub_type %d", __func__,
+ info_vrf->sub_type);
+ return;
+ }
+ if (!bgp_vpn)
+ return;
+
+ if (!afi) {
+ if (debug)
+ zlog_debug("%s: can't get afi of prefix", __func__);
+ return;
+ }
+
+ if (!vpn_leak_to_vpn_active(bgp_vrf, afi, &debugmsg)) {
+ if (debug)
+ zlog_debug("%s: skipping: %s", __func__, debugmsg);
+ return;
+ }
+
+ if (debug)
+ zlog_debug("%s: withdrawing (info_vrf=%p)", __func__, info_vrf);
+
+ bn = bgp_afi_node_get(bgp_vpn->rib[afi][safi], afi, safi, p,
+ &(bgp_vrf->vpn_policy[afi].tovpn_rd));
+
+ /*
+ * vrf -> vpn
+ * match original bi imported from
+ */
+ for (bi = (bn ? bn->info : NULL); bi; bi = bi->next) {
+ if (bi->extra && bi->extra->parent == info_vrf) {
+ break;
+ }
+ }
+
+ if (bi) {
+ /* withdraw from looped vrfs as well */
+ vpn_leak_to_vrf_withdraw(bgp_vpn, bi);
+
+ bgp_aggregate_decrement(bgp_vpn, p, bi, afi, safi);
+ bgp_info_delete(bn, bi);
+ bgp_process(bgp_vpn, bn, afi, safi);
+ }
+ bgp_unlock_node(bn);
+}
+
+void vpn_leak_from_vrf_withdraw_all(struct bgp *bgp_vpn, /* to */
+ struct bgp *bgp_vrf, /* from */
+ afi_t afi)
+{
+ int debug = BGP_DEBUG(vpn, VPN_LEAK_FROM_VRF);
+ struct bgp_node *prn;
+ safi_t safi = SAFI_MPLS_VPN;
+
+ /*
+ * Walk vpn table, delete bi with parent == bgp_vrf
+ * Walk vpn table, delete bi with bgp_orig == bgp_vrf
+ */
+ for (prn = bgp_table_top(bgp_vpn->rib[afi][safi]); prn;
+ prn = bgp_route_next(prn)) {
+
+ struct bgp_table *table;
+ struct bgp_node *bn;
+ struct bgp_info *bi;
+
+ /* This is the per-RD table of prefixes */
+ table = prn->info;
+
+ if (!table)
+ continue;
+
+ for (bn = bgp_table_top(table); bn; bn = bgp_route_next(bn)) {
+
+ char buf[PREFIX2STR_BUFFER];
+
+ if (debug && bn->info) {
+ zlog_debug(
+ "%s: looking at prefix %s", __func__,
+ prefix2str(&bn->p, buf, sizeof(buf)));
+ }
+
+ for (bi = bn->info; bi; bi = bi->next) {
+ if (debug)
+ zlog_debug("%s: type %d, sub_type %d",
+ __func__, bi->type,
+ bi->sub_type);
+ if (bi->sub_type != BGP_ROUTE_IMPORTED)
+ continue;
+ if (!bi->extra)
+ continue;
+ if ((struct bgp *)bi->extra->bgp_orig
+ == bgp_vrf) {
+ /* delete route */
+ if (debug)
+ zlog_debug("%s: deleting it\n",
+ __func__);
+ bgp_aggregate_decrement(bgp_vpn, &bn->p,
+ bi, afi, safi);
+ bgp_info_delete(bn, bi);
+ bgp_process(bgp_vpn, bn, afi, safi);
+ }
+ }
+ }
+ }
+}
+
+void vpn_leak_from_vrf_update_all(struct bgp *bgp_vpn, /* to */
+ struct bgp *bgp_vrf, /* from */
+ afi_t afi)
+{
+ struct bgp_node *bn;
+ struct bgp_info *bi;
+ int debug = BGP_DEBUG(vpn, VPN_LEAK_FROM_VRF);
+
+ if (debug)
+ zlog_debug("%s: entry, afi=%d, vrf=%s", __func__, afi,
+ bgp_vrf->name);
+
+ for (bn = bgp_table_top(bgp_vrf->rib[afi][SAFI_UNICAST]); bn;
+ bn = bgp_route_next(bn)) {
+
+ if (debug)
+ zlog_debug("%s: node=%p", __func__, bn);
+
+ for (bi = bn->info; bi; bi = bi->next) {
+ if (debug)
+ zlog_debug(
+ "%s: calling vpn_leak_from_vrf_update",
+ __func__);
+ vpn_leak_from_vrf_update(bgp_vpn, bgp_vrf, bi);
+ }
+ }
+}
+
+static void vpn_leak_to_vrf_update_onevrf(struct bgp *bgp_vrf, /* to */
+ struct bgp *bgp_vpn, /* from */
+ struct bgp_info *info_vpn) /* route */
+{
+ struct prefix *p = &info_vpn->net->p;
+ afi_t afi = family2afi(p->family);
+
+ struct bgp_redist *red;
+ struct attr static_attr = {0};
+ struct attr *new_attr = NULL;
+ struct bgp_node *bn;
+ safi_t safi = SAFI_UNICAST;
+ const char *debugmsg;
+ struct prefix nexthop_orig;
+ mpls_label_t *pLabels = NULL;
+ int num_labels = 0;
+
+ int debug = BGP_DEBUG(vpn, VPN_LEAK_TO_VRF);
+
+ if (!vpn_leak_from_vpn_active(bgp_vrf, afi, &debugmsg, &red)) {
+ if (debug)
+ zlog_debug("%s: skipping: %s", __func__, debugmsg);
+ return;
+ }
+
+ /* Check for intersection of route targets */
+ if (!ecom_intersect(
+ bgp_vrf->vpn_policy[afi].rtlist[BGP_VPN_POLICY_DIR_FROMVPN],
+ info_vpn->attr->ecommunity)) {
+
+ return;
+ }
+
+ if (debug)
+ zlog_debug("%s: updating to vrf %s", __func__, bgp_vrf->name);
+
+ bgp_attr_dup(&static_attr, info_vpn->attr); /* shallow copy */
+
+ /*
+ * Nexthop: stash and clear
+ *
+ * Nexthop is valid in context of VPN core, but not in destination vrf.
+ * Stash it for later label resolution by vrf ingress path and then
+ * overwrite with 0, i.e., "me", for the sake of vrf advertisement.
+ */
+ uint8_t nhfamily = NEXTHOP_FAMILY(info_vpn->attr->mp_nexthop_len);
+
+ memset(&nexthop_orig, 0, sizeof(nexthop_orig));
+ 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);
+
+ 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 */
+ break;
+ }
+
+
+ /*
+ * route map handling
+ * For now, we apply two route maps: the "redist" route map and the
+ * vpn-policy route map. Once we finalize CLI syntax, one of these
+ * route maps will probably go away.
+ */
+ if (red->rmap.map) {
+ struct bgp_info info;
+ route_map_result_t ret;
+
+ memset(&info, 0, sizeof(info));
+ info.peer = bgp_vrf->peer_self;
+ info.attr = &static_attr;
+ ret = route_map_apply(red->rmap.map, p, RMAP_BGP, &info);
+ if (RMAP_DENYMATCH == ret) {
+ bgp_attr_flush(&static_attr); /* free any added parts */
+ if (debug)
+ zlog_debug(
+ "%s: vrf %s redist route map \"%s\" says DENY, skipping",
+ __func__, bgp_vrf->name,
+ red->rmap.name);
+ return;
+ }
+ }
+ if (bgp_vrf->vpn_policy[afi].rmap[BGP_VPN_POLICY_DIR_FROMVPN]) {
+ struct bgp_info info;
+ route_map_result_t ret;
+
+ memset(&info, 0, sizeof(info));
+ info.peer = bgp_vrf->peer_self;
+ info.attr = &static_attr;
+ ret = route_map_apply(bgp_vrf->vpn_policy[afi]
+ .rmap[BGP_VPN_POLICY_DIR_FROMVPN],
+ p, RMAP_BGP, &info);
+ if (RMAP_DENYMATCH == ret) {
+ bgp_attr_flush(&static_attr); /* free any added parts */
+ if (debug)
+ zlog_debug(
+ "%s: vrf %s vpn-policy route map \"%s\" says DENY, returning",
+ __func__, bgp_vrf->name,
+ bgp_vrf->vpn_policy[afi]
+ .rmap[BGP_VPN_POLICY_DIR_FROMVPN]
+ ->name);
+ return;
+ }
+ }
+
+ new_attr = bgp_attr_intern(&static_attr);
+ bgp_attr_flush(&static_attr);
+
+ bn = bgp_afi_node_get(bgp_vrf->rib[afi][safi], afi, safi, p, NULL);
+
+ /*
+ * ensure labels are copied
+ */
+ 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 (debug) {
+ char buf_prefix[PREFIX_STRLEN];
+ prefix2str(p, buf_prefix, sizeof(buf_prefix));
+ zlog_debug("%s: pfx %s: num_labels %d", __func__, 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);
+}
+
+void vpn_leak_to_vrf_update(struct bgp *bgp_vpn, /* from */
+ struct bgp_info *info_vpn) /* route */
+{
+ struct listnode *mnode, *mnnode;
+ struct bgp *bgp;
+
+ int debug = BGP_DEBUG(vpn, VPN_LEAK_TO_VRF);
+
+ if (debug)
+ zlog_debug("%s: start (info_vpn=%p)", __func__, info_vpn);
+
+ /* Loop over VRFs */
+ for (ALL_LIST_ELEMENTS(bm->bgp, mnode, mnnode, bgp)) {
+
+ if (!info_vpn->extra
+ || info_vpn->extra->bgp_orig != bgp) { /* no loop */
+ vpn_leak_to_vrf_update_onevrf(bgp, bgp_vpn, info_vpn);
+ }
+ }
+}
+
+void vpn_leak_to_vrf_withdraw(struct bgp *bgp_vpn, /* from */
+ struct bgp_info *info_vpn) /* route */
+{
+ struct prefix *p = &info_vpn->net->p;
+ afi_t afi = family2afi(p->family);
+ safi_t safi = SAFI_UNICAST;
+ struct bgp *bgp;
+ struct listnode *mnode, *mnnode;
+ struct bgp_redist *red;
+ struct bgp_node *bn;
+ struct bgp_info *bi;
+ const char *debugmsg;
+
+ int debug = BGP_DEBUG(vpn, VPN_LEAK_TO_VRF);
+
+ if (debug)
+ zlog_debug("%s: start (info_vpn=%p)", __func__, info_vpn);
+
+
+ /* Loop over VRFs */
+ for (ALL_LIST_ELEMENTS(bm->bgp, mnode, mnnode, bgp)) {
+ if (!vpn_leak_from_vpn_active(bgp, afi, &debugmsg, &red)) {
+ if (debug)
+ zlog_debug("%s: skipping: %s", __func__,
+ debugmsg);
+ continue;
+ }
+
+ /* Check for intersection of route targets */
+ if (!ecom_intersect(bgp->vpn_policy[afi]
+ .rtlist[BGP_VPN_POLICY_DIR_FROMVPN],
+ info_vpn->attr->ecommunity)) {
+
+ continue;
+ }
+
+ if (debug)
+ zlog_debug("%s: withdrawing from vrf %s", __func__,
+ bgp->name);
+
+ bn = bgp_afi_node_get(bgp->rib[afi][safi], afi, safi, p, NULL);
+ for (bi = (bn ? bn->info : NULL); bi; bi = bi->next) {
+ if (bi->extra
+ && (struct bgp_info *)bi->extra->parent
+ == info_vpn) {
+ break;
+ }
+ }
+
+ if (bi) {
+ if (debug)
+ zlog_debug("%s: deleting bi %p", __func__, bi);
+ bgp_aggregate_decrement(bgp, p, bi, afi, safi);
+ bgp_info_delete(bn, bi);
+ bgp_process(bgp, bn, afi, safi);
+ }
+ bgp_unlock_node(bn);
+ }
+}
+
+void vpn_leak_to_vrf_withdraw_all(struct bgp *bgp_vrf, /* to */
+ afi_t afi)
+{
+ struct bgp_node *bn;
+ 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
+ */
+ 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) {
+
+ /* delete route */
+ bgp_aggregate_decrement(bgp_vrf, &bn->p, bi,
+ afi, safi);
+ bgp_info_delete(bn, bi);
+ bgp_process(bgp_vrf, bn, afi, safi);
+ }
+ }
+ }
+}
+
+void vpn_leak_to_vrf_update_all(struct bgp *bgp_vrf, /* to */
+ struct bgp *bgp_vpn, /* from */
+ afi_t afi)
+{
+ struct prefix_rd prd;
+ struct bgp_node *prn;
+ safi_t safi = SAFI_MPLS_VPN;
+
+ /*
+ * Walk vpn table
+ */
+ for (prn = bgp_table_top(bgp_vpn->rib[afi][safi]); prn;
+ prn = bgp_route_next(prn)) {
+
+ struct bgp_table *table;
+ struct bgp_node *bn;
+ struct bgp_info *bi;
+
+ memset(&prd, 0, sizeof(prd));
+ prd.family = AF_UNSPEC;
+ prd.prefixlen = 64;
+ memcpy(prd.val, prn->p.u.val, 8);
+
+ /* This is the per-RD table of prefixes */
+ table = prn->info;
+
+ if (!table)
+ continue;
+
+ for (bn = bgp_table_top(table); bn; bn = bgp_route_next(bn)) {
+
+ for (bi = bn->info; bi; bi = bi->next) {
+
+ if (bi->extra && bi->extra->bgp_orig == bgp_vrf)
+ continue;
+
+ vpn_leak_to_vrf_update_onevrf(bgp_vrf, bgp_vpn,
+ bi);
+ }
+ }
+ }
+}
+
+static void vpn_policy_routemap_update(struct bgp *bgp, const char *rmap_name)
+{
+ int debug = BGP_DEBUG(vpn, VPN_LEAK_RMAP_EVENT);
+ afi_t afi;
+ struct route_map *rmap;
+
+ if (bgp->inst_type != BGP_INSTANCE_TYPE_DEFAULT
+ && bgp->inst_type != BGP_INSTANCE_TYPE_VRF) {
+
+ return;
+ }
+
+ rmap = route_map_lookup_by_name(rmap_name); /* NULL if deleted */
+
+ 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,
+ bgp->vpn_policy[afi]
+ .rmap_name[BGP_VPN_POLICY_DIR_TOVPN])) {
+
+ if (debug)
+ zlog_debug(
+ "%s: rmap \"%s\" matches vrf-policy tovpn for as %d afi %s",
+ __func__, rmap_name, bgp->as,
+ afi2str(afi));
+
+ vpn_leak_prechange(BGP_VPN_POLICY_DIR_TOVPN, afi,
+ bgp_get_default(), bgp);
+ if (debug)
+ zlog_debug("%s: after vpn_leak_prechange",
+ __func__);
+
+ if (!rmap)
+ bgp->vpn_policy[afi]
+ .rmap[BGP_VPN_POLICY_DIR_TOVPN] = NULL;
+
+ vpn_leak_postchange(BGP_VPN_POLICY_DIR_TOVPN, afi,
+ bgp_get_default(), bgp);
+ if (debug)
+ zlog_debug("%s: after vpn_leak_postchange",
+ __func__);
+ }
+
+ /*
+ * vpn -> vrf leaking currently can have two route-maps:
+ * 1. the vpn-policy tovpn route-map
+ * 2. the (per-afi) redistribute vpn route-map
+ */
+ char *mapname_vpn_policy =
+ bgp->vpn_policy[afi]
+ .rmap_name[BGP_VPN_POLICY_DIR_FROMVPN];
+ struct bgp_redist *red = NULL;
+
+ if (vpn_leak_from_vpn_active(bgp, afi, NULL, &red)
+ && ((mapname_vpn_policy
+ && !strcmp(rmap_name, mapname_vpn_policy))
+ || (red && red->rmap.name
+ && !strcmp(red->rmap.name, rmap_name)))) {
+
+ if (debug)
+ zlog_debug(
+ "%s: rmap \"%s\" matches vrf-policy fromvpn"
+ " for as %d afi %s",
+ __func__, rmap_name, bgp->as,
+ afi2str(afi));
+
+ 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;
+
+ vpn_leak_postchange(BGP_VPN_POLICY_DIR_FROMVPN, afi,
+ bgp_get_default(), bgp);
+ }
+ }
+}
+
+void vpn_policy_routemap_event(const char *rmap_name)
+{
+ int debug = BGP_DEBUG(vpn, VPN_LEAK_RMAP_EVENT);
+ struct listnode *mnode, *mnnode;
+ struct bgp *bgp;
+
+ if (debug)
+ zlog_debug("%s: entry", __func__);
+
+ if (bm->bgp == NULL) /* may be called during cleanup */
+ return;
+
+ for (ALL_LIST_ELEMENTS(bm->bgp, mnode, mnnode, bgp))
+ vpn_policy_routemap_update(bgp, rmap_name);
+}
+
/* For testing purpose, static route of MPLS-VPN. */
DEFUN (vpnv4_network,
vpnv4_network_cmd,
diff --git a/bgpd/bgp_mplsvpn.h b/bgpd/bgp_mplsvpn.h
index 5c11f7526c..d0ad8ac846 100644
--- a/bgpd/bgp_mplsvpn.h
+++ b/bgpd/bgp_mplsvpn.h
@@ -23,6 +23,7 @@
#include "bgpd/bgp_route.h"
#include "bgpd/bgp_rd.h"
+#include "bgpd/bgp_zebra.h"
#define MPLS_LABEL_IS_SPECIAL(label) ((label) <= MPLS_LABEL_EXTENSION)
#define MPLS_LABEL_IS_NULL(label) \
@@ -51,4 +52,122 @@ extern 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);
+extern void vpn_leak_from_vrf_update(struct bgp *bgp_vpn, struct bgp *bgp_vrf,
+ struct bgp_info *info_vrf);
+
+extern void vpn_leak_from_vrf_withdraw(struct bgp *bgp_vpn, struct bgp *bgp_vrf,
+ struct bgp_info *info_vrf);
+
+extern void vpn_leak_from_vrf_withdraw_all(struct bgp *bgp_vpn,
+ struct bgp *bgp_vrf, afi_t afi);
+
+extern void vpn_leak_from_vrf_update_all(struct bgp *bgp_vpn,
+ struct bgp *bgp_vrf, afi_t afi);
+
+extern void vpn_leak_to_vrf_withdraw_all(struct bgp *bgp_vrf, afi_t afi);
+
+extern void vpn_leak_to_vrf_update_all(struct bgp *bgp_vrf, struct bgp *bgp_vpn,
+ afi_t afi);
+
+extern void vpn_leak_to_vrf_update(struct bgp *bgp_vpn,
+ struct bgp_info *info_vpn);
+
+extern void vpn_leak_to_vrf_withdraw(struct bgp *bgp_vpn,
+ struct bgp_info *info_vpn);
+
+extern void vpn_leak_zebra_vrf_label_update(struct bgp *bgp, afi_t afi);
+extern void vpn_leak_zebra_vrf_label_withdraw(struct bgp *bgp, afi_t afi);
+
+static inline int vpn_leak_to_vpn_active(struct bgp *bgp_vrf, afi_t afi,
+ const char **pmsg)
+{
+ /* Is vrf configured to export to vpn? */
+ if (!CHECK_FLAG(bgp_vrf->af_flags[afi][SAFI_UNICAST],
+ BGP_CONFIG_VRF_TO_MPLSVPN_EXPORT)) {
+ if (pmsg)
+ *pmsg = "export not set";
+ return 0;
+ }
+
+ /* Is there an RT list set? */
+ if (!bgp_vrf->vpn_policy[afi].rtlist[BGP_VPN_POLICY_DIR_TOVPN]) {
+ if (pmsg)
+ *pmsg = "rtlist tovpn not defined";
+ return 0;
+ }
+
+ /* Is there an RD set? */
+ if (!CHECK_FLAG(bgp_vrf->vpn_policy[afi].flags,
+ BGP_VPN_POLICY_TOVPN_RD_SET)) {
+ if (pmsg)
+ *pmsg = "rd not defined";
+ return 0;
+ }
+ return 1;
+}
+
+static inline int vpn_leak_from_vpn_active(struct bgp *bgp_vrf, afi_t afi,
+ const char **pmsg,
+ struct bgp_redist **pred)
+{
+ struct bgp_redist *red;
+
+ if (bgp_vrf->inst_type != BGP_INSTANCE_TYPE_VRF
+ && bgp_vrf->inst_type != BGP_INSTANCE_TYPE_DEFAULT) {
+
+ if (pmsg)
+ *pmsg = "destination bgp instance neither vrf nor default";
+ return 0;
+ }
+
+ /* Hijack zebra redist bits for this route type */
+ red = bgp_redist_lookup(bgp_vrf, afi, ZEBRA_ROUTE_BGP_VPN, 0);
+ if (red) {
+ if (pred)
+ *pred = red;
+ } else {
+ if (pmsg)
+ *pmsg = "redist not set";
+ return 0;
+ }
+ if (!bgp_vrf->vpn_policy[afi].rtlist[BGP_VPN_POLICY_DIR_FROMVPN]) {
+ if (pmsg)
+ *pmsg = "rtlist fromvpn not defined";
+ return 0;
+ }
+ return 1;
+}
+
+static inline void vpn_leak_prechange(vpn_policy_direction_t direction,
+ afi_t afi, struct bgp *bgp_vpn,
+ struct bgp *bgp_vrf)
+{
+ if (direction == BGP_VPN_POLICY_DIR_FROMVPN)
+ vpn_leak_to_vrf_withdraw_all(bgp_vrf, afi);
+ if (direction == BGP_VPN_POLICY_DIR_TOVPN)
+ vpn_leak_from_vrf_withdraw_all(bgp_vpn, bgp_vrf, afi);
+}
+
+static inline void vpn_leak_postchange(vpn_policy_direction_t direction,
+ afi_t afi, struct bgp *bgp_vpn,
+ struct bgp *bgp_vrf)
+{
+ if (direction == BGP_VPN_POLICY_DIR_FROMVPN)
+ 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
+ != bgp_vrf->vpn_policy[afi]
+ .tovpn_zebra_vrf_label_last_sent) {
+ vpn_leak_zebra_vrf_label_update(bgp_vrf, afi);
+ }
+
+ vpn_leak_from_vrf_update_all(bgp_vpn, bgp_vrf, afi);
+ }
+ if (direction == BGP_VPN_POLICY_DIR_TOVPN)
+ vpn_leak_from_vrf_update_all(bgp_vpn, bgp_vrf, afi);
+}
+
+extern void vpn_policy_routemap_event(const char *rmap_name);
+
#endif /* _QUAGGA_BGP_MPLSVPN_H */
diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c
index fd0c87c8ca..032b33229c 100644
--- a/bgpd/bgp_route.c
+++ b/bgpd/bgp_route.c
@@ -1379,6 +1379,16 @@ int subgroup_announce_check(struct bgp_node *rn, struct bgp_info *ri,
}
#endif
+ if (((afi == AFI_IP) || (afi == AFI_IP6))
+ && ((safi == SAFI_MPLS_VPN) || (safi == SAFI_UNICAST))
+ && (ri->type == ZEBRA_ROUTE_BGP)
+ && (ri->sub_type == BGP_ROUTE_IMPORTED)) {
+
+ /* Applies to routes leaked vpn->vrf and vrf->vpn */
+
+ samepeer_safe = 1;
+ }
+
/* With addpath we may be asked to TX all kinds of paths so make sure
* ri is valid */
if (!CHECK_FLAG(ri->flags, BGP_INFO_VALID)
@@ -1867,17 +1877,30 @@ void bgp_best_selection(struct bgp *bgp, struct bgp_node *rn,
&& (ri != old_select))
bgp_info_reap(rn, ri);
+ if (debug)
+ zlog_debug("%s: ri %p in holddown", __func__,
+ ri);
+
continue;
}
if (ri->peer && ri->peer != bgp->peer_self
&& !CHECK_FLAG(ri->peer->sflags, PEER_STATUS_NSF_WAIT))
- if (ri->peer->status != Established)
+ if (ri->peer->status != Established) {
+
+ if (debug)
+ zlog_debug(
+ "%s: ri %p non self peer %s not estab state",
+ __func__, ri, ri->peer->host);
+
continue;
+ }
if (bgp_flag_check(bgp, BGP_FLAG_DETERMINISTIC_MED)
&& (!CHECK_FLAG(ri->flags, BGP_INFO_DMED_SELECTED))) {
bgp_info_unset_flag(rn, ri, BGP_INFO_DMED_CHECK);
+ if (debug)
+ zlog_debug("%s: ri %p dmed", __func__, ri);
continue;
}
@@ -1981,6 +2004,13 @@ int subgroup_process_announce_selected(struct update_subgroup *subgrp,
onlypeer = ((SUBGRP_PCOUNT(subgrp) == 1) ? (SUBGRP_PFIRST(subgrp))->peer
: NULL);
+ if (BGP_DEBUG(update, UPDATE_OUT)) {
+ char buf_prefix[PREFIX_STRLEN];
+ prefix2str(p, buf_prefix, sizeof(buf_prefix));
+ zlog_debug("%s: p=%s, selected=%p", __func__, buf_prefix,
+ selected);
+ }
+
/* First update is deferred until ORF or ROUTE-REFRESH is received */
if (onlypeer && CHECK_FLAG(onlypeer->af_sflags[afi][safi],
PEER_STATUS_ORF_WAIT_REFRESH))
@@ -2072,6 +2102,8 @@ static void bgp_process_main_one(struct bgp *bgp, struct bgp_node *rn,
struct bgp_info *new_select;
struct bgp_info *old_select;
struct bgp_info_pair old_and_new;
+ char pfx_buf[PREFIX2STR_BUFFER];
+ int debug = 0;
/* Is it end of initial update? (after startup) */
if (!rn) {
@@ -2089,6 +2121,13 @@ static void bgp_process_main_one(struct bgp *bgp, struct bgp_node *rn,
return;
}
+ debug = bgp_debug_bestpath(&rn->p);
+ if (debug) {
+ prefix2str(&rn->p, pfx_buf, sizeof(pfx_buf));
+ zlog_debug("%s: p=%s afi=%s, safi=%s start", __func__, pfx_buf,
+ afi2str(afi), safi2str(safi));
+ }
+
/* Best path selection. */
bgp_best_selection(bgp, rn, &bgp->maxpaths[afi][safi], &old_and_new,
afi, safi);
@@ -2129,6 +2168,14 @@ static void bgp_process_main_one(struct bgp *bgp, struct bgp_node *rn,
bgp_unregister_for_label(rn);
}
+ if (debug) {
+ prefix2str(&rn->p, pfx_buf, sizeof(pfx_buf));
+ zlog_debug(
+ "%s: p=%s afi=%s, safi=%s, old_select=%p, new_select=%p",
+ __func__, pfx_buf, afi2str(afi), safi2str(safi),
+ old_select, new_select);
+ }
+
/* If best route remains the same and this is not due to user-initiated
* clear, see exactly what needs to be done.
*/
@@ -2143,11 +2190,16 @@ static void bgp_process_main_one(struct bgp *bgp, struct bgp_node *rn,
vnc_import_bgp_exterior_add_route(bgp, p, old_select);
#endif
if (bgp_fibupd_safi(safi)
- && !bgp_option_check(BGP_OPT_NO_FIB)
- && new_select->type == ZEBRA_ROUTE_BGP
- && new_select->sub_type == BGP_ROUTE_NORMAL)
- bgp_zebra_announce(rn, p, old_select, bgp, afi,
- safi);
+ && !bgp_option_check(BGP_OPT_NO_FIB)) {
+
+ if (new_select->type == ZEBRA_ROUTE_BGP
+ && (new_select->sub_type == BGP_ROUTE_NORMAL
+ || new_select->sub_type
+ == BGP_ROUTE_IMPORTED))
+
+ bgp_zebra_announce(rn, p, old_select,
+ bgp, afi, safi);
+ }
}
UNSET_FLAG(old_select->flags, BGP_INFO_MULTIPATH_CHG);
bgp_zebra_clear_route_change_flags(rn);
@@ -2194,6 +2246,8 @@ static void bgp_process_main_one(struct bgp *bgp, struct bgp_node *rn,
if (old_select)
bgp_info_unset_flag(rn, old_select, BGP_INFO_SELECTED);
if (new_select) {
+ if (debug)
+ zlog_debug("%s: setting SELECTED flag", __func__);
bgp_info_set_flag(rn, new_select, BGP_INFO_SELECTED);
bgp_info_unset_flag(rn, new_select, BGP_INFO_ATTR_CHANGED);
UNSET_FLAG(new_select->flags, BGP_INFO_MULTIPATH_CHG);
@@ -2229,13 +2283,17 @@ static void bgp_process_main_one(struct bgp *bgp, struct bgp_node *rn,
&& !bgp_option_check(BGP_OPT_NO_FIB)) {
if (new_select && new_select->type == ZEBRA_ROUTE_BGP
&& (new_select->sub_type == BGP_ROUTE_NORMAL
- || new_select->sub_type == BGP_ROUTE_AGGREGATE))
+ || new_select->sub_type == BGP_ROUTE_AGGREGATE
+ || new_select->sub_type == BGP_ROUTE_IMPORTED))
+
bgp_zebra_announce(rn, p, new_select, bgp, afi, safi);
else {
/* Withdraw the route from the kernel. */
if (old_select && old_select->type == ZEBRA_ROUTE_BGP
&& (old_select->sub_type == BGP_ROUTE_NORMAL
- || old_select->sub_type == BGP_ROUTE_AGGREGATE))
+ || old_select->sub_type == BGP_ROUTE_AGGREGATE
+ || old_select->sub_type == BGP_ROUTE_IMPORTED))
+
bgp_zebra_withdraw(p, old_select, safi);
}
}
@@ -3137,6 +3195,18 @@ int bgp_update(struct peer *peer, struct prefix *p, u_int32_t addpath_id,
bgp_process(bgp, rn, afi, safi);
bgp_unlock_node(rn);
+ if (SAFI_UNICAST == safi
+ && (bgp->inst_type == BGP_INSTANCE_TYPE_VRF
+ || bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT)) {
+
+ vpn_leak_from_vrf_update(bgp_get_default(), bgp, ri);
+ }
+ if ((SAFI_MPLS_VPN == safi)
+ && (bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT)) {
+
+ vpn_leak_to_vrf_update(bgp, ri);
+ }
+
#if ENABLE_BGP_VNC
if (SAFI_MPLS_VPN == safi) {
mpls_label_t label_decoded = decode_label(label);
@@ -3253,6 +3323,16 @@ int bgp_update(struct peer *peer, struct prefix *p, u_int32_t addpath_id,
/* Process change. */
bgp_process(bgp, rn, afi, safi);
+ if (SAFI_UNICAST == safi
+ && (bgp->inst_type == BGP_INSTANCE_TYPE_VRF
+ || bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT)) {
+ vpn_leak_from_vrf_update(bgp_get_default(), bgp, new);
+ }
+ if ((SAFI_MPLS_VPN == safi)
+ && (bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT)) {
+
+ vpn_leak_to_vrf_update(bgp, new);
+ }
#if ENABLE_BGP_VNC
if (SAFI_MPLS_VPN == safi) {
mpls_label_t label_decoded = decode_label(label);
@@ -3291,6 +3371,18 @@ filtered:
if (safi == SAFI_EVPN)
bgp_evpn_unimport_route(bgp, afi, safi, p, ri);
+ if (SAFI_UNICAST == safi
+ && (bgp->inst_type == BGP_INSTANCE_TYPE_VRF
+ || bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT)) {
+
+ vpn_leak_from_vrf_withdraw(bgp_get_default(), bgp, ri);
+ }
+ if ((SAFI_MPLS_VPN == safi)
+ && (bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT)) {
+
+ vpn_leak_to_vrf_withdraw(bgp, ri);
+ }
+
bgp_rib_remove(rn, ri, peer, afi, safi);
}
@@ -3377,9 +3469,19 @@ int bgp_withdraw(struct peer *peer, struct prefix *p, u_int32_t addpath_id,
}
/* Withdraw specified route from routing table. */
- if (ri && !CHECK_FLAG(ri->flags, BGP_INFO_HISTORY))
+ if (ri && !CHECK_FLAG(ri->flags, BGP_INFO_HISTORY)) {
bgp_rib_withdraw(rn, ri, peer, afi, safi, prd);
- else if (bgp_debug_update(peer, p, NULL, 1)) {
+ if (SAFI_UNICAST == safi
+ && (bgp->inst_type == BGP_INSTANCE_TYPE_VRF
+ || bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT)) {
+ vpn_leak_from_vrf_withdraw(bgp_get_default(), bgp, ri);
+ }
+ if ((SAFI_MPLS_VPN == safi)
+ && (bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT)) {
+
+ vpn_leak_to_vrf_withdraw(bgp, ri);
+ }
+ } else if (bgp_debug_update(peer, p, NULL, 1)) {
bgp_debug_rdpfxpath2str(afi, safi, prd, p, label, num_labels,
addpath_id ? 1 : 0, addpath_id, pfx_buf,
sizeof(pfx_buf));
@@ -3863,7 +3965,9 @@ static void bgp_cleanup_table(struct bgp_table *table, safi_t safi)
if (CHECK_FLAG(ri->flags, BGP_INFO_SELECTED)
&& ri->type == ZEBRA_ROUTE_BGP
&& (ri->sub_type == BGP_ROUTE_NORMAL
- || ri->sub_type == BGP_ROUTE_AGGREGATE)) {
+ || ri->sub_type == BGP_ROUTE_AGGREGATE
+ || ri->sub_type == BGP_ROUTE_IMPORTED)) {
+
if (bgp_fibupd_safi(safi))
bgp_zebra_withdraw(&rn->p, ri, safi);
bgp_info_reap(rn, ri);
@@ -4264,6 +4368,15 @@ void bgp_static_update(struct bgp *bgp, struct prefix *p,
/* Process change. */
bgp_aggregate_increment(bgp, p, ri, afi, safi);
bgp_process(bgp, rn, afi, safi);
+
+ if (SAFI_UNICAST == safi
+ && (bgp->inst_type == BGP_INSTANCE_TYPE_VRF
+ || bgp->inst_type
+ == BGP_INSTANCE_TYPE_DEFAULT)) {
+ vpn_leak_from_vrf_update(bgp_get_default(), bgp,
+ ri);
+ }
+
bgp_unlock_node(rn);
aspath_unintern(&attr.aspath);
return;
@@ -4311,6 +4424,12 @@ void bgp_static_update(struct bgp *bgp, struct prefix *p,
/* Process change. */
bgp_process(bgp, rn, afi, safi);
+ if (SAFI_UNICAST == safi
+ && (bgp->inst_type == BGP_INSTANCE_TYPE_VRF
+ || bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT)) {
+ vpn_leak_from_vrf_update(bgp_get_default(), bgp, new);
+ }
+
/* Unintern original. */
aspath_unintern(&attr.aspath);
}
@@ -4331,6 +4450,11 @@ void bgp_static_withdraw(struct bgp *bgp, struct prefix *p, afi_t afi,
/* Withdraw static BGP route from routing table. */
if (ri) {
+ if (SAFI_UNICAST == safi
+ && (bgp->inst_type == BGP_INSTANCE_TYPE_VRF
+ || bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT)) {
+ vpn_leak_from_vrf_withdraw(bgp_get_default(), bgp, ri);
+ }
bgp_aggregate_decrement(bgp, p, ri, afi, safi);
bgp_unlink_nexthop(ri);
bgp_info_delete(rn, ri);
@@ -4366,6 +4490,10 @@ static void bgp_static_withdraw_safi(struct bgp *bgp, struct prefix *p,
ri->peer, NULL, p, prd, ri->attr, afi, safi, ri->type,
1); /* Kill, since it is an administrative change */
#endif
+ if (SAFI_MPLS_VPN == safi
+ && bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT) {
+ vpn_leak_to_vrf_withdraw(bgp, ri);
+ }
bgp_aggregate_decrement(bgp, p, ri, afi, safi);
bgp_info_delete(rn, ri);
bgp_process(bgp, rn, afi, safi);
@@ -4494,6 +4622,11 @@ static void bgp_static_update_safi(struct bgp *bgp, struct prefix *p,
/* Process change. */
bgp_aggregate_increment(bgp, p, ri, afi, safi);
bgp_process(bgp, rn, afi, safi);
+
+ if (SAFI_MPLS_VPN == safi
+ && bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT) {
+ vpn_leak_to_vrf_update(bgp, ri);
+ }
#if ENABLE_BGP_VNC
rfapiProcessUpdate(ri->peer, NULL, p, &bgp_static->prd,
ri->attr, afi, safi, ri->type,
@@ -4530,6 +4663,10 @@ static void bgp_static_update_safi(struct bgp *bgp, struct prefix *p,
/* Process change. */
bgp_process(bgp, rn, afi, safi);
+ if (SAFI_MPLS_VPN == safi
+ && bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT) {
+ vpn_leak_to_vrf_update(bgp, new);
+ }
#if ENABLE_BGP_VNC
rfapiProcessUpdate(new->peer, NULL, p, &bgp_static->prd, new->attr, afi,
safi, new->type, new->sub_type, &label);
@@ -5994,6 +6131,14 @@ void bgp_redistribute_add(struct bgp *bgp, struct prefix *p,
bgp_process(bgp, bn, afi, SAFI_UNICAST);
bgp_unlock_node(bn);
aspath_unintern(&attr.aspath);
+
+ if ((bgp->inst_type == BGP_INSTANCE_TYPE_VRF)
+ || (bgp->inst_type
+ == BGP_INSTANCE_TYPE_DEFAULT)) {
+
+ vpn_leak_from_vrf_update(
+ bgp_get_default(), bgp, bi);
+ }
return;
}
}
@@ -6006,6 +6151,12 @@ void bgp_redistribute_add(struct bgp *bgp, struct prefix *p,
bgp_info_add(bn, new);
bgp_unlock_node(bn);
bgp_process(bgp, bn, afi, SAFI_UNICAST);
+
+ if ((bgp->inst_type == BGP_INSTANCE_TYPE_VRF)
+ || (bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT)) {
+
+ vpn_leak_from_vrf_update(bgp_get_default(), bgp, new);
+ }
}
/* Unintern original. */
@@ -6032,6 +6183,12 @@ void bgp_redistribute_delete(struct bgp *bgp, struct prefix *p, u_char type,
break;
if (ri) {
+ if ((bgp->inst_type == BGP_INSTANCE_TYPE_VRF)
+ || (bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT)) {
+
+ vpn_leak_from_vrf_withdraw(bgp_get_default(),
+ bgp, ri);
+ }
bgp_aggregate_decrement(bgp, p, ri, afi, SAFI_UNICAST);
bgp_info_delete(rn, ri);
bgp_process(bgp, rn, afi, SAFI_UNICAST);
@@ -6057,6 +6214,12 @@ void bgp_redistribute_withdraw(struct bgp *bgp, afi_t afi, int type,
break;
if (ri) {
+ if ((bgp->inst_type == BGP_INSTANCE_TYPE_VRF)
+ || (bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT)) {
+
+ vpn_leak_from_vrf_withdraw(bgp_get_default(),
+ bgp, ri);
+ }
bgp_aggregate_decrement(bgp, &rn->p, ri, afi,
SAFI_UNICAST);
bgp_info_delete(rn, ri);
diff --git a/bgpd/bgp_route.h b/bgpd/bgp_route.h
index dffe2b8ddc..748c4f9110 100644
--- a/bgpd/bgp_route.h
+++ b/bgpd/bgp_route.h
@@ -114,6 +114,30 @@ struct bgp_info_extra {
/* For imported routes into a VNI (or VRF), this points to the parent.
*/
void *parent;
+
+ /*
+ * Some tunnelish parameters follow. Maybe consolidate into an
+ * internal tunnel structure?
+ */
+
+ /*
+ * Original bgp instance for imported routes. Needed for:
+ * 1. Find all routes from a specific vrf for deletion
+ * 2. vrf context of original nexthop
+ *
+ * Store pointer to bgp instance rather than bgp->vrf_id because
+ * bgp->vrf_id is not always valid (or may change?).
+ *
+ * Set to NULL if route is not imported from another bgp instance.
+ */
+ struct bgp *bgp_orig;
+
+ /*
+ * Nexthop in context of original bgp instance. Needed
+ * for label resolution of core mpls routes exported to a vrf.
+ * Set nexthop_orig.family to 0 if not valid.
+ */
+ struct prefix nexthop_orig;
};
struct bgp_info {
@@ -179,6 +203,7 @@ struct bgp_info {
#ifdef ENABLE_BGP_VNC
# define BGP_ROUTE_RFP 4
#endif
+#define BGP_ROUTE_IMPORTED 5 /* from another bgp instance/safi */
u_short instance;
diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c
index b6910a222d..5a265b6c9c 100644
--- a/bgpd/bgp_routemap.c
+++ b/bgpd/bgp_routemap.c
@@ -57,6 +57,7 @@
#include "bgpd/bgp_evpn.h"
#include "bgpd/bgp_evpn_private.h"
#include "bgpd/bgp_evpn_vty.h"
+#include "bgpd/bgp_mplsvpn.h"
#if ENABLE_BGP_VNC
#include "bgpd/rfapi/bgp_rfapi_cfg.h"
@@ -3114,13 +3115,17 @@ static int bgp_route_map_process_update_cb(char *rmap_name)
struct listnode *node, *nnode;
struct bgp *bgp;
- for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp))
+ for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp)) {
bgp_route_map_process_update(bgp, rmap_name, 1);
#if ENABLE_BGP_VNC
- zlog_debug("%s: calling vnc_routemap_update", __func__);
- vnc_routemap_update(bgp, __func__);
+ /* zlog_debug("%s: calling vnc_routemap_update", __func__); */
+ vnc_routemap_update(bgp, __func__);
#endif
+ }
+
+ vpn_policy_routemap_event(rmap_name);
+
return 0;
}
diff --git a/bgpd/bgp_updgrp_adv.c b/bgpd/bgp_updgrp_adv.c
index 705cb152f0..e66e5a540b 100644
--- a/bgpd/bgp_updgrp_adv.c
+++ b/bgpd/bgp_updgrp_adv.c
@@ -113,6 +113,14 @@ static int group_announce_route_walkcb(struct update_group *updgrp, void *arg)
peer = UPDGRP_PEER(updgrp);
addpath_capable = bgp_addpath_encode_tx(peer, afi, safi);
+ if (BGP_DEBUG(update, UPDATE_OUT)) {
+ char buf_prefix[PREFIX_STRLEN];
+ prefix2str(&ctx->rn->p, buf_prefix, sizeof(buf_prefix));
+ zlog_debug("%s: afi=%s, safi=%s, p=%s", __func__, afi2str(afi),
+ safi2str(safi), buf_prefix);
+ }
+
+
UPDGRP_FOREACH_SUBGRP (updgrp, subgrp) {
/*
diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c
index c8e503d72a..4a5633c94d 100644
--- a/bgpd/bgp_vty.c
+++ b/bgpd/bgp_vty.c
@@ -6112,6 +6112,526 @@ ALIAS_HIDDEN(no_neighbor_addpath_tx_bestpath_per_as,
NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR2
"Use addpath to advertise the bestpath per each neighboring AS\n")
+
+DEFUN_NOSH (vpn_policy_afi,
+ vpn_policy_afi_cmd,
+ "vpn-policy <ipv4|ipv6>",
+ "Enter vpn-policy command mode\n"
+ BGP_AFI_HELP_STR)
+{
+ VTY_DECLVAR_CONTEXT(bgp, bgp);
+ if (bgp->inst_type != BGP_INSTANCE_TYPE_VRF
+ && bgp->inst_type != BGP_INSTANCE_TYPE_DEFAULT) {
+
+ vty_out(vty,
+ "vpn-policy supported only in core or vrf instances.\n");
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+
+ afi_t afi;
+ int idx = 0;
+
+ if (argv_find_and_parse_afi(argv, argc, &idx, &afi)) {
+ if (afi == AFI_IP)
+ vty->node = BGP_VPNPOLICY_IPV4_NODE;
+ else
+ vty->node = BGP_VPNPOLICY_IPV6_NODE;
+ return CMD_SUCCESS;
+ }
+ return CMD_WARNING_CONFIG_FAILED;
+}
+
+static int vpn_policy_afis(struct vty *vty, int *doafi)
+{
+ switch (vty->node) {
+ case BGP_VPNPOLICY_IPV4_NODE:
+ doafi[AFI_IP] = 1;
+ break;
+ case BGP_VPNPOLICY_IPV6_NODE:
+ doafi[AFI_IP6] = 1;
+ break;
+ default:
+ vty_out(vty,
+ "%% context error: valid only in vpn-policy block\n");
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+ return CMD_SUCCESS;
+}
+
+static int argv_find_and_parse_vpn_policy_dirs(struct vty *vty,
+ struct cmd_token **argv,
+ int argc, int *idx, int *dodir)
+{
+ if (argv_find(argv, argc, "fromvpn", idx)) {
+ dodir[BGP_VPN_POLICY_DIR_FROMVPN] = 1;
+ } else if (argv_find(argv, argc, "tovpn", idx)) {
+ dodir[BGP_VPN_POLICY_DIR_TOVPN] = 1;
+ } else if (argv_find(argv, argc, "both", idx)) {
+ dodir[BGP_VPN_POLICY_DIR_FROMVPN] = 1;
+ dodir[BGP_VPN_POLICY_DIR_TOVPN] = 1;
+ } else {
+ vty_out(vty, "%% direction parse error\n");
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+ return CMD_SUCCESS;
+}
+
+DEFUN (vpn_policy_rd,
+ vpn_policy_rd_cmd,
+ "rd ASN:NN_OR_IP-ADDRESS:NN",
+ "Specify route distinguisher\n"
+ "Route Distinguisher (<as-number>:<number> | <ip-address>:<number>)\n")
+{
+ VTY_DECLVAR_CONTEXT(bgp, bgp);
+ struct prefix_rd prd;
+ int ret;
+ int doafi[AFI_MAX] = {0};
+ afi_t afi;
+
+ ret = str2prefix_rd(argv[1]->arg, &prd);
+ if (!ret) {
+ vty_out(vty, "%% Malformed rd\n");
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+
+ ret = vpn_policy_afis(vty, doafi);
+ if (ret != CMD_SUCCESS)
+ return ret;
+
+
+ for (afi = 0; afi < AFI_MAX; ++afi) {
+ if (!doafi[afi])
+ continue;
+
+ /* pre-change: un-export vpn routes (vpn->vrf routes unaffected)
+ */
+ vpn_leak_prechange(BGP_VPN_POLICY_DIR_TOVPN, afi,
+ bgp_get_default(), bgp);
+
+ bgp->vpn_policy[afi].tovpn_rd = prd;
+ SET_FLAG(bgp->vpn_policy[afi].flags,
+ BGP_VPN_POLICY_TOVPN_RD_SET);
+
+ /* post-change: re-export vpn routes */
+ vpn_leak_postchange(BGP_VPN_POLICY_DIR_TOVPN, afi,
+ bgp_get_default(), bgp);
+ }
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (vpn_policy_no_rd,
+ vpn_policy_no_rd_cmd,
+ "no rd",
+ NO_STR
+ "Specify route distinguisher\n")
+{
+ VTY_DECLVAR_CONTEXT(bgp, bgp);
+ int ret;
+ int doafi[AFI_MAX] = {0};
+ afi_t afi;
+
+ ret = vpn_policy_afis(vty, doafi);
+ if (ret != CMD_SUCCESS)
+ return ret;
+
+
+ for (afi = 0; afi < AFI_MAX; ++afi) {
+ if (!doafi[afi])
+ continue;
+
+ /* pre-change: un-export vpn routes (vpn->vrf routes unaffected)
+ */
+ vpn_leak_prechange(BGP_VPN_POLICY_DIR_TOVPN, afi,
+ bgp_get_default(), bgp);
+
+ UNSET_FLAG(bgp->vpn_policy[afi].flags,
+ BGP_VPN_POLICY_TOVPN_RD_SET);
+
+ /* post-change: re-export vpn routes */
+ vpn_leak_postchange(BGP_VPN_POLICY_DIR_TOVPN, afi,
+ bgp_get_default(), bgp);
+ }
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (vpn_policy_label,
+ vpn_policy_label_cmd,
+ "label (0-1048575)",
+ "label value for VRF\n"
+ "Label Value <0-1048575>\n")
+{
+ VTY_DECLVAR_CONTEXT(bgp, bgp);
+ mpls_label_t label;
+ int doafi[AFI_MAX] = {0};
+ afi_t afi;
+ int ret;
+
+ label = strtoul(argv[1]->arg, NULL, 10);
+
+ ret = vpn_policy_afis(vty, doafi);
+ if (ret != CMD_SUCCESS)
+ return ret;
+
+ for (afi = 0; afi < AFI_MAX; ++afi) {
+ if (!doafi[afi])
+ continue;
+
+ /* pre-change: un-export vpn routes (vpn->vrf routes unaffected)
+ */
+ vpn_leak_prechange(BGP_VPN_POLICY_DIR_TOVPN, afi,
+ bgp_get_default(), bgp);
+
+ bgp->vpn_policy[afi].tovpn_label = label;
+
+ /* post-change: re-export vpn routes */
+ vpn_leak_postchange(BGP_VPN_POLICY_DIR_TOVPN, afi,
+ bgp_get_default(), bgp);
+ }
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (vpn_policy_no_label,
+ vpn_policy_no_label_cmd,
+ "no label",
+ "Negate a command or set its defaults\n"
+ "label value for VRF\n")
+{
+ VTY_DECLVAR_CONTEXT(bgp, bgp);
+ int doafi[AFI_MAX] = {0};
+ afi_t afi;
+ int ret;
+
+ ret = vpn_policy_afis(vty, doafi);
+ if (ret != CMD_SUCCESS)
+ return ret;
+
+ for (afi = 0; afi < AFI_MAX; ++afi) {
+ if (!doafi[afi])
+ continue;
+
+ /* pre-change: un-export vpn routes (vpn->vrf routes unaffected)
+ */
+ vpn_leak_prechange(BGP_VPN_POLICY_DIR_TOVPN, afi,
+ bgp_get_default(), bgp);
+
+ bgp->vpn_policy[afi].tovpn_label = MPLS_LABEL_NONE;
+
+ /* post-change: re-export vpn routes */
+ vpn_leak_postchange(BGP_VPN_POLICY_DIR_TOVPN, afi,
+ bgp_get_default(), bgp);
+ }
+
+ return CMD_SUCCESS;
+}
+
+DEFPY (vpn_policy_nexthop,
+ vpn_policy_nexthop_cmd,
+ "nexthop <A.B.C.D|X:X::X:X>$nexthop",
+ "Specify next hop to use for VRF advertised prefixes\n"
+ "IPv4 prefix\n"
+ "IPv6 prefix\n")
+{
+ VTY_DECLVAR_CONTEXT(bgp, bgp);
+ int doafi[AFI_MAX] = {0};
+ afi_t afi;
+ int ret;
+ struct prefix p;
+
+ if (!sockunion2hostprefix(nexthop, &p))
+ return CMD_WARNING_CONFIG_FAILED;
+
+ ret = vpn_policy_afis(vty, doafi);
+ if (ret != CMD_SUCCESS)
+ return ret;
+
+ for (afi = 0; afi < AFI_MAX; ++afi) {
+ if (!doafi[afi])
+ continue;
+
+ /*
+ * pre-change: un-export vpn routes (vpn->vrf routes unaffected)
+ */
+ vpn_leak_prechange(BGP_VPN_POLICY_DIR_TOVPN, afi,
+ bgp_get_default(), bgp);
+
+ bgp->vpn_policy[afi].tovpn_nexthop = p;
+ SET_FLAG(bgp->vpn_policy[afi].flags,
+ BGP_VPN_POLICY_TOVPN_NEXTHOP_SET);
+
+ /* post-change: re-export vpn routes */
+ vpn_leak_postchange(BGP_VPN_POLICY_DIR_TOVPN, afi,
+ bgp_get_default(), bgp);
+ }
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (vpn_policy_no_nexthop,
+ vpn_policy_no_nexthop_cmd,
+ "no nexthop",
+ NO_STR
+ "Specify next hop to use for VRF advertised prefixes\n")
+{
+ VTY_DECLVAR_CONTEXT(bgp, bgp);
+ int doafi[AFI_MAX] = {0};
+ afi_t afi;
+ int ret;
+
+ ret = vpn_policy_afis(vty, doafi);
+ if (ret != CMD_SUCCESS)
+ return ret;
+
+ for (afi = 0; afi < AFI_MAX; ++afi) {
+ if (!doafi[afi])
+ continue;
+
+ /* pre-change: un-export vpn routes (vpn->vrf routes unaffected)
+ */
+ vpn_leak_prechange(BGP_VPN_POLICY_DIR_TOVPN, afi,
+ bgp_get_default(), bgp);
+
+ UNSET_FLAG(bgp->vpn_policy[afi].flags,
+ BGP_VPN_POLICY_TOVPN_NEXTHOP_SET);
+
+ /* post-change: re-export vpn routes */
+ vpn_leak_postchange(BGP_VPN_POLICY_DIR_TOVPN, afi,
+ bgp_get_default(), bgp);
+ }
+
+ return CMD_SUCCESS;
+}
+
+static int set_ecom_list(struct vty *vty, int argc, struct cmd_token **argv,
+ struct ecommunity **list)
+{
+ struct ecommunity *ecom = NULL;
+ struct ecommunity *ecomadd;
+
+ for (; argc; --argc, ++argv) {
+
+ ecomadd = ecommunity_str2com(argv[0]->arg,
+ ECOMMUNITY_ROUTE_TARGET, 0);
+ if (!ecomadd) {
+ vty_out(vty, "Malformed community-list value\n");
+ if (ecom)
+ ecommunity_free(&ecom);
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+
+ if (ecom) {
+ ecommunity_merge(ecom, ecomadd);
+ ecommunity_free(&ecomadd);
+ } else {
+ ecom = ecomadd;
+ }
+ }
+
+ if (*list) {
+ ecommunity_free(&*list);
+ }
+ *list = ecom;
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (vpn_policy_rt,
+ vpn_policy_rt_cmd,
+ "rt <fromvpn|tovpn|both> RTLIST...",
+ "Specify route target list\n"
+ "fromvpn: match any\n"
+ "tovpn: set\n"
+ "both fromvpn: match any and tovpn: set\n"
+ "Space separated route target list (A.B.C.D:MN|EF:OPQR|GHJK:MN)\n")
+{
+ VTY_DECLVAR_CONTEXT(bgp, bgp);
+ int ret;
+ struct ecommunity *ecom = NULL;
+ int dodir[BGP_VPN_POLICY_DIR_MAX] = {0};
+ int doafi[AFI_MAX] = {0};
+ vpn_policy_direction_t dir;
+ afi_t afi;
+ int idx = 0;
+
+ ret = vpn_policy_afis(vty, doafi);
+ if (ret != CMD_SUCCESS)
+ return ret;
+
+ ret = argv_find_and_parse_vpn_policy_dirs(vty, argv, argc, &idx, dodir);
+ if (ret != CMD_SUCCESS)
+ return ret;
+
+ ret = set_ecom_list(vty, argc - 2, argv + 2, &ecom);
+ if (ret != CMD_SUCCESS) {
+ return ret;
+ }
+
+ for (afi = 0; afi < AFI_MAX; ++afi) {
+ if (!doafi[afi])
+ continue;
+ for (dir = 0; dir < BGP_VPN_POLICY_DIR_MAX; ++dir) {
+ if (!dodir[dir])
+ continue;
+
+ vpn_leak_prechange(dir, afi, bgp_get_default(), bgp);
+
+ if (bgp->vpn_policy[afi].rtlist[dir])
+ ecommunity_free(
+ &bgp->vpn_policy[afi].rtlist[dir]);
+ bgp->vpn_policy[afi].rtlist[dir] = ecommunity_dup(ecom);
+
+ vpn_leak_postchange(dir, afi, bgp_get_default(), bgp);
+ }
+ }
+ ecommunity_free(&ecom);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (vpn_policy_no_rt,
+ vpn_policy_no_rt_cmd,
+ "no rt <fromvpn|tovpn|both>",
+ NO_STR
+ "Specify route target list\n"
+ "fromvpn: match any\n"
+ "tovpn: set\n"
+ "both fromvpn: match any and tovpn: set\n")
+{
+ VTY_DECLVAR_CONTEXT(bgp, bgp);
+ int ret;
+ int dodir[BGP_VPN_POLICY_DIR_MAX] = {0};
+ int doafi[AFI_MAX] = {0};
+ vpn_policy_direction_t dir;
+ afi_t afi;
+ int idx = 0;
+
+ ret = vpn_policy_afis(vty, doafi);
+ if (ret != CMD_SUCCESS)
+ return ret;
+
+ ret = argv_find_and_parse_vpn_policy_dirs(vty, argv, argc, &idx, dodir);
+ if (ret != CMD_SUCCESS)
+ return ret;
+
+ for (afi = 0; afi < AFI_MAX; ++afi) {
+ if (!doafi[afi])
+ continue;
+ for (dir = 0; dir < BGP_VPN_POLICY_DIR_MAX; ++dir) {
+ if (!dodir[dir])
+ continue;
+
+ vpn_leak_prechange(dir, afi, bgp_get_default(), bgp);
+
+ if (bgp->vpn_policy[afi].rtlist[dir])
+ ecommunity_free(
+ &bgp->vpn_policy[afi].rtlist[dir]);
+ bgp->vpn_policy[afi].rtlist[dir] = NULL;
+
+ vpn_leak_postchange(dir, afi, bgp_get_default(), bgp);
+ }
+ }
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (vpn_policy_route_map,
+ vpn_policy_route_map_cmd,
+ "route-map <fromvpn|tovpn> WORD",
+ "Specify route map\n"
+ "fromvpn: core vpn -> this vrf\n"
+ "tovpn: this vrf -> core vpn\n"
+ "name of route-map\n")
+{
+ VTY_DECLVAR_CONTEXT(bgp, bgp);
+ int ret;
+ int dodir[BGP_VPN_POLICY_DIR_MAX] = {0};
+ int doafi[AFI_MAX] = {0};
+ vpn_policy_direction_t dir;
+ afi_t afi;
+ int map_name_arg = 2;
+ int idx = 0;
+
+ ret = vpn_policy_afis(vty, doafi);
+ if (ret != CMD_SUCCESS)
+ return ret;
+
+ ret = argv_find_and_parse_vpn_policy_dirs(vty, argv, argc, &idx, dodir);
+ if (ret != CMD_SUCCESS)
+ return ret;
+
+ for (afi = 0; afi < AFI_MAX; ++afi) {
+ if (!doafi[afi])
+ continue;
+ for (dir = 0; dir < BGP_VPN_POLICY_DIR_MAX; ++dir) {
+ if (!dodir[dir])
+ continue;
+
+ vpn_leak_prechange(dir, afi, bgp_get_default(), bgp);
+
+ if (bgp->vpn_policy[afi].rmap_name[dir])
+ XFREE(MTYPE_ROUTE_MAP_NAME,
+ bgp->vpn_policy[afi].rmap_name[dir]);
+ bgp->vpn_policy[afi].rmap_name[dir] = XSTRDUP(
+ MTYPE_ROUTE_MAP_NAME, argv[map_name_arg]->arg);
+ bgp->vpn_policy[afi].rmap[dir] =
+ route_map_lookup_by_name(
+ argv[map_name_arg]->arg);
+
+ vpn_leak_postchange(dir, afi, bgp_get_default(), bgp);
+ }
+ }
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (vpn_policy_no_route_map,
+ vpn_policy_no_route_map_cmd,
+ "no route-map <fromvpn|tovpn>",
+ NO_STR
+ "Specify route map\n"
+ "fromvpn: core vpn -> this vrf\n"
+ "tovpn: this vrf -> core vpn\n")
+{
+ VTY_DECLVAR_CONTEXT(bgp, bgp);
+ int ret;
+ int dodir[BGP_VPN_POLICY_DIR_MAX] = {0};
+ int doafi[AFI_MAX] = {0};
+ vpn_policy_direction_t dir;
+ afi_t afi;
+ int idx = 0;
+
+ ret = vpn_policy_afis(vty, doafi);
+ if (ret != CMD_SUCCESS)
+ return ret;
+
+ ret = argv_find_and_parse_vpn_policy_dirs(vty, argv, argc, &idx, dodir);
+ if (ret != CMD_SUCCESS)
+ return ret;
+
+ for (afi = 0; afi < AFI_MAX; ++afi) {
+ if (!doafi[afi])
+ continue;
+ for (dir = 0; dir < BGP_VPN_POLICY_DIR_MAX; ++dir) {
+ if (!dodir[dir])
+ continue;
+
+ vpn_leak_prechange(dir, afi, bgp_get_default(), bgp);
+
+ if (bgp->vpn_policy[afi].rmap_name[dir])
+ XFREE(MTYPE_ROUTE_MAP_NAME,
+ bgp->vpn_policy[afi].rmap_name[dir]);
+ bgp->vpn_policy[afi].rmap_name[dir] = NULL;
+ bgp->vpn_policy[afi].rmap[dir] = NULL;
+
+ vpn_leak_postchange(dir, afi, bgp_get_default(), bgp);
+ }
+ }
+
+ return CMD_SUCCESS;
+}
+
DEFUN_NOSH (address_family_ipv4_safi,
address_family_ipv4_safi_cmd,
"address-family ipv4 [<unicast|multicast|vpn|labeled-unicast>]",
@@ -11139,6 +11659,165 @@ void bgp_config_write_redistribute(struct vty *vty, struct bgp *bgp, afi_t afi,
}
}
+/* This command is valid only in a bgp vrf instance or the default instance */
+DEFUN (bgp_export_vpn,
+ bgp_export_vpn_cmd,
+ "export vpn",
+ "Export routes to another routing protocol\n"
+ "to VPN RIB per vpn-policy")
+{
+ VTY_DECLVAR_CONTEXT(bgp, bgp);
+ int was_off = 0;
+ afi_t afi;
+ safi_t safi;
+
+ if (BGP_INSTANCE_TYPE_VRF != bgp->inst_type
+ && BGP_INSTANCE_TYPE_DEFAULT != bgp->inst_type) {
+ vty_out(vty,
+ "%% export vpn valid only for bgp vrf or default instance\n");
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+ afi = bgp_node_afi(vty);
+ safi = bgp_node_safi(vty);
+ if ((SAFI_UNICAST != safi) || ((AFI_IP != afi) && (AFI_IP6 != afi))) {
+ vty_out(vty,
+ "%% export vpn valid only for unicast ipv4|ipv6\n");
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+
+ if (!CHECK_FLAG(bgp->af_flags[afi][safi],
+ BGP_CONFIG_VRF_TO_MPLSVPN_EXPORT)) {
+ was_off = 1;
+ }
+ SET_FLAG(bgp->af_flags[afi][safi], BGP_CONFIG_VRF_TO_MPLSVPN_EXPORT);
+ if (was_off) {
+ /* trigger export current vrf */
+ zlog_debug("%s: calling postchange", __func__);
+ vpn_leak_postchange(BGP_VPN_POLICY_DIR_TOVPN, afi,
+ bgp_get_default(), bgp);
+ }
+ return CMD_SUCCESS;
+}
+
+DEFUN (bgp_no_export_vpn,
+ bgp_no_export_vpn_cmd,
+ "no export vpn",
+ NO_STR
+ "Export routes to another routing protocol\n"
+ "to VPN RIB per vpn-policy")
+{
+ VTY_DECLVAR_CONTEXT(bgp, bgp);
+ int was_on = 0;
+ afi_t afi;
+ safi_t safi;
+
+ if (BGP_INSTANCE_TYPE_VRF != bgp->inst_type
+ && BGP_INSTANCE_TYPE_DEFAULT != bgp->inst_type) {
+ vty_out(vty,
+ "%% export vpn valid only for bgp vrf or default instance\n");
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+ afi = bgp_node_afi(vty);
+ safi = bgp_node_safi(vty);
+ if ((SAFI_UNICAST != safi) || ((AFI_IP != afi) && (AFI_IP6 != afi))) {
+ vty_out(vty,
+ "%% export vpn valid only for unicast ipv4|ipv6\n");
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+
+ if (CHECK_FLAG(bgp->af_flags[afi][safi],
+ BGP_CONFIG_VRF_TO_MPLSVPN_EXPORT)) {
+ was_on = 1;
+ }
+ if (was_on) {
+ /* trigger un-export current vrf */
+ zlog_debug("%s: calling postchange", __func__);
+ vpn_leak_prechange(BGP_VPN_POLICY_DIR_TOVPN, afi,
+ bgp_get_default(), bgp);
+ }
+ UNSET_FLAG(bgp->af_flags[afi][safi], BGP_CONFIG_VRF_TO_MPLSVPN_EXPORT);
+ return CMD_SUCCESS;
+}
+
+static void bgp_vpn_policy_config_write_afi(struct vty *vty, struct bgp *bgp,
+ afi_t afi)
+{
+ vty_frame(vty, " vpn-policy ipv%d\n", ((afi == AFI_IP) ? 4 : 6));
+
+ if (bgp->vpn_policy[afi].tovpn_label != MPLS_LABEL_NONE) {
+ vty_out(vty, " label %u\n",
+ bgp->vpn_policy[afi].tovpn_label);
+ }
+ if (CHECK_FLAG(bgp->vpn_policy[afi].flags,
+ BGP_VPN_POLICY_TOVPN_RD_SET)) {
+ char buf[RD_ADDRSTRLEN];
+ vty_out(vty, " rd %s\n",
+ prefix_rd2str(&bgp->vpn_policy[afi].tovpn_rd, buf,
+ sizeof(buf)));
+ }
+ if (CHECK_FLAG(bgp->vpn_policy[afi].flags,
+ BGP_VPN_POLICY_TOVPN_NEXTHOP_SET)) {
+
+ char buf[PREFIX_STRLEN];
+ if (inet_ntop(bgp->vpn_policy[afi].tovpn_nexthop.family,
+ &bgp->vpn_policy[afi].tovpn_nexthop.u.prefix, buf,
+ sizeof(buf))) {
+
+ vty_out(vty, " nexthop %s\n", buf);
+ }
+ }
+ if (bgp->vpn_policy[afi].rtlist[BGP_VPN_POLICY_DIR_FROMVPN]
+ && bgp->vpn_policy[afi].rtlist[BGP_VPN_POLICY_DIR_TOVPN]
+ && ecommunity_cmp(
+ bgp->vpn_policy[afi].rtlist[BGP_VPN_POLICY_DIR_FROMVPN],
+ bgp->vpn_policy[afi].rtlist[BGP_VPN_POLICY_DIR_TOVPN])) {
+
+ char *b = ecommunity_ecom2str(
+ bgp->vpn_policy[afi].rtlist[BGP_VPN_POLICY_DIR_TOVPN],
+ ECOMMUNITY_FORMAT_ROUTE_MAP, ECOMMUNITY_ROUTE_TARGET);
+ vty_out(vty, " rt both %s\n", b);
+ XFREE(MTYPE_ECOMMUNITY_STR, b);
+ } else {
+ if (bgp->vpn_policy[afi].rtlist[BGP_VPN_POLICY_DIR_FROMVPN]) {
+ char *b = ecommunity_ecom2str(
+ bgp->vpn_policy[afi]
+ .rtlist[BGP_VPN_POLICY_DIR_FROMVPN],
+ ECOMMUNITY_FORMAT_ROUTE_MAP,
+ ECOMMUNITY_ROUTE_TARGET);
+ vty_out(vty, " rt fromvpn %s\n", b);
+ XFREE(MTYPE_ECOMMUNITY_STR, b);
+ }
+ if (bgp->vpn_policy[afi].rtlist[BGP_VPN_POLICY_DIR_TOVPN]) {
+ char *b = ecommunity_ecom2str(
+ bgp->vpn_policy[afi]
+ .rtlist[BGP_VPN_POLICY_DIR_TOVPN],
+ ECOMMUNITY_FORMAT_ROUTE_MAP,
+ ECOMMUNITY_ROUTE_TARGET);
+ vty_out(vty, " rt tovpn %s\n", b);
+ XFREE(MTYPE_ECOMMUNITY_STR, b);
+ }
+ }
+ if (bgp->vpn_policy[afi].rmap_name[BGP_VPN_POLICY_DIR_FROMVPN]) {
+ vty_out(vty, " route-map fromvpn %s\n",
+ bgp->vpn_policy[afi]
+ .rmap_name[BGP_VPN_POLICY_DIR_FROMVPN]);
+ }
+ if (bgp->vpn_policy[afi].rmap_name[BGP_VPN_POLICY_DIR_TOVPN]) {
+ vty_out(vty, " route-map tovpn %s\n",
+ bgp->vpn_policy[afi]
+ .rmap_name[BGP_VPN_POLICY_DIR_TOVPN]);
+ }
+
+ vty_endframe(vty, " exit\n");
+}
+
+void bgp_vpn_policy_config_write(struct vty *vty, struct bgp *bgp)
+{
+ bgp_vpn_policy_config_write_afi(vty, bgp, AFI_IP);
+ bgp_vpn_policy_config_write_afi(vty, bgp, AFI_IP6);
+}
+
+
/* BGP node structure. */
static struct cmd_node bgp_node = {
BGP_NODE, "%s(config-router)# ", 1,
@@ -11180,6 +11859,12 @@ static struct cmd_node bgp_evpn_node = {BGP_EVPN_NODE,
static struct cmd_node bgp_evpn_vni_node = {BGP_EVPN_VNI_NODE,
"%s(config-router-af-vni)# ", 1};
+static struct cmd_node bgp_vpn_policy_ipv4_node = {
+ BGP_VPNPOLICY_IPV4_NODE, "%s(config-router-vpn-policy-ipv4)# ", 1};
+
+static struct cmd_node bgp_vpn_policy_ipv6_node = {
+ BGP_VPNPOLICY_IPV6_NODE, "%s(config-router-vpn-policy-ipv6)# ", 1};
+
static void community_list_vty(void);
static void bgp_ac_neighbor(vector comps, struct cmd_token *token)
@@ -11240,6 +11925,8 @@ void bgp_vty_init(void)
install_node(&bgp_vpnv6_node, NULL);
install_node(&bgp_evpn_node, NULL);
install_node(&bgp_evpn_vni_node, NULL);
+ install_node(&bgp_vpn_policy_ipv4_node, NULL);
+ install_node(&bgp_vpn_policy_ipv6_node, NULL);
/* Install default VTY commands to new nodes. */
install_default(BGP_NODE);
@@ -11253,6 +11940,8 @@ void bgp_vty_init(void)
install_default(BGP_VPNV6_NODE);
install_default(BGP_EVPN_NODE);
install_default(BGP_EVPN_VNI_NODE);
+ install_default(BGP_VPNPOLICY_IPV4_NODE);
+ install_default(BGP_VPNPOLICY_IPV6_NODE);
/* "bgp multiple-instance" commands. */
install_element(CONFIG_NODE, &bgp_multiple_instance_cmd);
@@ -12312,6 +13001,12 @@ void bgp_vty_init(void)
install_element(BGP_IPV6_NODE, &bgp_redistribute_ipv6_rmap_metric_cmd);
install_element(BGP_IPV6_NODE, &bgp_redistribute_ipv6_metric_rmap_cmd);
+ /* export vpn [route-map WORD] */
+ install_element(BGP_IPV4_NODE, &bgp_export_vpn_cmd);
+ install_element(BGP_IPV6_NODE, &bgp_export_vpn_cmd);
+ install_element(BGP_IPV4_NODE, &bgp_no_export_vpn_cmd);
+ install_element(BGP_IPV6_NODE, &bgp_no_export_vpn_cmd);
+
/* ttl_security commands */
install_element(BGP_NODE, &neighbor_ttl_security_cmd);
install_element(BGP_NODE, &no_neighbor_ttl_security_cmd);
@@ -12330,6 +13025,30 @@ void bgp_vty_init(void)
/* Community-list. */
community_list_vty();
+
+ /* vpn-policy commands */
+ install_element(BGP_NODE, &vpn_policy_afi_cmd);
+ install_element(BGP_VPNPOLICY_IPV4_NODE, &vpn_policy_rd_cmd);
+ install_element(BGP_VPNPOLICY_IPV6_NODE, &vpn_policy_rd_cmd);
+ install_element(BGP_VPNPOLICY_IPV4_NODE, &vpn_policy_label_cmd);
+ install_element(BGP_VPNPOLICY_IPV6_NODE, &vpn_policy_label_cmd);
+ install_element(BGP_VPNPOLICY_IPV4_NODE, &vpn_policy_nexthop_cmd);
+ install_element(BGP_VPNPOLICY_IPV6_NODE, &vpn_policy_nexthop_cmd);
+ install_element(BGP_VPNPOLICY_IPV4_NODE, &vpn_policy_rt_cmd);
+ install_element(BGP_VPNPOLICY_IPV6_NODE, &vpn_policy_rt_cmd);
+ install_element(BGP_VPNPOLICY_IPV4_NODE, &vpn_policy_route_map_cmd);
+ install_element(BGP_VPNPOLICY_IPV6_NODE, &vpn_policy_route_map_cmd);
+
+ install_element(BGP_VPNPOLICY_IPV4_NODE, &vpn_policy_no_rd_cmd);
+ install_element(BGP_VPNPOLICY_IPV6_NODE, &vpn_policy_no_rd_cmd);
+ install_element(BGP_VPNPOLICY_IPV4_NODE, &vpn_policy_no_label_cmd);
+ install_element(BGP_VPNPOLICY_IPV6_NODE, &vpn_policy_no_label_cmd);
+ install_element(BGP_VPNPOLICY_IPV4_NODE, &vpn_policy_no_nexthop_cmd);
+ install_element(BGP_VPNPOLICY_IPV6_NODE, &vpn_policy_no_nexthop_cmd);
+ install_element(BGP_VPNPOLICY_IPV4_NODE, &vpn_policy_no_rt_cmd);
+ install_element(BGP_VPNPOLICY_IPV6_NODE, &vpn_policy_no_rt_cmd);
+ install_element(BGP_VPNPOLICY_IPV4_NODE, &vpn_policy_no_route_map_cmd);
+ install_element(BGP_VPNPOLICY_IPV6_NODE, &vpn_policy_no_route_map_cmd);
}
#include "memory.h"
diff --git a/bgpd/bgp_vty.h b/bgpd/bgp_vty.h
index cbb41f0840..459c4ffcc3 100644
--- a/bgpd/bgp_vty.h
+++ b/bgpd/bgp_vty.h
@@ -71,4 +71,5 @@ extern int bgp_vty_find_and_parse_afi_safi_bgp(struct vty *vty,
safi_t *safi, struct bgp **bgp);
extern int bgp_show_summary_vty(struct vty *vty, const char *name, afi_t afi,
safi_t safi, u_char use_json);
+extern void bgp_vpn_policy_config_write(struct vty *vty, struct bgp *bgp);
#endif /* _QUAGGA_BGP_VTY_H */
diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c
index 23f626e960..22284fd28d 100644
--- a/bgpd/bgp_zebra.c
+++ b/bgpd/bgp_zebra.c
@@ -54,6 +54,7 @@
#include "bgpd/rfapi/vnc_export_bgp.h"
#endif
#include "bgpd/bgp_evpn.h"
+#include "bgpd/bgp_mplsvpn.h"
/* All information about zebra. */
struct zclient *zclient = NULL;
@@ -987,6 +988,7 @@ void bgp_zebra_announce(struct bgp_node *rn, struct prefix *p,
struct bgp_info *mpinfo_cp = &local_info;
route_tag_t tag;
mpls_label_t label;
+ int nh_othervrf = 0;
/* Don't try to install if we're not connected to Zebra or Zebra doesn't
* know of this instance.
@@ -997,6 +999,12 @@ void bgp_zebra_announce(struct bgp_node *rn, struct prefix *p,
if (bgp->main_zebra_update_hold)
return;
+ /*
+ * vrf leaking support (will have only one nexthop)
+ */
+ if (info->extra && info->extra->bgp_orig)
+ nh_othervrf = 1;
+
/* Make Zebra API structure. */
memset(&api, 0, sizeof(api));
memcpy(&api.rmac, &(info->attr->rmac), sizeof(struct ethaddr));
@@ -1008,6 +1016,21 @@ void bgp_zebra_announce(struct bgp_node *rn, struct prefix *p,
peer = info->peer;
+ if (info->type == ZEBRA_ROUTE_BGP
+ && info->sub_type == BGP_ROUTE_IMPORTED) {
+
+ struct bgp_info *bi;
+
+ /*
+ * Look at parent chain for peer sort
+ */
+ for (bi = info; bi->extra && bi->extra->parent;
+ bi = bi->extra->parent) {
+
+ peer = ((struct bgp_info *)(bi->extra->parent))->peer;
+ }
+ }
+
tag = info->attr->tag;
/* When we create an aggregate route we must also install a Null0 route
@@ -1060,12 +1083,38 @@ void bgp_zebra_announce(struct bgp_node *rn, struct prefix *p,
if (nh_family == AF_INET) {
struct in_addr *nexthop;
- if (bgp->table_map[afi][safi].name) {
+ if (bgp_debug_zebra(&api.prefix)) {
+ char buf_prefix[PREFIX_STRLEN];
+ prefix2str(&api.prefix, buf_prefix,
+ sizeof(buf_prefix));
+ if (mpinfo->extra) {
+ zlog_debug(
+ "%s: p=%s, bgp_is_valid_label: %d",
+ __func__, buf_prefix,
+ bgp_is_valid_label(
+ &mpinfo->extra
+ ->label[0]));
+ } else {
+ zlog_debug(
+ "%s: p=%s, extra is NULL, no label",
+ __func__, buf_prefix);
+ }
+ }
+
+ if (bgp->table_map[afi][safi].name || nh_othervrf) {
/* Copy info and attributes, so the route-map
apply doesn't modify the BGP route info. */
local_attr = *mpinfo->attr;
mpinfo_cp->attr = &local_attr;
+ if (nh_othervrf) {
+ /* allow route-map to modify */
+ local_attr.nexthop =
+ info->extra->nexthop_orig.u
+ .prefix4;
+ }
+ }
+ if (bgp->table_map[afi][safi].name) {
if (!bgp_table_map_apply(
bgp->table_map[afi][safi].map, p,
mpinfo_cp))
@@ -1082,6 +1131,9 @@ void bgp_zebra_announce(struct bgp_node *rn, struct prefix *p,
nexthop = &mpinfo_cp->attr->nexthop;
api_nh->gate.ipv4 = *nexthop;
+ api_nh->vrf_id = nh_othervrf
+ ? info->extra->bgp_orig->vrf_id
+ : bgp->vrf_id;
/* EVPN type-2 routes are
programmed as onlink on l3-vni SVI
*/
@@ -1095,6 +1147,21 @@ void bgp_zebra_announce(struct bgp_node *rn, struct prefix *p,
ifindex = 0;
+ if (bgp->table_map[afi][safi].name || nh_othervrf) {
+ /* Copy info and attributes, so the route-map
+ apply doesn't modify the BGP route info. */
+ local_attr = *mpinfo->attr;
+ mpinfo_cp->attr = &local_attr;
+ if (nh_othervrf) {
+ /* allow route-map to modify */
+ local_attr.mp_nexthop_global =
+ info->extra->nexthop_orig.u
+ .prefix6;
+ local_attr.mp_nexthop_len =
+ BGP_ATTR_NHLEN_IPV6_GLOBAL;
+ }
+ }
+
if (bgp->table_map[afi][safi].name) {
/* Copy info and attributes, so the route-map
apply doesn't modify the BGP route info. */
@@ -1139,6 +1206,9 @@ void bgp_zebra_announce(struct bgp_node *rn, struct prefix *p,
api_nh->gate.ipv6 = *nexthop;
api_nh->ifindex = ifindex;
api_nh->type = NEXTHOP_TYPE_IPV6_IFINDEX;
+ /* api_nh->vrf_id is not set for normal case? */
+ if (nh_othervrf)
+ api_nh->vrf_id = info->extra->bgp_orig->vrf_id;
}
if (mpinfo->extra
@@ -1229,9 +1299,12 @@ void bgp_zebra_announce_table(struct bgp *bgp, afi_t afi, safi_t safi)
for (rn = bgp_table_top(table); rn; rn = bgp_route_next(rn))
for (ri = rn->info; ri; ri = ri->next)
- if (CHECK_FLAG(ri->flags, BGP_INFO_SELECTED)
- && ri->type == ZEBRA_ROUTE_BGP
- && ri->sub_type == BGP_ROUTE_NORMAL)
+ if (CHECK_FLAG(ri->flags, BGP_INFO_SELECTED) &&
+
+ (ri->type == ZEBRA_ROUTE_BGP
+ && (ri->sub_type == BGP_ROUTE_NORMAL
+ || ri->sub_type == BGP_ROUTE_IMPORTED)))
+
bgp_zebra_announce(rn, &rn->p, ri, bgp, afi,
safi);
}
@@ -1244,6 +1317,21 @@ void bgp_zebra_withdraw(struct prefix *p, struct bgp_info *info, safi_t safi)
peer = info->peer;
assert(peer);
+ if (info->type == ZEBRA_ROUTE_BGP
+ && info->sub_type == BGP_ROUTE_IMPORTED) {
+
+ struct bgp_info *bi;
+
+ /*
+ * Look at parent chain for peer sort
+ */
+ for (bi = info; bi->extra && bi->extra->parent;
+ bi = bi->extra->parent) {
+
+ peer = ((struct bgp_info *)(bi->extra->parent))->peer;
+ }
+ }
+
/* Don't try to install if we're not connected to Zebra or Zebra doesn't
* know of this instance.
*/
@@ -1363,7 +1451,27 @@ int bgp_redistribute_set(struct bgp *bgp, afi_t afi, int type, u_short instance)
}
#endif
+ /* vpn -> vrf (happens within bgp but we hijack redist bits */
+ if ((bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT
+ || bgp->inst_type == BGP_INSTANCE_TYPE_VRF)
+ && type == ZEBRA_ROUTE_BGP_VPN) {
+
+ /* leak update all */
+ vpn_leak_prechange(BGP_VPN_POLICY_DIR_FROMVPN, afi,
+ bgp_get_default(), bgp);
+ }
+
vrf_bitmap_set(zclient->redist[afi][type], bgp->vrf_id);
+
+ /* vpn -> vrf (happens within bgp but we hijack redist bits */
+ if ((bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT
+ || bgp->inst_type == BGP_INSTANCE_TYPE_VRF)
+ && type == ZEBRA_ROUTE_BGP_VPN) {
+
+ /* leak update all */
+ vpn_leak_postchange(BGP_VPN_POLICY_DIR_FROMVPN, afi,
+ bgp_get_default(), bgp);
+ }
}
/*
@@ -1484,11 +1592,6 @@ int bgp_redistribute_unreg(struct bgp *bgp, afi_t afi, int type,
vrf_bitmap_unset(zclient->redist[afi][type], bgp->vrf_id);
}
-#if ENABLE_BGP_VNC
- if (bgp->vrf_id == VRF_DEFAULT && type == ZEBRA_ROUTE_VNC_DIRECT) {
- vnc_export_bgp_disable(bgp, afi);
- }
-#endif
if (bgp_install_info_to_zebra(bgp)) {
/* Send distribute delete message to zebra. */
@@ -1512,6 +1615,26 @@ int bgp_redistribute_unset(struct bgp *bgp, afi_t afi, int type,
{
struct bgp_redist *red;
+/*
+ * vnc and vpn->vrf checks must be before red check because
+ * they operate within bgpd irrespective of zebra connection
+ * status. red lookup fails if there is no zebra connection.
+ */
+#if ENABLE_BGP_VNC
+ if (bgp->vrf_id == VRF_DEFAULT && type == ZEBRA_ROUTE_VNC_DIRECT) {
+ vnc_export_bgp_disable(bgp, afi);
+ }
+#endif
+ /* vpn -> vrf (happend within bgp but we hijack redist bits */
+ if ((bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT
+ || bgp->inst_type == BGP_INSTANCE_TYPE_VRF)
+ && type == ZEBRA_ROUTE_BGP_VPN) {
+
+ /* leak withdraw all */
+ vpn_leak_prechange(BGP_VPN_POLICY_DIR_FROMVPN, afi,
+ bgp_get_default(), bgp);
+ }
+
red = bgp_redist_lookup(bgp, afi, type, instance);
if (!red)
return CMD_SUCCESS;
diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c
index eb68aee9fb..2eae2e5e9e 100644
--- a/bgpd/bgpd.c
+++ b/bgpd/bgpd.c
@@ -2941,6 +2941,11 @@ static struct bgp *bgp_create(as_t *as, const char *name,
}
#endif /* ENABLE_BGP_VNC */
+ for (afi = AFI_IP; afi < AFI_MAX; afi++) {
+ bgp->vpn_policy[afi].tovpn_label = MPLS_LABEL_NONE;
+ bgp->vpn_policy[afi].tovpn_zebra_vrf_label_last_sent =
+ MPLS_LABEL_NONE;
+ }
if (name) {
bgp->name = XSTRDUP(MTYPE_BGP, name);
} else {
@@ -7127,6 +7132,12 @@ static void bgp_config_write_family(struct vty *vty, struct bgp *bgp, afi_t afi,
if (safi == SAFI_EVPN)
bgp_config_write_evpn_info(vty, bgp, afi, safi);
+ if (CHECK_FLAG(bgp->af_flags[afi][safi],
+ BGP_CONFIG_VRF_TO_MPLSVPN_EXPORT)) {
+
+ vty_out(vty, " export vpn\n");
+ }
+
vty_endframe(vty, " exit-address-family\n");
}
@@ -7393,6 +7404,8 @@ int bgp_config_write(struct vty *vty)
if (bgp_option_check(BGP_OPT_CONFIG_CISCO))
vty_out(vty, " no auto-summary\n");
+ bgp_vpn_policy_config_write(vty, bgp);
+
/* IPv4 unicast configuration. */
bgp_config_write_family(vty, bgp, AFI_IP, SAFI_UNICAST);
diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h
index 9e1d279091..664f8c9da4 100644
--- a/bgpd/bgpd.h
+++ b/bgpd/bgpd.h
@@ -159,6 +159,12 @@ struct bgp_redist {
struct bgp_rmap rmap;
};
+typedef enum {
+ BGP_VPN_POLICY_DIR_FROMVPN = 0,
+ BGP_VPN_POLICY_DIR_TOVPN = 1,
+ BGP_VPN_POLICY_DIR_MAX = 2
+} vpn_policy_direction_t;
+
/*
* Type of 'struct bgp'.
* - Default: The default instance
@@ -311,6 +317,7 @@ struct bgp {
/* BGP Per AF flags */
u_int16_t af_flags[AFI_MAX][SAFI_MAX];
#define BGP_CONFIG_DAMPENING (1 << 0)
+#define BGP_CONFIG_VRF_TO_MPLSVPN_EXPORT (1 << 1)
/* l2vpn evpn flags - 1 << 0 is used for DAMPENNG */
#define BGP_L2VPN_EVPN_ADVERTISE_IPV4_UNICAST (1 << 1)
@@ -454,6 +461,22 @@ struct bgp {
/* route map for advertise ipv4/ipv6 unicast (type-5 routes) */
struct bgp_rmap adv_cmd_rmap[AFI_MAX][SAFI_MAX];
+ /* vpn-policy */
+ struct {
+ struct ecommunity *rtlist[BGP_VPN_POLICY_DIR_MAX];
+ char *rmap_name[BGP_VPN_POLICY_DIR_MAX];
+ struct route_map *rmap[BGP_VPN_POLICY_DIR_MAX];
+
+ /* should be mpls_label_t? */
+ uint32_t tovpn_label; /* may be MPLS_LABEL_NONE */
+ uint32_t tovpn_zebra_vrf_label_last_sent;
+ struct prefix_rd tovpn_rd;
+ struct prefix tovpn_nexthop; /* unset => set to router id */
+ uint32_t flags;
+#define BGP_VPN_POLICY_TOVPN_RD_SET 0x00000004
+#define BGP_VPN_POLICY_TOVPN_NEXTHOP_SET 0x00000008
+ } vpn_policy[AFI_MAX];
+
QOBJ_FIELDS
};
DECLARE_QOBJ_TYPE(bgp)
diff --git a/bgpd/rfapi/bgp_rfapi_cfg.c b/bgpd/rfapi/bgp_rfapi_cfg.c
index 4c7c392ab8..8c4d5ab043 100644
--- a/bgpd/rfapi/bgp_rfapi_cfg.c
+++ b/bgpd/rfapi/bgp_rfapi_cfg.c
@@ -2182,6 +2182,7 @@ void vnc_routemap_update(struct bgp *bgp, const char *unused)
vnc_zlog_debug_verbose("%s done", __func__);
}
+#if 0 /* superseded */
static void vnc_routemap_event(route_map_event_t type, /* ignored */
const char *rmap_name) /* ignored */
{
@@ -2197,6 +2198,7 @@ static void vnc_routemap_event(route_map_event_t type, /* ignored */
vnc_zlog_debug_verbose("%s: done", __func__);
}
+#endif
/*-------------------------------------------------------------------------
* nve-group
@@ -3673,7 +3675,8 @@ bgp_rfapi_get_ecommunity_by_lni_label(struct bgp *bgp, uint32_t is_import,
void bgp_rfapi_cfg_init(void)
{
/* main bgpd code does not use this hook, but vnc does */
- route_map_event_hook(vnc_routemap_event);
+ /* superseded by bgp_route_map_process_update_cb() */
+ /* bgp_route_map_event_hook_add(vnc_routemap_event); */
install_node(&bgp_vnc_defaults_node, NULL);
install_node(&bgp_vnc_nve_group_node, NULL);
diff --git a/bgpd/rfapi/vnc_export_bgp.c b/bgpd/rfapi/vnc_export_bgp.c
index c4d66bbc65..ae31c3fe9e 100644
--- a/bgpd/rfapi/vnc_export_bgp.c
+++ b/bgpd/rfapi/vnc_export_bgp.c
@@ -2049,6 +2049,9 @@ void vnc_direct_bgp_rh_reexport(struct bgp *bgp, afi_t afi)
*/
void vnc_export_bgp_enable(struct bgp *bgp, afi_t afi)
{
+ if (!bgp->rfapi_cfg)
+ return;
+
switch (bgp->rfapi_cfg->flags & BGP_VNC_CONFIG_EXPORT_BGP_MODE_BITS) {
case BGP_VNC_CONFIG_EXPORT_BGP_MODE_NONE:
break;
@@ -2069,6 +2072,9 @@ void vnc_export_bgp_enable(struct bgp *bgp, afi_t afi)
void vnc_export_bgp_disable(struct bgp *bgp, afi_t afi)
{
+ if (!bgp->rfapi_cfg)
+ return;
+
switch (bgp->rfapi_cfg->flags & BGP_VNC_CONFIG_EXPORT_BGP_MODE_BITS) {
case BGP_VNC_CONFIG_EXPORT_BGP_MODE_NONE:
break;
diff --git a/isisd/isis_redist.c b/isisd/isis_redist.c
index 198cf35e68..48fcf449c7 100644
--- a/isisd/isis_redist.c
+++ b/isisd/isis_redist.c
@@ -254,8 +254,8 @@ void isis_redist_add(int type, struct prefix *p, u_char distance,
char debug_buf[BUFSIZ];
prefix2str(p, debug_buf, sizeof(debug_buf));
- zlog_debug("%s: New route %s from %s.", __func__, debug_buf,
- zebra_route_string(type));
+ zlog_debug("%s: New route %s from %s: distance %d.", __func__,
+ debug_buf, zebra_route_string(type), distance);
if (!ei_table) {
zlog_warn("%s: External information table not initialized.",
diff --git a/lib/command.c b/lib/command.c
index 5697c1d812..b289cdd7a3 100644
--- a/lib/command.c
+++ b/lib/command.c
@@ -87,6 +87,8 @@ const char *node_names[] = {
"bgp vnc l2", // BGP_VNC_L2_GROUP_NODE,
"rfp defaults", // RFP_DEFAULTS_NODE,
"bgp evpn", // BGP_EVPN_NODE,
+ "bgp vpn policy ipv4", // BGP_VPNPOLICY_IPV4_NODE
+ "bgp vpn policy ipv6", // BGP_VPNPOLICY_IPV6_NODE
"ospf", // OSPF_NODE,
"ospf6", // OSPF6_NODE,
"ldp", // LDP_NODE,
@@ -949,6 +951,8 @@ enum node_type node_parent(enum node_type node)
case BGP_VPNV4_NODE:
case BGP_VPNV6_NODE:
case BGP_VRF_POLICY_NODE:
+ case BGP_VPNPOLICY_IPV4_NODE:
+ case BGP_VPNPOLICY_IPV6_NODE:
case BGP_VNC_DEFAULTS_NODE:
case BGP_VNC_NVE_GROUP_NODE:
case BGP_VNC_L2_GROUP_NODE:
@@ -1319,6 +1323,8 @@ void cmd_exit(struct vty *vty)
case BGP_VPNV4_NODE:
case BGP_VPNV6_NODE:
case BGP_VRF_POLICY_NODE:
+ case BGP_VPNPOLICY_IPV4_NODE:
+ case BGP_VPNPOLICY_IPV6_NODE:
case BGP_VNC_DEFAULTS_NODE:
case BGP_VNC_NVE_GROUP_NODE:
case BGP_VNC_L2_GROUP_NODE:
@@ -1389,6 +1395,8 @@ DEFUN (config_end,
case BABEL_NODE:
case BGP_NODE:
case BGP_VRF_POLICY_NODE:
+ case BGP_VPNPOLICY_IPV4_NODE:
+ case BGP_VPNPOLICY_IPV6_NODE:
case BGP_VNC_DEFAULTS_NODE:
case BGP_VNC_NVE_GROUP_NODE:
case BGP_VNC_L2_GROUP_NODE:
diff --git a/lib/command.h b/lib/command.h
index 0febf903a3..1e700aaa8f 100644
--- a/lib/command.h
+++ b/lib/command.h
@@ -73,73 +73,75 @@ struct host {
/* List of CLI nodes. Please remember to update the name array in command.c. */
enum node_type {
- AUTH_NODE, /* Authentication mode of vty interface. */
- VIEW_NODE, /* View node. Default mode of vty interface. */
- AUTH_ENABLE_NODE, /* Authentication mode for change enable. */
- ENABLE_NODE, /* Enable node. */
- CONFIG_NODE, /* Config node. Default mode of config file. */
- SERVICE_NODE, /* Service node. */
- DEBUG_NODE, /* Debug node. */
- VRF_DEBUG_NODE, /* Vrf Debug node. */
- DEBUG_VNC_NODE, /* Debug VNC node. */
- AAA_NODE, /* AAA node. */
- KEYCHAIN_NODE, /* Key-chain node. */
- KEYCHAIN_KEY_NODE, /* Key-chain key node. */
- LOGICALROUTER_NODE, /* Logical-Router node. */
- VRF_NODE, /* VRF mode node. */
- INTERFACE_NODE, /* Interface mode node. */
- NH_GROUP_NODE, /* Nexthop-Group mode node. */
- ZEBRA_NODE, /* zebra connection node. */
- TABLE_NODE, /* rtm_table selection node. */
- RIP_NODE, /* RIP protocol mode node. */
- RIPNG_NODE, /* RIPng protocol mode node. */
- BABEL_NODE, /* BABEL protocol mode node. */
- EIGRP_NODE, /* EIGRP protocol mode node. */
- BGP_NODE, /* BGP protocol mode which includes BGP4+ */
- BGP_VPNV4_NODE, /* BGP MPLS-VPN PE exchange. */
- BGP_VPNV6_NODE, /* BGP MPLS-VPN PE exchange. */
- BGP_IPV4_NODE, /* BGP IPv4 unicast address family. */
- BGP_IPV4M_NODE, /* BGP IPv4 multicast address family. */
- BGP_IPV4L_NODE, /* BGP IPv4 labeled unicast address family. */
- BGP_IPV6_NODE, /* BGP IPv6 address family */
- BGP_IPV6M_NODE, /* BGP IPv6 multicast address family. */
- BGP_IPV6L_NODE, /* BGP IPv6 labeled unicast address family. */
- BGP_VRF_POLICY_NODE, /* BGP VRF policy */
- BGP_VNC_DEFAULTS_NODE, /* BGP VNC nve defaults */
- BGP_VNC_NVE_GROUP_NODE, /* BGP VNC nve group */
- BGP_VNC_L2_GROUP_NODE, /* BGP VNC L2 group */
- RFP_DEFAULTS_NODE, /* RFP defaults node */
- BGP_EVPN_NODE, /* BGP EVPN node. */
- OSPF_NODE, /* OSPF protocol mode */
- OSPF6_NODE, /* OSPF protocol for IPv6 mode */
- LDP_NODE, /* LDP protocol mode */
- LDP_IPV4_NODE, /* LDP IPv4 address family */
- LDP_IPV6_NODE, /* LDP IPv6 address family */
- LDP_IPV4_IFACE_NODE, /* LDP IPv4 Interface */
- LDP_IPV6_IFACE_NODE, /* LDP IPv6 Interface */
- LDP_L2VPN_NODE, /* LDP L2VPN node */
- LDP_PSEUDOWIRE_NODE, /* LDP Pseudowire node */
- ISIS_NODE, /* ISIS protocol mode */
- MASC_NODE, /* MASC for multicast. */
- IRDP_NODE, /* ICMP Router Discovery Protocol mode. */
- IP_NODE, /* Static ip route node. */
- ACCESS_NODE, /* Access list node. */
- PREFIX_NODE, /* Prefix list node. */
- ACCESS_IPV6_NODE, /* Access list node. */
- ACCESS_MAC_NODE, /* MAC access list node*/
- PREFIX_IPV6_NODE, /* Prefix list node. */
- AS_LIST_NODE, /* AS list node. */
- COMMUNITY_LIST_NODE, /* Community list node. */
- RMAP_NODE, /* Route map node. */
- SMUX_NODE, /* SNMP configuration node. */
- DUMP_NODE, /* Packet dump node. */
- FORWARDING_NODE, /* IP forwarding node. */
- PROTOCOL_NODE, /* protocol filtering node */
- MPLS_NODE, /* MPLS config node */
- PW_NODE, /* Pseudowire config node */
- VTY_NODE, /* Vty node. */
- LINK_PARAMS_NODE, /* Link-parameters node */
- BGP_EVPN_VNI_NODE, /* BGP EVPN VNI */
+ AUTH_NODE, /* Authentication mode of vty interface. */
+ VIEW_NODE, /* View node. Default mode of vty interface. */
+ AUTH_ENABLE_NODE, /* Authentication mode for change enable. */
+ ENABLE_NODE, /* Enable node. */
+ CONFIG_NODE, /* Config node. Default mode of config file. */
+ SERVICE_NODE, /* Service node. */
+ DEBUG_NODE, /* Debug node. */
+ VRF_DEBUG_NODE, /* Vrf Debug node. */
+ DEBUG_VNC_NODE, /* Debug VNC node. */
+ AAA_NODE, /* AAA node. */
+ KEYCHAIN_NODE, /* Key-chain node. */
+ KEYCHAIN_KEY_NODE, /* Key-chain key node. */
+ LOGICALROUTER_NODE, /* Logical-Router node. */
+ VRF_NODE, /* VRF mode node. */
+ INTERFACE_NODE, /* Interface mode node. */
+ NH_GROUP_NODE, /* Nexthop-Group mode node. */
+ ZEBRA_NODE, /* zebra connection node. */
+ TABLE_NODE, /* rtm_table selection node. */
+ RIP_NODE, /* RIP protocol mode node. */
+ RIPNG_NODE, /* RIPng protocol mode node. */
+ BABEL_NODE, /* BABEL protocol mode node. */
+ EIGRP_NODE, /* EIGRP protocol mode node. */
+ BGP_NODE, /* BGP protocol mode which includes BGP4+ */
+ BGP_VPNV4_NODE, /* BGP MPLS-VPN PE exchange. */
+ BGP_VPNV6_NODE, /* BGP MPLS-VPN PE exchange. */
+ BGP_IPV4_NODE, /* BGP IPv4 unicast address family. */
+ BGP_IPV4M_NODE, /* BGP IPv4 multicast address family. */
+ BGP_IPV4L_NODE, /* BGP IPv4 labeled unicast address family. */
+ BGP_IPV6_NODE, /* BGP IPv6 address family */
+ BGP_IPV6M_NODE, /* BGP IPv6 multicast address family. */
+ BGP_IPV6L_NODE, /* BGP IPv6 labeled unicast address family. */
+ BGP_VRF_POLICY_NODE, /* BGP VRF policy */
+ BGP_VNC_DEFAULTS_NODE, /* BGP VNC nve defaults */
+ BGP_VNC_NVE_GROUP_NODE, /* BGP VNC nve group */
+ BGP_VNC_L2_GROUP_NODE, /* BGP VNC L2 group */
+ RFP_DEFAULTS_NODE, /* RFP defaults node */
+ BGP_EVPN_NODE, /* BGP EVPN node. */
+ BGP_VPNPOLICY_IPV4_NODE, /* BGP VPN IPv6 policy */
+ BGP_VPNPOLICY_IPV6_NODE, /* BGP VPN IPv6 policy */
+ OSPF_NODE, /* OSPF protocol mode */
+ OSPF6_NODE, /* OSPF protocol for IPv6 mode */
+ LDP_NODE, /* LDP protocol mode */
+ LDP_IPV4_NODE, /* LDP IPv4 address family */
+ LDP_IPV6_NODE, /* LDP IPv6 address family */
+ LDP_IPV4_IFACE_NODE, /* LDP IPv4 Interface */
+ LDP_IPV6_IFACE_NODE, /* LDP IPv6 Interface */
+ LDP_L2VPN_NODE, /* LDP L2VPN node */
+ LDP_PSEUDOWIRE_NODE, /* LDP Pseudowire node */
+ ISIS_NODE, /* ISIS protocol mode */
+ MASC_NODE, /* MASC for multicast. */
+ IRDP_NODE, /* ICMP Router Discovery Protocol mode. */
+ IP_NODE, /* Static ip route node. */
+ ACCESS_NODE, /* Access list node. */
+ PREFIX_NODE, /* Prefix list node. */
+ ACCESS_IPV6_NODE, /* Access list node. */
+ ACCESS_MAC_NODE, /* MAC access list node*/
+ PREFIX_IPV6_NODE, /* Prefix list node. */
+ AS_LIST_NODE, /* AS list node. */
+ COMMUNITY_LIST_NODE, /* Community list node. */
+ RMAP_NODE, /* Route map node. */
+ SMUX_NODE, /* SNMP configuration node. */
+ DUMP_NODE, /* Packet dump node. */
+ FORWARDING_NODE, /* IP forwarding node. */
+ PROTOCOL_NODE, /* protocol filtering node */
+ MPLS_NODE, /* MPLS config node */
+ PW_NODE, /* Pseudowire config node */
+ VTY_NODE, /* Vty node. */
+ LINK_PARAMS_NODE, /* Link-parameters node */
+ BGP_EVPN_VNI_NODE, /* BGP EVPN VNI */
RPKI_NODE, /* RPKI node for configuration of RPKI cache server
connections.*/
NODE_TYPE_MAX, /* maximum */
diff --git a/lib/log.c b/lib/log.c
index 74e7be7c7d..a8e7462baa 100644
--- a/lib/log.c
+++ b/lib/log.c
@@ -1055,6 +1055,8 @@ int proto_redistnum(int afi, const char *s)
return ZEBRA_ROUTE_BABEL;
else if (strmatch(s, "sharp"))
return ZEBRA_ROUTE_SHARP;
+ else if (strmatch(s, "vpn"))
+ return ZEBRA_ROUTE_BGP_VPN;
}
if (afi == AFI_IP6) {
if (strmatch(s, "kernel"))
@@ -1083,6 +1085,8 @@ int proto_redistnum(int afi, const char *s)
return ZEBRA_ROUTE_BABEL;
else if (strmatch(s, "sharp"))
return ZEBRA_ROUTE_SHARP;
+ else if (strmatch(s, "vpn"))
+ return ZEBRA_ROUTE_BGP_VPN;
}
return -1;
}
diff --git a/lib/route_types.txt b/lib/route_types.txt
index 4e764a14c1..98cada8f89 100644
--- a/lib/route_types.txt
+++ b/lib/route_types.txt
@@ -40,7 +40,7 @@
# Long description: Full description, but should try fit on a line.
####
#
-# If you add a new routing protocol here, make sure you go update
+# If you add a new routing protocol here, make sure you also update
# meta_queue_map in zebra_rib.c
#
## type cname daemon C 4 6 short help
@@ -76,6 +76,7 @@ ZEBRA_ROUTE_VNC_DIRECT_RH, vnc-rn, NULL, 'V', 0, 0, "VNC-RN"
ZEBRA_ROUTE_BGP_DIRECT, bgp-direct, NULL, 'b', 0, 0, "BGP-Direct"
# bgp unicast -> vnc
ZEBRA_ROUTE_BGP_DIRECT_EXT, bgp-direct-to-nve-groups, NULL, 'e', 0, 0, "BGP2VNC"
+ZEBRA_ROUTE_BGP_VPN, vpn, NULL, 'c', 1, 1, "VPN", bgpd
ZEBRA_ROUTE_BABEL, babel, babeld, 'A', 1, 1, "Babel"
ZEBRA_ROUTE_SHARP, sharp, sharpd, 'D', 1, 1, "SHARP"
ZEBRA_ROUTE_ALL, wildcard, none, '-', 0, 0, "-"
@@ -101,5 +102,6 @@ ZEBRA_ROUTE_OLSR, "Optimised Link State Routing (OLSR)"
ZEBRA_ROUTE_TABLE, "Non-main Kernel Routing Table"
ZEBRA_ROUTE_LDP, "Label Distribution Protocol (LDP)"
ZEBRA_ROUTE_VNC_DIRECT, "VNC direct (not via zebra) routes"
+ZEBRA_ROUTE_BGP_VPN, "BGP VPN routes"
ZEBRA_ROUTE_BABEL, "Babel routing protocol (Babel)"
ZEBRA_ROUTE_SHARP, "Super Happy Advanced Routing Protocol (sharpd)"
diff --git a/lib/zclient.c b/lib/zclient.c
index c720e2519b..777f6fcf9b 100644
--- a/lib/zclient.c
+++ b/lib/zclient.c
@@ -439,7 +439,7 @@ void zclient_send_reg_requests(struct zclient *zclient, vrf_id_t vrf_id)
}
}
- /* Flush all redistribute request. */
+ /* Resend all redistribute request. */
for (afi = AFI_IP; afi < AFI_MAX; afi++)
for (i = 0; i < ZEBRA_ROUTE_MAX; i++)
if (i != zclient->redist_default
diff --git a/ospfd/ospf_zebra.c b/ospfd/ospf_zebra.c
index 3b257fec96..e322f60509 100644
--- a/ospfd/ospf_zebra.c
+++ b/ospfd/ospf_zebra.c
@@ -949,6 +949,14 @@ static int ospf_zebra_read_route(int command, struct zclient *zclient,
if (IPV4_NET127(ntohl(p.prefix.s_addr)))
return 0;
+ if (IS_DEBUG_OSPF(zebra, ZEBRA_REDISTRIBUTE)) {
+ char buf_prefix[PREFIX_STRLEN];
+ prefix2str(&api.prefix, buf_prefix, sizeof(buf_prefix));
+
+ zlog_debug("%s: from client %s: vrf_id %d, p %s", __func__,
+ zebra_route_string(api.type), vrf_id, buf_prefix);
+ }
+
if (command == ZEBRA_REDISTRIBUTE_ROUTE_ADD) {
/* XXX|HACK|TODO|FIXME:
* Maybe we should ignore reject/blackhole routes? Testing
@@ -1455,8 +1463,6 @@ void ospf_zebra_vrf_register(struct ospf *ospf)
__PRETTY_FUNCTION__,
ospf_vrf_id_to_name(ospf->vrf_id),
ospf->vrf_id);
- /* Deregister for router-id, interfaces,
- * redistributed routes. */
zclient_send_reg_requests(zclient, ospf->vrf_id);
}
}
diff --git a/ospfd/ospfd.c b/ospfd/ospfd.c
index c8a4dc12cd..26bbc5ee11 100644
--- a/ospfd/ospfd.c
+++ b/ospfd/ospfd.c
@@ -2049,6 +2049,23 @@ static int ospf_vrf_delete(struct vrf *vrf)
return 0;
}
+static void ospf_set_redist_vrf_bitmaps(struct ospf *ospf)
+{
+ int type;
+ struct list *red_list;
+
+ for (type = 0; type < ZEBRA_ROUTE_MAX; type++) {
+ red_list = ospf->redist[type];
+ if (!red_list)
+ continue;
+ if (IS_DEBUG_OSPF_EVENT)
+ zlog_debug(
+ "%s: setting redist vrf %d bitmap for type %d",
+ __func__, ospf->vrf_id, type);
+ vrf_bitmap_set(zclient->redist[AFI_IP][type], ospf->vrf_id);
+ }
+}
+
/* Enable OSPF VRF instance */
static int ospf_vrf_enable(struct vrf *vrf)
{
@@ -2077,6 +2094,15 @@ static int ospf_vrf_enable(struct vrf *vrf)
"ospf_sock_init: could not raise privs, %s",
safe_strerror(errno));
}
+
+ /* stop zebra redist to us for old vrf */
+ zclient_send_dereg_requests(zclient, old_vrf_id);
+
+ ospf_set_redist_vrf_bitmaps(ospf);
+
+ /* start zebra redist to us for new vrf */
+ ospf_zebra_vrf_register(ospf);
+
ret = ospf_sock_init(ospf);
if (ospfd_privs.change(ZPRIVS_LOWER)) {
zlog_err(
@@ -2088,7 +2114,6 @@ static int ospf_vrf_enable(struct vrf *vrf)
thread_add_read(master, ospf_read, ospf, ospf->fd,
&ospf->t_read);
ospf->oi_running = 1;
- ospf_zebra_vrf_register(ospf);
ospf_router_id_update(ospf);
}
}
diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c
index efef106d97..556ce27229 100644
--- a/vtysh/vtysh.c
+++ b/vtysh/vtysh.c
@@ -360,7 +360,9 @@ static int vtysh_execute_func(const char *line, int pager)
} else if ((saved_node == KEYCHAIN_KEY_NODE
|| saved_node == LDP_PSEUDOWIRE_NODE
|| saved_node == LDP_IPV4_IFACE_NODE
- || saved_node == LDP_IPV6_IFACE_NODE)
+ || saved_node == LDP_IPV6_IFACE_NODE
+ || saved_node == BGP_VPNPOLICY_IPV4_NODE
+ || saved_node == BGP_VPNPOLICY_IPV6_NODE)
&& (tried == 1)) {
vtysh_execute("exit");
} else if (tried) {
@@ -632,7 +634,9 @@ int vtysh_mark_file(const char *filename)
} else if ((prev_node == BGP_EVPN_VNI_NODE)
&& (tried == 1)) {
fprintf(outputfile, "exit-vni\n");
- } else if ((prev_node == KEYCHAIN_KEY_NODE)
+ } else if ((prev_node == KEYCHAIN_KEY_NODE
+ || prev_node == BGP_VPNPOLICY_IPV4_NODE
+ || prev_node == BGP_VPNPOLICY_IPV6_NODE)
&& (tried == 1)) {
fprintf(outputfile, "exit\n");
} else if (tried) {
@@ -1013,6 +1017,12 @@ static struct cmd_node bgp_evpn_node = {BGP_EVPN_NODE,
static struct cmd_node bgp_evpn_vni_node = {BGP_EVPN_VNI_NODE,
"%s(config-router-af-vni)# "};
+static struct cmd_node bgp_vpn_policy_ipv4_node = {
+ BGP_VPNPOLICY_IPV4_NODE, "%s(config-router-vpn-policy-ipv4)# ", 1};
+
+static struct cmd_node bgp_vpn_policy_ipv6_node = {
+ BGP_VPNPOLICY_IPV6_NODE, "%s(config-router-vpn-policy-ipv6)# ", 1};
+
static struct cmd_node bgp_ipv6l_node = {BGP_IPV6L_NODE,
"%s(config-router-af)# "};
@@ -1264,6 +1274,20 @@ DEFUNSH(VTYSH_BGPD, bgp_evpn_vni, bgp_evpn_vni_cmd, "vni (1-16777215)",
return CMD_SUCCESS;
}
+DEFUNSH(VTYSH_BGPD, vpn_policy_afi, vpn_policy_afi_cmd, "vpn-policy <ipv4|ipv6>",
+ "Configure a VPN policy\n"
+ BGP_AFI_HELP_STR)
+{
+ int idx = 1;
+
+ if (argv_find(argv, argc, "ipv4", &idx))
+ vty->node = BGP_VPNPOLICY_IPV4_NODE;
+ else
+ vty->node = BGP_VPNPOLICY_IPV6_NODE;
+ return CMD_SUCCESS;
+}
+
+
#if defined(ENABLE_BGP_VNC)
DEFUNSH(VTYSH_BGPD, vnc_defaults, vnc_defaults_cmd, "vnc defaults",
"VNC/RFP related configuration\n"
@@ -1538,6 +1562,8 @@ static int vtysh_exit(struct vty *vty)
case BGP_IPV6M_NODE:
case BGP_IPV6L_NODE:
case BGP_VRF_POLICY_NODE:
+ case BGP_VPNPOLICY_IPV4_NODE:
+ case BGP_VPNPOLICY_IPV6_NODE:
case BGP_EVPN_NODE:
case BGP_VNC_DEFAULTS_NODE:
case BGP_VNC_NVE_GROUP_NODE:
@@ -3086,6 +3112,8 @@ void vtysh_init_vty(void)
install_node(&bgp_vrf_policy_node, NULL);
install_node(&bgp_evpn_node, NULL);
install_node(&bgp_evpn_vni_node, NULL);
+ install_node(&bgp_vpn_policy_ipv4_node, NULL);
+ install_node(&bgp_vpn_policy_ipv6_node, NULL);
install_node(&bgp_vnc_defaults_node, NULL);
install_node(&bgp_vnc_nve_group_node, NULL);
install_node(&bgp_vnc_l2_group_node, NULL);
@@ -3178,6 +3206,10 @@ void vtysh_init_vty(void)
install_element(BGP_EVPN_VNI_NODE, &vtysh_quit_bgpd_cmd);
install_element(BGP_IPV6L_NODE, &vtysh_exit_bgpd_cmd);
install_element(BGP_IPV6L_NODE, &vtysh_quit_bgpd_cmd);
+ install_element(BGP_VPNPOLICY_IPV4_NODE, &vtysh_exit_bgpd_cmd);
+ install_element(BGP_VPNPOLICY_IPV4_NODE, &vtysh_quit_bgpd_cmd);
+ install_element(BGP_VPNPOLICY_IPV6_NODE, &vtysh_exit_bgpd_cmd);
+ install_element(BGP_VPNPOLICY_IPV6_NODE, &vtysh_quit_bgpd_cmd);
#if defined(ENABLE_BGP_VNC)
install_element(BGP_VRF_POLICY_NODE, &vtysh_exit_bgpd_cmd);
install_element(BGP_VRF_POLICY_NODE, &vtysh_quit_bgpd_cmd);
@@ -3230,6 +3262,8 @@ void vtysh_init_vty(void)
install_element(BGP_VNC_DEFAULTS_NODE, &vtysh_end_all_cmd);
install_element(BGP_VNC_NVE_GROUP_NODE, &vtysh_end_all_cmd);
install_element(BGP_VNC_L2_GROUP_NODE, &vtysh_end_all_cmd);
+ install_element(BGP_VPNPOLICY_IPV4_NODE, &vtysh_end_all_cmd);
+ install_element(BGP_VPNPOLICY_IPV6_NODE, &vtysh_end_all_cmd);
install_element(ISIS_NODE, &vtysh_end_all_cmd);
install_element(KEYCHAIN_NODE, &vtysh_end_all_cmd);
install_element(KEYCHAIN_KEY_NODE, &vtysh_end_all_cmd);
@@ -3279,6 +3313,7 @@ void vtysh_init_vty(void)
install_element(CONFIG_NODE, &router_bgp_cmd);
install_element(BGP_NODE, &address_family_vpnv4_cmd);
install_element(BGP_NODE, &address_family_vpnv6_cmd);
+ install_element(BGP_NODE, &vpn_policy_afi_cmd);
#if defined(ENABLE_BGP_VNC)
install_element(BGP_NODE, &vnc_vrf_policy_cmd);
install_element(BGP_NODE, &vnc_defaults_cmd);
diff --git a/zebra/redistribute.c b/zebra/redistribute.c
index 5a239306fb..3a66aea45f 100644
--- a/zebra/redistribute.c
+++ b/zebra/redistribute.c
@@ -115,11 +115,12 @@ static void zebra_redistribute(struct zserv *client, int type, u_short instance,
if (IS_ZEBRA_DEBUG_EVENT)
zlog_debug(
- "%s: checking: selected=%d, type=%d, distance=%d, "
+ "%s: client %s vrf %d checking: selected=%d, type=%d, distance=%d, "
"zebra_check_addr=%d",
__func__,
- CHECK_FLAG(newre->flags,
- ZEBRA_FLAG_SELECTED),
+ zebra_route_string(client->proto),
+ vrf_id, CHECK_FLAG(newre->flags,
+ ZEBRA_FLAG_SELECTED),
newre->type, newre->distance,
zebra_check_addr(dst_p));
@@ -253,6 +254,12 @@ void zebra_redistribute_add(ZAPI_HANDLER_ARGS)
STREAM_GETC(msg, type);
STREAM_GETW(msg, instance);
+ if (IS_ZEBRA_DEBUG_EVENT)
+ zlog_debug(
+ "%s: client proto %s afi=%d, wants %s, vrf %d, instance=%d",
+ __func__, zebra_route_string(client->proto), afi,
+ zebra_route_string(type), zvrf_id(zvrf), instance);
+
if (afi == 0 || afi > AFI_MAX) {
zlog_warn("%s: Specified afi %d does not exist",
__PRETTY_FUNCTION__, afi);
@@ -276,6 +283,9 @@ void zebra_redistribute_add(ZAPI_HANDLER_ARGS)
} else {
if (!vrf_bitmap_check(client->redist[afi][type],
zvrf_id(zvrf))) {
+ if (IS_ZEBRA_DEBUG_EVENT)
+ zlog_debug("%s: setting vrf %d redist bitmap",
+ __func__, zvrf_id(zvrf));
vrf_bitmap_set(client->redist[afi][type],
zvrf_id(zvrf));
zebra_redistribute(client, type, 0, zvrf_id(zvrf), afi);
diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c
index 72dbfb12fc..b979037700 100644
--- a/zebra/zebra_rib.c
+++ b/zebra/zebra_rib.c
@@ -1864,6 +1864,7 @@ static const u_char meta_queue_map[ZEBRA_ROUTE_MAX] = {
[ZEBRA_ROUTE_VNC_DIRECT_RH] = 3,
[ZEBRA_ROUTE_BGP_DIRECT] = 3,
[ZEBRA_ROUTE_BGP_DIRECT_EXT] = 3,
+ [ZEBRA_ROUTE_BGP_VPN] = 3,
[ZEBRA_ROUTE_BABEL] = 2,
[ZEBRA_ROUTE_ALL] = 4, // Shouldn't happen but for safety
};
diff --git a/zebra/zserv.c b/zebra/zserv.c
index 0def903803..2f2c09112f 100644
--- a/zebra/zserv.c
+++ b/zebra/zserv.c
@@ -597,7 +597,44 @@ int zsend_redistribute_route(int cmd, struct zserv *client, struct prefix *p,
/* Encode route and send. */
if (zapi_route_encode(cmd, s, &api) < 0)
return -1;
- return zebra_server_send_message(client, s);
+
+ if (IS_ZEBRA_DEBUG_SEND) {
+ char buf_prefix[PREFIX_STRLEN];
+ prefix2str(&api.prefix, buf_prefix, sizeof(buf_prefix));
+
+ zlog_debug("%s: %s to client %s: type %s, vrf_id %d, p %s",
+ __func__, zserv_command_string(cmd),
+ zebra_route_string(client->proto),
+ zebra_route_string(api.type), api.vrf_id,
+ buf_prefix);
+ }
+ return zebra_server_send_message(client);
+}
+
+static int zsend_write_nexthop(struct stream *s, struct nexthop *nexthop)
+{
+ stream_putc(s, nexthop->type);
+ switch (nexthop->type) {
+ case NEXTHOP_TYPE_IPV4:
+ case NEXTHOP_TYPE_IPV4_IFINDEX:
+ stream_put_in_addr(s, &nexthop->gate.ipv4);
+ stream_putl(s, nexthop->ifindex);
+ break;
+ case NEXTHOP_TYPE_IPV6:
+ stream_put(s, &nexthop->gate.ipv6, 16);
+ break;
+ case NEXTHOP_TYPE_IPV6_IFINDEX:
+ stream_put(s, &nexthop->gate.ipv6, 16);
+ stream_putl(s, nexthop->ifindex);
+ break;
+ case NEXTHOP_TYPE_IFINDEX:
+ stream_putl(s, nexthop->ifindex);
+ break;
+ default:
+ /* do nothing */
+ break;
+ }
+ return 1;
}
/*
@@ -1149,6 +1186,16 @@ static void zread_route_add(ZAPI_HANDLER_ARGS)
s = msg;
zapi_route_decode(s, &api);
+ if (IS_ZEBRA_DEBUG_RECV) {
+ char buf_prefix[PREFIX_STRLEN];
+ prefix2str(&api.prefix, buf_prefix, sizeof(buf_prefix));
+ zlog_debug("%s: p=%s, ZAPI_MESSAGE_LABEL: %sset, flags=0x%x",
+ __func__, buf_prefix,
+ (CHECK_FLAG(api.message, ZAPI_MESSAGE_LABEL) ? ""
+ : "un"),
+ api.flags);
+ }
+
/* Allocate new route. */
vrf_id = zvrf_id(zvrf);
re = XCALLOC(MTYPE_RE, sizeof(struct route_entry));
@@ -1162,17 +1209,34 @@ static void zread_route_add(ZAPI_HANDLER_ARGS)
else
re->table = zvrf->table_id;
+ /*
+ * TBD should _all_ of the nexthop add operations use
+ * api_nh->vrf_id instead of re->vrf_id ? I only changed
+ * for cases NEXTHOP_TYPE_IPV4 and NEXTHOP_TYPE_IPV6.
+ */
if (CHECK_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP)) {
for (i = 0; i < api.nexthop_num; i++) {
api_nh = &api.nexthops[i];
ifindex_t ifindex = 0;
+ if (IS_ZEBRA_DEBUG_RECV) {
+ zlog_debug("nh type %d", api_nh->type);
+ }
+
switch (api_nh->type) {
case NEXTHOP_TYPE_IFINDEX:
nexthop = route_entry_nexthop_ifindex_add(
re, api_nh->ifindex, api_nh->vrf_id);
break;
case NEXTHOP_TYPE_IPV4:
+ if (IS_ZEBRA_DEBUG_RECV) {
+ char nhbuf[INET6_ADDRSTRLEN] = {0};
+ inet_ntop(AF_INET, &api_nh->gate.ipv4,
+ nhbuf, INET6_ADDRSTRLEN);
+ zlog_debug("%s: nh=%s, vrf_id=%d",
+ __func__, nhbuf,
+ api_nh->vrf_id);
+ }
nexthop = route_entry_nexthop_ipv4_add(
re, &api_nh->gate.ipv4, NULL,
api_nh->vrf_id);
@@ -1187,6 +1251,15 @@ static void zread_route_add(ZAPI_HANDLER_ARGS)
ifindex = api_nh->ifindex;
}
+ if (IS_ZEBRA_DEBUG_RECV) {
+ char nhbuf[INET6_ADDRSTRLEN] = {0};
+ inet_ntop(AF_INET, &api_nh->gate.ipv4,
+ nhbuf, INET6_ADDRSTRLEN);
+ zlog_debug(
+ "%s: nh=%s, vrf_id=%d (re->vrf_id=%d), ifindex=%d",
+ __func__, nhbuf, api_nh->vrf_id,
+ re->vrf_id, ifindex);
+ }
nexthop = route_entry_nexthop_ipv4_ifindex_add(
re, &api_nh->gate.ipv4, NULL, ifindex,
api_nh->vrf_id);
@@ -1265,6 +1338,14 @@ static void zread_route_add(ZAPI_HANDLER_ARGS)
label_type =
lsp_type_from_re_type(client->proto);
+
+ if (IS_ZEBRA_DEBUG_RECV) {
+ zlog_debug(
+ "%s: adding %d labels of type %d (1st=%u)",
+ __func__, api_nh->label_num,
+ label_type, api_nh->labels[0]);
+ }
+
nexthop_add_labels(nexthop, label_type,
api_nh->label_num,
&api_nh->labels[0]);