Mailing List Archive

[PATCH v2 1/2] bgpd: VRF vty configuration, RIB table creation
This commit introduces the BGP VRF configuration, and BGP VRF RIB
table.
It includes the ability for a BGP to configure its own route
distinguisher ( aka VRF). New vty commands introduced:

(config-router)# vrf rd <RD>

This structure permits configuring import and export route targets,
which is defined by RFC4360.
(config-router)# vrf rd <RD> exports <RT values>
(config-router)# vrf rd <RD> imports <RT values>

It brings some improvements.
- for a BGP speaker when emitting BGP updates, the exported route
targets will be mapped to BGP extended communities associated with
the BGP update for the defined Route distinguisher.
This commit does not enhance the support for emitting those BGP
extended communities, but provides the mecanism.
- for a BGP speaker when receiving BGP updaets. Its import route
target will be looked up, in order to match NLRI route distinguisher.
Then, if matching, the entry would be exported to a RIB per VRF table.

As mentioned before, the commit also introduces a BGP VRF RIB table per
Route distinguisher configured. This table aims at receiving BGP NLRI
entries, with matching import and export route targets.
This commit does not take into account the fullfill of this table,
but creates it.

Signed-off-by: David Lamparter <equinox@opensourcerouting.org>
Signed-off-by: Philippe Guibert <philippe.guibert@6wind.com>
---
bgpd/bgp_route.c | 193 +++++++++++++++++++++++++++++++++++++++++++++++++++--
bgpd/bgp_route.h | 4 ++
bgpd/bgp_table.h | 3 +
bgpd/bgp_vty.c | 177 +++++++++++++++++++++++++++++++++++++++++++++++++
bgpd/bgpd.c | 199 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-
bgpd/bgpd.h | 58 +++++++++++++---
lib/memtypes.c | 2 +
7 files changed, 622 insertions(+), 14 deletions(-)

diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c
index 4cb6c141bcdc..abad79f5c9d4 100644
--- a/bgpd/bgp_route.c
+++ b/bgpd/bgp_route.c
@@ -34,6 +34,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
#include "plist.h"
#include "thread.h"
#include "workqueue.h"
+#include "hash.h"

#include "bgpd/bgpd.h"
#include "bgpd/bgp_table.h"
@@ -61,6 +62,12 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
extern const char *bgp_origin_str[];
extern const char *bgp_origin_long_str[];

+static void
+bgp_static_withdraw_safi (struct bgp *bgp, struct prefix *p, afi_t afi,
+ safi_t safi, struct prefix_rd *prd, u_char *tag);
+static void
+bgp_static_free (struct bgp_static *bgp_static);
+
static struct bgp_node *
bgp_afi_node_get (struct bgp_table *table, afi_t afi, safi_t safi, struct prefix *p,
struct prefix_rd *prd)
@@ -77,7 +84,11 @@ bgp_afi_node_get (struct bgp_table *table, afi_t afi, safi_t safi, struct prefix
prn = bgp_node_get (table, (struct prefix *) prd);

if (prn->info == NULL)
- prn->info = bgp_table_init (afi, safi);
+ {
+ struct bgp_table *newtab = bgp_table_init (afi, safi);
+ newtab->prd = *prd;
+ prn->info = newtab;
+ }
else
bgp_unlock_node (prn);
table = prn->info;
@@ -1505,12 +1516,86 @@ bgp_process_announce_selected (struct peer *peer, struct bgp_info *selected,
else
bgp_adj_out_unset (rn, peer, p, afi, safi);
break;
+ case BGP_TABLE_VRF:
+ /* never called */
+ assert (0);
}

bgp_attr_flush (&attr);
return 0;
}

+void bgp_vrf_clean_tables (struct bgp_vrf *vrf)
+{
+ afi_t afi;
+ for (afi = AFI_IP; afi < AFI_MAX; afi++)
+ {
+ struct bgp_info *ri, *ri_next;
+ struct bgp_node *rn;
+
+ for (rn = bgp_table_top (vrf->rib[afi]); rn; rn = bgp_route_next (rn))
+ for (ri = rn->info; ri; ri = ri_next)
+ {
+ ri_next = ri->next;
+ bgp_info_reap (rn, ri);
+ }
+ bgp_table_finish (&vrf->rib[afi]);
+
+ for (rn = bgp_table_top (vrf->route[afi]); rn; rn = bgp_route_next (rn))
+ if (rn->info)
+ {
+ struct bgp_static *bs = rn->info;
+ bgp_static_withdraw_safi (vrf->bgp, &rn->p, afi, SAFI_MPLS_VPN,
+ &vrf->outbound_rd, NULL);
+ bgp_static_free (bs);
+ rn->info = NULL;
+ bgp_unlock_node (rn);
+ }
+ bgp_table_finish (&vrf->route[afi]);
+ }
+}
+
+void
+bgp_vrf_apply_new_imports (struct bgp_vrf *vrf, afi_t afi)
+{
+ struct bgp_node *rd_rn, *rn;
+ struct bgp_info *sel;
+ struct bgp_table *table;
+ struct ecommunity *ecom;
+ size_t i, j;
+ bool found;
+
+ if (!vrf->rt_import || vrf->rt_import->size == 0)
+ return;
+
+ for (rd_rn = bgp_table_top (vrf->bgp->rib[afi][SAFI_MPLS_VPN]); rd_rn;
+ rd_rn = bgp_route_next (rd_rn))
+ if (rd_rn->info != NULL)
+ {
+ table = rd_rn->info;
+
+ for (rn = bgp_table_top (table); rn; rn = bgp_route_next (rn))
+ {
+ for (sel = rn->info; sel; sel = sel->next)
+ if (CHECK_FLAG (sel->flags, BGP_INFO_SELECTED))
+ break;
+ if (!sel || !sel->attr || !sel->attr->extra)
+ continue;
+ ecom = sel->attr->extra->ecommunity;
+ if (!ecom)
+ continue;
+
+ found = false;
+ for (i = 0; i < (size_t)ecom->size && !found; i++)
+ for (j = 0; j < (size_t)vrf->rt_import->size && !found; j++)
+ if (!memcmp(ecom->val + i * 8, vrf->rt_import->val + j * 8, 8))
+ found = true;
+ if (!found)
+ continue;
+ }
+ }
+}
+
struct bgp_process_queue
{
struct bgp *bgp;
@@ -1746,6 +1831,9 @@ bgp_process (struct bgp *bgp, struct bgp_node *rn, afi_t afi, safi_t safi)
case BGP_TABLE_RSCLIENT:
work_queue_add (bm->process_rsclient_queue, pqnode);
break;
+ case BGP_TABLE_VRF:
+ /* never called */
+ assert (0);
}

