mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-08-05 08:23:56 +00:00
bgpd: import rt to vrf mapping
Signed-off-by: Mitesh Kanjariya <mitesh@cumulusnetworks.com>
This commit is contained in:
parent
bc59a6720c
commit
10ebe1ab54
281
bgpd/bgp_evpn.c
281
bgpd/bgp_evpn.c
@ -92,6 +92,131 @@ static int vni_hash_cmp(const void *p1, const void *p2)
|
||||
return (vpn1->vni == vpn2->vni);
|
||||
}
|
||||
|
||||
/*
|
||||
* Make vrf import route target hash key.
|
||||
*/
|
||||
static unsigned int vrf_import_rt_hash_key_make(void *p)
|
||||
{
|
||||
struct vrf_irt_node *irt = p;
|
||||
char *pnt = irt->rt.val;
|
||||
unsigned int key = 0;
|
||||
int c = 0;
|
||||
|
||||
key += pnt[c];
|
||||
key += pnt[c + 1];
|
||||
key += pnt[c + 2];
|
||||
key += pnt[c + 3];
|
||||
key += pnt[c + 4];
|
||||
key += pnt[c + 5];
|
||||
key += pnt[c + 6];
|
||||
key += pnt[c + 7];
|
||||
|
||||
return key;
|
||||
}
|
||||
|
||||
/*
|
||||
* Comparison function for vrf import rt hash
|
||||
*/
|
||||
static int vrf_import_rt_hash_cmp(const void *p1, const void *p2)
|
||||
{
|
||||
const struct vrf_irt_node *irt1 = p1;
|
||||
const struct vrf_irt_node *irt2 = p2;
|
||||
|
||||
if (irt1 == NULL && irt2 == NULL)
|
||||
return 1;
|
||||
|
||||
if (irt1 == NULL || irt2 == NULL)
|
||||
return 0;
|
||||
|
||||
return (memcmp(irt1->rt.val, irt2->rt.val, ECOMMUNITY_SIZE) == 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Create a new vrf import_rt in default instance
|
||||
*/
|
||||
static struct vrf_irt_node *vrf_import_rt_new(struct ecommunity_val *rt)
|
||||
{
|
||||
struct bgp *bgp_def = NULL;
|
||||
struct vrf_irt_node *irt;
|
||||
|
||||
bgp_def = bgp_get_default();
|
||||
if (!bgp_def) {
|
||||
zlog_err("vrf import rt new - def instance not created yet");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
irt = XCALLOC(MTYPE_BGP_EVPN_VRF_IMPORT_RT,
|
||||
sizeof(struct vrf_irt_node));
|
||||
if (!irt)
|
||||
return NULL;
|
||||
|
||||
irt->rt = *rt;
|
||||
irt->vrfs = list_new();
|
||||
|
||||
/* Add to hash */
|
||||
if (!hash_get(bgp_def->vrf_import_rt_hash, irt, hash_alloc_intern)) {
|
||||
XFREE(MTYPE_BGP_EVPN_VRF_IMPORT_RT, irt);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return irt;
|
||||
}
|
||||
|
||||
/*
|
||||
* Free the vrf import rt node
|
||||
*/
|
||||
static void vrf_import_rt_free(struct vrf_irt_node *irt)
|
||||
{
|
||||
struct bgp *bgp_def = NULL;
|
||||
|
||||
bgp_def = bgp_get_default();
|
||||
if (!bgp_def) {
|
||||
zlog_err("vrf import rt free - def instance not created yet");
|
||||
return;
|
||||
}
|
||||
|
||||
hash_release(bgp_def->vrf_import_rt_hash, irt);
|
||||
XFREE(MTYPE_BGP_EVPN_VRF_IMPORT_RT, irt);
|
||||
}
|
||||
|
||||
/*
|
||||
* Function to lookup Import RT node - used to map a RT to set of
|
||||
* VNIs importing routes with that RT.
|
||||
*/
|
||||
static struct vrf_irt_node *lookup_vrf_import_rt(struct ecommunity_val *rt)
|
||||
{
|
||||
struct bgp *bgp_def = NULL;
|
||||
struct vrf_irt_node *irt;
|
||||
struct vrf_irt_node tmp;
|
||||
|
||||
bgp_def = bgp_get_default();
|
||||
if (!bgp_def) {
|
||||
zlog_err("vrf import rt lookup - def instance not created yet");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(&tmp, 0, sizeof(struct vrf_irt_node));
|
||||
memcpy(&tmp.rt, rt, ECOMMUNITY_SIZE);
|
||||
irt = hash_lookup(bgp_def->vrf_import_rt_hash, &tmp);
|
||||
return irt;
|
||||
}
|
||||
|
||||
/*
|
||||
* Is specified VRF present on the RT's list of "importing" VRFs?
|
||||
*/
|
||||
static int is_vrf_present_in_irt_vrfs(struct list *vrfs,
|
||||
struct bgp *bgp_vrf)
|
||||
{
|
||||
struct listnode *node = NULL, *nnode = NULL;
|
||||
struct bgp *tmp_bgp_vrf = NULL;
|
||||
|
||||
for (ALL_LIST_ELEMENTS(vrfs, node, nnode, tmp_bgp_vrf)) {
|
||||
if (tmp_bgp_vrf == bgp_vrf)
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Make import route target hash key.
|
||||
*/
|
||||
@ -246,6 +371,57 @@ static inline void mask_ecom_global_admin(struct ecommunity_val *dst,
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Map one RT to specified VRF.
|
||||
* bgp_vrf = BGP vrf instance
|
||||
*/
|
||||
static void map_vrf_to_rt(struct bgp *bgp_vrf,
|
||||
struct ecommunity_val *eval)
|
||||
{
|
||||
struct vrf_irt_node *irt = NULL;
|
||||
struct ecommunity_val eval_tmp;
|
||||
|
||||
/* If using "automatic" RT,
|
||||
* we only care about the local-admin sub-field.
|
||||
* This is to facilitate using L3VNI(VRF-VNI)
|
||||
* as the RT for EBGP peering too.
|
||||
*/
|
||||
memcpy(&eval_tmp, eval, ECOMMUNITY_SIZE);
|
||||
if (!CHECK_FLAG(bgp_vrf->vrf_flags,
|
||||
BGP_VRF_IMPORT_RT_CFGD))
|
||||
mask_ecom_global_admin(&eval_tmp, eval);
|
||||
|
||||
irt = lookup_vrf_import_rt(&eval_tmp);
|
||||
if (irt && irt->vrfs)
|
||||
if (is_vrf_present_in_irt_vrfs(irt->vrfs, bgp_vrf))
|
||||
/* Already mapped. */
|
||||
return;
|
||||
|
||||
if (!irt) {
|
||||
irt = vrf_import_rt_new(&eval_tmp);
|
||||
assert(irt);
|
||||
}
|
||||
|
||||
/* Add VRF to the list for this RT. */
|
||||
listnode_add(irt->vrfs, bgp_vrf);
|
||||
}
|
||||
|
||||
/*
|
||||
* Unmap specified VRF from specified RT. If there are no other
|
||||
* VRFs for this RT, then the RT hash is deleted.
|
||||
* bgp_vrf: BGP VRF specific instance
|
||||
*/
|
||||
static void unmap_vrf_from_rt(struct bgp *bgp_vrf,
|
||||
struct vrf_irt_node *irt)
|
||||
{
|
||||
/* Delete VRF from list for this RT. */
|
||||
listnode_delete(irt->vrfs, bgp_vrf);
|
||||
if (!listnode_head(irt->vrfs)) {
|
||||
list_free(irt->vrfs);
|
||||
vrf_import_rt_free(irt);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Map one RT to specified VNI.
|
||||
*/
|
||||
@ -2135,8 +2311,16 @@ static void free_vni_entry(struct hash_backet *backet, struct bgp *bgp)
|
||||
*/
|
||||
static void evpn_auto_rt_import_add_for_vrf(struct bgp *bgp_vrf)
|
||||
{
|
||||
UNSET_FLAG(bgp_vrf->vrf_flags, BGP_VRF_IMPORT_RT_CFGD);
|
||||
struct bgp *bgp_def = NULL;
|
||||
|
||||
form_auto_rt(bgp_vrf, bgp_vrf->l3vni, bgp_vrf->vrf_import_rtl);
|
||||
UNSET_FLAG(bgp_vrf->vrf_flags, BGP_VRF_IMPORT_RT_CFGD);
|
||||
|
||||
/* Map RT to VRF */
|
||||
bgp_def = bgp_get_default();
|
||||
if (!bgp_def)
|
||||
return;
|
||||
bgp_evpn_map_vrf_to_its_rts(bgp_vrf);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -2209,8 +2393,13 @@ void evpn_rt_delete_auto(struct bgp *bgp, vni_t vni,
|
||||
}
|
||||
|
||||
void bgp_evpn_configure_import_rt_for_vrf(struct bgp *bgp_vrf,
|
||||
struct ecommunity *ecomadd)
|
||||
struct ecommunity *ecomadd)
|
||||
{
|
||||
//TODO_MITESH: uninstall routes from VRF
|
||||
|
||||
/* Cleanup the RT to VRF mapping */
|
||||
bgp_evpn_unmap_vrf_from_its_rts(bgp_vrf);
|
||||
|
||||
/* Remove auto generated RT */
|
||||
evpn_auto_rt_import_delete_for_vrf(bgp_vrf);
|
||||
|
||||
@ -2218,8 +2407,10 @@ void bgp_evpn_configure_import_rt_for_vrf(struct bgp *bgp_vrf,
|
||||
listnode_add_sort(bgp_vrf->vrf_import_rtl, ecomadd);
|
||||
SET_FLAG(bgp_vrf->vrf_flags, BGP_VRF_IMPORT_RT_CFGD);
|
||||
|
||||
//TODO_MITESH: handle RT change (uninstall old routes and install new
|
||||
//routes matching this RT)
|
||||
/* map VRF to its RTs */
|
||||
bgp_evpn_map_vrf_to_its_rts(bgp_vrf);
|
||||
|
||||
//TODO_MITESH: install routes matching the new VRF
|
||||
}
|
||||
|
||||
void bgp_evpn_unconfigure_import_rt_for_vrf(struct bgp *bgp_vrf,
|
||||
@ -2228,6 +2419,11 @@ void bgp_evpn_unconfigure_import_rt_for_vrf(struct bgp *bgp_vrf,
|
||||
struct listnode *node = NULL, *nnode = NULL, *node_to_del = NULL;
|
||||
struct ecommunity *ecom = NULL;
|
||||
|
||||
//TODO_MITESH: uninstall routes from VRF
|
||||
|
||||
/* Cleanup the RT to VRF mapping */
|
||||
bgp_evpn_unmap_vrf_from_its_rts(bgp_vrf);
|
||||
|
||||
/* remove the RT from the RT list */
|
||||
for (ALL_LIST_ELEMENTS(bgp_vrf->vrf_import_rtl, node, nnode, ecom)) {
|
||||
if (ecommunity_match(ecom, ecomdel)) {
|
||||
@ -2246,8 +2442,10 @@ void bgp_evpn_unconfigure_import_rt_for_vrf(struct bgp *bgp_vrf,
|
||||
evpn_auto_rt_import_add_for_vrf(bgp_vrf);
|
||||
}
|
||||
|
||||
//TODO_MITESH: handle import RT change
|
||||
//uninstall old routes, install new routes matching this RT
|
||||
/* map VRFs to its RTs */
|
||||
bgp_evpn_map_vrf_to_its_rts(bgp_vrf);
|
||||
|
||||
//TODO_MITESH: install routes matching this new RT
|
||||
}
|
||||
|
||||
void bgp_evpn_configure_export_rt_for_vrf(struct bgp *bgp_vrf,
|
||||
@ -2632,6 +2830,65 @@ int bgp_nlri_parse_evpn(struct peer *peer, struct attr *attr,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Map the RTs (configured or automatically derived) of a VRF to the VRF.
|
||||
* The mapping will be used during route processing.
|
||||
* bgp_def: default bgp instance
|
||||
* bgp_vrf: specific bgp vrf instance on which RT is configured
|
||||
*/
|
||||
void bgp_evpn_map_vrf_to_its_rts(struct bgp *bgp_vrf)
|
||||
{
|
||||
int i = 0;
|
||||
struct ecommunity_val *eval = NULL;
|
||||
struct listnode *node = NULL, *nnode = NULL;
|
||||
struct ecommunity *ecom = NULL;
|
||||
|
||||
for (ALL_LIST_ELEMENTS(bgp_vrf->vrf_import_rtl, node, nnode, ecom)) {
|
||||
for (i = 0; i < ecom->size; i++) {
|
||||
eval = (struct ecommunity_val *)(ecom->val
|
||||
+ (i
|
||||
* ECOMMUNITY_SIZE));
|
||||
map_vrf_to_rt(bgp_vrf, eval);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Unmap the RTs (configured or automatically derived) of a VRF from the VRF.
|
||||
*/
|
||||
void bgp_evpn_unmap_vrf_from_its_rts(struct bgp *bgp_vrf)
|
||||
{
|
||||
int i;
|
||||
struct ecommunity_val *eval;
|
||||
struct listnode *node, *nnode;
|
||||
struct ecommunity *ecom;
|
||||
|
||||
for (ALL_LIST_ELEMENTS(bgp_vrf->vrf_import_rtl, node, nnode, ecom)) {
|
||||
for (i = 0; i < ecom->size; i++) {
|
||||
struct vrf_irt_node *irt;
|
||||
struct ecommunity_val eval_tmp;
|
||||
|
||||
eval = (struct ecommunity_val *)(ecom->val
|
||||
+ (i
|
||||
* ECOMMUNITY_SIZE));
|
||||
/* If using "automatic" RT, we only care about the
|
||||
* local-admin sub-field.
|
||||
* This is to facilitate using VNI as the RT for EBGP
|
||||
* peering too.
|
||||
*/
|
||||
memcpy(&eval_tmp, eval, ECOMMUNITY_SIZE);
|
||||
if (!CHECK_FLAG(bgp_vrf->vrf_flags,
|
||||
BGP_VRF_IMPORT_RT_CFGD))
|
||||
mask_ecom_global_admin(&eval_tmp, eval);
|
||||
|
||||
irt = lookup_vrf_import_rt(&eval_tmp);
|
||||
if (irt)
|
||||
unmap_vrf_from_rt(bgp_vrf, irt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Map the RTs (configured or automatically derived) of a VNI to the VNI.
|
||||
@ -3071,6 +3328,7 @@ int bgp_evpn_local_l3vni_del(vni_t l3vni,
|
||||
|
||||
/* delete RD/RT */
|
||||
if (bgp_vrf->vrf_import_rtl && !list_isempty(bgp_vrf->vrf_import_rtl)) {
|
||||
bgp_evpn_unmap_vrf_from_its_rts(bgp_vrf);
|
||||
list_delete(bgp_vrf->vrf_import_rtl);
|
||||
bgp_vrf->vrf_import_rtl = NULL;
|
||||
}
|
||||
@ -3236,6 +3494,9 @@ void bgp_evpn_cleanup(struct bgp *bgp)
|
||||
if (bgp->import_rt_hash)
|
||||
hash_free(bgp->import_rt_hash);
|
||||
bgp->import_rt_hash = NULL;
|
||||
if (bgp->vrf_import_rt_hash)
|
||||
hash_free(bgp->vrf_import_rt_hash);
|
||||
bgp->vrf_import_rt_hash = NULL;
|
||||
if (bgp->vnihash)
|
||||
hash_free(bgp->vnihash);
|
||||
bgp->vnihash = NULL;
|
||||
@ -3265,6 +3526,9 @@ void bgp_evpn_init(struct bgp *bgp)
|
||||
bgp->import_rt_hash =
|
||||
hash_create(import_rt_hash_key_make, import_rt_hash_cmp,
|
||||
"BGP Import RT Hash");
|
||||
bgp->vrf_import_rt_hash =
|
||||
hash_create(vrf_import_rt_hash_key_make, vrf_import_rt_hash_cmp,
|
||||
"BGP VRF Import RT Hash");
|
||||
bgp->vrf_import_rtl = list_new();
|
||||
bgp->vrf_import_rtl->cmp =
|
||||
(int (*)(void *, void *))evpn_route_target_cmp;
|
||||
@ -3279,3 +3543,8 @@ void bgp_evpn_init(struct bgp *bgp)
|
||||
/*assign 0th index in the bitfield, so that we start with id 1*/
|
||||
bf_assign_zero_index(bgp->rd_idspace);
|
||||
}
|
||||
|
||||
void bgp_evpn_vrf_delete(struct bgp *bgp_vrf)
|
||||
{
|
||||
bgp_evpn_unmap_vrf_from_its_rts(bgp_vrf);
|
||||
}
|
||||
|
@ -25,6 +25,7 @@
|
||||
|
||||
#define EVPN_ROUTE_STRLEN 200 /* Must be >> MAC + IPv6 strings. */
|
||||
|
||||
extern void bgp_evpn_vrf_delete(struct bgp *);
|
||||
extern void bgp_evpn_handle_router_id_update(struct bgp *bgp, int withdraw);
|
||||
extern char *bgp_evpn_label2str(mpls_label_t *label, char *buf, int len);
|
||||
extern char *bgp_evpn_route2str(struct prefix_evpn *p, char *buf, int len);
|
||||
|
@ -97,6 +97,19 @@ struct irt_node {
|
||||
struct list *vnis;
|
||||
};
|
||||
|
||||
/* Mapping of Import RT to VRFs.
|
||||
* The Import RTs of all VRFss are maintained in a hash table with each
|
||||
* RT linking to all VRFs that will import routes matching this RT.
|
||||
*/
|
||||
struct vrf_irt_node {
|
||||
/* RT */
|
||||
struct ecommunity_val rt;
|
||||
|
||||
/* List of VNIs importing routes matching this RT. */
|
||||
struct list *vrfs;
|
||||
};
|
||||
|
||||
|
||||
#define RT_TYPE_IMPORT 1
|
||||
#define RT_TYPE_EXPORT 2
|
||||
#define RT_TYPE_BOTH 3
|
||||
@ -285,6 +298,8 @@ extern void bgp_evpn_handle_rd_change(struct bgp *bgp, struct bgpevpn *vpn,
|
||||
int withdraw);
|
||||
extern int bgp_evpn_install_routes(struct bgp *bgp, struct bgpevpn *vpn);
|
||||
extern int bgp_evpn_uninstall_routes(struct bgp *bgp, struct bgpevpn *vpn);
|
||||
extern void bgp_evpn_map_vrf_to_its_rts(struct bgp *);
|
||||
extern void bgp_evpn_unmap_vrf_from_its_rts(struct bgp *);
|
||||
extern void bgp_evpn_map_vni_to_its_rts(struct bgp *bgp, struct bgpevpn *vpn);
|
||||
extern void bgp_evpn_unmap_vni_from_its_rts(struct bgp *bgp,
|
||||
struct bgpevpn *vpn);
|
||||
|
@ -53,6 +53,117 @@ struct vni_walk_ctx {
|
||||
};
|
||||
|
||||
#if defined(HAVE_CUMULUS)
|
||||
static void display_vrf_import_rt(struct vty *vty,
|
||||
struct vrf_irt_node *irt,
|
||||
json_object *json)
|
||||
{
|
||||
u_char *pnt;
|
||||
u_char type, sub_type;
|
||||
struct ecommunity_as eas;
|
||||
struct ecommunity_ip eip;
|
||||
struct listnode *node, *nnode;
|
||||
struct bgp *tmp_bgp_vrf = NULL;
|
||||
json_object *json_rt = NULL;
|
||||
json_object *json_vrfs = NULL;
|
||||
char rt_buf[RT_ADDRSTRLEN];
|
||||
|
||||
if (json) {
|
||||
json_rt = json_object_new_object();
|
||||
json_vrfs = json_object_new_array();
|
||||
}
|
||||
|
||||
pnt = (u_char *)&irt->rt.val;
|
||||
type = *pnt++;
|
||||
sub_type = *pnt++;
|
||||
if (sub_type != ECOMMUNITY_ROUTE_TARGET)
|
||||
return;
|
||||
|
||||
memset(&eas, 0, sizeof(eas));
|
||||
switch (type) {
|
||||
case ECOMMUNITY_ENCODE_AS:
|
||||
eas.as = (*pnt++ << 8);
|
||||
eas.as |= (*pnt++);
|
||||
pnt = ptr_get_be32(pnt, &eas.val);
|
||||
|
||||
snprintf(rt_buf, RT_ADDRSTRLEN, "%u:%u", eas.as, eas.val);
|
||||
|
||||
if (json)
|
||||
json_object_string_add(json_rt, "rt", rt_buf);
|
||||
else
|
||||
vty_out(vty, "Route-target: %s", rt_buf);
|
||||
|
||||
break;
|
||||
|
||||
case ECOMMUNITY_ENCODE_IP:
|
||||
memcpy(&eip.ip, pnt, 4);
|
||||
pnt += 4;
|
||||
eip.val = (*pnt++ << 8);
|
||||
eip.val |= (*pnt++);
|
||||
|
||||
snprintf(rt_buf, RT_ADDRSTRLEN, "%s:%u", inet_ntoa(eip.ip),
|
||||
eip.val);
|
||||
|
||||
if (json)
|
||||
json_object_string_add(json_rt, "rt", rt_buf);
|
||||
else
|
||||
vty_out(vty, "Route-target: %s", rt_buf);
|
||||
|
||||
break;
|
||||
|
||||
case ECOMMUNITY_ENCODE_AS4:
|
||||
pnt = ptr_get_be32(pnt, &eas.val);
|
||||
eas.val = (*pnt++ << 8);
|
||||
eas.val |= (*pnt++);
|
||||
|
||||
snprintf(rt_buf, RT_ADDRSTRLEN, "%u:%u", eas.as, eas.val);
|
||||
|
||||
if (json)
|
||||
json_object_string_add(json_rt, "rt", rt_buf);
|
||||
else
|
||||
vty_out(vty, "Route-target: %s", rt_buf);
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
if (!json) {
|
||||
vty_out(vty,
|
||||
"\nList of VRFs importing routes with this route-target:\n");
|
||||
}
|
||||
|
||||
for (ALL_LIST_ELEMENTS(irt->vrfs, node, nnode, tmp_bgp_vrf)) {
|
||||
if (json)
|
||||
json_object_array_add(
|
||||
json_vrfs,
|
||||
json_object_new_string(
|
||||
vrf_id_to_name(
|
||||
tmp_bgp_vrf->vrf_id)));
|
||||
else
|
||||
vty_out(vty, " %s\n",
|
||||
vrf_id_to_name(tmp_bgp_vrf->vrf_id));
|
||||
}
|
||||
|
||||
if (json) {
|
||||
json_object_object_add(json_rt, "vrfs", json_vrfs);
|
||||
json_object_object_add(json, rt_buf, json_rt);
|
||||
}
|
||||
}
|
||||
|
||||
static void show_vrf_import_rt_entry(struct hash_backet *backet,
|
||||
void *args[])
|
||||
{
|
||||
json_object *json = NULL;
|
||||
struct vty *vty = NULL;
|
||||
struct vrf_irt_node *irt = (struct vrf_irt_node *)backet->data;
|
||||
|
||||
vty = args[0];
|
||||
json = args[1];
|
||||
|
||||
display_vrf_import_rt(vty, irt, json);
|
||||
}
|
||||
|
||||
static void display_import_rt(struct vty *vty, struct irt_node *irt,
|
||||
json_object *json)
|
||||
{
|
||||
@ -1432,6 +1543,25 @@ static int evpn_delete_vni(struct bgp *bgp, struct bgpevpn *vpn)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Display import RT mapping to VRFs (vty handler)
|
||||
* bgp_def: default bgp instance
|
||||
*/
|
||||
static void evpn_show_vrf_import_rts(struct vty *vty,
|
||||
struct bgp *bgp_def,
|
||||
json_object *json)
|
||||
{
|
||||
void *args[2];
|
||||
|
||||
args[0] = vty;
|
||||
args[1] = json;
|
||||
|
||||
hash_iterate(bgp_def->vrf_import_rt_hash,
|
||||
(void (*)(struct hash_backet *, void *))
|
||||
show_vrf_import_rt_entry,
|
||||
args);
|
||||
}
|
||||
|
||||
/*
|
||||
* Display import RT mapping to VNIs (vty handler)
|
||||
*/
|
||||
@ -2765,6 +2895,42 @@ DEFUN(show_bgp_l2vpn_evpn_route_vni_all,
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
* Display EVPN import route-target hash table
|
||||
*/
|
||||
DEFUN(show_bgp_l2vpn_evpn_vrf_import_rt,
|
||||
show_bgp_l2vpn_evpn_vrf_import_rt_cmd,
|
||||
"show bgp l2vpn evpn vrf-import-rt [json]",
|
||||
SHOW_STR
|
||||
BGP_STR
|
||||
L2VPN_HELP_STR
|
||||
EVPN_HELP_STR
|
||||
"Show vrf import route target\n"
|
||||
JSON_STR)
|
||||
{
|
||||
u_char uj = 0;
|
||||
struct bgp *bgp_def;
|
||||
json_object *json = NULL;
|
||||
|
||||
bgp_def = bgp_get_default();
|
||||
if (!bgp_def)
|
||||
return CMD_WARNING;
|
||||
|
||||
uj = use_json(argc, argv);
|
||||
if (uj)
|
||||
json = json_object_new_object();
|
||||
|
||||
evpn_show_vrf_import_rts(vty, bgp_def, json);
|
||||
|
||||
if (uj) {
|
||||
vty_out(vty, "%s\n", json_object_to_json_string_ext(
|
||||
json, JSON_C_TO_STRING_PRETTY));
|
||||
json_object_free(json);
|
||||
}
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
* Display EVPN import route-target hash table
|
||||
*/
|
||||
@ -3536,6 +3702,7 @@ void bgp_ethernetvpn_init(void)
|
||||
install_element(VIEW_NODE, &show_bgp_l2vpn_evpn_route_vni_macip_cmd);
|
||||
install_element(VIEW_NODE, &show_bgp_l2vpn_evpn_route_vni_all_cmd);
|
||||
install_element(VIEW_NODE, &show_bgp_l2vpn_evpn_import_rt_cmd);
|
||||
install_element(VIEW_NODE, &show_bgp_l2vpn_evpn_vrf_import_rt_cmd);
|
||||
|
||||
/* "show bgp evpn" commands. */
|
||||
install_element(VIEW_NODE, &show_bgp_evpn_vni_cmd);
|
||||
|
@ -117,4 +117,5 @@ DEFINE_MTYPE(BGPD, LCOMMUNITY_VAL, "Large Community value")
|
||||
|
||||
DEFINE_MTYPE(BGPD, BGP_EVPN, "BGP EVPN Information")
|
||||
DEFINE_MTYPE(BGPD, BGP_EVPN_IMPORT_RT, "BGP EVPN Import RT")
|
||||
DEFINE_MTYPE(BGPD, BGP_EVPN_VRF_IMPORT_RT, "BGP EVPN VRF Import RT")
|
||||
DEFINE_MTYPE(BGPD, BGP_EVPN_MACIP, "BGP EVPN MAC IP")
|
||||
|
@ -113,5 +113,6 @@ DECLARE_MTYPE(LCOMMUNITY_VAL)
|
||||
|
||||
DECLARE_MTYPE(BGP_EVPN)
|
||||
DECLARE_MTYPE(BGP_EVPN_IMPORT_RT)
|
||||
DECLARE_MTYPE(BGP_EVPN_VRF_IMPORT_RT)
|
||||
DECLARE_MTYPE(BGP_EVPN_MACIP)
|
||||
#endif /* _QUAGGA_BGP_MEMORY_H */
|
||||
|
@ -3139,6 +3139,9 @@ int bgp_delete(struct bgp *bgp)
|
||||
bgp->name);
|
||||
}
|
||||
|
||||
/* unmap from RT list */
|
||||
bgp_evpn_vrf_delete(bgp);
|
||||
|
||||
/* Stop timers. */
|
||||
if (bgp->t_rmap_def_originate_eval) {
|
||||
BGP_TIMER_OFF(bgp->t_rmap_def_originate_eval);
|
||||
|
@ -406,6 +406,9 @@ struct bgp {
|
||||
/* Hash table of Import RTs to EVIs */
|
||||
struct hash *import_rt_hash;
|
||||
|
||||
/* Hash table of VRF import RTs to VRFs */
|
||||
struct hash *vrf_import_rt_hash;
|
||||
|
||||
/* Id space for automatic RD derivation for an EVI */
|
||||
bitfield_t rd_idspace;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user