Commit 981474b85b for frr
commit 981474b85b0b214d06b1435ec6d381027c995762
Author: Robin Christ <r.christ@partimus.com>
Date: Wed Oct 14 10:45:16 2026 +0200
bgpd: let the EVPN code own the VRF RT list rebuild
34afeb5b10 made EVPN VRF RT changes batched for efficiency reasons.
It added new functions like bgp_evpn_vrf_rt_change_begin()/end()
around new _deferred setters, which are called by the VTY / CLI.
That means a bug in the CLI could leave EVPN in an inconsistent state.
This commit adds new _batch functions to EVPN core code, moving
the responsibility for consistency back to the EVPN core code.
The old single-RT setters have had no caller since 34afeb5b10
and are dropped as well.
Signed-off-by: Robin Christ <r.christ@partimus.com>
diff --git a/bgpd/bgp_evpn.c b/bgpd/bgp_evpn.c
index 86c7d2f18e..138b01bb8f 100644
--- a/bgpd/bgp_evpn.c
+++ b/bgpd/bgp_evpn.c
@@ -6607,24 +6607,6 @@ static void evpn_vrf_rt_routes_unmap(struct bgp *bgp_vrf)
bgp_evpn_unmap_vrf_from_its_rts(bgp_vrf);
}
-void bgp_evpn_vrf_rt_change_begin(struct bgp *bgp_vrf, bool is_import)
-{
- if (is_import)
- evpn_vrf_rt_routes_unmap(bgp_vrf);
-}
-
-void bgp_evpn_vrf_rt_change_end(struct bgp *bgp_vrf, bool is_import)
-{
- if (is_import) {
- bgp_evpn_vrf_regenerate_effective_import_rts(bgp_vrf);
- evpn_vrf_rt_routes_map(bgp_vrf);
- } else {
- bgp_evpn_vrf_regenerate_effective_export_rts(bgp_vrf);
- if (is_l3vni_live(bgp_vrf))
- bgp_evpn_handle_export_rt_change_for_vrf(bgp_vrf);
- }
-}
-
/* Remove a route target from a configured route target list and free it */
static void cfgd_rt_list_del(struct bgp_evpn_cfgd_rt_slu_head *head,
struct bgp_evpn_cfgd_rt *cfgd_rt)
@@ -6643,29 +6625,54 @@ static void cfgd_rt_list_add(struct bgp_evpn_cfgd_rt_slu_head *head,
bgp_evpn_cfgd_rt_free(cfgd_rt);
}
-/*
- * Add one import RT to the VRF without touching the RT-to-VRF mapping or
- * the imported routes. The caller owns that rebuild: it must have called
- * bgp_evpn_vrf_rt_change_begin() before the first RT of the list and must
- * call bgp_evpn_vrf_rt_change_end() after the last one, otherwise the VRF
- * is left with no effective imports.
- *
- * This split exists so a whole RTLIST walks the EVPN table once (one unmap
- * and one map) instead of twice per RT.
+/* Move every RT of cfgd_rts into a configured route target list, leaving
+ * cfgd_rts empty.
*/
-void bgp_evpn_configure_import_rt_for_vrf_deferred(struct bgp *bgp_vrf,
- struct bgp_evpn_cfgd_rt *cfgd_rt)
+static void cfgd_rt_list_add_batch(struct bgp_evpn_cfgd_rt_slu_head *head,
+ struct bgp_evpn_cfgd_rt_slu_head *cfgd_rts)
{
- struct bgp_evpn_rt_config *rt_config = bgp_vrf->vrf_route_target_config;
+ struct bgp_evpn_cfgd_rt *cfgd_rt;
+
+ while ((cfgd_rt = bgp_evpn_cfgd_rt_slu_pop(cfgd_rts)))
+ cfgd_rt_list_add(head, cfgd_rt);
+}
+
+/* Remove every RT of cfgd_rts from a configured route target list, then
+ * free cfgd_rts' entries, leaving it empty. RTs not configured are ignored.
+ */
+static void cfgd_rt_list_del_batch(struct bgp_evpn_cfgd_rt_slu_head *head,
+ struct bgp_evpn_cfgd_rt_slu_head *cfgd_rts)
+{
+ struct bgp_evpn_cfgd_rt *cfgd_rt, *existing;
- cfgd_rt_list_add(&rt_config->cfgd_import, cfgd_rt);
+ while ((cfgd_rt = bgp_evpn_cfgd_rt_slu_pop(cfgd_rts))) {
+ existing = bgp_evpn_cfgd_rt_slu_find(head, cfgd_rt);
+ if (existing)
+ cfgd_rt_list_del(head, existing);
+ bgp_evpn_cfgd_rt_free(cfgd_rt);
+ }
}
-void bgp_evpn_configure_import_rt_for_vrf(struct bgp *bgp_vrf, struct bgp_evpn_cfgd_rt *cfgd_rt)
+/* Add a set of import RTs to the VRF, taking ownership of every entry and
+ * leaving cfgd_rts empty. The VRF's routes are unmapped and remapped once
+ * for the whole set instead of once per RT.
+ */
+void bgp_evpn_configure_import_rts_for_vrf_batch(struct bgp *bgp_vrf,
+ struct bgp_evpn_cfgd_rt_slu_head *cfgd_rts)
{
- bgp_evpn_vrf_rt_change_begin(bgp_vrf, true);
- bgp_evpn_configure_import_rt_for_vrf_deferred(bgp_vrf, cfgd_rt);
- bgp_evpn_vrf_rt_change_end(bgp_vrf, true);
+ struct bgp_evpn_rt_config *rt_config = bgp_vrf->vrf_route_target_config;
+
+ if (!bgp_evpn_cfgd_rt_slu_count(cfgd_rts))
+ return;
+
+ evpn_vrf_rt_routes_unmap(bgp_vrf);
+
+ cfgd_rt_list_add_batch(&rt_config->cfgd_import, cfgd_rts);
+
+ /* This also removes the implicit auto RT, if there was one */
+ bgp_evpn_vrf_regenerate_effective_import_rts(bgp_vrf);
+
+ evpn_vrf_rt_routes_map(bgp_vrf);
}
void bgp_evpn_configure_import_auto_rt_for_vrf(struct bgp *bgp_vrf,
@@ -6688,23 +6695,28 @@ void bgp_evpn_configure_import_auto_rt_for_vrf(struct bgp *bgp_vrf,
evpn_vrf_rt_routes_map(bgp_vrf);
}
-void bgp_evpn_unconfigure_import_rt_for_vrf_deferred(struct bgp *bgp_vrf,
- const struct bgp_evpn_cfgd_rt *cfgd_rt)
+/* Remove a set of import RTs from the VRF. Every entry of cfgd_rts is
+ * freed and cfgd_rts is left empty. The VRF's routes are unmapped and
+ * remapped once for the whole set instead of once per RT.
+ */
+void bgp_evpn_unconfigure_import_rts_for_vrf_batch(struct bgp *bgp_vrf,
+ struct bgp_evpn_cfgd_rt_slu_head *cfgd_rts)
{
struct bgp_evpn_rt_config *rt_config = bgp_vrf->vrf_route_target_config;
- struct bgp_evpn_cfgd_rt *existing;
- existing = bgp_evpn_cfgd_rt_slu_find(&rt_config->cfgd_import, cfgd_rt);
- if (existing)
- cfgd_rt_list_del(&rt_config->cfgd_import, existing);
-}
+ if (!bgp_evpn_cfgd_rt_slu_count(cfgd_rts))
+ return;
-void bgp_evpn_unconfigure_import_rt_for_vrf(struct bgp *bgp_vrf,
- const struct bgp_evpn_cfgd_rt *cfgd_rt)
-{
- bgp_evpn_vrf_rt_change_begin(bgp_vrf, true);
- bgp_evpn_unconfigure_import_rt_for_vrf_deferred(bgp_vrf, cfgd_rt);
- bgp_evpn_vrf_rt_change_end(bgp_vrf, true);
+ evpn_vrf_rt_routes_unmap(bgp_vrf);
+
+ cfgd_rt_list_del_batch(&rt_config->cfgd_import, cfgd_rts);
+
+ /* This also restores the implicit auto RT if the last manual import
+ * RT was removed
+ */
+ bgp_evpn_vrf_regenerate_effective_import_rts(bgp_vrf);
+
+ evpn_vrf_rt_routes_map(bgp_vrf);
}
void bgp_evpn_unconfigure_import_auto_rt_for_vrf(struct bgp *bgp_vrf)
@@ -6723,18 +6735,25 @@ void bgp_evpn_unconfigure_import_auto_rt_for_vrf(struct bgp *bgp_vrf)
evpn_vrf_rt_routes_map(bgp_vrf);
}
-void bgp_evpn_configure_export_rt_for_vrf_deferred(struct bgp *bgp_vrf,
- struct bgp_evpn_cfgd_rt *cfgd_rt)
+/* Add a set of export RTs to the VRF, taking ownership of every entry and
+ * leaving cfgd_rts empty. The VRF's routes are re-advertised once for the
+ * whole set instead of once per RT.
+ */
+void bgp_evpn_configure_export_rts_for_vrf_batch(struct bgp *bgp_vrf,
+ struct bgp_evpn_cfgd_rt_slu_head *cfgd_rts)
{
struct bgp_evpn_rt_config *rt_config = bgp_vrf->vrf_route_target_config;
- cfgd_rt_list_add(&rt_config->cfgd_export, cfgd_rt);
-}
+ if (!bgp_evpn_cfgd_rt_slu_count(cfgd_rts))
+ return;
-void bgp_evpn_configure_export_rt_for_vrf(struct bgp *bgp_vrf, struct bgp_evpn_cfgd_rt *cfgd_rt)
-{
- bgp_evpn_configure_export_rt_for_vrf_deferred(bgp_vrf, cfgd_rt);
- bgp_evpn_vrf_rt_change_end(bgp_vrf, false);
+ cfgd_rt_list_add_batch(&rt_config->cfgd_export, cfgd_rts);
+
+ /* This also removes the implicit auto RT, if there was one */
+ bgp_evpn_vrf_regenerate_effective_export_rts(bgp_vrf);
+
+ if (is_l3vni_live(bgp_vrf))
+ bgp_evpn_handle_export_rt_change_for_vrf(bgp_vrf);
}
void bgp_evpn_configure_export_auto_rt_for_vrf(struct bgp *bgp_vrf,
@@ -6755,22 +6774,27 @@ void bgp_evpn_configure_export_auto_rt_for_vrf(struct bgp *bgp_vrf,
bgp_evpn_handle_export_rt_change_for_vrf(bgp_vrf);
}
-void bgp_evpn_unconfigure_export_rt_for_vrf_deferred(struct bgp *bgp_vrf,
- const struct bgp_evpn_cfgd_rt *cfgd_rt)
+/* Remove a set of export RTs from the VRF. Every entry of cfgd_rts is
+ * freed and cfgd_rts is left empty. The VRF's routes are re-advertised
+ * once for the whole set instead of once per RT.
+ */
+void bgp_evpn_unconfigure_export_rts_for_vrf_batch(struct bgp *bgp_vrf,
+ struct bgp_evpn_cfgd_rt_slu_head *cfgd_rts)
{
struct bgp_evpn_rt_config *rt_config = bgp_vrf->vrf_route_target_config;
- struct bgp_evpn_cfgd_rt *existing;
- existing = bgp_evpn_cfgd_rt_slu_find(&rt_config->cfgd_export, cfgd_rt);
- if (existing)
- cfgd_rt_list_del(&rt_config->cfgd_export, existing);
-}
+ if (!bgp_evpn_cfgd_rt_slu_count(cfgd_rts))
+ return;
-void bgp_evpn_unconfigure_export_rt_for_vrf(struct bgp *bgp_vrf,
- const struct bgp_evpn_cfgd_rt *cfgd_rt)
-{
- bgp_evpn_unconfigure_export_rt_for_vrf_deferred(bgp_vrf, cfgd_rt);
- bgp_evpn_vrf_rt_change_end(bgp_vrf, false);
+ cfgd_rt_list_del_batch(&rt_config->cfgd_export, cfgd_rts);
+
+ /* This also restores the implicit auto RT if the last manual export
+ * RT was removed
+ */
+ bgp_evpn_vrf_regenerate_effective_export_rts(bgp_vrf);
+
+ if (is_l3vni_live(bgp_vrf))
+ bgp_evpn_handle_export_rt_change_for_vrf(bgp_vrf);
}
void bgp_evpn_unconfigure_export_auto_rt_for_vrf(struct bgp *bgp_vrf)
diff --git a/bgpd/bgp_evpn_private.h b/bgpd/bgp_evpn_private.h
index 378ad17ca2..85167f89cd 100644
--- a/bgpd/bgp_evpn_private.h
+++ b/bgpd/bgp_evpn_private.h
@@ -995,29 +995,21 @@ extern void bgp_evpn_install_uninstall_default_route(struct bgp *bgp_vrf, afi_t
struct bgp_path_info *originator, bool add);
extern void bgp_evpn_l2vni_regenerate_effective_import_rts(struct bgp *bgp, struct bgpevpn *vpn);
extern void bgp_evpn_l2vni_regenerate_effective_export_rts(struct bgp *bgp, struct bgpevpn *vpn);
-extern void bgp_evpn_vrf_rt_change_begin(struct bgp *bgp_vrf, bool is_import);
-extern void bgp_evpn_vrf_rt_change_end(struct bgp *bgp_vrf, bool is_import);
-extern void bgp_evpn_configure_export_rt_for_vrf(struct bgp *bgp_vrf,
- struct bgp_evpn_cfgd_rt *cfgd_rt);
-extern void bgp_evpn_configure_export_rt_for_vrf_deferred(struct bgp *bgp_vrf,
- struct bgp_evpn_cfgd_rt *cfgd_rt);
+extern void bgp_evpn_configure_export_rts_for_vrf_batch(struct bgp *bgp_vrf,
+ struct bgp_evpn_cfgd_rt_slu_head *cfgd_rts);
extern void bgp_evpn_configure_export_auto_rt_for_vrf(struct bgp *bgp_vrf,
enum bgp_evpn_autort_cfgd autort);
-extern void bgp_evpn_unconfigure_export_rt_for_vrf(struct bgp *bgp_vrf,
- const struct bgp_evpn_cfgd_rt *cfgd_rt);
-extern void bgp_evpn_unconfigure_export_rt_for_vrf_deferred(struct bgp *bgp_vrf,
- const struct bgp_evpn_cfgd_rt *cfgd_rt);
+extern void
+bgp_evpn_unconfigure_export_rts_for_vrf_batch(struct bgp *bgp_vrf,
+ struct bgp_evpn_cfgd_rt_slu_head *cfgd_rts);
extern void bgp_evpn_unconfigure_export_auto_rt_for_vrf(struct bgp *bgp_vrf);
-extern void bgp_evpn_configure_import_rt_for_vrf(struct bgp *bgp_vrf,
- struct bgp_evpn_cfgd_rt *cfgd_rt);
-extern void bgp_evpn_configure_import_rt_for_vrf_deferred(struct bgp *bgp_vrf,
- struct bgp_evpn_cfgd_rt *cfgd_rt);
+extern void bgp_evpn_configure_import_rts_for_vrf_batch(struct bgp *bgp_vrf,
+ struct bgp_evpn_cfgd_rt_slu_head *cfgd_rts);
extern void bgp_evpn_configure_import_auto_rt_for_vrf(struct bgp *bgp_vrf,
enum bgp_evpn_autort_cfgd autort);
-extern void bgp_evpn_unconfigure_import_rt_for_vrf(struct bgp *bgp_vrf,
- const struct bgp_evpn_cfgd_rt *cfgd_rt);
-extern void bgp_evpn_unconfigure_import_rt_for_vrf_deferred(struct bgp *bgp_vrf,
- const struct bgp_evpn_cfgd_rt *cfgd_rt);
+extern void
+bgp_evpn_unconfigure_import_rts_for_vrf_batch(struct bgp *bgp_vrf,
+ struct bgp_evpn_cfgd_rt_slu_head *cfgd_rts);
extern void bgp_evpn_unconfigure_import_auto_rt_for_vrf(struct bgp *bgp_vrf);
extern int bgp_evpn_handle_export_rt_change(struct bgp *bgp,
struct bgpevpn *vpn);
diff --git a/bgpd/bgp_evpn_vty.c b/bgpd/bgp_evpn_vty.c
index 00880c1eea..46aff14dbf 100644
--- a/bgpd/bgp_evpn_vty.c
+++ b/bgpd/bgp_evpn_vty.c
@@ -6965,64 +6965,49 @@ DEFUN (show_bgp_vrf_l3vni_info,
return CMD_SUCCESS;
}
-static void vrf_rt_import_change_start(struct bgp *bgp, bool *import_started)
-{
- if (*import_started)
- return;
-
- bgp_evpn_vrf_rt_change_begin(bgp, true);
- *import_started = true;
-}
-
-/* Add a manual route target to the VRF (L3VNI) configuration. Takes
- * ownership of cfgd_rt on success. "both" is an alias for import plus
- * export. Mutations are deferred so the caller can rebuild once per list.
+/* Queue a manual route target for addition to the VRF (L3VNI)
+ * configuration. Takes ownership of cfgd_rt on success. "both" is an
+ * alias for import plus export. An RT queued by an earlier entry of the
+ * same list counts as configured.
*/
static int vrf_rt_add(struct bgp *bgp, struct bgp_evpn_cfgd_rt *cfgd_rt,
- enum bgp_evpn_rt_direction rt_direction, bool *import_started,
- bool *export_started)
+ enum bgp_evpn_rt_direction rt_direction,
+ struct bgp_evpn_cfgd_rt_slu_head *import_rts,
+ struct bgp_evpn_cfgd_rt_slu_head *export_rts)
{
struct bgp_evpn_rt_config *rt_config = bgp->vrf_route_target_config;
bool have_import, have_export;
+ have_import = bgp_evpn_cfgd_rt_slu_find(&rt_config->cfgd_import, cfgd_rt) ||
+ bgp_evpn_cfgd_rt_slu_find(import_rts, cfgd_rt);
+ have_export = bgp_evpn_cfgd_rt_slu_find(&rt_config->cfgd_export, cfgd_rt) ||
+ bgp_evpn_cfgd_rt_slu_find(export_rts, cfgd_rt);
+
/* Do nothing if we already have this route-target */
switch (rt_direction) {
case RT_TYPE_IMPORT:
- if (bgp_evpn_cfgd_rt_slu_find(&rt_config->cfgd_import, cfgd_rt))
+ if (have_import)
return -1;
- vrf_rt_import_change_start(bgp, import_started);
- bgp_evpn_configure_import_rt_for_vrf_deferred(bgp, cfgd_rt);
+ bgp_evpn_cfgd_rt_slu_add(import_rts, cfgd_rt);
break;
case RT_TYPE_EXPORT:
- if (bgp_evpn_cfgd_rt_slu_find(&rt_config->cfgd_export, cfgd_rt))
+ if (have_export)
return -1;
- bgp_evpn_configure_export_rt_for_vrf_deferred(bgp, cfgd_rt);
- /* Export begin() is a no-op; only end() re-advertises. */
- *export_started = true;
+ bgp_evpn_cfgd_rt_slu_add(export_rts, cfgd_rt);
break;
case RT_TYPE_BOTH:
- have_import = !!bgp_evpn_cfgd_rt_slu_find(&rt_config->cfgd_import, cfgd_rt);
- have_export = !!bgp_evpn_cfgd_rt_slu_find(&rt_config->cfgd_export, cfgd_rt);
-
if (have_import && have_export)
return -1;
- if (!have_import) {
- vrf_rt_import_change_start(bgp, import_started);
- if (!have_export) {
- bgp_evpn_configure_import_rt_for_vrf_deferred(bgp, cfgd_rt);
- bgp_evpn_configure_export_rt_for_vrf_deferred(bgp,
- bgp_evpn_cfgd_rt_dup(
- cfgd_rt));
- *export_started = true;
- } else {
- bgp_evpn_configure_import_rt_for_vrf_deferred(bgp, cfgd_rt);
- }
+ if (!have_import && !have_export) {
+ bgp_evpn_cfgd_rt_slu_add(import_rts, cfgd_rt);
+ bgp_evpn_cfgd_rt_slu_add(export_rts, bgp_evpn_cfgd_rt_dup(cfgd_rt));
+ } else if (!have_import) {
+ bgp_evpn_cfgd_rt_slu_add(import_rts, cfgd_rt);
} else {
- bgp_evpn_configure_export_rt_for_vrf_deferred(bgp, cfgd_rt);
- *export_started = true;
+ bgp_evpn_cfgd_rt_slu_add(export_rts, cfgd_rt);
}
break;
default:
@@ -7032,48 +7017,49 @@ static int vrf_rt_add(struct bgp *bgp, struct bgp_evpn_cfgd_rt *cfgd_rt,
return 0;
}
-/* Remove a manual route target from the VRF (L3VNI) configuration.
- * The caller keeps ownership of cfgd_rt. "both" removes whichever of
- * the two directions is configured.
+/* Queue a manual route target for removal from the VRF (L3VNI)
+ * configuration. Takes ownership of cfgd_rt on success. "both" removes
+ * whichever of the two directions is configured. An RT queued by an
+ * earlier entry of the same list counts as no longer configured.
*/
-static int vrf_rt_del(struct bgp *bgp, const struct bgp_evpn_cfgd_rt *cfgd_rt,
- enum bgp_evpn_rt_direction rt_direction, bool *import_started,
- bool *export_started)
+static int vrf_rt_del(struct bgp *bgp, struct bgp_evpn_cfgd_rt *cfgd_rt,
+ enum bgp_evpn_rt_direction rt_direction,
+ struct bgp_evpn_cfgd_rt_slu_head *import_rts,
+ struct bgp_evpn_cfgd_rt_slu_head *export_rts)
{
struct bgp_evpn_rt_config *rt_config = bgp->vrf_route_target_config;
bool have_import, have_export;
+ have_import = bgp_evpn_cfgd_rt_slu_find(&rt_config->cfgd_import, cfgd_rt) &&
+ !bgp_evpn_cfgd_rt_slu_find(import_rts, cfgd_rt);
+ have_export = bgp_evpn_cfgd_rt_slu_find(&rt_config->cfgd_export, cfgd_rt) &&
+ !bgp_evpn_cfgd_rt_slu_find(export_rts, cfgd_rt);
+
/* Verify we already have this route-target */
switch (rt_direction) {
case RT_TYPE_IMPORT:
- if (!bgp_evpn_cfgd_rt_slu_find(&rt_config->cfgd_import, cfgd_rt))
+ if (!have_import)
return -1;
- vrf_rt_import_change_start(bgp, import_started);
- bgp_evpn_unconfigure_import_rt_for_vrf_deferred(bgp, cfgd_rt);
+ bgp_evpn_cfgd_rt_slu_add(import_rts, cfgd_rt);
break;
case RT_TYPE_EXPORT:
- if (!bgp_evpn_cfgd_rt_slu_find(&rt_config->cfgd_export, cfgd_rt))
+ if (!have_export)
return -1;
- bgp_evpn_unconfigure_export_rt_for_vrf_deferred(bgp, cfgd_rt);
- /* Export begin() is a no-op; only end() re-advertises. */
- *export_started = true;
+ bgp_evpn_cfgd_rt_slu_add(export_rts, cfgd_rt);
break;
case RT_TYPE_BOTH:
- have_import = !!bgp_evpn_cfgd_rt_slu_find(&rt_config->cfgd_import, cfgd_rt);
- have_export = !!bgp_evpn_cfgd_rt_slu_find(&rt_config->cfgd_export, cfgd_rt);
-
if (!have_import && !have_export)
return -1;
- if (have_import) {
- vrf_rt_import_change_start(bgp, import_started);
- bgp_evpn_unconfigure_import_rt_for_vrf_deferred(bgp, cfgd_rt);
- }
- if (have_export) {
- bgp_evpn_unconfigure_export_rt_for_vrf_deferred(bgp, cfgd_rt);
- *export_started = true;
+ if (have_import && have_export) {
+ bgp_evpn_cfgd_rt_slu_add(import_rts, cfgd_rt);
+ bgp_evpn_cfgd_rt_slu_add(export_rts, bgp_evpn_cfgd_rt_dup(cfgd_rt));
+ } else if (have_import) {
+ bgp_evpn_cfgd_rt_slu_add(import_rts, cfgd_rt);
+ } else {
+ bgp_evpn_cfgd_rt_slu_add(export_rts, cfgd_rt);
}
break;
default:
@@ -7262,10 +7248,11 @@ static int vrf_process_rtlist_internal(struct bgp *bgp, struct vty *vty, struct
int n_rts, struct bgp_evpn_cfgd_rt **cfgd_rts, bool is_add,
enum bgp_evpn_rt_direction rt_direction)
{
+ struct bgp_evpn_cfgd_rt_slu_head import_rts, export_rts;
int ret = CMD_SUCCESS;
- /* True once at least one RT mutated that direction; end() then rebuilds once. */
- bool import_started = false;
- bool export_started = false;
+
+ bgp_evpn_cfgd_rt_slu_init(&import_rts);
+ bgp_evpn_cfgd_rt_slu_init(&export_rts);
for (int i = 0; i < n_rts; i++) {
struct bgp_evpn_cfgd_rt *cfgd_rt = cfgd_rts[i];
@@ -7273,8 +7260,7 @@ static int vrf_process_rtlist_internal(struct bgp *bgp, struct vty *vty, struct
cfgd_rts[i] = NULL;
if (is_add) {
- if (vrf_rt_add(bgp, cfgd_rt, rt_direction, &import_started,
- &export_started) != 0) {
+ if (vrf_rt_add(bgp, cfgd_rt, rt_direction, &import_rts, &export_rts) != 0) {
vty_out(vty,
"%% RT specified already configured for this VRF: %s\n",
rt_argv[i]->arg);
@@ -7283,22 +7269,29 @@ static int vrf_process_rtlist_internal(struct bgp *bgp, struct vty *vty, struct
}
} else {
- if (vrf_rt_del(bgp, cfgd_rt, rt_direction, &import_started,
- &export_started) != 0) {
+ if (vrf_rt_del(bgp, cfgd_rt, rt_direction, &import_rts, &export_rts) != 0) {
vty_out(vty,
"%% RT specified does not match configuration for this VRF: %s\n",
rt_argv[i]->arg);
+ bgp_evpn_cfgd_rt_free(cfgd_rt);
ret = CMD_WARNING;
}
-
- bgp_evpn_cfgd_rt_free(cfgd_rt);
}
}
- if (import_started)
- bgp_evpn_vrf_rt_change_end(bgp, true);
- if (export_started)
- bgp_evpn_vrf_rt_change_end(bgp, false);
+ /* Hand each direction's RTs to EVPN as one set, so the VRF's routes
+ * are rebuilt once per direction instead of once per RT.
+ */
+ if (is_add) {
+ bgp_evpn_configure_import_rts_for_vrf_batch(bgp, &import_rts);
+ bgp_evpn_configure_export_rts_for_vrf_batch(bgp, &export_rts);
+ } else {
+ bgp_evpn_unconfigure_import_rts_for_vrf_batch(bgp, &import_rts);
+ bgp_evpn_unconfigure_export_rts_for_vrf_batch(bgp, &export_rts);
+ }
+
+ bgp_evpn_cfgd_rt_slu_fini(&import_rts);
+ bgp_evpn_cfgd_rt_slu_fini(&export_rts);
return ret;
}