diff mbox series

[ovs-dev,RFC,2/2] northd: Commit all traffic when there is stateful NAT/LB.

Message ID 20241008101155.331151-3-amusil@redhat.com
State New
Headers show
Series Commit all traffic for stateful NAT/LB | expand

Checks

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

Commit Message

Ales Musil Oct. 8, 2024, 10:11 a.m. UTC
Commit all traffic that is not already commit by either NAT or LB. This
ensures that the traffic is tracked, and we don't erroneously commit
reply traffic, or reply traffic is not marked as invalid.

To achieve the commit we need to perform lookup on every packet
that goes through LR pipeline whenever there is stateful NAT.

The SNAT lookup requires additional flag as the unSNAT is happening
in ingress pipeline and at that point we need to know if the packet
is reply or not. This is not required for DNAT, because unDNAT stage
happens in egress.

Signed-off-by: Ales Musil <amusil@redhat.com>
---
There is one failing system test with userspace datapath, that's due
to the recirculation limit that is being hit due to additional
lookups.
---
 include/ovn/logical-fields.h |   4 ++
 lib/logical-fields.c         |   4 ++
 northd/northd.c              |  76 ++++++++++++----------
 tests/ovn-northd.at          | 118 ++++++++++++++++++++++++++---------
 tests/system-ovn.at          |  31 ++++++---
 5 files changed, 158 insertions(+), 75 deletions(-)

Comments

Ales Musil Oct. 9, 2024, 5:44 a.m. UTC | #1
On Tue, Oct 8, 2024 at 12:12 PM Ales Musil <amusil@redhat.com> wrote:

