@@ -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>
+ && 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 && ip4.dst == <var>B</var></code> or
- <code>ip && 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 &&
- ip4.dst == <var>B</var></code> or <code>ip &&
- 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> &&
+ 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> &&
@@ -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> &&
- 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> &&
- 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> &&
+ 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>
@@ -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
@@ -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