diff mbox series

[ovs-dev,ovn] ovn-northd: Address scale issues with DNAT flows.

Message ID 20200201105343.246333-1-numans@ovn.org
State Accepted
Headers show
Series [ovs-dev,ovn] ovn-northd: Address scale issues with DNAT flows. | expand

Commit Message

Numan Siddique Feb. 1, 2020, 10:53 a.m. UTC
From: Numan Siddique <numans@ovn.org>

When the commit [1] added Distributed NAT support in OVN, it didn't address
the requirement of making East/West NAT traffic distributed. The E/W NAT
traffic was still centralized. Later a couple of patches [2], addressed this
requirement. But the approach taken in [2] resulted in a lot of logical flows
as number of dnat_and_snat entries increase, as reported in @Reported-at.

This patch
  - reverts the approch taken in [2].
  - removing the flows which does the NAT direct (REGBIT_NAT_REDIRECT) to
    the gateway chassis.
  - and to solve the E/W centralized NAT it does the following:
     * Since for each NAT entry we know the MAC binding to be used for the
       external_ip - either the external_mac if set or the MAC of the
       distributed gateway router port, this patch adds the flows in the
       S_ROUTER_IN_ARP_RESOLVE stage to set the eth.dst to the MAC if the
       IP destination is external_ip.
     * The existing flows in the S_ROUTER_OUT_EGR_LOOP are now added by additional
       match -  is_chassis_resident('P') - where 'P' is logical_port of the NAT entry
       if set, otherwise it is the chassis resident port of distributed router port.
       With this additional match, the packet will be loopbacked to apply the unSNAT/DNAT
       rules on the relevant chassis.

Suppose if a logical port 'P' with IP 'A' has a dnat_and_snat entry with external_mac/logical_port
set, and if the packet's IP destination is one of the DNAT IP - then the packet will be sent out
of the local chassis, since eth.dst is resolved in the S_ROUTER_IN_ARP_RESOLVE stage.
If the external_mac/logical_port is not in NAT entry, then the packet will be redirected to
the gateway chassis.

With this patch, for the logical resource reported in @Reported-at, the number of logical
flows come down to around 45k from 650k.

[1] - ceacd9d49316("ovn: distributed NAT flows")

[2] - 551e3d989557("OVN: fix DVR Floating IP support")
      8244c6b6bd88("OVN: do not distribute traffic for local FIP")

Reported-at: https://mail.openvswitch.org/pipermail/ovs-discuss/2020-January/049714.html
Reported-by: Daniel Alvarez Sanchez <dalvarez@redhat.com>
Signed-off-by: Numan Siddique <numans@ovn.org>
---
 northd/ovn-northd.8.xml | 191 +++++++++--------------------
 northd/ovn-northd.c     | 264 ++++++----------------------------------
 tests/ovn-northd.at     |   8 +-
 3 files changed, 99 insertions(+), 364 deletions(-)

Comments

Dumitru Ceara Feb. 4, 2020, 12:59 p.m. UTC | #1
On 2/1/20 11:53 AM, numans@ovn.org wrote:
> From: Numan Siddique <numans@ovn.org>
> 
> When the commit [1] added Distributed NAT support in OVN, it didn't address
> the requirement of making East/West NAT traffic distributed. The E/W NAT
> traffic was still centralized. Later a couple of patches [2], addressed this
> requirement. But the approach taken in [2] resulted in a lot of logical flows
> as number of dnat_and_snat entries increase, as reported in @Reported-at.
> 
> This patch
>   - reverts the approch taken in [2].
>   - removing the flows which does the NAT direct (REGBIT_NAT_REDIRECT) to
>     the gateway chassis.
>   - and to solve the E/W centralized NAT it does the following:
>      * Since for each NAT entry we know the MAC binding to be used for the
>        external_ip - either the external_mac if set or the MAC of the
>        distributed gateway router port, this patch adds the flows in the
>        S_ROUTER_IN_ARP_RESOLVE stage to set the eth.dst to the MAC if the
>        IP destination is external_ip.
>      * The existing flows in the S_ROUTER_OUT_EGR_LOOP are now added by additional
>        match -  is_chassis_resident('P') - where 'P' is logical_port of the NAT entry
>        if set, otherwise it is the chassis resident port of distributed router port.
>        With this additional match, the packet will be loopbacked to apply the unSNAT/DNAT
>        rules on the relevant chassis.
> 
> Suppose if a logical port 'P' with IP 'A' has a dnat_and_snat entry with external_mac/logical_port
> set, and if the packet's IP destination is one of the DNAT IP - then the packet will be sent out
> of the local chassis, since eth.dst is resolved in the S_ROUTER_IN_ARP_RESOLVE stage.
> If the external_mac/logical_port is not in NAT entry, then the packet will be redirected to
> the gateway chassis.
> 
> With this patch, for the logical resource reported in @Reported-at, the number of logical
> flows come down to around 45k from 650k.
> 
> [1] - ceacd9d49316("ovn: distributed NAT flows")
> 
> [2] - 551e3d989557("OVN: fix DVR Floating IP support")
>       8244c6b6bd88("OVN: do not distribute traffic for local FIP")
> 
> Reported-at: https://mail.openvswitch.org/pipermail/ovs-discuss/2020-January/049714.html
> Reported-by: Daniel Alvarez Sanchez <dalvarez@redhat.com>
> Signed-off-by: Numan Siddique <numans@ovn.org>
> ---
>  northd/ovn-northd.8.xml | 191 +++++++++--------------------
>  northd/ovn-northd.c     | 264 ++++++----------------------------------
>  tests/ovn-northd.at     |   8 +-
>  3 files changed, 99 insertions(+), 364 deletions(-)
> 

Hi Numan,

The patch looks ok to me and it passes unit tests.

Hi Daniel,
As this is quite a significant change it might be nice if you could also
try it out on your setup.

Otherwise:

Acked-by: Dumitru Ceara <dceara@redhat.com>

Regards,
Dumitru
Daniel Alvarez Sanchez Feb. 4, 2020, 1:28 p.m. UTC | #2
Hi Numan,

Thanks for this. I have deployed a setup with master branch and this patch
applied. The patch LGTM and I can confirm that it works. Moreover, the
number of lflows has been dramatically reduced from around 50

With 150 FIPs:

Before: ~70K lflows  https://imgur.com/a/OaVelCb
After (in the same setup): 2K lflows

[root@central ~]# ovn-sbctl list logical_flow | grep _uuid -c
2092
[root@central ~]# ovn-sbctl list logical_flow | grep lr_out_egr_loop -c
155
[root@central ~]# ovn-sbctl list logical_flow | grep lr_in_ip_routing -c
7