SET_FLAG (rn->flags, BGP_NODE_PROCESS_SCHEDULED);
@@ -6291,6 +6379,9 @@ route_vty_out_detail (struct vty *vty, struct bgp *bgp, struct prefix *p,

attr = binfo->attr;

+ if (safi == SAFI_MPLS_LABELED_VPN)
+ safi = SAFI_MPLS_VPN;
+
if (attr)
{
/* Line1 display AS-path, Aggregator */
@@ -6510,6 +6601,7 @@ bgp_show_table (struct vty *vty, struct bgp_table *table, struct in_addr *router
int display;
unsigned long output_count;
unsigned long total_count;
+ safi_t safi = table->type == BGP_TABLE_VRF ? SAFI_MPLS_VPN : SAFI_UNICAST;

/* This is first entry point, so reset total line. */
output_count = 0;
@@ -6694,7 +6786,7 @@ bgp_show_table (struct vty *vty, struct bgp_table *table, struct in_addr *router

if (type == bgp_show_type_dampend_paths
|| type == bgp_show_type_damp_neighbor)
- damp_route_vty_out (vty, &rn->p, ri, display, SAFI_UNICAST);
+ damp_route_vty_out (vty, &rn->p, ri, display, safi);
else if (type == bgp_show_type_flap_statistics
|| type == bgp_show_type_flap_address
|| type == bgp_show_type_flap_prefix
@@ -6705,9 +6797,9 @@ bgp_show_table (struct vty *vty, struct bgp_table *table, struct in_addr *router
|| type == bgp_show_type_flap_prefix_longer
|| type == bgp_show_type_flap_route_map
|| type == bgp_show_type_flap_neighbor)
- flap_route_vty_out (vty, &rn->p, ri, display, SAFI_UNICAST);
+ flap_route_vty_out (vty, &rn->p, ri, display, safi);
else
- route_vty_out (vty, &rn->p, ri, display, SAFI_UNICAST);
+ route_vty_out (vty, &rn->p, ri, display, safi);
display++;
}
if (display)
@@ -6749,6 +6841,35 @@ bgp_show (struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi,
return bgp_show_table (vty, table, &bgp->router_id, type, output_arg);
}

+static int
+bgp_show_vrf (struct vty *vty, const char *vrf_name, afi_t afi,
+ enum bgp_show_type type, void *output_arg)
+{
+ struct bgp *bgp = bgp_get_default();
+ struct bgp_vrf *vrf;
+ struct prefix_rd prd;
+
+ if (! bgp)
+ {
+ vty_out (vty, "%% No default BGP instance%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ if (! str2prefix_rd (vrf_name, &prd))
+ {
+ vty_out (vty, "%% Invalid RD '%s'%s", vrf_name, VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ vrf = bgp_vrf_lookup (bgp, &prd);
+ if (! vrf)
+ {
+ vty_out (vty, "%% No VRF with RD '%s'%s", vrf_name, VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ return bgp_show_table (vty, vrf->rib[afi], &bgp->router_id, type, output_arg);
+}
+
/* Header of detailed BGP route information */
static void
route_vty_out_detail_header (struct vty *vty, struct bgp *bgp,
@@ -6816,6 +6937,12 @@ route_vty_out_detail_header (struct vty *vty, struct bgp *bgp,
vty_out (vty, ", Advertisements suppressed by an aggregate.");
vty_out (vty, ")%s", VTY_NEWLINE);

+ if (safi == SAFI_MPLS_LABELED_VPN)
+ {
+ vty_out (vty, "%s", VTY_NEWLINE);
+ return;
+ }
+
/* advertised peer */
for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer))
{
@@ -6939,6 +7066,36 @@ bgp_show_route_in_table (struct vty *vty, struct bgp *bgp,
return CMD_SUCCESS;
}

+static int
+bgp_show_vrf_route (struct vty *vty, const char *vrf_name, const char *ip_str,
+ afi_t afi, int prefix_check)
+{
+ struct bgp *bgp = bgp_get_default();
+ struct bgp_vrf *vrf;
+ struct prefix_rd prd;
+
+ if (! bgp)
+ {
+ vty_out (vty, "%% No default BGP instance%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ if (! str2prefix_rd (vrf_name, &prd))
+ {
+ vty_out (vty, "%% Invalid RD '%s'%s", vrf_name, VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ vrf = bgp_vrf_lookup (bgp, &prd);
+ if (! vrf)
+ {
+ vty_out (vty, "%% No VRF with RD '%s'%s", vrf_name, VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ return bgp_show_route_in_table (vty, bgp, vrf->rib[afi], ip_str,
+ afi, SAFI_MPLS_LABELED_VPN, NULL, prefix_check, BGP_PATH_ALL);
+}
+
/* Display specified route of Main RIB */
static int
bgp_show_route (struct vty *vty, const char *view_name, const char *ip_str,
@@ -6982,6 +7139,16 @@ DEFUN (show_ip_bgp,
return bgp_show (vty, NULL, AFI_IP, SAFI_UNICAST, bgp_show_type_normal, NULL);
}

+DEFUN (show_ip_bgp_vrf,
+ show_ip_bgp_vrf_cmd,
+ "show ip bgp vrf WORD",
+ SHOW_STR
+ IP_STR
+ BGP_STR)
+{
+ return bgp_show_vrf (vty, argv[0], AFI_IP, bgp_show_type_normal, NULL);
+}
+
DEFUN (show_ip_bgp_ipv4,
show_ip_bgp_ipv4_cmd,
"show ip bgp ipv4 (unicast|multicast)",
@@ -7050,6 +7217,19 @@ DEFUN (show_bgp_ipv4_safi_route_pathtype,
return bgp_show_route (vty, NULL, argv[1], AFI_IP, SAFI_UNICAST, NULL, 0, BGP_PATH_MULTIPATH);
}

+DEFUN (show_ip_bgp_vrf_route,
+ show_ip_bgp_vrf_route_cmd,
+ "show ip bgp vrf WORD (ipv4|ipv6) (A.B.C.D|X:X::X:X)",
+ SHOW_STR
+ IP_STR
+ BGP_STR
+ "VRF\n"
+ "Route Distinguisher\n")
+{
+ afi_t afi = (strncmp (argv[1], "ipv6", 4) == 0) ? AFI_IP6 : AFI_IP;
+ return bgp_show_vrf_route (vty, argv[0], argv[2], afi, 0);
+}
+
DEFUN (show_ip_bgp_ipv4_route,
show_ip_bgp_ipv4_route_cmd,
"show ip bgp ipv4 (unicast|multicast) A.B.C.D",
@@ -16702,10 +16882,12 @@ bgp_route_init (void)

/* old style commands */
install_element (VIEW_NODE, &show_ip_bgp_cmd);
+ install_element (VIEW_NODE, &show_ip_bgp_vrf_cmd);
install_element (VIEW_NODE, &show_ip_bgp_ipv4_cmd);
install_element (VIEW_NODE, &show_ip_bgp_route_cmd);
install_element (VIEW_NODE, &show_ip_bgp_route_pathtype_cmd);
install_element (VIEW_NODE, &show_bgp_ipv4_safi_route_pathtype_cmd);
+ install_element (VIEW_NODE, &show_ip_bgp_vrf_route_cmd);
install_element (VIEW_NODE, &show_ip_bgp_ipv4_route_cmd);
install_element (VIEW_NODE, &show_ip_bgp_vpnv4_all_route_cmd);
install_element (VIEW_NODE, &show_ip_bgp_vpnv4_rd_route_cmd);
@@ -16797,6 +16979,7 @@ bgp_route_init (void)
install_element (RESTRICTED_NODE, &show_ip_bgp_route_cmd);
install_element (RESTRICTED_NODE, &show_ip_bgp_route_pathtype_cmd);
install_element (RESTRICTED_NODE, &show_bgp_ipv4_safi_route_pathtype_cmd);
+ install_element (RESTRICTED_NODE, &show_ip_bgp_vrf_route_cmd);
install_element (RESTRICTED_NODE, &show_ip_bgp_ipv4_route_cmd);
install_element (RESTRICTED_NODE, &show_ip_bgp_vpnv4_rd_route_cmd);
install_element (RESTRICTED_NODE, &show_ip_bgp_prefix_cmd);
@@ -16832,7 +17015,7 @@ bgp_route_init (void)
install_element (VIEW_NODE, &show_ip_bgp_neighbor_prefix_counts_cmd);
install_element (VIEW_NODE, &show_ip_bgp_ipv4_neighbor_prefix_counts_cmd);
install_element (VIEW_NODE, &show_ip_bgp_vpnv4_neighbor_prefix_counts_cmd);
-
+ install_element (VIEW_NODE, &show_ip_bgp_vrf_cmd);
install_element (VIEW_NODE, &show_bgp_cmd);
install_element (VIEW_NODE, &show_bgp_ipv6_cmd);
install_element (VIEW_NODE, &show_bgp_route_cmd);
diff --git a/bgpd/bgp_route.h b/bgpd/bgp_route.h
index 332714c4f845..25a42e87bd94 100644
--- a/bgpd/bgp_route.h
+++ b/bgpd/bgp_route.h
@@ -43,6 +43,8 @@ struct bgp_info_extra

/* MPLS label. */
u_char tag[3];
+
+ struct prefix_rd vrf_rd;
};

struct bgp_info
@@ -270,4 +272,6 @@ extern void route_vty_out_tmp (struct vty *, struct prefix *, struct attr *, saf
extern void bgp_peer_clear_node_queue_drain_immediate (struct peer *peer);
extern void bgp_process_queues_drain_immediate (void);

+extern void bgp_vrf_apply_new_imports (struct bgp_vrf *vrf, afi_t afi);
+
#endif /* _QUAGGA_BGP_ROUTE_H */
diff --git a/bgpd/bgp_table.h b/bgpd/bgp_table.h
index 8e963aeeeb84..13d29469a058 100644
--- a/bgpd/bgp_table.h
+++ b/bgpd/bgp_table.h
@@ -27,6 +27,7 @@ typedef enum
{
BGP_TABLE_MAIN,
BGP_TABLE_RSCLIENT,
+ BGP_TABLE_VRF,
} bgp_table_t;

struct bgp_table
@@ -43,6 +44,8 @@ struct bgp_table
struct peer *owner;

struct route_table *route_table;
+
+ struct prefix_rd prd;
};

struct bgp_node
diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c
index 7af4e81a87b1..63a7b5bfdcf6 100644
--- a/bgpd/bgp_vty.c
+++ b/bgpd/bgp_vty.c
@@ -9891,6 +9891,178 @@ bgp_config_write_redistribute (struct vty *vty, struct bgp *bgp, afi_t afi,
return *write;
}

+DEFUN (bgp_vrf,
+ bgp_vrf_cmd,
+ "vrf rd WORD",
+ "BGP VPN VRF\n"
+ "Route Distinguisher\n"
+ "Route Distinguisher\n"
+)
+{
+ struct bgp *bgp = vty->index;
+ struct bgp_vrf *vrf;
+ struct prefix_rd prd;
+
+ if (! str2prefix_rd (argv[0], &prd))
+ {
+ vty_out (vty, "%% Invalid RD '%s'%s", argv[0], VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ vrf = bgp_vrf_lookup (bgp, &prd);
+ if (vrf)
+ {
+ vty_out (vty, "%% VRF with RD '%s' already exists%s", argv[0], VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ bgp_vrf_create (bgp, &prd);
+ return CMD_SUCCESS;
+}
+
+DEFUN (bgp_vrf_exports,
+ bgp_vrf_exports_cmd,
+ "vrf rd WORD exports .LINE",
+ "BGP VPN VRF\n"
+ "Route Distinguisher\n"
+ "Route Distinguisher\n"
+ "Export RT values\n"
+ "Export RT values\n"
+)
+{
+ struct bgp *bgp = vty->index;
+ struct bgp_vrf *vrf;
+ struct prefix_rd prd;
+ struct ecommunity *ecom = NULL;
+ int fail = 0, i;
+ char *rts = NULL, *rts_ptr;
+
+ if (! str2prefix_rd (argv[0], &prd))
+ {
+ vty_out (vty, "%% Invalid RD '%s'%s", argv[0], VTY_NEWLINE);
+ fail++;
+ }
+ /* forge export list */
+ i = 1;
+ rts = XCALLOC(MTYPE_TMP,2048);
+ rts_ptr = rts;
+ while(i < argc)
+ {
+ rts_ptr += sprintf(rts_ptr, "rt %s ",argv[i]);
+ i++;
+ }
+ /* convert list of ecoms string into ecom struct */
+ ecom = ecommunity_str2com (rts, ECOMMUNITY_ROUTE_TARGET, 1);
+ if (! ecom)
+ {
+ vty_out (vty, "%% Invalid RT '%s'%s", argv[1], VTY_NEWLINE);
+ fail++;
+ }
+ if (rts)
+ XFREE (MTYPE_TMP, rts);
+ if (fail)
+ return CMD_WARNING;
+
+ vrf = bgp_vrf_lookup (bgp, &prd);
+ if (! vrf)
+ {
+ ecommunity_free (&ecom);
+ vty_out (vty, "%% No VRF with RD '%s'%s", argv[0], VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ ecom = ecommunity_intern (ecom);
+ bgp_vrf_rt_export_set (vrf, ecom);
+ ecommunity_unintern (&ecom);
+ return CMD_SUCCESS;
+}
+
+DEFUN (bgp_vrf_imports,
+ bgp_vrf_imports_cmd,
+ "vrf rd WORD imports .LINE",
+ "BGP VPN VRF\n"
+ "Route Distinguisher\n"
+ "Route Distinguisher\n"
+ "Import RT values\n"
+ "Import RT values\n"
+)
+{
+ struct bgp *bgp = vty->index;
+ struct bgp_vrf *vrf;
+ struct prefix_rd prd;
+ struct ecommunity *ecom = NULL;
+ int fail = 0, i;
+ char *rts = NULL, *rts_ptr;
+
+ if (! str2prefix_rd (argv[0], &prd))
+ {
+ vty_out (vty, "%% Invalid RD '%s'%s", argv[0], VTY_NEWLINE);
+ fail++;
+ }
+ /* forge export list */
+ i = 1;
+ rts = XCALLOC(MTYPE_TMP,2048);
+ rts_ptr = rts;
+ while(i < argc)
+ {
+ rts_ptr += sprintf(rts_ptr, "rt %s ",argv[i]);
+ i++;
+ }
+ /* convert list of ecoms string into ecom struct */
+ ecom = ecommunity_str2com (rts, ECOMMUNITY_ROUTE_TARGET, 1);
+ if (! ecom)
+ {
+ vty_out (vty, "%% Invalid RT '%s'%s", argv[1], VTY_NEWLINE);
+ fail++;
+ }
+ if (rts)
+ XFREE (MTYPE_TMP, rts);
+ if (fail)
+ return CMD_WARNING;
+
+ vrf = bgp_vrf_lookup (bgp, &prd);
+ if (! vrf)
+ {
+ ecommunity_free (&ecom);
+ vty_out (vty, "%% No VRF with RD '%s'%s", argv[0], VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ ecom = ecommunity_intern (ecom);
+ bgp_vrf_rt_import_set (vrf, ecom);
+ ecommunity_unintern (&ecom);
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_bgp_vrf,
+ no_bgp_vrf_cmd,
+ "no vrf rd WORD",
+ NO_STR
+ "BGP VPN VRF\n"
+ "Route Distinguisher\n"
+ "Route Distinguisher\n"
+)
+{
+ struct bgp *bgp = vty->index;
+ struct bgp_vrf *vrf;
+ struct prefix_rd prd;
+
+ if (! str2prefix_rd (argv[0], &prd))
+ {
+ vty_out (vty, "%% Invalid RD '%s'%s", argv[0], VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ vrf = bgp_vrf_lookup (bgp, &prd);
+ if (! vrf)
+ {
+ vty_out (vty, "%% No VRF with RD '%s'%s", argv[0], VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ bgp_vrf_delete (vrf);
+ return CMD_SUCCESS;
+}
+
/* BGP node structure. */
static struct cmd_node bgp_node =
{
@@ -9982,6 +10154,11 @@ bgp_vty_init (void)
install_default (BGP_ENCAP_NODE);
install_default (BGP_ENCAPV6_NODE);

+ install_element (BGP_NODE, &bgp_vrf_cmd);
+ install_element (BGP_NODE, &bgp_vrf_exports_cmd);
+ install_element (BGP_NODE, &bgp_vrf_imports_cmd);
+ install_element (BGP_NODE, &no_bgp_vrf_cmd);
+
/* "bgp multiple-instance" commands. */
install_element (CONFIG_NODE, &bgp_multiple_instance_cmd);
install_element (CONFIG_NODE, &no_bgp_multiple_instance_cmd);
diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c
index 018a59941101..5725730d9454 100644
--- a/bgpd/bgpd.c
+++ b/bgpd/bgpd.c
@@ -35,6 +35,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
#include "log.h"
#include "plist.h"
#include "linklist.h"
+#include "hash.h"
#include "workqueue.h"
#include "table.h"

@@ -2057,6 +2058,164 @@ bgp_startup_timer_expire (struct thread *thread)
return 0;
}

+/* VRFs */
+
+static unsigned int bgp_rt_hash_key (void *arg)
+{
+ const struct bgp_rt_sub *rt_sub = arg;
+ uint32_t *rtval = (uint32_t *)(char *)&rt_sub->rt;
+ return rtval[0] ^ rtval[1];
+}
+
+static int bgp_rt_hash_cmp (const void *a, const void *b)
+{
+ const struct bgp_rt_sub *aa = a, *bb = b;
+ return !memcmp(&aa->rt, &bb->rt, sizeof(aa->rt));
+}
+
+static void *
+bgp_rt_hash_alloc (void *dummy)
+{
+ struct bgp_rt_sub *ddummy = dummy, *rt_sub;
+ rt_sub = XMALLOC (MTYPE_BGP_RT_SUB, sizeof (*rt_sub));
+ rt_sub->rt = ddummy->rt;
+ rt_sub->vrfs = list_new();
+ return rt_sub;
+}
+
+static void
+bgp_rt_hash_dealloc (struct bgp_rt_sub *rt_sub)
+{
+ list_delete (rt_sub->vrfs);
+ XFREE (MTYPE_BGP_RT_SUB, rt_sub);
+}
+
+struct bgp_vrf *
+bgp_vrf_lookup (struct bgp *bgp, struct prefix_rd *outbound_rd)
+{
+ struct listnode *node;
+ struct bgp_vrf *vrf;
+
+ for (ALL_LIST_ELEMENTS_RO(bgp->vrfs, node, vrf))
+ if (!memcmp (outbound_rd->val, vrf->outbound_rd.val, 8))
+ return vrf;
+ return NULL;
+}
+
+struct bgp_vrf *
+bgp_vrf_create (struct bgp *bgp, struct prefix_rd *outbound_rd)
+{
+ struct bgp_vrf *vrf;
+ afi_t afi;
+
+ if ( (vrf = XCALLOC (MTYPE_BGP_VRF, sizeof (struct bgp_vrf))) == NULL)
+ return NULL;
+
+ vrf->bgp = bgp;
+ vrf->outbound_rd = *outbound_rd;
+
+ for (afi = AFI_IP; afi < AFI_MAX; afi++)
+ {
+ vrf->route[afi] = bgp_table_init (afi, SAFI_UNICAST);
+ vrf->route[afi]->type = BGP_TABLE_VRF;
+ vrf->rib[afi] = bgp_table_init (afi, SAFI_UNICAST);
+ vrf->rib[afi]->type = BGP_TABLE_VRF;
+ }
+
+ listnode_add (bgp->vrfs, vrf);
+ return vrf;
+}
+
+static struct ecommunity * ecommunity_reintern (struct ecommunity *ecom)
+{
+ assert (ecom->refcnt > 0);
+ ecom->refcnt++;
+ return ecom;
+}
+
+void
+bgp_vrf_rt_export_set (struct bgp_vrf *vrf, struct ecommunity *rt_export)
+{
+ if (vrf->rt_export)
+ ecommunity_unintern (&vrf->rt_export);
+
+ vrf->rt_export = ecommunity_reintern (rt_export);
+}
+
+static void
+bgp_vrf_rt_import_unset (struct bgp_vrf *vrf)
+{
+ size_t i;
+
+ if (!vrf->rt_import)
+ return;
+
+ for (i = 0; i < (size_t)vrf->rt_import->size; i++)
+ {
+ struct bgp_rt_sub dummy, *rt_sub;
+ memcpy (&dummy.rt, vrf->rt_import->val + 8 * i, 8);
+
+ rt_sub = hash_lookup (vrf->bgp->rt_subscribers, &dummy);
+ assert(rt_sub);
+ listnode_delete (rt_sub->vrfs, vrf);
+ if (list_isempty (rt_sub->vrfs))
+ {
+ hash_release (vrf->bgp->rt_subscribers, rt_sub);
+ bgp_rt_hash_dealloc (rt_sub);
+ }
+ }
+
+ ecommunity_unintern (&vrf->rt_import);
+}
+
+void
+bgp_vrf_rt_import_set (struct bgp_vrf *vrf, struct ecommunity *rt_import)
+{
+ size_t i;
+ afi_t afi;
+
+ bgp_vrf_rt_import_unset (vrf);
+
+ vrf->rt_import = ecommunity_reintern (rt_import);
+
+ for (i = 0; i < (size_t)vrf->rt_import->size; i++)
+ {
+ struct bgp_rt_sub dummy, *rt_sub;
+ memcpy (&dummy.rt, vrf->rt_import->val + 8 * i, 8);
+
+ rt_sub = hash_get (vrf->bgp->rt_subscribers, &dummy, bgp_rt_hash_alloc);
+ listnode_add (rt_sub->vrfs, vrf);
+ }
+
+ for (afi = AFI_IP; afi < AFI_MAX; afi++)
+ bgp_vrf_apply_new_imports (vrf, afi);
+}
+
+static void
+bgp_vrf_delete_int (void *arg)
+{
+ struct bgp_vrf *vrf = arg;
+ char vrf_rd_str[RD_ADDRSTRLEN];
+
+ prefix_rd2str(&vrf->outbound_rd, vrf_rd_str, sizeof(vrf_rd_str));
+ zlog_info ("deleting vrf %s", vrf_rd_str);
+
+ bgp_vrf_clean_tables (vrf);
+
+ bgp_vrf_rt_import_unset (vrf);
+ if (vrf->rt_export)
+ ecommunity_unintern (&vrf->rt_export);
+
+ XFREE (MTYPE_BGP_VRF, vrf);
+}
+
+void
+bgp_vrf_delete (struct bgp_vrf *vrf)
+{
+ listnode_delete (vrf->bgp->vrfs, vrf);
+ bgp_vrf_delete_int(vrf);
+}
+
/* BGP instance creation by `router bgp' commands. */
static struct bgp *
bgp_create (as_t *as, const char *name)
@@ -2103,6 +2262,10 @@ bgp_create (as_t *as, const char *name)
if (name)
bgp->name = strdup (name);

+ bgp->vrfs = list_new();
+ bgp->vrfs->del = bgp_vrf_delete_int;
+ bgp->rt_subscribers = hash_create(bgp_rt_hash_key, bgp_rt_hash_cmp);
+
THREAD_TIMER_ON (bm->master, bgp->t_startup, bgp_startup_timer_expire,
bgp, bgp->restart_time);

@@ -2236,7 +2399,13 @@ bgp_delete (struct bgp *bgp)
BGP_NOTIFY_CEASE_PEER_UNCONFIG);
}
}
-
+ if(bgp->vrfs)
+ list_delete (bgp->vrfs);
+ if(bgp->rt_subscribers)
+ {
+ hash_clean (bgp->rt_subscribers, NULL);
+ hash_free (bgp->rt_subscribers);
+ }
/* Delete static route. */
bgp_static_delete (bgp);

@@ -5615,6 +5784,34 @@ bgp_config_write (struct vty *vty)
bgp_config_write_peer (vty, bgp, peer, AFI_IP, SAFI_UNICAST);
}

+ {
+ struct bgp_vrf *vrf;
+ char rdstr[RD_ADDRSTRLEN];
+ char *str_p, *str2_p;
+ for (ALL_LIST_ELEMENTS_RO(bgp->vrfs, node, vrf))
+ {
+ str_p = prefix_rd2str(&(vrf->outbound_rd), rdstr, RD_ADDRSTRLEN);
+ vty_out(vty, " vrf rd %s%s", str_p == NULL?"<err>":str_p, VTY_NEWLINE);
+ if(vrf->rt_import)
+ {
+ str2_p = ecommunity_ecom2str (vrf->rt_import, ECOMMUNITY_FORMAT_ROUTE_MAP);
+ if(str2_p)
+ {
+ vty_out(vty, " vrf rd %s import %s%s", str_p == NULL?"<err>":str_p, str2_p, VTY_NEWLINE);
+ XFREE (MTYPE_ECOMMUNITY_STR, str2_p);
+ }
+ }
+ if(vrf->rt_export)
+ {
+ str2_p = ecommunity_ecom2str (vrf->rt_export, ECOMMUNITY_FORMAT_ROUTE_MAP);
+ if(str2_p)
+ {
+ vty_out(vty, " vrf rd %s export %s%s", str_p == NULL?"<err>":str_p, str2_p, VTY_NEWLINE);
+ XFREE (MTYPE_ECOMMUNITY_STR, str2_p);
+ }
+ }
+ }
+ }
/* maximum-paths */
bgp_config_write_maxpaths (vty, bgp, AFI_IP, SAFI_UNICAST, &write);

diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h
index 0058b581377b..39fbbe5de525 100644
--- a/bgpd/bgpd.h
+++ b/bgpd/bgpd.h
@@ -23,12 +23,23 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA

/* For union sockunion. */
#include "sockunion.h"
+#include "bgp_ecommunity.h"
+#include "prefix.h"
+#include "vty.h"

/* Typedef BGP specific types. */
typedef u_int32_t as_t;
typedef u_int16_t as16_t; /* we may still encounter 16 Bit asnums */
typedef u_int16_t bgp_size_t;

+/* BGP router distinguisher value. */
+#define BGP_RD_SIZE 8
+
+struct bgp_rd
+{
+ u_char val[BGP_RD_SIZE];
+};
+
/* BGP master for system wide configurations and variables. */
struct bgp_master
{
@@ -179,6 +190,38 @@ struct bgp
u_int16_t maxpaths_ebgp;
u_int16_t maxpaths_ibgp;
} maxpaths[AFI_MAX][SAFI_MAX];
+
+ /* VRFs */
+ struct list *vrfs;
+
+ struct hash *rt_subscribers;
+
+};
+
+struct bgp_rt_sub
+{
+ struct ecommunity_val rt;
+
+ struct list *vrfs;
+};
+
+struct bgp_vrf
+{
+ struct bgp *bgp;
+
+ /* RD used for route advertisements */
+ struct prefix_rd outbound_rd;
+
+ /* import and export lists */
+ struct ecommunity *rt_import;
+ struct ecommunity *rt_export;
+
+ /* BGP routing information base. */
+ struct bgp_table *rib[AFI_MAX];
+
+ /* Static route configuration. */
+ struct bgp_table *route[AFI_MAX];
+
};

/* BGP peer-group support. */
@@ -215,14 +258,6 @@ struct bgp_nexthop
struct in6_addr v6_local;
};

-/* BGP router distinguisher value. */
-#define BGP_RD_SIZE 8
-
-struct bgp_rd
-{
- u_char val[BGP_RD_SIZE];
-};
-
#define RMAP_IN 0
#define RMAP_OUT 1
#define RMAP_IMPORT 2
@@ -999,4 +1034,11 @@ extern int peer_ttl_security_hops_set (struct peer *, int);
extern int peer_ttl_security_hops_unset (struct peer *);

extern void bgp_scan_finish (void);
+extern struct bgp_vrf *bgp_vrf_create (struct bgp *bgp, struct prefix_rd *outbound_rd);
+extern struct bgp_vrf *bgp_vrf_lookup (struct bgp *bgp, struct prefix_rd *outbound_rd);
+extern void bgp_vrf_delete (struct bgp_vrf *vrf);
+extern void bgp_vrf_rt_export_set (struct bgp_vrf *vrf, struct ecommunity *rt_export);
+extern void bgp_vrf_rt_import_set (struct bgp_vrf *vrf, struct ecommunity *rt_import);
+extern void bgp_vrf_clean_tables (struct bgp_vrf *vrf);
+
#endif /* _QUAGGA_BGPD_H */
diff --git a/lib/memtypes.c b/lib/memtypes.c
index 8abe99d2a495..3f5bdd255756 100644
--- a/lib/memtypes.c
+++ b/lib/memtypes.c
@@ -157,6 +157,8 @@ struct memory_list memory_list_bgp[] =
{ MTYPE_BGP_AGGREGATE, "BGP aggregate" },
{ MTYPE_BGP_ADDR, "BGP own address" },
{ MTYPE_ENCAP_TLV, "ENCAP TLV", },
+ { MTYPE_BGP_VRF, "BGP VRF", },
+ { MTYPE_BGP_RT_SUB, "BGP Route Target Subscribers" },
{ -1, NULL }
};

--
2.1.4


_______________________________________________
Quagga-dev mailing list
Quagga-dev@lists.quagga.net
https://lists.quagga.net/mailman/listinfo/quagga-dev
Re: [PATCH v2 1/2] bgpd: VRF vty configuration, RIB table creation [ In reply to ]
It looks like RD is your key to a VRF, is this right?

This doesn't match the semantics of BGP VPNs, where RDs are independent
of VRF. (RT set is really the critical thing.) The main implication of
this is that multipath/ECMP isn't (at least easily) supported. Also,
best path selection on import routes will be wrong if keyed based on RD
and I'm not sure what's being done on route reflectors.

I really think that BGP VRFs cannot / must not be keyed based on RDs.
If this is just the config interface, then changing this should be
pretty straight forward.

What do you think?

Lou

PS I think an update to bgpd.texi is needed for this patch

On 10/11/2016 4:17 AM, Philippe Guibert wrote:
> This commit introduces the BGP VRF configuration, and BGP VRF RIB
> table.
> It includes the ability for a BGP to configure its own route
> distinguisher ( aka VRF). New vty commands introduced:
>
> (config-router)# vrf rd <RD>
>
> This structure permits configuring import and export route targets,
> which is defined by RFC4360.
> (config-router)# vrf rd <RD> exports <RT values>
> (config-router)# vrf rd <RD> imports <RT values>
>
> It brings some improvements.
> - for a BGP speaker when emitting BGP updates, the exported route
> targets will be mapped to BGP extended communities associated with
> the BGP update for the defined Route distinguisher.
> This commit does not enhance the support for emitting those BGP
> extended communities, but provides the mecanism.
> - for a BGP speaker when receiving BGP updaets. Its import route
> target will be looked up, in order to match NLRI route distinguisher.
> Then, if matching, the entry would be exported to a RIB per VRF table.
>
> As mentioned before, the commit also introduces a BGP VRF RIB table per
> Route distinguisher configured. This table aims at receiving BGP NLRI
> entries, with matching import and export route targets.
> This commit does not take into account the fullfill of this table,
> but creates it.
>
> Signed-off-by: David Lamparter <equinox@opensourcerouting.org>
> Signed-off-by: Philippe Guibert <philippe.guibert@6wind.com>
> ---
> bgpd/bgp_route.c | 193 +++++++++++++++++++++++++++++++++++++++++++++++++++--
> bgpd/bgp_route.h | 4 ++
> bgpd/bgp_table.h | 3 +
> bgpd/bgp_vty.c | 177 +++++++++++++++++++++++++++++++++++++++++++++++++
> bgpd/bgpd.c | 199 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-
> bgpd/bgpd.h | 58 +++++++++++++---
> lib/memtypes.c | 2 +
> 7 files changed, 622 insertions(+), 14 deletions(-)
>
> diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c
> index 4cb6c141bcdc..abad79f5c9d4 100644
> --- a/bgpd/bgp_route.c
> +++ b/bgpd/bgp_route.c
> @@ -34,6 +34,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
> #include "plist.h"
> #include "thread.h"
> #include "workqueue.h"
> +#include "hash.h"
>
> #include "bgpd/bgpd.h"
> #include "bgpd/bgp_table.h"
> @@ -61,6 +62,12 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
> extern const char *bgp_origin_str[];
> extern const char *bgp_origin_long_str[];
>
> +static void
> +bgp_static_withdraw_safi (struct bgp *bgp, struct prefix *p, afi_t afi,
> + safi_t safi, struct prefix_rd *prd, u_char *tag);
> +static void
> +bgp_static_free (struct bgp_static *bgp_static);
> +
> static struct bgp_node *
> bgp_afi_node_get (struct bgp_table *table, afi_t afi, safi_t safi, struct prefix *p,
> struct prefix_rd *prd)
> @@ -77,7 +84,11 @@ bgp_afi_node_get (struct bgp_table *table, afi_t afi, safi_t safi, struct prefix
> prn = bgp_node_get (table, (struct prefix *) prd);
>
> if (prn->info == NULL)
> - prn->info = bgp_table_init (afi, safi);
> + {
> + struct bgp_table *newtab = bgp_table_init (afi, safi);
> + newtab->prd = *prd;
> + prn->info = newtab;
> + }
> else
> bgp_unlock_node (prn);
> table = prn->info;
> @@ -1505,12 +1516,86 @@ bgp_process_announce_selected (struct peer *peer, struct bgp_info *selected,
> else
> bgp_adj_out_unset (rn, peer, p, afi, safi);
> break;
> + case BGP_TABLE_VRF:
> + /* never called */
> + assert (0);
> }
>
> bgp_attr_flush (&attr);
> return 0;
> }
>
> +void bgp_vrf_clean_tables (struct bgp_vrf *vrf)
> +{
> + afi_t afi;
> + for (afi = AFI_IP; afi < AFI_MAX; afi++)
> + {
> + struct bgp_info *ri, *ri_next;
> + struct bgp_node *rn;
> +
> + for (rn = bgp_table_top (vrf->rib[afi]); rn; rn = bgp_route_next (rn))
> + for (ri = rn->info; ri; ri = ri_next)
> + {
> + ri_next = ri->next;
> + bgp_info_reap (rn, ri);
> + }
> + bgp_table_finish (&vrf->rib[afi]);
> +
> + for (rn = bgp_table_top (vrf->route[afi]); rn; rn = bgp_route_next (rn))
> + if (rn->info)
> + {
> + struct bgp_static *bs = rn->info;
> + bgp_static_withdraw_safi (vrf->bgp, &rn->p, afi, SAFI_MPLS_VPN,
> + &vrf->outbound_rd, NULL);
> + bgp_static_free (bs);
> + rn->info = NULL;
> + bgp_unlock_node (rn);
> + }
> + bgp_table_finish (&vrf->route[afi]);
> + }
> +}
> +
> +void
> +bgp_vrf_apply_new_imports (struct bgp_vrf *vrf, afi_t afi)
> +{
> + struct bgp_node *rd_rn, *rn;
> + struct bgp_info *sel;
> + struct bgp_table *table;
> + struct ecommunity *ecom;
> + size_t i, j;
> + bool found;
> +
> + if (!vrf->rt_import || vrf->rt_import->size == 0)
> + return;
> +
> + for (rd_rn = bgp_table_top (vrf->bgp->rib[afi][SAFI_MPLS_VPN]); rd_rn;
> + rd_rn = bgp_route_next (rd_rn))
> + if (rd_rn->info != NULL)
> + {
> + table = rd_rn->info;
> +
> + for (rn = bgp_table_top (table); rn; rn = bgp_route_next (rn))
> + {
> + for (sel = rn->info; sel; sel = sel->next)
> + if (CHECK_FLAG (sel->flags, BGP_INFO_SELECTED))
> + break;
> + if (!sel || !sel->attr || !sel->attr->extra)
> + continue;
> + ecom = sel->attr->extra->ecommunity;
> + if (!ecom)
> + continue;
> +
> + found = false;
> + for (i = 0; i < (size_t)ecom->size && !found; i++)
> + for (j = 0; j < (size_t)vrf->rt_import->size && !found; j++)
> + if (!memcmp(ecom->val + i * 8, vrf->rt_import->val + j * 8, 8))
> + found = true;
> + if (!found)
> + continue;
> + }
> + }
> +}
> +
> struct bgp_process_queue
> {
> struct bgp *bgp;
> @@ -1746,6 +1831,9 @@ bgp_process (struct bgp *bgp, struct bgp_node *rn, afi_t afi, safi_t safi)
> case BGP_TABLE_RSCLIENT:
> work_queue_add (bm->process_rsclient_queue, pqnode);
> break;
> + case BGP_TABLE_VRF:
> + /* never called */
> + assert (0);
> }
>
> SET_FLAG (rn->flags, BGP_NODE_PROCESS_SCHEDULED);
> @@ -6291,6 +6379,9 @@ route_vty_out_detail (struct vty *vty, struct bgp *bgp, struct prefix *p,
>
> attr = binfo->attr;
>
> + if (safi == SAFI_MPLS_LABELED_VPN)
> + safi = SAFI_MPLS_VPN;
> +
> if (attr)
> {
> /* Line1 display AS-path, Aggregator */
> @@ -6510,6 +6601,7 @@ bgp_show_table (struct vty *vty, struct bgp_table *table, struct in_addr *router
> int display;
> unsigned long output_count;
> unsigned long total_count;
> + safi_t safi = table->type == BGP_TABLE_VRF ? SAFI_MPLS_VPN : SAFI_UNICAST;
>
> /* This is first entry point, so reset total line. */
> output_count = 0;
> @@ -6694,7 +6786,7 @@ bgp_show_table (struct vty *vty, struct bgp_table *table, struct in_addr *router
>
> if (type == bgp_show_type_dampend_paths
> || type == bgp_show_type_damp_neighbor)
> - damp_route_vty_out (vty, &rn->p, ri, display, SAFI_UNICAST);
> + damp_route_vty_out (vty, &rn->p, ri, display, safi);
> else if (type == bgp_show_type_flap_statistics
> || type == bgp_show_type_flap_address
> || type == bgp_show_type_flap_prefix
> @@ -6705,9 +6797,9 @@ bgp_show_table (struct vty *vty, struct bgp_table *table, struct in_addr *router
> || type == bgp_show_type_flap_prefix_longer
> || type == bgp_show_type_flap_route_map
> || type == bgp_show_type_flap_neighbor)
> - flap_route_vty_out (vty, &rn->p, ri, display, SAFI_UNICAST);
> + flap_route_vty_out (vty, &rn->p, ri, display, safi);
> else
> - route_vty_out (vty, &rn->p, ri, display, SAFI_UNICAST);
> + route_vty_out (vty, &rn->p, ri, display, safi);
> display++;
> }
> if (display)
> @@ -6749,6 +6841,35 @@ bgp_show (struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi,
> return bgp_show_table (vty, table, &bgp->router_id, type, output_arg);
> }
>
> +static int
> +bgp_show_vrf (struct vty *vty, const char *vrf_name, afi_t afi,
> + enum bgp_show_type type, void *output_arg)
> +{
> + struct bgp *bgp = bgp_get_default();
> + struct bgp_vrf *vrf;
> + struct prefix_rd prd;
> +
> + if (! bgp)
> + {
> + vty_out (vty, "%% No default BGP instance%s", VTY_NEWLINE);
> + return CMD_WARNING;
> + }
> + if (! str2prefix_rd (vrf_name, &prd))
> + {
> + vty_out (vty, "%% Invalid RD '%s'%s", vrf_name, VTY_NEWLINE);
> + return CMD_WARNING;
> + }
> +
> + vrf = bgp_vrf_lookup (bgp, &prd);
> + if (! vrf)
> + {
> + vty_out (vty, "%% No VRF with RD '%s'%s", vrf_name, VTY_NEWLINE);
> + return CMD_WARNING;
> + }
> +
> + return bgp_show_table (vty, vrf->rib[afi], &bgp->router_id, type, output_arg);
> +}
> +
> /* Header of detailed BGP route information */
> static void
> route_vty_out_detail_header (struct vty *vty, struct bgp *bgp,
> @@ -6816,6 +6937,12 @@ route_vty_out_detail_header (struct vty *vty, struct bgp *bgp,
> vty_out (vty, ", Advertisements suppressed by an aggregate.");
> vty_out (vty, ")%s", VTY_NEWLINE);
>
> + if (safi == SAFI_MPLS_LABELED_VPN)
> + {
> + vty_out (vty, "%s", VTY_NEWLINE);
> + return;
> + }
> +
> /* advertised peer */
> for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer))
> {
> @@ -6939,6 +7066,36 @@ bgp_show_route_in_table (struct vty *vty, struct bgp *bgp,
> return CMD_SUCCESS;
> }
>
> +static int
> +bgp_show_vrf_route (struct vty *vty, const char *vrf_name, const char *ip_str,
> + afi_t afi, int prefix_check)
> +{
> + struct bgp *bgp = bgp_get_default();
> + struct bgp_vrf *vrf;
> + struct prefix_rd prd;
> +
> + if (! bgp)
> + {
> + vty_out (vty, "%% No default BGP instance%s", VTY_NEWLINE);
> + return CMD_WARNING;
> + }
> + if (! str2prefix_rd (vrf_name, &prd))
> + {
> + vty_out (vty, "%% Invalid RD '%s'%s", vrf_name, VTY_NEWLINE);
> + return CMD_WARNING;
> + }
> +
> + vrf = bgp_vrf_lookup (bgp, &prd);
> + if (! vrf)
> + {
> + vty_out (vty, "%% No VRF with RD '%s'%s", vrf_name, VTY_NEWLINE);
> + return CMD_WARNING;
> + }
> +
> + return bgp_show_route_in_table (vty, bgp, vrf->rib[afi], ip_str,
> + afi, SAFI_MPLS_LABELED_VPN, NULL, prefix_check, BGP_PATH_ALL);
> +}
> +
> /* Display specified route of Main RIB */
> static int
> bgp_show_route (struct vty *vty, const char *view_name, const char *ip_str,
> @@ -6982,6 +7139,16 @@ DEFUN (show_ip_bgp,
> return bgp_show (vty, NULL, AFI_IP, SAFI_UNICAST, bgp_show_type_normal, NULL);
> }
>
> +DEFUN (show_ip_bgp_vrf,
> + show_ip_bgp_vrf_cmd,
> + "show ip bgp vrf WORD",
> + SHOW_STR
> + IP_STR
> + BGP_STR)
> +{
> + return bgp_show_vrf (vty, argv[0], AFI_IP, bgp_show_type_normal, NULL);
> +}
> +
> DEFUN (show_ip_bgp_ipv4,
> show_ip_bgp_ipv4_cmd,
> "show ip bgp ipv4 (unicast|multicast)",
> @@ -7050,6 +7217,19 @@ DEFUN (show_bgp_ipv4_safi_route_pathtype,
> return bgp_show_route (vty, NULL, argv[1], AFI_IP, SAFI_UNICAST, NULL, 0, BGP_PATH_MULTIPATH);
> }
>
> +DEFUN (show_ip_bgp_vrf_route,
> + show_ip_bgp_vrf_route_cmd,
> + "show ip bgp vrf WORD (ipv4|ipv6) (A.B.C.D|X:X::X:X)",
> + SHOW_STR
> + IP_STR
> + BGP_STR
> + "VRF\n"
> + "Route Distinguisher\n")
> +{
> + afi_t afi = (strncmp (argv[1], "ipv6", 4) == 0) ? AFI_IP6 : AFI_IP;
> + return bgp_show_vrf_route (vty, argv[0], argv[2], afi, 0);
> +}
> +
> DEFUN (show_ip_bgp_ipv4_route,
> show_ip_bgp_ipv4_route_cmd,
> "show ip bgp ipv4 (unicast|multicast) A.B.C.D",
> @@ -16702,10 +16882,12 @@ bgp_route_init (void)
>
> /* old style commands */
> install_element (VIEW_NODE, &show_ip_bgp_cmd);
> + install_element (VIEW_NODE, &show_ip_bgp_vrf_cmd);
> install_element (VIEW_NODE, &show_ip_bgp_ipv4_cmd);
> install_element (VIEW_NODE, &show_ip_bgp_route_cmd);
> install_element (VIEW_NODE, &show_ip_bgp_route_pathtype_cmd);
> install_element (VIEW_NODE, &show_bgp_ipv4_safi_route_pathtype_cmd);
> + install_element (VIEW_NODE, &show_ip_bgp_vrf_route_cmd);
> install_element (VIEW_NODE, &show_ip_bgp_ipv4_route_cmd);
> install_element (VIEW_NODE, &show_ip_bgp_vpnv4_all_route_cmd);
> install_element (VIEW_NODE, &show_ip_bgp_vpnv4_rd_route_cmd);
> @@ -16797,6 +16979,7 @@ bgp_route_init (void)
> install_element (RESTRICTED_NODE, &show_ip_bgp_route_cmd);
> install_element (RESTRICTED_NODE, &show_ip_bgp_route_pathtype_cmd);
> install_element (RESTRICTED_NODE, &show_bgp_ipv4_safi_route_pathtype_cmd);
> + install_element (RESTRICTED_NODE, &show_ip_bgp_vrf_route_cmd);
> install_element (RESTRICTED_NODE, &show_ip_bgp_ipv4_route_cmd);
> install_element (RESTRICTED_NODE, &show_ip_bgp_vpnv4_rd_route_cmd);
> install_element (RESTRICTED_NODE, &show_ip_bgp_prefix_cmd);
> @@ -16832,7 +17015,7 @@ bgp_route_init (void)
> install_element (VIEW_NODE, &show_ip_bgp_neighbor_prefix_counts_cmd);
> install_element (VIEW_NODE, &show_ip_bgp_ipv4_neighbor_prefix_counts_cmd);
> install_element (VIEW_NODE, &show_ip_bgp_vpnv4_neighbor_prefix_counts_cmd);
> -
> + install_element (VIEW_NODE, &show_ip_bgp_vrf_cmd);
> install_element (VIEW_NODE, &show_bgp_cmd);
> install_element (VIEW_NODE, &show_bgp_ipv6_cmd);
> install_element (VIEW_NODE, &show_bgp_route_cmd);
> diff --git a/bgpd/bgp_route.h b/bgpd/bgp_route.h
> index 332714c4f845..25a42e87bd94 100644
> --- a/bgpd/bgp_route.h
> +++ b/bgpd/bgp_route.h
> @@ -43,6 +43,8 @@ struct bgp_info_extra
>
> /* MPLS label. */
> u_char tag[3];
> +
> + struct prefix_rd vrf_rd;
> };
>
> struct bgp_info
> @@ -270,4 +272,6 @@ extern void route_vty_out_tmp (struct vty *, struct prefix *, struct attr *, saf
> extern void bgp_peer_clear_node_queue_drain_immediate (struct peer *peer);
> extern void bgp_process_queues_drain_immediate (void);
>
> +extern void bgp_vrf_apply_new_imports (struct bgp_vrf *vrf, afi_t afi);
> +
> #endif /* _QUAGGA_BGP_ROUTE_H */
> diff --git a/bgpd/bgp_table.h b/bgpd/bgp_table.h
> index 8e963aeeeb84..13d29469a058 100644
> --- a/bgpd/bgp_table.h
> +++ b/bgpd/bgp_table.h
> @@ -27,6 +27,7 @@ typedef enum
> {
> BGP_TABLE_MAIN,
> BGP_TABLE_RSCLIENT,
> + BGP_TABLE_VRF,
> } bgp_table_t;
>
> struct bgp_table
> @@ -43,6 +44,8 @@ struct bgp_table
> struct peer *owner;
>
> struct route_table *route_table;
> +
> + struct prefix_rd prd;
> };
>
> struct bgp_node
> diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c
> index 7af4e81a87b1..63a7b5bfdcf6 100644
> --- a/bgpd/bgp_vty.c
> +++ b/bgpd/bgp_vty.c
> @@ -9891,6 +9891,178 @@ bgp_config_write_redistribute (struct vty *vty, struct bgp *bgp, afi_t afi,
> return *write;
> }
>
> +DEFUN (bgp_vrf,
> + bgp_vrf_cmd,
> + "vrf rd WORD",
> + "BGP VPN VRF\n"
> + "Route Distinguisher\n"
> + "Route Distinguisher\n"
> +)
> +{
> + struct bgp *bgp = vty->index;
> + struct bgp_vrf *vrf;
> + struct prefix_rd prd;
> +
> + if (! str2prefix_rd (argv[0], &prd))
> + {
> + vty_out (vty, "%% Invalid RD '%s'%s", argv[0], VTY_NEWLINE);
> + return CMD_WARNING;
> + }
> +
> + vrf = bgp_vrf_lookup (bgp, &prd);
> + if (vrf)
> + {
> + vty_out (vty, "%% VRF with RD '%s' already exists%s", argv[0], VTY_NEWLINE);
> + return CMD_WARNING;
> + }
> +
> + bgp_vrf_create (bgp, &prd);
> + return CMD_SUCCESS;
> +}
> +
> +DEFUN (bgp_vrf_exports,
> + bgp_vrf_exports_cmd,
> + "vrf rd WORD exports .LINE",
> + "BGP VPN VRF\n"
> + "Route Distinguisher\n"
> + "Route Distinguisher\n"
> + "Export RT values\n"
> + "Export RT values\n"
> +)
> +{
> + struct bgp *bgp = vty->index;
> + struct bgp_vrf *vrf;
> + struct prefix_rd prd;
> + struct ecommunity *ecom = NULL;
> + int fail = 0, i;
> + char *rts = NULL, *rts_ptr;
> +
> + if (! str2prefix_rd (argv[0], &prd))
> + {
> + vty_out (vty, "%% Invalid RD '%s'%s", argv[0], VTY_NEWLINE);
> + fail++;
> + }
> + /* forge export list */
> + i = 1;
> + rts = XCALLOC(MTYPE_TMP,2048);
> + rts_ptr = rts;
> + while(i < argc)
> + {
> + rts_ptr += sprintf(rts_ptr, "rt %s ",argv[i]);
> + i++;
> + }
> + /* convert list of ecoms string into ecom struct */
> + ecom = ecommunity_str2com (rts, ECOMMUNITY_ROUTE_TARGET, 1);
> + if (! ecom)
> + {
> + vty_out (vty, "%% Invalid RT '%s'%s", argv[1], VTY_NEWLINE);
> + fail++;
> + }
> + if (rts)
> + XFREE (MTYPE_TMP, rts);
> + if (fail)
> + return CMD_WARNING;
> +
> + vrf = bgp_vrf_lookup (bgp, &prd);
> + if (! vrf)
> + {
> + ecommunity_free (&ecom);
> + vty_out (vty, "%% No VRF with RD '%s'%s", argv[0], VTY_NEWLINE);
> + return CMD_WARNING;
> + }
> +
> + ecom = ecommunity_intern (ecom);
> + bgp_vrf_rt_export_set (vrf, ecom);
> + ecommunity_unintern (&ecom);
> + return CMD_SUCCESS;
> +}
> +
> +DEFUN (bgp_vrf_imports,
> + bgp_vrf_imports_cmd,
> + "vrf rd WORD imports .LINE",
> + "BGP VPN VRF\n"
> + "Route Distinguisher\n"
> + "Route Distinguisher\n"
> + "Import RT values\n"
> + "Import RT values\n"
> +)
> +{
> + struct bgp *bgp = vty->index;
> + struct bgp_vrf *vrf;
> + struct prefix_rd prd;
> + struct ecommunity *ecom = NULL;
> + int fail = 0, i;
> + char *rts = NULL, *rts_ptr;
> +
> + if (! str2prefix_rd (argv[0], &prd))
> + {
> + vty_out (vty, "%% Invalid RD '%s'%s", argv[0], VTY_NEWLINE);
> + fail++;
> + }
> + /* forge export list */
> + i = 1;
> + rts = XCALLOC(MTYPE_TMP,2048);
> + rts_ptr = rts;
> + while(i < argc)
> + {
> + rts_ptr += sprintf(rts_ptr, "rt %s ",argv[i]);
> + i++;
> + }
> + /* convert list of ecoms string into ecom struct */
> + ecom = ecommunity_str2com (rts, ECOMMUNITY_ROUTE_TARGET, 1);
> + if (! ecom)
> + {
> + vty_out (vty, "%% Invalid RT '%s'%s", argv[1], VTY_NEWLINE);
> + fail++;
> + }
> + if (rts)
> + XFREE (MTYPE_TMP, rts);
> + if (fail)
> + return CMD_WARNING;
> +
> + vrf = bgp_vrf_lookup (bgp, &prd);
> + if (! vrf)
> + {
> + ecommunity_free (&ecom);
> + vty_out (vty, "%% No VRF with RD '%s'%s", argv[0], VTY_NEWLINE);
> + return CMD_WARNING;
> + }
> +
> + ecom = ecommunity_intern (ecom);
> + bgp_vrf_rt_import_set (vrf, ecom);
> + ecommunity_unintern (&ecom);
> + return CMD_SUCCESS;
> +}
> +
> +DEFUN (no_bgp_vrf,
> + no_bgp_vrf_cmd,
> + "no vrf rd WORD",
> + NO_STR
> + "BGP VPN VRF\n"
> + "Route Distinguisher\n"
> + "Route Distinguisher\n"
> +)
> +{
> + struct bgp *bgp = vty->index;
> + struct bgp_vrf *vrf;
> + struct prefix_rd prd;
> +
> + if (! str2prefix_rd (argv[0], &prd))
> + {
> + vty_out (vty, "%% Invalid RD '%s'%s", argv[0], VTY_NEWLINE);
> + return CMD_WARNING;
> + }
> +
> + vrf = bgp_vrf_lookup (bgp, &prd);
> + if (! vrf)
> + {
> + vty_out (vty, "%% No VRF with RD '%s'%s", argv[0], VTY_NEWLINE);
> + return CMD_WARNING;
> + }
> + bgp_vrf_delete (vrf);
> + return CMD_SUCCESS;
> +}
> +
> /* BGP node structure. */
> static struct cmd_node bgp_node =
> {
> @@ -9982,6 +10154,11 @@ bgp_vty_init (void)
> install_default (BGP_ENCAP_NODE);
> install_default (BGP_ENCAPV6_NODE);
>
> + install_element (BGP_NODE, &bgp_vrf_cmd);
> + install_element (BGP_NODE, &bgp_vrf_exports_cmd);
> + install_element (BGP_NODE, &bgp_vrf_imports_cmd);
> + install_element (BGP_NODE, &no_bgp_vrf_cmd);
> +
> /* "bgp multiple-instance" commands. */
> install_element (CONFIG_NODE, &bgp_multiple_instance_cmd);
> install_element (CONFIG_NODE, &no_bgp_multiple_instance_cmd);
> diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c
> index 018a59941101..5725730d9454 100644
> --- a/bgpd/bgpd.c
> +++ b/bgpd/bgpd.c
> @@ -35,6 +35,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
> #include "log.h"
> #include "plist.h"
> #include "linklist.h"
> +#include "hash.h"
> #include "workqueue.h"
> #include "table.h"
>
> @@ -2057,6 +2058,164 @@ bgp_startup_timer_expire (struct thread *thread)
> return 0;
> }
>
> +/* VRFs */
> +
> +static unsigned int bgp_rt_hash_key (void *arg)
> +{
> + const struct bgp_rt_sub *rt_sub = arg;
> + uint32_t *rtval = (uint32_t *)(char *)&rt_sub->rt;
> + return rtval[0] ^ rtval[1];
> +}
> +
> +static int bgp_rt_hash_cmp (const void *a, const void *b)
> +{
> + const struct bgp_rt_sub *aa = a, *bb = b;
> + return !memcmp(&aa->rt, &bb->rt, sizeof(aa->rt));
> +}
> +
> +static void *
> +bgp_rt_hash_alloc (void *dummy)
> +{
> + struct bgp_rt_sub *ddummy = dummy, *rt_sub;
> + rt_sub = XMALLOC (MTYPE_BGP_RT_SUB, sizeof (*rt_sub));
> + rt_sub->rt = ddummy->rt;
> + rt_sub->vrfs = list_new();
> + return rt_sub;
> +}
> +
> +static void
> +bgp_rt_hash_dealloc (struct bgp_rt_sub *rt_sub)
> +{
> + list_delete (rt_sub->vrfs);
> + XFREE (MTYPE_BGP_RT_SUB, rt_sub);
> +}
> +
> +struct bgp_vrf *
> +bgp_vrf_lookup (struct bgp *bgp, struct prefix_rd *outbound_rd)
> +{
> + struct listnode *node;
> + struct bgp_vrf *vrf;
> +
> + for (ALL_LIST_ELEMENTS_RO(bgp->vrfs, node, vrf))
> + if (!memcmp (outbound_rd->val, vrf->outbound_rd.val, 8))
> + return vrf;
> + return NULL;
> +}
> +
> +struct bgp_vrf *
> +bgp_vrf_create (struct bgp *bgp, struct prefix_rd *outbound_rd)
> +{
> + struct bgp_vrf *vrf;
> + afi_t afi;
> +
> + if ( (vrf = XCALLOC (MTYPE_BGP_VRF, sizeof (struct bgp_vrf))) == NULL)
> + return NULL;
> +
> + vrf->bgp = bgp;
> + vrf->outbound_rd = *outbound_rd;
> +
> + for (afi = AFI_IP; afi < AFI_MAX; afi++)
> + {
> + vrf->route[afi] = bgp_table_init (afi, SAFI_UNICAST);
> + vrf->route[afi]->type = BGP_TABLE_VRF;
> + vrf->rib[afi] = bgp_table_init (afi, SAFI_UNICAST);
> + vrf->rib[afi]->type = BGP_TABLE_VRF;
> + }
> +
> + listnode_add (bgp->vrfs, vrf);
> + return vrf;
> +}
> +
> +static struct ecommunity * ecommunity_reintern (struct ecommunity *ecom)
> +{
> + assert (ecom->refcnt > 0);
> + ecom->refcnt++;
> + return ecom;
> +}
> +
> +void
> +bgp_vrf_rt_export_set (struct bgp_vrf *vrf, struct ecommunity *rt_export)
> +{
> + if (vrf->rt_export)
> + ecommunity_unintern (&vrf->rt_export);
> +
> + vrf->rt_export = ecommunity_reintern (rt_export);
> +}
> +
> +static void
> +bgp_vrf_rt_import_unset (struct bgp_vrf *vrf)
> +{
> + size_t i;
> +
> + if (!vrf->rt_import)
> + return;
> +
> + for (i = 0; i < (size_t)vrf->rt_import->size; i++)
> + {
> + struct bgp_rt_sub dummy, *rt_sub;
> + memcpy (&dummy.rt, vrf->rt_import->val + 8 * i, 8);
> +
> + rt_sub = hash_lookup (vrf->bgp->rt_subscribers, &dummy);
> + assert(rt_sub);
> + listnode_delete (rt_sub->vrfs, vrf);
> + if (list_isempty (rt_sub->vrfs))
> + {
> + hash_release (vrf->bgp->rt_subscribers, rt_sub);
> + bgp_rt_hash_dealloc (rt_sub);
> + }
> + }
> +
> + ecommunity_unintern (&vrf->rt_import);
> +}
> +
> +void
> +bgp_vrf_rt_import_set (struct bgp_vrf *vrf, struct ecommunity *rt_import)
> +{
> + size_t i;
> + afi_t afi;
> +
> + bgp_vrf_rt_import_unset (vrf);
> +
> + vrf->rt_import = ecommunity_reintern (rt_import);
> +
> + for (i = 0; i < (size_t)vrf->rt_import->size; i++)
> + {
> + struct bgp_rt_sub dummy, *rt_sub;
> + memcpy (&dummy.rt, vrf->rt_import->val + 8 * i, 8);
> +
> + rt_sub = hash_get (vrf->bgp->rt_subscribers, &dummy, bgp_rt_hash_alloc);
> + listnode_add (rt_sub->vrfs, vrf);
> + }
> +
> + for (afi = AFI_IP; afi < AFI_MAX; afi++)
> + bgp_vrf_apply_new_imports (vrf, afi);
> +}
> +
> +static void
> +bgp_vrf_delete_int (void *arg)
> +{
> + struct bgp_vrf *vrf = arg;
> + char vrf_rd_str[RD_ADDRSTRLEN];
> +
> + prefix_rd2str(&vrf->outbound_rd, vrf_rd_str, sizeof(vrf_rd_str));
> + zlog_info ("deleting vrf %s", vrf_rd_str);
> +
> + bgp_vrf_clean_tables (vrf);
> +
> + bgp_vrf_rt_import_unset (vrf);
> + if (vrf->rt_export)
> + ecommunity_unintern (&vrf->rt_export);
> +
> + XFREE (MTYPE_BGP_VRF, vrf);
> +}
> +
> +void
> +bgp_vrf_delete (struct bgp_vrf *vrf)
> +{
> + listnode_delete (vrf->bgp->vrfs, vrf);
> + bgp_vrf_delete_int(vrf);
> +}
> +
> /* BGP instance creation by `router bgp' commands. */
> static struct bgp *
> bgp_create (as_t *as, const char *name)
> @@ -2103,6 +2262,10 @@ bgp_create (as_t *as, const char *name)
> if (name)
> bgp->name = strdup (name);
>
> + bgp->vrfs = list_new();
> + bgp->vrfs->del = bgp_vrf_delete_int;
> + bgp->rt_subscribers = hash_create(bgp_rt_hash_key, bgp_rt_hash_cmp);
> +
> THREAD_TIMER_ON (bm->master, bgp->t_startup, bgp_startup_timer_expire,
> bgp, bgp->restart_time);
>
> @@ -2236,7 +2399,13 @@ bgp_delete (struct bgp *bgp)
> BGP_NOTIFY_CEASE_PEER_UNCONFIG);
> }
> }
> -
> + if(bgp->vrfs)
> + list_delete (bgp->vrfs);
> + if(bgp->rt_subscribers)
> + {
> + hash_clean (bgp->rt_subscribers, NULL);
> + hash_free (bgp->rt_subscribers);
> + }
> /* Delete static route. */
> bgp_static_delete (bgp);
>
> @@ -5615,6 +5784,34 @@ bgp_config_write (struct vty *vty)
> bgp_config_write_peer (vty, bgp, peer, AFI_IP, SAFI_UNICAST);
> }
>
> + {
> + struct bgp_vrf *vrf;
> + char rdstr[RD_ADDRSTRLEN];
> + char *str_p, *str2_p;
> + for (ALL_LIST_ELEMENTS_RO(bgp->vrfs, node, vrf))
> + {
> + str_p = prefix_rd2str(&(vrf->outbound_rd), rdstr, RD_ADDRSTRLEN);
> + vty_out(vty, " vrf rd %s%s", str_p == NULL?"<err>":str_p, VTY_NEWLINE);
> + if(vrf->rt_import)
> + {
> + str2_p = ecommunity_ecom2str (vrf->rt_import, ECOMMUNITY_FORMAT_ROUTE_MAP);
> + if(str2_p)
> + {
> + vty_out(vty, " vrf rd %s import %s%s", str_p == NULL?"<err>":str_p, str2_p, VTY_NEWLINE);
> + XFREE (MTYPE_ECOMMUNITY_STR, str2_p);
> + }
> + }
> + if(vrf->rt_export)
> + {
> + str2_p = ecommunity_ecom2str (vrf->rt_export, ECOMMUNITY_FORMAT_ROUTE_MAP);
> + if(str2_p)
> + {
> + vty_out(vty, " vrf rd %s export %s%s", str_p == NULL?"<err>":str_p, str2_p, VTY_NEWLINE);
> + XFREE (MTYPE_ECOMMUNITY_STR, str2_p);
> + }
> + }
> + }
> + }
> /* maximum-paths */
> bgp_config_write_maxpaths (vty, bgp, AFI_IP, SAFI_UNICAST, &write);
>
> diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h
> index 0058b581377b..39fbbe5de525 100644
> --- a/bgpd/bgpd.h
> +++ b/bgpd/bgpd.h
> @@ -23,12 +23,23 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
>
> /* For union sockunion. */
> #include "sockunion.h"
> +#include "bgp_ecommunity.h"
> +#include "prefix.h"
> +#include "vty.h"
>
> /* Typedef BGP specific types. */
> typedef u_int32_t as_t;
> typedef u_int16_t as16_t; /* we may still encounter 16 Bit asnums */
> typedef u_int16_t bgp_size_t;
>
> +/* BGP router distinguisher value. */
> +#define BGP_RD_SIZE 8
> +
> +struct bgp_rd
> +{
> + u_char val[BGP_RD_SIZE];
> +};
> +
> /* BGP master for system wide configurations and variables. */
> struct bgp_master
> {
> @@ -179,6 +190,38 @@ struct bgp
> u_int16_t maxpaths_ebgp;
> u_int16_t maxpaths_ibgp;
> } maxpaths[AFI_MAX][SAFI_MAX];
> +
> + /* VRFs */
> + struct list *vrfs;
> +
> + struct hash *rt_subscribers;
> +
> +};
> +
> +struct bgp_rt_sub
> +{
> + struct ecommunity_val rt;
> +
> + struct list *vrfs;
> +};
> +
> +struct bgp_vrf
> +{
> + struct bgp *bgp;
> +
> + /* RD used for route advertisements */
> + struct prefix_rd outbound_rd;
> +
> + /* import and export lists */
> + struct ecommunity *rt_import;
> + struct ecommunity *rt_export;
> +
> + /* BGP routing information base. */
> + struct bgp_table *rib[AFI_MAX];
> +
> + /* Static route configuration. */
> + struct bgp_table *route[AFI_MAX];
> +
> };
>
> /* BGP peer-group support. */
> @@ -215,14 +258,6 @@ struct bgp_nexthop
> struct in6_addr v6_local;
> };
>
> -/* BGP router distinguisher value. */
> -#define BGP_RD_SIZE 8
> -
> -struct bgp_rd
> -{
> - u_char val[BGP_RD_SIZE];
> -};
> -
> #define RMAP_IN 0
> #define RMAP_OUT 1
> #define RMAP_IMPORT 2
> @@ -999,4 +1034,11 @@ extern int peer_ttl_security_hops_set (struct peer *, int);
> extern int peer_ttl_security_hops_unset (struct peer *);
>
> extern void bgp_scan_finish (void);
> +extern struct bgp_vrf *bgp_vrf_create (struct bgp *bgp, struct prefix_rd *outbound_rd);
> +extern struct bgp_vrf *bgp_vrf_lookup (struct bgp *bgp, struct prefix_rd *outbound_rd);
> +extern void bgp_vrf_delete (struct bgp_vrf *vrf);
> +extern void bgp_vrf_rt_export_set (struct bgp_vrf *vrf, struct ecommunity *rt_export);
> +extern void bgp_vrf_rt_import_set (struct bgp_vrf *vrf, struct ecommunity *rt_import);
> +extern void bgp_vrf_clean_tables (struct bgp_vrf *vrf);
> +
> #endif /* _QUAGGA_BGPD_H */
> diff --git a/lib/memtypes.c b/lib/memtypes.c
> index 8abe99d2a495..3f5bdd255756 100644
> --- a/lib/memtypes.c
> +++ b/lib/memtypes.c
> @@ -157,6 +157,8 @@ struct memory_list memory_list_bgp[] =
> { MTYPE_BGP_AGGREGATE, "BGP aggregate" },
> { MTYPE_BGP_ADDR, "BGP own address" },
> { MTYPE_ENCAP_TLV, "ENCAP TLV", },
> + { MTYPE_BGP_VRF, "BGP VRF", },
> + { MTYPE_BGP_RT_SUB, "BGP Route Target Subscribers" },
> { -1, NULL }
> };
>


_______________________________________________
Quagga-dev mailing list
Quagga-dev@lists.quagga.net
https://lists.quagga.net/mailman/listinfo/quagga-dev
Re: [PATCH v2 1/2] bgpd: VRF vty configuration, RIB table creation [ In reply to ]
On Tue, Oct 18, 2016 at 3:56 PM, Lou Berger <lberger@labn.net> wrote:

Hello Lou,

Please read below my comments.
Consecutive to your feedback, I think there are some improvements to bring,
mainly about configuration and structure naming.

> It looks like RD is your key to a VRF, is this right?
> This doesn't match the semantics of BGP VPNs, where RDs are independent
> of VRF. (RT set is really the critical thing.)

Most of the modifications have been done around what is called the
"VRF structure".

The RD is mapped to that "VRF structure", but the RT also. This is a
one-to-one mapping.
That "VRF structure" has a RIB table where RT imports are processed.

I mean, on the design point of view, I don't make a difference between
a RD and a RT.
I just have to ensure that the incoming structure is available to
import appropriate entries.
in order to import a RT entry, I have to create a RT mapped to an
other "VRF structure".

If the RT is not mapped to that "VRF structure", then the RIB
associated to that RT is not present.
Then the import in the RIB RT will not be possible.

To illustrate, a quick example shows that routerA sends a NLRI entry to routerB.


RouterB will import NLRI entry to RT 100:111
This is possible because RouterB has the line rd100:111 ... created.

RouterB will not import NLRI entry to RT 300:111, since there is no
underlying structure.

About "VRF structure", My intention is not to interfere about current
VRF implementation in Quagga.
From the configuration point of view, it is easy to find in literature
cisco configuration where VRF
and RD configuration maps together.
Could you be more specific about the reason to dissociate RD from VRF ?

One modification improvement would consist in :
- That "VRF structure" could be renamed to "RT/RD structure"
- some show commands would be impacted. Instead of dumping VRF RIB
table, one would dump RT/RD RIB table
- the commit logs would be reworked

> The main implication of
> this is that multipath/ECMP isn't (at least easily) supported.
> Also,
> best path selection on import routes will be wrong if keyed based on RD

Multipath feature impacts both global RIB, and RIB per RT.

As before, let me illustrate this with a 3 router setup topology.
router A) and router B) send 2 NLRI ECMP entries to router C)




When receiving a NLRI entry from routerB), and routerA), bgp_update()
will append the entry in the global RIB, according to RD field.

Route Distinguisher : 200:111
*> 10.10.10.0/24 <nexthop_routerA>

Then, the import processing is storing the same 2 entries in RT RIB.
Route Distinguisher : 100:111
*> 10.10.10.0/24 <nexthop_routerA>

By playing with configuration, it is possible to have multipath
entries in the global RIB, but not in the RD RIB.

> and I'm not sure what's being done on route reflectors.

There may be some missing elements on implementation.
Only the global RIB entries injected by remote peer would be
transmitted, including the export RT information originated by routerA
and routerB.

> I really think that BGP VRFs cannot / must not be keyed based on RDs.
> If this is just the config interface, then changing this should be
> pretty straight forward.

RT RIBS are keyed based on RTs
global RIBS entries are keyed based on RDs.
About config interface, It would be possible to change configuration:
instead of "vrf rd", one could have "rd <>".

> PS I think an update to bgpd.texi is needed for this patch

of course, this is something that can be done.

Best Regards,

Philippe

> On 10/11/2016 4:17 AM, Philippe Guibert wrote:
>> This commit introduces the BGP VRF configuration, and BGP VRF RIB
>> table.
>> It includes the ability for a BGP to configure its own route
>> distinguisher ( aka VRF). New vty commands introduced:
>>
>> (config-router)# vrf rd <RD>
>>
>> This structure permits configuring import and export route targets,
>> which is defined by RFC4360.
>> (config-router)# vrf rd <RD> exports <RT values>
>> (config-router)# vrf rd <RD> imports <RT values>
>>
>> It brings some improvements.
>> - for a BGP speaker when emitting BGP updates, the exported route
>> targets will be mapped to BGP extended communities associated with
>> the BGP update for the defined Route distinguisher.
>> This commit does not enhance the support for emitting those BGP
>> extended communities, but provides the mecanism.
>> - for a BGP speaker when receiving BGP updaets. Its import route
>> target will be looked up, in order to match NLRI route distinguisher.
>> Then, if matching, the entry would be exported to a RIB per VRF table.
>>
>> As mentioned before, the commit also introduces a BGP VRF RIB table per
>> Route distinguisher configured. This table aims at receiving BGP NLRI
>> entries, with matching import and export route targets.
>> This commit does not take into account the fullfill of this table,
>> but creates it.
>>
>> Signed-off-by: David Lamparter <equinox@opensourcerouting.org>
>> Signed-off-by: Philippe Guibert <philippe.guibert@6wind.com>
>> ---
>> bgpd/bgp_route.c | 193 +++++++++++++++++++++++++++++++++++++++++++++++++++--
>> bgpd/bgp_route.h | 4 ++
>> bgpd/bgp_table.h | 3 +
>> bgpd/bgp_vty.c | 177 +++++++++++++++++++++++++++++++++++++++++++++++++
>> bgpd/bgpd.c | 199 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-
>> bgpd/bgpd.h | 58 +++++++++++++---
>> lib/memtypes.c | 2 +
>> 7 files changed, 622 insertions(+), 14 deletions(-)
>>
>> diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c
>> index 4cb6c141bcdc..abad79f5c9d4 100644
>> --- a/bgpd/bgp_route.c
>> +++ b/bgpd/bgp_route.c
>> @@ -34,6 +34,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
>> #include "plist.h"
>> #include "thread.h"
>> #include "workqueue.h"
>> +#include "hash.h"
>>
>> #include "bgpd/bgpd.h"
>> #include "bgpd/bgp_table.h"
>> @@ -61,6 +62,12 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
>> extern const char *bgp_origin_str[];
>> extern const char *bgp_origin_long_str[];
>>
>> +static void
>> +bgp_static_withdraw_safi (struct bgp *bgp, struct prefix *p, afi_t afi,
>> + safi_t safi, struct prefix_rd *prd, u_char *tag);
>> +static void
>> +bgp_static_free (struct bgp_static *bgp_static);
>> +
>> static struct bgp_node *
>> bgp_afi_node_get (struct bgp_table *table, afi_t afi, safi_t safi, struct prefix *p,
>> struct prefix_rd *prd)
>> @@ -77,7 +84,11 @@ bgp_afi_node_get (struct bgp_table *table, afi_t afi, safi_t safi, struct prefix
>> prn = bgp_node_get (table, (struct prefix *) prd);
>>
>> if (prn->info == NULL)
>> - prn->info = bgp_table_init (afi, safi);
>> + {
>> + struct bgp_table *newtab = bgp_table_init (afi, safi);
>> + newtab->prd = *prd;
>> + prn->info = newtab;
>> + }
>> else
>> bgp_unlock_node (prn);
>> table = prn->info;
>> @@ -1505,12 +1516,86 @@ bgp_process_announce_selected (struct peer *peer, struct bgp_info *selected,
>> else
>> bgp_adj_out_unset (rn, peer, p, afi, safi);
>> break;
>> + case BGP_TABLE_VRF:
>> + /* never called */
>> + assert (0);
>> }
>>
>> bgp_attr_flush (&attr);
>> return 0;
>> }
>>
>> +void bgp_vrf_clean_tables (struct bgp_vrf *vrf)
>> +{
>> + afi_t afi;
>> + for (afi = AFI_IP; afi < AFI_MAX; afi++)
>> + {
>> + struct bgp_info *ri, *ri_next;
>> + struct bgp_node *rn;
>> +
>> + for (rn = bgp_table_top (vrf->rib[afi]); rn; rn = bgp_route_next (rn))
>> + for (ri = rn->info; ri; ri = ri_next)
>> + {
>> + ri_next = ri->next;
>> + bgp_info_reap (rn, ri);
>> + }
>> + bgp_table_finish (&vrf->rib[afi]);
>> +
>> + for (rn = bgp_table_top (vrf->route[afi]); rn; rn = bgp_route_next (rn))
>> + if (rn->info)
>> + {
>> + struct bgp_static *bs = rn->info;
>> + bgp_static_withdraw_safi (vrf->bgp, &rn->p, afi, SAFI_MPLS_VPN,
>> + &vrf->outbound_rd, NULL);
>> + bgp_static_free (bs);
>> + rn->info = NULL;
>> + bgp_unlock_node (rn);
>> + }
>> + bgp_table_finish (&vrf->route[afi]);
>> + }
>> +}
>> +
>> +void
>> +bgp_vrf_apply_new_imports (struct bgp_vrf *vrf, afi_t afi)
>> +{
>> + struct bgp_node *rd_rn, *rn;
>> + struct bgp_info *sel;
>> + struct bgp_table *table;
>> + struct ecommunity *ecom;
>> + size_t i, j;
>> + bool found;
>> +
>> + if (!vrf->rt_import || vrf->rt_import->size == 0)
>> + return;
>> +
>> + for (rd_rn = bgp_table_top (vrf->bgp->rib[afi][SAFI_MPLS_VPN]); rd_rn;
>> + rd_rn = bgp_route_next (rd_rn))
>> + if (rd_rn->info != NULL)
>> + {
>> + table = rd_rn->info;
>> +
>> + for (rn = bgp_table_top (table); rn; rn = bgp_route_next (rn))
>> + {
>> + for (sel = rn->info; sel; sel = sel->next)
>> + if (CHECK_FLAG (sel->flags, BGP_INFO_SELECTED))
>> + break;
>> + if (!sel || !sel->attr || !sel->attr->extra)
>> + continue;
>> + ecom = sel->attr->extra->ecommunity;
>> + if (!ecom)
>> + continue;
>> +
>> + found = false;
>> + for (i = 0; i < (size_t)ecom->size && !found; i++)
>> + for (j = 0; j < (size_t)vrf->rt_import->size && !found; j++)
>> + if (!memcmp(ecom->val + i * 8, vrf->rt_import->val + j * 8, 8))
>> + found = true;
>> + if (!found)
>> + continue;
>> + }
>> + }
>> +}
>> +
>> struct bgp_process_queue
>> {
>> struct bgp *bgp;
>> @@ -1746,6 +1831,9 @@ bgp_process (struct bgp *bgp, struct bgp_node *rn, afi_t afi, safi_t safi)
>> case BGP_TABLE_RSCLIENT:
>> work_queue_add (bm->process_rsclient_queue, pqnode);
>> break;
>> + case BGP_TABLE_VRF:
>> + /* never called */
>> + assert (0);
>> }
>>
>> SET_FLAG (rn->flags, BGP_NODE_PROCESS_SCHEDULED);
>> @@ -6291,6 +6379,9 @@ route_vty_out_detail (struct vty *vty, struct bgp *bgp, struct prefix *p,
>>
>> attr = binfo->attr;
>>
>> + if (safi == SAFI_MPLS_LABELED_VPN)
>> + safi = SAFI_MPLS_VPN;
>> +
>> if (attr)
>> {
>> /* Line1 display AS-path, Aggregator */
>> @@ -6510,6 +6601,7 @@ bgp_show_table (struct vty *vty, struct bgp_table *table, struct in_addr *router
>> int display;
>> unsigned long output_count;
>> unsigned long total_count;
>> + safi_t safi = table->type == BGP_TABLE_VRF ? SAFI_MPLS_VPN : SAFI_UNICAST;
>>
>> /* This is first entry point, so reset total line. */
>> output_count = 0;
>> @@ -6694,7 +6786,7 @@ bgp_show_table (struct vty *vty, struct bgp_table *table, struct in_addr *router
>>
>> if (type == bgp_show_type_dampend_paths
>> || type == bgp_show_type_damp_neighbor)
>> - damp_route_vty_out (vty, &rn->p, ri, display, SAFI_UNICAST);
>> + damp_route_vty_out (vty, &rn->p, ri, display, safi);
>> else if (type == bgp_show_type_flap_statistics
>> || type == bgp_show_type_flap_address
>> || type == bgp_show_type_flap_prefix
>> @@ -6705,9 +6797,9 @@ bgp_show_table (struct vty *vty, struct bgp_table *table, struct in_addr *router
>> || type == bgp_show_type_flap_prefix_longer
>> || type == bgp_show_type_flap_route_map
>> || type == bgp_show_type_flap_neighbor)
>> - flap_route_vty_out (vty, &rn->p, ri, display, SAFI_UNICAST);
>> + flap_route_vty_out (vty, &rn->p, ri, display, safi);
>> else
>> - route_vty_out (vty, &rn->p, ri, display, SAFI_UNICAST);
>> + route_vty_out (vty, &rn->p, ri, display, safi);
>> display++;
>> }
>> if (display)
>> @@ -6749,6 +6841,35 @@ bgp_show (struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi,
>> return bgp_show_table (vty, table, &bgp->router_id, type, output_arg);
>> }
>>
>> +static int
>> +bgp_show_vrf (struct vty *vty, const char *vrf_name, afi_t afi,
>> + enum bgp_show_type type, void *output_arg)
>> +{
>> + struct bgp *bgp = bgp_get_default();
>> + struct bgp_vrf *vrf;
>> + struct prefix_rd prd;
>> +
>> + if (! bgp)
>> + {
>> + vty_out (vty, "%% No default BGP instance%s", VTY_NEWLINE);
>> + return CMD_WARNING;
>> + }
>> + if (! str2prefix_rd (vrf_name, &prd))
>> + {
>> + vty_out (vty, "%% Invalid RD '%s'%s", vrf_name, VTY_NEWLINE);
>> + return CMD_WARNING;
>> + }
>> +
>> + vrf = bgp_vrf_lookup (bgp, &prd);
>> + if (! vrf)
>> + {
>> + vty_out (vty, "%% No VRF with RD '%s'%s", vrf_name, VTY_NEWLINE);
>> + return CMD_WARNING;
>> + }
>> +
>> + return bgp_show_table (vty, vrf->rib[afi], &bgp->router_id, type, output_arg);
>> +}
>> +
>> /* Header of detailed BGP route information */
>> static void
>> route_vty_out_detail_header (struct vty *vty, struct bgp *bgp,
>> @@ -6816,6 +6937,12 @@ route_vty_out_detail_header (struct vty *vty, struct bgp *bgp,
>> vty_out (vty, ", Advertisements suppressed by an aggregate.");
>> vty_out (vty, ")%s", VTY_NEWLINE);
>>
>> + if (safi == SAFI_MPLS_LABELED_VPN)
>> + {
>> + vty_out (vty, "%s", VTY_NEWLINE);
>> + return;
>> + }
>> +
>> /* advertised peer */
>> for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer))
>> {
>> @@ -6939,6 +7066,36 @@ bgp_show_route_in_table (struct vty *vty, struct bgp *bgp,
>> return CMD_SUCCESS;
>> }
>>
>> +static int
>> +bgp_show_vrf_route (struct vty *vty, const char *vrf_name, const char *ip_str,
>> + afi_t afi, int prefix_check)
>> +{
>> + struct bgp *bgp = bgp_get_default();
>> + struct bgp_vrf *vrf;
>> + struct prefix_rd prd;
>> +
>> + if (! bgp)
>> + {
>> + vty_out (vty, "%% No default BGP instance%s", VTY_NEWLINE);
>> + return CMD_WARNING;
>> + }
>> + if (! str2prefix_rd (vrf_name, &prd))
>> + {
>> + vty_out (vty, "%% Invalid RD '%s'%s", vrf_name, VTY_NEWLINE);
>> + return CMD_WARNING;
>> + }
>> +
>> + vrf = bgp_vrf_lookup (bgp, &prd);
>> + if (! vrf)
>> + {
>> + vty_out (vty, "%% No VRF with RD '%s'%s", vrf_name, VTY_NEWLINE);
>> + return CMD_WARNING;
>> + }
>> +
>> + return bgp_show_route_in_table (vty, bgp, vrf->rib[afi], ip_str,
>> + afi, SAFI_MPLS_LABELED_VPN, NULL, prefix_check, BGP_PATH_ALL);
>> +}
>> +
>> /* Display specified route of Main RIB */
>> static int
>> bgp_show_route (struct vty *vty, const char *view_name, const char *ip_str,
>> @@ -6982,6 +7139,16 @@ DEFUN (show_ip_bgp,
>> return bgp_show (vty, NULL, AFI_IP, SAFI_UNICAST, bgp_show_type_normal, NULL);
>> }
>>
>> +DEFUN (show_ip_bgp_vrf,
>> + show_ip_bgp_vrf_cmd,
>> + "show ip bgp vrf WORD",
>> + SHOW_STR
>> + IP_STR
>> + BGP_STR)
>> +{
>> + return bgp_show_vrf (vty, argv[0], AFI_IP, bgp_show_type_normal, NULL);
>> +}
>> +
>> DEFUN (show_ip_bgp_ipv4,
>> show_ip_bgp_ipv4_cmd,
>> "show ip bgp ipv4 (unicast|multicast)",
>> @@ -7050,6 +7217,19 @@ DEFUN (show_bgp_ipv4_safi_route_pathtype,
>> return bgp_show_route (vty, NULL, argv[1], AFI_IP, SAFI_UNICAST, NULL, 0, BGP_PATH_MULTIPATH);
>> }
>>
>> +DEFUN (show_ip_bgp_vrf_route,
>> + show_ip_bgp_vrf_route_cmd,
>> + "show ip bgp vrf WORD (ipv4|ipv6) (A.B.C.D|X:X::X:X)",
>> + SHOW_STR
>> + IP_STR
>> + BGP_STR
>> + "VRF\n"
>> + "Route Distinguisher\n")
>> +{
>> + afi_t afi = (strncmp (argv[1], "ipv6", 4) == 0) ? AFI_IP6 : AFI_IP;
>> + return bgp_show_vrf_route (vty, argv[0], argv[2], afi, 0);
>> +}
>> +
>> DEFUN (show_ip_bgp_ipv4_route,
>> show_ip_bgp_ipv4_route_cmd,
>> "show ip bgp ipv4 (unicast|multicast) A.B.C.D",
>> @@ -16702,10 +16882,12 @@ bgp_route_init (void)
>>
>> /* old style commands */
>> install_element (VIEW_NODE, &show_ip_bgp_cmd);
>> + install_element (VIEW_NODE, &show_ip_bgp_vrf_cmd);
>> install_element (VIEW_NODE, &show_ip_bgp_ipv4_cmd);
>> install_element (VIEW_NODE, &show_ip_bgp_route_cmd);
>> install_element (VIEW_NODE, &show_ip_bgp_route_pathtype_cmd);
>> install_element (VIEW_NODE, &show_bgp_ipv4_safi_route_pathtype_cmd);
>> + install_element (VIEW_NODE, &show_ip_bgp_vrf_route_cmd);
>> install_element (VIEW_NODE, &show_ip_bgp_ipv4_route_cmd);
>> install_element (VIEW_NODE, &show_ip_bgp_vpnv4_all_route_cmd);
>> install_element (VIEW_NODE, &show_ip_bgp_vpnv4_rd_route_cmd);
>> @@ -16797,6 +16979,7 @@ bgp_route_init (void)
>> install_element (RESTRICTED_NODE, &show_ip_bgp_route_cmd);
>> install_element (RESTRICTED_NODE, &show_ip_bgp_route_pathtype_cmd);
>> install_element (RESTRICTED_NODE, &show_bgp_ipv4_safi_route_pathtype_cmd);
>> + install_element (RESTRICTED_NODE, &show_ip_bgp_vrf_route_cmd);
>> install_element (RESTRICTED_NODE, &show_ip_bgp_ipv4_route_cmd);
>> install_element (RESTRICTED_NODE, &show_ip_bgp_vpnv4_rd_route_cmd);
>> install_element (RESTRICTED_NODE, &show_ip_bgp_prefix_cmd);
>> @@ -16832,7 +17015,7 @@ bgp_route_init (void)
>> install_element (VIEW_NODE, &show_ip_bgp_neighbor_prefix_counts_cmd);
>> install_element (VIEW_NODE, &show_ip_bgp_ipv4_neighbor_prefix_counts_cmd);
>> install_element (VIEW_NODE, &show_ip_bgp_vpnv4_neighbor_prefix_counts_cmd);
>> -
>> + install_element (VIEW_NODE, &show_ip_bgp_vrf_cmd);
>> install_element (VIEW_NODE, &show_bgp_cmd);
>> install_element (VIEW_NODE, &show_bgp_ipv6_cmd);
>> install_element (VIEW_NODE, &show_bgp_route_cmd);
>> diff --git a/bgpd/bgp_route.h b/bgpd/bgp_route.h
>> index 332714c4f845..25a42e87bd94 100644
>> --- a/bgpd/bgp_route.h
>> +++ b/bgpd/bgp_route.h
>> @@ -43,6 +43,8 @@ struct bgp_info_extra
>>
>> /* MPLS label. */
>> u_char tag[3];
>> +
>> + struct prefix_rd vrf_rd;
>> };
>>
>> struct bgp_info
>> @@ -270,4 +272,6 @@ extern void route_vty_out_tmp (struct vty *, struct prefix *, struct attr *, saf
>> extern void bgp_peer_clear_node_queue_drain_immediate (struct peer *peer);
>> extern void bgp_process_queues_drain_immediate (void);
>>
>> +extern void bgp_vrf_apply_new_imports (struct bgp_vrf *vrf, afi_t afi);
>> +
>> #endif /* _QUAGGA_BGP_ROUTE_H */
>> diff --git a/bgpd/bgp_table.h b/bgpd/bgp_table.h
>> index 8e963aeeeb84..13d29469a058 100644
>> --- a/bgpd/bgp_table.h
>> +++ b/bgpd/bgp_table.h
>> @@ -27,6 +27,7 @@ typedef enum
>> {
>> BGP_TABLE_MAIN,
>> BGP_TABLE_RSCLIENT,
>> + BGP_TABLE_VRF,
>> } bgp_table_t;
>>
>> struct bgp_table
>> @@ -43,6 +44,8 @@ struct bgp_table
>> struct peer *owner;
>>
>> struct route_table *route_table;
>> +
>> + struct prefix_rd prd;
>> };
>>
>> struct bgp_node
>> diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c
>> index 7af4e81a87b1..63a7b5bfdcf6 100644
>> --- a/bgpd/bgp_vty.c
>> +++ b/bgpd/bgp_vty.c
>> @@ -9891,6 +9891,178 @@ bgp_config_write_redistribute (struct vty *vty, struct bgp *bgp, afi_t afi,
>> return *write;
>> }
>>
>> +DEFUN (bgp_vrf,
>> + bgp_vrf_cmd,
>> + "vrf rd WORD",
>> + "BGP VPN VRF\n"
>> + "Route Distinguisher\n"
>> + "Route Distinguisher\n"
>> +)
>> +{
>> + struct bgp *bgp = vty->index;
>> + struct bgp_vrf *vrf;
>> + struct prefix_rd prd;
>> +
>> + if (! str2prefix_rd (argv[0], &prd))
>> + {
>> + vty_out (vty, "%% Invalid RD '%s'%s", argv[0], VTY_NEWLINE);
>> + return CMD_WARNING;
>> + }
>> +
>> + vrf = bgp_vrf_lookup (bgp, &prd);
>> + if (vrf)
>> + {
>> + vty_out (vty, "%% VRF with RD '%s' already exists%s", argv[0], VTY_NEWLINE);
>> + return CMD_WARNING;
>> + }
>> +
>> + bgp_vrf_create (bgp, &prd);
>> + return CMD_SUCCESS;
>> +}
>> +
>> +DEFUN (bgp_vrf_exports,
>> + bgp_vrf_exports_cmd,
>> + "vrf rd WORD exports .LINE",
>> + "BGP VPN VRF\n"
>> + "Route Distinguisher\n"
>> + "Route Distinguisher\n"
>> + "Export RT values\n"
>> + "Export RT values\n"
>> +)
>> +{
>> + struct bgp *bgp = vty->index;
>> + struct bgp_vrf *vrf;
>> + struct prefix_rd prd;
>> + struct ecommunity *ecom = NULL;
>> + int fail = 0, i;
>> + char *rts = NULL, *rts_ptr;
>> +
>> + if (! str2prefix_rd (argv[0], &prd))
>> + {
>> + vty_out (vty, "%% Invalid RD '%s'%s", argv[0], VTY_NEWLINE);
>> + fail++;
>> + }
>> + /* forge export list */
>> + i = 1;
>> + rts = XCALLOC(MTYPE_TMP,2048);
>> + rts_ptr = rts;
>> + while(i < argc)
>> + {
>> + rts_ptr += sprintf(rts_ptr, "rt %s ",argv[i]);
>> + i++;
>> + }
>> + /* convert list of ecoms string into ecom struct */
>> + ecom = ecommunity_str2com (rts, ECOMMUNITY_ROUTE_TARGET, 1);
>> + if (! ecom)
>> + {
>> + vty_out (vty, "%% Invalid RT '%s'%s", argv[1], VTY_NEWLINE);
>> + fail++;
>> + }
>> + if (rts)
>> + XFREE (MTYPE_TMP, rts);
>> + if (fail)
>> + return CMD_WARNING;
>> +
>> + vrf = bgp_vrf_lookup (bgp, &prd);
>> + if (! vrf)
>> + {
>> + ecommunity_free (&ecom);
>> + vty_out (vty, "%% No VRF with RD '%s'%s", argv[0], VTY_NEWLINE);
>> + return CMD_WARNING;
>> + }
>> +
>> + ecom = ecommunity_intern (ecom);
>> + bgp_vrf_rt_export_set (vrf, ecom);
>> + ecommunity_unintern (&ecom);
>> + return CMD_SUCCESS;
>> +}
>> +
>> +DEFUN (bgp_vrf_imports,
>> + bgp_vrf_imports_cmd,
>> + "vrf rd WORD imports .LINE",
>> + "BGP VPN VRF\n"
>> + "Route Distinguisher\n"
>> + "Route Distinguisher\n"
>> + "Import RT values\n"
>> + "Import RT values\n"
>> +)
>> +{
>> + struct bgp *bgp = vty->index;
>> + struct bgp_vrf *vrf;
>> + struct prefix_rd prd;
>> + struct ecommunity *ecom = NULL;
>> + int fail = 0, i;
>> + char *rts = NULL, *rts_ptr;
>> +
>> + if (! str2prefix_rd (argv[0], &prd))
>> + {
>> + vty_out (vty, "%% Invalid RD '%s'%s", argv[0], VTY_NEWLINE);
>> + fail++;
>> + }
>> + /* forge export list */
>> + i = 1;
>> + rts = XCALLOC(MTYPE_TMP,2048);
>> + rts_ptr = rts;
>> + while(i < argc)
>> + {
>> + rts_ptr += sprintf(rts_ptr, "rt %s ",argv[i]);
>> + i++;
>> + }
>> + /* convert list of ecoms string into ecom struct */
>> + ecom = ecommunity_str2com (rts, ECOMMUNITY_ROUTE_TARGET, 1);
>> + if (! ecom)
>> + {
>> + vty_out (vty, "%% Invalid RT '%s'%s", argv[1], VTY_NEWLINE);
>> + fail++;
>> + }
>> + if (rts)
>> + XFREE (MTYPE_TMP, rts);
>> + if (fail)
>> + return CMD_WARNING;
>> +
>> + vrf = bgp_vrf_lookup (bgp, &prd);
>> + if (! vrf)
>> + {
>> + ecommunity_free (&ecom);
>> + vty_out (vty, "%% No VRF with RD '%s'%s", argv[0], VTY_NEWLINE);
>> + return CMD_WARNING;
>> + }
>> +
>> + ecom = ecommunity_intern (ecom);
>> + bgp_vrf_rt_import_set (vrf, ecom);
>> + ecommunity_unintern (&ecom);
>> + return CMD_SUCCESS;
>> +}
>> +
>> +DEFUN (no_bgp_vrf,
>> + no_bgp_vrf_cmd,
>> + "no vrf rd WORD",
>> + NO_STR
>> + "BGP VPN VRF\n"
>> + "Route Distinguisher\n"
>> + "Route Distinguisher\n"
>> +)
>> +{
>> + struct bgp *bgp = vty->index;
>> + struct bgp_vrf *vrf;
>> + struct prefix_rd prd;
>> +
>> + if (! str2prefix_rd (argv[0], &prd))
>> + {
>> + vty_out (vty, "%% Invalid RD '%s'%s", argv[0], VTY_NEWLINE);
>> + return CMD_WARNING;
>> + }
>> +
>> + vrf = bgp_vrf_lookup (bgp, &prd);
>> + if (! vrf)
>> + {
>> + vty_out (vty, "%% No VRF with RD '%s'%s", argv[0], VTY_NEWLINE);
>> + return CMD_WARNING;
>> + }
>> + bgp_vrf_delete (vrf);
>> + return CMD_SUCCESS;
>> +}
>> +
>> /* BGP node structure. */
>> static struct cmd_node bgp_node =
>> {
>> @@ -9982,6 +10154,11 @@ bgp_vty_init (void)
>> install_default (BGP_ENCAP_NODE);
>> install_default (BGP_ENCAPV6_NODE);
>>
>> + install_element (BGP_NODE, &bgp_vrf_cmd);
>> + install_element (BGP_NODE, &bgp_vrf_exports_cmd);
>> + install_element (BGP_NODE, &bgp_vrf_imports_cmd);
>> + install_element (BGP_NODE, &no_bgp_vrf_cmd);
>> +
>> /* "bgp multiple-instance" commands. */
>> install_element (CONFIG_NODE, &bgp_multiple_instance_cmd);
>> install_element (CONFIG_NODE, &no_bgp_multiple_instance_cmd);
>> diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c
>> index 018a59941101..5725730d9454 100644
>> --- a/bgpd/bgpd.c
>> +++ b/bgpd/bgpd.c
>> @@ -35,6 +35,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
>> #include "log.h"
>> #include "plist.h"
>> #include "linklist.h"
>> +#include "hash.h"
>> #include "workqueue.h"
>> #include "table.h"
>>
>> @@ -2057,6 +2058,164 @@ bgp_startup_timer_expire (struct thread *thread)
>> return 0;
>> }
>>
>> +/* VRFs */
>> +
>> +static unsigned int bgp_rt_hash_key (void *arg)
>> +{
>> + const struct bgp_rt_sub *rt_sub = arg;
>> + uint32_t *rtval = (uint32_t *)(char *)&rt_sub->rt;
>> + return rtval[0] ^ rtval[1];
>> +}
>> +
>> +static int bgp_rt_hash_cmp (const void *a, const void *b)
>> +{
>> + const struct bgp_rt_sub *aa = a, *bb = b;
>> + return !memcmp(&aa->rt, &bb->rt, sizeof(aa->rt));
>> +}
>> +
>> +static void *
>> +bgp_rt_hash_alloc (void *dummy)
>> +{
>> + struct bgp_rt_sub *ddummy = dummy, *rt_sub;
>> + rt_sub = XMALLOC (MTYPE_BGP_RT_SUB, sizeof (*rt_sub));
>> + rt_sub->rt = ddummy->rt;
>> + rt_sub->vrfs = list_new();
>> + return rt_sub;
>> +}
>> +
>> +static void
>> +bgp_rt_hash_dealloc (struct bgp_rt_sub *rt_sub)
>> +{
>> + list_delete (rt_sub->vrfs);
>> + XFREE (MTYPE_BGP_RT_SUB, rt_sub);
>> +}
>> +
>> +struct bgp_vrf *
>> +bgp_vrf_lookup (struct bgp *bgp, struct prefix_rd *outbound_rd)
>> +{
>> + struct listnode *node;
>> + struct bgp_vrf *vrf;
>> +
>> + for (ALL_LIST_ELEMENTS_RO(bgp->vrfs, node, vrf))
>> + if (!memcmp (outbound_rd->val, vrf->outbound_rd.val, 8))
>> + return vrf;
>> + return NULL;
>> +}
>> +
>> +struct bgp_vrf *
>> +bgp_vrf_create (struct bgp *bgp, struct prefix_rd *outbound_rd)
>> +{
>> + struct bgp_vrf *vrf;
>> + afi_t afi;
>> +
>> + if ( (vrf = XCALLOC (MTYPE_BGP_VRF, sizeof (struct bgp_vrf))) == NULL)
>> + return NULL;
>> +
>> + vrf->bgp = bgp;
>> + vrf->outbound_rd = *outbound_rd;
>> +
>> + for (afi = AFI_IP; afi < AFI_MAX; afi++)
>> + {
>> + vrf->route[afi] = bgp_table_init (afi, SAFI_UNICAST);
>> + vrf->route[afi]->type = BGP_TABLE_VRF;
>> + vrf->rib[afi] = bgp_table_init (afi, SAFI_UNICAST);
>> + vrf->rib[afi]->type = BGP_TABLE_VRF;
>> + }
>> +
>> + listnode_add (bgp->vrfs, vrf);
>> + return vrf;
>> +}
>> +
>> +static struct ecommunity * ecommunity_reintern (struct ecommunity *ecom)
>> +{
>> + assert (ecom->refcnt > 0);
>> + ecom->refcnt++;
>> + return ecom;
>> +}
>> +
>> +void
>> +bgp_vrf_rt_export_set (struct bgp_vrf *vrf, struct ecommunity *rt_export)
>> +{
>> + if (vrf->rt_export)
>> + ecommunity_unintern (&vrf->rt_export);
>> +
>> + vrf->rt_export = ecommunity_reintern (rt_export);
>> +}
>> +
>> +static void
>> +bgp_vrf_rt_import_unset (struct bgp_vrf *vrf)
>> +{
>> + size_t i;
>> +
>> + if (!vrf->rt_import)
>> + return;
>> +
>> + for (i = 0; i < (size_t)vrf->rt_import->size; i++)
>> + {
>> + struct bgp_rt_sub dummy, *rt_sub;
>> + memcpy (&dummy.rt, vrf->rt_import->val + 8 * i, 8);
>> +
>> + rt_sub = hash_lookup (vrf->bgp->rt_subscribers, &dummy);
>> + assert(rt_sub);
>> + listnode_delete (rt_sub->vrfs, vrf);
>> + if (list_isempty (rt_sub->vrfs))
>> + {
>> + hash_release (vrf->bgp->rt_subscribers, rt_sub);
>> + bgp_rt_hash_dealloc (rt_sub);
>> + }
>> + }
>> +
>> + ecommunity_unintern (&vrf->rt_import);
>> +}
>> +
>> +void
>> +bgp_vrf_rt_import_set (struct bgp_vrf *vrf, struct ecommunity *rt_import)
>> +{
>> + size_t i;
>> + afi_t afi;
>> +
>> + bgp_vrf_rt_import_unset (vrf);
>> +
>> + vrf->rt_import = ecommunity_reintern (rt_import);
>> +
>> + for (i = 0; i < (size_t)vrf->rt_import->size; i++)
>> + {
>> + struct bgp_rt_sub dummy, *rt_sub;
>> + memcpy (&dummy.rt, vrf->rt_import->val + 8 * i, 8);
>> +
>> + rt_sub = hash_get (vrf->bgp->rt_subscribers, &dummy, bgp_rt_hash_alloc);
>> + listnode_add (rt_sub->vrfs, vrf);
>> + }
>> +
>> + for (afi = AFI_IP; afi < AFI_MAX; afi++)
>> + bgp_vrf_apply_new_imports (vrf, afi);
>> +}
>> +
>> +static void
>> +bgp_vrf_delete_int (void *arg)
>> +{
>> + struct bgp_vrf *vrf = arg;
>> + char vrf_rd_str[RD_ADDRSTRLEN];
>> +
>> + prefix_rd2str(&vrf->outbound_rd, vrf_rd_str, sizeof(vrf_rd_str));
>> + zlog_info ("deleting vrf %s", vrf_rd_str);
>> +
>> + bgp_vrf_clean_tables (vrf);
>> +
>> + bgp_vrf_rt_import_unset (vrf);
>> + if (vrf->rt_export)
>> + ecommunity_unintern (&vrf->rt_export);
>> +
>> + XFREE (MTYPE_BGP_VRF, vrf);
>> +}
>> +
>> +void
>> +bgp_vrf_delete (struct bgp_vrf *vrf)
>> +{
>> + listnode_delete (vrf->bgp->vrfs, vrf);
>> + bgp_vrf_delete_int(vrf);
>> +}
>> +
>> /* BGP instance creation by `router bgp' commands. */
>> static struct bgp *
>> bgp_create (as_t *as, const char *name)
>> @@ -2103,6 +2262,10 @@ bgp_create (as_t *as, const char *name)
>> if (name)
>> bgp->name = strdup (name);
>>
>> + bgp->vrfs = list_new();
>> + bgp->vrfs->del = bgp_vrf_delete_int;
>> + bgp->rt_subscribers = hash_create(bgp_rt_hash_key, bgp_rt_hash_cmp);
>> +
>> THREAD_TIMER_ON (bm->master, bgp->t_startup, bgp_startup_timer_expire,
>> bgp, bgp->restart_time);
>>
>> @@ -2236,7 +2399,13 @@ bgp_delete (struct bgp *bgp)
>> BGP_NOTIFY_CEASE_PEER_UNCONFIG);
>> }
>> }
>> -
>> + if(bgp->vrfs)
>> + list_delete (bgp->vrfs);
>> + if(bgp->rt_subscribers)
>> + {
>> + hash_clean (bgp->rt_subscribers, NULL);
>> + hash_free (bgp->rt_subscribers);
>> + }
>> /* Delete static route. */
>> bgp_static_delete (bgp);
>>
>> @@ -5615,6 +5784,34 @@ bgp_config_write (struct vty *vty)
>> bgp_config_write_peer (vty, bgp, peer, AFI_IP, SAFI_UNICAST);
>> }
>>
>> + {
>> + struct bgp_vrf *vrf;
>> + char rdstr[RD_ADDRSTRLEN];
>> + char *str_p, *str2_p;
>> + for (ALL_LIST_ELEMENTS_RO(bgp->vrfs, node, vrf))
>> + {
>> + str_p = prefix_rd2str(&(vrf->outbound_rd), rdstr, RD_ADDRSTRLEN);
>> + vty_out(vty, " vrf rd %s%s", str_p == NULL?"<err>":str_p, VTY_NEWLINE);
>> + if(vrf->rt_import)
>> + {
>> + str2_p = ecommunity_ecom2str (vrf->rt_import, ECOMMUNITY_FORMAT_ROUTE_MAP);
>> + if(str2_p)
>> + {
>> + vty_out(vty, " vrf rd %s import %s%s", str_p == NULL?"<err>":str_p, str2_p, VTY_NEWLINE);
>> + XFREE (MTYPE_ECOMMUNITY_STR, str2_p);
>> + }
>> + }
>> + if(vrf->rt_export)
>> + {
>> + str2_p = ecommunity_ecom2str (vrf->rt_export, ECOMMUNITY_FORMAT_ROUTE_MAP);
>> + if(str2_p)
>> + {
>> + vty_out(vty, " vrf rd %s export %s%s", str_p == NULL?"<err>":str_p, str2_p, VTY_NEWLINE);
>> + XFREE (MTYPE_ECOMMUNITY_STR, str2_p);
>> + }
>> + }
>> + }
>> + }
>> /* maximum-paths */
>> bgp_config_write_maxpaths (vty, bgp, AFI_IP, SAFI_UNICAST, &write);
>>
>> diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h
>> index 0058b581377b..39fbbe5de525 100644
>> --- a/bgpd/bgpd.h
>> +++ b/bgpd/bgpd.h
>> @@ -23,12 +23,23 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
>>
>> /* For union sockunion. */
>> #include "sockunion.h"
>> +#include "bgp_ecommunity.h"
>> +#include "prefix.h"
>> +#include "vty.h"
>>
>> /* Typedef BGP specific types. */
>> typedef u_int32_t as_t;
>> typedef u_int16_t as16_t; /* we may still encounter 16 Bit asnums */
>> typedef u_int16_t bgp_size_t;
>>
>> +/* BGP router distinguisher value. */
>> +#define BGP_RD_SIZE 8
>> +
>> +struct bgp_rd
>> +{
>> + u_char val[BGP_RD_SIZE];
>> +};
>> +
>> /* BGP master for system wide configurations and variables. */
>> struct bgp_master
>> {
>> @@ -179,6 +190,38 @@ struct bgp
>> u_int16_t maxpaths_ebgp;
>> u_int16_t maxpaths_ibgp;
>> } maxpaths[AFI_MAX][SAFI_MAX];
>> +
>> + /* VRFs */
>> + struct list *vrfs;
>> +
>> + struct hash *rt_subscribers;
>> +
>> +};
>> +
>> +struct bgp_rt_sub
>> +{
>> + struct ecommunity_val rt;
>> +
>> + struct list *vrfs;
>> +};
>> +
>> +struct bgp_vrf
>> +{
>> + struct bgp *bgp;
>> +
>> + /* RD used for route advertisements */
>> + struct prefix_rd outbound_rd;
>> +
>> + /* import and export lists */
>> + struct ecommunity *rt_import;
>> + struct ecommunity *rt_export;
>> +
>> + /* BGP routing information base. */
>> + struct bgp_table *rib[AFI_MAX];
>> +
>> + /* Static route configuration. */
>> + struct bgp_table *route[AFI_MAX];
>> +
>> };
>>
>> /* BGP peer-group support. */
>> @@ -215,14 +258,6 @@ struct bgp_nexthop
>> struct in6_addr v6_local;
>> };
>>
>> -/* BGP router distinguisher value. */
>> -#define BGP_RD_SIZE 8
>> -
>> -struct bgp_rd
>> -{
>> - u_char val[BGP_RD_SIZE];
>> -};
>> -
>> #define RMAP_IN 0
>> #define RMAP_OUT 1
>> #define RMAP_IMPORT 2
>> @@ -999,4 +1034,11 @@ extern int peer_ttl_security_hops_set (struct peer *, int);
>> extern int peer_ttl_security_hops_unset (struct peer *);
>>
>> extern void bgp_scan_finish (void);
>> +extern struct bgp_vrf *bgp_vrf_create (struct bgp *bgp, struct prefix_rd *outbound_rd);
>> +extern struct bgp_vrf *bgp_vrf_lookup (struct bgp *bgp, struct prefix_rd *outbound_rd);
>> +extern void bgp_vrf_delete (struct bgp_vrf *vrf);
>> +extern void bgp_vrf_rt_export_set (struct bgp_vrf *vrf, struct ecommunity *rt_export);
>> +extern void bgp_vrf_rt_import_set (struct bgp_vrf *vrf, struct ecommunity *rt_import);
>> +extern void bgp_vrf_clean_tables (struct bgp_vrf *vrf);
>> +
>> #endif /* _QUAGGA_BGPD_H */
>> diff --git a/lib/memtypes.c b/lib/memtypes.c
>> index 8abe99d2a495..3f5bdd255756 100644
>> --- a/lib/memtypes.c
>> +++ b/lib/memtypes.c
>> @@ -157,6 +157,8 @@ struct memory_list memory_list_bgp[] =
>> { MTYPE_BGP_AGGREGATE, "BGP aggregate" },
>> { MTYPE_BGP_ADDR, "BGP own address" },
>> { MTYPE_ENCAP_TLV, "ENCAP TLV", },
>> + { MTYPE_BGP_VRF, "BGP VRF", },
>> + { MTYPE_BGP_RT_SUB, "BGP Route Target Subscribers" },
>> { -1, NULL }
>> };
>>
>
>
> _______________________________________________
> Quagga-dev mailing list
> Quagga-dev@lists.quagga.net
> https://lists.quagga.net/mailman/listinfo/quagga-dev

_______________________________________________
Quagga-dev mailing list
Quagga-dev@lists.quagga.net
https://lists.quagga.net/mailman/listinfo/quagga-dev
Re: [PATCH v2 1/2] bgpd: VRF vty configuration, RIB table creation [ In reply to ]
Philippe,

I think either we're talking past each other are have some other
major disconnect.

Per BGP LxVPNs, we really should distinguish between VRFs and (vpn)
route distribution.

WRT VRFs:

The contents of a VRF imported from BGP is determined by one or more
(import) RTs. RDs are ignored at this point.

An outgoing VPN route is exported to BGP with one or more (export) RTs.
One configured RD is typically used on outgoing routes exported from a
VRF (note not VPN) , but multiple routes (identified by different RDs)
may exist across a single VPN (as identified by an RT set).

WRT Route distribution:

Ignoring RT/community filtering, which currently isn't in the code, BGP
route distribution basically ignores RTs and uses standard route
selection based on NRLI route which includes the RD+prefix. This means
that different RDs can not only be used to segregate prefixes that exist
within a VPN (and are identified with disjoint sets of RTs) they can
also be use to support multi-path routes within a VPN (and are
identified with same/overlapping sets of RTs). BTW RRs only care about
this part.

So keying a VPN/VRF off an RD just seems wrong, particularly for the
import case where RD is ignored.

Lou

On 10/19/2016 3:59 AM, Philippe Guibert wrote:
> On Tue, Oct 18, 2016 at 3:56 PM, Lou Berger <lberger@labn.net> wrote:
>
> Hello Lou,
>
> Please read below my comments.
> Consecutive to your feedback, I think there are some improvements to bring,
> mainly about configuration and structure naming.
>
>> It looks like RD is your key to a VRF, is this right?
>> This doesn't match the semantics of BGP VPNs, where RDs are independent
>> of VRF. (RT set is really the critical thing.)
> Most of the modifications have been done around what is called the
> "VRF structure".
>
> The RD is mapped to that "VRF structure", but the RT also. This is a
> one-to-one mapping.
> That "VRF structure" has a RIB table where RT imports are processed.
>
> I mean, on the design point of view, I don't make a difference between
> a RD and a RT.
> I just have to ensure that the incoming structure is available to
> import appropriate entries.
> in order to import a RT entry, I have to create a RT mapped to an
> other "VRF structure".
>
> If the RT is not mapped to that "VRF structure", then the RIB
> associated to that RT is not present.
> Then the import in the RIB RT will not be possible.
>
> To illustrate, a quick example shows that routerA sends a NLRI entry to routerB.
>
> routerA> rd 200:111 import 100:111 export 100:111 300:111
> routerA> network 10.10.10.0/24 rd 200:111
> routerB> rd 100:111 import 100:111 export 100:111
>
> RouterB will import NLRI entry to RT 100:111
> This is possible because RouterB has the line rd100:111 ... created.
>
> RouterB will not import NLRI entry to RT 300:111, since there is no
> underlying structure.
>
> About "VRF structure", My intention is not to interfere about current
> VRF implementation in Quagga.
> From the configuration point of view, it is easy to find in literature
> cisco configuration where VRF
> and RD configuration maps together.
> Could you be more specific about the reason to dissociate RD from VRF ?
>
> One modification improvement would consist in :
> - That "VRF structure" could be renamed to "RT/RD structure"
> - some show commands would be impacted. Instead of dumping VRF RIB
> table, one would dump RT/RD RIB table
> - the commit logs would be reworked
>
>> The main implication of
>> this is that multipath/ECMP isn't (at least easily) supported.
>> Also,
>> best path selection on import routes will be wrong if keyed based on RD
> Multipath feature impacts both global RIB, and RIB per RT.
>
> As before, let me illustrate this with a 3 router setup topology.
> router A) and router B) send 2 NLRI ECMP entries to router C)
>
> routerA> rd 200:111 import 100:111 export 100:111
> routerA> network 10.10.10.0/24 rd 200:111 <nexthop_routerA>
>
> routerB> rd 200:111 import 100:111 export 100:111
> routerB> network 10.10.10.0/24 rd 200:111 <nexthop_routerB>
>
> routerC> rd 100:111 import 100:111 export 100:111
>
> When receiving a NLRI entry from routerB), and routerA), bgp_update()
> will append the entry in the global RIB, according to RD field.
>
> routerC> show bgp ipv4 vpn
> Route Distinguisher : 200:111
> *> 10.10.10.0/24 <nexthop_routerA>
> => 10.10.10.0/24 <nexthop_routerB>
>
> Then, the import processing is storing the same 2 entries in RT RIB.
> routerC> show ip bgp rd 100:111
> Route Distinguisher : 100:111
> *> 10.10.10.0/24 <nexthop_routerA>
> => 10.10.10.0/24 <nexthop_routerB>
>
> By playing with configuration, it is possible to have multipath
> entries in the global RIB, but not in the RD RIB.
>
>> and I'm not sure what's being done on route reflectors.
> There may be some missing elements on implementation.
> Only the global RIB entries injected by remote peer would be
> transmitted, including the export RT information originated by routerA
> and routerB.
>
>> I really think that BGP VRFs cannot / must not be keyed based on RDs.
>> If this is just the config interface, then changing this should be
>> pretty straight forward.
> RT RIBS are keyed based on RTs
> global RIBS entries are keyed based on RDs.
> About config interface, It would be possible to change configuration:
> instead of "vrf rd", one could have "rd <>".
>
>> PS I think an update to bgpd.texi is needed for this patch
> of course, this is something that can be done.
>
> Best Regards,
>
> Philippe
>
>> On 10/11/2016 4:17 AM, Philippe Guibert wrote:
>>> This commit introduces the BGP VRF configuration, and BGP VRF RIB
>>> table.
>>> It includes the ability for a BGP to configure its own route
>>> distinguisher ( aka VRF). New vty commands introduced:
>>>
>>> (config-router)# vrf rd <RD>
>>>
>>> This structure permits configuring import and export route targets,
>>> which is defined by RFC4360.
>>> (config-router)# vrf rd <RD> exports <RT values>
>>> (config-router)# vrf rd <RD> imports <RT values>
>>>
>>> It brings some improvements.
>>> - for a BGP speaker when emitting BGP updates, the exported route
>>> targets will be mapped to BGP extended communities associated with
>>> the BGP update for the defined Route distinguisher.
>>> This commit does not enhance the support for emitting those BGP
>>> extended communities, but provides the mecanism.
>>> - for a BGP speaker when receiving BGP updaets. Its import route
>>> target will be looked up, in order to match NLRI route distinguisher.
>>> Then, if matching, the entry would be exported to a RIB per VRF table.
>>>
>>> As mentioned before, the commit also introduces a BGP VRF RIB table per
>>> Route distinguisher configured. This table aims at receiving BGP NLRI
>>> entries, with matching import and export route targets.
>>> This commit does not take into account the fullfill of this table,
>>> but creates it.
>>>
>>> Signed-off-by: David Lamparter <equinox@opensourcerouting.org>
>>> Signed-off-by: Philippe Guibert <philippe.guibert@6wind.com>
>>> ---
>>> bgpd/bgp_route.c | 193 +++++++++++++++++++++++++++++++++++++++++++++++++++--
>>> bgpd/bgp_route.h | 4 ++
>>> bgpd/bgp_table.h | 3 +
>>> bgpd/bgp_vty.c | 177 +++++++++++++++++++++++++++++++++++++++++++++++++
>>> bgpd/bgpd.c | 199 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-
>>> bgpd/bgpd.h | 58 +++++++++++++---
>>> lib/memtypes.c | 2 +
>>> 7 files changed, 622 insertions(+), 14 deletions(-)
>>>
>>> diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c
>>> index 4cb6c141bcdc..abad79f5c9d4 100644
>>> --- a/bgpd/bgp_route.c
>>> +++ b/bgpd/bgp_route.c
>>> @@ -34,6 +34,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
>>> #include "plist.h"
>>> #include "thread.h"
>>> #include "workqueue.h"
>>> +#include "hash.h"
>>>
>>> #include "bgpd/bgpd.h"
>>> #include "bgpd/bgp_table.h"
>>> @@ -61,6 +62,12 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
>>> extern const char *bgp_origin_str[];
>>> extern const char *bgp_origin_long_str[];
>>>
>>> +static void
>>> +bgp_static_withdraw_safi (struct bgp *bgp, struct prefix *p, afi_t afi,
>>> + safi_t safi, struct prefix_rd *prd, u_char *tag);
>>> +static void
>>> +bgp_static_free (struct bgp_static *bgp_static);
>>> +
>>> static struct bgp_node *
>>> bgp_afi_node_get (struct bgp_table *table, afi_t afi, safi_t safi, struct prefix *p,
>>> struct prefix_rd *prd)
>>> @@ -77,7 +84,11 @@ bgp_afi_node_get (struct bgp_table *table, afi_t afi, safi_t safi, struct prefix
>>> prn = bgp_node_get (table, (struct prefix *) prd);
>>>
>>> if (prn->info == NULL)
>>> - prn->info = bgp_table_init (afi, safi);
>>> + {
>>> + struct bgp_table *newtab = bgp_table_init (afi, safi);
>>> + newtab->prd = *prd;
>>> + prn->info = newtab;
>>> + }
>>> else
>>> bgp_unlock_node (prn);
>>> table = prn->info;
>>> @@ -1505,12 +1516,86 @@ bgp_process_announce_selected (struct peer *peer, struct bgp_info *selected,
>>> else
>>> bgp_adj_out_unset (rn, peer, p, afi, safi);
>>> break;
>>> + case BGP_TABLE_VRF:
>>> + /* never called */
>>> + assert (0);
>>> }
>>>
>>> bgp_attr_flush (&attr);
>>> return 0;
>>> }
>>>
>>> +void bgp_vrf_clean_tables (struct bgp_vrf *vrf)
>>> +{
>>> + afi_t afi;
>>> + for (afi = AFI_IP; afi < AFI_MAX; afi++)
>>> + {
>>> + struct bgp_info *ri, *ri_next;
>>> + struct bgp_node *rn;
>>> +
>>> + for (rn = bgp_table_top (vrf->rib[afi]); rn; rn = bgp_route_next (rn))
>>> + for (ri = rn->info; ri; ri = ri_next)
>>> + {
>>> + ri_next = ri->next;
>>> + bgp_info_reap (rn, ri);
>>> + }
>>> + bgp_table_finish (&vrf->rib[afi]);
>>> +
>>> + for (rn = bgp_table_top (vrf->route[afi]); rn; rn = bgp_route_next (rn))
>>> + if (rn->info)
>>> + {
>>> + struct bgp_static *bs = rn->info;
>>> + bgp_static_withdraw_safi (vrf->bgp, &rn->p, afi, SAFI_MPLS_VPN,
>>> + &vrf->outbound_rd, NULL);
>>> + bgp_static_free (bs);
>>> + rn->info = NULL;
>>> + bgp_unlock_node (rn);
>>> + }
>>> + bgp_table_finish (&vrf->route[afi]);
>>> + }
>>> +}
>>> +
>>> +void
>>> +bgp_vrf_apply_new_imports (struct bgp_vrf *vrf, afi_t afi)
>>> +{
>>> + struct bgp_node *rd_rn, *rn;
>>> + struct bgp_info *sel;
>>> + struct bgp_table *table;
>>> + struct ecommunity *ecom;
>>> + size_t i, j;
>>> + bool found;
>>> +
>>> + if (!vrf->rt_import || vrf->rt_import->size == 0)
>>> + return;
>>> +
>>> + for (rd_rn = bgp_table_top (vrf->bgp->rib[afi][SAFI_MPLS_VPN]); rd_rn;
>>> + rd_rn = bgp_route_next (rd_rn))
>>> + if (rd_rn->info != NULL)
>>> + {
>>> + table = rd_rn->info;
>>> +
>>> + for (rn = bgp_table_top (table); rn; rn = bgp_route_next (rn))
>>> + {
>>> + for (sel = rn->info; sel; sel = sel->next)
>>> + if (CHECK_FLAG (sel->flags, BGP_INFO_SELECTED))
>>> + break;
>>> + if (!sel || !sel->attr || !sel->attr->extra)
>>> + continue;
>>> + ecom = sel->attr->extra->ecommunity;
>>> + if (!ecom)
>>> + continue;
>>> +
>>> + found = false;
>>> + for (i = 0; i < (size_t)ecom->size && !found; i++)
>>> + for (j = 0; j < (size_t)vrf->rt_import->size && !found; j++)
>>> + if (!memcmp(ecom->val + i * 8, vrf->rt_import->val + j * 8, 8))
>>> + found = true;
>>> + if (!found)
>>> + continue;
>>> + }
>>> + }
>>> +}
>>> +
>>> struct bgp_process_queue
>>> {
>>> struct bgp *bgp;
>>> @@ -1746,6 +1831,9 @@ bgp_process (struct bgp *bgp, struct bgp_node *rn, afi_t afi, safi_t safi)
>>> case BGP_TABLE_RSCLIENT:
>>> work_queue_add (bm->process_rsclient_queue, pqnode);
>>> break;
>>> + case BGP_TABLE_VRF:
>>> + /* never called */
>>> + assert (0);
>>> }
>>>
>>> SET_FLAG (rn->flags, BGP_NODE_PROCESS_SCHEDULED);
>>> @@ -6291,6 +6379,9 @@ route_vty_out_detail (struct vty *vty, struct bgp *bgp, struct prefix *p,
>>>
>>> attr = binfo->attr;
>>>
>>> + if (safi == SAFI_MPLS_LABELED_VPN)
>>> + safi = SAFI_MPLS_VPN;
>>> +
>>> if (attr)
>>> {
>>> /* Line1 display AS-path, Aggregator */
>>> @@ -6510,6 +6601,7 @@ bgp_show_table (struct vty *vty, struct bgp_table *table, struct in_addr *router
>>> int display;
>>> unsigned long output_count;
>>> unsigned long total_count;
>>> + safi_t safi = table->type == BGP_TABLE_VRF ? SAFI_MPLS_VPN : SAFI_UNICAST;
>>>
>>> /* This is first entry point, so reset total line. */
>>> output_count = 0;
>>> @@ -6694,7 +6786,7 @@ bgp_show_table (struct vty *vty, struct bgp_table *table, struct in_addr *router
>>>
>>> if (type == bgp_show_type_dampend_paths
>>> || type == bgp_show_type_damp_neighbor)
>>> - damp_route_vty_out (vty, &rn->p, ri, display, SAFI_UNICAST);
>>> + damp_route_vty_out (vty, &rn->p, ri, display, safi);
>>> else if (type == bgp_show_type_flap_statistics
>>> || type == bgp_show_type_flap_address
>>> || type == bgp_show_type_flap_prefix
>>> @@ -6705,9 +6797,9 @@ bgp_show_table (struct vty *vty, struct bgp_table *table, struct in_addr *router
>>> || type == bgp_show_type_flap_prefix_longer
>>> || type == bgp_show_type_flap_route_map
>>> || type == bgp_show_type_flap_neighbor)
>>> - flap_route_vty_out (vty, &rn->p, ri, display, SAFI_UNICAST);
>>> + flap_route_vty_out (vty, &rn->p, ri, display, safi);
>>> else
>>> - route_vty_out (vty, &rn->p, ri, display, SAFI_UNICAST);
>>> + route_vty_out (vty, &rn->p, ri, display, safi);
>>> display++;
>>> }
>>> if (display)
>>> @@ -6749,6 +6841,35 @@ bgp_show (struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi,
>>> return bgp_show_table (vty, table, &bgp->router_id, type, output_arg);
>>> }
>>>
>>> +static int
>>> +bgp_show_vrf (struct vty *vty, const char *vrf_name, afi_t afi,
>>> + enum bgp_show_type type, void *output_arg)
>>> +{
>>> + struct bgp *bgp = bgp_get_default();
>>> + struct bgp_vrf *vrf;
>>> + struct prefix_rd prd;
>>> +
>>> + if (! bgp)
>>> + {
>>> + vty_out (vty, "%% No default BGP instance%s", VTY_NEWLINE);
>>> + return CMD_WARNING;
>>> + }
>>> + if (! str2prefix_rd (vrf_name, &prd))
>>> + {
>>> + vty_out (vty, "%% Invalid RD '%s'%s", vrf_name, VTY_NEWLINE);
>>> + return CMD_WARNING;
>>> + }
>>> +
>>> + vrf = bgp_vrf_lookup (bgp, &prd);
>>> + if (! vrf)
>>> + {
>>> + vty_out (vty, "%% No VRF with RD '%s'%s", vrf_name, VTY_NEWLINE);
>>> + return CMD_WARNING;
>>> + }
>>> +
>>> + return bgp_show_table (vty, vrf->rib[afi], &bgp->router_id, type, output_arg);
>>> +}
>>> +
>>> /* Header of detailed BGP route information */
>>> static void
>>> route_vty_out_detail_header (struct vty *vty, struct bgp *bgp,
>>> @@ -6816,6 +6937,12 @@ route_vty_out_detail_header (struct vty *vty, struct bgp *bgp,
>>> vty_out (vty, ", Advertisements suppressed by an aggregate.");
>>> vty_out (vty, ")%s", VTY_NEWLINE);
>>>
>>> + if (safi == SAFI_MPLS_LABELED_VPN)
>>> + {
>>> + vty_out (vty, "%s", VTY_NEWLINE);
>>> + return;
>>> + }
>>> +
>>> /* advertised peer */
>>> for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer))
>>> {
>>> @@ -6939,6 +7066,36 @@ bgp_show_route_in_table (struct vty *vty, struct bgp *bgp,
>>> return CMD_SUCCESS;
>>> }
>>>
>>> +static int
>>> +bgp_show_vrf_route (struct vty *vty, const char *vrf_name, const char *ip_str,
>>> + afi_t afi, int prefix_check)
>>> +{
>>> + struct bgp *bgp = bgp_get_default();
>>> + struct bgp_vrf *vrf;
>>> + struct prefix_rd prd;
>>> +
>>> + if (! bgp)
>>> + {
>>> + vty_out (vty, "%% No default BGP instance%s", VTY_NEWLINE);
>>> + return CMD_WARNING;
>>> + }
>>> + if (! str2prefix_rd (vrf_name, &prd))
>>> + {
>>> + vty_out (vty, "%% Invalid RD '%s'%s", vrf_name, VTY_NEWLINE);
>>> + return CMD_WARNING;
>>> + }
>>> +
>>> + vrf = bgp_vrf_lookup (bgp, &prd);
>>> + if (! vrf)
>>> + {
>>> + vty_out (vty, "%% No VRF with RD '%s'%s", vrf_name, VTY_NEWLINE);
>>> + return CMD_WARNING;
>>> + }
>>> +
>>> + return bgp_show_route_in_table (vty, bgp, vrf->rib[afi], ip_str,
>>> + afi, SAFI_MPLS_LABELED_VPN, NULL, prefix_check, BGP_PATH_ALL);
>>> +}
>>> +
>>> /* Display specified route of Main RIB */
>>> static int
>>> bgp_show_route (struct vty *vty, const char *view_name, const char *ip_str,
>>> @@ -6982,6 +7139,16 @@ DEFUN (show_ip_bgp,
>>> return bgp_show (vty, NULL, AFI_IP, SAFI_UNICAST, bgp_show_type_normal, NULL);
>>> }
>>>
>>> +DEFUN (show_ip_bgp_vrf,
>>> + show_ip_bgp_vrf_cmd,
>>> + "show ip bgp vrf WORD",
>>> + SHOW_STR
>>> + IP_STR
>>> + BGP_STR)
>>> +{
>>> + return bgp_show_vrf (vty, argv[0], AFI_IP, bgp_show_type_normal, NULL);
>>> +}
>>> +
>>> DEFUN (show_ip_bgp_ipv4,
>>> show_ip_bgp_ipv4_cmd,
>>> "show ip bgp ipv4 (unicast|multicast)",
>>> @@ -7050,6 +7217,19 @@ DEFUN (show_bgp_ipv4_safi_route_pathtype,
>>> return bgp_show_route (vty, NULL, argv[1], AFI_IP, SAFI_UNICAST, NULL, 0, BGP_PATH_MULTIPATH);
>>> }
>>>
>>> +DEFUN (show_ip_bgp_vrf_route,
>>> + show_ip_bgp_vrf_route_cmd,
>>> + "show ip bgp vrf WORD (ipv4|ipv6) (A.B.C.D|X:X::X:X)",
>>> + SHOW_STR
>>> + IP_STR
>>> + BGP_STR
>>> + "VRF\n"
>>> + "Route Distinguisher\n")
>>> +{
>>> + afi_t afi = (strncmp (argv[1], "ipv6", 4) == 0) ? AFI_IP6 : AFI_IP;
>>> + return bgp_show_vrf_route (vty, argv[0], argv[2], afi, 0);
>>> +}
>>> +
>>> DEFUN (show_ip_bgp_ipv4_route,
>>> show_ip_bgp_ipv4_route_cmd,
>>> "show ip bgp ipv4 (unicast|multicast) A.B.C.D",
>>> @@ -16702,10 +16882,12 @@ bgp_route_init (void)
>>>
>>> /* old style commands */
>>> install_element (VIEW_NODE, &show_ip_bgp_cmd);
>>> + install_element (VIEW_NODE, &show_ip_bgp_vrf_cmd);
>>> install_element (VIEW_NODE, &show_ip_bgp_ipv4_cmd);
>>> install_element (VIEW_NODE, &show_ip_bgp_route_cmd);
>>> install_element (VIEW_NODE, &show_ip_bgp_route_pathtype_cmd);
>>> install_element (VIEW_NODE, &show_bgp_ipv4_safi_route_pathtype_cmd);
>>> + install_element (VIEW_NODE, &show_ip_bgp_vrf_route_cmd);
>>> install_element (VIEW_NODE, &show_ip_bgp_ipv4_route_cmd);
>>> install_element (VIEW_NODE, &show_ip_bgp_vpnv4_all_route_cmd);
>>> install_element (VIEW_NODE, &show_ip_bgp_vpnv4_rd_route_cmd);
>>> @@ -16797,6 +16979,7 @@ bgp_route_init (void)
>>> install_element (RESTRICTED_NODE, &show_ip_bgp_route_cmd);
>>> install_element (RESTRICTED_NODE, &show_ip_bgp_route_pathtype_cmd);
>>> install_element (RESTRICTED_NODE, &show_bgp_ipv4_safi_route_pathtype_cmd);
>>> + install_element (RESTRICTED_NODE, &show_ip_bgp_vrf_route_cmd);
>>> install_element (RESTRICTED_NODE, &show_ip_bgp_ipv4_route_cmd);
>>> install_element (RESTRICTED_NODE, &show_ip_bgp_vpnv4_rd_route_cmd);
>>> install_element (RESTRICTED_NODE, &show_ip_bgp_prefix_cmd);
>>> @@ -16832,7 +17015,7 @@ bgp_route_init (void)
>>> install_element (VIEW_NODE, &show_ip_bgp_neighbor_prefix_counts_cmd);
>>> install_element (VIEW_NODE, &show_ip_bgp_ipv4_neighbor_prefix_counts_cmd);
>>> install_element (VIEW_NODE, &show_ip_bgp_vpnv4_neighbor_prefix_counts_cmd);
>>> -
>>> + install_element (VIEW_NODE, &show_ip_bgp_vrf_cmd);
>>> install_element (VIEW_NODE, &show_bgp_cmd);
>>> install_element (VIEW_NODE, &show_bgp_ipv6_cmd);
>>> install_element (VIEW_NODE, &show_bgp_route_cmd);
>>> diff --git a/bgpd/bgp_route.h b/bgpd/bgp_route.h
>>> index 332714c4f845..25a42e87bd94 100644
>>> --- a/bgpd/bgp_route.h
>>> +++ b/bgpd/bgp_route.h
>>> @@ -43,6 +43,8 @@ struct bgp_info_extra
>>>
>>> /* MPLS label. */
>>> u_char tag[3];
>>> +
>>> + struct prefix_rd vrf_rd;
>>> };
>>>
>>> struct bgp_info
>>> @@ -270,4 +272,6 @@ extern void route_vty_out_tmp (struct vty *, struct prefix *, struct attr *, saf
>>> extern void bgp_peer_clear_node_queue_drain_immediate (struct peer *peer);
>>> extern void bgp_process_queues_drain_immediate (void);
>>>
>>> +extern void bgp_vrf_apply_new_imports (struct bgp_vrf *vrf, afi_t afi);
>>> +
>>> #endif /* _QUAGGA_BGP_ROUTE_H */
>>> diff --git a/bgpd/bgp_table.h b/bgpd/bgp_table.h
>>> index 8e963aeeeb84..13d29469a058 100644
>>> --- a/bgpd/bgp_table.h
>>> +++ b/bgpd/bgp_table.h
>>> @@ -27,6 +27,7 @@ typedef enum
>>> {
>>> BGP_TABLE_MAIN,
>>> BGP_TABLE_RSCLIENT,
>>> + BGP_TABLE_VRF,
>>> } bgp_table_t;
>>>
>>> struct bgp_table
>>> @@ -43,6 +44,8 @@ struct bgp_table
>>> struct peer *owner;
>>>
>>> struct route_table *route_table;
>>> +
>>> + struct prefix_rd prd;
>>> };
>>>
>>> struct bgp_node
>>> diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c
>>> index 7af4e81a87b1..63a7b5bfdcf6 100644
>>> --- a/bgpd/bgp_vty.c
>>> +++ b/bgpd/bgp_vty.c
>>> @@ -9891,6 +9891,178 @@ bgp_config_write_redistribute (struct vty *vty, struct bgp *bgp, afi_t afi,
>>> return *write;
>>> }
>>>
>>> +DEFUN (bgp_vrf,
>>> + bgp_vrf_cmd,
>>> + "vrf rd WORD",
>>> + "BGP VPN VRF\n"
>>> + "Route Distinguisher\n"
>>> + "Route Distinguisher\n"
>>> +)
>>> +{
>>> + struct bgp *bgp = vty->index;
>>> + struct bgp_vrf *vrf;
>>> + struct prefix_rd prd;
>>> +
>>> + if (! str2prefix_rd (argv[0], &prd))
>>> + {
>>> + vty_out (vty, "%% Invalid RD '%s'%s", argv[0], VTY_NEWLINE);
>>> + return CMD_WARNING;
>>> + }
>>> +
>>> + vrf = bgp_vrf_lookup (bgp, &prd);
>>> + if (vrf)
>>> + {
>>> + vty_out (vty, "%% VRF with RD '%s' already exists%s", argv[0], VTY_NEWLINE);
>>> + return CMD_WARNING;
>>> + }
>>> +
>>> + bgp_vrf_create (bgp, &prd);
>>> + return CMD_SUCCESS;
>>> +}
>>> +
>>> +DEFUN (bgp_vrf_exports,
>>> + bgp_vrf_exports_cmd,
>>> + "vrf rd WORD exports .LINE",
>>> + "BGP VPN VRF\n"
>>> + "Route Distinguisher\n"
>>> + "Route Distinguisher\n"
>>> + "Export RT values\n"
>>> + "Export RT values\n"
>>> +)
>>> +{
>>> + struct bgp *bgp = vty->index;
>>> + struct bgp_vrf *vrf;
>>> + struct prefix_rd prd;
>>> + struct ecommunity *ecom = NULL;
>>> + int fail = 0, i;
>>> + char *rts = NULL, *rts_ptr;
>>> +
>>> + if (! str2prefix_rd (argv[0], &prd))
>>> + {
>>> + vty_out (vty, "%% Invalid RD '%s'%s", argv[0], VTY_NEWLINE);
>>> + fail++;
>>> + }
>>> + /* forge export list */
>>> + i = 1;
>>> + rts = XCALLOC(MTYPE_TMP,2048);
>>> + rts_ptr = rts;
>>> + while(i < argc)
>>> + {
>>> + rts_ptr += sprintf(rts_ptr, "rt %s ",argv[i]);
>>> + i++;
>>> + }
>>> + /* convert list of ecoms string into ecom struct */
>>> + ecom = ecommunity_str2com (rts, ECOMMUNITY_ROUTE_TARGET, 1);
>>> + if (! ecom)
>>> + {
>>> + vty_out (vty, "%% Invalid RT '%s'%s", argv[1], VTY_NEWLINE);
>>> + fail++;
>>> + }
>>> + if (rts)
>>> + XFREE (MTYPE_TMP, rts);
>>> + if (fail)
>>> + return CMD_WARNING;
>>> +
>>> + vrf = bgp_vrf_lookup (bgp, &prd);
>>> + if (! vrf)
>>> + {
>>> + ecommunity_free (&ecom);
>>> + vty_out (vty, "%% No VRF with RD '%s'%s", argv[0], VTY_NEWLINE);
>>> + return CMD_WARNING;
>>> + }
>>> +
>>> + ecom = ecommunity_intern (ecom);
>>> + bgp_vrf_rt_export_set (vrf, ecom);
>>> + ecommunity_unintern (&ecom);
>>> + return CMD_SUCCESS;
>>> +}
>>> +
>>> +DEFUN (bgp_vrf_imports,
>>> + bgp_vrf_imports_cmd,
>>> + "vrf rd WORD imports .LINE",
>>> + "BGP VPN VRF\n"
>>> + "Route Distinguisher\n"
>>> + "Route Distinguisher\n"
>>> + "Import RT values\n"
>>> + "Import RT values\n"
>>> +)
>>> +{
>>> + struct bgp *bgp = vty->index;
>>> + struct bgp_vrf *vrf;
>>> + struct prefix_rd prd;
>>> + struct ecommunity *ecom = NULL;
>>> + int fail = 0, i;
>>> + char *rts = NULL, *rts_ptr;
>>> +
>>> + if (! str2prefix_rd (argv[0], &prd))
>>> + {
>>> + vty_out (vty, "%% Invalid RD '%s'%s", argv[0], VTY_NEWLINE);
>>> + fail++;
>>> + }
>>> + /* forge export list */
>>> + i = 1;
>>> + rts = XCALLOC(MTYPE_TMP,2048);
>>> + rts_ptr = rts;
>>> + while(i < argc)
>>> + {
>>> + rts_ptr += sprintf(rts_ptr, "rt %s ",argv[i]);
>>> + i++;
>>> + }
>>> + /* convert list of ecoms string into ecom struct */
>>> + ecom = ecommunity_str2com (rts, ECOMMUNITY_ROUTE_TARGET, 1);
>>> + if (! ecom)
>>> + {
>>> + vty_out (vty, "%% Invalid RT '%s'%s", argv[1], VTY_NEWLINE);
>>> + fail++;
>>> + }
>>> + if (rts)
>>> + XFREE (MTYPE_TMP, rts);
>>> + if (fail)
>>> + return CMD_WARNING;
>>> +
>>> + vrf = bgp_vrf_lookup (bgp, &prd);
>>> + if (! vrf)
>>> + {
>>> + ecommunity_free (&ecom);
>>> + vty_out (vty, "%% No VRF with RD '%s'%s", argv[0], VTY_NEWLINE);
>>> + return CMD_WARNING;
>>> + }
>>> +
>>> + ecom = ecommunity_intern (ecom);
>>> + bgp_vrf_rt_import_set (vrf, ecom);
>>> + ecommunity_unintern (&ecom);
>>> + return CMD_SUCCESS;
>>> +}
>>> +
>>> +DEFUN (no_bgp_vrf,
>>> + no_bgp_vrf_cmd,
>>> + "no vrf rd WORD",
>>> + NO_STR
>>> + "BGP VPN VRF\n"
>>> + "Route Distinguisher\n"
>>> + "Route Distinguisher\n"
>>> +)
>>> +{
>>> + struct bgp *bgp = vty->index;
>>> + struct bgp_vrf *vrf;
>>> + struct prefix_rd prd;
>>> +
>>> + if (! str2prefix_rd (argv[0], &prd))
>>> + {
>>> + vty_out (vty, "%% Invalid RD '%s'%s", argv[0], VTY_NEWLINE);
>>> + return CMD_WARNING;
>>> + }
>>> +
>>> + vrf = bgp_vrf_lookup (bgp, &prd);
>>> + if (! vrf)
>>> + {
>>> + vty_out (vty, "%% No VRF with RD '%s'%s", argv[0], VTY_NEWLINE);
>>> + return CMD_WARNING;
>>> + }
>>> + bgp_vrf_delete (vrf);
>>> + return CMD_SUCCESS;
>>> +}
>>> +
>>> /* BGP node structure. */
>>> static struct cmd_node bgp_node =
>>> {
>>> @@ -9982,6 +10154,11 @@ bgp_vty_init (void)
>>> install_default (BGP_ENCAP_NODE);
>>> install_default (BGP_ENCAPV6_NODE);
>>>
>>> + install_element (BGP_NODE, &bgp_vrf_cmd);
>>> + install_element (BGP_NODE, &bgp_vrf_exports_cmd);
>>> + install_element (BGP_NODE, &bgp_vrf_imports_cmd);
>>> + install_element (BGP_NODE, &no_bgp_vrf_cmd);
>>> +
>>> /* "bgp multiple-instance" commands. */
>>> install_element (CONFIG_NODE, &bgp_multiple_instance_cmd);
>>> install_element (CONFIG_NODE, &no_bgp_multiple_instance_cmd);
>>> diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c
>>> index 018a59941101..5725730d9454 100644
>>> --- a/bgpd/bgpd.c
>>> +++ b/bgpd/bgpd.c
>>> @@ -35,6 +35,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
>>> #include "log.h"
>>> #include "plist.h"
>>> #include "linklist.h"
>>> +#include "hash.h"
>>> #include "workqueue.h"
>>> #include "table.h"
>>>
>>> @@ -2057,6 +2058,164 @@ bgp_startup_timer_expire (struct thread *thread)
>>> return 0;
>>> }
>>>
>>> +/* VRFs */
>>> +
>>> +static unsigned int bgp_rt_hash_key (void *arg)
>>> +{
>>> + const struct bgp_rt_sub *rt_sub = arg;
>>> + uint32_t *rtval = (uint32_t *)(char *)&rt_sub->rt;
>>> + return rtval[0] ^ rtval[1];
>>> +}
>>> +
>>> +static int bgp_rt_hash_cmp (const void *a, const void *b)
>>> +{
>>> + const struct bgp_rt_sub *aa = a, *bb = b;
>>> + return !memcmp(&aa->rt, &bb->rt, sizeof(aa->rt));
>>> +}
>>> +
>>> +static void *
>>> +bgp_rt_hash_alloc (void *dummy)
>>> +{
>>> + struct bgp_rt_sub *ddummy = dummy, *rt_sub;
>>> + rt_sub = XMALLOC (MTYPE_BGP_RT_SUB, sizeof (*rt_sub));
>>> + rt_sub->rt = ddummy->rt;
>>> + rt_sub->vrfs = list_new();
>>> + return rt_sub;
>>> +}
>>> +
>>> +static void
>>> +bgp_rt_hash_dealloc (struct bgp_rt_sub *rt_sub)
>>> +{
>>> + list_delete (rt_sub->vrfs);
>>> + XFREE (MTYPE_BGP_RT_SUB, rt_sub);
>>> +}
>>> +
>>> +struct bgp_vrf *
>>> +bgp_vrf_lookup (struct bgp *bgp, struct prefix_rd *outbound_rd)
>>> +{
>>> + struct listnode *node;
>>> + struct bgp_vrf *vrf;
>>> +
>>> + for (ALL_LIST_ELEMENTS_RO(bgp->vrfs, node, vrf))
>>> + if (!memcmp (outbound_rd->val, vrf->outbound_rd.val, 8))
>>> + return vrf;
>>> + return NULL;
>>> +}
>>> +
>>> +struct bgp_vrf *
>>> +bgp_vrf_create (struct bgp *bgp, struct prefix_rd *outbound_rd)
>>> +{
>>> + struct bgp_vrf *vrf;
>>> + afi_t afi;
>>> +
>>> + if ( (vrf = XCALLOC (MTYPE_BGP_VRF, sizeof (struct bgp_vrf))) == NULL)
>>> + return NULL;
>>> +
>>> + vrf->bgp = bgp;
>>> + vrf->outbound_rd = *outbound_rd;
>>> +
>>> + for (afi = AFI_IP; afi < AFI_MAX; afi++)
>>> + {
>>> + vrf->route[afi] = bgp_table_init (afi, SAFI_UNICAST);
>>> + vrf->route[afi]->type = BGP_TABLE_VRF;
>>> + vrf->rib[afi] = bgp_table_init (afi, SAFI_UNICAST);
>>> + vrf->rib[afi]->type = BGP_TABLE_VRF;
>>> + }
>>> +
>>> + listnode_add (bgp->vrfs, vrf);
>>> + return vrf;
>>> +}
>>> +
>>> +static struct ecommunity * ecommunity_reintern (struct ecommunity *ecom)
>>> +{
>>> + assert (ecom->refcnt > 0);
>>> + ecom->refcnt++;
>>> + return ecom;
>>> +}
>>> +
>>> +void
>>> +bgp_vrf_rt_export_set (struct bgp_vrf *vrf, struct ecommunity *rt_export)
>>> +{
>>> + if (vrf->rt_export)
>>> + ecommunity_unintern (&vrf->rt_export);
>>> +
>>> + vrf->rt_export = ecommunity_reintern (rt_export);
>>> +}
>>> +
>>> +static void
>>> +bgp_vrf_rt_import_unset (struct bgp_vrf *vrf)
>>> +{
>>> + size_t i;
>>> +
>>> + if (!vrf->rt_import)
>>> + return;
>>> +
>>> + for (i = 0; i < (size_t)vrf->rt_import->size; i++)
>>> + {
>>> + struct bgp_rt_sub dummy, *rt_sub;
>>> + memcpy (&dummy.rt, vrf->rt_import->val + 8 * i, 8);
>>> +
>>> + rt_sub = hash_lookup (vrf->bgp->rt_subscribers, &dummy);
>>> + assert(rt_sub);
>>> + listnode_delete (rt_sub->vrfs, vrf);
>>> + if (list_isempty (rt_sub->vrfs))
>>> + {
>>> + hash_release (vrf->bgp->rt_subscribers, rt_sub);
>>> + bgp_rt_hash_dealloc (rt_sub);
>>> + }
>>> + }
>>> +
>>> + ecommunity_unintern (&vrf->rt_import);
>>> +}
>>> +
>>> +void
>>> +bgp_vrf_rt_import_set (struct bgp_vrf *vrf, struct ecommunity *rt_import)
>>> +{
>>> + size_t i;
>>> + afi_t afi;
>>> +
>>> + bgp_vrf_rt_import_unset (vrf);
>>> +
>>> + vrf->rt_import = ecommunity_reintern (rt_import);
>>> +
>>> + for (i = 0; i < (size_t)vrf->rt_import->size; i++)
>>> + {
>>> + struct bgp_rt_sub dummy, *rt_sub;
>>> + memcpy (&dummy.rt, vrf->rt_import->val + 8 * i, 8);
>>> +
>>> + rt_sub = hash_get (vrf->bgp->rt_subscribers, &dummy, bgp_rt_hash_alloc);
>>> + listnode_add (rt_sub->vrfs, vrf);
>>> + }
>>> +
>>> + for (afi = AFI_IP; afi < AFI_MAX; afi++)
>>> + bgp_vrf_apply_new_imports (vrf, afi);
>>> +}
>>> +
>>> +static void
>>> +bgp_vrf_delete_int (void *arg)
>>> +{
>>> + struct bgp_vrf *vrf = arg;
>>> + char vrf_rd_str[RD_ADDRSTRLEN];
>>> +
>>> + prefix_rd2str(&vrf->outbound_rd, vrf_rd_str, sizeof(vrf_rd_str));
>>> + zlog_info ("deleting vrf %s", vrf_rd_str);
>>> +
>>> + bgp_vrf_clean_tables (vrf);
>>> +
>>> + bgp_vrf_rt_import_unset (vrf);
>>> + if (vrf->rt_export)
>>> + ecommunity_unintern (&vrf->rt_export);
>>> +
>>> + XFREE (MTYPE_BGP_VRF, vrf);
>>> +}
>>> +
>>> +void
>>> +bgp_vrf_delete (struct bgp_vrf *vrf)
>>> +{
>>> + listnode_delete (vrf->bgp->vrfs, vrf);
>>> + bgp_vrf_delete_int(vrf);
>>> +}
>>> +
>>> /* BGP instance creation by `router bgp' commands. */
>>> static struct bgp *
>>> bgp_create (as_t *as, const char *name)
>>> @@ -2103,6 +2262,10 @@ bgp_create (as_t *as, const char *name)
>>> if (name)
>>> bgp->name = strdup (name);
>>>
>>> + bgp->vrfs = list_new();
>>> + bgp->vrfs->del = bgp_vrf_delete_int;
>>> + bgp->rt_subscribers = hash_create(bgp_rt_hash_key, bgp_rt_hash_cmp);
>>> +
>>> THREAD_TIMER_ON (bm->master, bgp->t_startup, bgp_startup_timer_expire,
>>> bgp, bgp->restart_time);
>>>
>>> @@ -2236,7 +2399,13 @@ bgp_delete (struct bgp *bgp)
>>> BGP_NOTIFY_CEASE_PEER_UNCONFIG);
>>> }
>>> }
>>> -
>>> + if(bgp->vrfs)
>>> + list_delete (bgp->vrfs);
>>> + if(bgp->rt_subscribers)
>>> + {
>>> + hash_clean (bgp->rt_subscribers, NULL);
>>> + hash_free (bgp->rt_subscribers);
>>> + }
>>> /* Delete static route. */
>>> bgp_static_delete (bgp);
>>>
>>> @@ -5615,6 +5784,34 @@ bgp_config_write (struct vty *vty)
>>> bgp_config_write_peer (vty, bgp, peer, AFI_IP, SAFI_UNICAST);
>>> }
>>>
>>> + {
>>> + struct bgp_vrf *vrf;
>>> + char rdstr[RD_ADDRSTRLEN];
>>> + char *str_p, *str2_p;
>>> + for (ALL_LIST_ELEMENTS_RO(bgp->vrfs, node, vrf))
>>> + {
>>> + str_p = prefix_rd2str(&(vrf->outbound_rd), rdstr, RD_ADDRSTRLEN);
>>> + vty_out(vty, " vrf rd %s%s", str_p == NULL?"<err>":str_p, VTY_NEWLINE);
>>> + if(vrf->rt_import)
>>> + {
>>> + str2_p = ecommunity_ecom2str (vrf->rt_import, ECOMMUNITY_FORMAT_ROUTE_MAP);
>>> + if(str2_p)
>>> + {
>>> + vty_out(vty, " vrf rd %s import %s%s", str_p == NULL?"<err>":str_p, str2_p, VTY_NEWLINE);
>>> + XFREE (MTYPE_ECOMMUNITY_STR, str2_p);
>>> + }
>>> + }
>>> + if(vrf->rt_export)
>>> + {
>>> + str2_p = ecommunity_ecom2str (vrf->rt_export, ECOMMUNITY_FORMAT_ROUTE_MAP);
>>> + if(str2_p)
>>> + {
>>> + vty_out(vty, " vrf rd %s export %s%s", str_p == NULL?"<err>":str_p, str2_p, VTY_NEWLINE);
>>> + XFREE (MTYPE_ECOMMUNITY_STR, str2_p);
>>> + }
>>> + }
>>> + }
>>> + }
>>> /* maximum-paths */
>>> bgp_config_write_maxpaths (vty, bgp, AFI_IP, SAFI_UNICAST, &write);
>>>
>>> diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h
>>> index 0058b581377b..39fbbe5de525 100644
>>> --- a/bgpd/bgpd.h
>>> +++ b/bgpd/bgpd.h
>>> @@ -23,12 +23,23 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
>>>
>>> /* For union sockunion. */
>>> #include "sockunion.h"
>>> +#include "bgp_ecommunity.h"
>>> +#include "prefix.h"
>>> +#include "vty.h"
>>>
>>> /* Typedef BGP specific types. */
>>> typedef u_int32_t as_t;
>>> typedef u_int16_t as16_t; /* we may still encounter 16 Bit asnums */
>>> typedef u_int16_t bgp_size_t;
>>>
>>> +/* BGP router distinguisher value. */
>>> +#define BGP_RD_SIZE 8
>>> +
>>> +struct bgp_rd
>>> +{
>>> + u_char val[BGP_RD_SIZE];
>>> +};
>>> +
>>> /* BGP master for system wide configurations and variables. */
>>> struct bgp_master
>>> {
>>> @@ -179,6 +190,38 @@ struct bgp
>>> u_int16_t maxpaths_ebgp;
>>> u_int16_t maxpaths_ibgp;
>>> } maxpaths[AFI_MAX][SAFI_MAX];
>>> +
>>> + /* VRFs */
>>> + struct list *vrfs;
>>> +
>>> + struct hash *rt_subscribers;
>>> +
>>> +};
>>> +
>>> +struct bgp_rt_sub
>>> +{
>>> + struct ecommunity_val rt;
>>> +
>>> + struct list *vrfs;
>>> +};
>>> +
>>> +struct bgp_vrf
>>> +{
>>> + struct bgp *bgp;
>>> +
>>> + /* RD used for route advertisements */
>>> + struct prefix_rd outbound_rd;
>>> +
>>> + /* import and export lists */
>>> + struct ecommunity *rt_import;
>>> + struct ecommunity *rt_export;
>>> +
>>> + /* BGP routing information base. */
>>> + struct bgp_table *rib[AFI_MAX];
>>> +
>>> + /* Static route configuration. */
>>> + struct bgp_table *route[AFI_MAX];
>>> +
>>> };
>>>
>>> /* BGP peer-group support. */
>>> @@ -215,14 +258,6 @@ struct bgp_nexthop
>>> struct in6_addr v6_local;
>>> };
>>>
>>> -/* BGP router distinguisher value. */
>>> -#define BGP_RD_SIZE 8
>>> -
>>> -struct bgp_rd
>>> -{
>>> - u_char val[BGP_RD_SIZE];
>>> -};
>>> -
>>> #define RMAP_IN 0
>>> #define RMAP_OUT 1
>>> #define RMAP_IMPORT 2
>>> @@ -999,4 +1034,11 @@ extern int peer_ttl_security_hops_set (struct peer *, int);
>>> extern int peer_ttl_security_hops_unset (struct peer *);
>>>
>>> extern void bgp_scan_finish (void);
>>> +extern struct bgp_vrf *bgp_vrf_create (struct bgp *bgp, struct prefix_rd *outbound_rd);
>>> +extern struct bgp_vrf *bgp_vrf_lookup (struct bgp *bgp, struct prefix_rd *outbound_rd);
>>> +extern void bgp_vrf_delete (struct bgp_vrf *vrf);
>>> +extern void bgp_vrf_rt_export_set (struct bgp_vrf *vrf, struct ecommunity *rt_export);
>>> +extern void bgp_vrf_rt_import_set (struct bgp_vrf *vrf, struct ecommunity *rt_import);
>>> +extern void bgp_vrf_clean_tables (struct bgp_vrf *vrf);
>>> +
>>> #endif /* _QUAGGA_BGPD_H */
>>> diff --git a/lib/memtypes.c b/lib/memtypes.c
>>> index 8abe99d2a495..3f5bdd255756 100644
>>> --- a/lib/memtypes.c
>>> +++ b/lib/memtypes.c
>>> @@ -157,6 +157,8 @@ struct memory_list memory_list_bgp[] =
>>> { MTYPE_BGP_AGGREGATE, "BGP aggregate" },
>>> { MTYPE_BGP_ADDR, "BGP own address" },
>>> { MTYPE_ENCAP_TLV, "ENCAP TLV", },
>>> + { MTYPE_BGP_VRF, "BGP VRF", },
>>> + { MTYPE_BGP_RT_SUB, "BGP Route Target Subscribers" },
>>> { -1, NULL }
>>> };
>>>
>>
>> _______________________________________________
>> Quagga-dev mailing list
>> Quagga-dev@lists.quagga.net
>> https://lists.quagga.net/mailman/listinfo/quagga-dev


_______________________________________________
Quagga-dev mailing list
Quagga-dev@lists.quagga.net
https://lists.quagga.net/mailman/listinfo/quagga-dev
Re: [PATCH v2 1/2] bgpd: VRF vty configuration, RIB table creation [ In reply to ]
On Wed, Oct 19, 2016 at 2:22 PM, Lou Berger <lberger@labn.net> wrote:

Hello Lou,

> I think either we're talking past each other are have some other
> major disconnect.

Let me reassure you. If both of us speak not at the same time design and
concepts,this may be problematic :-)
About the concepts you are talking about, I agree with you.
Regarding design issue, I think there is a misunderstanding because I
link RD with RTs, within a VRF.
Whereas you point the following:
- associate RD with VPN flows
- associate RT set with VRF

The design currently is not aware of the underlying VRF it works on.
One reason is that this work is pure signalling, there is no dataplane
interaction.

I think it should be possible, to adapt the configuration. For
instance, for a VPN network route,
to know which VRF it uses, and consequently, which RT set.

Before going further, can I ask you if we share the same point of view
about this patchwork issue ?
Do you see other points to discuss ?

Best Regards,

Philippe

> Per BGP LxVPNs, we really should distinguish between VRFs and (vpn)
> route distribution.
>
> WRT VRFs:
>
> The contents of a VRF imported from BGP is determined by one or more
> (import) RTs. RDs are ignored at this point.
>
> An outgoing VPN route is exported to BGP with one or more (export) RTs.
> One configured RD is typically used on outgoing routes exported from a
> VRF (note not VPN) , but multiple routes (identified by different RDs)
> may exist across a single VPN (as identified by an RT set).
>
> WRT Route distribution:
>
> Ignoring RT/community filtering, which currently isn't in the code, BGP
> route distribution basically ignores RTs and uses standard route
> selection based on NRLI route which includes the RD+prefix. This means
> that different RDs can not only be used to segregate prefixes that exist
> within a VPN (and are identified with disjoint sets of RTs) they can
> also be use to support multi-path routes within a VPN (and are
> identified with same/overlapping sets of RTs). BTW RRs only care about
> this part.
>
> So keying a VPN/VRF off an RD just seems wrong, particularly for the
> import case where RD is ignored.
>
> Lou
>
> On 10/19/2016 3:59 AM, Philippe Guibert wrote:
>> On Tue, Oct 18, 2016 at 3:56 PM, Lou Berger <lberger@labn.net> wrote:
>>
>> Hello Lou,
>>
>> Please read below my comments.
>> Consecutive to your feedback, I think there are some improvements to bring,
>> mainly about configuration and structure naming.
>>
>>> It looks like RD is your key to a VRF, is this right?
>>> This doesn't match the semantics of BGP VPNs, where RDs are independent
>>> of VRF. (RT set is really the critical thing.)
>> Most of the modifications have been done around what is called the
>> "VRF structure".
>>
>> The RD is mapped to that "VRF structure", but the RT also. This is a
>> one-to-one mapping.
>> That "VRF structure" has a RIB table where RT imports are processed.
>>
>> I mean, on the design point of view, I don't make a difference between
>> a RD and a RT.
>> I just have to ensure that the incoming structure is available to
>> import appropriate entries.
>> in order to import a RT entry, I have to create a RT mapped to an
>> other "VRF structure".
>>
>> If the RT is not mapped to that "VRF structure", then the RIB
>> associated to that RT is not present.
>> Then the import in the RIB RT will not be possible.
>>
>> To illustrate, a quick example shows that routerA sends a NLRI entry to routerB.
>>
>> routerA> rd 200:111 import 100:111 export 100:111 300:111
>> routerA> network 10.10.10.0/24 rd 200:111
>> routerB> rd 100:111 import 100:111 export 100:111
>>
>> RouterB will import NLRI entry to RT 100:111
>> This is possible because RouterB has the line rd100:111 ... created.
>>
>> RouterB will not import NLRI entry to RT 300:111, since there is no
>> underlying structure.
>>
>> About "VRF structure", My intention is not to interfere about current
>> VRF implementation in Quagga.
>> From the configuration point of view, it is easy to find in literature
>> cisco configuration where VRF
>> and RD configuration maps together.
>> Could you be more specific about the reason to dissociate RD from VRF ?
>>
>> One modification improvement would consist in :
>> - That "VRF structure" could be renamed to "RT/RD structure"
>> - some show commands would be impacted. Instead of dumping VRF RIB
>> table, one would dump RT/RD RIB table
>> - the commit logs would be reworked
>>
>>> The main implication of
>>> this is that multipath/ECMP isn't (at least easily) supported.
>>> Also,
>>> best path selection on import routes will be wrong if keyed based on RD
>> Multipath feature impacts both global RIB, and RIB per RT.
>>
>> As before, let me illustrate this with a 3 router setup topology.
>> router A) and router B) send 2 NLRI ECMP entries to router C)
>>
>> routerA> rd 200:111 import 100:111 export 100:111
>> routerA> network 10.10.10.0/24 rd 200:111 <nexthop_routerA>
>>
>> routerB> rd 200:111 import 100:111 export 100:111
>> routerB> network 10.10.10.0/24 rd 200:111 <nexthop_routerB>
>>
>> routerC> rd 100:111 import 100:111 export 100:111
>>
>> When receiving a NLRI entry from routerB), and routerA), bgp_update()
>> will append the entry in the global RIB, according to RD field.
>>
>> routerC> show bgp ipv4 vpn
>> Route Distinguisher : 200:111
>> *> 10.10.10.0/24 <nexthop_routerA>
>> => 10.10.10.0/24 <nexthop_routerB>
>>
>> Then, the import processing is storing the same 2 entries in RT RIB.
>> routerC> show ip bgp rd 100:111
>> Route Distinguisher : 100:111
>> *> 10.10.10.0/24 <nexthop_routerA>
>> => 10.10.10.0/24 <nexthop_routerB>
>>
>> By playing with configuration, it is possible to have multipath
>> entries in the global RIB, but not in the RD RIB.
>>
>>> and I'm not sure what's being done on route reflectors.
>> There may be some missing elements on implementation.
>> Only the global RIB entries injected by remote peer would be
>> transmitted, including the export RT information originated by routerA
>> and routerB.
>>
>>> I really think that BGP VRFs cannot / must not be keyed based on RDs.
>>> If this is just the config interface, then changing this should be
>>> pretty straight forward.
>> RT RIBS are keyed based on RTs
>> global RIBS entries are keyed based on RDs.
>> About config interface, It would be possible to change configuration:
>> instead of "vrf rd", one could have "rd <>".
>>
>>> PS I think an update to bgpd.texi is needed for this patch
>> of course, this is something that can be done.
>>
>> Best Regards,
>>
>> Philippe
>>
>>> On 10/11/2016 4:17 AM, Philippe Guibert wrote:
>>>> This commit introduces the BGP VRF configuration, and BGP VRF RIB
>>>> table.
>>>> It includes the ability for a BGP to configure its own route
>>>> distinguisher ( aka VRF). New vty commands introduced:
>>>>
>>>> (config-router)# vrf rd <RD>
>>>>
>>>> This structure permits configuring import and export route targets,
>>>> which is defined by RFC4360.
>>>> (config-router)# vrf rd <RD> exports <RT values>
>>>> (config-router)# vrf rd <RD> imports <RT values>
>>>>
>>>> It brings some improvements.
>>>> - for a BGP speaker when emitting BGP updates, the exported route
>>>> targets will be mapped to BGP extended communities associated with
>>>> the BGP update for the defined Route distinguisher.
>>>> This commit does not enhance the support for emitting those BGP
>>>> extended communities, but provides the mecanism.
>>>> - for a BGP speaker when receiving BGP updaets. Its import route
>>>> target will be looked up, in order to match NLRI route distinguisher.
>>>> Then, if matching, the entry would be exported to a RIB per VRF table.
>>>>
>>>> As mentioned before, the commit also introduces a BGP VRF RIB table per
>>>> Route distinguisher configured. This table aims at receiving BGP NLRI
>>>> entries, with matching import and export route targets.
>>>> This commit does not take into account the fullfill of this table,
>>>> but creates it.
>>>>
>>>> Signed-off-by: David Lamparter <equinox@opensourcerouting.org>
>>>> Signed-off-by: Philippe Guibert <philippe.guibert@6wind.com>
>>>> ---
>>>> bgpd/bgp_route.c | 193 +++++++++++++++++++++++++++++++++++++++++++++++++++--
>>>> bgpd/bgp_route.h | 4 ++
>>>> bgpd/bgp_table.h | 3 +
>>>> bgpd/bgp_vty.c | 177 +++++++++++++++++++++++++++++++++++++++++++++++++
>>>> bgpd/bgpd.c | 199 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-
>>>> bgpd/bgpd.h | 58 +++++++++++++---
>>>> lib/memtypes.c | 2 +
>>>> 7 files changed, 622 insertions(+), 14 deletions(-)
>>>>
>>>> diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c
>>>> index 4cb6c141bcdc..abad79f5c9d4 100644
>>>> --- a/bgpd/bgp_route.c
>>>> +++ b/bgpd/bgp_route.c
>>>> @@ -34,6 +34,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
>>>> #include "plist.h"
>>>> #include "thread.h"
>>>> #include "workqueue.h"
>>>> +#include "hash.h"
>>>>
>>>> #include "bgpd/bgpd.h"
>>>> #include "bgpd/bgp_table.h"
>>>> @@ -61,6 +62,12 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
>>>> extern const char *bgp_origin_str[];
>>>> extern const char *bgp_origin_long_str[];
>>>>
>>>> +static void
>>>> +bgp_static_withdraw_safi (struct bgp *bgp, struct prefix *p, afi_t afi,
>>>> + safi_t safi, struct prefix_rd *prd, u_char *tag);
>>>> +static void
>>>> +bgp_static_free (struct bgp_static *bgp_static);
>>>> +
>>>> static struct bgp_node *
>>>> bgp_afi_node_get (struct bgp_table *table, afi_t afi, safi_t safi, struct prefix *p,
>>>> struct prefix_rd *prd)
>>>> @@ -77,7 +84,11 @@ bgp_afi_node_get (struct bgp_table *table, afi_t afi, safi_t safi, struct prefix
>>>> prn = bgp_node_get (table, (struct prefix *) prd);
>>>>
>>>> if (prn->info == NULL)
>>>> - prn->info = bgp_table_init (afi, safi);
>>>> + {
>>>> + struct bgp_table *newtab = bgp_table_init (afi, safi);
>>>> + newtab->prd = *prd;
>>>> + prn->info = newtab;
>>>> + }
>>>> else
>>>> bgp_unlock_node (prn);
>>>> table = prn->info;
>>>> @@ -1505,12 +1516,86 @@ bgp_process_announce_selected (struct peer *peer, struct bgp_info *selected,
>>>> else
>>>> bgp_adj_out_unset (rn, peer, p, afi, safi);
>>>> break;
>>>> + case BGP_TABLE_VRF:
>>>> + /* never called */
>>>> + assert (0);
>>>> }
>>>>
>>>> bgp_attr_flush (&attr);
>>>> return 0;
>>>> }
>>>>
>>>> +void bgp_vrf_clean_tables (struct bgp_vrf *vrf)
>>>> +{
>>>> + afi_t afi;
>>>> + for (afi = AFI_IP; afi < AFI_MAX; afi++)
>>>> + {
>>>> + struct bgp_info *ri, *ri_next;
>>>> + struct bgp_node *rn;
>>>> +
>>>> + for (rn = bgp_table_top (vrf->rib[afi]); rn; rn = bgp_route_next (rn))
>>>> + for (ri = rn->info; ri; ri = ri_next)
>>>> + {
>>>> + ri_next = ri->next;
>>>> + bgp_info_reap (rn, ri);
>>>> + }
>>>> + bgp_table_finish (&vrf->rib[afi]);
>>>> +
>>>> + for (rn = bgp_table_top (vrf->route[afi]); rn; rn = bgp_route_next (rn))
>>>> + if (rn->info)
>>>> + {
>>>> + struct bgp_static *bs = rn->info;
>>>> + bgp_static_withdraw_safi (vrf->bgp, &rn->p, afi, SAFI_MPLS_VPN,
>>>> + &vrf->outbound_rd, NULL);
>>>> + bgp_static_free (bs);
>>>> + rn->info = NULL;
>>>> + bgp_unlock_node (rn);
>>>> + }
>>>> + bgp_table_finish (&vrf->route[afi]);
>>>> + }
>>>> +}
>>>> +
>>>> +void
>>>> +bgp_vrf_apply_new_imports (struct bgp_vrf *vrf, afi_t afi)
>>>> +{
>>>> + struct bgp_node *rd_rn, *rn;
>>>> + struct bgp_info *sel;
>>>> + struct bgp_table *table;
>>>> + struct ecommunity *ecom;
>>>> + size_t i, j;
>>>> + bool found;
>>>> +
>>>> + if (!vrf->rt_import || vrf->rt_import->size == 0)
>>>> + return;
>>>> +
>>>> + for (rd_rn = bgp_table_top (vrf->bgp->rib[afi][SAFI_MPLS_VPN]); rd_rn;
>>>> + rd_rn = bgp_route_next (rd_rn))
>>>> + if (rd_rn->info != NULL)
>>>> + {
>>>> + table = rd_rn->info;
>>>> +
>>>> + for (rn = bgp_table_top (table); rn; rn = bgp_route_next (rn))
>>>> + {
>>>> + for (sel = rn->info; sel; sel = sel->next)
>>>> + if (CHECK_FLAG (sel->flags, BGP_INFO_SELECTED))
>>>> + break;
>>>> + if (!sel || !sel->attr || !sel->attr->extra)
>>>> + continue;
>>>> + ecom = sel->attr->extra->ecommunity;
>>>> + if (!ecom)
>>>> + continue;
>>>> +
>>>> + found = false;
>>>> + for (i = 0; i < (size_t)ecom->size && !found; i++)
>>>> + for (j = 0; j < (size_t)vrf->rt_import->size && !found; j++)
>>>> + if (!memcmp(ecom->val + i * 8, vrf->rt_import->val + j * 8, 8))
>>>> + found = true;
>>>> + if (!found)
>>>> + continue;
>>>> + }
>>>> + }
>>>> +}
>>>> +
>>>> struct bgp_process_queue
>>>> {
>>>> struct bgp *bgp;
>>>> @@ -1746,6 +1831,9 @@ bgp_process (struct bgp *bgp, struct bgp_node *rn, afi_t afi, safi_t safi)
>>>> case BGP_TABLE_RSCLIENT:
>>>> work_queue_add (bm->process_rsclient_queue, pqnode);
>>>> break;
>>>> + case BGP_TABLE_VRF:
>>>> + /* never called */
>>>> + assert (0);
>>>> }
>>>>
>>>> SET_FLAG (rn->flags, BGP_NODE_PROCESS_SCHEDULED);
>>>> @@ -6291,6 +6379,9 @@ route_vty_out_detail (struct vty *vty, struct bgp *bgp, struct prefix *p,
>>>>
>>>> attr = binfo->attr;
>>>>
>>>> + if (safi == SAFI_MPLS_LABELED_VPN)
>>>> + safi = SAFI_MPLS_VPN;
>>>> +
>>>> if (attr)
>>>> {
>>>> /* Line1 display AS-path, Aggregator */
>>>> @@ -6510,6 +6601,7 @@ bgp_show_table (struct vty *vty, struct bgp_table *table, struct in_addr *router
>>>> int display;
>>>> unsigned long output_count;
>>>> unsigned long total_count;
>>>> + safi_t safi = table->type == BGP_TABLE_VRF ? SAFI_MPLS_VPN : SAFI_UNICAST;
>>>>
>>>> /* This is first entry point, so reset total line. */
>>>> output_count = 0;
>>>> @@ -6694,7 +6786,7 @@ bgp_show_table (struct vty *vty, struct bgp_table *table, struct in_addr *router
>>>>
>>>> if (type == bgp_show_type_dampend_paths
>>>> || type == bgp_show_type_damp_neighbor)
>>>> - damp_route_vty_out (vty, &rn->p, ri, display, SAFI_UNICAST);
>>>> + damp_route_vty_out (vty, &rn->p, ri, display, safi);
>>>> else if (type == bgp_show_type_flap_statistics
>>>> || type == bgp_show_type_flap_address
>>>> || type == bgp_show_type_flap_prefix
>>>> @@ -6705,9 +6797,9 @@ bgp_show_table (struct vty *vty, struct bgp_table *table, struct in_addr *router
>>>> || type == bgp_show_type_flap_prefix_longer
>>>> || type == bgp_show_type_flap_route_map
>>>> || type == bgp_show_type_flap_neighbor)
>>>> - flap_route_vty_out (vty, &rn->p, ri, display, SAFI_UNICAST);
>>>> + flap_route_vty_out (vty, &rn->p, ri, display, safi);
>>>> else
>>>> - route_vty_out (vty, &rn->p, ri, display, SAFI_UNICAST);
>>>> + route_vty_out (vty, &rn->p, ri, display, safi);
>>>> display++;
>>>> }
>>>> if (display)
>>>> @@ -6749,6 +6841,35 @@ bgp_show (struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi,
>>>> return bgp_show_table (vty, table, &bgp->router_id, type, output_arg);
>>>> }
>>>>
>>>> +static int
>>>> +bgp_show_vrf (struct vty *vty, const char *vrf_name, afi_t afi,
>>>> + enum bgp_show_type type, void *output_arg)
>>>> +{
>>>> + struct bgp *bgp = bgp_get_default();
>>>> + struct bgp_vrf *vrf;
>>>> + struct prefix_rd prd;
>>>> +
>>>> + if (! bgp)
>>>> + {
>>>> + vty_out (vty, "%% No default BGP instance%s", VTY_NEWLINE);
>>>> + return CMD_WARNING;
>>>> + }
>>>> + if (! str2prefix_rd (vrf_name, &prd))
>>>> + {
>>>> + vty_out (vty, "%% Invalid RD '%s'%s", vrf_name, VTY_NEWLINE);
>>>> + return CMD_WARNING;
>>>> + }
>>>> +
>>>> + vrf = bgp_vrf_lookup (bgp, &prd);
>>>> + if (! vrf)
>>>> + {
>>>> + vty_out (vty, "%% No VRF with RD '%s'%s", vrf_name, VTY_NEWLINE);
>>>> + return CMD_WARNING;
>>>> + }
>>>> +
>>>> + return bgp_show_table (vty, vrf->rib[afi], &bgp->router_id, type, output_arg);
>>>> +}
>>>> +
>>>> /* Header of detailed BGP route information */
>>>> static void
>>>> route_vty_out_detail_header (struct vty *vty, struct bgp *bgp,
>>>> @@ -6816,6 +6937,12 @@ route_vty_out_detail_header (struct vty *vty, struct bgp *bgp,
>>>> vty_out (vty, ", Advertisements suppressed by an aggregate.");
>>>> vty_out (vty, ")%s", VTY_NEWLINE);
>>>>
>>>> + if (safi == SAFI_MPLS_LABELED_VPN)
>>>> + {
>>>> + vty_out (vty, "%s", VTY_NEWLINE);
>>>> + return;
>>>> + }
>>>> +
>>>> /* advertised peer */
>>>> for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer))
>>>> {
>>>> @@ -6939,6 +7066,36 @@ bgp_show_route_in_table (struct vty *vty, struct bgp *bgp,
>>>> return CMD_SUCCESS;
>>>> }
>>>>
>>>> +static int
>>>> +bgp_show_vrf_route (struct vty *vty, const char *vrf_name, const char *ip_str,
>>>> + afi_t afi, int prefix_check)
>>>> +{
>>>> + struct bgp *bgp = bgp_get_default();
>>>> + struct bgp_vrf *vrf;
>>>> + struct prefix_rd prd;
>>>> +
>>>> + if (! bgp)
>>>> + {
>>>> + vty_out (vty, "%% No default BGP instance%s", VTY_NEWLINE);
>>>> + return CMD_WARNING;
>>>> + }
>>>> + if (! str2prefix_rd (vrf_name, &prd))
>>>> + {
>>>> + vty_out (vty, "%% Invalid RD '%s'%s", vrf_name, VTY_NEWLINE);
>>>> + return CMD_WARNING;
>>>> + }
>>>> +
>>>> + vrf = bgp_vrf_lookup (bgp, &prd);
>>>> + if (! vrf)
>>>> + {
>>>> + vty_out (vty, "%% No VRF with RD '%s'%s", vrf_name, VTY_NEWLINE);
>>>> + return CMD_WARNING;
>>>> + }
>>>> +
>>>> + return bgp_show_route_in_table (vty, bgp, vrf->rib[afi], ip_str,
>>>> + afi, SAFI_MPLS_LABELED_VPN, NULL, prefix_check, BGP_PATH_ALL);
>>>> +}
>>>> +
>>>> /* Display specified route of Main RIB */
>>>> static int
>>>> bgp_show_route (struct vty *vty, const char *view_name, const char *ip_str,
>>>> @@ -6982,6 +7139,16 @@ DEFUN (show_ip_bgp,
>>>> return bgp_show (vty, NULL, AFI_IP, SAFI_UNICAST, bgp_show_type_normal, NULL);
>>>> }
>>>>
>>>> +DEFUN (show_ip_bgp_vrf,
>>>> + show_ip_bgp_vrf_cmd,
>>>> + "show ip bgp vrf WORD",
>>>> + SHOW_STR
>>>> + IP_STR
>>>> + BGP_STR)
>>>> +{
>>>> + return bgp_show_vrf (vty, argv[0], AFI_IP, bgp_show_type_normal, NULL);
>>>> +}
>>>> +
>>>> DEFUN (show_ip_bgp_ipv4,
>>>> show_ip_bgp_ipv4_cmd,
>>>> "show ip bgp ipv4 (unicast|multicast)",
>>>> @@ -7050,6 +7217,19 @@ DEFUN (show_bgp_ipv4_safi_route_pathtype,
>>>> return bgp_show_route (vty, NULL, argv[1], AFI_IP, SAFI_UNICAST, NULL, 0, BGP_PATH_MULTIPATH);
>>>> }
>>>>
>>>> +DEFUN (show_ip_bgp_vrf_route,
>>>> + show_ip_bgp_vrf_route_cmd,
>>>> + "show ip bgp vrf WORD (ipv4|ipv6) (A.B.C.D|X:X::X:X)",
>>>> + SHOW_STR
>>>> + IP_STR
>>>> + BGP_STR
>>>> + "VRF\n"
>>>> + "Route Distinguisher\n")
>>>> +{
>>>> + afi_t afi = (strncmp (argv[1], "ipv6", 4) == 0) ? AFI_IP6 : AFI_IP;
>>>> + return bgp_show_vrf_route (vty, argv[0], argv[2], afi, 0);
>>>> +}
>>>> +
>>>> DEFUN (show_ip_bgp_ipv4_route,
>>>> show_ip_bgp_ipv4_route_cmd,
>>>> "show ip bgp ipv4 (unicast|multicast) A.B.C.D",
>>>> @@ -16702,10 +16882,12 @@ bgp_route_init (void)
>>>>
>>>> /* old style commands */
>>>> install_element (VIEW_NODE, &show_ip_bgp_cmd);
>>>> + install_element (VIEW_NODE, &show_ip_bgp_vrf_cmd);
>>>> install_element (VIEW_NODE, &show_ip_bgp_ipv4_cmd);
>>>> install_element (VIEW_NODE, &show_ip_bgp_route_cmd);
>>>> install_element (VIEW_NODE, &show_ip_bgp_route_pathtype_cmd);
>>>> install_element (VIEW_NODE, &show_bgp_ipv4_safi_route_pathtype_cmd);
>>>> + install_element (VIEW_NODE, &show_ip_bgp_vrf_route_cmd);
>>>> install_element (VIEW_NODE, &show_ip_bgp_ipv4_route_cmd);
>>>> install_element (VIEW_NODE, &show_ip_bgp_vpnv4_all_route_cmd);
>>>> install_element (VIEW_NODE, &show_ip_bgp_vpnv4_rd_route_cmd);
>>>> @@ -16797,6 +16979,7 @@ bgp_route_init (void)
>>>> install_element (RESTRICTED_NODE, &show_ip_bgp_route_cmd);
>>>> install_element (RESTRICTED_NODE, &show_ip_bgp_route_pathtype_cmd);
>>>> install_element (RESTRICTED_NODE, &show_bgp_ipv4_safi_route_pathtype_cmd);
>>>> + install_element (RESTRICTED_NODE, &show_ip_bgp_vrf_route_cmd);
>>>> install_element (RESTRICTED_NODE, &show_ip_bgp_ipv4_route_cmd);
>>>> install_element (RESTRICTED_NODE, &show_ip_bgp_vpnv4_rd_route_cmd);
>>>> install_element (RESTRICTED_NODE, &show_ip_bgp_prefix_cmd);
>>>> @@ -16832,7 +17015,7 @@ bgp_route_init (void)
>>>> install_element (VIEW_NODE, &show_ip_bgp_neighbor_prefix_counts_cmd);
>>>> install_element (VIEW_NODE, &show_ip_bgp_ipv4_neighbor_prefix_counts_cmd);
>>>> install_element (VIEW_NODE, &show_ip_bgp_vpnv4_neighbor_prefix_counts_cmd);
>>>> -
>>>> + install_element (VIEW_NODE, &show_ip_bgp_vrf_cmd);
>>>> install_element (VIEW_NODE, &show_bgp_cmd);
>>>> install_element (VIEW_NODE, &show_bgp_ipv6_cmd);
>>>> install_element (VIEW_NODE, &show_bgp_route_cmd);
>>>> diff --git a/bgpd/bgp_route.h b/bgpd/bgp_route.h
>>>> index 332714c4f845..25a42e87bd94 100644
>>>> --- a/bgpd/bgp_route.h
>>>> +++ b/bgpd/bgp_route.h
>>>> @@ -43,6 +43,8 @@ struct bgp_info_extra
>>>>
>>>> /* MPLS label. */
>>>> u_char tag[3];
>>>> +
>>>> + struct prefix_rd vrf_rd;
>>>> };
>>>>
>>>> struct bgp_info
>>>> @@ -270,4 +272,6 @@ extern void route_vty_out_tmp (struct vty *, struct prefix *, struct attr *, saf
>>>> extern void bgp_peer_clear_node_queue_drain_immediate (struct peer *peer);
>>>> extern void bgp_process_queues_drain_immediate (void);
>>>>
>>>> +extern void bgp_vrf_apply_new_imports (struct bgp_vrf *vrf, afi_t afi);
>>>> +
>>>> #endif /* _QUAGGA_BGP_ROUTE_H */
>>>> diff --git a/bgpd/bgp_table.h b/bgpd/bgp_table.h
>>>> index 8e963aeeeb84..13d29469a058 100644
>>>> --- a/bgpd/bgp_table.h
>>>> +++ b/bgpd/bgp_table.h
>>>> @@ -27,6 +27,7 @@ typedef enum
>>>> {
>>>> BGP_TABLE_MAIN,
>>>> BGP_TABLE_RSCLIENT,
>>>> + BGP_TABLE_VRF,
>>>> } bgp_table_t;
>>>>
>>>> struct bgp_table
>>>> @@ -43,6 +44,8 @@ struct bgp_table
>>>> struct peer *owner;
>>>>
>>>> struct route_table *route_table;
>>>> +
>>>> + struct prefix_rd prd;
>>>> };
>>>>
>>>> struct bgp_node
>>>> diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c
>>>> index 7af4e81a87b1..63a7b5bfdcf6 100644
>>>> --- a/bgpd/bgp_vty.c
>>>> +++ b/bgpd/bgp_vty.c
>>>> @@ -9891,6 +9891,178 @@ bgp_config_write_redistribute (struct vty *vty, struct bgp *bgp, afi_t afi,
>>>> return *write;
>>>> }
>>>>
>>>> +DEFUN (bgp_vrf,
>>>> + bgp_vrf_cmd,
>>>> + "vrf rd WORD",
>>>> + "BGP VPN VRF\n"
>>>> + "Route Distinguisher\n"
>>>> + "Route Distinguisher\n"
>>>> +)
>>>> +{
>>>> + struct bgp *bgp = vty->index;
>>>> + struct bgp_vrf *vrf;
>>>> + struct prefix_rd prd;
>>>> +
>>>> + if (! str2prefix_rd (argv[0], &prd))
>>>> + {
>>>> + vty_out (vty, "%% Invalid RD '%s'%s", argv[0], VTY_NEWLINE);
>>>> + return CMD_WARNING;
>>>> + }
>>>> +
>>>> + vrf = bgp_vrf_lookup (bgp, &prd);
>>>> + if (vrf)
>>>> + {
>>>> + vty_out (vty, "%% VRF with RD '%s' already exists%s", argv[0], VTY_NEWLINE);
>>>> + return CMD_WARNING;
>>>> + }
>>>> +
>>>> + bgp_vrf_create (bgp, &prd);
>>>> + return CMD_SUCCESS;
>>>> +}
>>>> +
>>>> +DEFUN (bgp_vrf_exports,
>>>> + bgp_vrf_exports_cmd,
>>>> + "vrf rd WORD exports .LINE",
>>>> + "BGP VPN VRF\n"
>>>> + "Route Distinguisher\n"
>>>> + "Route Distinguisher\n"
>>>> + "Export RT values\n"
>>>> + "Export RT values\n"
>>>> +)
>>>> +{
>>>> + struct bgp *bgp = vty->index;
>>>> + struct bgp_vrf *vrf;
>>>> + struct prefix_rd prd;
>>>> + struct ecommunity *ecom = NULL;
>>>> + int fail = 0, i;
>>>> + char *rts = NULL, *rts_ptr;
>>>> +
>>>> + if (! str2prefix_rd (argv[0], &prd))
>>>> + {
>>>> + vty_out (vty, "%% Invalid RD '%s'%s", argv[0], VTY_NEWLINE);
>>>> + fail++;
>>>> + }
>>>> + /* forge export list */
>>>> + i = 1;
>>>> + rts = XCALLOC(MTYPE_TMP,2048);
>>>> + rts_ptr = rts;
>>>> + while(i < argc)
>>>> + {
>>>> + rts_ptr += sprintf(rts_ptr, "rt %s ",argv[i]);
>>>> + i++;
>>>> + }
>>>> + /* convert list of ecoms string into ecom struct */
>>>> + ecom = ecommunity_str2com (rts, ECOMMUNITY_ROUTE_TARGET, 1);
>>>> + if (! ecom)
>>>> + {
>>>> + vty_out (vty, "%% Invalid RT '%s'%s", argv[1], VTY_NEWLINE);
>>>> + fail++;
>>>> + }
>>>> + if (rts)
>>>> + XFREE (MTYPE_TMP, rts);
>>>> + if (fail)
>>>> + return CMD_WARNING;
>>>> +
>>>> + vrf = bgp_vrf_lookup (bgp, &prd);
>>>> + if (! vrf)
>>>> + {
>>>> + ecommunity_free (&ecom);
>>>> + vty_out (vty, "%% No VRF with RD '%s'%s", argv[0], VTY_NEWLINE);
>>>> + return CMD_WARNING;
>>>> + }
>>>> +
>>>> + ecom = ecommunity_intern (ecom);
>>>> + bgp_vrf_rt_export_set (vrf, ecom);
>>>> + ecommunity_unintern (&ecom);
>>>> + return CMD_SUCCESS;
>>>> +}
>>>> +
>>>> +DEFUN (bgp_vrf_imports,
>>>> + bgp_vrf_imports_cmd,
>>>> + "vrf rd WORD imports .LINE",
>>>> + "BGP VPN VRF\n"
>>>> + "Route Distinguisher\n"
>>>> + "Route Distinguisher\n"
>>>> + "Import RT values\n"
>>>> + "Import RT values\n"
>>>> +)
>>>> +{
>>>> + struct bgp *bgp = vty->index;
>>>> + struct bgp_vrf *vrf;
>>>> + struct prefix_rd prd;
>>>> + struct ecommunity *ecom = NULL;
>>>> + int fail = 0, i;
>>>> + char *rts = NULL, *rts_ptr;
>>>> +
>>>> + if (! str2prefix_rd (argv[0], &prd))
>>>> + {
>>>> + vty_out (vty, "%% Invalid RD '%s'%s", argv[0], VTY_NEWLINE);
>>>> + fail++;
>>>> + }
>>>> + /* forge export list */
>>>> + i = 1;
>>>> + rts = XCALLOC(MTYPE_TMP,2048);
>>>> + rts_ptr = rts;
>>>> + while(i < argc)
>>>> + {
>>>> + rts_ptr += sprintf(rts_ptr, "rt %s ",argv[i]);
>>>> + i++;
>>>> + }
>>>> + /* convert list of ecoms string into ecom struct */
>>>> + ecom = ecommunity_str2com (rts, ECOMMUNITY_ROUTE_TARGET, 1);
>>>> + if (! ecom)
>>>> + {
>>>> + vty_out (vty, "%% Invalid RT '%s'%s", argv[1], VTY_NEWLINE);
>>>> + fail++;
>>>> + }
>>>> + if (rts)
>>>> + XFREE (MTYPE_TMP, rts);
>>>> + if (fail)
>>>> + return CMD_WARNING;
>>>> +
>>>> + vrf = bgp_vrf_lookup (bgp, &prd);
>>>> + if (! vrf)
>>>> + {
>>>> + ecommunity_free (&ecom);
>>>> + vty_out (vty, "%% No VRF with RD '%s'%s", argv[0], VTY_NEWLINE);
>>>> + return CMD_WARNING;
>>>> + }
>>>> +
>>>> + ecom = ecommunity_intern (ecom);
>>>> + bgp_vrf_rt_import_set (vrf, ecom);
>>>> + ecommunity_unintern (&ecom);
>>>> + return CMD_SUCCESS;
>>>> +}
>>>> +
>>>> +DEFUN (no_bgp_vrf,
>>>> + no_bgp_vrf_cmd,
>>>> + "no vrf rd WORD",
>>>> + NO_STR
>>>> + "BGP VPN VRF\n"
>>>> + "Route Distinguisher\n"
>>>> + "Route Distinguisher\n"
>>>> +)
>>>> +{
>>>> + struct bgp *bgp = vty->index;
>>>> + struct bgp_vrf *vrf;
>>>> + struct prefix_rd prd;
>>>> +
>>>> + if (! str2prefix_rd (argv[0], &prd))
>>>> + {
>>>> + vty_out (vty, "%% Invalid RD '%s'%s", argv[0], VTY_NEWLINE);
>>>> + return CMD_WARNING;
>>>> + }
>>>> +
>>>> + vrf = bgp_vrf_lookup (bgp, &prd);
>>>> + if (! vrf)
>>>> + {
>>>> + vty_out (vty, "%% No VRF with RD '%s'%s", argv[0], VTY_NEWLINE);
>>>> + return CMD_WARNING;
>>>> + }
>>>> + bgp_vrf_delete (vrf);
>>>> + return CMD_SUCCESS;
>>>> +}
>>>> +
>>>> /* BGP node structure. */
>>>> static struct cmd_node bgp_node =
>>>> {
>>>> @@ -9982,6 +10154,11 @@ bgp_vty_init (void)
>>>> install_default (BGP_ENCAP_NODE);
>>>> install_default (BGP_ENCAPV6_NODE);
>>>>
>>>> + install_element (BGP_NODE, &bgp_vrf_cmd);
>>>> + install_element (BGP_NODE, &bgp_vrf_exports_cmd);
>>>> + install_element (BGP_NODE, &bgp_vrf_imports_cmd);
>>>> + install_element (BGP_NODE, &no_bgp_vrf_cmd);
>>>> +
>>>> /* "bgp multiple-instance" commands. */
>>>> install_element (CONFIG_NODE, &bgp_multiple_instance_cmd);
>>>> install_element (CONFIG_NODE, &no_bgp_multiple_instance_cmd);
>>>> diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c
>>>> index 018a59941101..5725730d9454 100644
>>>> --- a/bgpd/bgpd.c
>>>> +++ b/bgpd/bgpd.c
>>>> @@ -35,6 +35,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
>>>> #include "log.h"
>>>> #include "plist.h"
>>>> #include "linklist.h"
>>>> +#include "hash.h"
>>>> #include "workqueue.h"
>>>> #include "table.h"
>>>>
>>>> @@ -2057,6 +2058,164 @@ bgp_startup_timer_expire (struct thread *thread)
>>>> return 0;
>>>> }
>>>>
>>>> +/* VRFs */
>>>> +
>>>> +static unsigned int bgp_rt_hash_key (void *arg)
>>>> +{
>>>> + const struct bgp_rt_sub *rt_sub = arg;
>>>> + uint32_t *rtval = (uint32_t *)(char *)&rt_sub->rt;
>>>> + return rtval[0] ^ rtval[1];
>>>> +}
>>>> +
>>>> +static int bgp_rt_hash_cmp (const void *a, const void *b)
>>>> +{
>>>> + const struct bgp_rt_sub *aa = a, *bb = b;
>>>> + return !memcmp(&aa->rt, &bb->rt, sizeof(aa->rt));
>>>> +}
>>>> +
>>>> +static void *
>>>> +bgp_rt_hash_alloc (void *dummy)
>>>> +{
>>>> + struct bgp_rt_sub *ddummy = dummy, *rt_sub;
>>>> + rt_sub = XMALLOC (MTYPE_BGP_RT_SUB, sizeof (*rt_sub));
>>>> + rt_sub->rt = ddummy->rt;
>>>> + rt_sub->vrfs = list_new();
>>>> + return rt_sub;
>>>> +}
>>>> +
>>>> +static void
>>>> +bgp_rt_hash_dealloc (struct bgp_rt_sub *rt_sub)
>>>> +{
>>>> + list_delete (rt_sub->vrfs);
>>>> + XFREE (MTYPE_BGP_RT_SUB, rt_sub);
>>>> +}
>>>> +
>>>> +struct bgp_vrf *
>>>> +bgp_vrf_lookup (struct bgp *bgp, struct prefix_rd *outbound_rd)
>>>> +{
>>>> + struct listnode *node;
>>>> + struct bgp_vrf *vrf;
>>>> +
>>>> + for (ALL_LIST_ELEMENTS_RO(bgp->vrfs, node, vrf))
>>>> + if (!memcmp (outbound_rd->val, vrf->outbound_rd.val, 8))
>>>> + return vrf;
>>>> + return NULL;
>>>> +}
>>>> +
>>>> +struct bgp_vrf *
>>>> +bgp_vrf_create (struct bgp *bgp, struct prefix_rd *outbound_rd)
>>>> +{
>>>> + struct bgp_vrf *vrf;
>>>> + afi_t afi;
>>>> +
>>>> + if ( (vrf = XCALLOC (MTYPE_BGP_VRF, sizeof (struct bgp_vrf))) == NULL)
>>>> + return NULL;
>>>> +
>>>> + vrf->bgp = bgp;
>>>> + vrf->outbound_rd = *outbound_rd;
>>>> +
>>>> + for (afi = AFI_IP; afi < AFI_MAX; afi++)
>>>> + {
>>>> + vrf->route[afi] = bgp_table_init (afi, SAFI_UNICAST);
>>>> + vrf->route[afi]->type = BGP_TABLE_VRF;
>>>> + vrf->rib[afi] = bgp_table_init (afi, SAFI_UNICAST);
>>>> + vrf->rib[afi]->type = BGP_TABLE_VRF;
>>>> + }
>>>> +
>>>> + listnode_add (bgp->vrfs, vrf);
>>>> + return vrf;
>>>> +}
>>>> +
>>>> +static struct ecommunity * ecommunity_reintern (struct ecommunity *ecom)
>>>> +{
>>>> + assert (ecom->refcnt > 0);
>>>> + ecom->refcnt++;
>>>> + return ecom;
>>>> +}
>>>> +
>>>> +void
>>>> +bgp_vrf_rt_export_set (struct bgp_vrf *vrf, struct ecommunity *rt_export)
>>>> +{
>>>> + if (vrf->rt_export)
>>>> + ecommunity_unintern (&vrf->rt_export);
>>>> +
>>>> + vrf->rt_export = ecommunity_reintern (rt_export);
>>>> +}
>>>> +
>>>> +static void
>>>> +bgp_vrf_rt_import_unset (struct bgp_vrf *vrf)
>>>> +{
>>>> + size_t i;
>>>> +
>>>> + if (!vrf->rt_import)
>>>> + return;
>>>> +
>>>> + for (i = 0; i < (size_t)vrf->rt_import->size; i++)
>>>> + {
>>>> + struct bgp_rt_sub dummy, *rt_sub;
>>>> + memcpy (&dummy.rt, vrf->rt_import->val + 8 * i, 8);
>>>> +
>>>> + rt_sub = hash_lookup (vrf->bgp->rt_subscribers, &dummy);
>>>> + assert(rt_sub);
>>>> + listnode_delete (rt_sub->vrfs, vrf);
>>>> + if (list_isempty (rt_sub->vrfs))
>>>> + {
>>>> + hash_release (vrf->bgp->rt_subscribers, rt_sub);
>>>> + bgp_rt_hash_dealloc (rt_sub);
>>>> + }
>>>> + }
>>>> +
>>>> + ecommunity_unintern (&vrf->rt_import);
>>>> +}
>>>> +
>>>> +void
>>>> +bgp_vrf_rt_import_set (struct bgp_vrf *vrf, struct ecommunity *rt_import)
>>>> +{
>>>> + size_t i;
>>>> + afi_t afi;
>>>> +
>>>> + bgp_vrf_rt_import_unset (vrf);
>>>> +
>>>> + vrf->rt_import = ecommunity_reintern (rt_import);
>>>> +
>>>> + for (i = 0; i < (size_t)vrf->rt_import->size; i++)
>>>> + {
>>>> + struct bgp_rt_sub dummy, *rt_sub;
>>>> + memcpy (&dummy.rt, vrf->rt_import->val + 8 * i, 8);
>>>> +
>>>> + rt_sub = hash_get (vrf->bgp->rt_subscribers, &dummy, bgp_rt_hash_alloc);
>>>> + listnode_add (rt_sub->vrfs, vrf);
>>>> + }
>>>> +
>>>> + for (afi = AFI_IP; afi < AFI_MAX; afi++)
>>>> + bgp_vrf_apply_new_imports (vrf, afi);
>>>> +}
>>>> +
>>>> +static void
>>>> +bgp_vrf_delete_int (void *arg)
>>>> +{
>>>> + struct bgp_vrf *vrf = arg;
>>>> + char vrf_rd_str[RD_ADDRSTRLEN];
>>>> +
>>>> + prefix_rd2str(&vrf->outbound_rd, vrf_rd_str, sizeof(vrf_rd_str));
>>>> + zlog_info ("deleting vrf %s", vrf_rd_str);
>>>> +
>>>> + bgp_vrf_clean_tables (vrf);
>>>> +
>>>> + bgp_vrf_rt_import_unset (vrf);
>>>> + if (vrf->rt_export)
>>>> + ecommunity_unintern (&vrf->rt_export);
>>>> +
>>>> + XFREE (MTYPE_BGP_VRF, vrf);
>>>> +}
>>>> +
>>>> +void
>>>> +bgp_vrf_delete (struct bgp_vrf *vrf)
>>>> +{
>>>> + listnode_delete (vrf->bgp->vrfs, vrf);
>>>> + bgp_vrf_delete_int(vrf);
>>>> +}
>>>> +
>>>> /* BGP instance creation by `router bgp' commands. */
>>>> static struct bgp *
>>>> bgp_create (as_t *as, const char *name)
>>>> @@ -2103,6 +2262,10 @@ bgp_create (as_t *as, const char *name)
>>>> if (name)
>>>> bgp->name = strdup (name);
>>>>
>>>> + bgp->vrfs = list_new();
>>>> + bgp->vrfs->del = bgp_vrf_delete_int;
>>>> + bgp->rt_subscribers = hash_create(bgp_rt_hash_key, bgp_rt_hash_cmp);
>>>> +
>>>> THREAD_TIMER_ON (bm->master, bgp->t_startup, bgp_startup_timer_expire,
>>>> bgp, bgp->restart_time);
>>>>
>>>> @@ -2236,7 +2399,13 @@ bgp_delete (struct bgp *bgp)
>>>> BGP_NOTIFY_CEASE_PEER_UNCONFIG);
>>>> }
>>>> }
>>>> -
>>>> + if(bgp->vrfs)
>>>> + list_delete (bgp->vrfs);
>>>> + if(bgp->rt_subscribers)
>>>> + {
>>>> + hash_clean (bgp->rt_subscribers, NULL);
>>>> + hash_free (bgp->rt_subscribers);
>>>> + }
>>>> /* Delete static route. */
>>>> bgp_static_delete (bgp);
>>>>
>>>> @@ -5615,6 +5784,34 @@ bgp_config_write (struct vty *vty)
>>>> bgp_config_write_peer (vty, bgp, peer, AFI_IP, SAFI_UNICAST);
>>>> }
>>>>
>>>> + {
>>>> + struct bgp_vrf *vrf;
>>>> + char rdstr[RD_ADDRSTRLEN];
>>>> + char *str_p, *str2_p;
>>>> + for (ALL_LIST_ELEMENTS_RO(bgp->vrfs, node, vrf))
>>>> + {
>>>> + str_p = prefix_rd2str(&(vrf->outbound_rd), rdstr, RD_ADDRSTRLEN);
>>>> + vty_out(vty, " vrf rd %s%s", str_p == NULL?"<err>":str_p, VTY_NEWLINE);
>>>> + if(vrf->rt_import)
>>>> + {
>>>> + str2_p = ecommunity_ecom2str (vrf->rt_import, ECOMMUNITY_FORMAT_ROUTE_MAP);
>>>> + if(str2_p)
>>>> + {
>>>> + vty_out(vty, " vrf rd %s import %s%s", str_p == NULL?"<err>":str_p, str2_p, VTY_NEWLINE);
>>>> + XFREE (MTYPE_ECOMMUNITY_STR, str2_p);
>>>> + }
>>>> + }
>>>> + if(vrf->rt_export)
>>>> + {
>>>> + str2_p = ecommunity_ecom2str (vrf->rt_export, ECOMMUNITY_FORMAT_ROUTE_MAP);
>>>> + if(str2_p)
>>>> + {
>>>> + vty_out(vty, " vrf rd %s export %s%s", str_p == NULL?"<err>":str_p, str2_p, VTY_NEWLINE);
>>>> + XFREE (MTYPE_ECOMMUNITY_STR, str2_p);
>>>> + }
>>>> + }
>>>> + }
>>>> + }
>>>> /* maximum-paths */
>>>> bgp_config_write_maxpaths (vty, bgp, AFI_IP, SAFI_UNICAST, &write);
>>>>
>>>> diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h
>>>> index 0058b581377b..39fbbe5de525 100644
>>>> --- a/bgpd/bgpd.h
>>>> +++ b/bgpd/bgpd.h
>>>> @@ -23,12 +23,23 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
>>>>
>>>> /* For union sockunion. */
>>>> #include "sockunion.h"
>>>> +#include "bgp_ecommunity.h"
>>>> +#include "prefix.h"
>>>> +#include "vty.h"
>>>>
>>>> /* Typedef BGP specific types. */
>>>> typedef u_int32_t as_t;
>>>> typedef u_int16_t as16_t; /* we may still encounter 16 Bit asnums */
>>>> typedef u_int16_t bgp_size_t;
>>>>
>>>> +/* BGP router distinguisher value. */
>>>> +#define BGP_RD_SIZE 8
>>>> +
>>>> +struct bgp_rd
>>>> +{
>>>> + u_char val[BGP_RD_SIZE];
>>>> +};
>>>> +
>>>> /* BGP master for system wide configurations and variables. */
>>>> struct bgp_master
>>>> {
>>>> @@ -179,6 +190,38 @@ struct bgp
>>>> u_int16_t maxpaths_ebgp;
>>>> u_int16_t maxpaths_ibgp;
>>>> } maxpaths[AFI_MAX][SAFI_MAX];
>>>> +
>>>> + /* VRFs */
>>>> + struct list *vrfs;
>>>> +
>>>> + struct hash *rt_subscribers;
>>>> +
>>>> +};
>>>> +
>>>> +struct bgp_rt_sub
>>>> +{
>>>> + struct ecommunity_val rt;
>>>> +
>>>> + struct list *vrfs;
>>>> +};
>>>> +
>>>> +struct bgp_vrf
>>>> +{
>>>> + struct bgp *bgp;
>>>> +
>>>> + /* RD used for route advertisements */
>>>> + struct prefix_rd outbound_rd;
>>>> +
>>>> + /* import and export lists */
>>>> + struct ecommunity *rt_import;
>>>> + struct ecommunity *rt_export;
>>>> +
>>>> + /* BGP routing information base. */
>>>> + struct bgp_table *rib[AFI_MAX];
>>>> +
>>>> + /* Static route configuration. */
>>>> + struct bgp_table *route[AFI_MAX];
>>>> +
>>>> };
>>>>
>>>> /* BGP peer-group support. */
>>>> @@ -215,14 +258,6 @@ struct bgp_nexthop
>>>> struct in6_addr v6_local;
>>>> };
>>>>
>>>> -/* BGP router distinguisher value. */
>>>> -#define BGP_RD_SIZE 8
>>>> -
>>>> -struct bgp_rd
>>>> -{
>>>> - u_char val[BGP_RD_SIZE];
>>>> -};
>>>> -
>>>> #define RMAP_IN 0
>>>> #define RMAP_OUT 1
>>>> #define RMAP_IMPORT 2
>>>> @@ -999,4 +1034,11 @@ extern int peer_ttl_security_hops_set (struct peer *, int);
>>>> extern int peer_ttl_security_hops_unset (struct peer *);
>>>>
>>>> extern void bgp_scan_finish (void);
>>>> +extern struct bgp_vrf *bgp_vrf_create (struct bgp *bgp, struct prefix_rd *outbound_rd);
>>>> +extern struct bgp_vrf *bgp_vrf_lookup (struct bgp *bgp, struct prefix_rd *outbound_rd);
>>>> +extern void bgp_vrf_delete (struct bgp_vrf *vrf);
>>>> +extern void bgp_vrf_rt_export_set (struct bgp_vrf *vrf, struct ecommunity *rt_export);
>>>> +extern void bgp_vrf_rt_import_set (struct bgp_vrf *vrf, struct ecommunity *rt_import);
>>>> +extern void bgp_vrf_clean_tables (struct bgp_vrf *vrf);
>>>> +
>>>> #endif /* _QUAGGA_BGPD_H */
>>>> diff --git a/lib/memtypes.c b/lib/memtypes.c
>>>> index 8abe99d2a495..3f5bdd255756 100644
>>>> --- a/lib/memtypes.c
>>>> +++ b/lib/memtypes.c
>>>> @@ -157,6 +157,8 @@ struct memory_list memory_list_bgp[] =
>>>> { MTYPE_BGP_AGGREGATE, "BGP aggregate" },
>>>> { MTYPE_BGP_ADDR, "BGP own address" },
>>>> { MTYPE_ENCAP_TLV, "ENCAP TLV", },
>>>> + { MTYPE_BGP_VRF, "BGP VRF", },
>>>> + { MTYPE_BGP_RT_SUB, "BGP Route Target Subscribers" },
>>>> { -1, NULL }
>>>> };
>>>>
>>>
>>> _______________________________________________
>>> Quagga-dev mailing list
>>> Quagga-dev@lists.quagga.net
>>> https://lists.quagga.net/mailman/listinfo/quagga-dev
>
>
> _______________________________________________
> Quagga-dev mailing list
> Quagga-dev@lists.quagga.net
> https://lists.quagga.net/mailman/listinfo/quagga-dev

_______________________________________________
Quagga-dev mailing list
Quagga-dev@lists.quagga.net
https://lists.quagga.net/mailman/listinfo/quagga-dev
Re: [PATCH v2 1/2] bgpd: VRF vty configuration, RIB table creation [ In reply to ]
Hi Philippe,


On October 20, 2016 9:32:38 AM Philippe Guibert
<philippe.guibert@6wind.com> wrote:

> On Wed, Oct 19, 2016 at 2:22 PM, Lou Berger <lberger@labn.net> wrote:
>
> Hello Lou,
>
>> I think either we're talking past each other are have some other
>> major disconnect.
>
> Let me reassure you. If both of us speak not at the same time design and
> concepts,this may be problematic :-)

okay, I think ;-)

> About the concepts you are talking about, I agree with you.
> Regarding design issue, I think there is a misunderstanding because I
> link RD with RTs, within a VRF.
> Whereas you point the following:
> - associate RD with VPN flows
Not sure what you mean here.

I don't understand what "VPN" means to you or in the config model. BGP
LxVPNs have VRFs and Route Distribution semantics. Together these
semantics can be combined to support LxVPNs.

I think having a default (outgoing) RD per VRF is fine (and sort of the
"normal" case.)

> - associate RT set with VRF
>
> The design currently is not aware of the underlying VRF it works on.
That's fine.

> One reason is that this work is pure signalling, there is no dataplane
> interaction.

As is always the the case for BGP ;-)

>
> I think it should be possible, to adapt the configuration. For
> instance, for a VPN network route,
> to know which VRF it uses, and consequently, which RT set.

I agree.

>
> Before going further, can I ask you if we share the same point of view
> about this patchwork issue ?

I think we may have a conceptual model disconnect. To me a VPN is made
up of a collection on VRFs, and BGP mechanisms are centered arounf these
(VRFs) not VPNs. Consequently, I'd suggest that the key word VRF be
used vs VPN in config / VTY. (although if VPN=VRF, always, the change
is just a cosmetic one and might not be worth it.)


> Do you see other points to discuss ?
>

Well, we need to ensure that route distribution happens properly for all
cases (including RR). See below for more specific comments.


> Best Regards,
>
> Philippe
>
>> Per BGP LxVPNs, we really should distinguish between VRFs and (vpn)
>> route distribution.
>>
>> WRT VRFs:
>>
>> The contents of a VRF imported from BGP is determined by one or more
>> (import) RTs. RDs are ignored at this point.
>>
>> An outgoing VPN route is exported to BGP with one or more (export) RTs.
>> One configured RD is typically used on outgoing routes exported from a
>> VRF (note not VPN) , but multiple routes (identified by different RDs)
>> may exist across a single VPN (as identified by an RT set).
>>
>> WRT Route distribution:
>>
>> Ignoring RT/community filtering, which currently isn't in the code, BGP
>> route distribution basically ignores RTs and uses standard route
>> selection based on NRLI route which includes the RD+prefix. This means
>> that different RDs can not only be used to segregate prefixes that exist
>> within a VPN (and are identified with disjoint sets of RTs) they can
>> also be use to support multi-path routes within a VPN (and are
>> identified with same/overlapping sets of RTs). BTW RRs only care about
>> this part.
>>
>> So keying a VPN/VRF off an RD just seems wrong, particularly for the
>> import case where RD is ignored.
>>
>> Lou
>>
>> On 10/19/2016 3:59 AM, Philippe Guibert wrote:
>>> On Tue, Oct 18, 2016 at 3:56 PM, Lou Berger <lberger@labn.net> wrote:
>>>
>>> Hello Lou,
>>>
>>> Please read below my comments.
>>> Consecutive to your feedback, I think there are some improvements to bring,
>>> mainly about configuration and structure naming.
>>>
>>>> It looks like RD is your key to a VRF, is this right?
>>>> This doesn't match the semantics of BGP VPNs, where RDs are independent
>>>> of VRF. (RT set is really the critical thing.)
>>> Most of the modifications have been done around what is called the
>>> "VRF structure".

This is good and aligned with the suggestion to move config to be per VRF.

>>>
>>> The RD is mapped to that "VRF structure", but the RT also. This is a
>>> one-to-one mapping.
>>> That "VRF structure" has a RIB table where RT imports are processed.
>>>

I think a mapping of VRF to RT set is right. Having a default RD for
VRF export is also good.

>>> I mean, on the design point of view, I don't make a difference between
>>> a RD and a RT.

I think this is a mistake. RD is about route (re)distribution
selection. RT is about topology and VRF control.

>>> I just have to ensure that the incoming structure is available to
>>> import appropriate entries.
>>> in order to import a RT entry, I have to create a RT mapped to an
>>> other "VRF structure".
>>>
>>> If the RT is not mapped to that "VRF structure", then the RIB
>>> associated to that RT is not present.
>>> Then the import in the RIB RT will not be possible.

We have parallel code doing the same in RFAPI.

>>>
>>> To illustrate, a quick example shows that routerA sends a NLRI entry to
>>> routerB.
>>>
>>> routerA> rd 200:111 import 100:111 export 100:111 300:111
>>> routerA> network 10.10.10.0/24 rd 200:111
>>> routerB> rd 100:111 import 100:111 export 100:111
>>>
is this all under a vpn/vrf config parameter or at the top (bgp) level?


>>> RouterB will import NLRI entry to RT 100:111

>>> This is possible because RouterB has the line rd100:111 ... created.

hopefully you really mean because RouterB has the line import 100:111

>>>
>>> RouterB will not import NLRI entry to RT 300:111, since there is no
>>> underlying structure.

all good here.


Is this a valid entry

assuming the config structure is under "... vpn ..."
what rt's would be in the update?

>>>
>>> About "VRF structure", My intention is not to interfere about current
>>> VRF implementation in Quagga.
>>> From the configuration point of view, it is easy to find in literature
>>> cisco configuration where VRF
>>> and RD configuration maps together.

Sorry, I work from the spec, not cisco manual/docs.

>>> Could you be more specific about the reason to dissociate RD from VRF ?
the key point to understand is where RDs are used in the processing (VRF
export and BGP route distribution) and where they are not (VRF import)
and that RD != VRF.

>>>
>>> One modification improvement would consist in :
>>> - That "VRF structure" could be renamed to "RT/RD structure"
please no! VRF is actually much better.

>>> - some show commands would be impacted. Instead of dumping VRF RIB
>>> table, one would dump RT/RD RIB table
>>> - the commit logs would be reworked
>>>
>>>> The main implication of
>>>> this is that multipath/ECMP isn't (at least easily) supported.
>>>> Also,
>>>> best path selection on import routes will be wrong if keyed based on RD
>>> Multipath feature impacts both global RIB, and RIB per RT.
>>>
>>> As before, let me illustrate this with a 3 router setup topology.
>>> router A) and router B) send 2 NLRI ECMP entries to router C)
>>>
>>> routerA> rd 200:111 import 100:111 export 100:111
>>> routerA> network 10.10.10.0/24 rd 200:111 <nexthop_routerA>
>>>
>>> routerB> rd 200:111 import 100:111 export 100:111
>>> routerB> network 10.10.10.0/24 rd 200:111 <nexthop_routerB>
you'd want a different RD here.


>>>
>>> routerC> rd 100:111 import 100:111 export 100:111
>>>
>>> When receiving a NLRI entry from routerB), and routerA), bgp_update()
>>> will append the entry in the global RIB, according to RD field.
>>>
>>> routerC> show bgp ipv4 vpn
>>> Route Distinguisher : 200:111
>>> *> 10.10.10.0/24 <nexthop_routerA>
>>> => 10.10.10.0/24 <nexthop_routerB>

