This change adds a new action 'ct_commit_to_zone' that enables users to commit
the flow into a specific zone in the connection tracker.

A new feature flag, OVN_FEATURE_CT_COMMIT_TO_ZONE, is also included to avoid
issues during upgrade in case the northd is upgraded to a version that supports
this action before the controller is upgraded.

Note that this action is meaningful only in the context of Logical Router
datapath. Logical Switch datapath does not use multiple zones and this action
falls back to committing the connection into the default zone for the Logical
Switch.

Signed-off-by: Martin Kalcok <martin.kal...@canonical.com>
---
 controller/chassis.c      |  8 ++++++
 include/ovn/actions.h     |  1 +
 include/ovn/features.h    |  1 +
 lib/actions.c             | 60 +++++++++++++++++++++++++++++++++++++++
 northd/en-global-config.c | 11 +++++++
 northd/en-global-config.h |  1 +
 ovn-sb.xml                | 24 ++++++++++++++++
 tests/ovn.at              | 16 +++++++++++
 utilities/ovn-trace.c     |  1 +
 9 files changed, 123 insertions(+)

diff --git a/controller/chassis.c b/controller/chassis.c
index ad75df288..9bb2eba95 100644
--- a/controller/chassis.c
+++ b/controller/chassis.c
@@ -371,6 +371,7 @@ chassis_build_other_config(const struct ovs_chassis_cfg 
*ovs_cfg,
     smap_replace(config, OVN_FEATURE_FDB_TIMESTAMP, "true");
     smap_replace(config, OVN_FEATURE_LS_DPG_COLUMN, "true");
     smap_replace(config, OVN_FEATURE_CT_COMMIT_NAT_V2, "true");
+    smap_replace(config, OVN_FEATURE_CT_COMMIT_TO_ZONE, "true");
 }
 
 /*
@@ -516,6 +517,12 @@ chassis_other_config_changed(const struct ovs_chassis_cfg 
*ovs_cfg,
         return true;
     }
 
+    if (!smap_get_bool(&chassis_rec->other_config,
+                       OVN_FEATURE_CT_COMMIT_TO_ZONE,
+                       false)) {
+        return true;
+    }
+
     return false;
 }
 
@@ -648,6 +655,7 @@ update_supported_sset(struct sset *supported)
     sset_add(supported, OVN_FEATURE_FDB_TIMESTAMP);
     sset_add(supported, OVN_FEATURE_LS_DPG_COLUMN);
     sset_add(supported, OVN_FEATURE_CT_COMMIT_NAT_V2);
+    sset_add(supported, OVN_FEATURE_CT_COMMIT_TO_ZONE);
 }
 
 static void
diff --git a/include/ovn/actions.h b/include/ovn/actions.h
index 8e794450c..4bcd1f58c 100644
--- a/include/ovn/actions.h
+++ b/include/ovn/actions.h
@@ -68,6 +68,7 @@ struct collector_set_ids;
     OVNACT(CT_NEXT,           ovnact_ct_next)         \
     /* CT_COMMIT_V1 is not supported anymore. */      \
     OVNACT(CT_COMMIT_V2,      ovnact_nest)            \
+    OVNACT(CT_COMMIT_TO_ZONE, ovnact_ct_commit_nat)   \
     OVNACT(CT_DNAT,           ovnact_ct_nat)          \
     OVNACT(CT_SNAT,           ovnact_ct_nat)          \
     OVNACT(CT_DNAT_IN_CZONE,  ovnact_ct_nat)          \
diff --git a/include/ovn/features.h b/include/ovn/features.h
index 08f1d8288..35a5d8ba0 100644
--- a/include/ovn/features.h
+++ b/include/ovn/features.h
@@ -28,6 +28,7 @@
 #define OVN_FEATURE_FDB_TIMESTAMP "fdb-timestamp"
 #define OVN_FEATURE_LS_DPG_COLUMN "ls-dpg-column"
 #define OVN_FEATURE_CT_COMMIT_NAT_V2 "ct-commit-nat-v2"