And I verified that FIP to FIP traffic works via the localnet port so it is
really distributed and does not traverse any tunnels.

Thanks!
Daniel

Tested-By: Daniel Alvarez Sanchez <dalvarez@redhat.com>
Acked-By: Daniel Alvarez Sanchez <dalvarez@redhat.com>

On Tue, Feb 4, 2020 at 1:59 PM Dumitru Ceara <dceara@redhat.com> wrote:

> On 2/1/20 11:53 AM, numans@ovn.org wrote:
> > From: Numan Siddique <numans@ovn.org>
> >
> > When the commit [1] added Distributed NAT support in OVN, it didn't
> address
> > the requirement of making East/West NAT traffic distributed. The E/W NAT
> > traffic was still centralized. Later a couple of patches [2], addressed
> this
> > requirement. But the approach taken in [2] resulted in a lot of logical
> flows
> > as number of dnat_and_snat entries increase, as reported in @Reported-at.
> >
> > This patch
> >   - reverts the approch taken in [2].
> >   - removing the flows which does the NAT direct (REGBIT_NAT_REDIRECT) to
> >     the gateway chassis.
> >   - and to solve the E/W centralized NAT it does the following:
> >      * Since for each NAT entry we know the MAC binding to be used for
> the
> >        external_ip - either the external_mac if set or the MAC of the
> >        distributed gateway router port, this patch adds the flows in the
> >        S_ROUTER_IN_ARP_RESOLVE stage to set the eth.dst to the MAC if the
> >        IP destination is external_ip.
> >      * The existing flows in the S_ROUTER_OUT_EGR_LOOP are now added by
> additional
> >        match -  is_chassis_resident('P') - where 'P' is logical_port of
> the NAT entry
> >        if set, otherwise it is the chassis resident port of distributed
> router port.
> >        With this additional match, the packet will be loopbacked to
> apply the unSNAT/DNAT
> >        rules on the relevant chassis.
> >
> > Suppose if a logical port 'P' with IP 'A' has a dnat_and_snat entry with
> external_mac/logical_port
> > set, and if the packet's IP destination is one of the DNAT IP - then the
> packet will be sent out
> > of the local chassis, since eth.dst is resolved in the
> S_ROUTER_IN_ARP_RESOLVE stage.
> > If the external_mac/logical_port is not in NAT entry, then the packet
> will be redirected to
> > the gateway chassis.
> >
> > With this patch, for the logical resource reported in @Reported-at, the
> number of logical
> > flows come down to around 45k from 650k.
> >
> > [1] - ceacd9d49316("ovn: distributed NAT flows")
> >
> > [2] - 551e3d989557("OVN: fix DVR Floating IP support")
> >       8244c6b6bd88("OVN: do not distribute traffic for local FIP")
> >
> > Reported-at:
> https://mail.openvswitch.org/pipermail/ovs-discuss/2020-January/049714.html
> > Reported-by: Daniel Alvarez Sanchez <dalvarez@redhat.com>
> > Signed-off-by: Numan Siddique <numans@ovn.org>
> > ---
> >  northd/ovn-northd.8.xml | 191 +++++++++--------------------
> >  northd/ovn-northd.c     | 264 ++++++----------------------------------
> >  tests/ovn-northd.at     |   8 +-
> >  3 files changed, 99 insertions(+), 364 deletions(-)
> >
>
> Hi Numan,
>
> The patch looks ok to me and it passes unit tests.
>
> Hi Daniel,
> As this is quite a significant change it might be nice if you could also
> try it out on your setup.
>
> Otherwise:
>
> Acked-by: Dumitru Ceara <dceara@redhat.com>
>
> Regards,
> Dumitru
>
>
Daniel Alvarez Sanchez Feb. 4, 2020, 2:06 p.m. UTC | #3
Can we please include this patch as part of the next release?

This is a really important bug fix especially on systems that have a
considerable number of floating IPs where otherwise the cloud becomes
unusable.

On Tue, Feb 4, 2020 at 2:28 PM Daniel Alvarez Sanchez <dalvarez@redhat.com>
wrote:

> Hi Numan,
>
> Thanks for this. I have deployed a setup with master branch and this patch
> applied. The patch LGTM and I can confirm that it works. Moreover, the
> number of lflows has been dramatically reduced from around 50
>
> With 150 FIPs:
>
> Before: ~70K lflows  https://imgur.com/a/OaVelCb
> After (in the same setup): 2K lflows
>
> [root@central ~]# ovn-sbctl list logical_flow | grep _uuid -c
> 2092
> [root@central ~]# ovn-sbctl list logical_flow | grep lr_out_egr_loop -c
> 155
> [root@central ~]# ovn-sbctl list logical_flow | grep lr_in_ip_routing -c
> 7
>
> And I verified that FIP to FIP traffic works via the localnet port so it
> is really distributed and does not traverse any tunnels.
>
> Thanks!
> Daniel
>
> Tested-By: Daniel Alvarez Sanchez <dalvarez@redhat.com>
> Acked-By: Daniel Alvarez Sanchez <dalvarez@redhat.com>
>
> On Tue, Feb 4, 2020 at 1:59 PM Dumitru Ceara <dceara@redhat.com> wrote:
>
>> On 2/1/20 11:53 AM, numans@ovn.org wrote:
>> > From: Numan Siddique <numans@ovn.org>
>> >
>> > When the commit [1] added Distributed NAT support in OVN, it didn't
>> address
>> > the requirement of making East/West NAT traffic distributed. The E/W NAT
>> > traffic was still centralized. Later a couple of patches [2], addressed
>> this
>> > requirement. But the approach taken in [2] resulted in a lot of logical
>> flows
>> > as number of dnat_and_snat entries increase, as reported in
>> @Reported-at.
>> >
>> > This patch
>> >   - reverts the approch taken in [2].
>> >   - removing the flows which does the NAT direct (REGBIT_NAT_REDIRECT)
>> to
>> >     the gateway chassis.
>> >   - and to solve the E/W centralized NAT it does the following:
>> >      * Since for each NAT entry we know the MAC binding to be used for
>> the
>> >        external_ip - either the external_mac if set or the MAC of the
>> >        distributed gateway router port, this patch adds the flows in the
>> >        S_ROUTER_IN_ARP_RESOLVE stage to set the eth.dst to the MAC if
>> the
>> >        IP destination is external_ip.
>> >      * The existing flows in the S_ROUTER_OUT_EGR_LOOP are now added by
>> additional
>> >        match -  is_chassis_resident('P') - where 'P' is logical_port of
>> the NAT entry
>> >        if set, otherwise it is the chassis resident port of distributed
>> router port.
>> >        With this additional match, the packet will be loopbacked to
>> apply the unSNAT/DNAT
>> >        rules on the relevant chassis.
>> >
>> > Suppose if a logical port 'P' with IP 'A' has a dnat_and_snat entry
>> with external_mac/logical_port
>> > set, and if the packet's IP destination is one of the DNAT IP - then
>> the packet will be sent out
>> > of the local chassis, since eth.dst is resolved in the
>> S_ROUTER_IN_ARP_RESOLVE stage.
>> > If the external_mac/logical_port is not in NAT entry, then the packet
>> will be redirected to
>> > the gateway chassis.
>> >
>> > With this patch, for the logical resource reported in @Reported-at, the
>> number of logical
>> > flows come down to around 45k from 650k.
>> >
>> > [1] - ceacd9d49316("ovn: distributed NAT flows")
>> >
>> > [2] - 551e3d989557("OVN: fix DVR Floating IP support")
>> >       8244c6b6bd88("OVN: do not distribute traffic for local FIP")
>> >
>> > Reported-at:
>> https://mail.openvswitch.org/pipermail/ovs-discuss/2020-January/049714.html
>> > Reported-by: Daniel Alvarez Sanchez <dalvarez@redhat.com>
>> > Signed-off-by: Numan Siddique <numans@ovn.org>
>> > ---
>> >  northd/ovn-northd.8.xml | 191 +++++++++--------------------
>> >  northd/ovn-northd.c     | 264 ++++++----------------------------------
>> >  tests/ovn-northd.at     |   8 +-
>> >  3 files changed, 99 insertions(+), 364 deletions(-)
>> >
>>
>> Hi Numan,
>>
>> The patch looks ok to me and it passes unit tests.
>>
>> Hi Daniel,
>> As this is quite a significant change it might be nice if you could also
>> try it out on your setup.
>>
>> Otherwise:
>>
>> Acked-by: Dumitru Ceara <dceara@redhat.com>
>>
>> Regards,
>> Dumitru
>>
>>
Numan Siddique Feb. 4, 2020, 3:28 p.m. UTC | #4
On Tue, Feb 4, 2020 at 7:37 PM Daniel Alvarez Sanchez
<dalvarez@redhat.com> wrote:
>
> Can we please include this patch as part of the next release?
>
> This is a really important bug fix especially on systems that have a
> considerable number of floating IPs where otherwise the cloud becomes
> unusable.