of course if you send this via a route reflector only on would be
recieved -- which is why you need different RDs to get both.

>>>
>>> Then, the import processing is storing the same 2 entries in RT RIB.
>>> routerC> show ip bgp rd 100:111
>>> Route Distinguisher : 100:111
>>> *> 10.10.10.0/24 <nexthop_routerA>
>>> => 10.10.10.0/24 <nexthop_routerB>
>>>
>>> By playing with configuration, it is possible to have multipath
>>> entries in the global RIB, but not in the RD RIB.
>>>

>>>> and I'm not sure what's being done on route reflectors.
>>> There may be some missing elements on implementation.
>>> Only the global RIB entries injected by remote peer would be
>>> transmitted, including the export RT information originated by routerA
>>> and routerB.
>>>
>>>> I really think that BGP VRFs cannot / must not be keyed based on RDs.
>>>> If this is just the config interface, then changing this should be
>>>> pretty straight forward.
>>> RT RIBS are keyed based on RTs
>>> global RIBS entries are keyed based on RDs.
>>> About config interface, It would be possible to change configuration:
>>> instead of "vrf rd", one could have "rd <>".

how about
vrf <name>
rd ...
rt (import|export|both) ...
network <prefix> [rd ...]

Lou

>>>
>>>> PS I think an update to bgpd.texi is needed for this patch
>>> of course, this is something that can be done.
>>>
>>> Best Regards,
>>>
>>> Philippe
>>>
>>>> On 10/11/2016 4:17 AM, Philippe Guibert wrote:
>>>>> This commit introduces the BGP VRF configuration, and BGP VRF RIB
>>>>> table.
>>>>> It includes the ability for a BGP to configure its own route
>>>>> distinguisher ( aka VRF). New vty commands introduced:
>>>>>
>>>>> (config-router)# vrf rd <RD>
>>>>>
>>>>> This structure permits configuring import and export route targets,
>>>>> which is defined by RFC4360.
>>>>> (config-router)# vrf rd <RD> exports <RT values>
>>>>> (config-router)# vrf rd <RD> imports <RT values>
>>>>>
>>>>> It brings some improvements.
>>>>> - for a BGP speaker when emitting BGP updates, the exported route
>>>>> targets will be mapped to BGP extended communities associated with
>>>>> the BGP update for the defined Route distinguisher.
>>>>> This commit does not enhance the support for emitting those BGP
>>>>> extended communities, but provides the mecanism.
>>>>> - for a BGP speaker when receiving BGP updaets. Its import route
>>>>> target will be looked up, in order to match NLRI route distinguisher.
>>>>> Then, if matching, the entry would be exported to a RIB per VRF table.
>>>>>
>>>>> As mentioned before, the commit also introduces a BGP VRF RIB table per
>>>>> Route distinguisher configured. This table aims at receiving BGP NLRI
>>>>> entries, with matching import and export route targets.
>>>>> This commit does not take into account the fullfill of this table,
>>>>> but creates it.
>>>>>
>>>>> Signed-off-by: David Lamparter <equinox@opensourcerouting.org>
>>>>> Signed-off-by: Philippe Guibert <philippe.guibert@6wind.com>
>>>>> ---
>>>>> bgpd/bgp_route.c | 193 +++++++++++++++++++++++++++++++++++++++++++++++++++--
>>>>> bgpd/bgp_route.h | 4 ++
>>>>> bgpd/bgp_table.h | 3 +
>>>>> bgpd/bgp_vty.c | 177 +++++++++++++++++++++++++++++++++++++++++++++++++
>>>>> bgpd/bgpd.c | 199 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-
>>>>> bgpd/bgpd.h | 58 +++++++++++++---
>>>>> lib/memtypes.c | 2 +
>>>>> 7 files changed, 622 insertions(+), 14 deletions(-)
>>>>>
>>>>> diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c
>>>>> index 4cb6c141bcdc..abad79f5c9d4 100644
>>>>> --- a/bgpd/bgp_route.c
>>>>> +++ b/bgpd/bgp_route.c
>>>>> @@ -34,6 +34,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330,
>>>>> Boston, MA
>>>>> #include "plist.h"
>>>>> #include "thread.h"
>>>>> #include "workqueue.h"
>>>>> +#include "hash.h"
>>>>>
>>>>> #include "bgpd/bgpd.h"
>>>>> #include "bgpd/bgp_table.h"
>>>>> @@ -61,6 +62,12 @@ Software Foundation, Inc., 59 Temple Place - Suite 330,
>>>>> Boston, MA
>>>>> extern const char *bgp_origin_str[];
>>>>> extern const char *bgp_origin_long_str[];
>>>>>
>>>>> +static void
>>>>> +bgp_static_withdraw_safi (struct bgp *bgp, struct prefix *p, afi_t afi,
>>>>> + safi_t safi, struct prefix_rd *prd, u_char *tag);
>>>>> +static void
>>>>> +bgp_static_free (struct bgp_static *bgp_static);
>>>>> +
>>>>> static struct bgp_node *
>>>>> bgp_afi_node_get (struct bgp_table *table, afi_t afi, safi_t safi, struct
>>>>> prefix *p,
>>>>> struct prefix_rd *prd)
>>>>> @@ -77,7 +84,11 @@ bgp_afi_node_get (struct bgp_table *table, afi_t afi,
>>>>> safi_t safi, struct prefix
>>>>> prn = bgp_node_get (table, (struct prefix *) prd);
>>>>>
>>>>> if (prn->info == NULL)
>>>>> - prn->info = bgp_table_init (afi, safi);
>>>>> + {
>>>>> + struct bgp_table *newtab = bgp_table_init (afi, safi);
>>>>> + newtab->prd = *prd;
>>>>> + prn->info = newtab;
>>>>> + }
>>>>> else
>>>>> bgp_unlock_node (prn);
>>>>> table = prn->info;
>>>>> @@ -1505,12 +1516,86 @@ bgp_process_announce_selected (struct peer *peer,
>>>>> struct bgp_info *selected,
>>>>> else
>>>>> bgp_adj_out_unset (rn, peer, p, afi, safi);
>>>>> break;
>>>>> + case BGP_TABLE_VRF:
>>>>> + /* never called */
>>>>> + assert (0);
>>>>> }
>>>>>
>>>>> bgp_attr_flush (&attr);
>>>>> return 0;
>>>>> }
>>>>>
>>>>> +void bgp_vrf_clean_tables (struct bgp_vrf *vrf)
>>>>> +{
>>>>> + afi_t afi;
>>>>> + for (afi = AFI_IP; afi < AFI_MAX; afi++)
>>>>> + {
>>>>> + struct bgp_info *ri, *ri_next;
>>>>> + struct bgp_node *rn;
>>>>> +
>>>>> + for (rn = bgp_table_top (vrf->rib[afi]); rn; rn = bgp_route_next (rn))
>>>>> + for (ri = rn->info; ri; ri = ri_next)
>>>>> + {
>>>>> + ri_next = ri->next;
>>>>> + bgp_info_reap (rn, ri);
>>>>> + }
>>>>> + bgp_table_finish (&vrf->rib[afi]);
>>>>> +
>>>>> + for (rn = bgp_table_top (vrf->route[afi]); rn; rn = bgp_route_next (rn))
>>>>> + if (rn->info)
>>>>> + {
>>>>> + struct bgp_static *bs = rn->info;
>>>>> + bgp_static_withdraw_safi (vrf->bgp, &rn->p, afi, SAFI_MPLS_VPN,
>>>>> + &vrf->outbound_rd, NULL);
>>>>> + bgp_static_free (bs);
>>>>> + rn->info = NULL;
>>>>> + bgp_unlock_node (rn);
>>>>> + }
>>>>> + bgp_table_finish (&vrf->route[afi]);
>>>>> + }
>>>>> +}
>>>>> +
>>>>> +void
>>>>> +bgp_vrf_apply_new_imports (struct bgp_vrf *vrf, afi_t afi)
>>>>> +{
>>>>> + struct bgp_node *rd_rn, *rn;
>>>>> + struct bgp_info *sel;
>>>>> + struct bgp_table *table;
>>>>> + struct ecommunity *ecom;
>>>>> + size_t i, j;
>>>>> + bool found;
>>>>> +
>>>>> + if (!vrf->rt_import || vrf->rt_import->size == 0)
>>>>> + return;
>>>>> +
>>>>> + for (rd_rn = bgp_table_top (vrf->bgp->rib[afi][SAFI_MPLS_VPN]); rd_rn;
>>>>> + rd_rn = bgp_route_next (rd_rn))
>>>>> + if (rd_rn->info != NULL)
>>>>> + {
>>>>> + table = rd_rn->info;
>>>>> +
>>>>> + for (rn = bgp_table_top (table); rn; rn = bgp_route_next (rn))
>>>>> + {
>>>>> + for (sel = rn->info; sel; sel = sel->next)
>>>>> + if (CHECK_FLAG (sel->flags, BGP_INFO_SELECTED))
>>>>> + break;
>>>>> + if (!sel || !sel->attr || !sel->attr->extra)
>>>>> + continue;
>>>>> + ecom = sel->attr->extra->ecommunity;
>>>>> + if (!ecom)
>>>>> + continue;
>>>>> +
>>>>> + found = false;
>>>>> + for (i = 0; i < (size_t)ecom->size && !found; i++)
>>>>> + for (j = 0; j < (size_t)vrf->rt_import->size && !found; j++)
>>>>> + if (!memcmp(ecom->val + i * 8, vrf->rt_import->val + j *
>>>>> 8, 8))
>>>>> + found = true;
>>>>> + if (!found)
>>>>> + continue;
>>>>> + }
>>>>> + }
>>>>> +}
>>>>> +
>>>>> struct bgp_process_queue
>>>>> {
>>>>> struct bgp *bgp;
>>>>> @@ -1746,6 +1831,9 @@ bgp_process (struct bgp *bgp, struct bgp_node *rn,
>>>>> afi_t afi, safi_t safi)
>>>>> case BGP_TABLE_RSCLIENT:
>>>>> work_queue_add (bm->process_rsclient_queue, pqnode);
>>>>> break;
>>>>> + case BGP_TABLE_VRF:
>>>>> + /* never called */
>>>>> + assert (0);
>>>>> }
>>>>>
>>>>> SET_FLAG (rn->flags, BGP_NODE_PROCESS_SCHEDULED);
>>>>> @@ -6291,6 +6379,9 @@ route_vty_out_detail (struct vty *vty, struct bgp
>>>>> *bgp, struct prefix *p,
>>>>>
>>>>> attr = binfo->attr;
>>>>>
>>>>> + if (safi == SAFI_MPLS_LABELED_VPN)
>>>>> + safi = SAFI_MPLS_VPN;
>>>>> +
>>>>> if (attr)
>>>>> {
>>>>> /* Line1 display AS-path, Aggregator */
>>>>> @@ -6510,6 +6601,7 @@ bgp_show_table (struct vty *vty, struct bgp_table
>>>>> *table, struct in_addr *router
>>>>> int display;
>>>>> unsigned long output_count;
>>>>> unsigned long total_count;
>>>>> + safi_t safi = table->type == BGP_TABLE_VRF ? SAFI_MPLS_VPN : SAFI_UNICAST;
>>>>>
>>>>> /* This is first entry point, so reset total line. */
>>>>> output_count = 0;
>>>>> @@ -6694,7 +6786,7 @@ bgp_show_table (struct vty *vty, struct bgp_table
>>>>> *table, struct in_addr *router
>>>>>
>>>>> if (type == bgp_show_type_dampend_paths
>>>>> || type == bgp_show_type_damp_neighbor)
>>>>> - damp_route_vty_out (vty, &rn->p, ri, display, SAFI_UNICAST);
>>>>> + damp_route_vty_out (vty, &rn->p, ri, display, safi);
>>>>> else if (type == bgp_show_type_flap_statistics
>>>>> || type == bgp_show_type_flap_address
>>>>> || type == bgp_show_type_flap_prefix
>>>>> @@ -6705,9 +6797,9 @@ bgp_show_table (struct vty *vty, struct bgp_table
>>>>> *table, struct in_addr *router
>>>>> || type == bgp_show_type_flap_prefix_longer
>>>>> || type == bgp_show_type_flap_route_map
>>>>> || type == bgp_show_type_flap_neighbor)
>>>>> - flap_route_vty_out (vty, &rn->p, ri, display, SAFI_UNICAST);
>>>>> + flap_route_vty_out (vty, &rn->p, ri, display, safi);
>>>>> else
>>>>> - route_vty_out (vty, &rn->p, ri, display, SAFI_UNICAST);
>>>>> + route_vty_out (vty, &rn->p, ri, display, safi);
>>>>> display++;
>>>>> }
>>>>> if (display)
>>>>> @@ -6749,6 +6841,35 @@ bgp_show (struct vty *vty, struct bgp *bgp, afi_t
>>>>> afi, safi_t safi,
>>>>> return bgp_show_table (vty, table, &bgp->router_id, type, output_arg);
>>>>> }
>>>>>
>>>>> +static int
>>>>> +bgp_show_vrf (struct vty *vty, const char *vrf_name, afi_t afi,
>>>>> + enum bgp_show_type type, void *output_arg)
>>>>> +{
>>>>> + struct bgp *bgp = bgp_get_default();
>>>>> + struct bgp_vrf *vrf;
>>>>> + struct prefix_rd prd;
>>>>> +
>>>>> + if (! bgp)
>>>>> + {
>>>>> + vty_out (vty, "%% No default BGP instance%s", VTY_NEWLINE);
>>>>> + return CMD_WARNING;
>>>>> + }
>>>>> + if (! str2prefix_rd (vrf_name, &prd))
>>>>> + {
>>>>> + vty_out (vty, "%% Invalid RD '%s'%s", vrf_name, VTY_NEWLINE);
>>>>> + return CMD_WARNING;
>>>>> + }
>>>>> +
>>>>> + vrf = bgp_vrf_lookup (bgp, &prd);
>>>>> + if (! vrf)
>>>>> + {
>>>>> + vty_out (vty, "%% No VRF with RD '%s'%s", vrf_name, VTY_NEWLINE);
>>>>> + return CMD_WARNING;
>>>>> + }
>>>>> +
>>>>> + return bgp_show_table (vty, vrf->rib[afi], &bgp->router_id, type,
>>>>> output_arg);
>>>>> +}
>>>>> +
>>>>> /* Header of detailed BGP route information */
>>>>> static void
>>>>> route_vty_out_detail_header (struct vty *vty, struct bgp *bgp,
>>>>> @@ -6816,6 +6937,12 @@ route_vty_out_detail_header (struct vty *vty, struct
>>>>> bgp *bgp,
>>>>> vty_out (vty, ", Advertisements suppressed by an aggregate.");
>>>>> vty_out (vty, ")%s", VTY_NEWLINE);
>>>>>
>>>>> + if (safi == SAFI_MPLS_LABELED_VPN)
>>>>> + {
>>>>> + vty_out (vty, "%s", VTY_NEWLINE);
>>>>> + return;
>>>>> + }
>>>>> +
>>>>> /* advertised peer */
>>>>> for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer))
>>>>> {
>>>>> @@ -6939,6 +7066,36 @@ bgp_show_route_in_table (struct vty *vty, struct bgp
>>>>> *bgp,
>>>>> return CMD_SUCCESS;
>>>>> }
>>>>>
>>>>> +static int
>>>>> +bgp_show_vrf_route (struct vty *vty, const char *vrf_name, const char *ip_str,
>>>>> + afi_t afi, int prefix_check)
>>>>> +{
>>>>> + struct bgp *bgp = bgp_get_default();
>>>>> + struct bgp_vrf *vrf;
>>>>> + struct prefix_rd prd;
>>>>> +
>>>>> + if (! bgp)
>>>>> + {
>>>>> + vty_out (vty, "%% No default BGP instance%s", VTY_NEWLINE);
>>>>> + return CMD_WARNING;
>>>>> + }
>>>>> + if (! str2prefix_rd (vrf_name, &prd))
>>>>> + {
>>>>> + vty_out (vty, "%% Invalid RD '%s'%s", vrf_name, VTY_NEWLINE);
>>>>> + return CMD_WARNING;
>>>>> + }
>>>>> +
>>>>> + vrf = bgp_vrf_lookup (bgp, &prd);
>>>>> + if (! vrf)
>>>>> + {
>>>>> + vty_out (vty, "%% No VRF with RD '%s'%s", vrf_name, VTY_NEWLINE);
>>>>> + return CMD_WARNING;
>>>>> + }
>>>>> +
>>>>> + return bgp_show_route_in_table (vty, bgp, vrf->rib[afi], ip_str,
>>>>> + afi, SAFI_MPLS_LABELED_VPN, NULL,
>>>>> prefix_check, BGP_PATH_ALL);
>>>>> +}
>>>>> +
>>>>> /* Display specified route of Main RIB */
>>>>> static int
>>>>> bgp_show_route (struct vty *vty, const char *view_name, const char *ip_str,
>>>>> @@ -6982,6 +7139,16 @@ DEFUN (show_ip_bgp,
>>>>> return bgp_show (vty, NULL, AFI_IP, SAFI_UNICAST, bgp_show_type_normal, NULL);
>>>>> }
>>>>>
>>>>> +DEFUN (show_ip_bgp_vrf,
>>>>> + show_ip_bgp_vrf_cmd,
>>>>> + "show ip bgp vrf WORD",
>>>>> + SHOW_STR
>>>>> + IP_STR
>>>>> + BGP_STR)
>>>>> +{
>>>>> + return bgp_show_vrf (vty, argv[0], AFI_IP, bgp_show_type_normal, NULL);
>>>>> +}
>>>>> +
>>>>> DEFUN (show_ip_bgp_ipv4,
>>>>> show_ip_bgp_ipv4_cmd,
>>>>> "show ip bgp ipv4 (unicast|multicast)",
>>>>> @@ -7050,6 +7217,19 @@ DEFUN (show_bgp_ipv4_safi_route_pathtype,
>>>>> return bgp_show_route (vty, NULL, argv[1], AFI_IP, SAFI_UNICAST, NULL, 0,
>>>>> BGP_PATH_MULTIPATH);
>>>>> }
>>>>>
>>>>> +DEFUN (show_ip_bgp_vrf_route,
>>>>> + show_ip_bgp_vrf_route_cmd,
>>>>> + "show ip bgp vrf WORD (ipv4|ipv6) (A.B.C.D|X:X::X:X)",
>>>>> + SHOW_STR
>>>>> + IP_STR
>>>>> + BGP_STR
>>>>> + "VRF\n"
>>>>> + "Route Distinguisher\n")
>>>>> +{
>>>>> + afi_t afi = (strncmp (argv[1], "ipv6", 4) == 0) ? AFI_IP6 : AFI_IP;
>>>>> + return bgp_show_vrf_route (vty, argv[0], argv[2], afi, 0);
>>>>> +}
>>>>> +
>>>>> DEFUN (show_ip_bgp_ipv4_route,
>>>>> show_ip_bgp_ipv4_route_cmd,
>>>>> "show ip bgp ipv4 (unicast|multicast) A.B.C.D",
>>>>> @@ -16702,10 +16882,12 @@ bgp_route_init (void)
>>>>>
>>>>> /* old style commands */
>>>>> install_element (VIEW_NODE, &show_ip_bgp_cmd);
>>>>> + install_element (VIEW_NODE, &show_ip_bgp_vrf_cmd);
>>>>> install_element (VIEW_NODE, &show_ip_bgp_ipv4_cmd);
>>>>> install_element (VIEW_NODE, &show_ip_bgp_route_cmd);
>>>>> install_element (VIEW_NODE, &show_ip_bgp_route_pathtype_cmd);
>>>>> install_element (VIEW_NODE, &show_bgp_ipv4_safi_route_pathtype_cmd);
>>>>> + install_element (VIEW_NODE, &show_ip_bgp_vrf_route_cmd);
>>>>> install_element (VIEW_NODE, &show_ip_bgp_ipv4_route_cmd);
>>>>> install_element (VIEW_NODE, &show_ip_bgp_vpnv4_all_route_cmd);
>>>>> install_element (VIEW_NODE, &show_ip_bgp_vpnv4_rd_route_cmd);
>>>>> @@ -16797,6 +16979,7 @@ bgp_route_init (void)
>>>>> install_element (RESTRICTED_NODE, &show_ip_bgp_route_cmd);
>>>>> install_element (RESTRICTED_NODE, &show_ip_bgp_route_pathtype_cmd);
>>>>> install_element (RESTRICTED_NODE, &show_bgp_ipv4_safi_route_pathtype_cmd);
>>>>> + install_element (RESTRICTED_NODE, &show_ip_bgp_vrf_route_cmd);
>>>>> install_element (RESTRICTED_NODE, &show_ip_bgp_ipv4_route_cmd);
>>>>> install_element (RESTRICTED_NODE, &show_ip_bgp_vpnv4_rd_route_cmd);
>>>>> install_element (RESTRICTED_NODE, &show_ip_bgp_prefix_cmd);
>>>>> @@ -16832,7 +17015,7 @@ bgp_route_init (void)
>>>>> install_element (VIEW_NODE, &show_ip_bgp_neighbor_prefix_counts_cmd);
>>>>> install_element (VIEW_NODE, &show_ip_bgp_ipv4_neighbor_prefix_counts_cmd);
>>>>> install_element (VIEW_NODE, &show_ip_bgp_vpnv4_neighbor_prefix_counts_cmd);
>>>>> -
>>>>> + install_element (VIEW_NODE, &show_ip_bgp_vrf_cmd);
>>>>> install_element (VIEW_NODE, &show_bgp_cmd);
>>>>> install_element (VIEW_NODE, &show_bgp_ipv6_cmd);
>>>>> install_element (VIEW_NODE, &show_bgp_route_cmd);
>>>>> diff --git a/bgpd/bgp_route.h b/bgpd/bgp_route.h
>>>>> index 332714c4f845..25a42e87bd94 100644
>>>>> --- a/bgpd/bgp_route.h
>>>>> +++ b/bgpd/bgp_route.h
>>>>> @@ -43,6 +43,8 @@ struct bgp_info_extra
>>>>>
>>>>> /* MPLS label. */
>>>>> u_char tag[3];
>>>>> +
>>>>> + struct prefix_rd vrf_rd;
>>>>> };
>>>>>
>>>>> struct bgp_info
>>>>> @@ -270,4 +272,6 @@ extern void route_vty_out_tmp (struct vty *, struct
>>>>> prefix *, struct attr *, saf
>>>>> extern void bgp_peer_clear_node_queue_drain_immediate (struct peer *peer);
>>>>> extern void bgp_process_queues_drain_immediate (void);
>>>>>
>>>>> +extern void bgp_vrf_apply_new_imports (struct bgp_vrf *vrf, afi_t afi);
>>>>> +
>>>>> #endif /* _QUAGGA_BGP_ROUTE_H */
>>>>> diff --git a/bgpd/bgp_table.h b/bgpd/bgp_table.h
>>>>> index 8e963aeeeb84..13d29469a058 100644
>>>>> --- a/bgpd/bgp_table.h
>>>>> +++ b/bgpd/bgp_table.h
>>>>> @@ -27,6 +27,7 @@ typedef enum
>>>>> {
>>>>> BGP_TABLE_MAIN,
>>>>> BGP_TABLE_RSCLIENT,
>>>>> + BGP_TABLE_VRF,
>>>>> } bgp_table_t;
>>>>>
>>>>> struct bgp_table
>>>>> @@ -43,6 +44,8 @@ struct bgp_table
>>>>> struct peer *owner;
>>>>>
>>>>> struct route_table *route_table;
>>>>> +
>>>>> + struct prefix_rd prd;
>>>>> };
>>>>>
>>>>> struct bgp_node
>>>>> diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c
>>>>> index 7af4e81a87b1..63a7b5bfdcf6 100644
>>>>> --- a/bgpd/bgp_vty.c
>>>>> +++ b/bgpd/bgp_vty.c
>>>>> @@ -9891,6 +9891,178 @@ bgp_config_write_redistribute (struct vty *vty,
>>>>> struct bgp *bgp, afi_t afi,
>>>>> return *write;
>>>>> }
>>>>>
>>>>> +DEFUN (bgp_vrf,
>>>>> + bgp_vrf_cmd,
>>>>> + "vrf rd WORD",
>>>>> + "BGP VPN VRF\n"
>>>>> + "Route Distinguisher\n"
>>>>> + "Route Distinguisher\n"
>>>>> +)
>>>>> +{
>>>>> + struct bgp *bgp = vty->index;
>>>>> + struct bgp_vrf *vrf;
>>>>> + struct prefix_rd prd;
>>>>> +
>>>>> + if (! str2prefix_rd (argv[0], &prd))
>>>>> + {
>>>>> + vty_out (vty, "%% Invalid RD '%s'%s", argv[0], VTY_NEWLINE);
>>>>> + return CMD_WARNING;
>>>>> + }
>>>>> +
>>>>> + vrf = bgp_vrf_lookup (bgp, &prd);
>>>>> + if (vrf)
>>>>> + {
>>>>> + vty_out (vty, "%% VRF with RD '%s' already exists%s", argv[0],
>>>>> VTY_NEWLINE);
>>>>> + return CMD_WARNING;
>>>>> + }
>>>>> +
>>>>> + bgp_vrf_create (bgp, &prd);
>>>>> + return CMD_SUCCESS;
>>>>> +}
>>>>> +
>>>>> +DEFUN (bgp_vrf_exports,
>>>>> + bgp_vrf_exports_cmd,
>>>>> + "vrf rd WORD exports .LINE",
>>>>> + "BGP VPN VRF\n"
>>>>> + "Route Distinguisher\n"
>>>>> + "Route Distinguisher\n"
>>>>> + "Export RT values\n"
>>>>> + "Export RT values\n"
>>>>> +)
>>>>> +{
>>>>> + struct bgp *bgp = vty->index;
>>>>> + struct bgp_vrf *vrf;
>>>>> + struct prefix_rd prd;
>>>>> + struct ecommunity *ecom = NULL;
>>>>> + int fail = 0, i;
>>>>> + char *rts = NULL, *rts_ptr;
>>>>> +
>>>>> + if (! str2prefix_rd (argv[0], &prd))
>>>>> + {
>>>>> + vty_out (vty, "%% Invalid RD '%s'%s", argv[0], VTY_NEWLINE);
>>>>> + fail++;
>>>>> + }
>>>>> + /* forge export list */
>>>>> + i = 1;
>>>>> + rts = XCALLOC(MTYPE_TMP,2048);
>>>>> + rts_ptr = rts;
>>>>> + while(i < argc)
>>>>> + {
>>>>> + rts_ptr += sprintf(rts_ptr, "rt %s ",argv[i]);
>>>>> + i++;
>>>>> + }
>>>>> + /* convert list of ecoms string into ecom struct */
>>>>> + ecom = ecommunity_str2com (rts, ECOMMUNITY_ROUTE_TARGET, 1);
>>>>> + if (! ecom)
>>>>> + {
>>>>> + vty_out (vty, "%% Invalid RT '%s'%s", argv[1], VTY_NEWLINE);
>>>>> + fail++;
>>>>> + }
>>>>> + if (rts)
>>>>> + XFREE (MTYPE_TMP, rts);
>>>>> + if (fail)
>>>>> + return CMD_WARNING;
>>>>> +
>>>>> + vrf = bgp_vrf_lookup (bgp, &prd);
>>>>> + if (! vrf)
>>>>> + {
>>>>> + ecommunity_free (&ecom);
>>>>> + vty_out (vty, "%% No VRF with RD '%s'%s", argv[0], VTY_NEWLINE);
>>>>> + return CMD_WARNING;
>>>>> + }
>>>>> +
>>>>> + ecom = ecommunity_intern (ecom);
>>>>> + bgp_vrf_rt_export_set (vrf, ecom);
>>>>> + ecommunity_unintern (&ecom);
>>>>> + return CMD_SUCCESS;
>>>>> +}
>>>>> +
>>>>> +DEFUN (bgp_vrf_imports,
>>>>> + bgp_vrf_imports_cmd,
>>>>> + "vrf rd WORD imports .LINE",
>>>>> + "BGP VPN VRF\n"
>>>>> + "Route Distinguisher\n"
>>>>> + "Route Distinguisher\n"
>>>>> + "Import RT values\n"
>>>>> + "Import RT values\n"
>>>>> +)
>>>>> +{
>>>>> + struct bgp *bgp = vty->index;
>>>>> + struct bgp_vrf *vrf;
>>>>> + struct prefix_rd prd;
>>>>> + struct ecommunity *ecom = NULL;
>>>>> + int fail = 0, i;
>>>>> + char *rts = NULL, *rts_ptr;
>>>>> +
>>>>> + if (! str2prefix_rd (argv[0], &prd))
>>>>> + {
>>>>> + vty_out (vty, "%% Invalid RD '%s'%s", argv[0], VTY_NEWLINE);
>>>>> + fail++;
>>>>> + }
>>>>> + /* forge export list */
>>>>> + i = 1;
>>>>> + rts = XCALLOC(MTYPE_TMP,2048);
>>>>> + rts_ptr = rts;
>>>>> + while(i < argc)
>>>>> + {
>>>>> + rts_ptr += sprintf(rts_ptr, "rt %s ",argv[i]);
>>>>> + i++;
>>>>> + }
>>>>> + /* convert list of ecoms string into ecom struct */
>>>>> + ecom = ecommunity_str2com (rts, ECOMMUNITY_ROUTE_TARGET, 1);
>>>>> + if (! ecom)
>>>>> + {
>>>>> + vty_out (vty, "%% Invalid RT '%s'%s", argv[1], VTY_NEWLINE);
>>>>> + fail++;
>>>>> + }
>>>>> + if (rts)
>>>>> + XFREE (MTYPE_TMP, rts);
>>>>> + if (fail)
>>>>> + return CMD_WARNING;
>>>>> +
>>>>> + vrf = bgp_vrf_lookup (bgp, &prd);
>>>>> + if (! vrf)
>>>>> + {
>>>>> + ecommunity_free (&ecom);
>>>>> + vty_out (vty, "%% No VRF with RD '%s'%s", argv[0], VTY_NEWLINE);
>>>>> + return CMD_WARNING;
>>>>> + }
>>>>> +
>>>>> + ecom = ecommunity_intern (ecom);
>>>>> + bgp_vrf_rt_import_set (vrf, ecom);
>>>>> + ecommunity_unintern (&ecom);
>>>>> + return CMD_SUCCESS;
>>>>> +}
>>>>> +
>>>>> +DEFUN (no_bgp_vrf,
>>>>> + no_bgp_vrf_cmd,
>>>>> + "no vrf rd WORD",
>>>>> + NO_STR
>>>>> + "BGP VPN VRF\n"
>>>>> + "Route Distinguisher\n"
>>>>> + "Route Distinguisher\n"
>>>>> +)
>>>>> +{
>>>>> + struct bgp *bgp = vty->index;
>>>>> + struct bgp_vrf *vrf;
>>>>> + struct prefix_rd prd;
>>>>> +
>>>>> + if (! str2prefix_rd (argv[0], &prd))
>>>>> + {
>>>>> + vty_out (vty, "%% Invalid RD '%s'%s", argv[0], VTY_NEWLINE);
>>>>> + return CMD_WARNING;
>>>>> + }
>>>>> +
>>>>> + vrf = bgp_vrf_lookup (bgp, &prd);
>>>>> + if (! vrf)
>>>>> + {
>>>>> + vty_out (vty, "%% No VRF with RD '%s'%s", argv[0], VTY_NEWLINE);
>>>>> + return CMD_WARNING;
>>>>> + }
>>>>> + bgp_vrf_delete (vrf);
>>>>> + return CMD_SUCCESS;
>>>>> +}
>>>>> +
>>>>> /* BGP node structure. */
>>>>> static struct cmd_node bgp_node =
>>>>> {
>>>>> @@ -9982,6 +10154,11 @@ bgp_vty_init (void)
>>>>> install_default (BGP_ENCAP_NODE);
>>>>> install_default (BGP_ENCAPV6_NODE);
>>>>>
>>>>> + install_element (BGP_NODE, &bgp_vrf_cmd);
>>>>> + install_element (BGP_NODE, &bgp_vrf_exports_cmd);
>>>>> + install_element (BGP_NODE, &bgp_vrf_imports_cmd);
>>>>> + install_element (BGP_NODE, &no_bgp_vrf_cmd);
>>>>> +
>>>>> /* "bgp multiple-instance" commands. */
>>>>> install_element (CONFIG_NODE, &bgp_multiple_instance_cmd);
>>>>> install_element (CONFIG_NODE, &no_bgp_multiple_instance_cmd);
>>>>> diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c
>>>>> index 018a59941101..5725730d9454 100644
>>>>> --- a/bgpd/bgpd.c
>>>>> +++ b/bgpd/bgpd.c
>>>>> @@ -35,6 +35,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330,
>>>>> Boston, MA
>>>>> #include "log.h"
>>>>> #include "plist.h"
>>>>> #include "linklist.h"
>>>>> +#include "hash.h"
>>>>> #include "workqueue.h"
>>>>> #include "table.h"
>>>>>
>>>>> @@ -2057,6 +2058,164 @@ bgp_startup_timer_expire (struct thread *thread)
>>>>> return 0;
>>>>> }
>>>>>
>>>>> +/* VRFs */
>>>>> +
>>>>> +static unsigned int bgp_rt_hash_key (void *arg)
>>>>> +{
>>>>> + const struct bgp_rt_sub *rt_sub = arg;
>>>>> + uint32_t *rtval = (uint32_t *)(char *)&rt_sub->rt;
>>>>> + return rtval[0] ^ rtval[1];
>>>>> +}
>>>>> +
>>>>> +static int bgp_rt_hash_cmp (const void *a, const void *b)
>>>>> +{
>>>>> + const struct bgp_rt_sub *aa = a, *bb = b;
>>>>> + return !memcmp(&aa->rt, &bb->rt, sizeof(aa->rt));
>>>>> +}
>>>>> +
>>>>> +static void *
>>>>> +bgp_rt_hash_alloc (void *dummy)
>>>>> +{
>>>>> + struct bgp_rt_sub *ddummy = dummy, *rt_sub;
>>>>> + rt_sub = XMALLOC (MTYPE_BGP_RT_SUB, sizeof (*rt_sub));
>>>>> + rt_sub->rt = ddummy->rt;
>>>>> + rt_sub->vrfs = list_new();
>>>>> + return rt_sub;
>>>>> +}
>>>>> +
>>>>> +static void
>>>>> +bgp_rt_hash_dealloc (struct bgp_rt_sub *rt_sub)
>>>>> +{
>>>>> + list_delete (rt_sub->vrfs);
>>>>> + XFREE (MTYPE_BGP_RT_SUB, rt_sub);
>>>>> +}
>>>>> +
>>>>> +struct bgp_vrf *
>>>>> +bgp_vrf_lookup (struct bgp *bgp, struct prefix_rd *outbound_rd)
>>>>> +{
>>>>> + struct listnode *node;
>>>>> + struct bgp_vrf *vrf;
>>>>> +
>>>>> + for (ALL_LIST_ELEMENTS_RO(bgp->vrfs, node, vrf))
>>>>> + if (!memcmp (outbound_rd->val, vrf->outbound_rd.val, 8))
>>>>> + return vrf;
>>>>> + return NULL;
>>>>> +}
>>>>> +
>>>>> +struct bgp_vrf *
>>>>> +bgp_vrf_create (struct bgp *bgp, struct prefix_rd *outbound_rd)
>>>>> +{
>>>>> + struct bgp_vrf *vrf;
>>>>> + afi_t afi;
>>>>> +
>>>>> + if ( (vrf = XCALLOC (MTYPE_BGP_VRF, sizeof (struct bgp_vrf))) == NULL)
>>>>> + return NULL;
>>>>> +
>>>>> + vrf->bgp = bgp;
>>>>> + vrf->outbound_rd = *outbound_rd;
>>>>> +
>>>>> + for (afi = AFI_IP; afi < AFI_MAX; afi++)
>>>>> + {
>>>>> + vrf->route[afi] = bgp_table_init (afi, SAFI_UNICAST);
>>>>> + vrf->route[afi]->type = BGP_TABLE_VRF;
>>>>> + vrf->rib[afi] = bgp_table_init (afi, SAFI_UNICAST);
>>>>> + vrf->rib[afi]->type = BGP_TABLE_VRF;
>>>>> + }
>>>>> +
>>>>> + listnode_add (bgp->vrfs, vrf);
>>>>> + return vrf;
>>>>> +}
>>>>> +
>>>>> +static struct ecommunity * ecommunity_reintern (struct ecommunity *ecom)
>>>>> +{
>>>>> + assert (ecom->refcnt > 0);
>>>>> + ecom->refcnt++;
>>>>> + return ecom;
>>>>> +}
>>>>> +
>>>>> +void
>>>>> +bgp_vrf_rt_export_set (struct bgp_vrf *vrf, struct ecommunity *rt_export)
>>>>> +{
>>>>> + if (vrf->rt_export)
>>>>> + ecommunity_unintern (&vrf->rt_export);
>>>>> +
>>>>> + vrf->rt_export = ecommunity_reintern (rt_export);
>>>>> +}
>>>>> +
>>>>> +static void
>>>>> +bgp_vrf_rt_import_unset (struct bgp_vrf *vrf)
>>>>> +{
>>>>> + size_t i;
>>>>> +
>>>>> + if (!vrf->rt_import)
>>>>> + return;
>>>>> +
>>>>> + for (i = 0; i < (size_t)vrf->rt_import->size; i++)
>>>>> + {
>>>>> + struct bgp_rt_sub dummy, *rt_sub;
>>>>> + memcpy (&dummy.rt, vrf->rt_import->val + 8 * i, 8);
>>>>> +
>>>>> + rt_sub = hash_lookup (vrf->bgp->rt_subscribers, &dummy);
>>>>> + assert(rt_sub);
>>>>> + listnode_delete (rt_sub->vrfs, vrf);
>>>>> + if (list_isempty (rt_sub->vrfs))
>>>>> + {
>>>>> + hash_release (vrf->bgp->rt_subscribers, rt_sub);
>>>>> + bgp_rt_hash_dealloc (rt_sub);
>>>>> + }
>>>>> + }
>>>>> +
>>>>> + ecommunity_unintern (&vrf->rt_import);
>>>>> +}
>>>>> +
>>>>> +void
>>>>> +bgp_vrf_rt_import_set (struct bgp_vrf *vrf, struct ecommunity *rt_import)
>>>>> +{
>>>>> + size_t i;
>>>>> + afi_t afi;
>>>>> +
>>>>> + bgp_vrf_rt_import_unset (vrf);
>>>>> +
>>>>> + vrf->rt_import = ecommunity_reintern (rt_import);
>>>>> +
>>>>> + for (i = 0; i < (size_t)vrf->rt_import->size; i++)
>>>>> + {
>>>>> + struct bgp_rt_sub dummy, *rt_sub;
>>>>> + memcpy (&dummy.rt, vrf->rt_import->val + 8 * i, 8);
>>>>> +
>>>>> + rt_sub = hash_get (vrf->bgp->rt_subscribers, &dummy, bgp_rt_hash_alloc);
>>>>> + listnode_add (rt_sub->vrfs, vrf);
>>>>> + }
>>>>> +
>>>>> + for (afi = AFI_IP; afi < AFI_MAX; afi++)
>>>>> + bgp_vrf_apply_new_imports (vrf, afi);
>>>>> +}
>>>>> +
>>>>> +static void
>>>>> +bgp_vrf_delete_int (void *arg)
>>>>> +{
>>>>> + struct bgp_vrf *vrf = arg;
>>>>> + char vrf_rd_str[RD_ADDRSTRLEN];
>>>>> +
>>>>> + prefix_rd2str(&vrf->outbound_rd, vrf_rd_str, sizeof(vrf_rd_str));
>>>>> + zlog_info ("deleting vrf %s", vrf_rd_str);
>>>>> +
>>>>> + bgp_vrf_clean_tables (vrf);
>>>>> +
>>>>> + bgp_vrf_rt_import_unset (vrf);
>>>>> + if (vrf->rt_export)
>>>>> + ecommunity_unintern (&vrf->rt_export);
>>>>> +
>>>>> + XFREE (MTYPE_BGP_VRF, vrf);
>>>>> +}
>>>>> +
>>>>> +void
>>>>> +bgp_vrf_delete (struct bgp_vrf *vrf)
>>>>> +{
>>>>> + listnode_delete (vrf->bgp->vrfs, vrf);
>>>>> + bgp_vrf_delete_int(vrf);
>>>>> +}
>>>>> +
>>>>> /* BGP instance creation by `router bgp' commands. */
>>>>> static struct bgp *
>>>>> bgp_create (as_t *as, const char *name)
>>>>> @@ -2103,6 +2262,10 @@ bgp_create (as_t *as, const char *name)
>>>>> if (name)
>>>>> bgp->name = strdup (name);
>>>>>
>>>>> + bgp->vrfs = list_new();
>>>>> + bgp->vrfs->del = bgp_vrf_delete_int;
>>>>> + bgp->rt_subscribers = hash_create(bgp_rt_hash_key, bgp_rt_hash_cmp);
>>>>> +
>>>>> THREAD_TIMER_ON (bm->master, bgp->t_startup, bgp_startup_timer_expire,
>>>>> bgp, bgp->restart_time);
>>>>>
>>>>> @@ -2236,7 +2399,13 @@ bgp_delete (struct bgp *bgp)
>>>>> BGP_NOTIFY_CEASE_PEER_UNCONFIG);
>>>>> }
>>>>> }
>>>>> -
>>>>> + if(bgp->vrfs)
>>>>> + list_delete (bgp->vrfs);
>>>>> + if(bgp->rt_subscribers)
>>>>> + {
>>>>> + hash_clean (bgp->rt_subscribers, NULL);
>>>>> + hash_free (bgp->rt_subscribers);
>>>>> + }
>>>>> /* Delete static route. */
>>>>> bgp_static_delete (bgp);
>>>>>
>>>>> @@ -5615,6 +5784,34 @@ bgp_config_write (struct vty *vty)
>>>>> bgp_config_write_peer (vty, bgp, peer, AFI_IP, SAFI_UNICAST);
>>>>> }
>>>>>
>>>>> + {
>>>>> + struct bgp_vrf *vrf;
>>>>> + char rdstr[RD_ADDRSTRLEN];
>>>>> + char *str_p, *str2_p;
>>>>> + for (ALL_LIST_ELEMENTS_RO(bgp->vrfs, node, vrf))
>>>>> + {
>>>>> + str_p = prefix_rd2str(&(vrf->outbound_rd), rdstr, RD_ADDRSTRLEN);
>>>>> + vty_out(vty, " vrf rd %s%s", str_p == NULL?"<err>":str_p,
>>>>> VTY_NEWLINE);
>>>>> + if(vrf->rt_import)
>>>>> + {
>>>>> + str2_p = ecommunity_ecom2str (vrf->rt_import,
>>>>> ECOMMUNITY_FORMAT_ROUTE_MAP);
>>>>> + if(str2_p)
>>>>> + {
>>>>> + vty_out(vty, " vrf rd %s import %s%s", str_p ==
>>>>> NULL?"<err>":str_p, str2_p, VTY_NEWLINE);
>>>>> + XFREE (MTYPE_ECOMMUNITY_STR, str2_p);
>>>>> + }
>>>>> + }
>>>>> + if(vrf->rt_export)
>>>>> + {
>>>>> + str2_p = ecommunity_ecom2str (vrf->rt_export,
>>>>> ECOMMUNITY_FORMAT_ROUTE_MAP);
>>>>> + if(str2_p)
>>>>> + {
>>>>> + vty_out(vty, " vrf rd %s export %s%s", str_p ==
>>>>> NULL?"<err>":str_p, str2_p, VTY_NEWLINE);
>>>>> + XFREE (MTYPE_ECOMMUNITY_STR, str2_p);
>>>>> + }
>>>>> + }
>>>>> + }
>>>>> + }
>>>>> /* maximum-paths */
>>>>> bgp_config_write_maxpaths (vty, bgp, AFI_IP, SAFI_UNICAST, &write);
>>>>>
>>>>> diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h
>>>>> index 0058b581377b..39fbbe5de525 100644
>>>>> --- a/bgpd/bgpd.h
>>>>> +++ b/bgpd/bgpd.h
>>>>> @@ -23,12 +23,23 @@ Software Foundation, Inc., 59 Temple Place - Suite 330,
>>>>> Boston, MA
>>>>>
>>>>> /* For union sockunion. */
>>>>> #include "sockunion.h"
>>>>> +#include "bgp_ecommunity.h"
>>>>> +#include "prefix.h"
>>>>> +#include "vty.h"
>>>>>
>>>>> /* Typedef BGP specific types. */
>>>>> typedef u_int32_t as_t;
>>>>> typedef u_int16_t as16_t; /* we may still encounter 16 Bit asnums */
>>>>> typedef u_int16_t bgp_size_t;
>>>>>
>>>>> +/* BGP router distinguisher value. */
>>>>> +#define BGP_RD_SIZE 8
>>>>> +
>>>>> +struct bgp_rd
>>>>> +{
>>>>> + u_char val[BGP_RD_SIZE];
>>>>> +};
>>>>> +
>>>>> /* BGP master for system wide configurations and variables. */
>>>>> struct bgp_master
>>>>> {
>>>>> @@ -179,6 +190,38 @@ struct bgp
>>>>> u_int16_t maxpaths_ebgp;
>>>>> u_int16_t maxpaths_ibgp;
>>>>> } maxpaths[AFI_MAX][SAFI_MAX];
>>>>> +
>>>>> + /* VRFs */
>>>>> + struct list *vrfs;
>>>>> +
>>>>> + struct hash *rt_subscribers;
>>>>> +
>>>>> +};
>>>>> +
>>>>> +struct bgp_rt_sub
>>>>> +{
>>>>> + struct ecommunity_val rt;
>>>>> +
>>>>> + struct list *vrfs;
>>>>> +};
>>>>> +
>>>>> +struct bgp_vrf
>>>>> +{
>>>>> + struct bgp *bgp;
>>>>> +
>>>>> + /* RD used for route advertisements */
>>>>> + struct prefix_rd outbound_rd;
>>>>> +
>>>>> + /* import and export lists */
>>>>> + struct ecommunity *rt_import;
>>>>> + struct ecommunity *rt_export;
>>>>> +
>>>>> + /* BGP routing information base. */
>>>>> + struct bgp_table *rib[AFI_MAX];
>>>>> +
>>>>> + /* Static route configuration. */
>>>>> + struct bgp_table *route[AFI_MAX];
>>>>> +
>>>>> };
>>>>>
>>>>> /* BGP peer-group support. */
>>>>> @@ -215,14 +258,6 @@ struct bgp_nexthop
>>>>> struct in6_addr v6_local;
>>>>> };
>>>>>
>>>>> -/* BGP router distinguisher value. */
>>>>> -#define BGP_RD_SIZE 8
>>>>> -
>>>>> -struct bgp_rd
>>>>> -{
>>>>> - u_char val[BGP_RD_SIZE];
>>>>> -};
>>>>> -
>>>>> #define RMAP_IN 0
>>>>> #define RMAP_OUT 1
>>>>> #define RMAP_IMPORT 2
>>>>> @@ -999,4 +1034,11 @@ extern int peer_ttl_security_hops_set (struct peer *,
>>>>> int);
>>>>> extern int peer_ttl_security_hops_unset (struct peer *);
>>>>>
>>>>> extern void bgp_scan_finish (void);
>>>>> +extern struct bgp_vrf *bgp_vrf_create (struct bgp *bgp, struct prefix_rd
>>>>> *outbound_rd);
>>>>> +extern struct bgp_vrf *bgp_vrf_lookup (struct bgp *bgp, struct prefix_rd
>>>>> *outbound_rd);
>>>>> +extern void bgp_vrf_delete (struct bgp_vrf *vrf);
>>>>> +extern void bgp_vrf_rt_export_set (struct bgp_vrf *vrf, struct ecommunity
>>>>> *rt_export);
>>>>> +extern void bgp_vrf_rt_import_set (struct bgp_vrf *vrf, struct ecommunity
>>>>> *rt_import);
>>>>> +extern void bgp_vrf_clean_tables (struct bgp_vrf *vrf);
>>>>> +
>>>>> #endif /* _QUAGGA_BGPD_H */
>>>>> diff --git a/lib/memtypes.c b/lib/memtypes.c
>>>>> index 8abe99d2a495..3f5bdd255756 100644
>>>>> --- a/lib/memtypes.c
>>>>> +++ b/lib/memtypes.c
>>>>> @@ -157,6 +157,8 @@ struct memory_list memory_list_bgp[] =
>>>>> { MTYPE_BGP_AGGREGATE, "BGP aggregate" },
>>>>> { MTYPE_BGP_ADDR, "BGP own address" },
>>>>> { MTYPE_ENCAP_TLV, "ENCAP TLV", },
>>>>> + { MTYPE_BGP_VRF, "BGP VRF", },
>>>>> + { MTYPE_BGP_RT_SUB, "BGP Route Target Subscribers" },
>>>>> { -1, NULL }
>>>>> };
>>>>>
>>>>
>>>> _______________________________________________
>>>> Quagga-dev mailing list
>>>> Quagga-dev@lists.quagga.net
>>>> https://lists.quagga.net/mailman/listinfo/quagga-dev
>>
>>
>> _______________________________________________
>> Quagga-dev mailing list
>> Quagga-dev@lists.quagga.net
>> https://lists.quagga.net/mailman/listinfo/quagga-dev
>