> Commit all traffic that is not already commit by either NAT or LB. This
> ensures that the traffic is tracked, and we don't erroneously commit
> reply traffic, or reply traffic is not marked as invalid.
>
> To achieve the commit we need to perform lookup on every packet
> that goes through LR pipeline whenever there is stateful NAT.
>
> The SNAT lookup requires additional flag as the unSNAT is happening
> in ingress pipeline and at that point we need to know if the packet
> is reply or not. This is not required for DNAT, because unDNAT stage
> happens in egress.
>
> Signed-off-by: Ales Musil <amusil@redhat.com>
> ---
> There is one failing system test with userspace datapath, that's due
> to the recirculation limit that is being hit due to additional
> lookups.
> ---
>  include/ovn/logical-fields.h |   4 ++
>  lib/logical-fields.c         |   4 ++
>  northd/northd.c              |  76 ++++++++++++----------
>  tests/ovn-northd.at          | 118 ++++++++++++++++++++++++++---------
>  tests/system-ovn.at          |  31 ++++++---
>  5 files changed, 158 insertions(+), 75 deletions(-)
>
> diff --git a/include/ovn/logical-fields.h b/include/ovn/logical-fields.h
> index d6c4a9b6b..cc1f50ff2 100644
> --- a/include/ovn/logical-fields.h
> +++ b/include/ovn/logical-fields.h
> @@ -82,6 +82,7 @@ enum mff_log_flags_bits {
>      MLF_LOCALNET_BIT = 15,
>      MLF_RX_FROM_TUNNEL_BIT = 16,
>      MLF_ICMP_SNAT_BIT = 17,
> +    MLF_WITHOUT_UNSNAT_BIT = 18,
>  };
>
>  /* MFF_LOG_FLAGS_REG flag assignments */
> @@ -137,6 +138,9 @@ enum mff_log_flags {
>      MLF_RX_FROM_TUNNEL = (1 << MLF_RX_FROM_TUNNEL_BIT),
>
>      MLF_ICMP_SNAT = (1 << MLF_ICMP_SNAT_BIT),
> +
> +    /* Indicate that the packet didn't go through unSNAT. */
> +    MLF_WITHOUT_UNSNAT = (1 << MLF_WITHOUT_UNSNAT_BIT),
>  };
>
>  /* OVN logical fields
> diff --git a/lib/logical-fields.c b/lib/logical-fields.c
> index 5a8b53f2b..c63e19897 100644
> --- a/lib/logical-fields.c
> +++ b/lib/logical-fields.c
> @@ -139,6 +139,10 @@ ovn_init_symtab(struct shash *symtab)
>                               flags_str);
>      snprintf(flags_str, sizeof flags_str, "flags[%d]",
> MLF_RX_FROM_TUNNEL_BIT);
>      expr_symtab_add_subfield(symtab, "flags.tunnel_rx", NULL, flags_str);
> +    snprintf(flags_str, sizeof flags_str, "flags[%d]",
> +             MLF_WITHOUT_UNSNAT_BIT);
> +    expr_symtab_add_subfield(symtab, "flags.without_unsnat", NULL,
> +                             flags_str);
>
>      /* Connection tracking state. */
>      expr_symtab_add_field_scoped(symtab, "ct_mark", MFF_CT_MARK, NULL,
> false,
> diff --git a/northd/northd.c b/northd/northd.c
> index 0364dd766..a42057e45 100644
> --- a/northd/northd.c
> +++ b/northd/northd.c
> @@ -15987,8 +15987,7 @@ build_lrouter_out_snat_flow(struct lflow_table
> *lflows,
>                              struct ds *actions, bool distributed_nat,
>                              struct eth_addr mac, int cidr_bits, bool
> is_v6,
>                              struct ovn_port *l3dgw_port,
> -                            struct lflow_ref *lflow_ref,
> -                            const struct chassis_features *features)
> +                            struct lflow_ref *lflow_ref)
>  {
>      if (!(nat_entry->type == SNAT || nat_entry->type == DNAT_AND_SNAT)) {
>          return;
> @@ -16019,34 +16018,6 @@ build_lrouter_out_snat_flow(struct lflow_table
> *lflows,
>                              priority, ds_cstr(match),
>                              ds_cstr(actions), &nat->header_,
>                              lflow_ref);
> -
> -    /* For the SNAT networks, we need to make sure that connections are
> -     * properly tracked so we can decide whether to perform SNAT on
> traffic
> -     * exiting the network. */
> -    if (features->ct_commit_to_zone && features->ct_next_zone &&
> -        nat_entry->type == SNAT && !od->is_gw_router) {
> -        /* For traffic that comes from SNAT network, initiate CT state
> before
> -         * entering S_ROUTER_OUT_SNAT to allow matching on various CT
> states.
> -         */
> -        ovn_lflow_add(lflows, od, S_ROUTER_OUT_POST_UNDNAT, 70,
> -                      ds_cstr(match), "ct_next(snat);",
> -                      lflow_ref);
> -
> -        build_lrouter_out_snat_match(lflows, od, nat, match,
> -                                     distributed_nat, cidr_bits, is_v6,
> -                                     l3dgw_port, lflow_ref, true);
> -
> -        /* New traffic that goes into SNAT network is committed to CT to
> avoid
> -         * SNAT-ing replies.*/
> -        ovn_lflow_add(lflows, od, S_ROUTER_OUT_SNAT, priority,
> -                      ds_cstr(match), "ct_snat;",
> -                      lflow_ref);
> -
> -        ds_put_cstr(match, " && ct.new");
> -        ovn_lflow_add(lflows, od, S_ROUTER_OUT_POST_SNAT, priority,
> -                      ds_cstr(match), "ct_commit_to_zone(snat);",
> -                      lflow_ref);
> -    }
>  }
>
>  static void
> @@ -16439,9 +16410,6 @@ build_lrouter_nat_defrag_and_lb(
>          ovn_lflow_add(lflows, od, S_ROUTER_OUT_UNDNAT, 50,
>                        "ip", "flags.loopback = 1; ct_dnat;",
>                        lflow_ref);
> -        ovn_lflow_add(lflows, od, S_ROUTER_OUT_POST_UNDNAT, 50,
> -                      "ip && ct.new", "ct_commit { } ; next; ",
> -                      lflow_ref);
>      }
>
>      /* NAT rules are only valid on Gateway routers and routers with
> @@ -16459,6 +16427,9 @@ build_lrouter_nat_defrag_and_lb(
>          !lport_addresses_is_empty(&lrnat_rec->dnat_force_snat_addrs);
>      bool lb_force_snat_ip =
>          !lport_addresses_is_empty(&lrnat_rec->lb_force_snat_addrs);
> +    bool stateful_dnat = lr_stateful_rec->has_lb_vip;
> +    bool stateful_snat = (dnat_force_snat_ip || lb_force_snat_ip ||
> +                          lrnat_rec->lb_force_snat_router_ip);
>
>      for (size_t i = 0; i < lrnat_rec->n_nat_entries; i++) {
>          struct ovn_nat *nat_entry = &lrnat_rec->nat_entries[i];
> @@ -16477,6 +16448,21 @@ build_lrouter_nat_defrag_and_lb(
>              continue;
>          }
>
> +        if (!stateless) {
> +            switch (nat_entry->type) {
> +            case DNAT:
> +                stateful_dnat = true;
> +                break;
> +            case SNAT:
> +                stateful_snat = true;
> +                break;
> +            case DNAT_AND_SNAT:
> +                stateful_snat = true;
> +                stateful_dnat = true;
> +                break;
> +            }
> +        }
> +
>          /* S_ROUTER_IN_UNSNAT
>           * Ingress UNSNAT table: It is for already established
> connections'
>           * reverse traffic. i.e., SNAT has already been done in egress
> @@ -16599,7 +16585,7 @@ build_lrouter_nat_defrag_and_lb(
>          } else {
>              build_lrouter_out_snat_flow(lflows, od, nat_entry, match,
> actions,
>                                          distributed_nat, mac, cidr_bits,
> is_v6,
> -                                        l3dgw_port, lflow_ref, features);
> +                                        l3dgw_port, lflow_ref);
>          }
>
>          /* S_ROUTER_IN_ADMISSION - S_ROUTER_IN_IP_INPUT */
> @@ -16689,6 +16675,28 @@ build_lrouter_nat_defrag_and_lb(
>          }
>      }
>
> +
> +    bool can_commit = features->ct_commit_to_zone &&
> features->ct_next_zone;
> +    if (can_commit && stateful_dnat) {
> +        ovn_lflow_add(lflows, od, S_ROUTER_IN_DEFRAG, 10,
> +                      "ip && (!ct.trk || !ct.rpl)",
> +                      "ct_next(dnat);", lflow_ref);
> +        ovn_lflow_add(lflows, od, S_ROUTER_IN_DNAT, 10,
> +                      "ip && ct.new", "ct_commit_to_zone(dnat);",
> lflow_ref);
> +    }
> +
> +    if (can_commit && stateful_snat) {
> +        ovn_lflow_add(lflows, od, S_ROUTER_IN_UNSNAT, 10,
> +                      "ip", "flags.without_unsnat = 1; next;", lflow_ref);
> +        ovn_lflow_add(lflows, od, S_ROUTER_OUT_POST_UNDNAT, 10,
> +                      "ip && (!ct.trk || !ct.rpl) && "
> +                      "flags.without_unsnat == 1", "ct_next(snat);",
> +                      lflow_ref);
> +        ovn_lflow_add(lflows, od, S_ROUTER_OUT_SNAT, 10,
> +                      "ip && ct.new && flags.without_unsnat == 1",
> +                      "ct_commit_to_zone(snat);", lflow_ref);
> +    }
> +
>      if (use_common_zone && od->nbr->n_nat) {
>          ds_clear(match);
>          ds_put_cstr(match, "ip && ct_mark.natted == 1");
> diff --git a/tests/ovn-northd.at b/tests/ovn-northd.at
> index d6a8c4640..96e28a54a 100644
> --- a/tests/ovn-northd.at
> +++ b/tests/ovn-northd.at
> @@ -1181,18 +1181,18 @@ AT_CAPTURE_FILE([crflows])
>
>  AT_CHECK([grep -e "lr_out_snat" drflows | ovn_strip_lflows], [0], [dnl
>    table=??(lr_out_snat        ), priority=0    , match=(1), action=(next;)
> +  table=??(lr_out_snat        ), priority=10   , match=(ip && ct.new &&
> flags.without_unsnat == 1), action=(ct_commit_to_zone(snat);)
>    table=??(lr_out_snat        ), priority=120  , match=(nd_ns),
> action=(next;)
> -  table=??(lr_out_snat        ), priority=161  , match=(ip && ip4.dst ==
> 50.0.0.11 && inport == "DR-S1" && is_chassis_resident("cr-DR-S1") &&
> ip4.src == $allowed_range), action=(ct_snat;)
>    table=??(lr_out_snat        ), priority=161  , match=(ip && ip4.src ==
> 50.0.0.11 && outport == "DR-S1" && is_chassis_resident("cr-DR-S1") &&
> ip4.dst == $allowed_range && (!ct.trk || !ct.rpl)),
> action=(ct_snat(172.16.1.1);)
>  ])
>
>  AT_CHECK([grep -e "lr_out_post_snat" drflows | ovn_strip_lflows], [0],
> [dnl
>    table=??(lr_out_post_snat   ), priority=0    , match=(1), action=(next;)
> -  table=??(lr_out_post_snat   ), priority=161  , match=(ip && ip4.dst ==
> 50.0.0.11 && inport == "DR-S1" && is_chassis_resident("cr-DR-S1") &&
> ip4.src == $allowed_range && ct.new), action=(ct_commit_to_zone(snat);)
>  ])
>
>  AT_CHECK([grep -e "lr_out_snat" crflows | ovn_strip_lflows], [0], [dnl
>    table=??(lr_out_snat        ), priority=0    , match=(1), action=(next;)
> +  table=??(lr_out_snat        ), priority=10   , match=(ip && ct.new &&
> flags.without_unsnat == 1), action=(ct_commit_to_zone(snat);)
>    table=??(lr_out_snat        ), priority=120  , match=(nd_ns),
> action=(next;)
>    table=??(lr_out_snat        ), priority=33   , match=(ip && ip4.src ==
> 50.0.0.11 && ip4.dst == $allowed_range && (!ct.trk || !ct.rpl)),
> action=(ct_snat(172.16.1.1);)
>  ])
> @@ -1220,19 +1220,19 @@ AT_CAPTURE_FILE([crflows2])
>
>  AT_CHECK([grep -e "lr_out_snat" drflows2 | ovn_strip_lflows], [0], [dnl
>    table=??(lr_out_snat        ), priority=0    , match=(1), action=(next;)
> +  table=??(lr_out_snat        ), priority=10   , match=(ip && ct.new &&
> flags.without_unsnat == 1), action=(ct_commit_to_zone(snat);)
>    table=??(lr_out_snat        ), priority=120  , match=(nd_ns),
> action=(next;)
> -  table=??(lr_out_snat        ), priority=161  , match=(ip && ip4.dst ==
> 50.0.0.11 && inport == "DR-S1" && is_chassis_resident("cr-DR-S1")),
> action=(ct_snat;)
>    table=??(lr_out_snat        ), priority=161  , match=(ip && ip4.src ==
> 50.0.0.11 && outport == "DR-S1" && is_chassis_resident("cr-DR-S1") &&
> (!ct.trk || !ct.rpl)), action=(ct_snat(172.16.1.1);)
>    table=??(lr_out_snat        ), priority=163  , match=(ip && ip4.src ==
> 50.0.0.11 && outport == "DR-S1" && is_chassis_resident("cr-DR-S1") &&
> ip4.dst == $disallowed_range), action=(next;)
>  ])
>
>  AT_CHECK([grep -e "lr_out_post_snat" drflows2 | ovn_strip_lflows], [0],
> [dnl
>    table=??(lr_out_post_snat   ), priority=0    , match=(1), action=(next;)
> -  table=??(lr_out_post_snat   ), priority=161  , match=(ip && ip4.dst ==
> 50.0.0.11 && inport == "DR-S1" && is_chassis_resident("cr-DR-S1") &&
> ct.new), action=(ct_commit_to_zone(snat);)
>  ])
>
>  AT_CHECK([grep -e "lr_out_snat" crflows2 | ovn_strip_lflows], [0], [dnl
>    table=??(lr_out_snat        ), priority=0    , match=(1), action=(next;)
> +  table=??(lr_out_snat        ), priority=10   , match=(ip && ct.new &&
> flags.without_unsnat == 1), action=(ct_commit_to_zone(snat);)
>    table=??(lr_out_snat        ), priority=120  , match=(nd_ns),
> action=(next;)
>    table=??(lr_out_snat        ), priority=33   , match=(ip && ip4.src ==
> 50.0.0.11 && (!ct.trk || !ct.rpl)), action=(ct_snat(172.16.1.1);)
>    table=??(lr_out_snat        ), priority=35   , match=(ip && ip4.src ==
> 50.0.0.11 && ip4.dst == $disallowed_range), action=(next;)
> @@ -1259,6 +1259,7 @@ AT_CAPTURE_FILE([crflows2])
>
>  AT_CHECK([grep -e "lr_out_snat" drflows3 | ovn_strip_lflows], [0], [dnl
>    table=??(lr_out_snat        ), priority=0    , match=(1), action=(next;)
> +  table=??(lr_out_snat        ), priority=10   , match=(ip && ct.new &&
> flags.without_unsnat == 1), action=(ct_commit_to_zone(snat);)
>    table=??(lr_out_snat        ), priority=120  , match=(nd_ns),
> action=(next;)
>    table=??(lr_out_snat        ), priority=161  , match=(ip && ip4.src ==
> 50.0.0.11 && outport == "DR-S1" && is_chassis_resident("cr-DR-S1") &&
> ip4.dst == $allowed_range && (!ct.trk || !ct.rpl)),
> action=(ct_snat(172.16.1.2);)
>  ])
> @@ -1269,6 +1270,7 @@ AT_CHECK([grep -e "lr_out_post_snat" drflows3 |
> ovn_strip_lflows], [0], [dnl
>
>  AT_CHECK([grep -e "lr_out_snat" crflows3 | ovn_strip_lflows], [0], [dnl
>    table=??(lr_out_snat        ), priority=0    , match=(1), action=(next;)
> +  table=??(lr_out_snat        ), priority=10   , match=(ip && ct.new &&
> flags.without_unsnat == 1), action=(ct_commit_to_zone(snat);)
>    table=??(lr_out_snat        ), priority=120  , match=(nd_ns),
> action=(next;)
>    table=??(lr_out_snat        ), priority=33   , match=(ip && ip4.src ==
> 50.0.0.11 && ip4.dst == $allowed_range && (!ct.trk || !ct.rpl)),
> action=(ct_snat(172.16.1.2);)
>  ])
> @@ -1294,6 +1296,7 @@ AT_CAPTURE_FILE([crflows2])
>
>  AT_CHECK([grep -e "lr_out_snat" drflows4 | ovn_strip_lflows], [0], [dnl
>    table=??(lr_out_snat        ), priority=0    , match=(1), action=(next;)
> +  table=??(lr_out_snat        ), priority=10   , match=(ip && ct.new &&
> flags.without_unsnat == 1), action=(ct_commit_to_zone(snat);)
>    table=??(lr_out_snat        ), priority=120  , match=(nd_ns),
> action=(next;)
>    table=??(lr_out_snat        ), priority=161  , match=(ip && ip4.src ==
> 50.0.0.11 && outport == "DR-S1" && is_chassis_resident("cr-DR-S1") &&
> (!ct.trk || !ct.rpl)), action=(ct_snat(172.16.1.2);)
>    table=??(lr_out_snat        ), priority=163  , match=(ip && ip4.src ==
> 50.0.0.11 && outport == "DR-S1" && is_chassis_resident("cr-DR-S1") &&
> ip4.dst == $disallowed_range), action=(next;)
> @@ -1301,6 +1304,7 @@ AT_CHECK([grep -e "lr_out_snat" drflows4 |
> ovn_strip_lflows], [0], [dnl
>
>  AT_CHECK([grep -e "lr_out_snat" crflows4 | ovn_strip_lflows], [0], [dnl
>    table=??(lr_out_snat        ), priority=0    , match=(1), action=(next;)
> +  table=??(lr_out_snat        ), priority=10   , match=(ip && ct.new &&
> flags.without_unsnat == 1), action=(ct_commit_to_zone(snat);)
>    table=??(lr_out_snat        ), priority=120  , match=(nd_ns),
> action=(next;)
>    table=??(lr_out_snat        ), priority=33   , match=(ip && ip4.src ==
> 50.0.0.11 && (!ct.trk || !ct.rpl)), action=(ct_snat(172.16.1.2);)
>    table=??(lr_out_snat        ), priority=35   , match=(ip && ip4.src ==
> 50.0.0.11 && ip4.dst == $disallowed_range), action=(next;)
> @@ -1663,6 +1667,7 @@ AT_CAPTURE_FILE([sbflows])
>  # dnat_and_snat or snat entry.
>  AT_CHECK([grep "lr_in_unsnat" sbflows | ovn_strip_lflows], [0], [dnl
>    table=??(lr_in_unsnat       ), priority=0    , match=(1), action=(next;)
> +  table=??(lr_in_unsnat       ), priority=10   , match=(ip),
> action=(flags.without_unsnat = 1; next;)
>    table=??(lr_in_unsnat       ), priority=90   , match=(ip && ip4.dst ==
> 192.168.2.1), action=(ct_snat;)
>    table=??(lr_in_unsnat       ), priority=90   , match=(ip && ip4.dst ==
> 192.168.2.4), action=(ct_snat;)
>  ])
> @@ -1693,6 +1698,7 @@ AT_CAPTURE_FILE([sbflows])
>  # dnat_and_snat or snat entry.
>  AT_CHECK([grep "lr_in_unsnat" sbflows | ovn_strip_lflows], [0], [dnl
>    table=??(lr_in_unsnat       ), priority=0    , match=(1), action=(next;)
> +  table=??(lr_in_unsnat       ), priority=10   , match=(ip),
> action=(flags.without_unsnat = 1; next;)
>    table=??(lr_in_unsnat       ), priority=90   , match=(ip && ip4.dst ==
> 192.168.2.1), action=(ct_snat;)
>    table=??(lr_in_unsnat       ), priority=90   , match=(ip && ip4.dst ==
> 192.168.2.4), action=(ct_snat;)
>  ])
> @@ -1801,6 +1807,7 @@ ovn-nbctl --wait=sb sync
>
>  AT_CHECK([ovn-sbctl lflow-list lr0 | grep lr_in_unsnat |
> ovn_strip_lflows], [0], [dnl
>    table=??(lr_in_unsnat       ), priority=0    , match=(1), action=(next;)
> +  table=??(lr_in_unsnat       ), priority=10   , match=(ip),
> action=(flags.without_unsnat = 1; next;)
>    table=??(lr_in_unsnat       ), priority=110  , match=(ip4 && ip4.dst ==
> 192.168.2.3), action=(ct_snat;)
>  ])
>
> @@ -4277,12 +4284,14 @@ AT_CHECK([grep "lr_in_unsnat" lr0flows |
> ovn_strip_lflows], [0], [dnl
>
>  AT_CHECK([grep "lr_in_defrag" lr0flows | ovn_strip_lflows], [0], [dnl
>    table=??(lr_in_defrag       ), priority=0    , match=(1), action=(next;)
> +  table=??(lr_in_defrag       ), priority=10   , match=(ip && (!ct.trk ||
> !ct.rpl)), action=(ct_next(dnat);)
>    table=??(lr_in_defrag       ), priority=100  , match=(ip && ip4.dst ==
> 10.0.0.10), action=(ct_dnat;)
>    table=??(lr_in_defrag       ), priority=100  , match=(ip && ip4.dst ==
> 10.0.0.100), action=(ct_dnat;)
>  ])
>
>  AT_CHECK([grep "lr_in_dnat" lr0flows | ovn_strip_lflows], [0], [dnl
>    table=??(lr_in_dnat         ), priority=0    , match=(1), action=(next;)
> +  table=??(lr_in_dnat         ), priority=10   , match=(ip && ct.new),
> action=(ct_commit_to_zone(dnat);)
>    table=??(lr_in_dnat         ), priority=120  , match=(ct.new && !ct.rel
> && ip4 && ip4.dst == 10.0.0.10 && tcp && tcp.dst == 80),
> action=(ct_lb_mark(backends=10.0.0.4:8080);)
>    table=??(lr_in_dnat         ), priority=120  , match=(ct.new && !ct.rel
> && ip4 && ip4.dst == 10.0.0.100 && tcp && tcp.dst == 80),
> action=(ct_lb_mark(backends=10.0.0.40:8080);)
>    table=??(lr_in_dnat         ), priority=50   , match=(ct.est && !ct.rel
> && !ct.new && ct_mark.natted), action=(next;)
> @@ -4302,18 +4311,21 @@ AT_CAPTURE_FILE([lr0flows])
>
>  AT_CHECK([grep "lr_in_unsnat" lr0flows | ovn_strip_lflows], [0], [dnl
>    table=??(lr_in_unsnat       ), priority=0    , match=(1), action=(next;)
> +  table=??(lr_in_unsnat       ), priority=10   , match=(ip),
> action=(flags.without_unsnat = 1; next;)
>    table=??(lr_in_unsnat       ), priority=110  , match=(ip4 && ip4.dst ==
> 20.0.0.4), action=(ct_snat;)
>    table=??(lr_in_unsnat       ), priority=110  , match=(ip6 && ip6.dst ==
> aef0::4), action=(ct_snat;)
>  ])
>
>  AT_CHECK([grep "lr_in_defrag" lr0flows | ovn_strip_lflows], [0], [dnl
>    table=??(lr_in_defrag       ), priority=0    , match=(1), action=(next;)
> +  table=??(lr_in_defrag       ), priority=10   , match=(ip && (!ct.trk ||
> !ct.rpl)), action=(ct_next(dnat);)
>    table=??(lr_in_defrag       ), priority=100  , match=(ip && ip4.dst ==
> 10.0.0.10), action=(ct_dnat;)
>    table=??(lr_in_defrag       ), priority=100  , match=(ip && ip4.dst ==
> 10.0.0.100), action=(ct_dnat;)
>  ])
>
>  AT_CHECK([grep "lr_in_dnat" lr0flows | ovn_strip_lflows], [0], [dnl
>    table=??(lr_in_dnat         ), priority=0    , match=(1), action=(next;)
> +  table=??(lr_in_dnat         ), priority=10   , match=(ip && ct.new),
> action=(ct_commit_to_zone(dnat);)
>    table=??(lr_in_dnat         ), priority=120  , match=(ct.new && !ct.rel
> && ip4 && ip4.dst == 10.0.0.10 && tcp && tcp.dst == 80),
> action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.4:8080;
> force_snat);)
>    table=??(lr_in_dnat         ), priority=120  , match=(ct.new && !ct.rel
> && ip4 && ip4.dst == 10.0.0.100 && tcp && tcp.dst == 80),
> action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.40:8080;
> force_snat);)
>    table=??(lr_in_dnat         ), priority=50   , match=(ct.est && !ct.rel
> && !ct.new && ct_mark.natted), action=(next;)
> @@ -4326,6 +4338,7 @@ AT_CHECK([grep "lr_in_dnat" lr0flows |
> ovn_strip_lflows], [0], [dnl
>
>  AT_CHECK([grep "lr_out_snat" lr0flows | ovn_strip_lflows], [0], [dnl
>    table=??(lr_out_snat        ), priority=0    , match=(1), action=(next;)
> +  table=??(lr_out_snat        ), priority=10   , match=(ip && ct.new &&
> flags.without_unsnat == 1), action=(ct_commit_to_zone(snat);)
>    table=??(lr_out_snat        ), priority=100  ,
> match=(flags.force_snat_for_lb == 1 && ip4), action=(ct_snat(20.0.0.4);)
>    table=??(lr_out_snat        ), priority=100  ,
> match=(flags.force_snat_for_lb == 1 && ip6), action=(ct_snat(aef0::4);)
>    table=??(lr_out_snat        ), priority=120  , match=(nd_ns),
> action=(next;)
> @@ -4339,7 +4352,7 @@ AT_CHECK([grep "lr_out_undnat" lr0flows |
> ovn_strip_lflows], [0], [dnl
>
>  AT_CHECK([grep "lr_out_post_undnat" lr0flows | ovn_strip_lflows], [0],
> [dnl
>    table=??(lr_out_post_undnat ), priority=0    , match=(1), action=(next;)
> -  table=??(lr_out_post_undnat ), priority=50   , match=(ip && ct.new),
> action=(ct_commit { } ; next; )
> +  table=??(lr_out_post_undnat ), priority=10   , match=(ip && (!ct.trk ||
> !ct.rpl) && flags.without_unsnat == 1), action=(ct_next(snat);)
>  ])
>
>  check ovn-nbctl --wait=sb set logical_router lr0
> options:lb_force_snat_ip="router_ip"
> @@ -4352,6 +4365,7 @@ AT_CHECK([grep "lr_in_ip_input" lr0flows | grep
> "priority=60" | sort], [0], [dnl
>
>  AT_CHECK([grep "lr_in_unsnat" lr0flows | ovn_strip_lflows], [0], [dnl
>    table=??(lr_in_unsnat       ), priority=0    , match=(1), action=(next;)
> +  table=??(lr_in_unsnat       ), priority=10   , match=(ip),
> action=(flags.without_unsnat = 1; next;)
>    table=??(lr_in_unsnat       ), priority=110  , match=(inport ==
> "lr0-public" && ip4.dst == 172.168.0.100), action=(ct_snat;)
>    table=??(lr_in_unsnat       ), priority=110  , match=(inport ==
> "lr0-sw0" && ip4.dst == 10.0.0.1), action=(ct_snat;)
>    table=??(lr_in_unsnat       ), priority=110  , match=(inport ==
> "lr0-sw1" && ip4.dst == 20.0.0.1), action=(ct_snat;)
> @@ -4359,12 +4373,14 @@ AT_CHECK([grep "lr_in_unsnat" lr0flows |
> ovn_strip_lflows], [0], [dnl
>
>  AT_CHECK([grep "lr_in_defrag" lr0flows | ovn_strip_lflows], [0], [dnl
>    table=??(lr_in_defrag       ), priority=0    , match=(1), action=(next;)
> +  table=??(lr_in_defrag       ), priority=10   , match=(ip && (!ct.trk ||
> !ct.rpl)), action=(ct_next(dnat);)
>    table=??(lr_in_defrag       ), priority=100  , match=(ip && ip4.dst ==
> 10.0.0.10), action=(ct_dnat;)
>    table=??(lr_in_defrag       ), priority=100  , match=(ip && ip4.dst ==
> 10.0.0.100), action=(ct_dnat;)
>  ])
>
>  AT_CHECK([grep "lr_in_dnat" lr0flows | ovn_strip_lflows], [0], [dnl
>    table=??(lr_in_dnat         ), priority=0    , match=(1), action=(next;)
> +  table=??(lr_in_dnat         ), priority=10   , match=(ip && ct.new),
> action=(ct_commit_to_zone(dnat);)
>    table=??(lr_in_dnat         ), priority=120  , match=(ct.new && !ct.rel
> && ip4 && ip4.dst == 10.0.0.10 && tcp && tcp.dst == 80),
> action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.4:8080;
> force_snat);)
>    table=??(lr_in_dnat         ), priority=120  , match=(ct.new && !ct.rel
> && ip4 && ip4.dst == 10.0.0.100 && tcp && tcp.dst == 80),
> action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.40:8080;
> force_snat);)
>    table=??(lr_in_dnat         ), priority=50   , match=(ct.est && !ct.rel
> && !ct.new && ct_mark.natted), action=(next;)
> @@ -4377,6 +4393,7 @@ AT_CHECK([grep "lr_in_dnat" lr0flows |
> ovn_strip_lflows], [0], [dnl
>
>  AT_CHECK([grep "lr_out_snat" lr0flows | ovn_strip_lflows], [0], [dnl
>    table=??(lr_out_snat        ), priority=0    , match=(1), action=(next;)
> +  table=??(lr_out_snat        ), priority=10   , match=(ip && ct.new &&
> flags.without_unsnat == 1), action=(ct_commit_to_zone(snat);)
>    table=??(lr_out_snat        ), priority=110  ,
> match=(flags.force_snat_for_lb == 1 && ip4 && outport == "lr0-public"),
> action=(ct_snat(172.168.0.100);)
>    table=??(lr_out_snat        ), priority=110  ,
> match=(flags.force_snat_for_lb == 1 && ip4 && outport == "lr0-sw0"),
> action=(ct_snat(10.0.0.1);)
>    table=??(lr_out_snat        ), priority=110  ,
> match=(flags.force_snat_for_lb == 1 && ip4 && outport == "lr0-sw1"),
> action=(ct_snat(20.0.0.1);)
> @@ -4391,7 +4408,7 @@ AT_CHECK([grep "lr_out_undnat" lr0flows |
> ovn_strip_lflows], [0], [dnl
>
>  AT_CHECK([grep "lr_out_post_undnat" lr0flows | ovn_strip_lflows], [0],
> [dnl
>    table=??(lr_out_post_undnat ), priority=0    , match=(1), action=(next;)
> -  table=??(lr_out_post_undnat ), priority=50   , match=(ip && ct.new),
> action=(ct_commit { } ; next; )
> +  table=??(lr_out_post_undnat ), priority=10   , match=(ip && (!ct.trk ||
> !ct.rpl) && flags.without_unsnat == 1), action=(ct_next(snat);)
>  ])
>
>  check ovn-nbctl --wait=sb remove logical_router lr0 options chassis
> @@ -4416,6 +4433,7 @@ AT_CAPTURE_FILE([lr0flows])
>
>  AT_CHECK([grep "lr_in_unsnat" lr0flows | ovn_strip_lflows], [0], [dnl
>    table=??(lr_in_unsnat       ), priority=0    , match=(1), action=(next;)
> +  table=??(lr_in_unsnat       ), priority=10   , match=(ip),
> action=(flags.without_unsnat = 1; next;)
>    table=??(lr_in_unsnat       ), priority=110  , match=(inport ==
> "lr0-public" && ip4.dst == 172.168.0.100), action=(ct_snat;)
>    table=??(lr_in_unsnat       ), priority=110  , match=(inport ==
> "lr0-sw0" && ip4.dst == 10.0.0.1), action=(ct_snat;)
>    table=??(lr_in_unsnat       ), priority=110  , match=(inport ==
> "lr0-sw1" && ip4.dst == 20.0.0.1), action=(ct_snat;)
> @@ -4424,12 +4442,14 @@ AT_CHECK([grep "lr_in_unsnat" lr0flows |
> ovn_strip_lflows], [0], [dnl
>
>  AT_CHECK([grep "lr_in_defrag" lr0flows | ovn_strip_lflows], [0], [dnl
>    table=??(lr_in_defrag       ), priority=0    , match=(1), action=(next;)
> +  table=??(lr_in_defrag       ), priority=10   , match=(ip && (!ct.trk ||
> !ct.rpl)), action=(ct_next(dnat);)
>    table=??(lr_in_defrag       ), priority=100  , match=(ip && ip4.dst ==
> 10.0.0.10), action=(ct_dnat;)
>    table=??(lr_in_defrag       ), priority=100  , match=(ip && ip4.dst ==
> 10.0.0.100), action=(ct_dnat;)
>  ])
>
>  AT_CHECK([grep "lr_in_dnat" lr0flows | ovn_strip_lflows], [0], [dnl
>    table=??(lr_in_dnat         ), priority=0    , match=(1), action=(next;)
> +  table=??(lr_in_dnat         ), priority=10   , match=(ip && ct.new),
> action=(ct_commit_to_zone(dnat);)
>    table=??(lr_in_dnat         ), priority=120  , match=(ct.new && !ct.rel
> && ip4 && ip4.dst == 10.0.0.10 && tcp && tcp.dst == 80),
> action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.4:8080;
> force_snat);)
>    table=??(lr_in_dnat         ), priority=120  , match=(ct.new && !ct.rel
> && ip4 && ip4.dst == 10.0.0.100 && tcp && tcp.dst == 80),
> action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.40:8080;
> force_snat);)
>    table=??(lr_in_dnat         ), priority=50   , match=(ct.est && !ct.rel
> && !ct.new && ct_mark.natted), action=(next;)
> @@ -4442,6 +4462,7 @@ AT_CHECK([grep "lr_in_dnat" lr0flows |
> ovn_strip_lflows], [0], [dnl
>
>  AT_CHECK([grep "lr_out_snat" lr0flows | ovn_strip_lflows], [0], [dnl
>    table=??(lr_out_snat        ), priority=0    , match=(1), action=(next;)
> +  table=??(lr_out_snat        ), priority=10   , match=(ip && ct.new &&
> flags.without_unsnat == 1), action=(ct_commit_to_zone(snat);)
>    table=??(lr_out_snat        ), priority=110  ,
> match=(flags.force_snat_for_lb == 1 && ip4 && outport == "lr0-public"),
> action=(ct_snat(172.168.0.100);)
>    table=??(lr_out_snat        ), priority=110  ,
> match=(flags.force_snat_for_lb == 1 && ip4 && outport == "lr0-sw0"),
> action=(ct_snat(10.0.0.1);)
>    table=??(lr_out_snat        ), priority=110  ,
> match=(flags.force_snat_for_lb == 1 && ip4 && outport == "lr0-sw1"),
> action=(ct_snat(20.0.0.1);)
> @@ -4457,7 +4478,7 @@ AT_CHECK([grep "lr_out_undnat" lr0flows |
> ovn_strip_lflows], [0], [dnl
>
>  AT_CHECK([grep "lr_out_post_undnat" lr0flows | ovn_strip_lflows], [0],
> [dnl
>    table=??(lr_out_post_undnat ), priority=0    , match=(1), action=(next;)
> -  table=??(lr_out_post_undnat ), priority=50   , match=(ip && ct.new),
> action=(ct_commit { } ; next; )
> +  table=??(lr_out_post_undnat ), priority=10   , match=(ip && (!ct.trk ||
> !ct.rpl) && flags.without_unsnat == 1), action=(ct_next(snat);)
>  ])
>
>  check ovn-nbctl --wait=sb lb-add lb2 10.0.0.20:80 10.0.0.40:8080
> @@ -4468,6 +4489,7 @@ ovn-sbctl dump-flows lr0 > lr0flows
>
>  AT_CHECK([grep "lr_in_unsnat" lr0flows | ovn_strip_lflows], [0], [dnl
>    table=??(lr_in_unsnat       ), priority=0    , match=(1), action=(next;)
> +  table=??(lr_in_unsnat       ), priority=10   , match=(ip),
> action=(flags.without_unsnat = 1; next;)
>    table=??(lr_in_unsnat       ), priority=110  , match=(inport ==
> "lr0-public" && ip4.dst == 172.168.0.100), action=(ct_snat;)
>    table=??(lr_in_unsnat       ), priority=110  , match=(inport ==
> "lr0-sw0" && ip4.dst == 10.0.0.1), action=(ct_snat;)
>    table=??(lr_in_unsnat       ), priority=110  , match=(inport ==
> "lr0-sw1" && ip4.dst == 20.0.0.1), action=(ct_snat;)
> @@ -4476,6 +4498,7 @@ AT_CHECK([grep "lr_in_unsnat" lr0flows |
> ovn_strip_lflows], [0], [dnl
>
>  AT_CHECK([grep "lr_in_defrag" lr0flows | ovn_strip_lflows], [0], [dnl
>    table=??(lr_in_defrag       ), priority=0    , match=(1), action=(next;)
> +  table=??(lr_in_defrag       ), priority=10   , match=(ip && (!ct.trk ||
> !ct.rpl)), action=(ct_next(dnat);)
>    table=??(lr_in_defrag       ), priority=100  , match=(ip && ip4.dst ==
> 10.0.0.100), action=(ct_dnat;)
>    table=??(lr_in_defrag       ), priority=100  , match=(ip && ip4.dst ==
> 10.0.0.20), action=(ct_dnat;)
>  ])
> @@ -4498,7 +4521,7 @@ AT_CHECK([grep "lr_out_undnat" lr0flows |
> ovn_strip_lflows], [0], [dnl
>
>  AT_CHECK([grep "lr_out_post_undnat" lr0flows | ovn_strip_lflows], [0],
> [dnl
>    table=??(lr_out_post_undnat ), priority=0    , match=(1), action=(next;)
> -  table=??(lr_out_post_undnat ), priority=50   , match=(ip && ct.new),
> action=(ct_commit { } ; next; )
> +  table=??(lr_out_post_undnat ), priority=10   , match=(ip && (!ct.trk ||
> !ct.rpl) && flags.without_unsnat == 1), action=(ct_next(snat);)
>  ])
>
>  AT_CLEANUP
> @@ -5744,6 +5767,7 @@ AT_CAPTURE_FILE([lr0flows])
>
>  AT_CHECK([grep "lr_in_unsnat" lr0flows | ovn_strip_lflows], [0], [dnl
>    table=??(lr_in_unsnat       ), priority=0    , match=(1), action=(next;)
> +  table=??(lr_in_unsnat       ), priority=10   , match=(ip),
> action=(flags.without_unsnat = 1; next;)
>    table=??(lr_in_unsnat       ), priority=100  , match=(ip && ip4.dst ==
> 172.168.0.10 && inport == "lr0-public" &&
> is_chassis_resident("cr-lr0-public") && flags.loopback == 0),
> action=(ct_snat_in_czone;)
>    table=??(lr_in_unsnat       ), priority=100  , match=(ip && ip4.dst ==
> 172.168.0.10 && inport == "lr0-public" &&
> is_chassis_resident("cr-lr0-public") && flags.loopback == 1 &&
> flags.use_snat_zone == 1), action=(ct_snat;)
>    table=??(lr_in_unsnat       ), priority=100  , match=(ip && ip4.dst ==
> 172.168.0.20 && inport == "lr0-public" &&
> is_chassis_resident("cr-lr0-public") && flags.loopback == 0),
> action=(ct_snat_in_czone;)
> @@ -5754,10 +5778,12 @@ AT_CHECK([grep "lr_in_unsnat" lr0flows |
> ovn_strip_lflows], [0], [dnl
>
>  AT_CHECK([grep "lr_in_defrag" lr0flows | ovn_strip_lflows], [0], [dnl
>    table=??(lr_in_defrag       ), priority=0    , match=(1), action=(next;)
> +  table=??(lr_in_defrag       ), priority=10   , match=(ip && (!ct.trk ||
> !ct.rpl)), action=(ct_next(dnat);)
>  ])
>
>  AT_CHECK([grep "lr_in_dnat" lr0flows | ovn_strip_lflows], [0], [dnl
>    table=??(lr_in_dnat         ), priority=0    , match=(1), action=(next;)
> +  table=??(lr_in_dnat         ), priority=10   , match=(ip && ct.new),
> action=(ct_commit_to_zone(dnat);)
>    table=??(lr_in_dnat         ), priority=100  , match=(ip && ip4.dst ==
> 172.168.0.20 && inport == "lr0-public" &&
> is_chassis_resident("cr-lr0-public")), action=(ct_dnat_in_czone(10.0.0.3);)
>  ])
>
> @@ -5776,10 +5802,12 @@ AT_CHECK([grep "lr_out_undnat" lr0flows |
> ovn_strip_lflows], [0], [dnl
>
>  AT_CHECK([grep "lr_out_post_undnat" lr0flows | ovn_strip_lflows], [0],
> [dnl
>    table=??(lr_out_post_undnat ), priority=0    , match=(1), action=(next;)
> +  table=??(lr_out_post_undnat ), priority=10   , match=(ip && (!ct.trk ||
> !ct.rpl) && flags.without_unsnat == 1), action=(ct_next(snat);)
>  ])
>
>  AT_CHECK([grep "lr_out_snat" lr0flows | ovn_strip_lflows], [0], [dnl
>    table=??(lr_out_snat        ), priority=0    , match=(1), action=(next;)
> +  table=??(lr_out_snat        ), priority=10   , match=(ip && ct.new &&
> flags.without_unsnat == 1), action=(ct_commit_to_zone(snat);)
>    table=??(lr_out_snat        ), priority=120  , match=(nd_ns),
> action=(next;)
>    table=??(lr_out_snat        ), priority=153  , match=(ip && ip4.src ==
> 10.0.0.0/24 && outport == "lr0-public" &&
> is_chassis_resident("cr-lr0-public") && (!ct.trk || !ct.rpl)),
> action=(ct_snat_in_czone(172.168.0.10);)
>    table=??(lr_out_snat        ), priority=154  , match=(ip && ip4.src ==
> 10.0.0.0/24 && outport == "lr0-public" &&
> is_chassis_resident("cr-lr0-public") && (!ct.trk || !ct.rpl) && reg9[[4]]
> == 1), action=(reg9[[4]] = 0; ct_snat(172.168.0.10);)
> @@ -5799,6 +5827,7 @@ AT_CAPTURE_FILE([lr0flows])
>
>  AT_CHECK([grep "lr_in_unsnat" lr0flows | ovn_strip_lflows], [0], [dnl
>    table=??(lr_in_unsnat       ), priority=0    , match=(1), action=(next;)
> +  table=??(lr_in_unsnat       ), priority=10   , match=(ip),
> action=(flags.without_unsnat = 1; next;)
>    table=??(lr_in_unsnat       ), priority=100  , match=(ip && ip4.dst ==
> 172.168.0.10 && inport == "lr0-public" &&
> is_chassis_resident("cr-lr0-public")), action=(ct_snat;)
>    table=??(lr_in_unsnat       ), priority=100  , match=(ip && ip4.dst ==
> 172.168.0.20 && inport == "lr0-public" &&
> is_chassis_resident("cr-lr0-public")), action=(ct_snat;)
>    table=??(lr_in_unsnat       ), priority=100  , match=(ip && ip4.dst ==
> 172.168.0.30 && inport == "lr0-public" &&
> is_chassis_resident("cr-lr0-public")), action=(ct_snat;)
> @@ -5806,10 +5835,12 @@ AT_CHECK([grep "lr_in_unsnat" lr0flows |
> ovn_strip_lflows], [0], [dnl
>
>  AT_CHECK([grep "lr_in_defrag" lr0flows | ovn_strip_lflows], [0], [dnl
>    table=??(lr_in_defrag       ), priority=0    , match=(1), action=(next;)
> +  table=??(lr_in_defrag       ), priority=10   , match=(ip && (!ct.trk ||
> !ct.rpl)), action=(ct_next(dnat);)
>  ])
>
>  AT_CHECK([grep "lr_in_dnat" lr0flows | ovn_strip_lflows], [0], [dnl
>    table=??(lr_in_dnat         ), priority=0    , match=(1), action=(next;)
> +  table=??(lr_in_dnat         ), priority=10   , match=(ip && ct.new),
> action=(ct_commit_to_zone(dnat);)
>    table=??(lr_in_dnat         ), priority=100  , match=(ip && ip4.dst ==
> 172.168.0.20 && inport == "lr0-public" &&
> is_chassis_resident("cr-lr0-public")), action=(ct_dnat(10.0.0.3);)
>  ])
>
> @@ -5824,24 +5855,20 @@ AT_CHECK([grep "lr_out_undnat" lr0flows |
> ovn_strip_lflows], [0], [dnl
>
>  AT_CHECK([grep "lr_out_post_undnat" lr0flows | ovn_strip_lflows], [0],
> [dnl
>    table=??(lr_out_post_undnat ), priority=0    , match=(1), action=(next;)
> -  table=??(lr_out_post_undnat ), priority=70   , match=(ip && ip4.src ==
> 10.0.0.0/24 && outport == "lr0-public" &&
> is_chassis_resident("cr-lr0-public") && (!ct.trk || !ct.rpl)),
> action=(ct_next(snat);)
> -  table=??(lr_out_post_undnat ), priority=70   , match=(ip && ip4.src ==
> 10.0.0.10 && outport == "lr0-public" &&
> is_chassis_resident("cr-lr0-public") && (!ct.trk || !ct.rpl)),
> action=(ct_next(snat);)
> +  table=??(lr_out_post_undnat ), priority=10   , match=(ip && (!ct.trk ||
> !ct.rpl) && flags.without_unsnat == 1), action=(ct_next(snat);)
>  ])
>
>  AT_CHECK([grep "lr_out_snat" lr0flows | ovn_strip_lflows], [0], [dnl
>    table=??(lr_out_snat        ), priority=0    , match=(1), action=(next;)
> +  table=??(lr_out_snat        ), priority=10   , match=(ip && ct.new &&
> flags.without_unsnat == 1), action=(ct_commit_to_zone(snat);)
>    table=??(lr_out_snat        ), priority=120  , match=(nd_ns),
> action=(next;)
> -  table=??(lr_out_snat        ), priority=153  , match=(ip && ip4.dst ==
> 10.0.0.0/24 && inport == "lr0-public" &&
> is_chassis_resident("cr-lr0-public")), action=(ct_snat;)
>    table=??(lr_out_snat        ), priority=153  , match=(ip && ip4.src ==
> 10.0.0.0/24 && outport == "lr0-public" &&
> is_chassis_resident("cr-lr0-public") && (!ct.trk || !ct.rpl)),
> action=(ct_snat(172.168.0.10);)
> -  table=??(lr_out_snat        ), priority=161  , match=(ip && ip4.dst ==
> 10.0.0.10 && inport == "lr0-public" &&
> is_chassis_resident("cr-lr0-public")), action=(ct_snat;)
>    table=??(lr_out_snat        ), priority=161  , match=(ip && ip4.src ==
> 10.0.0.10 && outport == "lr0-public" &&
> is_chassis_resident("cr-lr0-public") && (!ct.trk || !ct.rpl)),
> action=(ct_snat(172.168.0.30);)
>    table=??(lr_out_snat        ), priority=161  , match=(ip && ip4.src ==
> 10.0.0.3 && outport == "lr0-public" && is_chassis_resident("cr-lr0-public")
> && (!ct.trk || !ct.rpl)), action=(ct_snat(172.168.0.20);)
>  ])
>
>  AT_CHECK([grep "lr_out_post_snat" lr0flows | ovn_strip_lflows], [0], [dnl
>    table=??(lr_out_post_snat   ), priority=0    , match=(1), action=(next;)
> -  table=??(lr_out_post_snat   ), priority=153  , match=(ip && ip4.dst ==
> 10.0.0.0/24 && inport == "lr0-public" &&
> is_chassis_resident("cr-lr0-public") && ct.new),
> action=(ct_commit_to_zone(snat);)
> -  table=??(lr_out_post_snat   ), priority=161  , match=(ip && ip4.dst ==
> 10.0.0.10 && inport == "lr0-public" && is_chassis_resident("cr-lr0-public")
> && ct.new), action=(ct_commit_to_zone(snat);)
>  ])
>
>  # Associate load balancer to lr0
> @@ -5866,6 +5893,7 @@ AT_CAPTURE_FILE([lr0flows])
>
>  AT_CHECK([grep "lr_in_unsnat" lr0flows | ovn_strip_lflows], [0], [dnl
>    table=??(lr_in_unsnat       ), priority=0    , match=(1), action=(next;)
> +  table=??(lr_in_unsnat       ), priority=10   , match=(ip),
> action=(flags.without_unsnat = 1; next;)
>    table=??(lr_in_unsnat       ), priority=100  , match=(ip && ip4.dst ==
> 172.168.0.10 && inport == "lr0-public" &&
> is_chassis_resident("cr-lr0-public") && flags.loopback == 0),
> action=(ct_snat_in_czone;)
>    table=??(lr_in_unsnat       ), priority=100  , match=(ip && ip4.dst ==
> 172.168.0.10 && inport == "lr0-public" &&
> is_chassis_resident("cr-lr0-public") && flags.loopback == 1 &&
> flags.use_snat_zone == 1), action=(ct_snat;)
>    table=??(lr_in_unsnat       ), priority=100  , match=(ip && ip4.dst ==
> 172.168.0.20 && inport == "lr0-public" &&
> is_chassis_resident("cr-lr0-public") && flags.loopback == 0),
> action=(ct_snat_in_czone;)
> @@ -5876,6 +5904,7 @@ AT_CHECK([grep "lr_in_unsnat" lr0flows |
> ovn_strip_lflows], [0], [dnl
>
>  AT_CHECK([grep "lr_in_defrag" lr0flows | ovn_strip_lflows], [0], [dnl
>    table=??(lr_in_defrag       ), priority=0    , match=(1), action=(next;)
> +  table=??(lr_in_defrag       ), priority=10   , match=(ip && (!ct.trk ||
> !ct.rpl)), action=(ct_next(dnat);)
>    table=??(lr_in_defrag       ), priority=100  , match=(ip && ip4.dst ==
> 10.0.0.10), action=(ct_dnat;)
>    table=??(lr_in_defrag       ), priority=100  , match=(ip && ip4.dst ==
> 172.168.0.100), action=(ct_dnat;)
>    table=??(lr_in_defrag       ), priority=100  , match=(ip && ip4.dst ==
> 172.168.0.200), action=(ct_dnat;)
> @@ -5884,6 +5913,7 @@ AT_CHECK([grep "lr_in_defrag" lr0flows |
> ovn_strip_lflows], [0], [dnl
>
>  AT_CHECK([grep "lr_in_dnat" lr0flows | ovn_strip_lflows], [0], [dnl
>    table=??(lr_in_dnat         ), priority=0    , match=(1), action=(next;)
> +  table=??(lr_in_dnat         ), priority=10   , match=(ip && ct.new),
> action=(ct_commit_to_zone(dnat);)
>    table=??(lr_in_dnat         ), priority=100  , match=(ip && ip4.dst ==
> 172.168.0.20 && inport == "lr0-public" &&
> is_chassis_resident("cr-lr0-public")), action=(ct_dnat_in_czone(10.0.0.3);)
>    table=??(lr_in_dnat         ), priority=110  , match=(ct.new && !ct.rel
> && ip4 && ip4.dst == 172.168.0.200 &&
> is_chassis_resident("cr-lr0-public")),
> action=(ct_lb_mark(backends=10.0.0.80,10.0.0.81);)
>    table=??(lr_in_dnat         ), priority=120  , match=(ct.new && !ct.rel
> && ip4 && ip4.dst == 10.0.0.10 && tcp && tcp.dst == 80 &&
> is_chassis_resident("cr-lr0-public")),
> action=(ct_lb_mark(backends=10.0.0.4:8080);)
> @@ -5916,10 +5946,12 @@ AT_CHECK([grep "lr_out_undnat" lr0flows |
> ovn_strip_lflows], [0], [dnl
>
>  AT_CHECK([grep "lr_out_post_undnat" lr0flows | ovn_strip_lflows], [0],
> [dnl
>    table=??(lr_out_post_undnat ), priority=0    , match=(1), action=(next;)
> +  table=??(lr_out_post_undnat ), priority=10   , match=(ip && (!ct.trk ||
> !ct.rpl) && flags.without_unsnat == 1), action=(ct_next(snat);)
>  ])
>
>  AT_CHECK([grep "lr_out_snat" lr0flows | ovn_strip_lflows], [0], [dnl
>    table=??(lr_out_snat        ), priority=0    , match=(1), action=(next;)
> +  table=??(lr_out_snat        ), priority=10   , match=(ip && ct.new &&
> flags.without_unsnat == 1), action=(ct_commit_to_zone(snat);)
>    table=??(lr_out_snat        ), priority=120  , match=(nd_ns),
> action=(next;)
>    table=??(lr_out_snat        ), priority=153  , match=(ip && ip4.src ==
> 10.0.0.0/24 && outport == "lr0-public" &&
> is_chassis_resident("cr-lr0-public") && (!ct.trk || !ct.rpl)),
> action=(ct_snat_in_czone(172.168.0.10);)
>    table=??(lr_out_snat        ), priority=154  , match=(ip && ip4.src ==
> 10.0.0.0/24 && outport == "lr0-public" &&
> is_chassis_resident("cr-lr0-public") && (!ct.trk || !ct.rpl) && reg9[[4]]
> == 1), action=(reg9[[4]] = 0; ct_snat(172.168.0.10);)
> @@ -5939,6 +5971,7 @@ AT_CAPTURE_FILE([lr0flows])
>
>  AT_CHECK([grep "lr_in_unsnat" lr0flows | ovn_strip_lflows], [0], [dnl
>    table=??(lr_in_unsnat       ), priority=0    , match=(1), action=(next;)
> +  table=??(lr_in_unsnat       ), priority=10   , match=(ip),
> action=(flags.without_unsnat = 1; next;)
>    table=??(lr_in_unsnat       ), priority=100  , match=(ip && ip4.dst ==
> 172.168.0.10 && inport == "lr0-public" &&
> is_chassis_resident("cr-lr0-public")), action=(ct_snat;)
>    table=??(lr_in_unsnat       ), priority=100  , match=(ip && ip4.dst ==
> 172.168.0.20 && inport == "lr0-public" &&
> is_chassis_resident("cr-lr0-public")), action=(ct_snat;)
>    table=??(lr_in_unsnat       ), priority=100  , match=(ip && ip4.dst ==
> 172.168.0.30 && inport == "lr0-public" &&
> is_chassis_resident("cr-lr0-public")), action=(ct_snat;)
> @@ -5946,6 +5979,7 @@ AT_CHECK([grep "lr_in_unsnat" lr0flows |
> ovn_strip_lflows], [0], [dnl
>
>  AT_CHECK([grep "lr_in_defrag" lr0flows | ovn_strip_lflows], [0], [dnl
>    table=??(lr_in_defrag       ), priority=0    , match=(1), action=(next;)
> +  table=??(lr_in_defrag       ), priority=10   , match=(ip && (!ct.trk ||
> !ct.rpl)), action=(ct_next(dnat);)
>    table=??(lr_in_defrag       ), priority=100  , match=(ip && ip4.dst ==
> 10.0.0.10), action=(ct_dnat;)
>    table=??(lr_in_defrag       ), priority=100  , match=(ip && ip4.dst ==
> 172.168.0.100), action=(ct_dnat;)
>    table=??(lr_in_defrag       ), priority=100  , match=(ip && ip4.dst ==
> 172.168.0.200), action=(ct_dnat;)
> @@ -5954,6 +5988,7 @@ AT_CHECK([grep "lr_in_defrag" lr0flows |
> ovn_strip_lflows], [0], [dnl
>
>  AT_CHECK([grep "lr_in_dnat" lr0flows | ovn_strip_lflows], [0], [dnl
>    table=??(lr_in_dnat         ), priority=0    , match=(1), action=(next;)
> +  table=??(lr_in_dnat         ), priority=10   , match=(ip && ct.new),
> action=(ct_commit_to_zone(dnat);)
>    table=??(lr_in_dnat         ), priority=100  , match=(ip && ip4.dst ==
> 172.168.0.20 && inport == "lr0-public" &&
> is_chassis_resident("cr-lr0-public")), action=(ct_dnat(10.0.0.3);)
>    table=??(lr_in_dnat         ), priority=110  , match=(ct.new && !ct.rel
> && ip4 && ip4.dst == 172.168.0.200 &&
> is_chassis_resident("cr-lr0-public")),
> action=(ct_lb_mark(backends=10.0.0.80,10.0.0.81);)
>    table=??(lr_in_dnat         ), priority=120  , match=(ct.new && !ct.rel
> && ip4 && ip4.dst == 10.0.0.10 && tcp && tcp.dst == 80 &&
> is_chassis_resident("cr-lr0-public")),
> action=(ct_lb_mark(backends=10.0.0.4:8080);)
> @@ -5982,24 +6017,20 @@ AT_CHECK([grep "lr_out_undnat" lr0flows |
> ovn_strip_lflows], [0], [dnl
>
>  AT_CHECK([grep "lr_out_post_undnat" lr0flows | ovn_strip_lflows], [0],
> [dnl
>    table=??(lr_out_post_undnat ), priority=0    , match=(1), action=(next;)
> -  table=??(lr_out_post_undnat ), priority=70   , match=(ip && ip4.src ==
> 10.0.0.0/24 && outport == "lr0-public" &&
> is_chassis_resident("cr-lr0-public") && (!ct.trk || !ct.rpl)),
> action=(ct_next(snat);)
> -  table=??(lr_out_post_undnat ), priority=70   , match=(ip && ip4.src ==
> 10.0.0.10 && outport == "lr0-public" &&
> is_chassis_resident("cr-lr0-public") && (!ct.trk || !ct.rpl)),
> action=(ct_next(snat);)
> +  table=??(lr_out_post_undnat ), priority=10   , match=(ip && (!ct.trk ||
> !ct.rpl) && flags.without_unsnat == 1), action=(ct_next(snat);)
>  ])
>
>  AT_CHECK([grep "lr_out_snat" lr0flows | ovn_strip_lflows], [0], [dnl
>    table=??(lr_out_snat        ), priority=0    , match=(1), action=(next;)
> +  table=??(lr_out_snat        ), priority=10   , match=(ip && ct.new &&
> flags.without_unsnat == 1), action=(ct_commit_to_zone(snat);)
>    table=??(lr_out_snat        ), priority=120  , match=(nd_ns),
> action=(next;)
> -  table=??(lr_out_snat        ), priority=153  , match=(ip && ip4.dst ==
> 10.0.0.0/24 && inport == "lr0-public" &&
> is_chassis_resident("cr-lr0-public")), action=(ct_snat;)
>    table=??(lr_out_snat        ), priority=153  , match=(ip && ip4.src ==
> 10.0.0.0/24 && outport == "lr0-public" &&
> is_chassis_resident("cr-lr0-public") && (!ct.trk || !ct.rpl)),
> action=(ct_snat(172.168.0.10);)
> -  table=??(lr_out_snat        ), priority=161  , match=(ip && ip4.dst ==
> 10.0.0.10 && inport == "lr0-public" &&
> is_chassis_resident("cr-lr0-public")), action=(ct_snat;)
>    table=??(lr_out_snat        ), priority=161  , match=(ip && ip4.src ==
> 10.0.0.10 && outport == "lr0-public" &&
> is_chassis_resident("cr-lr0-public") && (!ct.trk || !ct.rpl)),
> action=(ct_snat(172.168.0.30);)
>    table=??(lr_out_snat        ), priority=161  , match=(ip && ip4.src ==
> 10.0.0.3 && outport == "lr0-public" && is_chassis_resident("cr-lr0-public")
> && (!ct.trk || !ct.rpl)), action=(ct_snat(172.168.0.20);)
>  ])
>
>  AT_CHECK([grep "lr_out_post_snat" lr0flows | ovn_strip_lflows], [0], [dnl
>    table=??(lr_out_post_snat   ), priority=0    , match=(1), action=(next;)
> -  table=??(lr_out_post_snat   ), priority=153  , match=(ip && ip4.dst ==
> 10.0.0.0/24 && inport == "lr0-public" &&
> is_chassis_resident("cr-lr0-public") && ct.new),
> action=(ct_commit_to_zone(snat);)
> -  table=??(lr_out_post_snat   ), priority=161  , match=(ip && ip4.dst ==
> 10.0.0.10 && inport == "lr0-public" && is_chassis_resident("cr-lr0-public")
> && ct.new), action=(ct_commit_to_zone(snat);)
>  ])
>
>  # Make the logical router as Gateway router
> @@ -6013,6 +6044,7 @@ AT_CAPTURE_FILE([lr0flows])
>
>  AT_CHECK([grep "lr_in_unsnat" lr0flows | ovn_strip_lflows], [0], [dnl
>    table=??(lr_in_unsnat       ), priority=0    , match=(1), action=(next;)
> +  table=??(lr_in_unsnat       ), priority=10   , match=(ip),
> action=(flags.without_unsnat = 1; next;)
>    table=??(lr_in_unsnat       ), priority=90   , match=(ip && ip4.dst ==
> 172.168.0.10), action=(ct_snat;)
>    table=??(lr_in_unsnat       ), priority=90   , match=(ip && ip4.dst ==
> 172.168.0.20), action=(ct_snat;)
>    table=??(lr_in_unsnat       ), priority=90   , match=(ip && ip4.dst ==
> 172.168.0.30), action=(ct_snat;)
> @@ -6020,6 +6052,7 @@ AT_CHECK([grep "lr_in_unsnat" lr0flows |
> ovn_strip_lflows], [0], [dnl
>
>  AT_CHECK([grep "lr_in_defrag" lr0flows | ovn_strip_lflows], [0], [dnl
>    table=??(lr_in_defrag       ), priority=0    , match=(1), action=(next;)
> +  table=??(lr_in_defrag       ), priority=10   , match=(ip && (!ct.trk ||
> !ct.rpl)), action=(ct_next(dnat);)
>    table=??(lr_in_defrag       ), priority=100  , match=(ip && ip4.dst ==
> 10.0.0.10), action=(ct_dnat;)
>    table=??(lr_in_defrag       ), priority=100  , match=(ip && ip4.dst ==
> 172.168.0.100), action=(ct_dnat;)
>    table=??(lr_in_defrag       ), priority=100  , match=(ip && ip4.dst ==
> 172.168.0.200), action=(ct_dnat;)
> @@ -6028,6 +6061,7 @@ AT_CHECK([grep "lr_in_defrag" lr0flows |
> ovn_strip_lflows], [0], [dnl
>
>  AT_CHECK([grep "lr_in_dnat" lr0flows | ovn_strip_lflows], [0], [dnl
>    table=??(lr_in_dnat         ), priority=0    , match=(1), action=(next;)
> +  table=??(lr_in_dnat         ), priority=10   , match=(ip && ct.new),
> action=(ct_commit_to_zone(dnat);)
>    table=??(lr_in_dnat         ), priority=100  , match=(ip && ip4.dst ==
> 172.168.0.20), action=(flags.loopback = 1; ct_dnat(10.0.0.3);)
>    table=??(lr_in_dnat         ), priority=110  , match=(ct.new && !ct.rel
> && ip4 && ip4.dst == 172.168.0.200),
> action=(ct_lb_mark(backends=10.0.0.80,10.0.0.81);)
>    table=??(lr_in_dnat         ), priority=120  , match=(ct.new && !ct.rel
> && ip4 && ip4.dst == 10.0.0.10 && tcp && tcp.dst == 80),
> action=(ct_lb_mark(backends=10.0.0.4:8080);)
> @@ -6053,11 +6087,12 @@ AT_CHECK([grep "lr_out_undnat" lr0flows |
> ovn_strip_lflows], [0], [dnl
>
>  AT_CHECK([grep "lr_out_post_undnat" lr0flows | ovn_strip_lflows], [0],
> [dnl
>    table=??(lr_out_post_undnat ), priority=0    , match=(1), action=(next;)
> -  table=??(lr_out_post_undnat ), priority=50   , match=(ip && ct.new),
> action=(ct_commit { } ; next; )
> +  table=??(lr_out_post_undnat ), priority=10   , match=(ip && (!ct.trk ||
> !ct.rpl) && flags.without_unsnat == 1), action=(ct_next(snat);)
>  ])
>
>  AT_CHECK([grep "lr_out_snat" lr0flows | ovn_strip_lflows], [0], [dnl
>    table=??(lr_out_snat        ), priority=0    , match=(1), action=(next;)
> +  table=??(lr_out_snat        ), priority=10   , match=(ip && ct.new &&
> flags.without_unsnat == 1), action=(ct_commit_to_zone(snat);)
>    table=??(lr_out_snat        ), priority=120  , match=(nd_ns),
> action=(next;)
>    table=??(lr_out_snat        ), priority=25   , match=(ip && ip4.src ==
> 10.0.0.0/24 && (!ct.trk || !ct.rpl)), action=(ct_snat(172.168.0.10);)
>    table=??(lr_out_snat        ), priority=33   , match=(ip && ip4.src ==
> 10.0.0.10 && (!ct.trk || !ct.rpl)), action=(ct_snat(172.168.0.30);)
> @@ -6074,6 +6109,7 @@ AT_CAPTURE_FILE([lr0flows])
>
>  AT_CHECK([grep "lr_in_unsnat" lr0flows | ovn_strip_lflows], [0], [dnl
>    table=??(lr_in_unsnat       ), priority=0    , match=(1), action=(next;)
> +  table=??(lr_in_unsnat       ), priority=10   , match=(ip),
> action=(flags.without_unsnat = 1; next;)
>    table=??(lr_in_unsnat       ), priority=110  , match=(inport ==
> "lr0-public" && ip4.dst == 172.168.0.10), action=(ct_snat;)
>    table=??(lr_in_unsnat       ), priority=110  , match=(inport ==
> "lr0-sw0" && ip4.dst == 10.0.0.1), action=(ct_snat;)
>    table=??(lr_in_unsnat       ), priority=90   , match=(ip && ip4.dst ==
> 172.168.0.10), action=(ct_snat;)
> @@ -6083,6 +6119,7 @@ AT_CHECK([grep "lr_in_unsnat" lr0flows |
> ovn_strip_lflows], [0], [dnl
>
>  AT_CHECK([grep "lr_in_defrag" lr0flows | ovn_strip_lflows], [0], [dnl
>    table=??(lr_in_defrag       ), priority=0    , match=(1), action=(next;)
> +  table=??(lr_in_defrag       ), priority=10   , match=(ip && (!ct.trk ||
> !ct.rpl)), action=(ct_next(dnat);)
>    table=??(lr_in_defrag       ), priority=100  , match=(ip && ip4.dst ==
> 10.0.0.10), action=(ct_dnat;)
>    table=??(lr_in_defrag       ), priority=100  , match=(ip && ip4.dst ==
> 172.168.0.100), action=(ct_dnat;)
>    table=??(lr_in_defrag       ), priority=100  , match=(ip && ip4.dst ==
> 172.168.0.200), action=(ct_dnat;)
> @@ -6091,6 +6128,7 @@ AT_CHECK([grep "lr_in_defrag" lr0flows |
> ovn_strip_lflows], [0], [dnl
>
>  AT_CHECK([grep "lr_in_dnat" lr0flows | ovn_strip_lflows], [0], [dnl
>    table=??(lr_in_dnat         ), priority=0    , match=(1), action=(next;)
> +  table=??(lr_in_dnat         ), priority=10   , match=(ip && ct.new),
> action=(ct_commit_to_zone(dnat);)
>    table=??(lr_in_dnat         ), priority=100  , match=(ip && ip4.dst ==
> 172.168.0.20), action=(flags.loopback = 1; ct_dnat(10.0.0.3);)
>    table=??(lr_in_dnat         ), priority=110  , match=(ct.new && !ct.rel
> && ip4 && ip4.dst == 172.168.0.200), action=(flags.force_snat_for_lb = 1;
> ct_lb_mark(backends=10.0.0.80,10.0.0.81; force_snat);)
>    table=??(lr_in_dnat         ), priority=120  , match=(ct.new && !ct.rel
> && ip4 && ip4.dst == 10.0.0.10 && tcp && tcp.dst == 80),
> action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.4:8080;
> force_snat);)
> @@ -6116,11 +6154,12 @@ AT_CHECK([grep "lr_out_undnat" lr0flows |
> ovn_strip_lflows], [0], [dnl
>
>  AT_CHECK([grep "lr_out_post_undnat" lr0flows | ovn_strip_lflows], [0],
> [dnl
>    table=??(lr_out_post_undnat ), priority=0    , match=(1), action=(next;)
> -  table=??(lr_out_post_undnat ), priority=50   , match=(ip && ct.new),
> action=(ct_commit { } ; next; )
> +  table=??(lr_out_post_undnat ), priority=10   , match=(ip && (!ct.trk ||
> !ct.rpl) && flags.without_unsnat == 1), action=(ct_next(snat);)
>  ])
>
>  AT_CHECK([grep "lr_out_snat" lr0flows | ovn_strip_lflows], [0], [dnl
>    table=??(lr_out_snat        ), priority=0    , match=(1), action=(next;)
> +  table=??(lr_out_snat        ), priority=10   , match=(ip && ct.new &&
> flags.without_unsnat == 1), action=(ct_commit_to_zone(snat);)
>    table=??(lr_out_snat        ), priority=110  ,
> match=(flags.force_snat_for_lb == 1 && ip4 && outport == "lr0-public"),
> action=(ct_snat(172.168.0.10);)
>    table=??(lr_out_snat        ), priority=110  ,
> match=(flags.force_snat_for_lb == 1 && ip4 && outport == "lr0-sw0"),
> action=(ct_snat(10.0.0.1);)
>    table=??(lr_out_snat        ), priority=120  , match=(nd_ns),
> action=(next;)
> @@ -6138,6 +6177,7 @@ AT_CAPTURE_FILE([lr0flows])
>
>  AT_CHECK([grep "lr_in_unsnat" lr0flows | ovn_strip_lflows], [0], [dnl
>    table=??(lr_in_unsnat       ), priority=0    , match=(1), action=(next;)
> +  table=??(lr_in_unsnat       ), priority=10   , match=(ip),
> action=(flags.without_unsnat = 1; next;)
>    table=??(lr_in_unsnat       ), priority=110  , match=(inport ==
> "lr0-public" && ip4.dst == 172.168.0.10), action=(ct_snat;)
>    table=??(lr_in_unsnat       ), priority=110  , match=(inport ==
> "lr0-sw0" && ip4.dst == 10.0.0.1), action=(ct_snat;)
>    table=??(lr_in_unsnat       ), priority=90   , match=(ip && ip4.dst ==
> 172.168.0.10), action=(ct_snat;)
> @@ -6147,6 +6187,7 @@ AT_CHECK([grep "lr_in_unsnat" lr0flows |
> ovn_strip_lflows], [0], [dnl
>
>  AT_CHECK([grep "lr_in_defrag" lr0flows | ovn_strip_lflows], [0], [dnl
>    table=??(lr_in_defrag       ), priority=0    , match=(1), action=(next;)
> +  table=??(lr_in_defrag       ), priority=10   , match=(ip && (!ct.trk ||
> !ct.rpl)), action=(ct_next(dnat);)
>    table=??(lr_in_defrag       ), priority=100  , match=(ip && ip4.dst ==
> 10.0.0.10), action=(ct_dnat;)
>    table=??(lr_in_defrag       ), priority=100  , match=(ip && ip4.dst ==
> 172.168.0.10), action=(ct_dnat;)
>    table=??(lr_in_defrag       ), priority=100  , match=(ip && ip4.dst ==
> 172.168.0.100), action=(ct_dnat;)
> @@ -6156,6 +6197,7 @@ AT_CHECK([grep "lr_in_defrag" lr0flows |
> ovn_strip_lflows], [0], [dnl
>
>  AT_CHECK([grep "lr_in_dnat" lr0flows | ovn_strip_lflows], [0], [dnl
>    table=??(lr_in_dnat         ), priority=0    , match=(1), action=(next;)
> +  table=??(lr_in_dnat         ), priority=10   , match=(ip && ct.new),
> action=(ct_commit_to_zone(dnat);)
>    table=??(lr_in_dnat         ), priority=100  , match=(ip && ip4.dst ==
> 172.168.0.20), action=(flags.loopback = 1; ct_dnat(10.0.0.3);)
>    table=??(lr_in_dnat         ), priority=110  , match=(ct.new && !ct.rel
> && ip4 && ip4.dst == 172.168.0.200), action=(flags.force_snat_for_lb = 1;
> ct_lb_mark(backends=10.0.0.80,10.0.0.81; force_snat);)
>    table=??(lr_in_dnat         ), priority=120  , match=(ct.new && !ct.rel
> && ip4 && ip4.dst == 10.0.0.10 && tcp && tcp.dst == 80),
> action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.4:8080;
> force_snat);)
> @@ -6182,11 +6224,12 @@ AT_CHECK([grep "lr_out_undnat" lr0flows |
> ovn_strip_lflows], [0], [dnl
>
>  AT_CHECK([grep "lr_out_post_undnat" lr0flows | ovn_strip_lflows], [0],
> [dnl
>    table=??(lr_out_post_undnat ), priority=0    , match=(1), action=(next;)
> -  table=??(lr_out_post_undnat ), priority=50   , match=(ip && ct.new),
> action=(ct_commit { } ; next; )
> +  table=??(lr_out_post_undnat ), priority=10   , match=(ip && (!ct.trk ||
> !ct.rpl) && flags.without_unsnat == 1), action=(ct_next(snat);)
>  ])
>
>  AT_CHECK([grep "lr_out_snat" lr0flows | ovn_strip_lflows], [0], [dnl
>    table=??(lr_out_snat        ), priority=0    , match=(1), action=(next;)
> +  table=??(lr_out_snat        ), priority=10   , match=(ip && ct.new &&
> flags.without_unsnat == 1), action=(ct_commit_to_zone(snat);)
>    table=??(lr_out_snat        ), priority=110  ,
> match=(flags.force_snat_for_lb == 1 && ip4 && outport == "lr0-public"),
> action=(ct_snat(172.168.0.10);)
>    table=??(lr_out_snat        ), priority=110  ,
> match=(flags.force_snat_for_lb == 1 && ip4 && outport == "lr0-sw0"),
> action=(ct_snat(10.0.0.1);)
>    table=??(lr_out_snat        ), priority=120  , match=(nd_ns),
> action=(next;)
> @@ -6212,6 +6255,7 @@ AT_CAPTURE_FILE([lr0flows])
>
>  AT_CHECK([grep "lr_in_unsnat" lr0flows | ovn_strip_lflows], [0], [dnl
>    table=??(lr_in_unsnat       ), priority=0    , match=(1), action=(next;)
> +  table=??(lr_in_unsnat       ), priority=10   , match=(ip),
> action=(flags.without_unsnat = 1; next;)
>    table=??(lr_in_unsnat       ), priority=110  , match=(inport ==
> "lr0-public" && ip4.dst == 172.168.0.10), action=(ct_snat;)
>    table=??(lr_in_unsnat       ), priority=110  , match=(inport ==
> "lr0-public" && ip6.dst == def0::10), action=(ct_snat;)
>    table=??(lr_in_unsnat       ), priority=110  , match=(inport ==
> "lr0-sw0" && ip4.dst == 10.0.0.1), action=(ct_snat;)
> @@ -6223,6 +6267,7 @@ AT_CHECK([grep "lr_in_unsnat" lr0flows |
> ovn_strip_lflows], [0], [dnl
>
>  AT_CHECK([grep "lr_in_defrag" lr0flows | ovn_strip_lflows], [0], [dnl
>    table=??(lr_in_defrag       ), priority=0    , match=(1), action=(next;)
> +  table=??(lr_in_defrag       ), priority=10   , match=(ip && (!ct.trk ||
> !ct.rpl)), action=(ct_next(dnat);)
>    table=??(lr_in_defrag       ), priority=100  , match=(ip && ip4.dst ==
> 10.0.0.10), action=(ct_dnat;)
>    table=??(lr_in_defrag       ), priority=100  , match=(ip && ip4.dst ==
> 172.168.0.10), action=(ct_dnat;)
>    table=??(lr_in_defrag       ), priority=100  , match=(ip && ip4.dst ==
> 172.168.0.100), action=(ct_dnat;)
> @@ -6233,6 +6278,7 @@ AT_CHECK([grep "lr_in_defrag" lr0flows |
> ovn_strip_lflows], [0], [dnl
>
>  AT_CHECK([grep "lr_in_dnat" lr0flows | ovn_strip_lflows], [0], [dnl
>    table=??(lr_in_dnat         ), priority=0    , match=(1), action=(next;)
> +  table=??(lr_in_dnat         ), priority=10   , match=(ip && ct.new),
> action=(ct_commit_to_zone(dnat);)
>    table=??(lr_in_dnat         ), priority=100  , match=(ip && ip4.dst ==
> 172.168.0.20), action=(flags.loopback = 1; ct_dnat(10.0.0.3);)
>    table=??(lr_in_dnat         ), priority=110  , match=(ct.new && !ct.rel
> && ip4 && ip4.dst == 172.168.0.200), action=(flags.force_snat_for_lb = 1;
> ct_lb_mark(backends=10.0.0.80,10.0.0.81; force_snat);)
>    table=??(lr_in_dnat         ), priority=120  , match=(ct.new && !ct.rel
> && ip4 && ip4.dst == 10.0.0.10 && tcp && tcp.dst == 80),
> action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.4:8080;
> force_snat);)
> @@ -6260,11 +6306,12 @@ AT_CHECK([grep "lr_out_undnat" lr0flows |
> ovn_strip_lflows], [0], [dnl
>
>  AT_CHECK([grep "lr_out_post_undnat" lr0flows | ovn_strip_lflows], [0],
> [dnl
>    table=??(lr_out_post_undnat ), priority=0    , match=(1), action=(next;)
> -  table=??(lr_out_post_undnat ), priority=50   , match=(ip && ct.new),
> action=(ct_commit { } ; next; )
> +  table=??(lr_out_post_undnat ), priority=10   , match=(ip && (!ct.trk ||
> !ct.rpl) && flags.without_unsnat == 1), action=(ct_next(snat);)
>  ])
>
>  AT_CHECK([grep "lr_out_snat" lr0flows | ovn_strip_lflows], [0], [dnl
>    table=??(lr_out_snat        ), priority=0    , match=(1), action=(next;)
> +  table=??(lr_out_snat        ), priority=10   , match=(ip && ct.new &&
> flags.without_unsnat == 1), action=(ct_commit_to_zone(snat);)
>    table=??(lr_out_snat        ), priority=110  ,
> match=(flags.force_snat_for_lb == 1 && ip4 && outport == "lr0-public"),
> action=(ct_snat(172.168.0.10);)
>    table=??(lr_out_snat        ), priority=110  ,
> match=(flags.force_snat_for_lb == 1 && ip4 && outport == "lr0-sw0"),
> action=(ct_snat(10.0.0.1);)
>    table=??(lr_out_snat        ), priority=110  ,
> match=(flags.force_snat_for_lb == 1 && ip6 && outport == "lr0-public"),
> action=(ct_snat(def0::10);)
> @@ -6291,15 +6338,18 @@ AT_CAPTURE_FILE([lr0flows])
>
>  AT_CHECK([grep "lr_in_unsnat" lr0flows | ovn_strip_lflows], [0], [dnl
>    table=??(lr_in_unsnat       ), priority=0    , match=(1), action=(next;)
> +  table=??(lr_in_unsnat       ), priority=10   , match=(ip),
> action=(flags.without_unsnat = 1; next;)
>  ])
>
>  AT_CHECK([grep "lr_in_defrag" lr0flows | ovn_strip_lflows], [0], [dnl
>    table=??(lr_in_defrag       ), priority=0    , match=(1), action=(next;)
> +  table=??(lr_in_defrag       ), priority=10   , match=(ip && (!ct.trk ||
> !ct.rpl)), action=(ct_next(dnat);)
>    table=??(lr_in_defrag       ), priority=100  , match=(ip && ip4.dst ==
> 172.168.0.210), action=(ct_dnat;)
>  ])
>
>  AT_CHECK([grep "lr_in_dnat" lr0flows | ovn_strip_lflows], [0], [dnl
>    table=??(lr_in_dnat         ), priority=0    , match=(1), action=(next;)
> +  table=??(lr_in_dnat         ), priority=10   , match=(ip && ct.new),
> action=(ct_commit_to_zone(dnat);)
>    table=??(lr_in_dnat         ), priority=120  , match=(ct.new && !ct.rel
> && ip4 && ip4.dst == 172.168.0.210 && tcp && tcp.dst == 60),
> action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.50:6062,
> 10.0.0.60:6062; force_snat);)
>    table=??(lr_in_dnat         ), priority=120  , match=(ct.new && !ct.rel
> && ip4 && ip4.dst == 172.168.0.210 && udp && udp.dst == 60),
> action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.50:6062,
> 10.0.0.60:6062; force_snat);)
>    table=??(lr_in_dnat         ), priority=50   , match=(ct.est && !ct.rel
> && !ct.new && ct_mark.natted), action=(next;)
> @@ -6322,11 +6372,12 @@ AT_CHECK([grep "lr_out_undnat" lr0flows |
> ovn_strip_lflows], [0], [dnl
>
>  AT_CHECK([grep "lr_out_post_undnat" lr0flows | ovn_strip_lflows], [0],
> [dnl
>    table=??(lr_out_post_undnat ), priority=0    , match=(1), action=(next;)
> -  table=??(lr_out_post_undnat ), priority=50   , match=(ip && ct.new),
> action=(ct_commit { } ; next; )
> +  table=??(lr_out_post_undnat ), priority=10   , match=(ip && (!ct.trk ||
> !ct.rpl) && flags.without_unsnat == 1), action=(ct_next(snat);)
>  ])
>
>  AT_CHECK([grep "lr_out_snat" lr0flows | ovn_strip_lflows], [0], [dnl
>    table=??(lr_out_snat        ), priority=0    , match=(1), action=(next;)
> +  table=??(lr_out_snat        ), priority=10   , match=(ip && ct.new &&
> flags.without_unsnat == 1), action=(ct_commit_to_zone(snat);)
>    table=??(lr_out_snat        ), priority=120  , match=(nd_ns),
> action=(next;)
>  ])
>
> @@ -6358,6 +6409,7 @@ check ovn-nbctl --wait=sb sync
>
>  AT_CHECK([ovn-sbctl dump-flows lr0 | grep "lr_in_dnat" |
> ovn_strip_lflows], [0], [dnl
>    table=??(lr_in_dnat         ), priority=0    , match=(1), action=(next;)
> +  table=??(lr_in_dnat         ), priority=10   , match=(ip && ct.new),
> action=(ct_commit_to_zone(dnat);)
>    table=??(lr_in_dnat         ), priority=110  , match=(ct.new && !ct.rel
> && ip4 && ip4.dst == 172.168.10.10), action=(reg0 = 0; reject { outport <->
> inport; next(pipeline=egress,table=??);};)
>    table=??(lr_in_dnat         ), priority=50   , match=(ct.est && !ct.rel
> && !ct.new && ct_mark.natted), action=(next;)
>    table=??(lr_in_dnat         ), priority=50   , match=(ct.rel && !ct.est
> && !ct.new), action=(ct_commit_nat;)
> @@ -6372,6 +6424,7 @@ check ovn-nbctl --wait=sb set load_balancer lb5
> options:skip_snat=true
>
>  AT_CHECK([ovn-sbctl dump-flows lr0 | grep "lr_in_dnat" |
> ovn_strip_lflows], [0], [dnl
>    table=??(lr_in_dnat         ), priority=0    , match=(1), action=(next;)
> +  table=??(lr_in_dnat         ), priority=10   , match=(ip && ct.new),
> action=(ct_commit_to_zone(dnat);)
>    table=??(lr_in_dnat         ), priority=110  , match=(ct.new && !ct.rel
> && ip4 && ip4.dst == 172.168.10.10), action=(flags.skip_snat_for_lb = 1;
> reg0 = 0; reject { outport <-> inport; next(pipeline=egress,table=??);};)
>    table=??(lr_in_dnat         ), priority=50   , match=(ct.est && !ct.rel
> && !ct.new && ct_mark.natted), action=(next;)
>    table=??(lr_in_dnat         ), priority=50   , match=(ct.rel && !ct.est
> && !ct.new), action=(ct_commit_nat;)
> @@ -6388,6 +6441,7 @@ check ovn-nbctl --wait=sb set logical_router lr0
> options:lb_force_snat_ip="route
>
>  AT_CHECK([ovn-sbctl dump-flows lr0 | grep "lr_in_dnat" |
> ovn_strip_lflows], [0], [dnl
>    table=??(lr_in_dnat         ), priority=0    , match=(1), action=(next;)
> +  table=??(lr_in_dnat         ), priority=10   , match=(ip && ct.new),
> action=(ct_commit_to_zone(dnat);)
>    table=??(lr_in_dnat         ), priority=110  , match=(ct.new && !ct.rel
> && ip4 && ip4.dst == 172.168.10.10), action=(flags.force_snat_for_lb = 1;
> reg0 = 0; reject { outport <-> inport; next(pipeline=egress,table=??);};)
>    table=??(lr_in_dnat         ), priority=50   , match=(ct.est && !ct.rel
> && !ct.new && ct_mark.natted), action=(next;)
>    table=??(lr_in_dnat         ), priority=50   , match=(ct.rel && !ct.est
> && !ct.new), action=(ct_commit_nat;)
> @@ -6405,6 +6459,7 @@ check ovn-nbctl --wait=sb lr-lb-add lr0 lb6
>
>  AT_CHECK([ovn-sbctl dump-flows lr0 | grep "lr_in_dnat" |
> ovn_strip_lflows], [0], [dnl
>    table=??(lr_in_dnat         ), priority=0    , match=(1), action=(next;)
> +  table=??(lr_in_dnat         ), priority=10   , match=(ip && ct.new),
> action=(ct_commit_to_zone(dnat);)
>    table=??(lr_in_dnat         ), priority=110  , match=(ct.new && !ct.rel
> && ip4 && ip4.dst == 172.168.10.30), action=(drop;)
>    table=??(lr_in_dnat         ), priority=50   , match=(ct.est && !ct.rel
> && !ct.new && ct_mark.natted), action=(next;)
>    table=??(lr_in_dnat         ), priority=50   , match=(ct.rel && !ct.est
> && !ct.new), action=(ct_commit_nat;)
> @@ -6419,6 +6474,7 @@ check ovn-nbctl --wait=sb set load_balancer lb6
> options:skip_snat=true
>
>  AT_CHECK([ovn-sbctl dump-flows lr0 | grep "lr_in_dnat" |
> ovn_strip_lflows], [0], [dnl
>    table=??(lr_in_dnat         ), priority=0    , match=(1), action=(next;)
> +  table=??(lr_in_dnat         ), priority=10   , match=(ip && ct.new),
> action=(ct_commit_to_zone(dnat);)
>    table=??(lr_in_dnat         ), priority=110  , match=(ct.new && !ct.rel
> && ip4 && ip4.dst == 172.168.10.30), action=(flags.skip_snat_for_lb = 1;
> drop;)
>    table=??(lr_in_dnat         ), priority=50   , match=(ct.est && !ct.rel
> && !ct.new && ct_mark.natted), action=(next;)
>    table=??(lr_in_dnat         ), priority=50   , match=(ct.rel && !ct.est
> && !ct.new), action=(ct_commit_nat;)
> @@ -6435,6 +6491,7 @@ check ovn-nbctl --wait=sb set logical_router lr0
> options:lb_force_snat_ip="route
>
>  AT_CHECK([ovn-sbctl dump-flows lr0 | grep "lr_in_dnat" |
> ovn_strip_lflows], [0], [dnl
>    table=??(lr_in_dnat         ), priority=0    , match=(1), action=(next;)
> +  table=??(lr_in_dnat         ), priority=10   , match=(ip && ct.new),
> action=(ct_commit_to_zone(dnat);)
>    table=??(lr_in_dnat         ), priority=110  , match=(ct.new && !ct.rel
> && ip4 && ip4.dst == 172.168.10.30), action=(flags.force_snat_for_lb = 1;
> drop;)
>    table=??(lr_in_dnat         ), priority=50   , match=(ct.est && !ct.rel
> && !ct.new && ct_mark.natted), action=(next;)
>    table=??(lr_in_dnat         ), priority=50   , match=(ct.rel && !ct.est
> && !ct.new), action=(ct_commit_nat;)
> @@ -7951,9 +8008,6 @@ AT_CHECK([grep lr_in_unsnat lrflows | grep ct_snat |
> ovn_strip_lflows], [0], [dn
>  ])
>
>  AT_CHECK([grep lr_out_snat lrflows | grep ct_snat | ovn_strip_lflows],
> [0], [dnl
> -  table=??(lr_out_snat        ), priority=161  , match=(ip && ip4.dst ==
> 20.0.0.10 && inport == "DR-S1" && is_chassis_resident("cr-DR-S1")),
> action=(ct_snat;)
> -  table=??(lr_out_snat        ), priority=161  , match=(ip && ip4.dst ==
> 20.0.0.10 && inport == "DR-S2" && is_chassis_resident("cr-DR-S2")),
> action=(ct_snat;)
> -  table=??(lr_out_snat        ), priority=161  , match=(ip && ip4.dst ==
> 20.0.0.10 && inport == "DR-S3" && is_chassis_resident("cr-DR-S3")),
> action=(ct_snat;)
>    table=??(lr_out_snat        ), priority=161  , match=(ip && ip4.src ==
> 20.0.0.10 && outport == "DR-S1" && is_chassis_resident("cr-DR-S1") &&
> (!ct.trk || !ct.rpl)), action=(ct_snat(172.16.1.10);)
>    table=??(lr_out_snat        ), priority=161  , match=(ip && ip4.src ==
> 20.0.0.10 && outport == "DR-S2" && is_chassis_resident("cr-DR-S2") &&
> (!ct.trk || !ct.rpl)), action=(ct_snat(10.0.0.10);)
>    table=??(lr_out_snat        ), priority=161  , match=(ip && ip4.src ==
> 20.0.0.10 && outport == "DR-S3" && is_chassis_resident("cr-DR-S3") &&
> (!ct.trk || !ct.rpl)), action=(ct_snat(192.168.0.10);)
> @@ -7961,9 +8015,6 @@ AT_CHECK([grep lr_out_snat lrflows | grep ct_snat |
> ovn_strip_lflows], [0], [dnl
>
>  AT_CHECK([grep lr_out_post_snat lrflows | ovn_strip_lflows], [0], [dnl
>    table=??(lr_out_post_snat   ), priority=0    , match=(1), action=(next;)
> -  table=??(lr_out_post_snat   ), priority=161  , match=(ip && ip4.dst ==
> 20.0.0.10 && inport == "DR-S1" && is_chassis_resident("cr-DR-S1") &&
> ct.new), action=(ct_commit_to_zone(snat);)
> -  table=??(lr_out_post_snat   ), priority=161  , match=(ip && ip4.dst ==
> 20.0.0.10 && inport == "DR-S2" && is_chassis_resident("cr-DR-S2") &&
> ct.new), action=(ct_commit_to_zone(snat);)
> -  table=??(lr_out_post_snat   ), priority=161  , match=(ip && ip4.dst ==
> 20.0.0.10 && inport == "DR-S3" && is_chassis_resident("cr-DR-S3") &&
> ct.new), action=(ct_commit_to_zone(snat);)
>  ])
>
>  check ovn-nbctl --wait=sb lr-nat-del DR snat 20.0.0.10
> @@ -9387,6 +9438,7 @@ AT_CHECK([grep "lr_in_lb_aff_check" R1flows |
> ovn_strip_lflows], [0], [dnl
>  ])
>  AT_CHECK([grep "lr_in_dnat " R1flows | ovn_strip_lflows], [0], [dnl
>    table=??(lr_in_dnat         ), priority=0    , match=(1), action=(next;)
> +  table=??(lr_in_dnat         ), priority=10   , match=(ip && ct.new),
> action=(ct_commit_to_zone(dnat);)
>    table=??(lr_in_dnat         ), priority=120  , match=(ct.new && !ct.rel
> && ip4 && ip4.dst == 172.16.0.10 && tcp && tcp.dst == 80),
> action=(ct_lb_mark(backends=10.0.0.2:80,20.0.0.2:80);)
>    table=??(lr_in_dnat         ), priority=150  , match=(reg9[[6]] == 1 &&
> ct.new && ip4.dst == 172.16.0.10 && reg4 == 10.0.0.2 && reg8[[0..15]] ==
> 80), action=(reg0 = 172.16.0.10; ct_lb_mark(backends=10.0.0.2:80);)
>    table=??(lr_in_dnat         ), priority=150  , match=(reg9[[6]] == 1 &&
> ct.new && ip4.dst == 172.16.0.10 && reg4 == 20.0.0.2 && reg8[[0..15]] ==
> 80), action=(reg0 = 172.16.0.10; ct_lb_mark(backends=20.0.0.2:80);)
> @@ -9411,6 +9463,7 @@ AT_CAPTURE_FILE([R1flows_skip_snat])
>
>  AT_CHECK([grep "lr_in_dnat " R1flows_skip_snat | ovn_strip_lflows], [0],
> [dnl
>    table=??(lr_in_dnat         ), priority=0    , match=(1), action=(next;)
> +  table=??(lr_in_dnat         ), priority=10   , match=(ip && ct.new),
> action=(ct_commit_to_zone(dnat);)
>    table=??(lr_in_dnat         ), priority=120  , match=(ct.new && !ct.rel
> && ip4 && ip4.dst == 172.16.0.10 && tcp && tcp.dst == 80),
> action=(flags.skip_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.2:80,
> 20.0.0.2:80; skip_snat);)
>    table=??(lr_in_dnat         ), priority=150  , match=(reg9[[6]] == 1 &&
> ct.new && ip4.dst == 172.16.0.10 && reg4 == 10.0.0.2 && reg8[[0..15]] ==
> 80), action=(reg0 = 172.16.0.10; flags.skip_snat_for_lb = 1;
> ct_lb_mark(backends=10.0.0.2:80; skip_snat);)
>    table=??(lr_in_dnat         ), priority=150  , match=(reg9[[6]] == 1 &&
> ct.new && ip4.dst == 172.16.0.10 && reg4 == 20.0.0.2 && reg8[[0..15]] ==
> 80), action=(reg0 = 172.16.0.10; flags.skip_snat_for_lb = 1;
> ct_lb_mark(backends=20.0.0.2:80; skip_snat);)
> @@ -9432,6 +9485,7 @@ AT_CAPTURE_FILE([R1flows_force_snat])
>
>  AT_CHECK([grep "lr_in_dnat " R1flows_force_snat | ovn_strip_lflows], [0],
> [dnl
>    table=??(lr_in_dnat         ), priority=0    , match=(1), action=(next;)
> +  table=??(lr_in_dnat         ), priority=10   , match=(ip && ct.new),
> action=(ct_commit_to_zone(dnat);)
>    table=??(lr_in_dnat         ), priority=120  , match=(ct.new && !ct.rel
> && ip4 && ip4.dst == 172.16.0.10 && tcp && tcp.dst == 80),
> action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.2:80,
> 20.0.0.2:80; force_snat);)
>    table=??(lr_in_dnat         ), priority=150  , match=(reg9[[6]] == 1 &&
> ct.new && ip4.dst == 172.16.0.10 && reg4 == 10.0.0.2 && reg8[[0..15]] ==
> 80), action=(reg0 = 172.16.0.10; flags.force_snat_for_lb = 1;
> ct_lb_mark(backends=10.0.0.2:80; force_snat);)
>    table=??(lr_in_dnat         ), priority=150  , match=(reg9[[6]] == 1 &&
> ct.new && ip4.dst == 172.16.0.10 && reg4 == 20.0.0.2 && reg8[[0..15]] ==
> 80), action=(reg0 = 172.16.0.10; flags.force_snat_for_lb = 1;
> ct_lb_mark(backends=20.0.0.2:80; force_snat);)
> @@ -9452,6 +9506,7 @@ AT_CAPTURE_FILE([R1flows_force_skip_snat])
>
>  AT_CHECK([grep "lr_in_dnat " R1flows_force_skip_snat | ovn_strip_lflows],
> [0], [dnl
>    table=??(lr_in_dnat         ), priority=0    , match=(1), action=(next;)
> +  table=??(lr_in_dnat         ), priority=10   , match=(ip && ct.new),
> action=(ct_commit_to_zone(dnat);)
>    table=??(lr_in_dnat         ), priority=120  , match=(ct.new && !ct.rel
> && ip4 && ip4.dst == 172.16.0.10 && tcp && tcp.dst == 80),
> action=(flags.skip_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.2:80,
> 20.0.0.2:80; skip_snat);)
>    table=??(lr_in_dnat         ), priority=150  , match=(reg9[[6]] == 1 &&
> ct.new && ip4.dst == 172.16.0.10 && reg4 == 10.0.0.2 && reg8[[0..15]] ==
> 80), action=(reg0 = 172.16.0.10; flags.skip_snat_for_lb = 1;
> ct_lb_mark(backends=10.0.0.2:80; skip_snat);)
>    table=??(lr_in_dnat         ), priority=150  , match=(reg9[[6]] == 1 &&
> ct.new && ip4.dst == 172.16.0.10 && reg4 == 20.0.0.2 && reg8[[0..15]] ==
> 80), action=(reg0 = 172.16.0.10; flags.skip_snat_for_lb = 1;
> ct_lb_mark(backends=20.0.0.2:80; skip_snat);)
> @@ -9476,6 +9531,7 @@ AT_CAPTURE_FILE([R1flows_2lbs])
>
>  AT_CHECK([grep "lr_in_dnat " R1flows_2lbs | ovn_strip_lflows], [0], [dnl
>    table=??(lr_in_dnat         ), priority=0    , match=(1), action=(next;)
> +  table=??(lr_in_dnat         ), priority=10   , match=(ip && ct.new),
> action=(ct_commit_to_zone(dnat);)
>    table=??(lr_in_dnat         ), priority=120  , match=(ct.new && !ct.rel
> && ip4 && ip4.dst == 172.16.0.10 && tcp && tcp.dst == 80),
> action=(flags.skip_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.2:80,
> 20.0.0.2:80; skip_snat);)
>    table=??(lr_in_dnat         ), priority=120  , match=(ct.new && !ct.rel
> && ip4 && ip4.dst == 172.16.0.20 && tcp && tcp.dst == 80),
> action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.2:80,
> 20.0.0.2:80; force_snat);)
>    table=??(lr_in_dnat         ), priority=150  , match=(reg9[[6]] == 1 &&
> ct.new && ip4.dst == 172.16.0.10 && reg4 == 10.0.0.2 && reg8[[0..15]] ==
> 80), action=(reg0 = 172.16.0.10; flags.skip_snat_for_lb = 1;
> ct_lb_mark(backends=10.0.0.2:80; skip_snat);)
> diff --git a/tests/system-ovn.at b/tests/system-ovn.at
> index 861b1cb99..dc7b0ab2e 100644
> --- a/tests/system-ovn.at
> +++ b/tests/system-ovn.at
> @@ -117,6 +117,7 @@ NS_CHECK_EXEC([alice1], [ping -q -c 3 -i 0.3 -w 2
> 30.0.0.2 | FORMAT_PING], \
>  AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(172.16.1.2) | \
>  sed -e 's/zone=[[0-9]]*/zone=<cleared>/'], [0], [dnl
>
>  icmp,orig=(src=172.16.1.2,dst=192.168.1.2,id=<cleared>,type=8,code=0),reply=(src=192.168.1.2,dst=172.16.1.2,id=<cleared>,type=0,code=0),zone=<cleared>
>
> +icmp,orig=(src=172.16.1.2,dst=192.168.1.2,id=<cleared>,type=8,code=0),reply=(src=192.168.1.2,dst=172.16.1.2,id=<cleared>,type=0,code=0),zone=<cleared>
>
>  icmp,orig=(src=172.16.1.2,dst=30.0.0.2,id=<cleared>,type=8,code=0),reply=(src=192.168.1.2,dst=172.16.1.2,id=<cleared>,type=0,code=0),zone=<cleared>
>  ])
>
> @@ -297,6 +298,7 @@ NS_CHECK_EXEC([alice1], [ping6 -q -c 3 -i 0.3 -w 2
> fd30::2 | FORMAT_PING], \
>  AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(fd21::2) | \
>  sed -e 's/zone=[[0-9]]*/zone=<cleared>/'], [0], [dnl
>
>  icmpv6,orig=(src=fd21::2,dst=fd11::2,id=<cleared>,type=128,code=0),reply=(src=fd11::2,dst=fd21::2,id=<cleared>,type=129,code=0),zone=<cleared>
>
> +icmpv6,orig=(src=fd21::2,dst=fd11::2,id=<cleared>,type=128,code=0),reply=(src=fd11::2,dst=fd21::2,id=<cleared>,type=129,code=0),zone=<cleared>
>
>  icmpv6,orig=(src=fd21::2,dst=fd30::2,id=<cleared>,type=128,code=0),reply=(src=fd11::2,dst=fd21::2,id=<cleared>,type=129,code=0),zone=<cleared>
>  ])
>
> @@ -3753,6 +3755,7 @@ NS_CHECK_EXEC([foo2], [ping6 -q -c 3 -i 0.3 -w 2
> fd20::2 | FORMAT_PING], \
>  ovs-appctl dpctl/dump-conntrack | grep icmpv6
>  AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(fd11::3) | \
>  sed -e 's/zone=[[0-9]]*/zone=<cleared>/'], [0], [dnl
>
> +icmpv6,orig=(src=fd11::3,dst=fd20::2,id=<cleared>,type=128,code=0),reply=(src=fd20::2,dst=fd11::3,id=<cleared>,type=129,code=0),zone=<cleared>
>  ])
>
>  # We verify that SNAT indeed happened via 'dump-conntrack' command.
> @@ -3938,6 +3941,8 @@ NS_CHECK_EXEC([foo1], [ping -q -c 3 -i 0.3 -w 2
> 192.168.2.2 | FORMAT_PING], \
>  # We verify that the connection is not tracked.
>  AT_CHECK([ovs-appctl dpctl/dump-conntrack | grep icmp |
> FORMAT_CT(192.168.2.2) | \
>  sed -e 's/zone=[[0-9]]*/zone=<cleared>/'], [0], [dnl
>
> +icmp,orig=(src=192.168.1.2,dst=192.168.2.2,id=<cleared>,type=8,code=0),reply=(src=192.168.2.2,dst=192.168.1.2,id=<cleared>,type=0,code=0),zone=<cleared>
>
> +icmp,orig=(src=192.168.1.2,dst=192.168.2.2,id=<cleared>,type=8,code=0),reply=(src=192.168.2.2,dst=192.168.1.2,id=<cleared>,type=0,code=0),zone=<cleared>
>  ])
>
>  AT_CHECK([ovs-appctl dpctl/flush-conntrack])
> @@ -3950,6 +3955,8 @@ NS_CHECK_EXEC([foo2], [ping -q -c 3 -i 0.3 -w 2
> 192.168.2.2 | FORMAT_PING], \
>  # We verify that the connection is not tracked.
>  AT_CHECK([ovs-appctl dpctl/dump-conntrack | grep icmp |
> FORMAT_CT(192.168.2.2) | \
>  sed -e 's/zone=[[0-9]]*/zone=<cleared>/'], [0], [dnl
>
> +icmp,orig=(src=192.168.1.3,dst=192.168.2.2,id=<cleared>,type=8,code=0),reply=(src=192.168.2.2,dst=192.168.1.3,id=<cleared>,type=0,code=0),zone=<cleared>
>
> +icmp,orig=(src=192.168.1.3,dst=192.168.2.2,id=<cleared>,type=8,code=0),reply=(src=192.168.2.2,dst=192.168.1.3,id=<cleared>,type=0,code=0),zone=<cleared>
>  ])
>
>  AT_CHECK([ovs-appctl dpctl/flush-conntrack])
> @@ -3959,9 +3966,11 @@ NS_CHECK_EXEC([bar1], [ping -q -c 3 -i 0.3 -w 2
> 192.168.1.3 | FORMAT_PING], \
>  3 packets transmitted, 3 received, 0% packet loss, time 0ms
>  ])
>
> -# We verify that the connection is not tracked.
> +# We verify that the connection is tracked.
>  AT_CHECK([ovs-appctl dpctl/dump-conntrack | grep icmp |
> FORMAT_CT(192.168.2.2) | \
>  sed -e 's/zone=[[0-9]]*/zone=<cleared>/'], [0], [dnl
>
> +icmp,orig=(src=192.168.2.2,dst=192.168.1.3,id=<cleared>,type=8,code=0),reply=(src=192.168.1.3,dst=192.168.2.2,id=<cleared>,type=0,code=0),zone=<cleared>
>
> +icmp,orig=(src=192.168.2.2,dst=192.168.1.3,id=<cleared>,type=8,code=0),reply=(src=192.168.1.3,dst=192.168.2.2,id=<cleared>,type=0,code=0),zone=<cleared>
>  ])
>
>  AT_CHECK([ovs-appctl dpctl/flush-conntrack])
> @@ -3978,6 +3987,7 @@ AT_CHECK([ovs-appctl dpctl/dump-conntrack | grep
> icmp | FORMAT_CT(172.16.1.4) |
>  sed -e 's/zone=[[0-9]]*/zone=<cleared>/'], [0], [dnl
>
>  icmp,orig=(src=172.16.1.3,dst=172.16.1.4,id=<cleared>,type=8,code=0),reply=(src=192.168.2.2,dst=172.16.1.3,id=<cleared>,type=0,code=0),zone=<cleared>
>
>  icmp,orig=(src=192.168.1.2,dst=172.16.1.4,id=<cleared>,type=8,code=0),reply=(src=172.16.1.4,dst=172.16.1.3,id=<cleared>,type=0,code=0),zone=<cleared>
>
> +icmp,orig=(src=192.168.1.2,dst=172.16.1.4,id=<cleared>,type=8,code=0),reply=(src=172.16.1.4,dst=192.168.1.2,id=<cleared>,type=0,code=0),zone=<cleared>
>  ])
>
>  AT_CHECK([ovs-appctl dpctl/flush-conntrack])
> @@ -3993,7 +4003,6 @@ NS_CHECK_EXEC([foo2], [ping -q -c 3 -i 0.3 -w 2
> 172.16.1.4 | FORMAT_PING], \
>  AT_CHECK([ovs-appctl dpctl/dump-conntrack | grep icmp |
> FORMAT_CT(172.16.1.1) | \
>  sed -e 's/zone=[[0-9]]*/zone=<cleared>/'], [0], [dnl
>
>  icmp,orig=(src=172.16.1.1,dst=172.16.1.4,id=<cleared>,type=8,code=0),reply=(src=192.168.2.2,dst=172.16.1.1,id=<cleared>,type=0,code=0),zone=<cleared>
>
> -icmp,orig=(src=172.16.1.1,dst=192.168.2.2,id=<cleared>,type=8,code=0),reply=(src=192.168.2.2,dst=172.16.1.1,id=<cleared>,type=0,code=0),zone=<cleared>
>
>  icmp,orig=(src=192.168.1.3,dst=172.16.1.4,id=<cleared>,type=8,code=0),reply=(src=172.16.1.4,dst=172.16.1.1,id=<cleared>,type=0,code=0),zone=<cleared>
>  ])
>
> @@ -4144,6 +4153,7 @@ NS_CHECK_EXEC([foo1], [ping -q -c 3 -i 0.3 -w 2
> fd20::4 | FORMAT_PING], \
>  # Then DNAT of 'bar1' address happens (listed first below).
>  AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(fd20::4) | \
>  sed -e 's/zone=[[0-9]]*/zone=<cleared>/'], [0], [dnl
>
> +icmpv6,orig=(src=fd11::2,dst=fd20::4,id=<cleared>,type=128,code=0),reply=(src=fd20::4,dst=fd11::2,id=<cleared>,type=129,code=0),zone=<cleared>
>
>  icmpv6,orig=(src=fd11::2,dst=fd20::4,id=<cleared>,type=128,code=0),reply=(src=fd20::4,dst=fd20::3,id=<cleared>,type=129,code=0),zone=<cleared>
>
>  icmpv6,orig=(src=fd20::3,dst=fd20::4,id=<cleared>,type=128,code=0),reply=(src=fd12::2,dst=fd20::3,id=<cleared>,type=129,code=0),zone=<cleared>
>  ])
> @@ -4161,7 +4171,6 @@ NS_CHECK_EXEC([foo2], [ping -q -c 3 -i 0.3 -w 2
> fd20::4 | FORMAT_PING], \
>  AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(fd20::1) | \
>  sed -e 's/zone=[[0-9]]*/zone=<cleared>/'], [0], [dnl
>
>  icmpv6,orig=(src=fd11::3,dst=fd20::4,id=<cleared>,type=128,code=0),reply=(src=fd20::4,dst=fd20::1,id=<cleared>,type=129,code=0),zone=<cleared>
>
> -icmpv6,orig=(src=fd20::1,dst=fd12::2,id=<cleared>,type=128,code=0),reply=(src=fd12::2,dst=fd20::1,id=<cleared>,type=129,code=0),zone=<cleared>
>
>  icmpv6,orig=(src=fd20::1,dst=fd20::4,id=<cleared>,type=128,code=0),reply=(src=fd12::2,dst=fd20::1,id=<cleared>,type=129,code=0),zone=<cleared>
>  ])
>
> @@ -8682,10 +8691,10 @@ test_ping sw11 192.168.1.2
>  OVS_WAIT_UNTIL([ovs-ofctl dump-flows br-int | grep -v "n_packets=0" |
> grep 'nat(src=172.16.1.21)'])
>  # Ensure conntrack entry is present
>  OVS_WAIT_FOR_OUTPUT([
> -    ovs-appctl dpctl/dump-conntrack | FORMAT_CT(192.168.2.2) | \
> +    ovs-appctl dpctl/dump-conntrack | FORMAT_CT(192.168.1.2) | \
>        sed -e 's/zone=[[0-9]]*/zone=<cleared>/'], [0], [dnl
>
> -icmp,orig=(src=192.168.2.2,dst=192.168.1.2,id=<cleared>,type=8,code=0),reply=(src=192.168.1.2,dst=192.168.2.2,id=<cleared>,type=0,code=0),zone=<cleared>
>
> -tcp,orig=(src=192.168.2.2,dst=192.168.1.2,sport=<cleared>,dport=<cleared>),reply=(src=192.168.1.2,dst=192.168.2.2,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
>
> +icmp,orig=(src=192.168.2.2,dst=192.168.1.2,id=<cleared>,type=8,code=0),reply=(src=192.168.1.2,dst=172.16.1.21,id=<cleared>,type=0,code=0),zone=<cleared>
>
> +tcp,orig=(src=192.168.2.2,dst=192.168.1.2,sport=<cleared>,dport=<cleared>),reply=(src=192.168.1.2,dst=172.16.1.21,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
>  ])
>
>  AT_CHECK([ovs-appctl dpctl/flush-conntrack])
> @@ -8697,9 +8706,11 @@ test_ping sw11 192.168.1.2
>
>  # Ensure conntrack entry is present
>  OVS_WAIT_FOR_OUTPUT([
> -    ovs-appctl dpctl/dump-conntrack | FORMAT_CT(192.168.2.2) | \
> +    ovs-appctl dpctl/dump-conntrack | FORMAT_CT(192.168.1.2) | \
>        sed -e 's/zone=[[0-9]]*/zone=<cleared>/'], [0], [dnl
>
> +icmp,orig=(src=192.168.2.2,dst=192.168.1.2,id=<cleared>,type=8,code=0),reply=(src=192.168.1.2,dst=172.16.1.21,id=<cleared>,type=0,code=0),zone=<cleared>
>
>  icmp,orig=(src=192.168.2.2,dst=192.168.1.2,id=<cleared>,type=8,code=0),reply=(src=192.168.1.2,dst=192.168.2.2,id=<cleared>,type=0,code=0),zone=<cleared>
>
> +tcp,orig=(src=192.168.2.2,dst=192.168.1.2,sport=<cleared>,dport=<cleared>),reply=(src=192.168.1.2,dst=172.16.1.21,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
>
>  tcp,orig=(src=192.168.2.2,dst=192.168.1.2,sport=<cleared>,dport=<cleared>),reply=(src=192.168.1.2,dst=192.168.2.2,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
>  ])
>
> @@ -8711,10 +8722,10 @@ test_ping sw11 172.16.1.2
>
>  # Ensure conntrack entry is present
>  OVS_WAIT_FOR_OUTPUT([
> -    ovs-appctl dpctl/dump-conntrack | FORMAT_CT(192.168.2.2) | \
> +    ovs-appctl dpctl/dump-conntrack | FORMAT_CT(192.168.1.2) | \
>        sed -e 's/zone=[[0-9]]*/zone=<cleared>/'], [0], [dnl
>
> -icmp,orig=(src=192.168.2.2,dst=172.16.1.2,id=<cleared>,type=8,code=0),reply=(src=192.168.1.2,dst=192.168.2.2,id=<cleared>,type=0,code=0),zone=<cleared>
>
> -tcp,orig=(src=192.168.2.2,dst=172.16.1.2,sport=<cleared>,dport=<cleared>),reply=(src=192.168.1.2,dst=192.168.2.2,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
>
> +icmp,orig=(src=192.168.2.2,dst=192.168.1.2,id=<cleared>,type=8,code=0),reply=(src=192.168.1.2,dst=172.16.1.21,id=<cleared>,type=0,code=0),zone=<cleared>
>
> +tcp,orig=(src=192.168.2.2,dst=192.168.1.2,sport=<cleared>,dport=<cleared>),reply=(src=192.168.1.2,dst=172.16.1.21,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
>  ])
>
>  AT_CHECK([ovs-appctl dpctl/flush-conntrack])
> --
> 2.46.2
>
>
Forgot to CC Han.
diff mbox series

Patch

diff --git a/include/ovn/logical-fields.h b/include/ovn/logical-fields.h
index d6c4a9b6b..cc1f50ff2 100644
--- a/include/ovn/logical-fields.h
+++ b/include/ovn/logical-fields.h
@@ -82,6 +82,7 @@  enum mff_log_flags_bits {
     MLF_LOCALNET_BIT = 15,
     MLF_RX_FROM_TUNNEL_BIT = 16,
     MLF_ICMP_SNAT_BIT = 17,
+    MLF_WITHOUT_UNSNAT_BIT = 18,
 };
 
 /* MFF_LOG_FLAGS_REG flag assignments */
@@ -137,6 +138,9 @@  enum mff_log_flags {
     MLF_RX_FROM_TUNNEL = (1 << MLF_RX_FROM_TUNNEL_BIT),
 
     MLF_ICMP_SNAT = (1 << MLF_ICMP_SNAT_BIT),
+
+    /* Indicate that the packet didn't go through unSNAT. */
+    MLF_WITHOUT_UNSNAT = (1 << MLF_WITHOUT_UNSNAT_BIT),
 };
 
 /* OVN logical fields
diff --git a/lib/logical-fields.c b/lib/logical-fields.c
index 5a8b53f2b..c63e19897 100644
--- a/lib/logical-fields.c
+++ b/lib/logical-fields.c
@@ -139,6 +139,10 @@  ovn_init_symtab(struct shash *symtab)
                              flags_str);
     snprintf(flags_str, sizeof flags_str, "flags[%d]", MLF_RX_FROM_TUNNEL_BIT);
     expr_symtab_add_subfield(symtab, "flags.tunnel_rx", NULL, flags_str);
+    snprintf(flags_str, sizeof flags_str, "flags[%d]",
+             MLF_WITHOUT_UNSNAT_BIT);
+    expr_symtab_add_subfield(symtab, "flags.without_unsnat", NULL,
+                             flags_str);
 
     /* Connection tracking state. */
     expr_symtab_add_field_scoped(symtab, "ct_mark", MFF_CT_MARK, NULL, false,
diff --git a/northd/northd.c b/northd/northd.c
index 0364dd766..a42057e45 100644
--- a/northd/northd.c
+++ b/northd/northd.c
@@ -15987,8 +15987,7 @@  build_lrouter_out_snat_flow(struct lflow_table *lflows,
                             struct ds *actions, bool distributed_nat,
                             struct eth_addr mac, int cidr_bits, bool is_v6,
                             struct ovn_port *l3dgw_port,
-                            struct lflow_ref *lflow_ref,
-                            const struct chassis_features *features)
+                            struct lflow_ref *lflow_ref)
 {
     if (!(nat_entry->type == SNAT || nat_entry->type == DNAT_AND_SNAT)) {
         return;
@@ -16019,34 +16018,6 @@  build_lrouter_out_snat_flow(struct lflow_table *lflows,
                             priority, ds_cstr(match),
                             ds_cstr(actions), &nat->header_,
                             lflow_ref);
-
-    /* For the SNAT networks, we need to make sure that connections are
-     * properly tracked so we can decide whether to perform SNAT on traffic
-     * exiting the network. */
-    if (features->ct_commit_to_zone && features->ct_next_zone &&
-        nat_entry->type == SNAT && !od->is_gw_router) {
-        /* For traffic that comes from SNAT network, initiate CT state before
-         * entering S_ROUTER_OUT_SNAT to allow matching on various CT states.
-         */
-        ovn_lflow_add(lflows, od, S_ROUTER_OUT_POST_UNDNAT, 70,
-                      ds_cstr(match), "ct_next(snat);",
-                      lflow_ref);
-
-        build_lrouter_out_snat_match(lflows, od, nat, match,
-                                     distributed_nat, cidr_bits, is_v6,
-                                     l3dgw_port, lflow_ref, true);
-
-        /* New traffic that goes into SNAT network is committed to CT to avoid
-         * SNAT-ing replies.*/
-        ovn_lflow_add(lflows, od, S_ROUTER_OUT_SNAT, priority,
-                      ds_cstr(match), "ct_snat;",
-                      lflow_ref);
-
-        ds_put_cstr(match, " && ct.new");
-        ovn_lflow_add(lflows, od, S_ROUTER_OUT_POST_SNAT, priority,
-                      ds_cstr(match), "ct_commit_to_zone(snat);",
-                      lflow_ref);
-    }
 }
 
 static void
@@ -16439,9 +16410,6 @@  build_lrouter_nat_defrag_and_lb(
         ovn_lflow_add(lflows, od, S_ROUTER_OUT_UNDNAT, 50,
                       "ip", "flags.loopback = 1; ct_dnat;",
                       lflow_ref);
-        ovn_lflow_add(lflows, od, S_ROUTER_OUT_POST_UNDNAT, 50,
-                      "ip && ct.new", "ct_commit { } ; next; ",
-                      lflow_ref);
     }
 
     /* NAT rules are only valid on Gateway routers and routers with
@@ -16459,6 +16427,9 @@  build_lrouter_nat_defrag_and_lb(
         !lport_addresses_is_empty(&lrnat_rec->dnat_force_snat_addrs);
     bool lb_force_snat_ip =
         !lport_addresses_is_empty(&lrnat_rec->lb_force_snat_addrs);
+    bool stateful_dnat = lr_stateful_rec->has_lb_vip;
+    bool stateful_snat = (dnat_force_snat_ip || lb_force_snat_ip ||
+                          lrnat_rec->lb_force_snat_router_ip);
 
     for (size_t i = 0; i < lrnat_rec->n_nat_entries; i++) {
         struct ovn_nat *nat_entry = &lrnat_rec->nat_entries[i];
@@ -16477,6 +16448,21 @@  build_lrouter_nat_defrag_and_lb(
             continue;
         }
 
+        if (!stateless) {
+            switch (nat_entry->type) {
+            case DNAT:
+                stateful_dnat = true;
+                break;
+            case SNAT:
+                stateful_snat = true;
+                break;
+            case DNAT_AND_SNAT:
+                stateful_snat = true;
+                stateful_dnat = true;
+                break;
+            }
+        }
+
         /* S_ROUTER_IN_UNSNAT
          * Ingress UNSNAT table: It is for already established connections'
          * reverse traffic. i.e., SNAT has already been done in egress
@@ -16599,7 +16585,7 @@  build_lrouter_nat_defrag_and_lb(
         } else {
             build_lrouter_out_snat_flow(lflows, od, nat_entry, match, actions,
                                         distributed_nat, mac, cidr_bits, is_v6,
-                                        l3dgw_port, lflow_ref, features);
+                                        l3dgw_port, lflow_ref);
         }
 
         /* S_ROUTER_IN_ADMISSION - S_ROUTER_IN_IP_INPUT */
@@ -16689,6 +16675,28 @@  build_lrouter_nat_defrag_and_lb(
         }
     }
 
+
+    bool can_commit = features->ct_commit_to_zone && features->ct_next_zone;
+    if (can_commit && stateful_dnat) {
+        ovn_lflow_add(lflows, od, S_ROUTER_IN_DEFRAG, 10,
+                      "ip && (!ct.trk || !ct.rpl)",
+                      "ct_next(dnat);", lflow_ref);
+        ovn_lflow_add(lflows, od, S_ROUTER_IN_DNAT, 10,
+                      "ip && ct.new", "ct_commit_to_zone(dnat);", lflow_ref);
+    }
+
+    if (can_commit && stateful_snat) {
+        ovn_lflow_add(lflows, od, S_ROUTER_IN_UNSNAT, 10,
+                      "ip", "flags.without_unsnat = 1; next;", lflow_ref);
+        ovn_lflow_add(lflows, od, S_ROUTER_OUT_POST_UNDNAT, 10,
+                      "ip && (!ct.trk || !ct.rpl) && "
+                      "flags.without_unsnat == 1", "ct_next(snat);",
+                      lflow_ref);
+        ovn_lflow_add(lflows, od, S_ROUTER_OUT_SNAT, 10,
+                      "ip && ct.new && flags.without_unsnat == 1",
+                      "ct_commit_to_zone(snat);", lflow_ref);
+    }
+
     if (use_common_zone && od->nbr->n_nat) {
         ds_clear(match);
         ds_put_cstr(match, "ip && ct_mark.natted == 1");
diff --git a/tests/ovn-northd.at b/tests/ovn-northd.at
index d6a8c4640..96e28a54a 100644
--- a/tests/ovn-northd.at
+++ b/tests/ovn-northd.at
@@ -1181,18 +1181,18 @@  AT_CAPTURE_FILE([crflows])
 
 AT_CHECK([grep -e "lr_out_snat" drflows | ovn_strip_lflows], [0], [dnl
   table=??(lr_out_snat        ), priority=0    , match=(1), action=(next;)
+  table=??(lr_out_snat        ), priority=10   , match=(ip && ct.new && flags.without_unsnat == 1), action=(ct_commit_to_zone(snat);)
   table=??(lr_out_snat        ), priority=120  , match=(nd_ns), action=(next;)
-  table=??(lr_out_snat        ), priority=161  , match=(ip && ip4.dst == 50.0.0.11 && inport == "DR-S1" && is_chassis_resident("cr-DR-S1") && ip4.src == $allowed_range), action=(ct_snat;)
   table=??(lr_out_snat        ), priority=161  , match=(ip && ip4.src == 50.0.0.11 && outport == "DR-S1" && is_chassis_resident("cr-DR-S1") && ip4.dst == $allowed_range && (!ct.trk || !ct.rpl)), action=(ct_snat(172.16.1.1);)
 ])
 
 AT_CHECK([grep -e "lr_out_post_snat" drflows | ovn_strip_lflows], [0], [dnl
   table=??(lr_out_post_snat   ), priority=0    , match=(1), action=(next;)
-  table=??(lr_out_post_snat   ), priority=161  , match=(ip && ip4.dst == 50.0.0.11 && inport == "DR-S1" && is_chassis_resident("cr-DR-S1") && ip4.src == $allowed_range && ct.new), action=(ct_commit_to_zone(snat);)
 ])
 
 AT_CHECK([grep -e "lr_out_snat" crflows | ovn_strip_lflows], [0], [dnl
   table=??(lr_out_snat        ), priority=0    , match=(1), action=(next;)
+  table=??(lr_out_snat        ), priority=10   , match=(ip && ct.new && flags.without_unsnat == 1), action=(ct_commit_to_zone(snat);)
   table=??(lr_out_snat        ), priority=120  , match=(nd_ns), action=(next;)
   table=??(lr_out_snat        ), priority=33   , match=(ip && ip4.src == 50.0.0.11 && ip4.dst == $allowed_range && (!ct.trk || !ct.rpl)), action=(ct_snat(172.16.1.1);)
 ])
@@ -1220,19 +1220,19 @@  AT_CAPTURE_FILE([crflows2])
 
 AT_CHECK([grep -e "lr_out_snat" drflows2 | ovn_strip_lflows], [0], [dnl
   table=??(lr_out_snat        ), priority=0    , match=(1), action=(next;)
+  table=??(lr_out_snat        ), priority=10   , match=(ip && ct.new && flags.without_unsnat == 1), action=(ct_commit_to_zone(snat);)
   table=??(lr_out_snat        ), priority=120  , match=(nd_ns), action=(next;)
-  table=??(lr_out_snat        ), priority=161  , match=(ip && ip4.dst == 50.0.0.11 && inport == "DR-S1" && is_chassis_resident("cr-DR-S1")), action=(ct_snat;)
   table=??(lr_out_snat        ), priority=161  , match=(ip && ip4.src == 50.0.0.11 && outport == "DR-S1" && is_chassis_resident("cr-DR-S1") && (!ct.trk || !ct.rpl)), action=(ct_snat(172.16.1.1);)
   table=??(lr_out_snat        ), priority=163  , match=(ip && ip4.src == 50.0.0.11 && outport == "DR-S1" && is_chassis_resident("cr-DR-S1") && ip4.dst == $disallowed_range), action=(next;)
 ])
 
 AT_CHECK([grep -e "lr_out_post_snat" drflows2 | ovn_strip_lflows], [0], [dnl
   table=??(lr_out_post_snat   ), priority=0    , match=(1), action=(next;)
-  table=??(lr_out_post_snat   ), priority=161  , match=(ip && ip4.dst == 50.0.0.11 && inport == "DR-S1" && is_chassis_resident("cr-DR-S1") && ct.new), action=(ct_commit_to_zone(snat);)
 ])
 
 AT_CHECK([grep -e "lr_out_snat" crflows2 | ovn_strip_lflows], [0], [dnl
   table=??(lr_out_snat        ), priority=0    , match=(1), action=(next;)
+  table=??(lr_out_snat        ), priority=10   , match=(ip && ct.new && flags.without_unsnat == 1), action=(ct_commit_to_zone(snat);)
   table=??(lr_out_snat        ), priority=120  , match=(nd_ns), action=(next;)
   table=??(lr_out_snat        ), priority=33   , match=(ip && ip4.src == 50.0.0.11 && (!ct.trk || !ct.rpl)), action=(ct_snat(172.16.1.1);)
   table=??(lr_out_snat        ), priority=35   , match=(ip && ip4.src == 50.0.0.11 && ip4.dst == $disallowed_range), action=(next;)
@@ -1259,6 +1259,7 @@  AT_CAPTURE_FILE([crflows2])
 
 AT_CHECK([grep -e "lr_out_snat" drflows3 | ovn_strip_lflows], [0], [dnl
   table=??(lr_out_snat        ), priority=0    , match=(1), action=(next;)
+  table=??(lr_out_snat        ), priority=10   , match=(ip && ct.new && flags.without_unsnat == 1), action=(ct_commit_to_zone(snat);)
   table=??(lr_out_snat        ), priority=120  , match=(nd_ns), action=(next;)
   table=??(lr_out_snat        ), priority=161  , match=(ip && ip4.src == 50.0.0.11 && outport == "DR-S1" && is_chassis_resident("cr-DR-S1") && ip4.dst == $allowed_range && (!ct.trk || !ct.rpl)), action=(ct_snat(172.16.1.2);)
 ])
@@ -1269,6 +1270,7 @@  AT_CHECK([grep -e "lr_out_post_snat" drflows3 | ovn_strip_lflows], [0], [dnl
 
 AT_CHECK([grep -e "lr_out_snat" crflows3 | ovn_strip_lflows], [0], [dnl
   table=??(lr_out_snat        ), priority=0    , match=(1), action=(next;)
+  table=??(lr_out_snat        ), priority=10   , match=(ip && ct.new && flags.without_unsnat == 1), action=(ct_commit_to_zone(snat);)
   table=??(lr_out_snat        ), priority=120  , match=(nd_ns), action=(next;)
   table=??(lr_out_snat        ), priority=33   , match=(ip && ip4.src == 50.0.0.11 && ip4.dst == $allowed_range && (!ct.trk || !ct.rpl)), action=(ct_snat(172.16.1.2);)
 ])
@@ -1294,6 +1296,7 @@  AT_CAPTURE_FILE([crflows2])
 
 AT_CHECK([grep -e "lr_out_snat" drflows4 | ovn_strip_lflows], [0], [dnl
   table=??(lr_out_snat        ), priority=0    , match=(1), action=(next;)
+  table=??(lr_out_snat        ), priority=10   , match=(ip && ct.new && flags.without_unsnat == 1), action=(ct_commit_to_zone(snat);)
   table=??(lr_out_snat        ), priority=120  , match=(nd_ns), action=(next;)
   table=??(lr_out_snat        ), priority=161  , match=(ip && ip4.src == 50.0.0.11 && outport == "DR-S1" && is_chassis_resident("cr-DR-S1") && (!ct.trk || !ct.rpl)), action=(ct_snat(172.16.1.2);)
   table=??(lr_out_snat        ), priority=163  , match=(ip && ip4.src == 50.0.0.11 && outport == "DR-S1" && is_chassis_resident("cr-DR-S1") && ip4.dst == $disallowed_range), action=(next;)
@@ -1301,6 +1304,7 @@  AT_CHECK([grep -e "lr_out_snat" drflows4 | ovn_strip_lflows], [0], [dnl
 
 AT_CHECK([grep -e "lr_out_snat" crflows4 | ovn_strip_lflows], [0], [dnl
   table=??(lr_out_snat        ), priority=0    , match=(1), action=(next;)
+  table=??(lr_out_snat        ), priority=10   , match=(ip && ct.new && flags.without_unsnat == 1), action=(ct_commit_to_zone(snat);)
   table=??(lr_out_snat        ), priority=120  , match=(nd_ns), action=(next;)
   table=??(lr_out_snat        ), priority=33   , match=(ip && ip4.src == 50.0.0.11 && (!ct.trk || !ct.rpl)), action=(ct_snat(172.16.1.2);)
   table=??(lr_out_snat        ), priority=35   , match=(ip && ip4.src == 50.0.0.11 && ip4.dst == $disallowed_range), action=(next;)
@@ -1663,6 +1667,7 @@  AT_CAPTURE_FILE([sbflows])
 # dnat_and_snat or snat entry.
 AT_CHECK([grep "lr_in_unsnat" sbflows | ovn_strip_lflows], [0], [dnl
   table=??(lr_in_unsnat       ), priority=0    , match=(1), action=(next;)
+  table=??(lr_in_unsnat       ), priority=10   , match=(ip), action=(flags.without_unsnat = 1; next;)
   table=??(lr_in_unsnat       ), priority=90   , match=(ip && ip4.dst == 192.168.2.1), action=(ct_snat;)
   table=??(lr_in_unsnat       ), priority=90   , match=(ip && ip4.dst == 192.168.2.4), action=(ct_snat;)
 ])
@@ -1693,6 +1698,7 @@  AT_CAPTURE_FILE([sbflows])
 # dnat_and_snat or snat entry.
 AT_CHECK([grep "lr_in_unsnat" sbflows | ovn_strip_lflows], [0], [dnl
   table=??(lr_in_unsnat       ), priority=0    , match=(1), action=(next;)
+  table=??(lr_in_unsnat       ), priority=10   , match=(ip), action=(flags.without_unsnat = 1; next;)
   table=??(lr_in_unsnat       ), priority=90   , match=(ip && ip4.dst == 192.168.2.1), action=(ct_snat;)
   table=??(lr_in_unsnat       ), priority=90   , match=(ip && ip4.dst == 192.168.2.4), action=(ct_snat;)
 ])
@@ -1801,6 +1807,7 @@  ovn-nbctl --wait=sb sync
 
 AT_CHECK([ovn-sbctl lflow-list lr0 | grep lr_in_unsnat | ovn_strip_lflows], [0], [dnl
   table=??(lr_in_unsnat       ), priority=0    , match=(1), action=(next;)
+  table=??(lr_in_unsnat       ), priority=10   , match=(ip), action=(flags.without_unsnat = 1; next;)
   table=??(lr_in_unsnat       ), priority=110  , match=(ip4 && ip4.dst == 192.168.2.3), action=(ct_snat;)
 ])
 
@@ -4277,12 +4284,14 @@  AT_CHECK([grep "lr_in_unsnat" lr0flows | ovn_strip_lflows], [0], [dnl
 
 AT_CHECK([grep "lr_in_defrag" lr0flows | ovn_strip_lflows], [0], [dnl
   table=??(lr_in_defrag       ), priority=0    , match=(1), action=(next;)
+  table=??(lr_in_defrag       ), priority=10   , match=(ip && (!ct.trk || !ct.rpl)), action=(ct_next(dnat);)
   table=??(lr_in_defrag       ), priority=100  , match=(ip && ip4.dst == 10.0.0.10), action=(ct_dnat;)
   table=??(lr_in_defrag       ), priority=100  , match=(ip && ip4.dst == 10.0.0.100), action=(ct_dnat;)
 ])
 
 AT_CHECK([grep "lr_in_dnat" lr0flows | ovn_strip_lflows], [0], [dnl
   table=??(lr_in_dnat         ), priority=0    , match=(1), action=(next;)
+  table=??(lr_in_dnat         ), priority=10   , match=(ip && ct.new), action=(ct_commit_to_zone(dnat);)
   table=??(lr_in_dnat         ), priority=120  , match=(ct.new && !ct.rel && ip4 && ip4.dst == 10.0.0.10 && tcp && tcp.dst == 80), action=(ct_lb_mark(backends=10.0.0.4:8080);)
   table=??(lr_in_dnat         ), priority=120  , match=(ct.new && !ct.rel && ip4 && ip4.dst == 10.0.0.100 && tcp && tcp.dst == 80), action=(ct_lb_mark(backends=10.0.0.40:8080);)
   table=??(lr_in_dnat         ), priority=50   , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted), action=(next;)
@@ -4302,18 +4311,21 @@  AT_CAPTURE_FILE([lr0flows])
 
 AT_CHECK([grep "lr_in_unsnat" lr0flows | ovn_strip_lflows], [0], [dnl
   table=??(lr_in_unsnat       ), priority=0    , match=(1), action=(next;)
+  table=??(lr_in_unsnat       ), priority=10   , match=(ip), action=(flags.without_unsnat = 1; next;)
   table=??(lr_in_unsnat       ), priority=110  , match=(ip4 && ip4.dst == 20.0.0.4), action=(ct_snat;)
   table=??(lr_in_unsnat       ), priority=110  , match=(ip6 && ip6.dst == aef0::4), action=(ct_snat;)
 ])
 
 AT_CHECK([grep "lr_in_defrag" lr0flows | ovn_strip_lflows], [0], [dnl
   table=??(lr_in_defrag       ), priority=0    , match=(1), action=(next;)
+  table=??(lr_in_defrag       ), priority=10   , match=(ip && (!ct.trk || !ct.rpl)), action=(ct_next(dnat);)
   table=??(lr_in_defrag       ), priority=100  , match=(ip && ip4.dst == 10.0.0.10), action=(ct_dnat;)
   table=??(lr_in_defrag       ), priority=100  , match=(ip && ip4.dst == 10.0.0.100), action=(ct_dnat;)
 ])
 
 AT_CHECK([grep "lr_in_dnat" lr0flows | ovn_strip_lflows], [0], [dnl
   table=??(lr_in_dnat         ), priority=0    , match=(1), action=(next;)
+  table=??(lr_in_dnat         ), priority=10   , match=(ip && ct.new), action=(ct_commit_to_zone(dnat);)
   table=??(lr_in_dnat         ), priority=120  , match=(ct.new && !ct.rel && ip4 && ip4.dst == 10.0.0.10 && tcp && tcp.dst == 80), action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.4:8080; force_snat);)
   table=??(lr_in_dnat         ), priority=120  , match=(ct.new && !ct.rel && ip4 && ip4.dst == 10.0.0.100 && tcp && tcp.dst == 80), action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.40:8080; force_snat);)
   table=??(lr_in_dnat         ), priority=50   , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted), action=(next;)
@@ -4326,6 +4338,7 @@  AT_CHECK([grep "lr_in_dnat" lr0flows | ovn_strip_lflows], [0], [dnl
 
 AT_CHECK([grep "lr_out_snat" lr0flows | ovn_strip_lflows], [0], [dnl
   table=??(lr_out_snat        ), priority=0    , match=(1), action=(next;)
+  table=??(lr_out_snat        ), priority=10   , match=(ip && ct.new && flags.without_unsnat == 1), action=(ct_commit_to_zone(snat);)
   table=??(lr_out_snat        ), priority=100  , match=(flags.force_snat_for_lb == 1 && ip4), action=(ct_snat(20.0.0.4);)
   table=??(lr_out_snat        ), priority=100  , match=(flags.force_snat_for_lb == 1 && ip6), action=(ct_snat(aef0::4);)
   table=??(lr_out_snat        ), priority=120  , match=(nd_ns), action=(next;)
@@ -4339,7 +4352,7 @@  AT_CHECK([grep "lr_out_undnat" lr0flows | ovn_strip_lflows], [0], [dnl
 
 AT_CHECK([grep "lr_out_post_undnat" lr0flows | ovn_strip_lflows], [0], [dnl
   table=??(lr_out_post_undnat ), priority=0    , match=(1), action=(next;)
-  table=??(lr_out_post_undnat ), priority=50   , match=(ip && ct.new), action=(ct_commit { } ; next; )
+  table=??(lr_out_post_undnat ), priority=10   , match=(ip && (!ct.trk || !ct.rpl) && flags.without_unsnat == 1), action=(ct_next(snat);)
 ])
 
 check ovn-nbctl --wait=sb set logical_router lr0 options:lb_force_snat_ip="router_ip"
@@ -4352,6 +4365,7 @@  AT_CHECK([grep "lr_in_ip_input" lr0flows | grep "priority=60" | sort], [0], [dnl
 
 AT_CHECK([grep "lr_in_unsnat" lr0flows | ovn_strip_lflows], [0], [dnl
   table=??(lr_in_unsnat       ), priority=0    , match=(1), action=(next;)
+  table=??(lr_in_unsnat       ), priority=10   , match=(ip), action=(flags.without_unsnat = 1; next;)
   table=??(lr_in_unsnat       ), priority=110  , match=(inport == "lr0-public" && ip4.dst == 172.168.0.100), action=(ct_snat;)
   table=??(lr_in_unsnat       ), priority=110  , match=(inport == "lr0-sw0" && ip4.dst == 10.0.0.1), action=(ct_snat;)
   table=??(lr_in_unsnat       ), priority=110  , match=(inport == "lr0-sw1" && ip4.dst == 20.0.0.1), action=(ct_snat;)
@@ -4359,12 +4373,14 @@  AT_CHECK([grep "lr_in_unsnat" lr0flows | ovn_strip_lflows], [0], [dnl
 
 AT_CHECK([grep "lr_in_defrag" lr0flows | ovn_strip_lflows], [0], [dnl
   table=??(lr_in_defrag       ), priority=0    , match=(1), action=(next;)
+  table=??(lr_in_defrag       ), priority=10   , match=(ip && (!ct.trk || !ct.rpl)), action=(ct_next(dnat);)
   table=??(lr_in_defrag       ), priority=100  , match=(ip && ip4.dst == 10.0.0.10), action=(ct_dnat;)
   table=??(lr_in_defrag       ), priority=100  , match=(ip && ip4.dst == 10.0.0.100), action=(ct_dnat;)
 ])
 
 AT_CHECK([grep "lr_in_dnat" lr0flows | ovn_strip_lflows], [0], [dnl
   table=??(lr_in_dnat         ), priority=0    , match=(1), action=(next;)
+  table=??(lr_in_dnat         ), priority=10   , match=(ip && ct.new), action=(ct_commit_to_zone(dnat);)
   table=??(lr_in_dnat         ), priority=120  , match=(ct.new && !ct.rel && ip4 && ip4.dst == 10.0.0.10 && tcp && tcp.dst == 80), action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.4:8080; force_snat);)
   table=??(lr_in_dnat         ), priority=120  , match=(ct.new && !ct.rel && ip4 && ip4.dst == 10.0.0.100 && tcp && tcp.dst == 80), action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.40:8080; force_snat);)
   table=??(lr_in_dnat         ), priority=50   , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted), action=(next;)
@@ -4377,6 +4393,7 @@  AT_CHECK([grep "lr_in_dnat" lr0flows | ovn_strip_lflows], [0], [dnl
 
 AT_CHECK([grep "lr_out_snat" lr0flows | ovn_strip_lflows], [0], [dnl
   table=??(lr_out_snat        ), priority=0    , match=(1), action=(next;)
+  table=??(lr_out_snat        ), priority=10   , match=(ip && ct.new && flags.without_unsnat == 1), action=(ct_commit_to_zone(snat);)
   table=??(lr_out_snat        ), priority=110  , match=(flags.force_snat_for_lb == 1 && ip4 && outport == "lr0-public"), action=(ct_snat(172.168.0.100);)
   table=??(lr_out_snat        ), priority=110  , match=(flags.force_snat_for_lb == 1 && ip4 && outport == "lr0-sw0"), action=(ct_snat(10.0.0.1);)
   table=??(lr_out_snat        ), priority=110  , match=(flags.force_snat_for_lb == 1 && ip4 && outport == "lr0-sw1"), action=(ct_snat(20.0.0.1);)
@@ -4391,7 +4408,7 @@  AT_CHECK([grep "lr_out_undnat" lr0flows | ovn_strip_lflows], [0], [dnl
 
 AT_CHECK([grep "lr_out_post_undnat" lr0flows | ovn_strip_lflows], [0], [dnl
   table=??(lr_out_post_undnat ), priority=0    , match=(1), action=(next;)
-  table=??(lr_out_post_undnat ), priority=50   , match=(ip && ct.new), action=(ct_commit { } ; next; )
+  table=??(lr_out_post_undnat ), priority=10   , match=(ip && (!ct.trk || !ct.rpl) && flags.without_unsnat == 1), action=(ct_next(snat);)
 ])
 
 check ovn-nbctl --wait=sb remove logical_router lr0 options chassis
@@ -4416,6 +4433,7 @@  AT_CAPTURE_FILE([lr0flows])
 
 AT_CHECK([grep "lr_in_unsnat" lr0flows | ovn_strip_lflows], [0], [dnl
   table=??(lr_in_unsnat       ), priority=0    , match=(1), action=(next;)
+  table=??(lr_in_unsnat       ), priority=10   , match=(ip), action=(flags.without_unsnat = 1; next;)
   table=??(lr_in_unsnat       ), priority=110  , match=(inport == "lr0-public" && ip4.dst == 172.168.0.100), action=(ct_snat;)
   table=??(lr_in_unsnat       ), priority=110  , match=(inport == "lr0-sw0" && ip4.dst == 10.0.0.1), action=(ct_snat;)
   table=??(lr_in_unsnat       ), priority=110  , match=(inport == "lr0-sw1" && ip4.dst == 20.0.0.1), action=(ct_snat;)
@@ -4424,12 +4442,14 @@  AT_CHECK([grep "lr_in_unsnat" lr0flows | ovn_strip_lflows], [0], [dnl
 
 AT_CHECK([grep "lr_in_defrag" lr0flows | ovn_strip_lflows], [0], [dnl
   table=??(lr_in_defrag       ), priority=0    , match=(1), action=(next;)
+  table=??(lr_in_defrag       ), priority=10   , match=(ip && (!ct.trk || !ct.rpl)), action=(ct_next(dnat);)
   table=??(lr_in_defrag       ), priority=100  , match=(ip && ip4.dst == 10.0.0.10), action=(ct_dnat;)
   table=??(lr_in_defrag       ), priority=100  , match=(ip && ip4.dst == 10.0.0.100), action=(ct_dnat;)
 ])
 
 AT_CHECK([grep "lr_in_dnat" lr0flows | ovn_strip_lflows], [0], [dnl
   table=??(lr_in_dnat         ), priority=0    , match=(1), action=(next;)
+  table=??(lr_in_dnat         ), priority=10   , match=(ip && ct.new), action=(ct_commit_to_zone(dnat);)
   table=??(lr_in_dnat         ), priority=120  , match=(ct.new && !ct.rel && ip4 && ip4.dst == 10.0.0.10 && tcp && tcp.dst == 80), action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.4:8080; force_snat);)
   table=??(lr_in_dnat         ), priority=120  , match=(ct.new && !ct.rel && ip4 && ip4.dst == 10.0.0.100 && tcp && tcp.dst == 80), action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.40:8080; force_snat);)
   table=??(lr_in_dnat         ), priority=50   , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted), action=(next;)
@@ -4442,6 +4462,7 @@  AT_CHECK([grep "lr_in_dnat" lr0flows | ovn_strip_lflows], [0], [dnl
 
 AT_CHECK([grep "lr_out_snat" lr0flows | ovn_strip_lflows], [0], [dnl
   table=??(lr_out_snat        ), priority=0    , match=(1), action=(next;)
+  table=??(lr_out_snat        ), priority=10   , match=(ip && ct.new && flags.without_unsnat == 1), action=(ct_commit_to_zone(snat);)
   table=??(lr_out_snat        ), priority=110  , match=(flags.force_snat_for_lb == 1 && ip4 && outport == "lr0-public"), action=(ct_snat(172.168.0.100);)
   table=??(lr_out_snat        ), priority=110  , match=(flags.force_snat_for_lb == 1 && ip4 && outport == "lr0-sw0"), action=(ct_snat(10.0.0.1);)
   table=??(lr_out_snat        ), priority=110  , match=(flags.force_snat_for_lb == 1 && ip4 && outport == "lr0-sw1"), action=(ct_snat(20.0.0.1);)
@@ -4457,7 +4478,7 @@  AT_CHECK([grep "lr_out_undnat" lr0flows | ovn_strip_lflows], [0], [dnl
 
 AT_CHECK([grep "lr_out_post_undnat" lr0flows | ovn_strip_lflows], [0], [dnl
   table=??(lr_out_post_undnat ), priority=0    , match=(1), action=(next;)
-  table=??(lr_out_post_undnat ), priority=50   , match=(ip && ct.new), action=(ct_commit { } ; next; )
+  table=??(lr_out_post_undnat ), priority=10   , match=(ip && (!ct.trk || !ct.rpl) && flags.without_unsnat == 1), action=(ct_next(snat);)
 ])
 
 check ovn-nbctl --wait=sb lb-add lb2 10.0.0.20:80 10.0.0.40:8080
@@ -4468,6 +4489,7 @@  ovn-sbctl dump-flows lr0 > lr0flows
 
 AT_CHECK([grep "lr_in_unsnat" lr0flows | ovn_strip_lflows], [0], [dnl
   table=??(lr_in_unsnat       ), priority=0    , match=(1), action=(next;)
+  table=??(lr_in_unsnat       ), priority=10   , match=(ip), action=(flags.without_unsnat = 1; next;)
   table=??(lr_in_unsnat       ), priority=110  , match=(inport == "lr0-public" && ip4.dst == 172.168.0.100), action=(ct_snat;)
   table=??(lr_in_unsnat       ), priority=110  , match=(inport == "lr0-sw0" && ip4.dst == 10.0.0.1), action=(ct_snat;)
   table=??(lr_in_unsnat       ), priority=110  , match=(inport == "lr0-sw1" && ip4.dst == 20.0.0.1), action=(ct_snat;)
@@ -4476,6 +4498,7 @@  AT_CHECK([grep "lr_in_unsnat" lr0flows | ovn_strip_lflows], [0], [dnl
 
 AT_CHECK([grep "lr_in_defrag" lr0flows | ovn_strip_lflows], [0], [dnl
   table=??(lr_in_defrag       ), priority=0    , match=(1), action=(next;)
+  table=??(lr_in_defrag       ), priority=10   , match=(ip && (!ct.trk || !ct.rpl)), action=(ct_next(dnat);)
   table=??(lr_in_defrag       ), priority=100  , match=(ip && ip4.dst == 10.0.0.100), action=(ct_dnat;)
   table=??(lr_in_defrag       ), priority=100  , match=(ip && ip4.dst == 10.0.0.20), action=(ct_dnat;)
 ])
@@ -4498,7 +4521,7 @@  AT_CHECK([grep "lr_out_undnat" lr0flows | ovn_strip_lflows], [0], [dnl
 
 AT_CHECK([grep "lr_out_post_undnat" lr0flows | ovn_strip_lflows], [0], [dnl
   table=??(lr_out_post_undnat ), priority=0    , match=(1), action=(next;)
-  table=??(lr_out_post_undnat ), priority=50   , match=(ip && ct.new), action=(ct_commit { } ; next; )
+  table=??(lr_out_post_undnat ), priority=10   , match=(ip && (!ct.trk || !ct.rpl) && flags.without_unsnat == 1), action=(ct_next(snat);)
 ])
 
 AT_CLEANUP
@@ -5744,6 +5767,7 @@  AT_CAPTURE_FILE([lr0flows])
 
 AT_CHECK([grep "lr_in_unsnat" lr0flows | ovn_strip_lflows], [0], [dnl
   table=??(lr_in_unsnat       ), priority=0    , match=(1), action=(next;)
+  table=??(lr_in_unsnat       ), priority=10   , match=(ip), action=(flags.without_unsnat = 1; next;)
   table=??(lr_in_unsnat       ), priority=100  , match=(ip && ip4.dst == 172.168.0.10 && inport == "lr0-public" && is_chassis_resident("cr-lr0-public") && flags.loopback == 0), action=(ct_snat_in_czone;)
   table=??(lr_in_unsnat       ), priority=100  , match=(ip && ip4.dst == 172.168.0.10 && inport == "lr0-public" && is_chassis_resident("cr-lr0-public") && flags.loopback == 1 && flags.use_snat_zone == 1), action=(ct_snat;)
   table=??(lr_in_unsnat       ), priority=100  , match=(ip && ip4.dst == 172.168.0.20 && inport == "lr0-public" && is_chassis_resident("cr-lr0-public") && flags.loopback == 0), action=(ct_snat_in_czone;)
@@ -5754,10 +5778,12 @@  AT_CHECK([grep "lr_in_unsnat" lr0flows | ovn_strip_lflows], [0], [dnl
 
 AT_CHECK([grep "lr_in_defrag" lr0flows | ovn_strip_lflows], [0], [dnl
   table=??(lr_in_defrag       ), priority=0    , match=(1), action=(next;)
+  table=??(lr_in_defrag       ), priority=10   , match=(ip && (!ct.trk || !ct.rpl)), action=(ct_next(dnat);)
 ])
 
 AT_CHECK([grep "lr_in_dnat" lr0flows | ovn_strip_lflows], [0], [dnl
   table=??(lr_in_dnat         ), priority=0    , match=(1), action=(next;)
+  table=??(lr_in_dnat         ), priority=10   , match=(ip && ct.new), action=(ct_commit_to_zone(dnat);)
   table=??(lr_in_dnat         ), priority=100  , match=(ip && ip4.dst == 172.168.0.20 && inport == "lr0-public" && is_chassis_resident("cr-lr0-public")), action=(ct_dnat_in_czone(10.0.0.3);)
 ])
 
@@ -5776,10 +5802,12 @@  AT_CHECK([grep "lr_out_undnat" lr0flows | ovn_strip_lflows], [0], [dnl
 
 AT_CHECK([grep "lr_out_post_undnat" lr0flows | ovn_strip_lflows], [0], [dnl
   table=??(lr_out_post_undnat ), priority=0    , match=(1), action=(next;)
+  table=??(lr_out_post_undnat ), priority=10   , match=(ip && (!ct.trk || !ct.rpl) && flags.without_unsnat == 1), action=(ct_next(snat);)
 ])
 
 AT_CHECK([grep "lr_out_snat" lr0flows | ovn_strip_lflows], [0], [dnl
   table=??(lr_out_snat        ), priority=0    , match=(1), action=(next;)
+  table=??(lr_out_snat        ), priority=10   , match=(ip && ct.new && flags.without_unsnat == 1), action=(ct_commit_to_zone(snat);)
   table=??(lr_out_snat        ), priority=120  , match=(nd_ns), action=(next;)
   table=??(lr_out_snat        ), priority=153  , match=(ip && ip4.src == 10.0.0.0/24 && outport == "lr0-public" && is_chassis_resident("cr-lr0-public") && (!ct.trk || !ct.rpl)), action=(ct_snat_in_czone(172.168.0.10);)
   table=??(lr_out_snat        ), priority=154  , match=(ip && ip4.src == 10.0.0.0/24 && outport == "lr0-public" && is_chassis_resident("cr-lr0-public") && (!ct.trk || !ct.rpl) && reg9[[4]] == 1), action=(reg9[[4]] = 0; ct_snat(172.168.0.10);)
@@ -5799,6 +5827,7 @@  AT_CAPTURE_FILE([lr0flows])
 
 AT_CHECK([grep "lr_in_unsnat" lr0flows | ovn_strip_lflows], [0], [dnl
   table=??(lr_in_unsnat       ), priority=0    , match=(1), action=(next;)
+  table=??(lr_in_unsnat       ), priority=10   , match=(ip), action=(flags.without_unsnat = 1; next;)
   table=??(lr_in_unsnat       ), priority=100  , match=(ip && ip4.dst == 172.168.0.10 && inport == "lr0-public" && is_chassis_resident("cr-lr0-public")), action=(ct_snat;)
   table=??(lr_in_unsnat       ), priority=100  , match=(ip && ip4.dst == 172.168.0.20 && inport == "lr0-public" && is_chassis_resident("cr-lr0-public")), action=(ct_snat;)
   table=??(lr_in_unsnat       ), priority=100  , match=(ip && ip4.dst == 172.168.0.30 && inport == "lr0-public" && is_chassis_resident("cr-lr0-public")), action=(ct_snat;)
@@ -5806,10 +5835,12 @@  AT_CHECK([grep "lr_in_unsnat" lr0flows | ovn_strip_lflows], [0], [dnl
 
 AT_CHECK([grep "lr_in_defrag" lr0flows | ovn_strip_lflows], [0], [dnl
   table=??(lr_in_defrag       ), priority=0    , match=(1), action=(next;)
+  table=??(lr_in_defrag       ), priority=10   , match=(ip && (!ct.trk || !ct.rpl)), action=(ct_next(dnat);)
 ])
 
 AT_CHECK([grep "lr_in_dnat" lr0flows | ovn_strip_lflows], [0], [dnl
   table=??(lr_in_dnat         ), priority=0    , match=(1), action=(next;)
+  table=??(lr_in_dnat         ), priority=10   , match=(ip && ct.new), action=(ct_commit_to_zone(dnat);)
   table=??(lr_in_dnat         ), priority=100  , match=(ip && ip4.dst == 172.168.0.20 && inport == "lr0-public" && is_chassis_resident("cr-lr0-public")), action=(ct_dnat(10.0.0.3);)
 ])
 
@@ -5824,24 +5855,20 @@  AT_CHECK([grep "lr_out_undnat" lr0flows | ovn_strip_lflows], [0], [dnl
 
 AT_CHECK([grep "lr_out_post_undnat" lr0flows | ovn_strip_lflows], [0], [dnl
   table=??(lr_out_post_undnat ), priority=0    , match=(1), action=(next;)
-  table=??(lr_out_post_undnat ), priority=70   , match=(ip && ip4.src == 10.0.0.0/24 && outport == "lr0-public" && is_chassis_resident("cr-lr0-public") && (!ct.trk || !ct.rpl)), action=(ct_next(snat);)
-  table=??(lr_out_post_undnat ), priority=70   , match=(ip && ip4.src == 10.0.0.10 && outport == "lr0-public" && is_chassis_resident("cr-lr0-public") && (!ct.trk || !ct.rpl)), action=(ct_next(snat);)
+  table=??(lr_out_post_undnat ), priority=10   , match=(ip && (!ct.trk || !ct.rpl) && flags.without_unsnat == 1), action=(ct_next(snat);)
 ])
 
 AT_CHECK([grep "lr_out_snat" lr0flows | ovn_strip_lflows], [0], [dnl
   table=??(lr_out_snat        ), priority=0    , match=(1), action=(next;)
+  table=??(lr_out_snat        ), priority=10   , match=(ip && ct.new && flags.without_unsnat == 1), action=(ct_commit_to_zone(snat);)
   table=??(lr_out_snat        ), priority=120  , match=(nd_ns), action=(next;)
-  table=??(lr_out_snat        ), priority=153  , match=(ip && ip4.dst == 10.0.0.0/24 && inport == "lr0-public" && is_chassis_resident("cr-lr0-public")), action=(ct_snat;)
   table=??(lr_out_snat        ), priority=153  , match=(ip && ip4.src == 10.0.0.0/24 && outport == "lr0-public" && is_chassis_resident("cr-lr0-public") && (!ct.trk || !ct.rpl)), action=(ct_snat(172.168.0.10);)
-  table=??(lr_out_snat        ), priority=161  , match=(ip && ip4.dst == 10.0.0.10 && inport == "lr0-public" && is_chassis_resident("cr-lr0-public")), action=(ct_snat;)
   table=??(lr_out_snat        ), priority=161  , match=(ip && ip4.src == 10.0.0.10 && outport == "lr0-public" && is_chassis_resident("cr-lr0-public") && (!ct.trk || !ct.rpl)), action=(ct_snat(172.168.0.30);)
   table=??(lr_out_snat        ), priority=161  , match=(ip && ip4.src == 10.0.0.3 && outport == "lr0-public" && is_chassis_resident("cr-lr0-public") && (!ct.trk || !ct.rpl)), action=(ct_snat(172.168.0.20);)
 ])
 
 AT_CHECK([grep "lr_out_post_snat" lr0flows | ovn_strip_lflows], [0], [dnl
   table=??(lr_out_post_snat   ), priority=0    , match=(1), action=(next;)
-  table=??(lr_out_post_snat   ), priority=153  , match=(ip && ip4.dst == 10.0.0.0/24 && inport == "lr0-public" && is_chassis_resident("cr-lr0-public") && ct.new), action=(ct_commit_to_zone(snat);)
-  table=??(lr_out_post_snat   ), priority=161  , match=(ip && ip4.dst == 10.0.0.10 && inport == "lr0-public" && is_chassis_resident("cr-lr0-public") && ct.new), action=(ct_commit_to_zone(snat);)
 ])
 
 # Associate load balancer to lr0
@@ -5866,6 +5893,7 @@  AT_CAPTURE_FILE([lr0flows])
 
 AT_CHECK([grep "lr_in_unsnat" lr0flows | ovn_strip_lflows], [0], [dnl
   table=??(lr_in_unsnat       ), priority=0    , match=(1), action=(next;)
+  table=??(lr_in_unsnat       ), priority=10   , match=(ip), action=(flags.without_unsnat = 1; next;)
   table=??(lr_in_unsnat       ), priority=100  , match=(ip && ip4.dst == 172.168.0.10 && inport == "lr0-public" && is_chassis_resident("cr-lr0-public") && flags.loopback == 0), action=(ct_snat_in_czone;)
   table=??(lr_in_unsnat       ), priority=100  , match=(ip && ip4.dst == 172.168.0.10 && inport == "lr0-public" && is_chassis_resident("cr-lr0-public") && flags.loopback == 1 && flags.use_snat_zone == 1), action=(ct_snat;)
   table=??(lr_in_unsnat       ), priority=100  , match=(ip && ip4.dst == 172.168.0.20 && inport == "lr0-public" && is_chassis_resident("cr-lr0-public") && flags.loopback == 0), action=(ct_snat_in_czone;)
@@ -5876,6 +5904,7 @@  AT_CHECK([grep "lr_in_unsnat" lr0flows | ovn_strip_lflows], [0], [dnl
 
 AT_CHECK([grep "lr_in_defrag" lr0flows | ovn_strip_lflows], [0], [dnl
   table=??(lr_in_defrag       ), priority=0    , match=(1), action=(next;)
+  table=??(lr_in_defrag       ), priority=10   , match=(ip && (!ct.trk || !ct.rpl)), action=(ct_next(dnat);)
   table=??(lr_in_defrag       ), priority=100  , match=(ip && ip4.dst == 10.0.0.10), action=(ct_dnat;)
   table=??(lr_in_defrag       ), priority=100  , match=(ip && ip4.dst == 172.168.0.100), action=(ct_dnat;)
   table=??(lr_in_defrag       ), priority=100  , match=(ip && ip4.dst == 172.168.0.200), action=(ct_dnat;)
@@ -5884,6 +5913,7 @@  AT_CHECK([grep "lr_in_defrag" lr0flows | ovn_strip_lflows], [0], [dnl
 
 AT_CHECK([grep "lr_in_dnat" lr0flows | ovn_strip_lflows], [0], [dnl
   table=??(lr_in_dnat         ), priority=0    , match=(1), action=(next;)
+  table=??(lr_in_dnat         ), priority=10   , match=(ip && ct.new), action=(ct_commit_to_zone(dnat);)
   table=??(lr_in_dnat         ), priority=100  , match=(ip && ip4.dst == 172.168.0.20 && inport == "lr0-public" && is_chassis_resident("cr-lr0-public")), action=(ct_dnat_in_czone(10.0.0.3);)
   table=??(lr_in_dnat         ), priority=110  , match=(ct.new && !ct.rel && ip4 && ip4.dst == 172.168.0.200 && is_chassis_resident("cr-lr0-public")), action=(ct_lb_mark(backends=10.0.0.80,10.0.0.81);)
   table=??(lr_in_dnat         ), priority=120  , match=(ct.new && !ct.rel && ip4 && ip4.dst == 10.0.0.10 && tcp && tcp.dst == 80 && is_chassis_resident("cr-lr0-public")), action=(ct_lb_mark(backends=10.0.0.4:8080);)
@@ -5916,10 +5946,12 @@  AT_CHECK([grep "lr_out_undnat" lr0flows | ovn_strip_lflows], [0], [dnl
 
 AT_CHECK([grep "lr_out_post_undnat" lr0flows | ovn_strip_lflows], [0], [dnl
   table=??(lr_out_post_undnat ), priority=0    , match=(1), action=(next;)
+  table=??(lr_out_post_undnat ), priority=10   , match=(ip && (!ct.trk || !ct.rpl) && flags.without_unsnat == 1), action=(ct_next(snat);)
 ])
 
 AT_CHECK([grep "lr_out_snat" lr0flows | ovn_strip_lflows], [0], [dnl
   table=??(lr_out_snat        ), priority=0    , match=(1), action=(next;)
+  table=??(lr_out_snat        ), priority=10   , match=(ip && ct.new && flags.without_unsnat == 1), action=(ct_commit_to_zone(snat);)
   table=??(lr_out_snat        ), priority=120  , match=(nd_ns), action=(next;)
   table=??(lr_out_snat        ), priority=153  , match=(ip && ip4.src == 10.0.0.0/24 && outport == "lr0-public" && is_chassis_resident("cr-lr0-public") && (!ct.trk || !ct.rpl)), action=(ct_snat_in_czone(172.168.0.10);)
   table=??(lr_out_snat        ), priority=154  , match=(ip && ip4.src == 10.0.0.0/24 && outport == "lr0-public" && is_chassis_resident("cr-lr0-public") && (!ct.trk || !ct.rpl) && reg9[[4]] == 1), action=(reg9[[4]] = 0; ct_snat(172.168.0.10);)
@@ -5939,6 +5971,7 @@  AT_CAPTURE_FILE([lr0flows])
 
 AT_CHECK([grep "lr_in_unsnat" lr0flows | ovn_strip_lflows], [0], [dnl
   table=??(lr_in_unsnat       ), priority=0    , match=(1), action=(next;)
+  table=??(lr_in_unsnat       ), priority=10   , match=(ip), action=(flags.without_unsnat = 1; next;)
   table=??(lr_in_unsnat       ), priority=100  , match=(ip && ip4.dst == 172.168.0.10 && inport == "lr0-public" && is_chassis_resident("cr-lr0-public")), action=(ct_snat;)
   table=??(lr_in_unsnat       ), priority=100  , match=(ip && ip4.dst == 172.168.0.20 && inport == "lr0-public" && is_chassis_resident("cr-lr0-public")), action=(ct_snat;)
   table=??(lr_in_unsnat       ), priority=100  , match=(ip && ip4.dst == 172.168.0.30 && inport == "lr0-public" && is_chassis_resident("cr-lr0-public")), action=(ct_snat;)
@@ -5946,6 +5979,7 @@  AT_CHECK([grep "lr_in_unsnat" lr0flows | ovn_strip_lflows], [0], [dnl
 
 AT_CHECK([grep "lr_in_defrag" lr0flows | ovn_strip_lflows], [0], [dnl
   table=??(lr_in_defrag       ), priority=0    , match=(1), action=(next;)
+  table=??(lr_in_defrag       ), priority=10   , match=(ip && (!ct.trk || !ct.rpl)), action=(ct_next(dnat);)
   table=??(lr_in_defrag       ), priority=100  , match=(ip && ip4.dst == 10.0.0.10), action=(ct_dnat;)
   table=??(lr_in_defrag       ), priority=100  , match=(ip && ip4.dst == 172.168.0.100), action=(ct_dnat;)
   table=??(lr_in_defrag       ), priority=100  , match=(ip && ip4.dst == 172.168.0.200), action=(ct_dnat;)
@@ -5954,6 +5988,7 @@  AT_CHECK([grep "lr_in_defrag" lr0flows | ovn_strip_lflows], [0], [dnl
 
 AT_CHECK([grep "lr_in_dnat" lr0flows | ovn_strip_lflows], [0], [dnl
   table=??(lr_in_dnat         ), priority=0    , match=(1), action=(next;)
+  table=??(lr_in_dnat         ), priority=10   , match=(ip && ct.new), action=(ct_commit_to_zone(dnat);)
   table=??(lr_in_dnat         ), priority=100  , match=(ip && ip4.dst == 172.168.0.20 && inport == "lr0-public" && is_chassis_resident("cr-lr0-public")), action=(ct_dnat(10.0.0.3);)
   table=??(lr_in_dnat         ), priority=110  , match=(ct.new && !ct.rel && ip4 && ip4.dst == 172.168.0.200 && is_chassis_resident("cr-lr0-public")), action=(ct_lb_mark(backends=10.0.0.80,10.0.0.81);)
   table=??(lr_in_dnat         ), priority=120  , match=(ct.new && !ct.rel && ip4 && ip4.dst == 10.0.0.10 && tcp && tcp.dst == 80 && is_chassis_resident("cr-lr0-public")), action=(ct_lb_mark(backends=10.0.0.4:8080);)
@@ -5982,24 +6017,20 @@  AT_CHECK([grep "lr_out_undnat" lr0flows | ovn_strip_lflows], [0], [dnl
 
 AT_CHECK([grep "lr_out_post_undnat" lr0flows | ovn_strip_lflows], [0], [dnl
   table=??(lr_out_post_undnat ), priority=0    , match=(1), action=(next;)
-  table=??(lr_out_post_undnat ), priority=70   , match=(ip && ip4.src == 10.0.0.0/24 && outport == "lr0-public" && is_chassis_resident("cr-lr0-public") && (!ct.trk || !ct.rpl)), action=(ct_next(snat);)
-  table=??(lr_out_post_undnat ), priority=70   , match=(ip && ip4.src == 10.0.0.10 && outport == "lr0-public" && is_chassis_resident("cr-lr0-public") && (!ct.trk || !ct.rpl)), action=(ct_next(snat);)
+  table=??(lr_out_post_undnat ), priority=10   , match=(ip && (!ct.trk || !ct.rpl) && flags.without_unsnat == 1), action=(ct_next(snat);)
 ])
 
 AT_CHECK([grep "lr_out_snat" lr0flows | ovn_strip_lflows], [0], [dnl
   table=??(lr_out_snat        ), priority=0    , match=(1), action=(next;)
+  table=??(lr_out_snat        ), priority=10   , match=(ip && ct.new && flags.without_unsnat == 1), action=(ct_commit_to_zone(snat);)
   table=??(lr_out_snat        ), priority=120  , match=(nd_ns), action=(next;)
-  table=??(lr_out_snat        ), priority=153  , match=(ip && ip4.dst == 10.0.0.0/24 && inport == "lr0-public" && is_chassis_resident("cr-lr0-public")), action=(ct_snat;)
   table=??(lr_out_snat        ), priority=153  , match=(ip && ip4.src == 10.0.0.0/24 && outport == "lr0-public" && is_chassis_resident("cr-lr0-public") && (!ct.trk || !ct.rpl)), action=(ct_snat(172.168.0.10);)
-  table=??(lr_out_snat        ), priority=161  , match=(ip && ip4.dst == 10.0.0.10 && inport == "lr0-public" && is_chassis_resident("cr-lr0-public")), action=(ct_snat;)
   table=??(lr_out_snat        ), priority=161  , match=(ip && ip4.src == 10.0.0.10 && outport == "lr0-public" && is_chassis_resident("cr-lr0-public") && (!ct.trk || !ct.rpl)), action=(ct_snat(172.168.0.30);)
   table=??(lr_out_snat        ), priority=161  , match=(ip && ip4.src == 10.0.0.3 && outport == "lr0-public" && is_chassis_resident("cr-lr0-public") && (!ct.trk || !ct.rpl)), action=(ct_snat(172.168.0.20);)
 ])
 
 AT_CHECK([grep "lr_out_post_snat" lr0flows | ovn_strip_lflows], [0], [dnl
   table=??(lr_out_post_snat   ), priority=0    , match=(1), action=(next;)
-  table=??(lr_out_post_snat   ), priority=153  , match=(ip && ip4.dst == 10.0.0.0/24 && inport == "lr0-public" && is_chassis_resident("cr-lr0-public") && ct.new), action=(ct_commit_to_zone(snat);)
-  table=??(lr_out_post_snat   ), priority=161  , match=(ip && ip4.dst == 10.0.0.10 && inport == "lr0-public" && is_chassis_resident("cr-lr0-public") && ct.new), action=(ct_commit_to_zone(snat);)
 ])
 
 # Make the logical router as Gateway router
@@ -6013,6 +6044,7 @@  AT_CAPTURE_FILE([lr0flows])
 
 AT_CHECK([grep "lr_in_unsnat" lr0flows | ovn_strip_lflows], [0], [dnl
   table=??(lr_in_unsnat       ), priority=0    , match=(1), action=(next;)
+  table=??(lr_in_unsnat       ), priority=10   , match=(ip), action=(flags.without_unsnat = 1; next;)
   table=??(lr_in_unsnat       ), priority=90   , match=(ip && ip4.dst == 172.168.0.10), action=(ct_snat;)
   table=??(lr_in_unsnat       ), priority=90   , match=(ip && ip4.dst == 172.168.0.20), action=(ct_snat;)
   table=??(lr_in_unsnat       ), priority=90   , match=(ip && ip4.dst == 172.168.0.30), action=(ct_snat;)
@@ -6020,6 +6052,7 @@  AT_CHECK([grep "lr_in_unsnat" lr0flows | ovn_strip_lflows], [0], [dnl
 
 AT_CHECK([grep "lr_in_defrag" lr0flows | ovn_strip_lflows], [0], [dnl
   table=??(lr_in_defrag       ), priority=0    , match=(1), action=(next;)
+  table=??(lr_in_defrag       ), priority=10   , match=(ip && (!ct.trk || !ct.rpl)), action=(ct_next(dnat);)
   table=??(lr_in_defrag       ), priority=100  , match=(ip && ip4.dst == 10.0.0.10), action=(ct_dnat;)
   table=??(lr_in_defrag       ), priority=100  , match=(ip && ip4.dst == 172.168.0.100), action=(ct_dnat;)
   table=??(lr_in_defrag       ), priority=100  , match=(ip && ip4.dst == 172.168.0.200), action=(ct_dnat;)
@@ -6028,6 +6061,7 @@  AT_CHECK([grep "lr_in_defrag" lr0flows | ovn_strip_lflows], [0], [dnl
 
 AT_CHECK([grep "lr_in_dnat" lr0flows | ovn_strip_lflows], [0], [dnl
   table=??(lr_in_dnat         ), priority=0    , match=(1), action=(next;)
+  table=??(lr_in_dnat         ), priority=10   , match=(ip && ct.new), action=(ct_commit_to_zone(dnat);)
   table=??(lr_in_dnat         ), priority=100  , match=(ip && ip4.dst == 172.168.0.20), action=(flags.loopback = 1; ct_dnat(10.0.0.3);)
   table=??(lr_in_dnat         ), priority=110  , match=(ct.new && !ct.rel && ip4 && ip4.dst == 172.168.0.200), action=(ct_lb_mark(backends=10.0.0.80,10.0.0.81);)
   table=??(lr_in_dnat         ), priority=120  , match=(ct.new && !ct.rel && ip4 && ip4.dst == 10.0.0.10 && tcp && tcp.dst == 80), action=(ct_lb_mark(backends=10.0.0.4:8080);)
@@ -6053,11 +6087,12 @@  AT_CHECK([grep "lr_out_undnat" lr0flows | ovn_strip_lflows], [0], [dnl
 
 AT_CHECK([grep "lr_out_post_undnat" lr0flows | ovn_strip_lflows], [0], [dnl
   table=??(lr_out_post_undnat ), priority=0    , match=(1), action=(next;)
-  table=??(lr_out_post_undnat ), priority=50   , match=(ip && ct.new), action=(ct_commit { } ; next; )
+  table=??(lr_out_post_undnat ), priority=10   , match=(ip && (!ct.trk || !ct.rpl) && flags.without_unsnat == 1), action=(ct_next(snat);)
 ])
 
 AT_CHECK([grep "lr_out_snat" lr0flows | ovn_strip_lflows], [0], [dnl
   table=??(lr_out_snat        ), priority=0    , match=(1), action=(next;)
+  table=??(lr_out_snat        ), priority=10   , match=(ip && ct.new && flags.without_unsnat == 1), action=(ct_commit_to_zone(snat);)
   table=??(lr_out_snat        ), priority=120  , match=(nd_ns), action=(next;)
   table=??(lr_out_snat        ), priority=25   , match=(ip && ip4.src == 10.0.0.0/24 && (!ct.trk || !ct.rpl)), action=(ct_snat(172.168.0.10);)
   table=??(lr_out_snat        ), priority=33   , match=(ip && ip4.src == 10.0.0.10 && (!ct.trk || !ct.rpl)), action=(ct_snat(172.168.0.30);)
@@ -6074,6 +6109,7 @@  AT_CAPTURE_FILE([lr0flows])
 
 AT_CHECK([grep "lr_in_unsnat" lr0flows | ovn_strip_lflows], [0], [dnl
   table=??(lr_in_unsnat       ), priority=0    , match=(1), action=(next;)
+  table=??(lr_in_unsnat       ), priority=10   , match=(ip), action=(flags.without_unsnat = 1; next;)
   table=??(lr_in_unsnat       ), priority=110  , match=(inport == "lr0-public" && ip4.dst == 172.168.0.10), action=(ct_snat;)
   table=??(lr_in_unsnat       ), priority=110  , match=(inport == "lr0-sw0" && ip4.dst == 10.0.0.1), action=(ct_snat;)
   table=??(lr_in_unsnat       ), priority=90   , match=(ip && ip4.dst == 172.168.0.10), action=(ct_snat;)
@@ -6083,6 +6119,7 @@  AT_CHECK([grep "lr_in_unsnat" lr0flows | ovn_strip_lflows], [0], [dnl
 
 AT_CHECK([grep "lr_in_defrag" lr0flows | ovn_strip_lflows], [0], [dnl
   table=??(lr_in_defrag       ), priority=0    , match=(1), action=(next;)
+  table=??(lr_in_defrag       ), priority=10   , match=(ip && (!ct.trk || !ct.rpl)), action=(ct_next(dnat);)
   table=??(lr_in_defrag       ), priority=100  , match=(ip && ip4.dst == 10.0.0.10), action=(ct_dnat;)
   table=??(lr_in_defrag       ), priority=100  , match=(ip && ip4.dst == 172.168.0.100), action=(ct_dnat;)
   table=??(lr_in_defrag       ), priority=100  , match=(ip && ip4.dst == 172.168.0.200), action=(ct_dnat;)
@@ -6091,6 +6128,7 @@  AT_CHECK([grep "lr_in_defrag" lr0flows | ovn_strip_lflows], [0], [dnl
 
 AT_CHECK([grep "lr_in_dnat" lr0flows | ovn_strip_lflows], [0], [dnl
   table=??(lr_in_dnat         ), priority=0    , match=(1), action=(next;)
+  table=??(lr_in_dnat         ), priority=10   , match=(ip && ct.new), action=(ct_commit_to_zone(dnat);)
   table=??(lr_in_dnat         ), priority=100  , match=(ip && ip4.dst == 172.168.0.20), action=(flags.loopback = 1; ct_dnat(10.0.0.3);)
   table=??(lr_in_dnat         ), priority=110  , match=(ct.new && !ct.rel && ip4 && ip4.dst == 172.168.0.200), action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.80,10.0.0.81; force_snat);)
   table=??(lr_in_dnat         ), priority=120  , match=(ct.new && !ct.rel && ip4 && ip4.dst == 10.0.0.10 && tcp && tcp.dst == 80), action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.4:8080; force_snat);)
@@ -6116,11 +6154,12 @@  AT_CHECK([grep "lr_out_undnat" lr0flows | ovn_strip_lflows], [0], [dnl
 
 AT_CHECK([grep "lr_out_post_undnat" lr0flows | ovn_strip_lflows], [0], [dnl
   table=??(lr_out_post_undnat ), priority=0    , match=(1), action=(next;)
-  table=??(lr_out_post_undnat ), priority=50   , match=(ip && ct.new), action=(ct_commit { } ; next; )
+  table=??(lr_out_post_undnat ), priority=10   , match=(ip && (!ct.trk || !ct.rpl) && flags.without_unsnat == 1), action=(ct_next(snat);)
 ])
 
 AT_CHECK([grep "lr_out_snat" lr0flows | ovn_strip_lflows], [0], [dnl
   table=??(lr_out_snat        ), priority=0    , match=(1), action=(next;)
+  table=??(lr_out_snat        ), priority=10   , match=(ip && ct.new && flags.without_unsnat == 1), action=(ct_commit_to_zone(snat);)
   table=??(lr_out_snat        ), priority=110  , match=(flags.force_snat_for_lb == 1 && ip4 && outport == "lr0-public"), action=(ct_snat(172.168.0.10);)
   table=??(lr_out_snat        ), priority=110  , match=(flags.force_snat_for_lb == 1 && ip4 && outport == "lr0-sw0"), action=(ct_snat(10.0.0.1);)
   table=??(lr_out_snat        ), priority=120  , match=(nd_ns), action=(next;)
@@ -6138,6 +6177,7 @@  AT_CAPTURE_FILE([lr0flows])
 
 AT_CHECK([grep "lr_in_unsnat" lr0flows | ovn_strip_lflows], [0], [dnl
   table=??(lr_in_unsnat       ), priority=0    , match=(1), action=(next;)
+  table=??(lr_in_unsnat       ), priority=10   , match=(ip), action=(flags.without_unsnat = 1; next;)
   table=??(lr_in_unsnat       ), priority=110  , match=(inport == "lr0-public" && ip4.dst == 172.168.0.10), action=(ct_snat;)
   table=??(lr_in_unsnat       ), priority=110  , match=(inport == "lr0-sw0" && ip4.dst == 10.0.0.1), action=(ct_snat;)
   table=??(lr_in_unsnat       ), priority=90   , match=(ip && ip4.dst == 172.168.0.10), action=(ct_snat;)
@@ -6147,6 +6187,7 @@  AT_CHECK([grep "lr_in_unsnat" lr0flows | ovn_strip_lflows], [0], [dnl
 
 AT_CHECK([grep "lr_in_defrag" lr0flows | ovn_strip_lflows], [0], [dnl
   table=??(lr_in_defrag       ), priority=0    , match=(1), action=(next;)
+  table=??(lr_in_defrag       ), priority=10   , match=(ip && (!ct.trk || !ct.rpl)), action=(ct_next(dnat);)
   table=??(lr_in_defrag       ), priority=100  , match=(ip && ip4.dst == 10.0.0.10), action=(ct_dnat;)
   table=??(lr_in_defrag       ), priority=100  , match=(ip && ip4.dst == 172.168.0.10), action=(ct_dnat;)
   table=??(lr_in_defrag       ), priority=100  , match=(ip && ip4.dst == 172.168.0.100), action=(ct_dnat;)
@@ -6156,6 +6197,7 @@  AT_CHECK([grep "lr_in_defrag" lr0flows | ovn_strip_lflows], [0], [dnl
 
 AT_CHECK([grep "lr_in_dnat" lr0flows | ovn_strip_lflows], [0], [dnl
   table=??(lr_in_dnat         ), priority=0    , match=(1), action=(next;)
+  table=??(lr_in_dnat         ), priority=10   , match=(ip && ct.new), action=(ct_commit_to_zone(dnat);)
   table=??(lr_in_dnat         ), priority=100  , match=(ip && ip4.dst == 172.168.0.20), action=(flags.loopback = 1; ct_dnat(10.0.0.3);)
   table=??(lr_in_dnat         ), priority=110  , match=(ct.new && !ct.rel && ip4 && ip4.dst == 172.168.0.200), action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.80,10.0.0.81; force_snat);)
   table=??(lr_in_dnat         ), priority=120  , match=(ct.new && !ct.rel && ip4 && ip4.dst == 10.0.0.10 && tcp && tcp.dst == 80), action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.4:8080; force_snat);)
@@ -6182,11 +6224,12 @@  AT_CHECK([grep "lr_out_undnat" lr0flows | ovn_strip_lflows], [0], [dnl
 
 AT_CHECK([grep "lr_out_post_undnat" lr0flows | ovn_strip_lflows], [0], [dnl
   table=??(lr_out_post_undnat ), priority=0    , match=(1), action=(next;)
-  table=??(lr_out_post_undnat ), priority=50   , match=(ip && ct.new), action=(ct_commit { } ; next; )
+  table=??(lr_out_post_undnat ), priority=10   , match=(ip && (!ct.trk || !ct.rpl) && flags.without_unsnat == 1), action=(ct_next(snat);)
 ])
 
 AT_CHECK([grep "lr_out_snat" lr0flows | ovn_strip_lflows], [0], [dnl
   table=??(lr_out_snat        ), priority=0    , match=(1), action=(next;)
+  table=??(lr_out_snat        ), priority=10   , match=(ip && ct.new && flags.without_unsnat == 1), action=(ct_commit_to_zone(snat);)
   table=??(lr_out_snat        ), priority=110  , match=(flags.force_snat_for_lb == 1 && ip4 && outport == "lr0-public"), action=(ct_snat(172.168.0.10);)
   table=??(lr_out_snat        ), priority=110  , match=(flags.force_snat_for_lb == 1 && ip4 && outport == "lr0-sw0"), action=(ct_snat(10.0.0.1);)
   table=??(lr_out_snat        ), priority=120  , match=(nd_ns), action=(next;)
@@ -6212,6 +6255,7 @@  AT_CAPTURE_FILE([lr0flows])
 
 AT_CHECK([grep "lr_in_unsnat" lr0flows | ovn_strip_lflows], [0], [dnl
   table=??(lr_in_unsnat       ), priority=0    , match=(1), action=(next;)
+  table=??(lr_in_unsnat       ), priority=10   , match=(ip), action=(flags.without_unsnat = 1; next;)
   table=??(lr_in_unsnat       ), priority=110  , match=(inport == "lr0-public" && ip4.dst == 172.168.0.10), action=(ct_snat;)
   table=??(lr_in_unsnat       ), priority=110  , match=(inport == "lr0-public" && ip6.dst == def0::10), action=(ct_snat;)
   table=??(lr_in_unsnat       ), priority=110  , match=(inport == "lr0-sw0" && ip4.dst == 10.0.0.1), action=(ct_snat;)
@@ -6223,6 +6267,7 @@  AT_CHECK([grep "lr_in_unsnat" lr0flows | ovn_strip_lflows], [0], [dnl
 
 AT_CHECK([grep "lr_in_defrag" lr0flows | ovn_strip_lflows], [0], [dnl
   table=??(lr_in_defrag       ), priority=0    , match=(1), action=(next;)
+  table=??(lr_in_defrag       ), priority=10   , match=(ip && (!ct.trk || !ct.rpl)), action=(ct_next(dnat);)
   table=??(lr_in_defrag       ), priority=100  , match=(ip && ip4.dst == 10.0.0.10), action=(ct_dnat;)
   table=??(lr_in_defrag       ), priority=100  , match=(ip && ip4.dst == 172.168.0.10), action=(ct_dnat;)
   table=??(lr_in_defrag       ), priority=100  , match=(ip && ip4.dst == 172.168.0.100), action=(ct_dnat;)
@@ -6233,6 +6278,7 @@  AT_CHECK([grep "lr_in_defrag" lr0flows | ovn_strip_lflows], [0], [dnl
 
 AT_CHECK([grep "lr_in_dnat" lr0flows | ovn_strip_lflows], [0], [dnl
   table=??(lr_in_dnat         ), priority=0    , match=(1), action=(next;)
+  table=??(lr_in_dnat         ), priority=10   , match=(ip && ct.new), action=(ct_commit_to_zone(dnat);)
   table=??(lr_in_dnat         ), priority=100  , match=(ip && ip4.dst == 172.168.0.20), action=(flags.loopback = 1; ct_dnat(10.0.0.3);)
   table=??(lr_in_dnat         ), priority=110  , match=(ct.new && !ct.rel && ip4 && ip4.dst == 172.168.0.200), action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.80,10.0.0.81; force_snat);)
   table=??(lr_in_dnat         ), priority=120  , match=(ct.new && !ct.rel && ip4 && ip4.dst == 10.0.0.10 && tcp && tcp.dst == 80), action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.4:8080; force_snat);)
@@ -6260,11 +6306,12 @@  AT_CHECK([grep "lr_out_undnat" lr0flows | ovn_strip_lflows], [0], [dnl
 
 AT_CHECK([grep "lr_out_post_undnat" lr0flows | ovn_strip_lflows], [0], [dnl
   table=??(lr_out_post_undnat ), priority=0    , match=(1), action=(next;)
-  table=??(lr_out_post_undnat ), priority=50   , match=(ip && ct.new), action=(ct_commit { } ; next; )
+  table=??(lr_out_post_undnat ), priority=10   , match=(ip && (!ct.trk || !ct.rpl) && flags.without_unsnat == 1), action=(ct_next(snat);)
 ])
 
 AT_CHECK([grep "lr_out_snat" lr0flows | ovn_strip_lflows], [0], [dnl
   table=??(lr_out_snat        ), priority=0    , match=(1), action=(next;)
+  table=??(lr_out_snat        ), priority=10   , match=(ip && ct.new && flags.without_unsnat == 1), action=(ct_commit_to_zone(snat);)
   table=??(lr_out_snat        ), priority=110  , match=(flags.force_snat_for_lb == 1 && ip4 && outport == "lr0-public"), action=(ct_snat(172.168.0.10);)
   table=??(lr_out_snat        ), priority=110  , match=(flags.force_snat_for_lb == 1 && ip4 && outport == "lr0-sw0"), action=(ct_snat(10.0.0.1);)
   table=??(lr_out_snat        ), priority=110  , match=(flags.force_snat_for_lb == 1 && ip6 && outport == "lr0-public"), action=(ct_snat(def0::10);)
@@ -6291,15 +6338,18 @@  AT_CAPTURE_FILE([lr0flows])
 
 AT_CHECK([grep "lr_in_unsnat" lr0flows | ovn_strip_lflows], [0], [dnl
   table=??(lr_in_unsnat       ), priority=0    , match=(1), action=(next;)
+  table=??(lr_in_unsnat       ), priority=10   , match=(ip), action=(flags.without_unsnat = 1; next;)
 ])
 
 AT_CHECK([grep "lr_in_defrag" lr0flows | ovn_strip_lflows], [0], [dnl
   table=??(lr_in_defrag       ), priority=0    , match=(1), action=(next;)
+  table=??(lr_in_defrag       ), priority=10   , match=(ip && (!ct.trk || !ct.rpl)), action=(ct_next(dnat);)
   table=??(lr_in_defrag       ), priority=100  , match=(ip && ip4.dst == 172.168.0.210), action=(ct_dnat;)
 ])
 
 AT_CHECK([grep "lr_in_dnat" lr0flows | ovn_strip_lflows], [0], [dnl
   table=??(lr_in_dnat         ), priority=0    , match=(1), action=(next;)
+  table=??(lr_in_dnat         ), priority=10   , match=(ip && ct.new), action=(ct_commit_to_zone(dnat);)
   table=??(lr_in_dnat         ), priority=120  , match=(ct.new && !ct.rel && ip4 && ip4.dst == 172.168.0.210 && tcp && tcp.dst == 60), action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.50:6062,10.0.0.60:6062; force_snat);)
   table=??(lr_in_dnat         ), priority=120  , match=(ct.new && !ct.rel && ip4 && ip4.dst == 172.168.0.210 && udp && udp.dst == 60), action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.50:6062,10.0.0.60:6062; force_snat);)
   table=??(lr_in_dnat         ), priority=50   , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted), action=(next;)
@@ -6322,11 +6372,12 @@  AT_CHECK([grep "lr_out_undnat" lr0flows | ovn_strip_lflows], [0], [dnl
 
 AT_CHECK([grep "lr_out_post_undnat" lr0flows | ovn_strip_lflows], [0], [dnl
   table=??(lr_out_post_undnat ), priority=0    , match=(1), action=(next;)
-  table=??(lr_out_post_undnat ), priority=50   , match=(ip && ct.new), action=(ct_commit { } ; next; )
+  table=??(lr_out_post_undnat ), priority=10   , match=(ip && (!ct.trk || !ct.rpl) && flags.without_unsnat == 1), action=(ct_next(snat);)
 ])
 
 AT_CHECK([grep "lr_out_snat" lr0flows | ovn_strip_lflows], [0], [dnl
   table=??(lr_out_snat        ), priority=0    , match=(1), action=(next;)
+  table=??(lr_out_snat        ), priority=10   , match=(ip && ct.new && flags.without_unsnat == 1), action=(ct_commit_to_zone(snat);)
   table=??(lr_out_snat        ), priority=120  , match=(nd_ns), action=(next;)
 ])
 
@@ -6358,6 +6409,7 @@  check ovn-nbctl --wait=sb sync
 
 AT_CHECK([ovn-sbctl dump-flows lr0 | grep "lr_in_dnat" | ovn_strip_lflows], [0], [dnl
   table=??(lr_in_dnat         ), priority=0    , match=(1), action=(next;)
+  table=??(lr_in_dnat         ), priority=10   , match=(ip && ct.new), action=(ct_commit_to_zone(dnat);)
   table=??(lr_in_dnat         ), priority=110  , match=(ct.new && !ct.rel && ip4 && ip4.dst == 172.168.10.10), action=(reg0 = 0; reject { outport <-> inport; next(pipeline=egress,table=??);};)
   table=??(lr_in_dnat         ), priority=50   , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted), action=(next;)
   table=??(lr_in_dnat         ), priority=50   , match=(ct.rel && !ct.est && !ct.new), action=(ct_commit_nat;)
@@ -6372,6 +6424,7 @@  check ovn-nbctl --wait=sb set load_balancer lb5 options:skip_snat=true
 
 AT_CHECK([ovn-sbctl dump-flows lr0 | grep "lr_in_dnat" | ovn_strip_lflows], [0], [dnl
   table=??(lr_in_dnat         ), priority=0    , match=(1), action=(next;)
+  table=??(lr_in_dnat         ), priority=10   , match=(ip && ct.new), action=(ct_commit_to_zone(dnat);)
   table=??(lr_in_dnat         ), priority=110  , match=(ct.new && !ct.rel && ip4 && ip4.dst == 172.168.10.10), action=(flags.skip_snat_for_lb = 1; reg0 = 0; reject { outport <-> inport; next(pipeline=egress,table=??);};)
   table=??(lr_in_dnat         ), priority=50   , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted), action=(next;)
   table=??(lr_in_dnat         ), priority=50   , match=(ct.rel && !ct.est && !ct.new), action=(ct_commit_nat;)
@@ -6388,6 +6441,7 @@  check ovn-nbctl --wait=sb set logical_router lr0 options:lb_force_snat_ip="route
 
 AT_CHECK([ovn-sbctl dump-flows lr0 | grep "lr_in_dnat" | ovn_strip_lflows], [0], [dnl
   table=??(lr_in_dnat         ), priority=0    , match=(1), action=(next;)
+  table=??(lr_in_dnat         ), priority=10   , match=(ip && ct.new), action=(ct_commit_to_zone(dnat);)
   table=??(lr_in_dnat         ), priority=110  , match=(ct.new && !ct.rel && ip4 && ip4.dst == 172.168.10.10), action=(flags.force_snat_for_lb = 1; reg0 = 0; reject { outport <-> inport; next(pipeline=egress,table=??);};)
   table=??(lr_in_dnat         ), priority=50   , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted), action=(next;)
   table=??(lr_in_dnat         ), priority=50   , match=(ct.rel && !ct.est && !ct.new), action=(ct_commit_nat;)
@@ -6405,6 +6459,7 @@  check ovn-nbctl --wait=sb lr-lb-add lr0 lb6
 
 AT_CHECK([ovn-sbctl dump-flows lr0 | grep "lr_in_dnat" | ovn_strip_lflows], [0], [dnl
   table=??(lr_in_dnat         ), priority=0    , match=(1), action=(next;)
+  table=??(lr_in_dnat         ), priority=10   , match=(ip && ct.new), action=(ct_commit_to_zone(dnat);)
   table=??(lr_in_dnat         ), priority=110  , match=(ct.new && !ct.rel && ip4 && ip4.dst == 172.168.10.30), action=(drop;)
   table=??(lr_in_dnat         ), priority=50   , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted), action=(next;)
   table=??(lr_in_dnat         ), priority=50   , match=(ct.rel && !ct.est && !ct.new), action=(ct_commit_nat;)
@@ -6419,6 +6474,7 @@  check ovn-nbctl --wait=sb set load_balancer lb6 options:skip_snat=true
 
 AT_CHECK([ovn-sbctl dump-flows lr0 | grep "lr_in_dnat" | ovn_strip_lflows], [0], [dnl
   table=??(lr_in_dnat         ), priority=0    , match=(1), action=(next;)
+  table=??(lr_in_dnat         ), priority=10   , match=(ip && ct.new), action=(ct_commit_to_zone(dnat);)
   table=??(lr_in_dnat         ), priority=110  , match=(ct.new && !ct.rel && ip4 && ip4.dst == 172.168.10.30), action=(flags.skip_snat_for_lb = 1; drop;)
   table=??(lr_in_dnat         ), priority=50   , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted), action=(next;)
   table=??(lr_in_dnat         ), priority=50   , match=(ct.rel && !ct.est && !ct.new), action=(ct_commit_nat;)
@@ -6435,6 +6491,7 @@  check ovn-nbctl --wait=sb set logical_router lr0 options:lb_force_snat_ip="route
 
 AT_CHECK([ovn-sbctl dump-flows lr0 | grep "lr_in_dnat" | ovn_strip_lflows], [0], [dnl
   table=??(lr_in_dnat         ), priority=0    , match=(1), action=(next;)
+  table=??(lr_in_dnat         ), priority=10   , match=(ip && ct.new), action=(ct_commit_to_zone(dnat);)
   table=??(lr_in_dnat         ), priority=110  , match=(ct.new && !ct.rel && ip4 && ip4.dst == 172.168.10.30), action=(flags.force_snat_for_lb = 1; drop;)
   table=??(lr_in_dnat         ), priority=50   , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted), action=(next;)
   table=??(lr_in_dnat         ), priority=50   , match=(ct.rel && !ct.est && !ct.new), action=(ct_commit_nat;)
@@ -7951,9 +8008,6 @@  AT_CHECK([grep lr_in_unsnat lrflows | grep ct_snat | ovn_strip_lflows], [0], [dn
 ])
 
 AT_CHECK([grep lr_out_snat lrflows | grep ct_snat | ovn_strip_lflows], [0], [dnl
-  table=??(lr_out_snat        ), priority=161  , match=(ip && ip4.dst == 20.0.0.10 && inport == "DR-S1" && is_chassis_resident("cr-DR-S1")), action=(ct_snat;)
-  table=??(lr_out_snat        ), priority=161  , match=(ip && ip4.dst == 20.0.0.10 && inport == "DR-S2" && is_chassis_resident("cr-DR-S2")), action=(ct_snat;)
-  table=??(lr_out_snat        ), priority=161  , match=(ip && ip4.dst == 20.0.0.10 && inport == "DR-S3" && is_chassis_resident("cr-DR-S3")), action=(ct_snat;)
   table=??(lr_out_snat        ), priority=161  , match=(ip && ip4.src == 20.0.0.10 && outport == "DR-S1" && is_chassis_resident("cr-DR-S1") && (!ct.trk || !ct.rpl)), action=(ct_snat(172.16.1.10);)
   table=??(lr_out_snat        ), priority=161  , match=(ip && ip4.src == 20.0.0.10 && outport == "DR-S2" && is_chassis_resident("cr-DR-S2") && (!ct.trk || !ct.rpl)), action=(ct_snat(10.0.0.10);)
   table=??(lr_out_snat        ), priority=161  , match=(ip && ip4.src == 20.0.0.10 && outport == "DR-S3" && is_chassis_resident("cr-DR-S3") && (!ct.trk || !ct.rpl)), action=(ct_snat(192.168.0.10);)
@@ -7961,9 +8015,6 @@  AT_CHECK([grep lr_out_snat lrflows | grep ct_snat | ovn_strip_lflows], [0], [dnl
 
 AT_CHECK([grep lr_out_post_snat lrflows | ovn_strip_lflows], [0], [dnl
   table=??(lr_out_post_snat   ), priority=0    , match=(1), action=(next;)
-  table=??(lr_out_post_snat   ), priority=161  , match=(ip && ip4.dst == 20.0.0.10 && inport == "DR-S1" && is_chassis_resident("cr-DR-S1") && ct.new), action=(ct_commit_to_zone(snat);)
-  table=??(lr_out_post_snat   ), priority=161  , match=(ip && ip4.dst == 20.0.0.10 && inport == "DR-S2" && is_chassis_resident("cr-DR-S2") && ct.new), action=(ct_commit_to_zone(snat);)
-  table=??(lr_out_post_snat   ), priority=161  , match=(ip && ip4.dst == 20.0.0.10 && inport == "DR-S3" && is_chassis_resident("cr-DR-S3") && ct.new), action=(ct_commit_to_zone(snat);)
 ])
 
 check ovn-nbctl --wait=sb lr-nat-del DR snat 20.0.0.10
@@ -9387,6 +9438,7 @@  AT_CHECK([grep "lr_in_lb_aff_check" R1flows | ovn_strip_lflows], [0], [dnl
 ])
 AT_CHECK([grep "lr_in_dnat " R1flows | ovn_strip_lflows], [0], [dnl
   table=??(lr_in_dnat         ), priority=0    , match=(1), action=(next;)
+  table=??(lr_in_dnat         ), priority=10   , match=(ip && ct.new), action=(ct_commit_to_zone(dnat);)
   table=??(lr_in_dnat         ), priority=120  , match=(ct.new && !ct.rel && ip4 && ip4.dst == 172.16.0.10 && tcp && tcp.dst == 80), action=(ct_lb_mark(backends=10.0.0.2:80,20.0.0.2:80);)
   table=??(lr_in_dnat         ), priority=150  , match=(reg9[[6]] == 1 && ct.new && ip4.dst == 172.16.0.10 && reg4 == 10.0.0.2 && reg8[[0..15]] == 80), action=(reg0 = 172.16.0.10; ct_lb_mark(backends=10.0.0.2:80);)
   table=??(lr_in_dnat         ), priority=150  , match=(reg9[[6]] == 1 && ct.new && ip4.dst == 172.16.0.10 && reg4 == 20.0.0.2 && reg8[[0..15]] == 80), action=(reg0 = 172.16.0.10; ct_lb_mark(backends=20.0.0.2:80);)
@@ -9411,6 +9463,7 @@  AT_CAPTURE_FILE([R1flows_skip_snat])
 
 AT_CHECK([grep "lr_in_dnat " R1flows_skip_snat | ovn_strip_lflows], [0], [dnl
   table=??(lr_in_dnat         ), priority=0    , match=(1), action=(next;)
+  table=??(lr_in_dnat         ), priority=10   , match=(ip && ct.new), action=(ct_commit_to_zone(dnat);)
   table=??(lr_in_dnat         ), priority=120  , match=(ct.new && !ct.rel && ip4 && ip4.dst == 172.16.0.10 && tcp && tcp.dst == 80), action=(flags.skip_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.2:80,20.0.0.2:80; skip_snat);)
   table=??(lr_in_dnat         ), priority=150  , match=(reg9[[6]] == 1 && ct.new && ip4.dst == 172.16.0.10 && reg4 == 10.0.0.2 && reg8[[0..15]] == 80), action=(reg0 = 172.16.0.10; flags.skip_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.2:80; skip_snat);)
   table=??(lr_in_dnat         ), priority=150  , match=(reg9[[6]] == 1 && ct.new && ip4.dst == 172.16.0.10 && reg4 == 20.0.0.2 && reg8[[0..15]] == 80), action=(reg0 = 172.16.0.10; flags.skip_snat_for_lb = 1; ct_lb_mark(backends=20.0.0.2:80; skip_snat);)
@@ -9432,6 +9485,7 @@  AT_CAPTURE_FILE([R1flows_force_snat])
 
 AT_CHECK([grep "lr_in_dnat " R1flows_force_snat | ovn_strip_lflows], [0], [dnl
   table=??(lr_in_dnat         ), priority=0    , match=(1), action=(next;)
+  table=??(lr_in_dnat         ), priority=10   , match=(ip && ct.new), action=(ct_commit_to_zone(dnat);)
   table=??(lr_in_dnat         ), priority=120  , match=(ct.new && !ct.rel && ip4 && ip4.dst == 172.16.0.10 && tcp && tcp.dst == 80), action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.2:80,20.0.0.2:80; force_snat);)
   table=??(lr_in_dnat         ), priority=150  , match=(reg9[[6]] == 1 && ct.new && ip4.dst == 172.16.0.10 && reg4 == 10.0.0.2 && reg8[[0..15]] == 80), action=(reg0 = 172.16.0.10; flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.2:80; force_snat);)
   table=??(lr_in_dnat         ), priority=150  , match=(reg9[[6]] == 1 && ct.new && ip4.dst == 172.16.0.10 && reg4 == 20.0.0.2 && reg8[[0..15]] == 80), action=(reg0 = 172.16.0.10; flags.force_snat_for_lb = 1; ct_lb_mark(backends=20.0.0.2:80; force_snat);)
@@ -9452,6 +9506,7 @@  AT_CAPTURE_FILE([R1flows_force_skip_snat])
 
 AT_CHECK([grep "lr_in_dnat " R1flows_force_skip_snat | ovn_strip_lflows], [0], [dnl
   table=??(lr_in_dnat         ), priority=0    , match=(1), action=(next;)
+  table=??(lr_in_dnat         ), priority=10   , match=(ip && ct.new), action=(ct_commit_to_zone(dnat);)
   table=??(lr_in_dnat         ), priority=120  , match=(ct.new && !ct.rel && ip4 && ip4.dst == 172.16.0.10 && tcp && tcp.dst == 80), action=(flags.skip_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.2:80,20.0.0.2:80; skip_snat);)
   table=??(lr_in_dnat         ), priority=150  , match=(reg9[[6]] == 1 && ct.new && ip4.dst == 172.16.0.10 && reg4 == 10.0.0.2 && reg8[[0..15]] == 80), action=(reg0 = 172.16.0.10; flags.skip_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.2:80; skip_snat);)
   table=??(lr_in_dnat         ), priority=150  , match=(reg9[[6]] == 1 && ct.new && ip4.dst == 172.16.0.10 && reg4 == 20.0.0.2 && reg8[[0..15]] == 80), action=(reg0 = 172.16.0.10; flags.skip_snat_for_lb = 1; ct_lb_mark(backends=20.0.0.2:80; skip_snat);)
@@ -9476,6 +9531,7 @@  AT_CAPTURE_FILE([R1flows_2lbs])
 
 AT_CHECK([grep "lr_in_dnat " R1flows_2lbs | ovn_strip_lflows], [0], [dnl
   table=??(lr_in_dnat         ), priority=0    , match=(1), action=(next;)
+  table=??(lr_in_dnat         ), priority=10   , match=(ip && ct.new), action=(ct_commit_to_zone(dnat);)
   table=??(lr_in_dnat         ), priority=120  , match=(ct.new && !ct.rel && ip4 && ip4.dst == 172.16.0.10 && tcp && tcp.dst == 80), action=(flags.skip_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.2:80,20.0.0.2:80; skip_snat);)
   table=??(lr_in_dnat         ), priority=120  , match=(ct.new && !ct.rel && ip4 && ip4.dst == 172.16.0.20 && tcp && tcp.dst == 80), action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.2:80,20.0.0.2:80; force_snat);)
   table=??(lr_in_dnat         ), priority=150  , match=(reg9[[6]] == 1 && ct.new && ip4.dst == 172.16.0.10 && reg4 == 10.0.0.2 && reg8[[0..15]] == 80), action=(reg0 = 172.16.0.10; flags.skip_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.2:80; skip_snat);)
diff --git a/tests/system-ovn.at b/tests/system-ovn.at
index 861b1cb99..dc7b0ab2e 100644
--- a/tests/system-ovn.at
+++ b/tests/system-ovn.at
@@ -117,6 +117,7 @@  NS_CHECK_EXEC([alice1], [ping -q -c 3 -i 0.3 -w 2 30.0.0.2 | FORMAT_PING], \
 AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(172.16.1.2) | \
 sed -e 's/zone=[[0-9]]*/zone=<cleared>/'], [0], [dnl
 icmp,orig=(src=172.16.1.2,dst=192.168.1.2,id=<cleared>,type=8,code=0),reply=(src=192.168.1.2,dst=172.16.1.2,id=<cleared>,type=0,code=0),zone=<cleared>
+icmp,orig=(src=172.16.1.2,dst=192.168.1.2,id=<cleared>,type=8,code=0),reply=(src=192.168.1.2,dst=172.16.1.2,id=<cleared>,type=0,code=0),zone=<cleared>
 icmp,orig=(src=172.16.1.2,dst=30.0.0.2,id=<cleared>,type=8,code=0),reply=(src=192.168.1.2,dst=172.16.1.2,id=<cleared>,type=0,code=0),zone=<cleared>
 ])
 
@@ -297,6 +298,7 @@  NS_CHECK_EXEC([alice1], [ping6 -q -c 3 -i 0.3 -w 2 fd30::2 | FORMAT_PING], \
 AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(fd21::2) | \
 sed -e 's/zone=[[0-9]]*/zone=<cleared>/'], [0], [dnl
 icmpv6,orig=(src=fd21::2,dst=fd11::2,id=<cleared>,type=128,code=0),reply=(src=fd11::2,dst=fd21::2,id=<cleared>,type=129,code=0),zone=<cleared>
+icmpv6,orig=(src=fd21::2,dst=fd11::2,id=<cleared>,type=128,code=0),reply=(src=fd11::2,dst=fd21::2,id=<cleared>,type=129,code=0),zone=<cleared>
 icmpv6,orig=(src=fd21::2,dst=fd30::2,id=<cleared>,type=128,code=0),reply=(src=fd11::2,dst=fd21::2,id=<cleared>,type=129,code=0),zone=<cleared>
 ])
 
@@ -3753,6 +3755,7 @@  NS_CHECK_EXEC([foo2], [ping6 -q -c 3 -i 0.3 -w 2 fd20::2 | FORMAT_PING], \
 ovs-appctl dpctl/dump-conntrack | grep icmpv6
 AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(fd11::3) | \
 sed -e 's/zone=[[0-9]]*/zone=<cleared>/'], [0], [dnl
+icmpv6,orig=(src=fd11::3,dst=fd20::2,id=<cleared>,type=128,code=0),reply=(src=fd20::2,dst=fd11::3,id=<cleared>,type=129,code=0),zone=<cleared>
 ])
 
 # We verify that SNAT indeed happened via 'dump-conntrack' command.
@@ -3938,6 +3941,8 @@  NS_CHECK_EXEC([foo1], [ping -q -c 3 -i 0.3 -w 2 192.168.2.2 | FORMAT_PING], \
 # We verify that the connection is not tracked.
 AT_CHECK([ovs-appctl dpctl/dump-conntrack | grep icmp | FORMAT_CT(192.168.2.2) | \
 sed -e 's/zone=[[0-9]]*/zone=<cleared>/'], [0], [dnl
+icmp,orig=(src=192.168.1.2,dst=192.168.2.2,id=<cleared>,type=8,code=0),reply=(src=192.168.2.2,dst=192.168.1.2,id=<cleared>,type=0,code=0),zone=<cleared>
+icmp,orig=(src=192.168.1.2,dst=192.168.2.2,id=<cleared>,type=8,code=0),reply=(src=192.168.2.2,dst=192.168.1.2,id=<cleared>,type=0,code=0),zone=<cleared>
 ])
 
 AT_CHECK([ovs-appctl dpctl/flush-conntrack])
@@ -3950,6 +3955,8 @@  NS_CHECK_EXEC([foo2], [ping -q -c 3 -i 0.3 -w 2 192.168.2.2 | FORMAT_PING], \
 # We verify that the connection is not tracked.
 AT_CHECK([ovs-appctl dpctl/dump-conntrack | grep icmp | FORMAT_CT(192.168.2.2) | \
 sed -e 's/zone=[[0-9]]*/zone=<cleared>/'], [0], [dnl
+icmp,orig=(src=192.168.1.3,dst=192.168.2.2,id=<cleared>,type=8,code=0),reply=(src=192.168.2.2,dst=192.168.1.3,id=<cleared>,type=0,code=0),zone=<cleared>
+icmp,orig=(src=192.168.1.3,dst=192.168.2.2,id=<cleared>,type=8,code=0),reply=(src=192.168.2.2,dst=192.168.1.3,id=<cleared>,type=0,code=0),zone=<cleared>
 ])
 
 AT_CHECK([ovs-appctl dpctl/flush-conntrack])
@@ -3959,9 +3966,11 @@  NS_CHECK_EXEC([bar1], [ping -q -c 3 -i 0.3 -w 2 192.168.1.3 | FORMAT_PING], \
 3 packets transmitted, 3 received, 0% packet loss, time 0ms
 ])
 
-# We verify that the connection is not tracked.
+# We verify that the connection is tracked.
 AT_CHECK([ovs-appctl dpctl/dump-conntrack | grep icmp | FORMAT_CT(192.168.2.2) | \
 sed -e 's/zone=[[0-9]]*/zone=<cleared>/'], [0], [dnl
+icmp,orig=(src=192.168.2.2,dst=192.168.1.3,id=<cleared>,type=8,code=0),reply=(src=192.168.1.3,dst=192.168.2.2,id=<cleared>,type=0,code=0),zone=<cleared>
+icmp,orig=(src=192.168.2.2,dst=192.168.1.3,id=<cleared>,type=8,code=0),reply=(src=192.168.1.3,dst=192.168.2.2,id=<cleared>,type=0,code=0),zone=<cleared>
 ])
 
 AT_CHECK([ovs-appctl dpctl/flush-conntrack])
@@ -3978,6 +3987,7 @@  AT_CHECK([ovs-appctl dpctl/dump-conntrack | grep icmp | FORMAT_CT(172.16.1.4) |
 sed -e 's/zone=[[0-9]]*/zone=<cleared>/'], [0], [dnl
 icmp,orig=(src=172.16.1.3,dst=172.16.1.4,id=<cleared>,type=8,code=0),reply=(src=192.168.2.2,dst=172.16.1.3,id=<cleared>,type=0,code=0),zone=<cleared>
 icmp,orig=(src=192.168.1.2,dst=172.16.1.4,id=<cleared>,type=8,code=0),reply=(src=172.16.1.4,dst=172.16.1.3,id=<cleared>,type=0,code=0),zone=<cleared>
+icmp,orig=(src=192.168.1.2,dst=172.16.1.4,id=<cleared>,type=8,code=0),reply=(src=172.16.1.4,dst=192.168.1.2,id=<cleared>,type=0,code=0),zone=<cleared>
 ])
 
 AT_CHECK([ovs-appctl dpctl/flush-conntrack])
@@ -3993,7 +4003,6 @@  NS_CHECK_EXEC([foo2], [ping -q -c 3 -i 0.3 -w 2 172.16.1.4 | FORMAT_PING], \
 AT_CHECK([ovs-appctl dpctl/dump-conntrack | grep icmp | FORMAT_CT(172.16.1.1) | \
 sed -e 's/zone=[[0-9]]*/zone=<cleared>/'], [0], [dnl
 icmp,orig=(src=172.16.1.1,dst=172.16.1.4,id=<cleared>,type=8,code=0),reply=(src=192.168.2.2,dst=172.16.1.1,id=<cleared>,type=0,code=0),zone=<cleared>
-icmp,orig=(src=172.16.1.1,dst=192.168.2.2,id=<cleared>,type=8,code=0),reply=(src=192.168.2.2,dst=172.16.1.1,id=<cleared>,type=0,code=0),zone=<cleared>
 icmp,orig=(src=192.168.1.3,dst=172.16.1.4,id=<cleared>,type=8,code=0),reply=(src=172.16.1.4,dst=172.16.1.1,id=<cleared>,type=0,code=0),zone=<cleared>
 ])
 
@@ -4144,6 +4153,7 @@  NS_CHECK_EXEC([foo1], [ping -q -c 3 -i 0.3 -w 2 fd20::4 | FORMAT_PING], \
 # Then DNAT of 'bar1' address happens (listed first below).
 AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(fd20::4) | \
 sed -e 's/zone=[[0-9]]*/zone=<cleared>/'], [0], [dnl
+icmpv6,orig=(src=fd11::2,dst=fd20::4,id=<cleared>,type=128,code=0),reply=(src=fd20::4,dst=fd11::2,id=<cleared>,type=129,code=0),zone=<cleared>
 icmpv6,orig=(src=fd11::2,dst=fd20::4,id=<cleared>,type=128,code=0),reply=(src=fd20::4,dst=fd20::3,id=<cleared>,type=129,code=0),zone=<cleared>
 icmpv6,orig=(src=fd20::3,dst=fd20::4,id=<cleared>,type=128,code=0),reply=(src=fd12::2,dst=fd20::3,id=<cleared>,type=129,code=0),zone=<cleared>
 ])
@@ -4161,7 +4171,6 @@  NS_CHECK_EXEC([foo2], [ping -q -c 3 -i 0.3 -w 2 fd20::4 | FORMAT_PING], \
 AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(fd20::1) | \
 sed -e 's/zone=[[0-9]]*/zone=<cleared>/'], [0], [dnl
 icmpv6,orig=(src=fd11::3,dst=fd20::4,id=<cleared>,type=128,code=0),reply=(src=fd20::4,dst=fd20::1,id=<cleared>,type=129,code=0),zone=<cleared>
-icmpv6,orig=(src=fd20::1,dst=fd12::2,id=<cleared>,type=128,code=0),reply=(src=fd12::2,dst=fd20::1,id=<cleared>,type=129,code=0),zone=<cleared>
 icmpv6,orig=(src=fd20::1,dst=fd20::4,id=<cleared>,type=128,code=0),reply=(src=fd12::2,dst=fd20::1,id=<cleared>,type=129,code=0),zone=<cleared>
 ])
 
@@ -8682,10 +8691,10 @@  test_ping sw11 192.168.1.2
 OVS_WAIT_UNTIL([ovs-ofctl dump-flows br-int | grep -v "n_packets=0" | grep 'nat(src=172.16.1.21)'])
 # Ensure conntrack entry is present
 OVS_WAIT_FOR_OUTPUT([
-    ovs-appctl dpctl/dump-conntrack | FORMAT_CT(192.168.2.2) | \
+    ovs-appctl dpctl/dump-conntrack | FORMAT_CT(192.168.1.2) | \
       sed -e 's/zone=[[0-9]]*/zone=<cleared>/'], [0], [dnl
-icmp,orig=(src=192.168.2.2,dst=192.168.1.2,id=<cleared>,type=8,code=0),reply=(src=192.168.1.2,dst=192.168.2.2,id=<cleared>,type=0,code=0),zone=<cleared>
-tcp,orig=(src=192.168.2.2,dst=192.168.1.2,sport=<cleared>,dport=<cleared>),reply=(src=192.168.1.2,dst=192.168.2.2,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
+icmp,orig=(src=192.168.2.2,dst=192.168.1.2,id=<cleared>,type=8,code=0),reply=(src=192.168.1.2,dst=172.16.1.21,id=<cleared>,type=0,code=0),zone=<cleared>
+tcp,orig=(src=192.168.2.2,dst=192.168.1.2,sport=<cleared>,dport=<cleared>),reply=(src=192.168.1.2,dst=172.16.1.21,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
 ])
 
 AT_CHECK([ovs-appctl dpctl/flush-conntrack])
@@ -8697,9 +8706,11 @@  test_ping sw11 192.168.1.2
 
 # Ensure conntrack entry is present
 OVS_WAIT_FOR_OUTPUT([
-    ovs-appctl dpctl/dump-conntrack | FORMAT_CT(192.168.2.2) | \
+    ovs-appctl dpctl/dump-conntrack | FORMAT_CT(192.168.1.2) | \
       sed -e 's/zone=[[0-9]]*/zone=<cleared>/'], [0], [dnl
+icmp,orig=(src=192.168.2.2,dst=192.168.1.2,id=<cleared>,type=8,code=0),reply=(src=192.168.1.2,dst=172.16.1.21,id=<cleared>,type=0,code=0),zone=<cleared>
 icmp,orig=(src=192.168.2.2,dst=192.168.1.2,id=<cleared>,type=8,code=0),reply=(src=192.168.1.2,dst=192.168.2.2,id=<cleared>,type=0,code=0),zone=<cleared>
+tcp,orig=(src=192.168.2.2,dst=192.168.1.2,sport=<cleared>,dport=<cleared>),reply=(src=192.168.1.2,dst=172.16.1.21,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
 tcp,orig=(src=192.168.2.2,dst=192.168.1.2,sport=<cleared>,dport=<cleared>),reply=(src=192.168.1.2,dst=192.168.2.2,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
 ])
 
@@ -8711,10 +8722,10 @@  test_ping sw11 172.16.1.2
 
 # Ensure conntrack entry is present
 OVS_WAIT_FOR_OUTPUT([
-    ovs-appctl dpctl/dump-conntrack | FORMAT_CT(192.168.2.2) | \
+    ovs-appctl dpctl/dump-conntrack | FORMAT_CT(192.168.1.2) | \
       sed -e 's/zone=[[0-9]]*/zone=<cleared>/'], [0], [dnl
-icmp,orig=(src=192.168.2.2,dst=172.16.1.2,id=<cleared>,type=8,code=0),reply=(src=192.168.1.2,dst=192.168.2.2,id=<cleared>,type=0,code=0),zone=<cleared>
-tcp,orig=(src=192.168.2.2,dst=172.16.1.2,sport=<cleared>,dport=<cleared>),reply=(src=192.168.1.2,dst=192.168.2.2,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
+icmp,orig=(src=192.168.2.2,dst=192.168.1.2,id=<cleared>,type=8,code=0),reply=(src=192.168.1.2,dst=172.16.1.21,id=<cleared>,type=0,code=0),zone=<cleared>
+tcp,orig=(src=192.168.2.2,dst=192.168.1.2,sport=<cleared>,dport=<cleared>),reply=(src=192.168.1.2,dst=172.16.1.21,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
 ])
 
 AT_CHECK([ovs-appctl dpctl/flush-conntrack])