Skip to content

Commit

Permalink
bgpd: evpn mh changes to advertise EAD routes with user configured ex…
Browse files Browse the repository at this point in the history
…port-rt

This is an alternate to EAD route fragmenation and allows the user to limit
the route to a single UPDATE (<4K) independent of the number of EVIs.

Sample config (add one l2-vni RT from each VRF) -
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
!
router bgp 5556
 !
 address-family l2vpn evpn
  ead-es-route-target export 5556:1001
  ead-es-route-target export 5556:1004
  ead-es-route-target export 5556:1008
 exit-address-family
!
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

Sample route
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
   Network          Next Hop            Metric LocPrf Weight Path
*> [1]:[4294967295]:[03:44:38:39:ff:ff:01:00:00:01]:[32]:[27.0.0.21]
                    27.0.0.21                          32768 i
                    ET:8 ESI-label-Rt:AA RT:5556:1001 RT:5556:1004 RT:5556:1008
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

When configured, the ead-es-route-target is used instead of
the auto-generated version that includes all associated EVI's RTs.

Ticket: #2632967

Signed-off-by: Anuradha Karuppiah <anuradhak@nvidia.com>
  • Loading branch information
AnuradhaKaruppiah authored and donaldsharp committed Mar 18, 2022
1 parent 0cd8bce commit f4a5218
Show file tree
Hide file tree
Showing 5 changed files with 199 additions and 20 deletions.
24 changes: 13 additions & 11 deletions bgpd/bgp_evpn.c
Original file line number Diff line number Diff line change
Expand Up @@ -325,8 +325,8 @@ static int is_vni_present_in_irt_vnis(struct list *vnis, struct bgpevpn *vpn)
/*
* Compare Route Targets.
*/
static int evpn_route_target_cmp(struct ecommunity *ecom1,
struct ecommunity *ecom2)
int bgp_evpn_route_target_cmp(struct ecommunity *ecom1,
struct ecommunity *ecom2)
{
if (ecom1 && !ecom2)
return -1;
Expand All @@ -349,7 +349,7 @@ static int evpn_route_target_cmp(struct ecommunity *ecom1,
return strcmp(ecom1->str, ecom2->str);
}

static void evpn_xxport_delete_ecomm(void *val)
void bgp_evpn_xxport_delete_ecomm(void *val)
{
struct ecommunity *ecomm = val;
ecommunity_free(&ecomm);
Expand Down Expand Up @@ -5318,11 +5318,13 @@ struct bgpevpn *bgp_evpn_new(struct bgp *bgp, vni_t vni,

/* Initialize route-target import and export lists */
vpn->import_rtl = list_new();
vpn->import_rtl->cmp = (int (*)(void *, void *))evpn_route_target_cmp;
vpn->import_rtl->del = evpn_xxport_delete_ecomm;
vpn->import_rtl->cmp =
(int (*)(void *, void *))bgp_evpn_route_target_cmp;
vpn->import_rtl->del = bgp_evpn_xxport_delete_ecomm;
vpn->export_rtl = list_new();
vpn->export_rtl->cmp = (int (*)(void *, void *))evpn_route_target_cmp;
vpn->export_rtl->del = evpn_xxport_delete_ecomm;
vpn->export_rtl->cmp =
(int (*)(void *, void *))bgp_evpn_route_target_cmp;
vpn->export_rtl->del = bgp_evpn_xxport_delete_ecomm;
bf_assign_index(bm->rd_idspace, vpn->rd_id);
derive_rd_rt_for_vni(bgp, vpn);

Expand Down Expand Up @@ -6023,12 +6025,12 @@ void bgp_evpn_init(struct bgp *bgp)
"BGP VRF Import RT Hash");
bgp->vrf_import_rtl = list_new();
bgp->vrf_import_rtl->cmp =
(int (*)(void *, void *))evpn_route_target_cmp;
bgp->vrf_import_rtl->del = evpn_xxport_delete_ecomm;
(int (*)(void *, void *))bgp_evpn_route_target_cmp;
bgp->vrf_import_rtl->del = bgp_evpn_xxport_delete_ecomm;
bgp->vrf_export_rtl = list_new();
bgp->vrf_export_rtl->cmp =
(int (*)(void *, void *))evpn_route_target_cmp;
bgp->vrf_export_rtl->del = evpn_xxport_delete_ecomm;
(int (*)(void *, void *))bgp_evpn_route_target_cmp;
bgp->vrf_export_rtl->del = bgp_evpn_xxport_delete_ecomm;
bgp->l2vnis = list_new();
bgp->l2vnis->cmp = vni_list_cmp;
/* By default Duplicate Address Dection is enabled.
Expand Down
98 changes: 89 additions & 9 deletions bgpd/bgp_evpn_mh.c
Original file line number Diff line number Diff line change
Expand Up @@ -880,16 +880,21 @@ static void bgp_evpn_type1_es_route_extcomm_build(struct bgp_evpn_es *es,
/* XXX - suppress EAD-ES advertisment if there are no EVIs associated
* with it.
*/
for (ALL_LIST_ELEMENTS_RO(es->es_evi_list,
evi_node, es_evi)) {
if (!CHECK_FLAG(es_evi->flags, BGP_EVPNES_EVI_LOCAL))
continue;
for (ALL_LIST_ELEMENTS_RO(es_evi->vpn->export_rtl,
rt_node, ecom))
if (listcount(bgp_mh_info->ead_es_export_rtl)) {
for (ALL_LIST_ELEMENTS_RO(bgp_mh_info->ead_es_export_rtl,
rt_node, ecom))
bgp_attr_set_ecommunity(
attr,
ecommunity_merge(bgp_attr_get_ecommunity(attr),
ecom));
attr, ecommunity_merge(attr->ecommunity, ecom));
} else {
for (ALL_LIST_ELEMENTS_RO(es->es_evi_list, evi_node, es_evi)) {
if (!CHECK_FLAG(es_evi->flags, BGP_EVPNES_EVI_LOCAL))
continue;
for (ALL_LIST_ELEMENTS_RO(es_evi->vpn->export_rtl,
rt_node, ecom))
bgp_attr_set_ecommunity(
attr, ecommunity_merge(attr->ecommunity,
ecom));
}
}

attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES);
Expand Down Expand Up @@ -1199,6 +1204,76 @@ int bgp_evpn_type1_route_process(struct peer *peer, afi_t afi, safi_t safi,
return ret;
}

void bgp_evpn_mh_config_ead_export_rt(struct bgp *bgp,
struct ecommunity *ecomcfg, bool del)
{
struct listnode *node, *nnode, *node_to_del;
struct ecommunity *ecom;
struct prefix_evpn p;
struct bgp_evpn_es *es;

if (del) {
if (ecomcfg == NULL) {
/* Reset to default and process all routes. */
for (ALL_LIST_ELEMENTS(bgp_mh_info->ead_es_export_rtl,
node, nnode, ecom)) {
ecommunity_free(&ecom);
list_delete_node(bgp_mh_info->ead_es_export_rtl,
node);
}
}

/* Delete a specific export RT */
else {
node_to_del = NULL;

for (ALL_LIST_ELEMENTS(bgp_mh_info->ead_es_export_rtl,
node, nnode, ecom)) {
if (ecommunity_match(ecom, ecomcfg)) {
ecommunity_free(&ecom);
node_to_del = node;
break;
}
}

if (node_to_del)
list_delete_node(bgp_mh_info->ead_es_export_rtl,
node_to_del);
}
} else {
listnode_add_sort(bgp_mh_info->ead_es_export_rtl, ecomcfg);
}

if (BGP_DEBUG(evpn_mh, EVPN_MH_RT))
zlog_debug("local ES del/re-add EAD route on export RT change");
/*
* walk through all active ESs withdraw the old EAD and
* generate a new one
*/
RB_FOREACH (es, bgp_es_rb_head, &bgp_mh_info->es_rb_tree) {
if (!bgp_evpn_is_es_local(es) ||
!bgp_evpn_local_es_is_active(es))
continue;

build_evpn_type1_prefix(&p, BGP_EVPN_AD_ES_ETH_TAG, &es->esi,
es->originator_ip);

if (BGP_DEBUG(evpn_mh, EVPN_MH_RT))
zlog_debug(
"local ES %s del/re-add EAD route on export RT change",
es->esi_str);

/*
* withdraw EAD-ES. XXX - this should technically not be
* needed; can be removed after testing
*/
bgp_evpn_type1_es_route_delete(bgp, es, &p);

/* generate EAD-ES */
bgp_evpn_type1_route_update(bgp, es, NULL, &p);
}
}

/*****************************************************************************/
/* Ethernet Segment Management
* 1. Ethernet Segment is a collection of links attached to the same
Expand Down Expand Up @@ -4664,6 +4739,10 @@ void bgp_evpn_mh_init(void)

bgp_mh_info->ead_evi_rx = BGP_EVPN_MH_EAD_EVI_RX_DEF;
bgp_mh_info->ead_evi_tx = BGP_EVPN_MH_EAD_EVI_TX_DEF;
bgp_mh_info->ead_es_export_rtl = list_new();
bgp_mh_info->ead_es_export_rtl->cmp =
(int (*)(void *, void *))bgp_evpn_route_target_cmp;
bgp_mh_info->ead_es_export_rtl->del = bgp_evpn_xxport_delete_ecomm;

/* config knobs - XXX add cli to control it */
bgp_mh_info->ead_evi_adv_for_down_links = true;
Expand Down Expand Up @@ -4692,6 +4771,7 @@ void bgp_evpn_mh_finish(void)
thread_cancel(&bgp_mh_info->t_cons_check);
list_delete(&bgp_mh_info->local_es_list);
list_delete(&bgp_mh_info->pend_es_list);
list_delete(&bgp_mh_info->ead_es_export_rtl);

XFREE(MTYPE_BGP_EVPN_MH_INFO, bgp_mh_info);
}
Expand Down
7 changes: 7 additions & 0 deletions bgpd/bgp_evpn_mh.h
Original file line number Diff line number Diff line change
Expand Up @@ -310,6 +310,11 @@ struct bgp_evpn_mh_info {
bool suppress_l3_ecomm_on_inactive_es;
/* Setup EVPN PE nexthops and their RMAC in bgpd */
bool bgp_evpn_nh_setup;

/* If global export-rts are configured that is used for sending
* sending the ead-per-es route instead of the L2-VNI(s) RTs
*/
struct list *ead_es_export_rtl;
};