_______________________________________________
Quagga-dev mailing list
Quagga-dev@lists.quagga.net
https://lists.quagga.net/mailman/listinfo/quagga-dev
Re: [PATCH v2 1/2] bgpd: VRF vty configuration, RIB table creation [ In reply to ]
On Fri, Oct 21, 2016 at 8:21 PM, Lou Berger <lberger@labn.net> wrote:

Hello Lou,

Thanks for your detailed response,
I agree to configure the RD , and the RT set per VRF.
However, I tried to make a counter proposal about the way to configure it.
You will find it below.
Your comments are welcome.

Best Regards,

Philippe

>> About the concepts you are talking about, I agree with you.
>> Regarding design issue, I think there is a misunderstanding because I
>> link RD with RTs, within a VRF.
>> Whereas you point the following:
>> - associate RD with VPN flows
> Not sure what you mean here.

About linking RD with RTs, this is not correct. You are right.
In previous mail, you underlined the way to associate RD with VPN flows.
So I was thinking about configuring RD per VPN flows.
This is why I used that sentence "associate RD with VPN flows".

> I don't understand what "VPN" means to you or in the config model. BGP
> LxVPNs have VRFs and Route Distribution semantics. Together these
> semantics can be combined to support LxVPNs.


> how about
> vrf <name>
> rd ...
> rt (import|export|both) ...
> network <prefix> [rd ...]
>
In proposed patchwork, vrf is under bgp router subnode.
I think, your proposal refers to reuse vrf command under configuration
mode. Right ?
If that is it, yes. Adaptation is possible.
Or you probably think of keeping the VRF command under bgp router node ?

