From c589d84746d96c1714582e437eb9cec691795252 Mon Sep 17 00:00:00 2001 From: Anuradha Karuppiah Date: Fri, 8 May 2020 19:24:56 -0700 Subject: [PATCH] bgpd: L3NHG infrastructure for host routes in EVPN ES-VRF entries are maintained for the purpose of L3-NHG creation - 1. Each ES-EVI entry is associated with a tenant VRF. This associaton triggers the creation of an ES-VRF entry. 2. Type-2/MAC-IP routes are imported into a tenant VRF and programmed as a /32 or host route entry in the dataplane. If the destination of the host route is a remote-ES the route is programmed with the corresponding (keyed in by {vrf,ES-id}) L3-NHG. 3. The reason for this indirection (route->L3-NHG, L3-NHG->list-of-VTEPs) is to avoid route updates to the dplane when a remote-ES link flaps i.e. instead of updating all the dependent routes the NHG's contents are updated. This reduces the amount of dataplane updates (fewer nhg updates vs. route updates) allowing for a faster failover. Signed-off-by: Anuradha Karuppiah --- bgpd/bgp_evpn_mh.c | 278 ++++++++++++++++++++++++++++++++++++++++ bgpd/bgp_evpn_mh.h | 36 ++++++ bgpd/bgp_evpn_private.h | 7 + bgpd/bgp_main.c | 2 + bgpd/bgp_memory.c | 1 + bgpd/bgp_memory.h | 1 + bgpd/bgp_nht.c | 38 ++++++ bgpd/bgp_nht.h | 6 + bgpd/bgpd.c | 2 + bgpd/bgpd.h | 6 + 10 files changed, 377 insertions(+) diff --git a/bgpd/bgp_evpn_mh.c b/bgpd/bgp_evpn_mh.c index bf9a2f849a..39523ea206 100644 --- a/bgpd/bgp_evpn_mh.c +++ b/bgpd/bgp_evpn_mh.c @@ -48,6 +48,7 @@ #include "bgpd/bgp_zebra.h" #include "bgpd/bgp_addpath.h" #include "bgpd/bgp_label.h" +#include "bgpd/bgp_nht.h" static void bgp_evpn_local_es_down(struct bgp *bgp, struct bgp_evpn_es *es); @@ -63,6 +64,8 @@ static void bgp_evpn_es_vtep_del(struct bgp *bgp, static void bgp_evpn_es_cons_checks_pend_add(struct bgp_evpn_es *es); static void bgp_evpn_es_cons_checks_pend_del(struct bgp_evpn_es *es); static void bgp_evpn_local_es_evi_do_del(struct bgp_evpn_es_evi *es_evi); +static uint32_t bgp_evpn_es_get_active_vtep_cnt(struct bgp_evpn_es *es); +static void bgp_evpn_l3nhg_update_on_vtep_chg(struct bgp_evpn_es *es); esi_t zero_esi_buf, *zero_esi = &zero_esi_buf; @@ -1228,6 +1231,9 @@ static void bgp_evpn_es_vtep_re_eval_active(struct bgp *bgp, /* send remote ES to zebra */ bgp_zebra_send_remote_es_vtep(bgp, es_vtep, new_active); + /* update L3NHG associated with the ES */ + bgp_evpn_l3nhg_update_on_vtep_chg(es_vtep->es); + /* queue up the es for background consistency checks */ bgp_evpn_es_cons_checks_pend_add(es_vtep->es); } @@ -1351,6 +1357,10 @@ static struct bgp_evpn_es *bgp_evpn_es_new(struct bgp *bgp, const esi_t *esi) es->es_evi_list = list_new(); listset_app_node_mem(es->es_evi_list); + /* Initialise the ES-VRF list used for L3NHG management */ + es->es_vrf_list = list_new(); + listset_app_node_mem(es->es_vrf_list); + QOBJ_REG(es, bgp_evpn_es); return es; @@ -1370,6 +1380,7 @@ static void bgp_evpn_es_free(struct bgp_evpn_es *es, const char *caller) /* cleanup resources maintained against the ES */ list_delete(&es->es_evi_list); + list_delete(&es->es_vrf_list); list_delete(&es->es_vtep_list); bgp_table_unlock(es->route_table); @@ -1940,6 +1951,269 @@ void bgp_evpn_es_show_esi(struct vty *vty, esi_t *esi, bool uj) } } +/*****************************************************************************/ +/* Ethernet Segment to VRF association - + * 1. Each ES-EVI entry is associated with a tenant VRF. This associaton + * triggers the creation of an ES-VRF entry. + * 2. The ES-VRF entry is maintained for the purpose of L3-NHG creation + * 3. Type-2/MAC-IP routes are imported into a tenant VRF and programmed as + * a /32 or host route entry in the dataplane. If the destination of + * the host route is a remote-ES the route is programmed with the + * corresponding (keyed in by {vrf,ES-id}) L3-NHG. + * 4. The reason for this indirection (route->L3-NHG, L3-NHG->list-of-VTEPs) + * is to avoid route updates to the dplane when a remote-ES link flaps i.e. + * instead of updating all the dependent routes the NHG's contents are updated. + * This reduces the amount of datplane updates (nhg updates vs. route updates) + * allowing for a faster failover. + * + * XXX - can the L3 SVI index change without change in vpn->bgp_vrf + * association? If yes we need to handle that by updating all the L3 NHGs + * in that VRF. + */ +/******************************** L3 NHG management *************************/ +static void bgp_evpn_l3nhg_zebra_add(struct bgp_evpn_es_vrf *es_vrf) +{ + uint32_t nh_cnt = 0; + struct listnode *node; + struct bgp_evpn_es_vtep *es_vtep; + struct bgp_evpn_es *es = es_vrf->es; + + if (BGP_DEBUG(evpn_mh, EVPN_MH_ES)) + zlog_debug("es %s vrf %u nhg 0x%x to zebra", es->esi_str, + es_vrf->bgp_vrf->vrf_id, es_vrf->nhg_id); + for (ALL_LIST_ELEMENTS_RO(es->es_vtep_list, node, es_vtep)) { + if (CHECK_FLAG(es_vtep->flags, BGP_EVPNES_VTEP_ACTIVE)) { + ++nh_cnt; + if (BGP_DEBUG(evpn_mh, EVPN_MH_ES)) + zlog_debug("nhg 0x%x vtep %pI4 dev 0x%x", + es_vrf->nhg_id, &es_vtep->vtep_ip, + es_vrf->bgp_vrf->l3vni_svi_ifindex); + } + } + + /* XXX - program NHG in zebra */ +} + +static void bgp_evpn_l3nhg_zebra_del(struct bgp_evpn_es_vrf *es_vrf) +{ + if (BGP_DEBUG(evpn_mh, EVPN_MH_ES)) + zlog_debug("es %s vrf %u nhg 0x%x to zebra", + es_vrf->es->esi_str, es_vrf->bgp_vrf->vrf_id, + es_vrf->nhg_id); + + /* XXX - program NHG in zebra */ +} + +static void bgp_evpn_l3nhg_deactivate(struct bgp_evpn_es_vrf *es_vrf) +{ + if (!(es_vrf->flags & BGP_EVPNES_VRF_NHG_ACTIVE)) + return; + + if (BGP_DEBUG(evpn_mh, EVPN_MH_ES)) + zlog_debug("es %s vrf %u nhg 0x%x de-activate", + es_vrf->es->esi_str, es_vrf->bgp_vrf->vrf_id, + es_vrf->nhg_id); + bgp_evpn_l3nhg_zebra_del(es_vrf); + es_vrf->flags &= ~BGP_EVPNES_VRF_NHG_ACTIVE; +} + +static void bgp_evpn_l3nhg_activate(struct bgp_evpn_es_vrf *es_vrf, bool update) +{ + if (!bgp_evpn_es_get_active_vtep_cnt(es_vrf->es)) { + bgp_evpn_l3nhg_deactivate(es_vrf); + return; + } + + if (es_vrf->flags & BGP_EVPNES_VRF_NHG_ACTIVE) { + if (!update) + return; + } else { + if (BGP_DEBUG(evpn_mh, EVPN_MH_ES)) + zlog_debug("es %s vrf %u nhg 0x%x activate", + es_vrf->es->esi_str, es_vrf->bgp_vrf->vrf_id, + es_vrf->nhg_id); + es_vrf->flags |= BGP_EVPNES_VRF_NHG_ACTIVE; + } + + bgp_evpn_l3nhg_zebra_add(es_vrf); +} + +/* when a VTEP is activated or de-activated against an ES associated + * VRFs' NHG needs to be updated + */ +static void bgp_evpn_l3nhg_update_on_vtep_chg(struct bgp_evpn_es *es) +{ + struct bgp_evpn_es_vrf *es_vrf; + struct listnode *es_vrf_node; + + if (BGP_DEBUG(evpn_mh, EVPN_MH_ES)) + zlog_debug("es %s nhg update on vtep chg", es->esi_str); + + for (ALL_LIST_ELEMENTS_RO(es->es_vrf_list, es_vrf_node, es_vrf)) + bgp_evpn_l3nhg_activate(es_vrf, true /* update */); +} + +/* compare ES-IDs for the ES-VRF RB tree maintained per-VRF */ +static int bgp_es_vrf_rb_cmp(const struct bgp_evpn_es_vrf *es_vrf1, + const struct bgp_evpn_es_vrf *es_vrf2) +{ + return memcmp(&es_vrf1->es->esi, &es_vrf2->es->esi, ESI_BYTES); +} +RB_GENERATE(bgp_es_vrf_rb_head, bgp_evpn_es_vrf, rb_node, bgp_es_vrf_rb_cmp); + +/* Initialize the ES tables maintained per-tenant vrf */ +void bgp_evpn_vrf_es_init(struct bgp *bgp_vrf) +{ + /* Initialize the ES-VRF RB tree */ + RB_INIT(bgp_es_vrf_rb_head, &bgp_vrf->es_vrf_rb_tree); +} + +/* find the ES-VRF in the per-VRF RB tree */ +static struct bgp_evpn_es_vrf *bgp_evpn_es_vrf_find(struct bgp_evpn_es *es, + struct bgp *bgp_vrf) +{ + struct bgp_evpn_es_vrf es_vrf; + + es_vrf.es = es; + + return RB_FIND(bgp_es_vrf_rb_head, &bgp_vrf->es_vrf_rb_tree, &es_vrf); +} + +/* allocate a new ES-VRF and setup L3NHG for it */ +static struct bgp_evpn_es_vrf *bgp_evpn_es_vrf_create(struct bgp_evpn_es *es, + struct bgp *bgp_vrf) +{ + struct bgp_evpn_es_vrf *es_vrf; + + es_vrf = XCALLOC(MTYPE_BGP_EVPN_ES_VRF, sizeof(*es_vrf)); + + es_vrf->es = es; + es_vrf->bgp_vrf = bgp_vrf; + + /* insert into the VRF-ESI rb tree */ + if (RB_INSERT(bgp_es_vrf_rb_head, &bgp_vrf->es_vrf_rb_tree, es_vrf)) { + XFREE(MTYPE_BGP_EVPN_ES_VRF, es_vrf); + return NULL; + } + + /* add to the ES's VRF list */ + listnode_init(&es_vrf->es_listnode, es_vrf); + listnode_add(es->es_vrf_list, &es_vrf->es_listnode); + + /* setup the L3 NHG id for the ES */ + es_vrf->nhg_id = bgp_l3nhg_id_alloc(); + if (BGP_DEBUG(evpn_mh, EVPN_MH_ES)) + zlog_debug("es %s vrf %u nhg 0x%x create", es->esi_str, + bgp_vrf->vrf_id, es_vrf->nhg_id); + bgp_evpn_l3nhg_activate(es_vrf, false /* update */); + + return es_vrf; +} + +/* remove the L3-NHG associated with the ES-VRF and free it */ +static void bgp_evpn_es_vrf_delete(struct bgp_evpn_es_vrf *es_vrf) +{ + struct bgp_evpn_es *es = es_vrf->es; + struct bgp *bgp_vrf = es_vrf->bgp_vrf; + + if (BGP_DEBUG(evpn_mh, EVPN_MH_ES)) + zlog_debug("es %s vrf %u nhg 0x%x delete", es->esi_str, + bgp_vrf->vrf_id, es_vrf->nhg_id); + + /* Remove the NHG resources */ + bgp_evpn_l3nhg_deactivate(es_vrf); + if (es_vrf->nhg_id) + bgp_l3nhg_id_free(es_vrf->nhg_id); + es_vrf->nhg_id = 0; + + /* remove from the ES's VRF list */ + list_delete_node(es->es_vrf_list, &es_vrf->es_listnode); + + /* remove from the VRF-ESI rb tree */ + RB_REMOVE(bgp_es_vrf_rb_head, &bgp_vrf->es_vrf_rb_tree, es_vrf); + + XFREE(MTYPE_BGP_EVPN_ES_VRF, es_vrf); +} + +/* deref and delete if there are no references */ +void bgp_evpn_es_vrf_deref(struct bgp_evpn_es_evi *es_evi) +{ + struct bgp_evpn_es_vrf *es_vrf = es_evi->es_vrf; + + if (!es_vrf) + return; + + if (BGP_DEBUG(evpn_mh, EVPN_MH_ES)) + zlog_debug("es-evi %s vni %u vrf %u de-ref", + es_evi->es->esi_str, es_evi->vpn->vni, + es_vrf->bgp_vrf->vrf_id); + + es_evi->es_vrf = NULL; + if (es_vrf->ref_cnt) + --es_vrf->ref_cnt; + + if (!es_vrf->ref_cnt) + bgp_evpn_es_vrf_delete(es_vrf); +} + +/* find or create and reference */ +void bgp_evpn_es_vrf_ref(struct bgp_evpn_es_evi *es_evi, struct bgp *bgp_vrf) +{ + struct bgp_evpn_es *es = es_evi->es; + struct bgp_evpn_es_vrf *es_vrf = es_evi->es_vrf; + struct bgp *old_bgp_vrf = NULL; + + if (es_vrf) + old_bgp_vrf = es_vrf->bgp_vrf; + + if (old_bgp_vrf == bgp_vrf) + return; + + /* deref the old ES-VRF */ + bgp_evpn_es_vrf_deref(es_evi); + + if (!bgp_vrf) + return; + + if (BGP_DEBUG(evpn_mh, EVPN_MH_ES)) + zlog_debug("es-evi %s vni %u vrf %u ref", es_evi->es->esi_str, + es_evi->vpn->vni, bgp_vrf->vrf_id); + + /* find-create the new ES-VRF */ + es_vrf = bgp_evpn_es_vrf_find(es, bgp_vrf); + if (!es_vrf) + es_vrf = bgp_evpn_es_vrf_create(es, bgp_vrf); + if (!es_vrf) + return; + + es_evi->es_vrf = es_vrf; + ++es_vrf->ref_cnt; +} + +/* When the L2-VNI is associated with a L3-VNI/VRF update all the + * associated ES-EVI entries + */ +void bgp_evpn_es_evi_vrf_deref(struct bgpevpn *vpn) +{ + struct bgp_evpn_es_evi *es_evi; + + if (BGP_DEBUG(evpn_mh, EVPN_MH_ES)) + zlog_debug("es-vrf de-ref for vni %u", vpn->vni); + + RB_FOREACH (es_evi, bgp_es_evi_rb_head, &vpn->es_evi_rb_tree) + bgp_evpn_es_vrf_deref(es_evi); +} +void bgp_evpn_es_evi_vrf_ref(struct bgpevpn *vpn) +{ + struct bgp_evpn_es_evi *es_evi; + + if (BGP_DEBUG(evpn_mh, EVPN_MH_ES)) + zlog_debug("es-vrf ref for vni %u", vpn->vni); + + RB_FOREACH (es_evi, bgp_es_evi_rb_head, &vpn->es_evi_rb_tree) + bgp_evpn_es_vrf_ref(es_evi, vpn->bgp_vrf); +} + /*****************************************************************************/ /* Ethernet Segment to EVI association - * 1. The ES-EVI entry is maintained as a RB tree per L2-VNI @@ -2152,6 +2426,8 @@ static struct bgp_evpn_es_evi *bgp_evpn_es_evi_new(struct bgp_evpn_es *es, listnode_init(&es_evi->es_listnode, es_evi); listnode_add(es->es_evi_list, &es_evi->es_listnode); + bgp_evpn_es_vrf_ref(es_evi, vpn->bgp_vrf); + return es_evi; } @@ -2169,6 +2445,8 @@ static void bgp_evpn_es_evi_free(struct bgp_evpn_es_evi *es_evi) if (es_evi->flags & (BGP_EVPNES_EVI_LOCAL | BGP_EVPNES_EVI_REMOTE)) return; + bgp_evpn_es_vrf_deref(es_evi); + /* remove from the ES's VNI list */ list_delete_node(es->es_evi_list, &es_evi->es_listnode); diff --git a/bgpd/bgp_evpn_mh.h b/bgpd/bgp_evpn_mh.h index d719524bdd..bf957e581a 100644 --- a/bgpd/bgp_evpn_mh.h +++ b/bgpd/bgp_evpn_mh.h @@ -96,6 +96,9 @@ struct bgp_evpn_es { /* List of ES-EVIs associated with this ES */ struct list *es_evi_list; + /* List of ES-VRFs associated with this ES */ + struct list *es_vrf_list; + /* Number of remote VNIs referencing this ES */ uint32_t remote_es_evi_cnt; @@ -142,6 +145,33 @@ struct bgp_evpn_es_vtep { struct listnode es_listnode; }; +/* ES-VRF element needed for managing L3 NHGs. It is implicitly created + * when an ES-EVI is associated with a tenant VRF + */ +struct bgp_evpn_es_vrf { + struct bgp_evpn_es *es; + struct bgp *bgp_vrf; + + uint32_t flags; +/* NHG can only be activated if there are active VTEPs in the ES and + * there is a valid L3-VNI associated with the VRF + */ +#define BGP_EVPNES_VRF_NHG_ACTIVE (1 << 0) + + /* memory used for adding the es_vrf to + * es_vrf->bgp_vrf->es_vrf_rb_tree + */ + RB_ENTRY(bgp_evpn_es_vrf) rb_node; + + /* memory used for linking the es_vrf to es_vrf->es->es_vrf_list */ + struct listnode es_listnode; + + uint32_t nhg_id; + + /* Number of ES-EVI entries associated with this ES-VRF */ + uint32_t ref_cnt; +}; + /* ES per-EVI info * - ES-EVIs are maintained per-L2-VNI (vpn->es_evi_rb_tree) * - ES-EVIs are also linked to the parent ES (es->es_evi_list) @@ -175,6 +205,8 @@ struct bgp_evpn_es_evi { /* list of PEs (bgp_evpn_es_evi_vtep) attached to the ES for this VNI */ struct list *es_evi_vtep_list; + + struct bgp_evpn_es_vrf *es_vrf; }; /* PE attached to an ES for a VNI. This entry is created when an EAD-per-ES @@ -308,5 +340,9 @@ void bgp_evpn_es_evi_show_vni(struct vty *vty, vni_t vni, void bgp_evpn_es_evi_show(struct vty *vty, bool uj, bool detail); struct bgp_evpn_es *bgp_evpn_es_find(const esi_t *esi); extern bool bgp_evpn_is_esi_local(esi_t *esi); +extern void bgp_evpn_vrf_es_init(struct bgp *bgp_vrf); +extern void bgp_evpn_es_vrf_deref(struct bgp_evpn_es_evi *es_evi); +extern void bgp_evpn_es_vrf_ref(struct bgp_evpn_es_evi *es_evi, + struct bgp *bgp_vrf); #endif /* _FRR_BGP_EVPN_MH_H */ diff --git a/bgpd/bgp_evpn_private.h b/bgpd/bgp_evpn_private.h index c47576c00c..e8e68c8387 100644 --- a/bgpd/bgp_evpn_private.h +++ b/bgpd/bgp_evpn_private.h @@ -218,6 +218,9 @@ static inline struct list *bgpevpn_get_vrf_import_rtl(struct bgpevpn *vpn) return vpn->bgp_vrf->vrf_import_rtl; } +extern void bgp_evpn_es_evi_vrf_ref(struct bgpevpn *vpn); +extern void bgp_evpn_es_evi_vrf_deref(struct bgpevpn *vpn); + static inline void bgpevpn_unlink_from_l3vni(struct bgpevpn *vpn) { /* bail if vpn is not associated to bgp_vrf */ @@ -227,6 +230,8 @@ static inline void bgpevpn_unlink_from_l3vni(struct bgpevpn *vpn) UNSET_FLAG(vpn->flags, VNI_FLAG_USE_TWO_LABELS); listnode_delete(vpn->bgp_vrf->l2vnis, vpn); + bgp_evpn_es_evi_vrf_deref(vpn); + /* remove the backpointer to the vrf instance */ bgp_unlock(vpn->bgp_vrf); vpn->bgp_vrf = NULL; @@ -255,6 +260,8 @@ static inline void bgpevpn_link_to_l3vni(struct bgpevpn *vpn) if (bgp_vrf->l3vni && !CHECK_FLAG(bgp_vrf->vrf_flags, BGP_VRF_L3VNI_PREFIX_ROUTES_ONLY)) SET_FLAG(vpn->flags, VNI_FLAG_USE_TWO_LABELS); + + bgp_evpn_es_evi_vrf_ref(vpn); } static inline int is_vni_configured(struct bgpevpn *vpn) diff --git a/bgpd/bgp_main.c b/bgpd/bgp_main.c index 21c880e95b..f961647778 100644 --- a/bgpd/bgp_main.c +++ b/bgpd/bgp_main.c @@ -63,6 +63,7 @@ #include "lib/routing_nb.h" #include "bgpd/bgp_nb.h" #include "bgpd/bgp_evpn_mh.h" +#include "bgpd/bgp_nht.h" #ifdef ENABLE_BGP_VNC #include "bgpd/rfapi/rfapi_backend.h" @@ -209,6 +210,7 @@ static __attribute__((__noreturn__)) void bgp_exit(int status) bgp_delete(bgp_default); bgp_evpn_mh_finish(); + bgp_l3nhg_finish(); /* reverse bgp_dump_init */ bgp_dump_finish(); diff --git a/bgpd/bgp_memory.c b/bgpd/bgp_memory.c index d8fc98e048..1582b90a2e 100644 --- a/bgpd/bgp_memory.c +++ b/bgpd/bgp_memory.c @@ -121,6 +121,7 @@ DEFINE_MTYPE(BGPD, BGP_EVPN_ES_VTEP, "BGP EVPN ES VTEP") DEFINE_MTYPE(BGPD, BGP_EVPN_ES_EVI_VTEP, "BGP EVPN ES-EVI VTEP") DEFINE_MTYPE(BGPD, BGP_EVPN_ES, "BGP EVPN ESI Information") DEFINE_MTYPE(BGPD, BGP_EVPN_ES_EVI, "BGP EVPN ES-per-EVI Information") +DEFINE_MTYPE(BGPD, BGP_EVPN_ES_VRF, "BGP EVPN ES-per-VRF 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") diff --git a/bgpd/bgp_memory.h b/bgpd/bgp_memory.h index d1ae392c65..058fa4b295 100644 --- a/bgpd/bgp_memory.h +++ b/bgpd/bgp_memory.h @@ -114,6 +114,7 @@ DECLARE_MTYPE(LCOMMUNITY_VAL) DECLARE_MTYPE(BGP_EVPN_MH_INFO) DECLARE_MTYPE(BGP_EVPN_ES) DECLARE_MTYPE(BGP_EVPN_ES_EVI) +DECLARE_MTYPE(BGP_EVPN_ES_VRF) DECLARE_MTYPE(BGP_EVPN_ES_VTEP) DECLARE_MTYPE(BGP_EVPN_ES_EVI_VTEP) diff --git a/bgpd/bgp_nht.c b/bgpd/bgp_nht.c index 9635fe1224..f4acf379fc 100644 --- a/bgpd/bgp_nht.c +++ b/bgpd/bgp_nht.c @@ -966,3 +966,41 @@ void bgp_nht_dereg_enhe_cap_intfs(struct peer *peer) 0); } } + +/**************************************************************************** + * L3 NHGs are used for fast failover of nexthops in the dplane. These are + * the APIs for allocating L3 NHG ids. Management of the L3 NHG itself is + * left to the application using it. + * PS: Currently EVPN host routes is the only app using L3 NHG for fast + * failover of remote ES links. + ***************************************************************************/ +static bitfield_t bgp_nh_id_bitmap; + +uint32_t bgp_l3nhg_id_alloc(void) +{ + uint32_t nhg_id = 0; + + bf_assign_index(bgp_nh_id_bitmap, nhg_id); + + return nhg_id; +} + +void bgp_l3nhg_id_free(uint32_t nhg_id) +{ + if (!nhg_id) + return; + + bf_release_index(bgp_nh_id_bitmap, nhg_id); +} + +void bgp_l3nhg_init(void) +{ +#define BGP_NH_ID_MAX (16 * 1024) + bf_init(bgp_nh_id_bitmap, BGP_NH_ID_MAX); + bf_assign_zero_index(bgp_nh_id_bitmap); +} + +void bgp_l3nhg_finish(void) +{ + bf_free(bgp_nh_id_bitmap); +} diff --git a/bgpd/bgp_nht.h b/bgpd/bgp_nht.h index 4e015e4aae..8451f0689d 100644 --- a/bgpd/bgp_nht.h +++ b/bgpd/bgp_nht.h @@ -90,4 +90,10 @@ extern void bgp_nht_register_nexthops(struct bgp *bgp); extern void bgp_nht_reg_enhe_cap_intfs(struct peer *peer); extern void bgp_nht_dereg_enhe_cap_intfs(struct peer *peer); +/* APIs for setting up and allocating L3 nexthop group ids */ +extern uint32_t bgp_l3nhg_id_alloc(void); +extern void bgp_l3nhg_id_free(uint32_t nhg_id); +extern void bgp_l3nhg_init(void); +void bgp_l3nhg_finish(void); + #endif /* _BGP_NHT_H */ diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index 25f3526a23..82ce0c3882 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -3156,6 +3156,7 @@ static struct bgp *bgp_create(as_t *as, const char *name, sizeof(struct bgp_evpn_info)); bgp_evpn_init(bgp); + bgp_evpn_vrf_es_init(bgp); bgp_pbr_init(bgp); /*initilize global GR FSM */ @@ -7327,6 +7328,7 @@ void bgp_master_init(struct thread_master *master, const int buffer_size) /* mpls label dynamic allocation pool */ bgp_lp_init(bm->master, &bm->labelpool); + bgp_l3nhg_init(); bgp_evpn_mh_init(); QOBJ_REG(bm, bgp_master); } diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index d22fd008d8..965a35b345 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -302,6 +302,9 @@ enum bgp_link_bw_handling { BGP_LINK_BW_DEFWT_4_MISSING }; +RB_HEAD(bgp_es_vrf_rb_head, bgp_evpn_es_vrf); +RB_PROTOTYPE(bgp_es_vrf_rb_head, bgp_evpn_es_vrf, rb_node, bgp_es_vrf_rb_cmp); + /* BGP instance structure. */ struct bgp { /* AS number of this BGP instance. */ @@ -637,6 +640,9 @@ struct bgp { /* SVI associated with the L3-VNI corresponding to this vrf */ ifindex_t l3vni_svi_ifindex; + /* RB tree of ES-VRFs */ + struct bgp_es_vrf_rb_head es_vrf_rb_tree; + /* vrf flags */ uint32_t vrf_flags; #define BGP_VRF_AUTO (1 << 0) -- 2.39.5