When a logical switch is created or updated, lflow_handle_northd_ls_changes()
already builds and syncs that switch's ls_stateful flows together with its
by_ls flows (so the shared datapath groups stay stable).  The ls_stateful
record for the same switch also shows up in the ls_stateful node's tracked
"crupdated" set, so lflow_ls_stateful_handler() would rebuild and resync
those exact flows a second time.

Pass northd's tracked switches down to lflow_handle_ls_stateful_changes()
and skip any crupdated ls_stateful record whose switch datapath was already
handled by lflow_handle_northd_ls_changes().  Records for pre-existing
switches (e.g. an ACL or port-group change) are untouched and still
processed here.

Assisted-bt: Claude Opus 4.8, Claude Code
Signed-off-by: Lucas Vargas Dias <[email protected]>
---
 northd/en-lflow.c |  9 +++++++++
 northd/northd.c   | 24 ++++++++++++++++++++++++
 northd/northd.h   |  1 +
 3 files changed, 34 insertions(+)

diff --git a/northd/en-lflow.c b/northd/en-lflow.c
index 9a517ae48..052e22c9d 100644
--- a/northd/en-lflow.c
+++ b/northd/en-lflow.c
@@ -236,6 +236,14 @@ lflow_ls_stateful_handler(struct engine_node *node, void 
*data)
         return EN_UNHANDLED;
     }
 
+    /* Switch datapaths created/updated in this run had their ls_stateful
+     * flows already handled by lflow_handle_northd_ls_changes(); pass northd's
+     * tracked switches so we don't reprocess them here. */
+    struct northd_data *northd_data = engine_get_input_data("northd", node);
+    const struct tracked_dps *trk_switches =
+        northd_has_lswitches_in_tracked_data(&northd_data->trk_data)
+        ? &northd_data->trk_data.trk_switches : NULL;
+
     const struct engine_context *eng_ctx = engine_get_context();
     struct lflow_data *lflow_data = data;
     struct lflow_input lflow_input;
@@ -243,6 +251,7 @@ lflow_ls_stateful_handler(struct engine_node *node, void 
*data)
     lflow_get_input_data(node, &lflow_input);
     if (!lflow_handle_ls_stateful_changes(eng_ctx->ovnsb_idl_txn,
                                           &ls_sful_data->trk_data,
+                                          trk_switches,
                                           &lflow_input,
                                           lflow_data->lflow_table)) {
         return EN_UNHANDLED;
diff --git a/northd/northd.c b/northd/northd.c
index 9ecc072f3..d15ad8395 100644
--- a/northd/northd.c
+++ b/northd/northd.c
@@ -22126,6 +22126,7 @@ exit:
 bool
 lflow_handle_ls_stateful_changes(struct ovsdb_idl_txn *ovnsb_txn,
                                 struct ls_stateful_tracked_data *trk_data,
+                                const struct tracked_dps *trk_switches,
                                 struct lflow_input *lflow_input,
                                 struct lflow_table *lflows)
 {
@@ -22139,6 +22140,17 @@ lflow_handle_ls_stateful_changes(struct ovsdb_idl_txn 
*ovnsb_txn,
         ovs_assert(od->nbs && uuid_equals(&od->nbs->header_.uuid,
                                           &ls_stateful_rec->nbs_uuid));
 
+        /* Newly created/updated switch datapaths already had their
+         * ls_stateful flows built and synced by
+         * lflow_handle_northd_ls_changes() (which processes both the by_ls
+         * and ls_stateful refs together to keep shared datapath groups
+         * stable).  Skip them here to avoid rebuilding the same flows. */
+        if (trk_switches && hmapx_contains(&trk_switches->crupdated,
+                                           CONST_CAST(struct ovn_datapath *,
+                                                      od))) {
+            continue;
+        }
+
         lflow_ref_unlink_lflows(ls_stateful_rec->lflow_ref);
 
         /* Generate new lflows. */
@@ -22156,6 +22168,18 @@ lflow_handle_ls_stateful_changes(struct ovsdb_idl_txn 
*ovnsb_txn,
      * those datapath groups within those flows over and over again. */
     HMAPX_FOR_EACH (hmapx_node, &trk_data->crupdated) {
         struct ls_stateful_record *ls_stateful_rec = hmapx_node->data;
+
+        /* Already synced by lflow_handle_northd_ls_changes() (see above). */
+        if (trk_switches) {
+            const struct ovn_datapath *od =
+                ovn_datapaths_find_by_index(lflow_input->ls_datapaths,
+                                            ls_stateful_rec->ls_index);
+            if (hmapx_contains(&trk_switches->crupdated,
+                               CONST_CAST(struct ovn_datapath *, od))) {
+                continue;
+            }
+        }
+
         /* Sync the new flows to SB. */
         bool handled = lflow_ref_sync_lflows(
             ls_stateful_rec->lflow_ref, lflows, ovnsb_txn,
diff --git a/northd/northd.h b/northd/northd.h
index 217f3c6fb..20e03e1a5 100644
--- a/northd/northd.h
+++ b/northd/northd.h
@@ -1024,6 +1024,7 @@ bool lflow_handle_lr_stateful_changes(struct 
ovsdb_idl_txn *,
                                       struct lflow_table *lflows);
 bool lflow_handle_ls_stateful_changes(struct ovsdb_idl_txn *,
                                       struct ls_stateful_tracked_data *,
+                                      const struct tracked_dps *trk_switches,
                                       struct lflow_input *,
                                       struct lflow_table *lflows);
 bool northd_handle_sb_port_binding_changes(
-- 
2.43.0


-- 




_'Esta mensagem é direcionada apenas para os endereços constantes no 
cabeçalho inicial. Se você não está listado nos endereços constantes no 
cabeçalho, pedimos-lhe que desconsidere completamente o conteúdo dessa 
mensagem e cuja cópia, encaminhamento e/ou execução das ações citadas estão 
imediatamente anuladas e proibidas'._


* **'Apesar do Magazine Luiza tomar 
todas as precauções razoáveis para assegurar que nenhum vírus esteja 
presente nesse e-mail, a empresa não poderá aceitar a responsabilidade por 
quaisquer perdas ou danos causados por esse e-mail ou por seus anexos'.*



_______________________________________________
dev mailing list
[email protected]
https://mail.openvswitch.org/mailman/listinfo/ovs-dev

Reply via email to