For RD and RT set dissociation, yes too.
For network command, I don't see the need to move network command
under vrf subnode, whereas there is yet some network commands under
various bgp vpnvx subnodes.
What about keeping network command under address family subnode ?

>> One reason is that this work is pure signalling, there is no dataplane
>> interaction.
>
> As is always the the case for BGP ;-)

Sorry, I am diving one more time into quagga code :-).
The implementation I did does not take into account zebra <-> bgpd
communication, and FIB updates.
That is what I insisted on when I say the work is "pure signalling".

>> Do you see other points to discuss ?
>>
>
> Well, we need to ensure that route distribution happens properly for all
> cases (including RR). See below for more specific comments.

I noticed a problem , using RR with VPNv4.
Actually, this does not work with VPNv4. No BGP updates messages
received from RR.

>>>> Most of the modifications have been done around what is called the
>>>> "VRF structure".
>
> This is good and aligned with the suggestion to move config to be per VRF.

ok

>>>>
>>>> The RD is mapped to that "VRF structure", but the RT also. This is a
>>>> one-to-one mapping.
>>>> That "VRF structure" has a RIB table where RT imports are processed.
>>>>
>
> I think a mapping of VRF to RT set is right. Having a default RD for
> VRF export is also good.
>
>>>> I mean, on the design point of view, I don't make a difference between
>>>> a RD and a RT.
>
> I think this is a mistake. RD is about route (re)distribution
> selection. RT is about topology and VRF control.

