diff mbox series

[ovs-dev,v2,1/2] actions: Add new actions - ct_dnat_in_czone and ct_snat_in_czone.

Message ID 20211118181305.92940-1-numans@ovn.org
State Changes Requested
Headers show
Series [ovs-dev,v2,1/2] actions: Add new actions - ct_dnat_in_czone and ct_snat_in_czone. | expand

Checks

Context Check Description
ovsrobot/apply-robot success apply and check: success
ovsrobot/github-robot-_Build_and_Test success github build: passed
ovsrobot/github-robot-_ovn-kubernetes fail github build: failed

Commit Message

Numan Siddique Nov. 18, 2021, 6:13 p.m. UTC
From: Numan Siddique <numans@ovn.org>

These actions are very similar to ct_dnat and ct_snat respectively
with one difference.  These new actions use the same zone id
for natting.  Upcoming patch will make use of these actions.

Signed-off-by: Numan Siddique <numans@ovn.org>
---

v1 -> v2
----
 * No changes.

 include/ovn/actions.h        |  2 ++
 include/ovn/logical-fields.h |  2 ++
 lib/actions.c                | 59 +++++++++++++++++++++++++-----
 ovn-sb.xml                   | 44 +++++++++++++++++++++++
 tests/ovn.at                 | 69 ++++++++++++++++++++++++++++++++++++
 utilities/ovn-trace.c        | 18 ++++++++--
 6 files changed, 184 insertions(+), 10 deletions(-)

Comments

Mark Michelson Nov. 18, 2021, 9:37 p.m. UTC | #1
Acked-by: Mark Michelson <mmichels@redhat.com>