/****************************************************************************/
Expand Down Expand Up @@ -434,5 +439,7 @@ extern void bgp_evpn_nh_finish(struct bgp *bgp_vrf);
extern void bgp_evpn_nh_show(struct vty *vty, bool uj);
extern void bgp_evpn_path_nh_add(struct bgp *bgp_vrf, struct bgp_path_info *pi);
extern void bgp_evpn_path_nh_del(struct bgp *bgp_vrf, struct bgp_path_info *pi);
extern void bgp_evpn_mh_config_ead_export_rt(struct bgp *bgp,
struct ecommunity *ecom, bool del);

#endif /* _FRR_BGP_EVPN_MH_H */
3 changes: 3 additions & 0 deletions bgpd/bgp_evpn_private.h
Original file line number Diff line number Diff line change
Expand Up @@ -656,4 +656,7 @@ extern int bgp_evpn_route_entry_install_if_vrf_match(struct bgp *bgp_vrf,
struct bgp_path_info *pi,
int install);
extern void bgp_evpn_import_type2_route(struct bgp_path_info *pi, int import);
extern void bgp_evpn_xxport_delete_ecomm(void *val);
extern int bgp_evpn_route_target_cmp(struct ecommunity *ecom1,
struct ecommunity *ecom2);
#endif /* _BGP_EVPN_PRIVATE_H */
87 changes: 87 additions & 0 deletions bgpd/bgp_evpn_vty.c
Original file line number Diff line number Diff line change
Expand Up @@ -5992,6 +5992,74 @@ DEFUN (no_bgp_evpn_vrf_rt,
return CMD_SUCCESS;
}