yes.

>>>> I just have to ensure that the incoming structure is available to
>>>> import appropriate entries.
>>>> in order to import a RT entry, I have to create a RT mapped to an
>>>> other "VRF structure".
>>>>
>>>> If the RT is not mapped to that "VRF structure", then the RIB
>>>> associated to that RT is not present.
>>>> Then the import in the RIB RT will not be possible.
>
> We have parallel code doing the same in RFAPI.
0
I am looking at the RFAPI : imported_vpn table seems to be the one
that is similar to the VRF table.
I try to find out a solution in order to permit both code live together.
I mean, I code redundancy ( not code duplication) can be possible, no?

>>>>
>>>> To illustrate, a quick example shows that routerA sends a NLRI entry to
>>>> routerB.
>>>>
>>>> routerA> rd 200:111 import 100:111 export 100:111 300:111
>>>> routerA> network 10.10.10.0/24 rd 200:111
>>>> routerB> rd 100:111 import 100:111 export 100:111
>>>>
> is this all under a vpn/vrf config parameter or at the top (bgp) level?
>

see answer above.
currently:
- vrf rd command is under bgp router sub node.
- network is under vpnv4 address family subnode

>>>> RouterB will import NLRI entry to RT 100:111
>
>>>> This is possible because RouterB has the line rd100:111 ... created.
>
> hopefully you really mean because RouterB has the line import 100:111
>
>>>>
>>>> RouterB will not import NLRI entry to RT 300:111, since there is no
>>>> underlying structure.
>
> all good here.
>
>
> Is this a valid entry
> routerA> network 10.10.10.0/24 rd 123:111
>
> assuming the config structure is under "... vpn ..."
> what rt's would be in the update?

