Commit f14fef7665 for frr

commit f14fef7665f3f4cb4ada98564f7010add4b5d3a8
Author: Donald Sharp <sharpd@nvidia.com>
Date:   Tue Nov 10 18:09:39 2026 -0500

    zebra: Make all label operations work through the metaQ

    Currently the a replace operation, or a add operation
    gets put on the metaQ for handling.  Then if a delete
    comes in, the delete operation happens immediately
    leaving the operation on the metaQ.  When the metaQ
    wakes up the add/replace operation is handled which
    adds the label back incorrectly.

    Modify the code to place all label operations on the
    Q and to handle everything done in the order on the
    label MetaQ.

    Signed-off-by: Donald Sharp <sharpd@nvidia.com>

diff --git a/zebra/zapi_msg.c b/zebra/zapi_msg.c
index 5c3a40828e..aa4aaa63b0 100644
--- a/zebra/zapi_msg.c
+++ b/zebra/zapi_msg.c
@@ -2602,7 +2602,7 @@ static void zread_mpls_labels_add(ZAPI_HANDLER_ARGS)
 	if (zapi_labels_validate(&zl) < 0)
 		return;

-	mpls_zapi_labels_process(true, zvrf, &zl);
+	mpls_zapi_labels_process(true /*add*/, false /*replace*/, zvrf, &zl);
 }

 /*
@@ -2632,15 +2632,7 @@ static void zread_mpls_labels_delete(ZAPI_HANDLER_ARGS)
 	if (!mpls_enabled)
 		return;

-	if (zl.nexthop_num > 0) {
-		mpls_zapi_labels_process(false /*delete*/, zvrf, &zl);
-	} else {
-		mpls_lsp_uninstall_all_vrf(zvrf, zl.type, zl.local_label);
-
-		if (CHECK_FLAG(zl.message, ZAPI_LABELS_FTN))
-			mpls_ftn_uninstall(zvrf, zl.type, &zl.route.prefix,
-					   zl.route.type, zl.route.instance);
-	}
+	mpls_zapi_labels_process(false /*add*/, false /*replace*/, zvrf, &zl);
 }

 /*
@@ -2676,16 +2668,7 @@ static void zread_mpls_labels_replace(ZAPI_HANDLER_ARGS)
 	if (zapi_labels_validate(&zl) < 0)
 		return;

-	/* This removes everything, then re-adds from the client's
-	 * zapi message. Since the LSP will be processed later, on this
-	 * this same pthread, all of the changes will 'appear' at once.
-	 */
-	mpls_lsp_uninstall_all_vrf(zvrf, zl.type, zl.local_label);
-	if (CHECK_FLAG(zl.message, ZAPI_LABELS_FTN))
-		mpls_ftn_uninstall(zvrf, zl.type, &zl.route.prefix,
-				   zl.route.type, zl.route.instance);
-
-	mpls_zapi_labels_process(true, zvrf, &zl);
+	mpls_zapi_labels_process(true /*add*/, true /*replace*/, zvrf, &zl);
 }

 static void zread_sr_policy_set(ZAPI_HANDLER_ARGS)
diff --git a/zebra/zebra_mpls.c b/zebra/zebra_mpls.c
index 9478d31e9d..72b5efe0bd 100644
--- a/zebra/zebra_mpls.c
+++ b/zebra/zebra_mpls.c
@@ -2906,13 +2906,32 @@ static bool ftn_update_znh(bool add_p, enum lsp_types_t type,
 	return success;
 }

+/*
+ * Uninstall every NHLFE of this label and, when requested, the FTN binding.
+ */
+static void mpls_zapi_labels_uninstall_all(struct zebra_vrf *zvrf, const struct zapi_labels *zl)
+{
+	struct prefix p;
+
+	mpls_lsp_uninstall_all_vrf(zvrf, zl->type, zl->local_label);
+
+	if (!CHECK_FLAG(zl->message, ZAPI_LABELS_FTN))
+		return;
+
+	p = zl->route.prefix;
+	zebra_mpls_ftn_uninstall(zvrf, zl->type, &p, zl->route.type, zl->route.instance);
+}
+
 /*
  * Install/uninstall LSP and (optionally) FEC-To-NHLFE (FTN) bindings,
  * using zapi message info.
  * There are several changes that need to be made, in several zebra
  * data structures, so we want to do all the work required at once.
+ *
+ * A delete with no nexthops removes the whole LSP. A replace removes the
+ * current LSP and then applies the message as an add.
  */
