This commit introduces pipeline length validation between ovn-northd and
ovn-controller, enabling dynamic adjustment of OpenFlow table numbering
when pipeline dimensions change.

Runtime validation features:
- Northd publishes pipeline lengths in SB_Global options
- Controller detects length mismatches and dynamically renumbers tables
- Full recompute triggered only when necessary for consistency

The solution enables flexible upgrade scenarios where:
- New northd versions can extend pipeline lengths without breaking older
  controllers.

Signed-off-by: Alexandra Rukomoinikova <[email protected]>
---
 controller/ovn-controller.c | 53 ++++++++++++++++++++++++++++++++++++-
 lib/oftable.c               | 47 ++++++++++++++++++++++++++++++++
 lib/oftable.h               |  3 +++
 northd/en-global-config.c   |  7 +++++
 4 files changed, 109 insertions(+), 1 deletion(-)

diff --git a/controller/ovn-controller.c b/controller/ovn-controller.c
index f5935098f..b4d46435f 100644
--- a/controller/ovn-controller.c
+++ b/controller/ovn-controller.c
@@ -61,6 +61,7 @@
 #include "lib/ovn-dirs.h"
 #include "lib/ovn-sb-idl.h"
 #include "lib/ovn-util.h"
+#include "lib/oftable.h"
 #include "ovsport.h"
 #include "patch.h"
 #include "vif-plug.h"
@@ -6465,6 +6466,52 @@ check_northd_version(struct ovsdb_idl *ovs_idl, struct 
ovsdb_idl *ovnsb_idl,
     return true;
 }
 