If the config structure was under vpn, I think this entry would not be valid.


>>>>
>>>> About "VRF structure", My intention is not to interfere about current
>>>> VRF implementation in Quagga.
>>>> From the configuration point of view, it is easy to find in literature
>>>> cisco configuration where VRF
>>>> and RD configuration maps together.
>
> Sorry, I work from the spec, not cisco manual/docs.
>
>>>> Could you be more specific about the reason to dissociate RD from VRF ?
> the key point to understand is where RDs are used in the processing (VRF
> export and BGP route distribution) and where they are not (VRF import)
> and that RD != VRF.
>
>>>>
>>>> One modification improvement would consist in :
>>>> - That "VRF structure" could be renamed to "RT/RD structure"
> please no! VRF is actually much better.
>
ok

> you'd want a different RD here.
>>>>
>>>> routerC> rd 100:111 import 100:111 export 100:111
>>>>
>>>> When receiving a NLRI entry from routerB), and routerA), bgp_update()
>>>> will append the entry in the global RIB, according to RD field.
>>>>
>>>> routerC> show bgp ipv4 vpn
>>>> Route Distinguisher : 200:111
>>>> *> 10.10.10.0/24 <nexthop_routerA>
>>>> => 10.10.10.0/24 <nexthop_routerB>
>
> of course if you send this via a route reflector only on would be
> recieved -- which is why you need different RDs to get both.