-void zebra_mpls_zapi_labels_process(bool add_p, struct zebra_vrf *zvrf,
+void zebra_mpls_zapi_labels_process(bool add_p, bool replace_p, struct zebra_vrf *zvrf,
 				    const struct zapi_labels *zl)
 {
 	int i, counter, ret = 0;
@@ -2929,6 +2948,14 @@ void zebra_mpls_zapi_labels_process(bool add_p, struct zebra_vrf *zvrf,
 	struct zebra_ile tmp_ile;
 	struct zebra_lsp *lsp = NULL;

+	if (!add_p && zl->nexthop_num == 0) {
+		mpls_zapi_labels_uninstall_all(zvrf, zl);
+		return;
+	}
+
+	if (replace_p)
+		mpls_zapi_labels_uninstall_all(zvrf, zl);
+
 	/* Prep LSP for add case */
 	if (add_p) {
 		/* Lookup table. */
diff --git a/zebra/zebra_mpls.h b/zebra/zebra_mpls.h
index 5d7553aa15..85b8517f74 100644
--- a/zebra/zebra_mpls.h
+++ b/zebra/zebra_mpls.h
@@ -250,11 +250,15 @@ void zebra_mpls_print_fec(struct vty *vty, struct zebra_vrf *zvrf,
  *
  * mpls_zapi_labels_process -> Installs for future processing
  *                             in the meta-q
- * zebra_mpls_labels_process -> called by the meta-q
+ * zebra_mpls_zapi_labels_process -> called by the meta-q
+ *
+ * replace_p is meaningful only when add_p is true. The queued replace
+ * uninstalls the current LSP and then applies the message, in that order,
+ * when the meta-q item runs.
  */
-void mpls_zapi_labels_process(bool add_p, struct zebra_vrf *zvrf,
+void mpls_zapi_labels_process(bool add_p, bool replace_p, struct zebra_vrf *zvrf,
 			      const struct zapi_labels *zl);
-void zebra_mpls_zapi_labels_process(bool add_p, struct zebra_vrf *zvrf,
+void zebra_mpls_zapi_labels_process(bool add_p, bool replace_p, struct zebra_vrf *zvrf,
 				    const struct zapi_labels *zl);

 /*
diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c
index 736bec1a92..453c507bbe 100644
--- a/zebra/zebra_rib.c
+++ b/zebra/zebra_rib.c
@@ -239,6 +239,7 @@ struct wq_label_wrapper {
 	uint8_t route_instance;

 	bool add_p;
+	bool replace_p;
 	struct zapi_labels zl;

 	int afi;
@@ -2573,7 +2574,7 @@ static void process_subq_early_label(struct listnode *lnode)
 					 w->route_instance);
 		break;
 	case WQ_LABEL_LABELS_PROCESS:
-		zebra_mpls_zapi_labels_process(w->add_p, zvrf, &w->zl);
+		zebra_mpls_zapi_labels_process(w->add_p, w->replace_p, zvrf, &w->zl);
 		break;
 	}

@@ -3554,7 +3555,7 @@ void mpls_ftn_uninstall(struct zebra_vrf *zvrf, enum lsp_types_t type,
 	mq_add_handler(w, early_label_meta_queue_add);
 }

-void mpls_zapi_labels_process(bool add_p, struct zebra_vrf *zvrf,
+void mpls_zapi_labels_process(bool add_p, bool replace_p, struct zebra_vrf *zvrf,
 			      const struct zapi_labels *zl)
 {
 	struct wq_label_wrapper *w;
@@ -3563,6 +3564,7 @@ void mpls_zapi_labels_process(bool add_p, struct zebra_vrf *zvrf,
 	w->type = WQ_LABEL_LABELS_PROCESS;
 	w->vrf_id = zvrf->vrf->vrf_id;
 	w->add_p = add_p;
+	w->replace_p = replace_p;
 	w->zl = *zl;

 	if (IS_ZEBRA_DEBUG_RIB_DETAILED)