+static bool
+verify_pipeline_length_compatibility(struct ovsdb_idl *ovnsb_idl)
+{
+    bool pipeline_length_mismatch;
+
+    const struct sbrec_sb_global *sb = sbrec_sb_global_first(ovnsb_idl);
+    if (!sb) {
+        pipeline_length_mismatch = true;
+        return false;
+    }
+
+    /* No results found - indicates legacy northd version;
+     * preserve backward compatibility by skipping processing. */
+    int northd_ingress_pipeline_len = smap_get_int(&sb->options,
+                                                   "log-pipeline-ingress-len",
+                                                   LOG_PIPELINE_INGRESS_LEN);
+    int northd_egress_pipeline_len = smap_get_int(&sb->options,
+                                                   "log-pipeline-egress-len",
+                                                    LOG_PIPELINE_EGRESS_LEN);
+
+    /* Check if northd pipeline lengths differ from
+     * controller's configuration. */
+    pipeline_length_mismatch = (northd_ingress_pipeline_len !=
+                               LOG_PIPELINE_INGRESS_LEN) ||
+                               (northd_egress_pipeline_len !=
+                               LOG_PIPELINE_EGRESS_LEN);
+
+    /* If the pipeline lengths don't match,
+     * shift the table numbers and force a full recompute.*/
+    if (pipeline_length_mismatch) {
+        VLOG_INFO("Pipeline length mismatch detected: "
+                  "northd(ingress=%d, egress=%d) "
+                  "vs controller(ingress=%d, egress=%d)",
+                  northd_ingress_pipeline_len,
+                  northd_egress_pipeline_len,
+                  LOG_PIPELINE_INGRESS_LEN,
+                  LOG_PIPELINE_EGRESS_LEN);
+        recalculate_oftable_offsets(northd_ingress_pipeline_len,
+                                    northd_egress_pipeline_len);
+        engine_set_force_recompute();
+    }
+
+    pipeline_length_mismatch = false;
+    return true;
+}
+
 static void
 br_int_remote_update(struct br_int_remote *remote,
                      const struct ovsrec_bridge *br_int,
@@ -7282,6 +7329,9 @@ main(int argc, char *argv[])
             check_northd_version(ovs_idl_loop.idl, ovnsb_idl_loop.idl,
                                  ovn_version);
 
+        bool pipeline_length_match =
+            verify_pipeline_length_compatibility(ovnsb_idl_loop.idl);
+
         init_validate_actions(ovs_idl_loop.idl);
 
         if (validate_actions.controller_validate_actions) {
@@ -7326,7 +7376,8 @@ main(int argc, char *argv[])
 
         if (ovsdb_idl_has_ever_connected(ovnsb_idl_loop.idl) &&
             northd_version_match && cfg &&
-            validate_actions.validated) {
+            validate_actions.validated &&
+            pipeline_length_match) {
             /* Unconditionally remove all deleted lflows from the lflow
              * cache.
              */
diff --git a/lib/oftable.c b/lib/oftable.c
index 721b3ad49..49f8c0cc5 100644
--- a/lib/oftable.c
+++ b/lib/oftable.c
@@ -15,6 +15,7 @@
 #include <config.h>
 
 #include "lib/oftable.h"
+#include "lib/ovn-util.h"
 
 int OFTABLE_PHY_TO_LOG = 0;
 
@@ -53,3 +54,49 @@ int OFTABLE_FLOOD_REMOTE_CHASSIS = 84;
 int OFTABLE_CT_STATE_SAVE        = 85;
 int OFTABLE_CT_ORIG_PROTO_LOAD   = 86;
 int OFTABLE_GET_REMOTE_FDB       = 87;
+
+void
+recalculate_oftable_offsets(int new_ingress_len,
+                            int new_egress_len)
+{
+    const int ingress_delta =
+        new_ingress_len - LOG_PIPELINE_INGRESS_LEN;
+
+    OFTABLE_OUTPUT_LARGE_PKT_DETECT += ingress_delta;
+    OFTABLE_OUTPUT_INIT += ingress_delta;
+    OFTABLE_OUTPUT_LARGE_PKT_PROCESS += ingress_delta;
+    OFTABLE_REMOTE_OUTPUT += ingress_delta;
+    OFTABLE_REMOTE_VTEP_OUTPUT += ingress_delta;
+    OFTABLE_LOCAL_OUTPUT += ingress_delta;
+    OFTABLE_CHECK_LOOPBACK += ingress_delta;
+
+    /* Start of LOG_PIPELINE_LEN tables. */
+    OFTABLE_LOG_EGRESS_PIPELINE += ingress_delta;
+    OFTABLE_SAVE_INPORT += ingress_delta;
+    OFTABLE_LOG_TO_PHY += ingress_delta;
+    OFTABLE_MAC_BINDING += ingress_delta;
+    OFTABLE_MAC_LOOKUP += ingress_delta;
+    OFTABLE_CHK_LB_HAIRPIN += ingress_delta;
+    OFTABLE_CHK_LB_HAIRPIN_REPLY += ingress_delta;
+    OFTABLE_CT_SNAT_HAIRPIN += ingress_delta;
+    OFTABLE_GET_FDB += ingress_delta;
+    OFTABLE_LOOKUP_FDB += ingress_delta;
+    OFTABLE_CHK_IN_PORT_SEC += ingress_delta;
+    OFTABLE_CHK_IN_PORT_SEC_ND += ingress_delta;
+    OFTABLE_CHK_OUT_PORT_SEC += ingress_delta;
+    OFTABLE_ECMP_NH_MAC += ingress_delta;
+    OFTABLE_ECMP_NH += ingress_delta;
+    OFTABLE_CHK_LB_AFFINITY += ingress_delta;
+    OFTABLE_MAC_CACHE_USE += ingress_delta;
+    OFTABLE_CT_ZONE_LOOKUP += ingress_delta;
+    OFTABLE_CT_ORIG_NW_DST_LOAD += ingress_delta;
+    OFTABLE_CT_ORIG_IP6_DST_LOAD += ingress_delta;
+    OFTABLE_CT_ORIG_TP_DST_LOAD  += ingress_delta;
+    OFTABLE_FLOOD_REMOTE_CHASSIS += ingress_delta;
+    OFTABLE_CT_STATE_SAVE += ingress_delta;
+    OFTABLE_CT_ORIG_PROTO_LOAD += ingress_delta;
+    OFTABLE_GET_REMOTE_FDB += ingress_delta;
+
+    LOG_PIPELINE_INGRESS_LEN = new_ingress_len;
+    LOG_PIPELINE_EGRESS_LEN = new_egress_len;
+}
diff --git a/lib/oftable.h b/lib/oftable.h
index 54425964d..ddabb65c5 100644
--- a/lib/oftable.h
+++ b/lib/oftable.h
@@ -56,3 +56,6 @@ extern int OFTABLE_FLOOD_REMOTE_CHASSIS;
 extern int OFTABLE_CT_STATE_SAVE;
 extern int OFTABLE_CT_ORIG_PROTO_LOAD;
 extern int OFTABLE_GET_REMOTE_FDB;
+
+void recalculate_oftable_offsets(int new_ingress_len,
+                                 int new_egress_len);
diff --git a/northd/en-global-config.c b/northd/en-global-config.c
index 51a991ce5..96a8dc690 100644
--- a/northd/en-global-config.c
+++ b/northd/en-global-config.c
@@ -682,6 +682,13 @@ update_sb_config_options_to_sbrec(struct 
ed_type_global_config *config_data,
      * register usage. */
     smap_add(options, "register_consolidation", "true");
 
+
+    smap_add_format(options, "log-pipeline-ingress-len",
+        "%d", LOG_PIPELINE_INGRESS_LEN);
+
+    smap_add_format(options, "log-pipeline-egress-len",
+        "%d", LOG_PIPELINE_EGRESS_LEN);
+
     if (!smap_equal(&sb->options, options)) {
         sbrec_sb_global_set_options(sb, options);
     }
-- 
2.48.1

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

Reply via email to