Thanks Dumitru and Daniel for the review and testing out the patch.

I applied this patch to master.

Thanks
Numan

>
> On Tue, Feb 4, 2020 at 2:28 PM Daniel Alvarez Sanchez <dalvarez@redhat.com>
> wrote:
>
> > Hi Numan,
> >
> > Thanks for this. I have deployed a setup with master branch and this patch
> > applied. The patch LGTM and I can confirm that it works. Moreover, the
> > number of lflows has been dramatically reduced from around 50
> >
> > With 150 FIPs:
> >
> > Before: ~70K lflows  https://imgur.com/a/OaVelCb
> > After (in the same setup): 2K lflows
> >
> > [root@central ~]# ovn-sbctl list logical_flow | grep _uuid -c
> > 2092
> > [root@central ~]# ovn-sbctl list logical_flow | grep lr_out_egr_loop -c
> > 155
> > [root@central ~]# ovn-sbctl list logical_flow | grep lr_in_ip_routing -c
> > 7
> >
> > And I verified that FIP to FIP traffic works via the localnet port so it
> > is really distributed and does not traverse any tunnels.
> >
> > Thanks!
> > Daniel
> >
> > Tested-By: Daniel Alvarez Sanchez <dalvarez@redhat.com>
> > Acked-By: Daniel Alvarez Sanchez <dalvarez@redhat.com>
> >
> > On Tue, Feb 4, 2020 at 1:59 PM Dumitru Ceara <dceara@redhat.com> wrote:
> >
> >> On 2/1/20 11:53 AM, numans@ovn.org wrote:
> >> > From: Numan Siddique <numans@ovn.org>
> >> >
> >> > When the commit [1] added Distributed NAT support in OVN, it didn't
> >> address
> >> > the requirement of making East/West NAT traffic distributed. The E/W NAT
> >> > traffic was still centralized. Later a couple of patches [2], addressed
> >> this
> >> > requirement. But the approach taken in [2] resulted in a lot of logical
> >> flows
> >> > as number of dnat_and_snat entries increase, as reported in
> >> @Reported-at.
> >> >
> >> > This patch
> >> >   - reverts the approch taken in [2].
> >> >   - removing the flows which does the NAT direct (REGBIT_NAT_REDIRECT)
> >> to
> >> >     the gateway chassis.
> >> >   - and to solve the E/W centralized NAT it does the following:
> >> >      * Since for each NAT entry we know the MAC binding to be used for
> >> the
> >> >        external_ip - either the external_mac if set or the MAC of the
> >> >        distributed gateway router port, this patch adds the flows in the
> >> >        S_ROUTER_IN_ARP_RESOLVE stage to set the eth.dst to the MAC if
> >> the
> >> >        IP destination is external_ip.
> >> >      * The existing flows in the S_ROUTER_OUT_EGR_LOOP are now added by
> >> additional
> >> >        match -  is_chassis_resident('P') - where 'P' is logical_port of
> >> the NAT entry
> >> >        if set, otherwise it is the chassis resident port of distributed
> >> router port.
> >> >        With this additional match, the packet will be loopbacked to
> >> apply the unSNAT/DNAT
> >> >        rules on the relevant chassis.
> >> >
> >> > Suppose if a logical port 'P' with IP 'A' has a dnat_and_snat entry
> >> with external_mac/logical_port
> >> > set, and if the packet's IP destination is one of the DNAT IP - then
> >> the packet will be sent out
> >> > of the local chassis, since eth.dst is resolved in the
> >> S_ROUTER_IN_ARP_RESOLVE stage.
> >> > If the external_mac/logical_port is not in NAT entry, then the packet
> >> will be redirected to
> >> > the gateway chassis.
> >> >
> >> > With this patch, for the logical resource reported in @Reported-at, the
> >> number of logical
> >> > flows come down to around 45k from 650k.
> >> >
> >> > [1] - ceacd9d49316("ovn: distributed NAT flows")
> >> >
> >> > [2] - 551e3d989557("OVN: fix DVR Floating IP support")
> >> >       8244c6b6bd88("OVN: do not distribute traffic for local FIP")
> >> >
> >> > Reported-at:
> >> https://mail.openvswitch.org/pipermail/ovs-discuss/2020-January/049714.html
> >> > Reported-by: Daniel Alvarez Sanchez <dalvarez@redhat.com>
> >> > Signed-off-by: Numan Siddique <numans@ovn.org>
> >> > ---
> >> >  northd/ovn-northd.8.xml | 191 +++++++++--------------------
> >> >  northd/ovn-northd.c     | 264 ++++++----------------------------------
> >> >  tests/ovn-northd.at     |   8 +-
> >> >  3 files changed, 99 insertions(+), 364 deletions(-)
> >> >
> >>
> >> Hi Numan,
> >>
> >> The patch looks ok to me and it passes unit tests.
> >>
> >> Hi Daniel,
> >> As this is quite a significant change it might be nice if you could also
> >> try it out on your setup.
> >>
> >> Otherwise:
> >>
> >> Acked-by: Dumitru Ceara <dceara@redhat.com>
> >>
> >> Regards,
> >> Dumitru
> >>
> >>
> _______________________________________________
> dev mailing list
> dev@openvswitch.org
> https://mail.openvswitch.org/mailman/listinfo/ovs-dev
>
Tomáš Sapák May 27, 2020, 1:31 p.m. UTC | #5
Hi all.
We are experiencing the issue from this thread. We have ~150000 flows, 
DVR enabled and ovn-controller and sbdb constantly running 100% CPU. 
Will this patch be backported to 2.12 branch, or do we need to upgrade 
to OVS 2.13/ OVN 20.03?
Kind regards