DEFUN(bgp_evpn_ead_es_rt, bgp_evpn_ead_es_rt_cmd,
"ead-es-route-target export RT",
"EAD ES Route Target\n"
"export\n"
"Route target (A.B.C.D:MN|EF:OPQR|GHJK:MN)\n")
{
struct bgp *bgp = VTY_GET_CONTEXT(bgp);
struct ecommunity *ecomadd = NULL;

if (!bgp)
return CMD_WARNING;

if (!EVPN_ENABLED(bgp)) {
vty_out(vty, "This command is only supported under EVPN VRF\n");
return CMD_WARNING;
}

/* Add/update the export route-target */
ecomadd = ecommunity_str2com(argv[2]->arg, ECOMMUNITY_ROUTE_TARGET, 0);
if (!ecomadd) {
vty_out(vty, "%% Malformed Route Target list\n");
return CMD_WARNING;
}
ecommunity_str(ecomadd);

/* Do nothing if we already have this export route-target */
if (!bgp_evpn_rt_matches_existing(bgp_mh_info->ead_es_export_rtl,
ecomadd))
bgp_evpn_mh_config_ead_export_rt(bgp, ecomadd, false);

return CMD_SUCCESS;
}

DEFUN(no_bgp_evpn_ead_es_rt, no_bgp_evpn_ead_es_rt_cmd,
"no ead-es-route-target export RT",
NO_STR
"EAD ES Route Target\n"
"export\n" EVPN_ASN_IP_HELP_STR)
{
struct bgp *bgp = VTY_GET_CONTEXT(bgp);
struct ecommunity *ecomdel = NULL;

if (!bgp)
return CMD_WARNING;

if (!EVPN_ENABLED(bgp)) {
vty_out(vty, "This command is only supported under EVPN VRF\n");
return CMD_WARNING;
}

ecomdel = ecommunity_str2com(argv[3]->arg, ECOMMUNITY_ROUTE_TARGET, 0);
if (!ecomdel) {
vty_out(vty, "%% Malformed Route Target list\n");
return CMD_WARNING;
}
ecommunity_str(ecomdel);

if (!bgp_evpn_rt_matches_existing(bgp_mh_info->ead_es_export_rtl,
ecomdel)) {
vty_out(vty,
"%% RT specified does not match EAD-ES RT configuration\n");
return CMD_WARNING;
}
bgp_evpn_mh_config_ead_export_rt(bgp, ecomdel, true);

return CMD_SUCCESS;
}