On 11/18/21 13:13, numans@ovn.org wrote:
> From: Numan Siddique <numans@ovn.org>
> 
> These actions are very similar to ct_dnat and ct_snat respectively
> with one difference.  These new actions use the same zone id
> for natting.  Upcoming patch will make use of these actions.
> 
> Signed-off-by: Numan Siddique <numans@ovn.org>
> ---
> 
> v1 -> v2
> ----
>   * No changes.
> 
>   include/ovn/actions.h        |  2 ++
>   include/ovn/logical-fields.h |  2 ++
>   lib/actions.c                | 59 +++++++++++++++++++++++++-----
>   ovn-sb.xml                   | 44 +++++++++++++++++++++++
>   tests/ovn.at                 | 69 ++++++++++++++++++++++++++++++++++++
>   utilities/ovn-trace.c        | 18 ++++++++--
>   6 files changed, 184 insertions(+), 10 deletions(-)
> 
> diff --git a/include/ovn/actions.h b/include/ovn/actions.h
> index f023a37b9..ede5eb93c 100644
> --- a/include/ovn/actions.h
> +++ b/include/ovn/actions.h
> @@ -66,6 +66,8 @@ struct ovn_extend_table;
>       OVNACT(CT_COMMIT_V2,      ovnact_nest)            \
>       OVNACT(CT_DNAT,           ovnact_ct_nat)          \
>       OVNACT(CT_SNAT,           ovnact_ct_nat)          \
> +    OVNACT(CT_DNAT_IN_CZONE,  ovnact_ct_nat)          \
> +    OVNACT(CT_SNAT_IN_CZONE,  ovnact_ct_nat)          \
>       OVNACT(CT_LB,             ovnact_ct_lb)           \
>       OVNACT(SELECT,            ovnact_select)          \
>       OVNACT(CT_CLEAR,          ovnact_null)            \
> diff --git a/include/ovn/logical-fields.h b/include/ovn/logical-fields.h
> index ef97117b9..c9675f81c 100644
> --- a/include/ovn/logical-fields.h
> +++ b/include/ovn/logical-fields.h
> @@ -36,6 +36,8 @@ enum ovn_controller_event {
>                                          * (32 bits). */
>   #define MFF_LOG_SNAT_ZONE  MFF_REG12  /* conntrack snat zone for gateway router
>                                          * (32 bits). */
> +#define MFF_LOG_NAT_ZONE   MFF_LOG_DNAT_ZONE /* conntrack zone for both snat
> +                                              * and dnat. */
>   #define MFF_LOG_CT_ZONE    MFF_REG13  /* Logical conntrack zone for lports
>                                          * (32 bits). */
>   #define MFF_LOG_INPORT     MFF_REG14  /* Logical input port (32 bits). */
> diff --git a/lib/actions.c b/lib/actions.c
> index 7cf6be308..6b9a426ae 100644
> --- a/lib/actions.c
> +++ b/lib/actions.c
> @@ -917,6 +917,20 @@ parse_CT_SNAT(struct action_context *ctx)
>       parse_ct_nat(ctx, "ct_snat", ovnact_put_CT_SNAT(ctx->ovnacts));
>   }
>   
> +static void
> +parse_CT_DNAT_IN_CZONE(struct action_context *ctx)
> +{
> +    parse_ct_nat(ctx, "ct_dnat_in_czone",
> +                 ovnact_put_CT_DNAT_IN_CZONE(ctx->ovnacts));
> +}
> +
> +static void
> +parse_CT_SNAT_IN_CZONE(struct action_context *ctx)
> +{
> +    parse_ct_nat(ctx, "ct_snat_in_czone",
> +                 ovnact_put_CT_SNAT_IN_CZONE(ctx->ovnacts));
> +}
> +
>   static void
>   format_ct_nat(const struct ovnact_ct_nat *cn, const char *name, struct ds *s)
>   {
> @@ -954,21 +968,30 @@ format_CT_SNAT(const struct ovnact_ct_nat *cn, struct ds *s)
>       format_ct_nat(cn, "ct_snat", s);
>   }
>   
> +static void
> +format_CT_DNAT_IN_CZONE(const struct ovnact_ct_nat *cn, struct ds *s)
> +{
> +    format_ct_nat(cn, "ct_dnat_in_czone", s);
> +}
> +
> +static void
> +format_CT_SNAT_IN_CZONE(const struct ovnact_ct_nat *cn, struct ds *s)
> +{
> +    format_ct_nat(cn, "ct_snat_in_czone", s);
> +}
> +
>   static void
>   encode_ct_nat(const struct ovnact_ct_nat *cn,
>                 const struct ovnact_encode_params *ep,
> -              bool snat, struct ofpbuf *ofpacts)
> +              bool snat, enum mf_field_id zone_src,
> +              struct ofpbuf *ofpacts)
>   {
>       const size_t ct_offset = ofpacts->size;
>       ofpbuf_pull(ofpacts, ct_offset);
>   
>       struct ofpact_conntrack *ct = ofpact_put_CT(ofpacts);
>       ct->recirc_table = cn->ltable + first_ptable(ep, ep->pipeline);
> -    if (snat) {
> -        ct->zone_src.field = mf_from_id(MFF_LOG_SNAT_ZONE);
> -    } else {
> -        ct->zone_src.field = mf_from_id(MFF_LOG_DNAT_ZONE);
> -    }
> +    ct->zone_src.field = mf_from_id(zone_src);
>       ct->zone_src.ofs = 0;
>       ct->zone_src.n_bits = 16;
>       ct->flags = 0;
> @@ -1020,7 +1043,7 @@ encode_CT_DNAT(const struct ovnact_ct_nat *cn,
>                  const struct ovnact_encode_params *ep,
>                  struct ofpbuf *ofpacts)
>   {
> -    encode_ct_nat(cn, ep, false, ofpacts);
> +    encode_ct_nat(cn, ep, false, MFF_LOG_DNAT_ZONE, ofpacts);
>   }
>   
>   static void
> @@ -1028,7 +1051,23 @@ encode_CT_SNAT(const struct ovnact_ct_nat *cn,
>                  const struct ovnact_encode_params *ep,
>                  struct ofpbuf *ofpacts)
>   {
> -    encode_ct_nat(cn, ep, true, ofpacts);
> +    encode_ct_nat(cn, ep, true, MFF_LOG_SNAT_ZONE, ofpacts);
> +}
> +
> +static void
> +encode_CT_DNAT_IN_CZONE(const struct ovnact_ct_nat *cn,
> +                        const struct ovnact_encode_params *ep,
> +                        struct ofpbuf *ofpacts)
> +{
> +    encode_ct_nat(cn, ep, false, MFF_LOG_NAT_ZONE, ofpacts);
> +}
> +
> +static void
> +encode_CT_SNAT_IN_CZONE(const struct ovnact_ct_nat *cn,
> +                        const struct ovnact_encode_params *ep,
> +                        struct ofpbuf *ofpacts)
> +{
> +    encode_ct_nat(cn, ep, true, MFF_LOG_NAT_ZONE, ofpacts);
>   }
>   
>   static void
> @@ -4017,6 +4056,10 @@ parse_action(struct action_context *ctx)
>           parse_CT_DNAT(ctx);
>       } else if (lexer_match_id(ctx->lexer, "ct_snat")) {
>           parse_CT_SNAT(ctx);
> +    } else if (lexer_match_id(ctx->lexer, "ct_dnat_in_czone")) {
> +        parse_CT_DNAT_IN_CZONE(ctx);
> +    } else if (lexer_match_id(ctx->lexer, "ct_snat_in_czone")) {
> +        parse_CT_SNAT_IN_CZONE(ctx);
>       } else if (lexer_match_id(ctx->lexer, "ct_lb")) {
>           parse_ct_lb_action(ctx);
>       } else if (lexer_match_id(ctx->lexer, "ct_clear")) {
> diff --git a/ovn-sb.xml b/ovn-sb.xml
> index 150051f26..9ddacdf09 100644
> --- a/ovn-sb.xml
> +++ b/ovn-sb.xml
> @@ -1383,6 +1383,50 @@
>             </p>
>           </dd>
>   
> +        <dt><code>ct_dnat_in_czone;</code></dt>
> +        <dt><code>ct_dnat_in_czone(<var>IP</var>);</code></dt>
> +        <dd>
> +          <p>
> +            <code>ct_dnat_in_czone</code> sends the packet through the common
> +            NAT zone (used for both DNAT and SNAT) in connection tracking table
> +            to unDNAT any packet that was DNATed in the opposite direction.
> +            The packet is then automatically sent to to the next tables as if
> +            followed by <code>next;</code> action.  The next tables will see
> +            the changes in the packet caused by the connection tracker.
> +          </p>
> +          <p>
> +            <code>ct_dnat_in_czone(<var>IP</var>)</code> sends the packet
> +            through the common NAT zone to change the destination IP address
> +            of the packet to the one provided inside the parentheses and
> +            commits the connection.  The packet is then automatically sent to
> +            the next tables as if followed by <code>next;</code> action.  The
> +            next tables will see the changes in the packet caused by the
> +            connection tracker.
> +          </p>
> +        </dd>
> +
> +        <dt><code>ct_snat_in_czone;</code></dt>
> +        <dt><code>ct_snat_in_czone(<var>IP</var>);</code></dt>
> +        <dd>
> +          <p>
> +            <code>ct_snat_in_czone</code> sends the packet through the common
> +            NAT zone to unSNAT any packet that was SNATed in the opposite
> +            direction.  The packet is automatically sent to the next tables as
> +            if followed by the <code>next;</code> action.   The next tables
> +            will see the changes in the packet caused by the connection
> +            tracker.
> +          </p>
> +          <p>
> +            <code>ct_snat_in_czone(<var>IP</var>)</code> sends the packet\
> +            through the common NAT zone to change the source IP address of
> +            the packet to the one provided inside the parenthesis and commits
> +            the connection.  The packet is then automatically sent to the next
> +            tables as if followed by <code>next;</code> action.  The next
> +            tables will see the changes in the packet caused by the connection
> +            tracker.
> +          </p>
> +        </dd>
> +
>           <dt><code>ct_clear;</code></dt>
>           <dd>
>             Clears connection tracking state.
> diff --git a/tests/ovn.at b/tests/ovn.at
> index ae832918c..0d606b42f 100644
> --- a/tests/ovn.at
> +++ b/tests/ovn.at
> @@ -1193,6 +1193,40 @@ ct_dnat(192.168.1.2, 1000);
>   ct_dnat(192.168.1.2, 1000-100);
>       Syntax error at `100' range high should be greater than range low.
>   
> +# ct_dnat_in_czone
> +ct_dnat_in_czone;
> +    encodes as ct(table=19,zone=NXM_NX_REG11[0..15],nat)
> +    has prereqs ip
> +ct_dnat_in_czone(192.168.1.2);
> +    encodes as ct(commit,table=19,zone=NXM_NX_REG11[0..15],nat(dst=192.168.1.2))
> +    has prereqs ip
> +ct_dnat_in_czone(fd11::2);
> +    encodes as ct(commit,table=19,zone=NXM_NX_REG11[0..15],nat(dst=fd11::2))
> +    has prereqs ip
> +ct_dnat_in_czone(192.168.1.2, 1-3000);
> +    formats as ct_dnat_in_czone(192.168.1.2,1-3000);
> +    encodes as ct(commit,table=19,zone=NXM_NX_REG11[0..15],nat(dst=192.168.1.2:1-3000))
> +    has prereqs ip
> +
> +ct_dnat_in_czone(192.168.1.2, 192.168.1.3);
> +    Syntax error at `192.168.1.3' expecting Integer for port range.
> +ct_dnat_in_czone(foo);
> +    Syntax error at `foo' expecting IPv4 or IPv6 address.
> +ct_dnat_in_czone(foo, bar);
> +    Syntax error at `foo' expecting IPv4 or IPv6 address.
> +ct_dnat_in_czone();
> +    Syntax error at `)' expecting IPv4 or IPv6 address.
> +ct_dnat_in_czone(192.168.1.2, foo);
> +    Syntax error at `foo' expecting Integer for port range.
> +ct_dnat_in_czone(192.168.1.2, 1000-foo);
> +    Syntax error at `foo' expecting Integer for port range.
> +ct_dnat_in_czone(192.168.1.2, 1000);
> +    formats as ct_dnat_in_czone(192.168.1.2,1000);
> +    encodes as ct(commit,table=19,zone=NXM_NX_REG11[0..15],nat(dst=192.168.1.2:1000))
> +    has prereqs ip
> +ct_dnat_in_czone(192.168.1.2, 1000-100);
> +    Syntax error at `100' range high should be greater than range low.
> +
>   # ct_snat
>   ct_snat;
>       encodes as ct(table=19,zone=NXM_NX_REG12[0..15],nat)
> @@ -1226,6 +1260,41 @@ ct_snat(192.168.1.2, 1000);
>       has prereqs ip
>   ct_snat(192.168.1.2, 1000-100);
>       Syntax error at `100' range high should be greater than range low.
> +
> +# ct_snat_in_czone
> +ct_snat_in_czone;
> +    encodes as ct(table=19,zone=NXM_NX_REG11[0..15],nat)
> +    has prereqs ip
> +ct_snat_in_czone(192.168.1.2);
> +    encodes as ct(commit,table=19,zone=NXM_NX_REG11[0..15],nat(src=192.168.1.2))
> +    has prereqs ip
> +ct_snat_in_czone(fd11::2);
> +    encodes as ct(commit,table=19,zone=NXM_NX_REG11[0..15],nat(src=fd11::2))
> +    has prereqs ip
> +ct_snat_in_czone(192.168.1.2, 1-3000);
> +    formats as ct_snat_in_czone(192.168.1.2,1-3000);
> +    encodes as ct(commit,table=19,zone=NXM_NX_REG11[0..15],nat(src=192.168.1.2:1-3000))
> +    has prereqs ip
> +
> +ct_snat_in_czone(192.168.1.2, 192.168.1.3);
> +    Syntax error at `192.168.1.3' expecting Integer for port range.
> +ct_snat_in_czone(foo);
> +    Syntax error at `foo' expecting IPv4 or IPv6 address.
> +ct_snat_in_czone(foo, bar);
> +    Syntax error at `foo' expecting IPv4 or IPv6 address.
> +ct_snat_in_czone();
> +    Syntax error at `)' expecting IPv4 or IPv6 address.
> +ct_snat_in_czone(192.168.1.2, foo);
> +    Syntax error at `foo' expecting Integer for port range.
> +ct_snat_in_czone(192.168.1.2, 1000-foo);
> +    Syntax error at `foo' expecting Integer for port range.
> +ct_snat_in_czone(192.168.1.2, 1000);
> +    formats as ct_snat_in_czone(192.168.1.2,1000);
> +    encodes as ct(commit,table=19,zone=NXM_NX_REG11[0..15],nat(src=192.168.1.2:1000))
> +    has prereqs ip
> +ct_snat_in_czone(192.168.1.2, 1000-100);
> +    Syntax error at `100' range high should be greater than range low.
> +
>   # ct_clear
>   ct_clear;
>       encodes as ct_clear
> diff --git a/utilities/ovn-trace.c b/utilities/ovn-trace.c
> index 65a1822ea..617ad834c 100644
> --- a/utilities/ovn-trace.c
> +++ b/utilities/ovn-trace.c
> @@ -2286,7 +2286,10 @@ execute_ct_nat(const struct ovnact_ct_nat *ct_nat,
>                  const struct ovntrace_datapath *dp, struct flow *uflow,
>                  enum ovnact_pipeline pipeline, struct ovs_list *super)
>   {
> -    bool is_dst = ct_nat->ovnact.type == OVNACT_CT_DNAT;
> +    bool is_dst = (ct_nat->ovnact.type == OVNACT_CT_DNAT ||
> +                   ct_nat->ovnact.type == OVNACT_CT_DNAT_IN_CZONE);
> +    bool nat_in_czone = (ct_nat->ovnact.type == OVNACT_CT_DNAT_IN_CZONE ||
> +                         ct_nat->ovnact.type == OVNACT_CT_SNAT_IN_CZONE);
>       if (!is_dst && dp->has_local_l3gateway && ct_nat->family == AF_UNSPEC) {
>           /* "ct_snat;" has no visible effect in a gateway router. */
>           return;
> @@ -2297,7 +2300,8 @@ execute_ct_nat(const struct ovnact_ct_nat *ct_nat,
>        * and figure out the changes if any. */
>       struct flow ct_flow = *uflow;
>       struct ds s = DS_EMPTY_INITIALIZER;
> -    ds_put_format(&s, "ct_%cnat", direction[0]);
> +    ds_put_format(&s, "ct_%cnat%s", direction[0],
> +                  nat_in_czone ? "in_czone" : "");
>       if (ct_nat->family != AF_UNSPEC) {
>           if (ct_nat->family == AF_INET) {
>               ds_put_format(&s, "(ip4.%s="IP_FMT")", direction,
> @@ -2610,6 +2614,16 @@ trace_actions(const struct ovnact *ovnacts, size_t ovnacts_len,
>               execute_ct_nat(ovnact_get_CT_SNAT(a), dp, uflow, pipeline, super);
>               break;
>   
> +        case OVNACT_CT_DNAT_IN_CZONE:
> +            execute_ct_nat(ovnact_get_CT_DNAT_IN_CZONE(a), dp, uflow,
> +                           pipeline, super);
> +            break;
> +
> +        case OVNACT_CT_SNAT_IN_CZONE:
> +            execute_ct_nat(ovnact_get_CT_SNAT_IN_CZONE(a), dp, uflow,
> +                           pipeline, super);
> +            break;
> +
>           case OVNACT_CT_LB:
>               execute_ct_lb(ovnact_get_CT_LB(a), dp, uflow, pipeline, super);
>               break;
>
diff mbox series

Patch

diff --git a/include/ovn/actions.h b/include/ovn/actions.h
index f023a37b9..ede5eb93c 100644
--- a/include/ovn/actions.h
+++ b/include/ovn/actions.h
@@ -66,6 +66,8 @@  struct ovn_extend_table;
     OVNACT(CT_COMMIT_V2,      ovnact_nest)            \
     OVNACT(CT_DNAT,           ovnact_ct_nat)          \
     OVNACT(CT_SNAT,           ovnact_ct_nat)          \
+    OVNACT(CT_DNAT_IN_CZONE,  ovnact_ct_nat)          \
+    OVNACT(CT_SNAT_IN_CZONE,  ovnact_ct_nat)          \
     OVNACT(CT_LB,             ovnact_ct_lb)           \
     OVNACT(SELECT,            ovnact_select)          \
     OVNACT(CT_CLEAR,          ovnact_null)            \
diff --git a/include/ovn/logical-fields.h b/include/ovn/logical-fields.h
index ef97117b9..c9675f81c 100644
--- a/include/ovn/logical-fields.h
+++ b/include/ovn/logical-fields.h
@@ -36,6 +36,8 @@  enum ovn_controller_event {
                                        * (32 bits). */
 #define MFF_LOG_SNAT_ZONE  MFF_REG12  /* conntrack snat zone for gateway router
                                        * (32 bits). */
+#define MFF_LOG_NAT_ZONE   MFF_LOG_DNAT_ZONE /* conntrack zone for both snat
+                                              * and dnat. */
 #define MFF_LOG_CT_ZONE    MFF_REG13  /* Logical conntrack zone for lports
                                        * (32 bits). */
 #define MFF_LOG_INPORT     MFF_REG14  /* Logical input port (32 bits). */
diff --git a/lib/actions.c b/lib/actions.c
index 7cf6be308..6b9a426ae 100644
--- a/lib/actions.c
+++ b/lib/actions.c
@@ -917,6 +917,20 @@  parse_CT_SNAT(struct action_context *ctx)
     parse_ct_nat(ctx, "ct_snat", ovnact_put_CT_SNAT(ctx->ovnacts));
 }
 
+static void
+parse_CT_DNAT_IN_CZONE(struct action_context *ctx)
+{
+    parse_ct_nat(ctx, "ct_dnat_in_czone",
+                 ovnact_put_CT_DNAT_IN_CZONE(ctx->ovnacts));
+}
+
+static void
+parse_CT_SNAT_IN_CZONE(struct action_context *ctx)
+{
+    parse_ct_nat(ctx, "ct_snat_in_czone",
+                 ovnact_put_CT_SNAT_IN_CZONE(ctx->ovnacts));
+}
+
 static void
 format_ct_nat(const struct ovnact_ct_nat *cn, const char *name, struct ds *s)
 {
@@ -954,21 +968,30 @@  format_CT_SNAT(const struct ovnact_ct_nat *cn, struct ds *s)
     format_ct_nat(cn, "ct_snat", s);
 }
 
+static void
+format_CT_DNAT_IN_CZONE(const struct ovnact_ct_nat *cn, struct ds *s)
+{
+    format_ct_nat(cn, "ct_dnat_in_czone", s);
+}
+
+static void
+format_CT_SNAT_IN_CZONE(const struct ovnact_ct_nat *cn, struct ds *s)
+{
+    format_ct_nat(cn, "ct_snat_in_czone", s);
+}
+
 static void
 encode_ct_nat(const struct ovnact_ct_nat *cn,
               const struct ovnact_encode_params *ep,
-              bool snat, struct ofpbuf *ofpacts)
+              bool snat, enum mf_field_id zone_src,
+              struct ofpbuf *ofpacts)
 {
     const size_t ct_offset = ofpacts->size;
     ofpbuf_pull(ofpacts, ct_offset);
 
     struct ofpact_conntrack *ct = ofpact_put_CT(ofpacts);
     ct->recirc_table = cn->ltable + first_ptable(ep, ep->pipeline);
-    if (snat) {
-        ct->zone_src.field = mf_from_id(MFF_LOG_SNAT_ZONE);
-    } else {
-        ct->zone_src.field = mf_from_id(MFF_LOG_DNAT_ZONE);
-    }
+    ct->zone_src.field = mf_from_id(zone_src);
     ct->zone_src.ofs = 0;
     ct->zone_src.n_bits = 16;
     ct->flags = 0;
@@ -1020,7 +1043,7 @@  encode_CT_DNAT(const struct ovnact_ct_nat *cn,
                const struct ovnact_encode_params *ep,
                struct ofpbuf *ofpacts)
 {
-    encode_ct_nat(cn, ep, false, ofpacts);
+    encode_ct_nat(cn, ep, false, MFF_LOG_DNAT_ZONE, ofpacts);
 }
 
 static void
@@ -1028,7 +1051,23 @@  encode_CT_SNAT(const struct ovnact_ct_nat *cn,
                const struct ovnact_encode_params *ep,
                struct ofpbuf *ofpacts)
 {
-    encode_ct_nat(cn, ep, true, ofpacts);
+    encode_ct_nat(cn, ep, true, MFF_LOG_SNAT_ZONE, ofpacts);
+}
+
+static void
+encode_CT_DNAT_IN_CZONE(const struct ovnact_ct_nat *cn,
+                        const struct ovnact_encode_params *ep,
+                        struct ofpbuf *ofpacts)
+{
+    encode_ct_nat(cn, ep, false, MFF_LOG_NAT_ZONE, ofpacts);
+}
+
+static void
+encode_CT_SNAT_IN_CZONE(const struct ovnact_ct_nat *cn,
+                        const struct ovnact_encode_params *ep,
+                        struct ofpbuf *ofpacts)
+{
+    encode_ct_nat(cn, ep, true, MFF_LOG_NAT_ZONE, ofpacts);
 }
 
 static void
@@ -4017,6 +4056,10 @@  parse_action(struct action_context *ctx)
         parse_CT_DNAT(ctx);
     } else if (lexer_match_id(ctx->lexer, "ct_snat")) {
         parse_CT_SNAT(ctx);
+    } else if (lexer_match_id(ctx->lexer, "ct_dnat_in_czone")) {
+        parse_CT_DNAT_IN_CZONE(ctx);
+    } else if (lexer_match_id(ctx->lexer, "ct_snat_in_czone")) {
+        parse_CT_SNAT_IN_CZONE(ctx);
     } else if (lexer_match_id(ctx->lexer, "ct_lb")) {
         parse_ct_lb_action(ctx);
     } else if (lexer_match_id(ctx->lexer, "ct_clear")) {
diff --git a/ovn-sb.xml b/ovn-sb.xml
index 150051f26..9ddacdf09 100644
--- a/ovn-sb.xml
+++ b/ovn-sb.xml
@@ -1383,6 +1383,50 @@ 
           </p>
         </dd>
 
+        <dt><code>ct_dnat_in_czone;</code></dt>
+        <dt><code>ct_dnat_in_czone(<var>IP</var>);</code></dt>
+        <dd>
+          <p>
+            <code>ct_dnat_in_czone</code> sends the packet through the common
+            NAT zone (used for both DNAT and SNAT) in connection tracking table
+            to unDNAT any packet that was DNATed in the opposite direction.
+            The packet is then automatically sent to to the next tables as if
+            followed by <code>next;</code> action.  The next tables will see
+            the changes in the packet caused by the connection tracker.
+          </p>
+          <p>
+            <code>ct_dnat_in_czone(<var>IP</var>)</code> sends the packet
+            through the common NAT zone to change the destination IP address
+            of the packet to the one provided inside the parentheses and
+            commits the connection.  The packet is then automatically sent to
+            the next tables as if followed by <code>next;</code> action.  The
+            next tables will see the changes in the packet caused by the
+            connection tracker.
+          </p>
+        </dd>
+
+        <dt><code>ct_snat_in_czone;</code></dt>
+        <dt><code>ct_snat_in_czone(<var>IP</var>);</code></dt>
+        <dd>
+          <p>
+            <code>ct_snat_in_czone</code> sends the packet through the common
+            NAT zone to unSNAT any packet that was SNATed in the opposite
+            direction.  The packet is automatically sent to the next tables as
+            if followed by the <code>next;</code> action.   The next tables
+            will see the changes in the packet caused by the connection
+            tracker.
+          </p>
+          <p>
+            <code>ct_snat_in_czone(<var>IP</var>)</code> sends the packet\
+            through the common NAT zone to change the source IP address of
+            the packet to the one provided inside the parenthesis and commits
+            the connection.  The packet is then automatically sent to the next
+            tables as if followed by <code>next;</code> action.  The next
+            tables will see the changes in the packet caused by the connection
+            tracker.
+          </p>
+        </dd>
+
         <dt><code>ct_clear;</code></dt>
         <dd>
           Clears connection tracking state.
diff --git a/tests/ovn.at b/tests/ovn.at
index ae832918c..0d606b42f 100644
--- a/tests/ovn.at
+++ b/tests/ovn.at
@@ -1193,6 +1193,40 @@  ct_dnat(192.168.1.2, 1000);
 ct_dnat(192.168.1.2, 1000-100);
     Syntax error at `100' range high should be greater than range low.
 
+# ct_dnat_in_czone
+ct_dnat_in_czone;
+    encodes as ct(table=19,zone=NXM_NX_REG11[0..15],nat)
+    has prereqs ip
+ct_dnat_in_czone(192.168.1.2);
+    encodes as ct(commit,table=19,zone=NXM_NX_REG11[0..15],nat(dst=192.168.1.2))
+    has prereqs ip
+ct_dnat_in_czone(fd11::2);
+    encodes as ct(commit,table=19,zone=NXM_NX_REG11[0..15],nat(dst=fd11::2))
+    has prereqs ip
+ct_dnat_in_czone(192.168.1.2, 1-3000);
+    formats as ct_dnat_in_czone(192.168.1.2,1-3000);
+    encodes as ct(commit,table=19,zone=NXM_NX_REG11[0..15],nat(dst=192.168.1.2:1-3000))
+    has prereqs ip
+
+ct_dnat_in_czone(192.168.1.2, 192.168.1.3);
+    Syntax error at `192.168.1.3' expecting Integer for port range.
+ct_dnat_in_czone(foo);
+    Syntax error at `foo' expecting IPv4 or IPv6 address.
+ct_dnat_in_czone(foo, bar);
+    Syntax error at `foo' expecting IPv4 or IPv6 address.
+ct_dnat_in_czone();
+    Syntax error at `)' expecting IPv4 or IPv6 address.
+ct_dnat_in_czone(192.168.1.2, foo);
+    Syntax error at `foo' expecting Integer for port range.
+ct_dnat_in_czone(192.168.1.2, 1000-foo);
+    Syntax error at `foo' expecting Integer for port range.
+ct_dnat_in_czone(192.168.1.2, 1000);
+    formats as ct_dnat_in_czone(192.168.1.2,1000);
+    encodes as ct(commit,table=19,zone=NXM_NX_REG11[0..15],nat(dst=192.168.1.2:1000))
+    has prereqs ip
+ct_dnat_in_czone(192.168.1.2, 1000-100);
+    Syntax error at `100' range high should be greater than range low.
+
 # ct_snat
 ct_snat;
     encodes as ct(table=19,zone=NXM_NX_REG12[0..15],nat)
@@ -1226,6 +1260,41 @@  ct_snat(192.168.1.2, 1000);
     has prereqs ip
 ct_snat(192.168.1.2, 1000-100);
     Syntax error at `100' range high should be greater than range low.
+
+# ct_snat_in_czone
+ct_snat_in_czone;
+    encodes as ct(table=19,zone=NXM_NX_REG11[0..15],nat)
+    has prereqs ip
+ct_snat_in_czone(192.168.1.2);
+    encodes as ct(commit,table=19,zone=NXM_NX_REG11[0..15],nat(src=192.168.1.2))
+    has prereqs ip
+ct_snat_in_czone(fd11::2);
+    encodes as ct(commit,table=19,zone=NXM_NX_REG11[0..15],nat(src=fd11::2))
+    has prereqs ip
+ct_snat_in_czone(192.168.1.2, 1-3000);
+    formats as ct_snat_in_czone(192.168.1.2,1-3000);
+    encodes as ct(commit,table=19,zone=NXM_NX_REG11[0..15],nat(src=192.168.1.2:1-3000))
+    has prereqs ip
+
+ct_snat_in_czone(192.168.1.2, 192.168.1.3);
+    Syntax error at `192.168.1.3' expecting Integer for port range.
+ct_snat_in_czone(foo);
+    Syntax error at `foo' expecting IPv4 or IPv6 address.
+ct_snat_in_czone(foo, bar);
+    Syntax error at `foo' expecting IPv4 or IPv6 address.
+ct_snat_in_czone();
+    Syntax error at `)' expecting IPv4 or IPv6 address.
+ct_snat_in_czone(192.168.1.2, foo);
+    Syntax error at `foo' expecting Integer for port range.
+ct_snat_in_czone(192.168.1.2, 1000-foo);
+    Syntax error at `foo' expecting Integer for port range.
+ct_snat_in_czone(192.168.1.2, 1000);
+    formats as ct_snat_in_czone(192.168.1.2,1000);
+    encodes as ct(commit,table=19,zone=NXM_NX_REG11[0..15],nat(src=192.168.1.2:1000))
+    has prereqs ip
+ct_snat_in_czone(192.168.1.2, 1000-100);
+    Syntax error at `100' range high should be greater than range low.
+
 # ct_clear
 ct_clear;
     encodes as ct_clear
diff --git a/utilities/ovn-trace.c b/utilities/ovn-trace.c
index 65a1822ea..617ad834c 100644
--- a/utilities/ovn-trace.c
+++ b/utilities/ovn-trace.c
@@ -2286,7 +2286,10 @@  execute_ct_nat(const struct ovnact_ct_nat *ct_nat,
                const struct ovntrace_datapath *dp, struct flow *uflow,
                enum ovnact_pipeline pipeline, struct ovs_list *super)
 {
-    bool is_dst = ct_nat->ovnact.type == OVNACT_CT_DNAT;
+    bool is_dst = (ct_nat->ovnact.type == OVNACT_CT_DNAT ||
+                   ct_nat->ovnact.type == OVNACT_CT_DNAT_IN_CZONE);
+    bool nat_in_czone = (ct_nat->ovnact.type == OVNACT_CT_DNAT_IN_CZONE ||
+                         ct_nat->ovnact.type == OVNACT_CT_SNAT_IN_CZONE);
     if (!is_dst && dp->has_local_l3gateway && ct_nat->family == AF_UNSPEC) {
         /* "ct_snat;" has no visible effect in a gateway router. */
         return;
@@ -2297,7 +2300,8 @@  execute_ct_nat(const struct ovnact_ct_nat *ct_nat,
      * and figure out the changes if any. */
     struct flow ct_flow = *uflow;
     struct ds s = DS_EMPTY_INITIALIZER;
-    ds_put_format(&s, "ct_%cnat", direction[0]);
+    ds_put_format(&s, "ct_%cnat%s", direction[0],
+                  nat_in_czone ? "in_czone" : "");
     if (ct_nat->family != AF_UNSPEC) {
         if (ct_nat->family == AF_INET) {
             ds_put_format(&s, "(ip4.%s="IP_FMT")", direction,
@@ -2610,6 +2614,16 @@  trace_actions(const struct ovnact *ovnacts, size_t ovnacts_len,
             execute_ct_nat(ovnact_get_CT_SNAT(a), dp, uflow, pipeline, super);
             break;
 
+        case OVNACT_CT_DNAT_IN_CZONE:
+            execute_ct_nat(ovnact_get_CT_DNAT_IN_CZONE(a), dp, uflow,
+                           pipeline, super);
+            break;
+
+        case OVNACT_CT_SNAT_IN_CZONE:
+            execute_ct_nat(ovnact_get_CT_SNAT_IN_CZONE(a), dp, uflow,
+                           pipeline, super);
+            break;
+
         case OVNACT_CT_LB:
             execute_ct_lb(ovnact_get_CT_LB(a), dp, uflow, pipeline, super);
             break;