Mailing List Archive

[PATCH v3 3/5] 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 | 192 +++++++++++++++++++++++++++++++++++++++++++++++++++--
bgpd/bgp_route.h | 4 ++
bgpd/bgp_table.h | 3 +
bgpd/bgp_vty.c | 177 +++++++++++++++++++++++++++++++++++++++++++++++++
bgpd/bgpd.c | 199 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-
bgpd/bgpd.h | 57 +++++++++++++---
lib/memtypes.c | 2 +
7 files changed, 620 insertions(+), 14 deletions(-)

diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c
index 4cb6c141bcdc..eb0c9e50094f 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,6 @@ 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_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..15245ceeb8d2 100644
--- a/bgpd/bgpd.h
+++ b/bgpd/bgpd.h
@@ -23,12 +23,22 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA

/* For union sockunion. */
#include "sockunion.h"
+#include "bgp_ecommunity.h"
+#include "prefix.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 +189,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 +257,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 +1033,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 632aadc92415..75f77a8e13fb 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 RT SUB", },
{ -1, NULL }
};

--
2.1.4


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