Tomas
Numan Siddique May 27, 2020, 1:44 p.m. UTC | #6
On Wed, May 27, 2020 at 7:07 PM Tomas Sapak <sapakt@ics.muni.cz> wrote:

> Hi all.
> We are experiencing the issue from this thread. We have ~150000 flows,
> DVR enabled and ovn-controller and sbdb constantly running 100% CPU.
> Will this patch be backported to 2.12 branch, or do we need to upgrade
> to OVS 2.13/ OVN 20.03?
>

I think we can backport to 2.12. For that we need to submit on the
openvswitch branch.
Are you OK to send a backport ? If not, I can give a try a bit later.

If you can upgrade to OVN 20.03 that would be great too. If you don't want
to upgrade
OVS to OVS2.13, you can still do so and OVN 20.03 should work with OVS 2.12
without any
issues.

Thanks
Numan


Kind regards
>
> Tomas
>
> _______________________________________________
> dev mailing list
> dev@openvswitch.org
> https://mail.openvswitch.org/mailman/listinfo/ovs-dev
>
>
Tomáš Sapák May 27, 2020, 2:10 p.m. UTC | #7
On Wed, May 27, 2020 at 3:45 PM Numan Siddique <numans@ovn.org> wrote:

>
>
> On Wed, May 27, 2020 at 7:07 PM Tomas Sapak <sapakt@ics.muni.cz> wrote:
>
>> Hi all.
>> We are experiencing the issue from this thread. We have ~150000 flows,
>> DVR enabled and ovn-controller and sbdb constantly running 100% CPU.
>> Will this patch be backported to 2.12 branch, or do we need to upgrade
>> to OVS 2.13/ OVN 20.03?
>>
>
> I think we can backport to 2.12. For that we need to submit on the
> openvswitch branch.
> Are you OK to send a backport ? If not, I can give a try a bit later.
>

I'm not C developer, but I can give it a try, since it should be just
cherry picking.


>
> If you can upgrade to OVN 20.03 that would be great too. If you don't want
> to upgrade
> OVS to OVS2.13, you can still do so and OVN 20.03 should work with OVS
> 2.12 without any
> issues.
>

I was waiting for more resources regarding upgrade/split of OVN/OVS. And
since these issues became more urgent lately, installing patches would be
probably safer solution.

Thank you.
Kind regards

Tomas


>
> Thanks
> Numan
>
>
> Kind regards
>>
>> Tomas
>>
>> _______________________________________________
>> dev mailing list
>> dev@openvswitch.org
>> https://mail.openvswitch.org/mailman/listinfo/ovs-dev
>>
>>
diff mbox series

Patch

diff --git a/northd/ovn-northd.8.xml b/northd/ovn-northd.8.xml
index 81a682fb2..a27dfa951 100644
--- a/northd/ovn-northd.8.xml
+++ b/northd/ovn-northd.8.xml
@@ -1587,6 +1587,24 @@  next;
     </p>
 
     <ul>
+      <li>
+        <p>
+          For each NAT entry of a distributed logical router  (with
+          distributed gateway router port) of type <code>snat</code>,
+          a priorirty-120 flow with the match <code>inport == <var>P</var>
+          &amp;&amp; ip4.src == <var>A</var></code> advances the packet to
+          the next pipeline, where <var>P</var> is the distributed logical
+          router port and <var>A</var> is the <code>external_ip</code> set
+          in the NAT entry. If <var>A</var> is an IPv6 address, then
+          <code>ip6.src</code> is used for the match.
+        </p>
+
+        <p>
+          The above flow is required to handle the routing of the East/west NAT
+          traffic.
+        </p>
+      </li>
+
       <li>
         <p>
           L3 admission control: A priority-100 flow drops packets that match
