mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-08-06 09:00:55 +00:00
bgpd: evpn mh changes to advertise EAD routes with user configured export-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>
This commit is contained in:
parent
0cd8bce123
commit
f4a5218dc6
@ -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;
|
||||
@ -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);
|
||||
@ -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);
|
||||
|
||||
@ -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.
|
||||
|
@ -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);
|
||||
@ -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
|
||||
@ -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;
|
||||
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
/****************************************************************************/
|
||||
@ -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 */
|
||||
|
@ -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 */
|
||||
|
@ -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",
|
||||
@ -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)
|
||||
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user