DEFUN (bgp_evpn_vni_rt,
bgp_evpn_vni_rt_cmd,
"route-target <both|import|export> RT",
Expand Down Expand Up @@ -6321,6 +6389,23 @@ void bgp_config_write_evpn_info(struct vty *vty, struct bgp *bgp, afi_t afi,
vty_out(vty, " advertise ipv4 unicast gateway-ip\n");
}

/* EAD ES export route-target */
if (listcount(bgp_mh_info->ead_es_export_rtl)) {
struct ecommunity *ecom;
char *ecom_str;
struct listnode *node;

for (ALL_LIST_ELEMENTS_RO(bgp_mh_info->ead_es_export_rtl, node,
ecom)) {

ecom_str = ecommunity_ecom2str(
ecom, ECOMMUNITY_FORMAT_ROUTE_MAP, 0);
vty_out(vty, " ead-es-route-target export %s\n",
ecom_str);
XFREE(MTYPE_ECOMMUNITY_STR, ecom_str);
}
}

if (CHECK_FLAG(bgp->af_flags[AFI_L2VPN][SAFI_EVPN],
BGP_L2VPN_EVPN_ADV_IPV6_UNICAST)) {
if (bgp->adv_cmd_rmap[AFI_IP6][SAFI_UNICAST].name)
Expand Down Expand Up @@ -6506,6 +6591,8 @@ void bgp_ethernetvpn_init(void)
install_element(BGP_NODE, &no_bgp_evpn_vrf_rd_without_val_cmd);
install_element(BGP_EVPN_NODE, &bgp_evpn_vrf_rt_cmd);
install_element(BGP_EVPN_NODE, &no_bgp_evpn_vrf_rt_cmd);
install_element(BGP_EVPN_NODE, &bgp_evpn_ead_es_rt_cmd);
install_element(BGP_EVPN_NODE, &no_bgp_evpn_ead_es_rt_cmd);
install_element(BGP_EVPN_VNI_NODE, &bgp_evpn_advertise_svi_ip_vni_cmd);
install_element(BGP_EVPN_VNI_NODE,
&bgp_evpn_advertise_default_gw_vni_cmd);
Expand Down

0 comments on commit f4a5218

Please sign in to comment.