@@ -2099,21 +2117,6 @@  icmp6 {
           <code>redirect-chassis</code>.
         </p>
 
-        <p>
-          For each configuration in the OVN Northbound database, that asks
-          to change the source IP address of a packet from <var>A</var> to
-          <var>B</var>, a priority-50 flow matches
-          <code>ip &amp;&amp; ip4.dst == <var>B</var></code> or
-          <code>ip &amp;&amp; ip6.dst == <var>B</var></code>
-          with an action
-          <code>REGBIT_NAT_REDIRECT = 1; next;</code>.  This flow is for
-          east/west traffic to a NAT destination IPv4/IPv6 address.  By
-          setting the <code>REGBIT_NAT_REDIRECT</code> flag, in the
-          ingress table <code>Gateway Redirect</code> this will trigger a
-          redirect to the instance of the gateway port on the
-          <code>redirect-chassis</code>.
-        </p>
-
         <p>
           A priority-0 logical flow with match <code>1</code> has actions
           <code>next;</code>.
@@ -2269,20 +2272,6 @@  icmp6 {
           <code>redirect-chassis</code>.
         </p>
 
-        <p>
-          For each configuration in the OVN Northbound database, that asks
-          to change the destination IP address of a packet from <var>A</var> to
-          <var>B</var>, a priority-50 flow matches <code>ip &amp;&amp;
-          ip4.dst == <var>B</var></code> or <code>ip &amp;&amp;
-          ip6.dst == <var>B</var></code> with an action
-          <code>REGBIT_NAT_REDIRECT = 1; next;</code>.  This flow is for
-          east/west traffic to a NAT destination IPv4/IPv6 address.  By
-          setting the <code>REGBIT_NAT_REDIRECT</code> flag, in the
-          ingress table <code>Gateway Redirect</code> this will trigger a
-          redirect to the instance of the gateway port on the
-          <code>redirect-chassis</code>.
-        </p>
-
         <p>
           A priority-0 logical flow with match <code>1</code> has actions
           <code>next;</code>.
@@ -2416,54 +2405,6 @@  output;
         </p>
       </li>
 
-      <li>
-        <p>
-          For distributed logical routers where one of the logical router
-          ports specifies a <code>redirect-chassis</code>, a priority-400
-          logical flow for each ip source/destination couple that matches the
-          <code>dnat_and_snat</code> NAT rules configured. These flows will
-          allow to properly forward traffic to the external connections if
-          available and avoid sending it through the tunnel.
-          Assuming the two following NAT rules have been configured:
-        </p>
-
-        <pre>
-external_ip{0,1} = <var>EIP{0,1}</var>;
-external_mac{0,1} = <var>MAC{0,1}</var>;
-logical_ip{0,1} = <var>LIP{0,1}</var>;
-        </pre>
-
-        <p>
-            the following action will be applied:
-        </p>
-
-        <pre>
-eth.dst = <var>MAC0</var>;
-eth.src = <var>MAC1</var>;
-reg0 = ip4.dst; /* xxreg0 = ip6.dst; in the IPv6 case */
-reg1 = <var>EIP1</var>; /* xxreg1 in the IPv6 case */
-outport = <code>redirect-chassis-port</code>;
-<code>REGBIT_DISTRIBUTED_NAT = 1; next;</code>.
-        </pre>
-
-        <p>
-            Morover a priority-400 logical flow is configured for each
-            <code>dnat_and_snat</code> NAT rule configured in order to
-            not send traffic for local FIP through the overlay tunnels
-            but manage it in the local hypervisor
-        </p>
-      </li>
-
-      <li>
-        <p>
-          For distributed logical routers where one of the logical router
-          ports specifies a <code>redirect-chassis</code>, a priority-300
-          logical flow with match <code>REGBIT_NAT_REDIRECT == 1</code> has
-          actions <code>ip.ttl--; next;</code>.  The <code>outport</code>
-          will be set later in the Gateway Redirect table.
-        </p>
-      </li>
-
       <li>
         <p>
           IPv4 routing table.  For each route to IPv4 network <var>N</var> with
@@ -2630,23 +2571,6 @@  outport = <var>P</var>;
         </p>
       </li>
 
-      <li>
-        <p>
-          For distributed logical routers where one of the logical router
-          ports specifies a <code>redirect-chassis</code>, a priority-400
-          logical flow with match <code>REGBIT_DISTRIBUTED_NAT == 1</code>
-          has action <code>next;</code>
-        </p>
-        <p>
-          For distributed logical routers where one of the logical router
-          ports specifies a <code>redirect-chassis</code>, a priority-200
-          logical flow with match <code>REGBIT_NAT_REDIRECT == 1</code> has
-          actions <code>eth.dst = <var>E</var>; next;</code>, where
-          <var>E</var> is the ethernet address of the router's distributed
-          gateway port.
-        </p>
-      </li>
-
       <li>
         <p>
           Static MAC bindings.  MAC bindings can be known statically based on
@@ -2721,6 +2645,35 @@  outport = <var>P</var>;
         </p>
       </li>
 
+      <li>
+        <p>
+          Static MAC bindings from NAT entries.  MAC bindings can also be known
+          for the entries in the <code>NAT</code> table. Below flows are
+          programmed for distributed logical routers i.e with a distributed
+          router port.
+        </p>
+
+        <p>
+          For each row in the <code>NAT</code> table with IPv4 address
+          <var>A</var> in the <ref column="external_ip"
+          table="NAT" db="OVN_Northbound"/> column of
+          <ref table="NAT" db="OVN_Northbound"/> table, a priority-100
+          flow with the match <code>outport === <var>P</var> &amp;&amp;
+          reg0 == <var>A</var></code> has actions <code>eth.dst = <var>E</var>;
+          next;</code>, where <code>P</code> is the distributed logical router
+          port, <var>E</var> is the Ethernet address if set in the
+          <ref column="external_mac" table="NAT" db="OVN_Northbound"/> column
+          of <ref table="NAT" db="OVN_Northbound"/> table for of type
+          <code>dnat_and_snat</code>, otherwise the Ethernet address of the
+          distributed logical router port.
+        </p>
+
+        <p>
+          For IPv6 NAT entries, same flows are added, but using the register
+          <code>xxreg0</code> for the match.
+        </p>
+      </li>
+
       <li>
         <p>
           Dynamic MAC bindings.  These flows resolve MAC-to-IP bindings
@@ -2843,20 +2796,6 @@  icmp4 {
     </p>
 
     <ul>
-      <li>
-        A priority-300 logical flow with match
-        <code>REGBIT_DISTRIBUTED_NAT == 1</code> has action
-        <code>next;</code>
-      </li>
-      <li>
-        A priority-200 logical flow with match
-        <code>REGBIT_NAT_REDIRECT == 1</code> has actions
-        <code>outport = <var>CR</var>; next;</code>, where <var>CR</var>
-        is the <code>chassisredirect</code> port representing the instance
-        of the logical router distributed gateway port on the
-        <code>redirect-chassis</code>.
-      </li>
-
       <li>
         A priority-150 logical flow with match
         <code>outport == <var>GW</var> &amp;&amp;
@@ -3148,19 +3087,6 @@  nd_ns {
       ports specifies a <code>redirect-chassis</code>.
     </p>
 
-    <p>
-      Earlier in the ingress pipeline, some east-west traffic was
-      redirected to the <code>chassisredirect</code> port, based on
-      flows in the <code>UNSNAT</code> and <code>DNAT</code> ingress
-      tables setting the <code>REGBIT_NAT_REDIRECT</code> flag, which
-      then triggered a match to a flow in the
-      <code>Gateway Redirect</code> ingress table.  The intention was
-      not to actually send traffic out the distributed gateway port
-      instance on the <code>redirect-chassis</code>.  This traffic was
-      sent to the distributed gateway port instance in order for DNAT
-      and/or SNAT processing to be applied.
-    </p>
-
     <p>
       While UNDNAT and SNAT processing have already occurred by this
       point, this traffic needs to be forced through egress loopback on
@@ -3176,23 +3102,20 @@  nd_ns {
 
     <ul>
       <li>
-        <p>
-          For each <code>dnat_and_snat</code> NAT rule couple in the
-          OVN Northbound database on a distributed router,
-          a priority-200 logical with match
-          <code>ip4.dst == <var>external_ip0</var> &amp;&amp;
-          ip4.src == <var>external_ip1</var></code>, has action
-          <code>next;</code>
-        </p>
-
         <p>
           For each NAT rule in the OVN Northbound database on a
           distributed router, a priority-100 logical flow with match
           <code>ip4.dst == <var>E</var> &amp;&amp;
-          outport == <var>GW</var></code>, where <var>E</var> is the
-          external IP address specified in the NAT rule, and <var>GW</var>
-          is the logical router distributed gateway port, with the
-          following actions:
+          outport == <var>GW</var> &amp;&amp;
+          is_chassis_resident(<var>P</var>)</code>, where <var>E</var> is the
+          external IP address specified in the NAT rule, <var>GW</var>
+          is the logical router distributed gateway port. For dnat_and_snat
+          NAT rule, <var>P</var> is the logical port specified in the NAT rule.
+          If <ref column="logical_port"
+          table="NAT" db="OVN_Northbound"/> column of
+          <ref table="NAT" db="OVN_Northbound"/> table is NOT set, then
+          <var>P</var> is the <code>chassisredirect port</code> of
+          <var>GW</var> with the following actions:
         </p>
 
         <pre>
diff --git a/northd/ovn-northd.c b/northd/ovn-northd.c
index 2ce4f5ddb..b843226fc 100644
--- a/northd/ovn-northd.c
+++ b/northd/ovn-northd.c
@@ -215,17 +215,17 @@  enum ovn_stage {
 #define REGBIT_HAIRPIN           "reg0[6]"
 
 /* Register definitions for switches and routers. */
-#define REGBIT_NAT_REDIRECT     "reg9[0]"
+
 /* Indicate that this packet has been recirculated using egress
  * loopback.  This allows certain checks to be bypassed, such as a
  * logical router dropping packets with source IP address equals
  * one of the logical router's own IP addresses. */
-#define REGBIT_EGRESS_LOOPBACK  "reg9[1]"
-#define REGBIT_DISTRIBUTED_NAT  "reg9[2]"
+#define REGBIT_EGRESS_LOOPBACK  "reg9[0]"
 /* Register to store the result of check_pkt_larger action. */
-#define REGBIT_PKT_LARGER        "reg9[3]"
-#define REGBIT_LOOKUP_NEIGHBOR_RESULT "reg9[4]"
-#define REGBIT_SKIP_LOOKUP_NEIGHBOR "reg9[5]"
+#define REGBIT_PKT_LARGER        "reg9[1]"
+#define REGBIT_LOOKUP_NEIGHBOR_RESULT "reg9[2]"
+#define REGBIT_SKIP_LOOKUP_NEIGHBOR "reg9[3]"
+
 /* Register for ECMP bucket selection. */
 #define REG_ECMP_GROUP_ID       "reg8[0..15]"
 #define REG_ECMP_MEMBER_ID      "reg8[16..31]"
@@ -6829,128 +6829,6 @@  build_routing_policy_flow(struct hmap *lflows, struct ovn_datapath *od,
     ds_destroy(&actions);
 }
 
-static void
-add_distributed_nat_routes(struct hmap *lflows, const struct ovn_port *op)
-{
-    struct ds actions = DS_EMPTY_INITIALIZER;
-    struct ds match = DS_EMPTY_INITIALIZER;
-
-    if (!op->od->l3dgw_port) {
-        return;
-    }
-
-    if (!op->peer || !op->peer->od->nbs) {
-        return;
-    }
-
-    for (size_t i = 0; i < op->od->nbr->n_nat; i++) {
-        const struct nbrec_nat *nat = op->od->nbr->nat[i];
-        bool found = false;
-        struct eth_addr mac;
-
-        if (strcmp(nat->type, "dnat_and_snat") ||
-                !nat->external_mac ||
-                !eth_addr_from_string(nat->external_mac, &mac) ||
-                !nat->external_ip || !nat->logical_port) {
-            continue;
-        }
-
-        const struct ovn_datapath *peer_dp = op->peer->od;
-        for (size_t j = 0; j < peer_dp->nbs->n_ports; j++) {
-            if (!strcmp(peer_dp->nbs->ports[j]->name, nat->logical_port)) {
-                found = true;
-                break;
-            }
-        }
-        if (!found) {
-            continue;
-        }
-
-        /* Determine if we need to create IPv4 or IPv6 flows */
-        ovs_be32 ip;
-        struct in6_addr ipv6;
-        int family = AF_INET;
-        if (!ip_parse(nat->external_ip, &ip) || !ip) {
-            family = AF_INET6;
-            if (!ipv6_parse(nat->external_ip, &ipv6)) {
-                static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1);
-                VLOG_WARN_RL(&rl, "bad ip address %s in nat configuration "
-                             "for router %s", nat->external_ip, op->key);
-                /* We'll create IPv6 flows anyway, but the address
-                 * is probably bogus ... */
-            }
-        }
-
-        ds_put_format(&match, "inport == %s && "
-                      "ip%s.src == %s && ip%s.dst == %s",
-                       op->json_key,
-                       family == AF_INET ? "4" : "6",
-                       nat->logical_ip,
-                       family == AF_INET ? "4" : "6",
-                       nat->external_ip);
-        ds_put_format(&actions, "outport = %s; eth.dst = %s; "
-                      REGBIT_DISTRIBUTED_NAT" = 1; "
-                      REGBIT_NAT_REDIRECT" = 0; next;",
-                      op->od->l3dgw_port->json_key,
-                      nat->external_mac);
-        ovn_lflow_add(lflows, op->od, S_ROUTER_IN_IP_ROUTING, 400,
-                      ds_cstr(&match), ds_cstr(&actions));
-        ds_clear(&match);
-        ds_clear(&actions);
-
-        for (size_t j = 0; j < op->od->nbr->n_nat; j++) {
-            const struct nbrec_nat *nat2 = op->od->nbr->nat[j];
-            struct eth_addr mac2;
-
-            if (nat == nat2 || strcmp(nat2->type, "dnat_and_snat") ||
-                    !nat2->external_mac ||
-                    !eth_addr_from_string(nat2->external_mac, &mac2) ||
-                    !nat2->external_ip) {
-                continue;
-            }
-
-            family = AF_INET;
-            if (!ip_parse(nat2->external_ip, &ip) || !ip) {
-                family = AF_INET6;
-                if (!ipv6_parse(nat2->external_ip, &ipv6)) {
-                    static struct vlog_rate_limit rl =
-                        VLOG_RATE_LIMIT_INIT(5, 1);
-                    VLOG_WARN_RL(&rl, "bad ip address %s in nat configuration "
-                                 "for router %s", nat2->external_ip, op->key);
-                    /* We'll create IPv6 flows anyway, but the address
-                     * is probably bogus ... */
-                }
-            }
-
-            ds_put_format(&match, "inport == %s && "
-                          "ip%s.src == %s && ip%s.dst == %s",
-                          op->json_key,
-                          family == AF_INET ? "4" : "6",
-                          nat->logical_ip,
-                          family == AF_INET ? "4" : "6",
-                          nat2->external_ip);
-            ds_put_format(&actions, "outport = %s; "
-                          "eth.src = %s; eth.dst = %s; "
-                          "%sreg0 = ip%s.dst; %sreg1 = %s; "
-                          REGBIT_DISTRIBUTED_NAT" = 1; "
-                          REGBIT_NAT_REDIRECT" = 0; next;",
-                          op->od->l3dgw_port->json_key,
-                          op->od->l3dgw_port->lrp_networks.ea_s,
-                          nat2->external_mac,
-                          family == AF_INET ? "" : "xx",
-                          family == AF_INET ? "4" : "6",
-                          family == AF_INET ? "" : "xx",
-                          nat->external_ip);
-            ovn_lflow_add(lflows, op->od, S_ROUTER_IN_IP_ROUTING, 400,
-                          ds_cstr(&match), ds_cstr(&actions));
-            ds_clear(&match);
-            ds_clear(&actions);
-        }
-    }
-    ds_destroy(&match);
-    ds_destroy(&actions);
-}
-
 static bool
 ip46_parse_cidr(const char *str, struct v46_ip *prefix, unsigned int *plen)
 {
@@ -8688,17 +8566,6 @@  build_lrouter_flows(struct hmap *datapaths, struct hmap *ports,
 
                     ovn_lflow_add(lflows, od, S_ROUTER_IN_UNSNAT, 100,
                                   ds_cstr(&match), ds_cstr(&actions));
-
-                    /* Traffic received on other router ports must be
-                     * redirected to the central instance of the l3dgw_port
-                     * for NAT processing. */
-                    ds_clear(&match);
-                    ds_put_format(&match, "ip && ip%s.dst == %s",
-                                  is_v6 ? "6" : "4",
-                                  nat->external_ip);
-                    ovn_lflow_add(lflows, od, S_ROUTER_IN_UNSNAT, 50,
-                                  ds_cstr(&match),
-                                  REGBIT_NAT_REDIRECT" = 1; next;");
                 }
             }
 
@@ -8764,18 +8631,33 @@  build_lrouter_flows(struct hmap *datapaths, struct hmap *ports,
 
                     ovn_lflow_add(lflows, od, S_ROUTER_IN_DNAT, 100,
                                   ds_cstr(&match), ds_cstr(&actions));
+                }
+            }
 
-                    /* Traffic received on other router ports must be
-                     * redirected to the central instance of the l3dgw_port
-                     * for NAT processing. */
+            /* ARP resolve for NAT IPs. */
+            if (od->l3dgw_port) {
+                if (!strcmp(nat->type, "snat")) {
                     ds_clear(&match);
-                    ds_put_format(&match, "ip && ip%s.dst == %s",
-                                  is_v6 ? "6" : "4",
-                                  nat->external_ip);
-                    ovn_lflow_add(lflows, od, S_ROUTER_IN_DNAT, 50,
-                                  ds_cstr(&match),
-                                  REGBIT_NAT_REDIRECT" = 1; next;");
+                    ds_put_format(
+                        &match, "inport == %s && %s == %s",
+                        od->l3dgw_port->json_key,
+                        is_v6 ? "ip6.src" : "ip4.src", nat->external_ip);
+                    ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_INPUT, 120,
+                                  ds_cstr(&match), "next;");
                 }
+
+                ds_clear(&match);
+                ds_put_format(
+                    &match, "outport == %s && %s == %s",
+                    od->l3dgw_port->json_key,
+                    is_v6 ? "xxreg0" : "reg0", nat->external_ip);
+                ds_clear(&actions);
+                ds_put_format(
+                    &actions, "eth.dst = %s; next;",
+                    distributed ? nat->external_mac :
+                    od->l3dgw_port->lrp_networks.ea_s);
+                ovn_lflow_add(lflows, od, S_ROUTER_IN_ARP_RESOLVE, 100,
+                                ds_cstr(&match), ds_cstr(&actions));
             }
 
             /* Egress UNDNAT table: It is for already established connections'
@@ -8922,49 +8804,19 @@  build_lrouter_flows(struct hmap *datapaths, struct hmap *ports,
              * ingress pipeline with inport = outport. */
             if (od->l3dgw_port) {
                 /* Distributed router. */
-                if (!strcmp(nat->type, "dnat_and_snat") &&
-                        nat->external_mac && nat->external_ip &&
-                        eth_addr_from_string(nat->external_mac, &mac)) {
-                    for (int j = 0; j < od->nbr->n_nat; j++) {
-                        const struct nbrec_nat *nat2 = od->nbr->nat[j];
-
-                        if (nat2 == nat ||
-                            strcmp(nat2->type, "dnat_and_snat") ||
-                            !nat2->external_mac || !nat2->external_ip) {
-                            continue;
-                        }
-
-                        ds_clear(&match);
-                        ds_put_format(&match, "is_chassis_resident(\"%s\") && "
-                                      "ip%s.src == %s && ip%s.dst == %s",
-                                      nat->logical_port,
-                                      is_v6 ? "6" : "4", nat2->external_ip,
-                                      is_v6 ? "6" : "4", nat->external_ip);
-                        ds_clear(&actions);
-                        ds_put_format(&actions,
-                                      "inport = outport; outport = \"\"; "
-                                      "flags = 0; flags.loopback = 1; "
-                                      REGBIT_EGRESS_LOOPBACK" = 1; "
-                                      "next(pipeline=ingress, table=0); ");
-                        ovn_lflow_add(lflows, od, S_ROUTER_OUT_EGR_LOOP, 300,
-                                      ds_cstr(&match),  ds_cstr(&actions));
-
-                        ds_clear(&match);
-                        ds_put_format(&match,
-                                      "ip%s.src == %s && ip%s.dst == %s",
-                                      is_v6 ? "6" : "4", nat2->external_ip,
-                                      is_v6 ? "6" : "4", nat->external_ip);
-                        ovn_lflow_add(lflows, od, S_ROUTER_OUT_EGR_LOOP, 200,
-                                      ds_cstr(&match), "next;");
-                        ds_clear(&match);
-                    }
-                }
-
                 ds_clear(&match);
                 ds_put_format(&match, "ip%s.dst == %s && outport == %s",
                               is_v6 ? "6" : "4",
                               nat->external_ip,
                               od->l3dgw_port->json_key);
+                if (!distributed) {
+                    ds_put_format(&match, " && is_chassis_resident(%s)",
+                                  od->l3redirect_port->json_key);
+                } else {
+                    ds_put_format(&match, " && is_chassis_resident(\"%s\")",
+                                  nat->logical_port);
+                }
+
                 ds_clear(&actions);
                 ds_put_format(&actions,
                               "clone { ct_clear; "
@@ -9035,40 +8887,6 @@  build_lrouter_flows(struct hmap *datapaths, struct hmap *ports,
             * we can do it here, saving a future re-circulation. */
             ovn_lflow_add(lflows, od, S_ROUTER_IN_DNAT, 50,
                           "ip", "flags.loopback = 1; ct_dnat;");
-        } else {
-            ovn_lflow_add(lflows, od, S_ROUTER_IN_ARP_RESOLVE, 400,
-                          REGBIT_DISTRIBUTED_NAT" == 1", "next;");
-
-            /* For NAT on a distributed router, add flows to Ingress
-             * IP Routing table, Ingress ARP Resolution table, and
-             * Ingress Gateway Redirect Table that are not specific to a
-             * NAT rule. */
-
-            /* The highest priority IN_IP_ROUTING rule matches packets
-             * with REGBIT_NAT_REDIRECT (set in DNAT or UNSNAT stages),
-             * with action "ip.ttl--; next;".  The IN_GW_REDIRECT table
-             * will take care of setting the outport. */
-            ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_ROUTING, 300,
-                          REGBIT_NAT_REDIRECT" == 1", "ip.ttl--; next;");
-
-            /* The highest priority IN_ARP_RESOLVE rule matches packets
-             * with REGBIT_NAT_REDIRECT (set in DNAT or UNSNAT stages),
-             * then sets eth.dst to the distributed gateway port's
-             * ethernet address. */
-            ds_clear(&actions);
-            ds_put_format(&actions, "eth.dst = %s; next;",
-                          od->l3dgw_port->lrp_networks.ea_s);
-            ovn_lflow_add(lflows, od, S_ROUTER_IN_ARP_RESOLVE, 200,
-                          REGBIT_NAT_REDIRECT" == 1", ds_cstr(&actions));
-
-            /* The highest priority IN_GW_REDIRECT rule redirects packets
-             * with REGBIT_NAT_REDIRECT (set in DNAT or UNSNAT stages) to
-             * the central instance of the l3dgw_port for NAT processing. */
-            ds_clear(&actions);
-            ds_put_format(&actions, "outport = %s; next;",
-                          od->l3redirect_port->json_key);
-            ovn_lflow_add(lflows, od, S_ROUTER_IN_GW_REDIRECT, 200,
-                          REGBIT_NAT_REDIRECT" == 1", ds_cstr(&actions));
         }
 
         /* Load balancing and packet defrag are only valid on
@@ -9271,9 +9089,6 @@  build_lrouter_flows(struct hmap *datapaths, struct hmap *ports,
             continue;
         }
 
-        /* create logical flows for DVR floating IPs */
-        add_distributed_nat_routes(lflows, op);
-
         for (int i = 0; i < op->lrp_networks.n_ipv4_addrs; i++) {
             add_route(lflows, op, op->lrp_networks.ipv4_addrs[i].addr_s,
                       op->lrp_networks.ipv4_addrs[i].network_s,
@@ -9840,9 +9655,6 @@  build_lrouter_flows(struct hmap *datapaths, struct hmap *ports,
             continue;
         }
         if (od->l3dgw_port && od->l3redirect_port) {
-            ovn_lflow_add(lflows, od, S_ROUTER_IN_GW_REDIRECT, 300,
-                          REGBIT_DISTRIBUTED_NAT" == 1", "next;");
-
             /* For traffic with outport == l3dgw_port, if the
              * packet did not match any higher priority redirect
              * rule, then the traffic is redirected to the central
diff --git a/tests/ovn-northd.at b/tests/ovn-northd.at
index 3d4cc29f1..a2989e78e 100644
--- a/tests/ovn-northd.at
+++ b/tests/ovn-northd.at
@@ -1002,7 +1002,7 @@  echo "CR-LRP UUID is: " $uuid
 # IPV4
 ovn-nbctl lr-nat-add R1 dnat_and_snat  172.16.1.1 50.0.0.11
 
-OVS_WAIT_UNTIL([test 3 = `ovn-sbctl dump-flows R1 | grep lr_in_unsnat | \
+OVS_WAIT_UNTIL([test 2 = `ovn-sbctl dump-flows R1 | grep lr_in_unsnat | \
 wc -l`])
 
 AT_CHECK([ovn-sbctl dump-flows R1 | grep ct_snat | wc -l], [0], [2
@@ -1020,7 +1020,7 @@  AT_CHECK([ovn-sbctl dump-flows R1 | grep ip4.src=| wc -l], [0], [0
 ovn-nbctl lr-nat-del R1 dnat_and_snat  172.16.1.1
 
 ovn-nbctl --stateless lr-nat-add R1 dnat_and_snat  172.16.1.1 50.0.0.11
-OVS_WAIT_UNTIL([test 3 = `ovn-sbctl dump-flows R1 | grep lr_in_unsnat | \
+OVS_WAIT_UNTIL([test 2 = `ovn-sbctl dump-flows R1 | grep lr_in_unsnat | \
 wc -l`])
 
 AT_CHECK([ovn-sbctl dump-flows R1 | grep ct_snat | wc -l], [0], [0
@@ -1039,7 +1039,7 @@  ovn-nbctl lr-nat-del R1 dnat_and_snat  172.16.1.1
 # IPV6
 ovn-nbctl lr-nat-add R1 dnat_and_snat fd01::1 fd11::2
 
-OVS_WAIT_UNTIL([test 3 = `ovn-sbctl dump-flows R1 | grep lr_in_unsnat | \
+OVS_WAIT_UNTIL([test 2 = `ovn-sbctl dump-flows R1 | grep lr_in_unsnat | \
 wc -l`])
 
 AT_CHECK([ovn-sbctl dump-flows R1 | grep ct_snat | wc -l], [0], [2
@@ -1057,7 +1057,7 @@  AT_CHECK([ovn-sbctl dump-flows R1 | grep ip6.src=| wc -l], [0], [0
 ovn-nbctl lr-nat-del R1 dnat_and_snat  fd01::1
 ovn-nbctl --stateless lr-nat-add R1 dnat_and_snat fd01::1 fd11::2
 
-OVS_WAIT_UNTIL([test 3 = `ovn-sbctl dump-flows R1 | grep lr_in_unsnat | \
+OVS_WAIT_UNTIL([test 2 = `ovn-sbctl dump-flows R1 | grep lr_in_unsnat | \
 wc -l`])
 
 AT_CHECK([ovn-sbctl dump-flows R1 | grep ct_snat | wc -l], [0], [0