+#define OVN_FEATURE_CT_COMMIT_TO_ZONE "ct-commit-to-zone"
 
 /* OVS datapath supported features.  Based on availability OVN might generate
  * different types of openflows.
diff --git a/lib/actions.c b/lib/actions.c
index 39bb5bc8a..f26817018 100644
--- a/lib/actions.c
+++ b/lib/actions.c
@@ -791,6 +791,64 @@ encode_CT_COMMIT_V2(const struct ovnact_nest *on,
     ofpacts->header = ofpbuf_push_uninit(ofpacts, set_field_offset);
     ct = ofpacts->header;
     ofpact_finish(ofpacts, &ct->ofpact);
+}
+
+static void
+parse_CT_COMMIT_TO_ZONE(struct action_context *ctx)
+{
+    add_prerequisite(ctx, "ip");
+
+    struct ovnact_ct_commit_nat *ct_commit =
+        ovnact_put_CT_COMMIT_TO_ZONE(ctx->ovnacts);
+
+    lexer_force_match(ctx->lexer, LEX_T_LPAREN);
+
+    if (lexer_match_id(ctx->lexer, "dnat")) {
+        ct_commit->dnat_zone = true;
+    } else if (lexer_match_id(ctx->lexer, "snat")) {
+        ct_commit->dnat_zone = false;
+    } else {
+        lexer_syntax_error(ctx->lexer, "expecting parameter 'dnat' or 'snat'");
+    }
+
+    lexer_force_match(ctx->lexer, LEX_T_RPAREN);
+}
+
+static void
+format_CT_COMMIT_TO_ZONE(const struct ovnact_ct_commit_nat *ct_commit,
+                         struct ds *s)
+{
+    ds_put_format(s, "ct_commit_to_zone(%s);",
+                  ct_commit->dnat_zone ? "dnat" : "snat");
+
+}
+
+static void
+encode_CT_COMMIT_TO_ZONE(const struct ovnact_ct_commit_nat *ct_commit,
+                         const struct ovnact_encode_params *ep,
+                         struct ofpbuf *ofpacts)
+{
+    struct ofpact_conntrack *ct = ofpact_put_CT(ofpacts);
+    ct->flags = NX_CT_F_COMMIT;
+    ct->recirc_table = NX_CT_RECIRC_NONE;
+    ct->zone_src.ofs = 0;
+    ct->zone_src.n_bits = 16;
+
+    if (ep->is_switch) {
+        ct->zone_src.field = mf_from_id(MFF_LOG_CT_ZONE);
+    } else {
+        ct->zone_src.field = mf_from_id(ct_commit->dnat_zone
+                                        ? MFF_LOG_DNAT_ZONE
+                                        : MFF_LOG_SNAT_ZONE);
+    }
+
+    size_t set_field_offset = ofpacts->size;
+    ofpbuf_pull(ofpacts, set_field_offset);
+    ofpacts->header = ofpbuf_push_uninit(ofpacts, set_field_offset);
+    ct = ofpacts->header;
+    ofpact_finish(ofpacts, &ct->ofpact);
+
+
 }
 
 static void
@@ -5306,6 +5364,8 @@ parse_action(struct action_context *ctx)
         parse_CT_NEXT(ctx);
     } else if (lexer_match_id(ctx->lexer, "ct_commit")) {
         parse_CT_COMMIT(ctx);
+    } else if (lexer_match_id(ctx->lexer, "ct_commit_to_zone")) {
+        parse_CT_COMMIT_TO_ZONE(ctx);
     } else if (lexer_match_id(ctx->lexer, "ct_dnat")) {
         parse_CT_DNAT(ctx);
     } else if (lexer_match_id(ctx->lexer, "ct_snat")) {
diff --git a/northd/en-global-config.c b/northd/en-global-config.c
index 34e393b33..842ac5b64 100644
--- a/northd/en-global-config.c
+++ b/northd/en-global-config.c
@@ -370,6 +370,7 @@ northd_enable_all_features(struct ed_type_global_config 
*data)
         .fdb_timestamp = true,
         .ls_dpg_column = true,
         .ct_commit_nat_v2 = true,
+        .ct_commit_to_zone = true,
     };
 }
 
@@ -439,6 +440,16 @@ build_chassis_features(const struct sbrec_chassis_table 
*sbrec_chassis_table,
             chassis_features->ct_commit_nat_v2) {
             chassis_features->ct_commit_nat_v2 = false;
         }
+
+        bool ct_commit_to_zone =
+                smap_get_bool(&chassis->other_config,
+                              OVN_FEATURE_CT_COMMIT_TO_ZONE,
+                              false);
+        if (!ct_commit_to_zone &&
+            chassis_features->ct_commit_to_zone) {
+            chassis_features->ct_commit_to_zone = false;
+        }
+
     }
 }
 
diff --git a/northd/en-global-config.h b/northd/en-global-config.h
index 38d732808..842bcee70 100644
--- a/northd/en-global-config.h
+++ b/northd/en-global-config.h
@@ -20,6 +20,7 @@ struct chassis_features {
     bool fdb_timestamp;
     bool ls_dpg_column;
     bool ct_commit_nat_v2;
+    bool ct_commit_to_zone;
 };
 
 struct global_config_tracked_data {
diff --git a/ovn-sb.xml b/ovn-sb.xml
index 4c26c6714..0d1f640dd 100644
--- a/ovn-sb.xml
+++ b/ovn-sb.xml
@@ -1432,6 +1432,30 @@
           </p>
         </dd>
 
+        <dt><code>ct_commit_to_zone(dnat);</code></dt>
+        <dt><code>ct_commit_to_zone(snat);</code></dt>
+        <dd>
+          <p>
+            Commit the flow to the specific zone in the connection tracker.
+            Similar to the <code>ct_commit</code> action, this action requires
+            previous call to <code>ct_next</code> to initialize connection
+            tracking state.
+          </p>
+
+          <p>
+            If you want processing to continue in the next table, you must
+            execute the <code>next</code> action after
+            <code>ct_commit_to_zone</code>.
+          </p>
+
+          <p>
+            Note that this action is meaningful only in the Logical Router
+            Datapath as the Logical Switch Datapath does not use separate
+            connection tracking zones. Using this action in Logical Switch
+            Datapath falls back to committing the flow into the switch's
+            default zone.
+          </p>
+        </dd>
         <dt><code>ct_dnat;</code></dt>
         <dt><code>ct_dnat(<var>IP</var>);</code></dt>
         <dd>
diff --git a/tests/ovn.at b/tests/ovn.at
index c8cc1d37f..cbb303459 100644
--- a/tests/ovn.at
+++ b/tests/ovn.at
@@ -1316,6 +1316,22 @@ ct_commit { 
ct_label=0x181716151413121110090807060504030201; };
 ct_commit { ip4.dst = 192.168.0.1; };
     Field ip4.dst is not modifiable.
 
+# ct_commit_to_zone
+ct_commit_to_zone(dnat);
+    encodes as ct(commit,zone=NXM_NX_REG13[[0..15]])
+    has prereqs ip
+ct_commit_to_zone(dnat);
+    encodes as ct(commit,zone=NXM_NX_REG13[[0..15]])
+    has prereqs ip
+ct_commit_to_zone;
+    Syntax error at `;' expecting `('.
+ct_commit_to_zone();
+    Syntax error at `)' expecting parameter 'dnat' or 'snat'.
+ct_commit_to_zone(foo);
+    Syntax error at `foo' expecting parameter 'dnat' or 'snat'.
+ct_commit_to_zone(dnat;
+    Syntax error at `;' expecting `)'.
+
 # Legact ct_commit_v1 action.
 ct_commit();
     Syntax error at `(' expecting `;'.
diff --git a/utilities/ovn-trace.c b/utilities/ovn-trace.c
index 5e55fbbcc..554682cd0 100644
--- a/utilities/ovn-trace.c
+++ b/utilities/ovn-trace.c
@@ -3107,6 +3107,7 @@ trace_actions(const struct ovnact *ovnacts, size_t 
ovnacts_len,
             execute_ct_next(ovnact_get_CT_NEXT(a), dp, uflow, pipeline, super);
             break;
 
+        case OVNACT_CT_COMMIT_TO_ZONE:
         case OVNACT_CT_COMMIT_V2:
             /* Nothing to do. */
             break;
-- 
2.40.1

_______________________________________________
dev mailing list
d...@openvswitch.org
https://mail.openvswitch.org/mailman/listinfo/ovs-dev

Reply via email to