How come BGP does not handle reception of NLRI multipath entries
without addpath feature :-).
You mean this use case should not occur, due to the fact that RDs are
often configured specific for each router.
So, If I reuse the above example, there would not be multipath entry
in the global RIB.
But VRF import processing would shows 2 multipath entries in the VRF RIB 100:111

routerA> rd 200:111 import 100:111 export 100:111
routerA> network 10.10.10.0/24 rd 200:111 <nexthop_routerA>

routerB> rd 300:111 import 100:111 export 100:111
routerB> network 10.10.10.0/24 rd 300:111 <nexthop_routerB>

routerC> rd 100:111 import 100:111 export 100:111
routerC> show bgp ipv4 vpn
Route Distinguisher : 200:111
*> 10.10.10.0/24 <nexthop_routerA>
Route Distinguisher : 300:111
*> 10.10.10.0/24 <nexthop_routerB>

routerC> show ip bgp vrf 100:111
*> 10.10.10.0/24 <nexthop_routerA>
=> 10.10.10.0/24 <nexthop_routerB>

Does RFAPI code permit such result ?

Best Regards,

Philippe

_______________________________________________
Quagga-dev mailing list
Quagga-dev@lists.quagga.net
https://lists.quagga.net/mailman/listinfo/quagga-dev
Re: [PATCH v2 1/2] bgpd: VRF vty configuration, RIB table creation [ In reply to ]
Hi Lou,

+Vivek too

I updated the following google document to VPN discussion, boiled
down to how to config.

https://docs.google.com/document/d/1w_ie2tNXCgn0N3ZNFGYTK6lJkwMmk_XN5yz33MMNNqM/edit?usp=sharing

Please share our feedback about the way to configure VPN.
So that I would do the necessary adaptations for acceptance.
In this document, I would opt for option 4.

BR,

Philippe

On Mon, Oct 24, 2016 at 3:05 PM, Philippe Guibert
<philippe.guibert@6wind.com> wrote:
> On Fri, Oct 21, 2016 at 8:21 PM, Lou Berger <lberger@labn.net> wrote:
>
> Hello Lou,
>
> Thanks for your detailed response,
> I agree to configure the RD , and the RT set per VRF.
> However, I tried to make a counter proposal about the way to configure it.
> You will find it below.
> Your comments are welcome.
>
> Best Regards,
>
> Philippe
>
>>> About the concepts you are talking about, I agree with you.
>>> Regarding design issue, I think there is a misunderstanding because I
>>> link RD with RTs, within a VRF.
>>> Whereas you point the following:
>>> - associate RD with VPN flows
>> Not sure what you mean here.
>
> About linking RD with RTs, this is not correct. You are right.
> In previous mail, you underlined the way to associate RD with VPN flows.
> So I was thinking about configuring RD per VPN flows.
> This is why I used that sentence "associate RD with VPN flows".
>
>> I don't understand what "VPN" means to you or in the config model. BGP
>> LxVPNs have VRFs and Route Distribution semantics. Together these
>> semantics can be combined to support LxVPNs.
>
>
>> how about
>> vrf <name>
>> rd ...
>> rt (import|export|both) ...
>> network <prefix> [rd ...]
>>
> In proposed patchwork, vrf is under bgp router subnode.
> I think, your proposal refers to reuse vrf command under configuration
> mode. Right ?
> If that is it, yes. Adaptation is possible.
> Or you probably think of keeping the VRF command under bgp router node ?
>
> For RD and RT set dissociation, yes too.
> For network command, I don't see the need to move network command
> under vrf subnode, whereas there is yet some network commands under
> various bgp vpnvx subnodes.
> What about keeping network command under address family subnode ?
>
>>> One reason is that this work is pure signalling, there is no dataplane
>>> interaction.
>>
>> As is always the the case for BGP ;-)
>
> Sorry, I am diving one more time into quagga code :-).
> The implementation I did does not take into account zebra <-> bgpd
> communication, and FIB updates.
> That is what I insisted on when I say the work is "pure signalling".
>
>>> Do you see other points to discuss ?
>>>
>>
>> Well, we need to ensure that route distribution happens properly for all
>> cases (including RR). See below for more specific comments.
>
> I noticed a problem , using RR with VPNv4.
> Actually, this does not work with VPNv4. No BGP updates messages
> received from RR.
>
>>>>> Most of the modifications have been done around what is called the
>>>>> "VRF structure".
>>
>> This is good and aligned with the suggestion to move config to be per VRF.
>
> ok
>
>>>>>
>>>>> The RD is mapped to that "VRF structure", but the RT also. This is a
>>>>> one-to-one mapping.
>>>>> That "VRF structure" has a RIB table where RT imports are processed.
>>>>>
>>
>> I think a mapping of VRF to RT set is right. Having a default RD for
>> VRF export is also good.
>>
>>>>> I mean, on the design point of view, I don't make a difference between
>>>>> a RD and a RT.
>>
>> I think this is a mistake. RD is about route (re)distribution
>> selection. RT is about topology and VRF control.
>
> yes.
>
>>>>> I just have to ensure that the incoming structure is available to
>>>>> import appropriate entries.
>>>>> in order to import a RT entry, I have to create a RT mapped to an
>>>>> other "VRF structure".
>>>>>
>>>>> If the RT is not mapped to that "VRF structure", then the RIB
>>>>> associated to that RT is not present.
>>>>> Then the import in the RIB RT will not be possible.
>>
>> We have parallel code doing the same in RFAPI.
> 0
> I am looking at the RFAPI : imported_vpn table seems to be the one
> that is similar to the VRF table.
> I try to find out a solution in order to permit both code live together.
> I mean, I code redundancy ( not code duplication) can be possible, no?
>
>>>>>
>>>>> To illustrate, a quick example shows that routerA sends a NLRI entry to
>>>>> routerB.
>>>>>
>>>>> routerA> rd 200:111 import 100:111 export 100:111 300:111
>>>>> routerA> network 10.10.10.0/24 rd 200:111
>>>>> routerB> rd 100:111 import 100:111 export 100:111
>>>>>
>> is this all under a vpn/vrf config parameter or at the top (bgp) level?
>>
>
> see answer above.
> currently:
> - vrf rd command is under bgp router sub node.
> - network is under vpnv4 address family subnode
>
>>>>> RouterB will import NLRI entry to RT 100:111
>>
>>>>> This is possible because RouterB has the line rd100:111 ... created.
>>
>> hopefully you really mean because RouterB has the line import 100:111
>>
>>>>>
>>>>> RouterB will not import NLRI entry to RT 300:111, since there is no
>>>>> underlying structure.
>>
>> all good here.
>>
>>
>> Is this a valid entry
>> routerA> network 10.10.10.0/24 rd 123:111
>>
>> assuming the config structure is under "... vpn ..."
>> what rt's would be in the update?
>
> If the config structure was under vpn, I think this entry would not be valid.
>
>
>>>>>
>>>>> About "VRF structure", My intention is not to interfere about current
>>>>> VRF implementation in Quagga.
>>>>> From the configuration point of view, it is easy to find in literature
>>>>> cisco configuration where VRF
>>>>> and RD configuration maps together.
>>
>> Sorry, I work from the spec, not cisco manual/docs.
>>
>>>>> Could you be more specific about the reason to dissociate RD from VRF ?
>> the key point to understand is where RDs are used in the processing (VRF
>> export and BGP route distribution) and where they are not (VRF import)
>> and that RD != VRF.
>>
>>>>>
>>>>> One modification improvement would consist in :
>>>>> - That "VRF structure" could be renamed to "RT/RD structure"
>> please no! VRF is actually much better.
>>
> ok
>
>> you'd want a different RD here.
>>>>>
>>>>> routerC> rd 100:111 import 100:111 export 100:111
>>>>>
>>>>> When receiving a NLRI entry from routerB), and routerA), bgp_update()
>>>>> will append the entry in the global RIB, according to RD field.
>>>>>
>>>>> routerC> show bgp ipv4 vpn
>>>>> Route Distinguisher : 200:111
>>>>> *> 10.10.10.0/24 <nexthop_routerA>
>>>>> => 10.10.10.0/24 <nexthop_routerB>
>>
>> of course if you send this via a route reflector only on would be
>> recieved -- which is why you need different RDs to get both.
>
> How come BGP does not handle reception of NLRI multipath entries
> without addpath feature :-).
> You mean this use case should not occur, due to the fact that RDs are
> often configured specific for each router.
> So, If I reuse the above example, there would not be multipath entry
> in the global RIB.
> But VRF import processing would shows 2 multipath entries in the VRF RIB 100:111
>
> routerA> rd 200:111 import 100:111 export 100:111
> routerA> network 10.10.10.0/24 rd 200:111 <nexthop_routerA>
>
> routerB> rd 300:111 import 100:111 export 100:111
> routerB> network 10.10.10.0/24 rd 300:111 <nexthop_routerB>
>
> routerC> rd 100:111 import 100:111 export 100:111
> routerC> show bgp ipv4 vpn
> Route Distinguisher : 200:111
> *> 10.10.10.0/24 <nexthop_routerA>
> Route Distinguisher : 300:111
> *> 10.10.10.0/24 <nexthop_routerB>
>
> routerC> show ip bgp vrf 100:111
> *> 10.10.10.0/24 <nexthop_routerA>
> => 10.10.10.0/24 <nexthop_routerB>
>
> Does RFAPI code permit such result ?
>
> Best Regards,
>
> Philippe

_______________________________________________
Quagga-dev mailing list
Quagga-dev@lists.quagga.net
https://lists.quagga.net/mailman/listinfo/quagga-dev