FIN or FIN-ACK packets from client was dropping because the client
side was using conntrack. Connection is in SYN_SENT state because the
response from backends bypass the conntrack, when client sends a FIN
or FIN-ACK, the conntrack is invalid and packet is dropped.
To fix it, remove the client side from conntrack, calculating the hash
from packet to choice the backend.
REG_CT_TP_DST is reused to store the index from backend
because some flows the depends from conntracks use this register.
Fixes: 264c8310c399 ("northd: Fix logical router load-balancer nat rules when
using DGP.")
Signed-off-by: Lucas Vargas Dias <[email protected]>
---
northd/northd.c | 131 +++++++++++++++++++-------
tests/multinode.at | 99 ++++++++++++--------
tests/ovn-northd.at | 218 +++++++++++++++++++++++++++++++++++++++++---
3 files changed, 367 insertions(+), 81 deletions(-)
diff --git a/northd/northd.c b/northd/northd.c
index 2cb69f9aa..f7c8053dd 100644
--- a/northd/northd.c
+++ b/northd/northd.c
@@ -11955,37 +11955,13 @@ build_distr_lrouter_nat_flows_for_lb(struct
lrouter_nat_lb_flows_ctx *ctx,
bool stateless_nat)
{
struct ds dnat_action = DS_EMPTY_INITIALIZER;
+ struct ds new_action_stateless_nat = DS_EMPTY_INITIALIZER;
+ struct ds new_match_stateless_nat = DS_EMPTY_INITIALIZER;
/* Store the match lengths, so we can reuse the ds buffer. */
size_t new_match_len = ctx->new_match->length;
size_t undnat_match_len = ctx->undnat_match->length;
- /* (NOTE) dnat_action: Add the first LB backend IP as a destination
- * action of the lr_in_dnat NAT rule. Including the backend IP is useful
- * for accepting packets coming from a chassis that does not have
- * previously established conntrack entries. This means that the actions
- * (ip4.dst + ct_lb_mark) are executed in addition and ip4.dst is not
- * useful when traffic passes through the same chassis for ingress/egress
- * packets. However, the actions are complementary in cases where traffic
- * enters from one chassis, the ack response comes from another chassis,
- * and the final ack step of the TCP handshake comes from the first
- * chassis used. Without using stateless NAT, the connection will not be
- * established because the return packet followed a path through another
- * chassis and only ct_lb_mark will not be able to receive the ack and
- * forward it to the right backend. With using stateless NAT, the packet
- * will be accepted and forwarded to the same backend that corresponds to
- * the previous conntrack entry that is in the SYN_SENT state
- * (created by ct_lb_mark for the first rcv packet in this flow).
- */
- if (stateless_nat) {
- if (!vector_is_empty(&ctx->lb_vip->backends)) {
- const struct ovn_lb_backend *backend =
- vector_get_ptr(&ctx->lb_vip->backends, 0);
- bool ipv6 = !IN6_IS_ADDR_V4MAPPED(&backend->ip);
- ds_put_format(&dnat_action, "%s.dst = %s; ", ipv6 ? "ip6" : "ip4",
- backend->ip_str);
- }
- }
ds_put_format(&dnat_action, "%s", ctx->new_action[type]);
const char *meter = NULL;
@@ -11996,18 +11972,77 @@ build_distr_lrouter_nat_flows_for_lb(struct
lrouter_nat_lb_flows_ctx *ctx,
if (!vector_is_empty(&ctx->lb_vip->backends) ||
!ctx->lb_vip->empty_backend_rej) {
+ ds_put_format(&new_match_stateless_nat, "is_chassis_resident(%s)",
+ dgp->cr_port->json_key);
ds_put_format(ctx->new_match, " && is_chassis_resident(%s)",
dgp->cr_port->json_key);
}
- ovn_lflow_add_with_hint__(ctx->lflows, od, S_ROUTER_IN_DNAT, ctx->prio,
- ds_cstr(ctx->new_match), ds_cstr(&dnat_action),
- NULL, meter, &ctx->lb->nlb->header_,
- lflow_ref);
+ if (stateless_nat) {
+ bool ipv4 = ctx->lb_vip->address_family == AF_INET;
+ const char *ip_match = ipv4 ? "ip4" : "ip6";
+ ds_put_format(&new_match_stateless_nat, " && %s && %s.dst == %s",
+ ip_match, ip_match, ctx->lb_vip->vip_str);
+ if (ctx->lb_vip->port_str) {
+ ds_put_format(&new_match_stateless_nat,
+ " && %s && %s.dst == %s",
+ ctx->lb->proto, ctx->lb->proto,
+ ctx->lb_vip->port_str);
+ }
+ const struct ovn_lb_backend *backend;
+ if (vector_len(&ctx->lb_vip->backends) == 1) {
+ backend = vector_get_ptr(&ctx->lb_vip->backends, 0);
+ ds_put_format(&new_action_stateless_nat, "%s.dst = %s; ",
+ ip_match, backend->ip_str);
+ if (ctx->lb_vip->port_str) {
+ ds_put_format(&new_action_stateless_nat, "%s.dst = %s; ",
+ ctx->lb->proto, backend->port_str);
+ }
+ ds_put_format(&new_action_stateless_nat, "next;");
+ ovn_lflow_add_with_hint__(ctx->lflows, od, S_ROUTER_IN_DNAT,
+ ctx->prio,
+ ds_cstr(&new_match_stateless_nat),
+ ds_cstr(&new_action_stateless_nat),
+ NULL, meter, &ctx->lb->nlb->header_,
+ lflow_ref);
+ }
+ size_t match_len = new_match_stateless_nat.length;
+ size_t i = 0;
+ VECTOR_FOR_EACH_PTR (&ctx->lb_vip->backends, backend) {
+ if (vector_len(&ctx->lb_vip->backends) <= 1) {
+ break;
+ }
+ ds_put_format(&new_match_stateless_nat, " && "REG_CT_TP_DST" == "
+ "%"PRIuSIZE, i++);
+ ds_put_format(&new_action_stateless_nat, "%s.dst = %s; ",
+ ip_match, backend->ip_str);
+ if (ctx->lb_vip->port_str) {
+ ds_put_format(&new_action_stateless_nat, "%s.dst = %s; ",
+ ctx->lb->proto, backend->port_str);
+ }
+ ds_put_format(&new_action_stateless_nat, "next;");
+ ovn_lflow_add_with_hint__(ctx->lflows, od, S_ROUTER_IN_DNAT,
+ ctx->prio,
+ ds_cstr(&new_match_stateless_nat),
+ ds_cstr(&new_action_stateless_nat),
+ NULL, meter, &ctx->lb->nlb->header_,
+ lflow_ref);
+ ds_clear(&new_action_stateless_nat);
+ ds_truncate(&new_match_stateless_nat, match_len);
+ }
+ } else {
+ ovn_lflow_add_with_hint__(ctx->lflows, od, S_ROUTER_IN_DNAT,
+ ctx->prio, ds_cstr(ctx->new_match),
+ ds_cstr(&dnat_action), NULL, meter,
+ &ctx->lb->nlb->header_, lflow_ref);
+ }
ds_truncate(ctx->new_match, new_match_len);
ds_destroy(&dnat_action);
+ ds_destroy(&new_match_stateless_nat);
+ ds_destroy(&new_action_stateless_nat);
+
if (vector_is_empty(&ctx->lb_vip->backends)) {
return;
}
@@ -12401,21 +12436,51 @@ build_lrouter_defrag_flows_for_lb(struct
ovn_lb_datapaths *lb_dps,
if (!lb_dps->n_nb_lr) {
return;
}
+ struct ds action = DS_EMPTY_INITIALIZER;
+ struct ds values = DS_EMPTY_INITIALIZER;
+ bool use_stateless_nat = smap_get_bool(&lb_dps->lb->nlb->options,
+ "use_stateless_nat", false);
for (size_t i = 0; i < lb_dps->lb->n_vips; i++) {
struct ovn_lb_vip *lb_vip = &lb_dps->lb->vips[i];
bool ipv6 = lb_vip->address_family == AF_INET6;
int prio = 100;
-
+ enum ovn_stage stage = S_ROUTER_IN_DEFRAG;
ds_clear(match);
ds_put_format(match, "ip && ip%c.dst == %s", ipv6 ? '6' : '4',
lb_vip->vip_str);
-
+ if (use_stateless_nat) {
+ stage = S_ROUTER_IN_CT_EXTRACT;
+ prio = 120;
+ if (vector_len(&lb_vip->backends) > 1) {
+ ds_put_format(&action, REG_CT_TP_DST" = select(");
+ for (size_t idx_backend = 0; idx_backend <
+ vector_len(&lb_vip->backends); idx_backend++){
+ ds_put_format(&values, "%"PRIuSIZE",", idx_backend);
+ }
+ ds_truncate(&values, values.length - 1);
+ if (lb_dps->lb->selection_fields) {
+ ds_put_format(&action, "values=(%s); hash_fields=\"%s\"",
+ ds_cstr(&values),
+ lb_dps->lb->selection_fields);
+ } else {
+ ds_put_format(&action, "%s", ds_cstr(&values));
+ }
+ ds_put_format(&action,"); ");
+ }
+ ds_put_format(&action, "next;");
+ } else {
+ ds_put_format(&action, "ct_dnat;");
+ }
ovn_lflow_add_with_dp_group(
lflows, lb_dps->nb_lr_map, ods_size(lr_datapaths),
- S_ROUTER_IN_DEFRAG, prio, ds_cstr(match), "ct_dnat;",
+ stage, prio, ds_cstr(match), ds_cstr(&action),
&lb_dps->lb->nlb->header_, lb_dps->lflow_ref);
+ ds_clear(&action);
+ ds_clear(&values);
}
+ ds_destroy(&action);
+ ds_destroy(&values);
}
static void
diff --git a/tests/multinode.at b/tests/multinode.at
index cf748af49..25e3193f7 100644
--- a/tests/multinode.at
+++ b/tests/multinode.at
@@ -1643,6 +1643,7 @@ check multinode_nbctl ls-lb-add sw0 lb0
# Set use_stateless_nat to true
check multinode_nbctl set load_balancer lb0 options:use_stateless_nat=true
+check multinode_nbctl set load_balancer lb0
selection_fields="ip_src,tp_src,ip_dst,tp_dst"
# Start backend http services
M_NS_DAEMONIZE([ovn-chassis-1], [sw0p1], [python3 -m http.server --bind
10.0.1.3 80 >/dev/null 2>&1], [http1.pid])
@@ -1674,14 +1675,12 @@ m_as ovn-gw-2 ovs-appctl dpctl/flush-conntrack
M_NS_EXEC([ovn-chassis-3], [publicp1], [sh -c 'curl -v 172.16.0.100:80 --retry
0 --connect-timeout 1 --max-time 1 --local-port 59001'])
OVS_WAIT_FOR_OUTPUT([m_as ovn-gw-1 ovs-appctl dpctl/dump-conntrack |
M_FORMAT_CT(20.0.1.3) | \
grep tcp | sed -E -e 's/10.0.1.3|10.0.1.4/<cleared>/g' | sort], [0], [dnl
-tcp,orig=(src=20.0.1.3,dst=<cleared>,sport=59001,dport=80),reply=(src=<cleared>,dst=20.0.1.3,sport=80,dport=59001),zone=<cleared>,mark=<cleared>,protoinfo=(state=<cleared>)
tcp,orig=(src=20.0.1.3,dst=<cleared>,sport=59001,dport=80),reply=(src=<cleared>,dst=20.0.1.3,sport=80,dport=59001),zone=<cleared>,protoinfo=(state=<cleared>)
])
M_NS_EXEC([ovn-chassis-4], [publicp2], [sh -c 'curl -v 172.16.0.100:80 --retry
0 --connect-timeout 1 --max-time 1 --local-port 59000'])
OVS_WAIT_FOR_OUTPUT([m_as ovn-gw-2 ovs-appctl dpctl/dump-conntrack |
M_FORMAT_CT(30.0.1.3) | \
grep tcp | sed -E -e 's/10.0.1.3|10.0.1.4/<cleared>/g' | sort], [0], [dnl
-tcp,orig=(src=30.0.1.3,dst=<cleared>,sport=59000,dport=80),reply=(src=<cleared>,dst=30.0.1.3,sport=80,dport=59000),zone=<cleared>,mark=<cleared>,protoinfo=(state=<cleared>)
tcp,orig=(src=30.0.1.3,dst=<cleared>,sport=59000,dport=80),reply=(src=<cleared>,dst=30.0.1.3,sport=80,dport=59000),zone=<cleared>,protoinfo=(state=<cleared>)
])
@@ -1712,7 +1711,6 @@ Connected to 172.16.0.100 (172.16.0.100) port 80
# Check if we have only one backend for the same connection - orig + dest ports
OVS_WAIT_FOR_OUTPUT([echo -e $gw1_ct | M_FORMAT_CT(20.0.1.3) | \
grep tcp | sed -E -e 's/10.0.1.3|10.0.1.4/<cleared>/g' | sort], [0], [dnl
-tcp,orig=(src=20.0.1.3,dst=<cleared>,sport=59004,dport=80),reply=(src=<cleared>,dst=20.0.1.3,sport=80,dport=59004),zone=<cleared>,mark=<cleared>,protoinfo=(state=<cleared>)
tcp,orig=(src=20.0.1.3,dst=<cleared>,sport=59004,dport=80),reply=(src=<cleared>,dst=20.0.1.3,sport=80,dport=59004),zone=<cleared>,protoinfo=(state=<cleared>)
])
@@ -1778,7 +1776,6 @@ Connected to 172.16.0.100 (172.16.0.100) port 80
# Check if we have only one backend for the same connection - orig + dest ports
OVS_WAIT_FOR_OUTPUT([echo -e $gw1_ct | M_FORMAT_CT(20.0.1.3) | \
grep tcp | sed -E -e 's/10.0.1.3|10.0.1.4/<cleared>/g' | sort], [0], [dnl
-tcp,orig=(src=20.0.1.3,dst=<cleared>,sport=59005,dport=80),reply=(src=<cleared>,dst=20.0.1.3,sport=80,dport=59005),zone=<cleared>,mark=<cleared>,protoinfo=(state=<cleared>)
tcp,orig=(src=20.0.1.3,dst=<cleared>,sport=59005,dport=80),reply=(src=<cleared>,dst=20.0.1.3,sport=80,dport=59005),zone=<cleared>,protoinfo=(state=<cleared>)
])
@@ -1834,7 +1831,6 @@ Connected to 172.16.0.100 (172.16.0.100) port 80
# Check if we have only one backend for the same connection - orig + dest ports
OVS_WAIT_FOR_OUTPUT([echo -e $gw2_ct | M_FORMAT_CT(30.0.1.3) | \
grep tcp | sed -E -e 's/10.0.1.3|10.0.1.4/<cleared>/g' | sort], [0], [dnl
-tcp,orig=(src=30.0.1.3,dst=<cleared>,sport=59006,dport=80),reply=(src=<cleared>,dst=30.0.1.3,sport=80,dport=59006),zone=<cleared>,mark=<cleared>,protoinfo=(state=<cleared>)
tcp,orig=(src=30.0.1.3,dst=<cleared>,sport=59006,dport=80),reply=(src=<cleared>,dst=30.0.1.3,sport=80,dport=59006),zone=<cleared>,protoinfo=(state=<cleared>)
])
@@ -1900,7 +1896,6 @@ Connected to 172.16.0.100 (172.16.0.100) port 80
# Check if we have only one backend for the same connection - orig + dest ports
OVS_WAIT_FOR_OUTPUT([echo -e $gw2_ct | M_FORMAT_CT(30.0.1.3) | \
grep tcp | sed -E -e 's/10.0.1.3|10.0.1.4/<cleared>/g' | sort], [0], [dnl
-tcp,orig=(src=30.0.1.3,dst=<cleared>,sport=59007,dport=80),reply=(src=<cleared>,dst=30.0.1.3,sport=80,dport=59007),zone=<cleared>,mark=<cleared>,protoinfo=(state=<cleared>)
tcp,orig=(src=30.0.1.3,dst=<cleared>,sport=59007,dport=80),reply=(src=<cleared>,dst=30.0.1.3,sport=80,dport=59007),zone=<cleared>,protoinfo=(state=<cleared>)
])
@@ -1987,7 +1982,6 @@ M_NS_EXEC([ovn-chassis-3], [publicp1], [sh -c 'curl -v -O
172.16.0.100:9000/down
OVS_WAIT_FOR_OUTPUT([m_as ovn-gw-1 ovs-appctl dpctl/dump-conntrack |
M_FORMAT_CT(20.0.1.3) | \
grep tcp | sed -E -e 's/10.0.1.3|10.0.1.4/<cleared>/g' | sort], [0], [dnl
tcp,orig=(src=20.0.1.3,dst=<cleared>,sport=59008,dport=80),reply=(src=<cleared>,dst=20.0.1.3,sport=80,dport=59008),zone=<cleared>,protoinfo=(state=<cleared>)
-tcp,orig=(src=20.0.1.3,dst=<cleared>,sport=59008,dport=9000),reply=(src=<cleared>,dst=20.0.1.3,sport=80,dport=59008),zone=<cleared>,mark=<cleared>,protoinfo=(state=<cleared>)
])
OVS_WAIT_FOR_OUTPUT([m_as ovn-chassis-3 cat -v curl.out |
M_FORMAT_CURL([172.16.0.100], [9000])], [0], [dnl
@@ -2003,7 +1997,6 @@ M_NS_EXEC([ovn-chassis-4], [publicp2], [sh -c 'curl -v -O
172.16.0.100:9000/down
OVS_WAIT_FOR_OUTPUT([m_as ovn-gw-2 ovs-appctl dpctl/dump-conntrack |
M_FORMAT_CT(30.0.1.3) | \
grep tcp | sed -E -e 's/10.0.1.3|10.0.1.4/<cleared>/g' | sort], [0], [dnl
tcp,orig=(src=30.0.1.3,dst=<cleared>,sport=59008,dport=80),reply=(src=<cleared>,dst=30.0.1.3,sport=80,dport=59008),zone=<cleared>,protoinfo=(state=<cleared>)
-tcp,orig=(src=30.0.1.3,dst=<cleared>,sport=59008,dport=9000),reply=(src=<cleared>,dst=30.0.1.3,sport=80,dport=59008),zone=<cleared>,mark=<cleared>,protoinfo=(state=<cleared>)
])
OVS_WAIT_FOR_OUTPUT([m_as ovn-chassis-3 cat -v curl.out |
M_FORMAT_CURL([172.16.0.100], [9000])], [0], [dnl
@@ -2036,14 +2029,14 @@ done
# |
#
+.............................|.............................+
# |
|
-# DGP publicp3 (ovn-gw-3) (20.0.2.3/24) DGP publicp4
(ovn-gw-4) (20.0.2.4/24)
+# DGP publicp3 (ovn-gw-3) (20.0.1.2/24) DGP publicp4
(ovn-gw-4) (20.0.2.4/24)
# |
|
#
+.............................+.............................+
-# |
-# | (overlay)
+# |
|
+# | (public_right)
(public_left)|
#
+.............................+.............................+
# |
|
-# DGP public1 (ovn-gw-1) (20.0.2.1/24) DGP public2
(ovn-gw-2) (20.0.2.2/24)
+# DGP public1 (ovn-gw-1) (20.0.1.1/24) DGP public2
(ovn-gw-2) (20.0.2.2/24)
# |
|
#
+.............................+.............................+
# |
@@ -2100,17 +2093,18 @@ check multinode_nbctl lsp-set-addresses sw0-lr0 router
check multinode_nbctl lsp-set-options sw0-lr0 router-port=lr0-sw0
# create external connection for N/S traffic using multiple DGPs
-check multinode_nbctl ls-add public
+check multinode_nbctl ls-add public_right
+check multinode_nbctl ls-add public_left
# create external connection for N/S traffic
# DGP public1
-check multinode_nbctl lsp-add public ln-public-1
+check multinode_nbctl lsp-add public_right ln-public-1
check multinode_nbctl lsp-set-type ln-public-1 localnet
check multinode_nbctl lsp-set-addresses ln-public-1 unknown
check multinode_nbctl lsp-set-options ln-public-1 network_name=public1
# DGP public2
-check multinode_nbctl lsp-add public ln-public-2
+check multinode_nbctl lsp-add public_left ln-public-2
check multinode_nbctl lsp-set-type ln-public-2 localnet
check multinode_nbctl lsp-set-addresses ln-public-2 unknown
check multinode_nbctl lsp-set-options ln-public-2 network_name=public2
@@ -2121,8 +2115,8 @@ m_as ovn-gw-1 ovs-vsctl set open .
external-ids:ovn-bridge-mappings=public1:br-e
# Attach DGP public2 to GW-2 public2 (overlay connectivity)
m_as ovn-gw-2 ovs-vsctl set open .
external-ids:ovn-bridge-mappings=public2:br-ex
-check multinode_nbctl lrp-add lr0 lr0-public-p1 40:54:00:00:00:01 20.0.2.1/24
2000::1/64
-check multinode_nbctl lsp-add public public-lr0-p1
+check multinode_nbctl lrp-add lr0 lr0-public-p1 40:54:00:00:00:01 20.0.1.1/24
2000::1/64
+check multinode_nbctl lsp-add public_right public-lr0-p1
check multinode_nbctl lsp-set-type public-lr0-p1 router
check multinode_nbctl lsp-set-addresses public-lr0-p1 router
check multinode_nbctl lsp-set-options public-lr0-p1 router-port=lr0-public-p1
@@ -2130,13 +2124,13 @@ check multinode_nbctl lrp-set-gateway-chassis
lr0-public-p1 ovn-gw-1 10
m_wait_for_ports_up
-M_NS_CHECK_EXEC([ovn-chassis-1], [sw0p1], [ping -q -c 3 -i 0.3 -w 2 20.0.2.1 |
FORMAT_PING], \
+M_NS_CHECK_EXEC([ovn-chassis-1], [sw0p1], [ping -q -c 3 -i 0.3 -w 2 20.0.1.1 |
FORMAT_PING], \
[0], [dnl
3 packets transmitted, 3 received, 0% packet loss, time 0ms
])
check multinode_nbctl lrp-add lr0 lr0-public-p2 40:54:00:00:00:02 20.0.2.2/24
2000::2/64
-check multinode_nbctl lsp-add public public-lr0-p2
+check multinode_nbctl lsp-add public_left public-lr0-p2
check multinode_nbctl lsp-set-type public-lr0-p2 router
check multinode_nbctl lsp-set-addresses public-lr0-p2 router
check multinode_nbctl lsp-set-options public-lr0-p2 router-port=lr0-public-p2
@@ -2157,7 +2151,7 @@ check multinode_nbctl lsp-set-options sw1-lr1
router-port=lr1-sw1
# create external connection for N/S traffic
# DGP public3
-check multinode_nbctl lsp-add public ln-public-3
+check multinode_nbctl lsp-add public_right ln-public-3
check multinode_nbctl lsp-set-type ln-public-3 localnet
check multinode_nbctl lsp-set-addresses ln-public-3 unknown
check multinode_nbctl lsp-set-options ln-public-3 network_name=public3
@@ -2165,8 +2159,8 @@ check multinode_nbctl lsp-set-options ln-public-3
network_name=public3
# Attach DGP public3 to GW-3 public3 (overlay connectivity)
m_as ovn-gw-3 ovs-vsctl set open .
external-ids:ovn-bridge-mappings=public3:br-ex
-check multinode_nbctl lrp-add lr1 lr1-public-p3 40:54:00:00:00:03 20.0.2.3/24
2000::3/64
-check multinode_nbctl lsp-add public public-lr1-p3
+check multinode_nbctl lrp-add lr1 lr1-public-p3 40:54:00:00:00:03 20.0.1.2/24
2000::3/64
+check multinode_nbctl lsp-add public_right public-lr1-p3
check multinode_nbctl lsp-set-type public-lr1-p3 router
check multinode_nbctl lsp-set-addresses public-lr1-p3 router
check multinode_nbctl lsp-set-options public-lr1-p3 router-port=lr1-public-p3
@@ -2177,21 +2171,16 @@ M_NS_CHECK_EXEC([ovn-chassis-3], [sw1p1], [ping -q -c 3
-i 0.3 -w 2 40.0.2.1 | F
3 packets transmitted, 3 received, 0% packet loss, time 0ms
])
-M_NS_CHECK_EXEC([ovn-chassis-3], [sw1p1], [ping -q -c 3 -i 0.3 -w 2 20.0.2.3 |
FORMAT_PING], \
+M_NS_CHECK_EXEC([ovn-chassis-3], [sw1p1], [ping -q -c 3 -i 0.3 -w 2 20.0.1.2 |
FORMAT_PING], \
[0], [dnl
3 packets transmitted, 3 received, 0% packet loss, time 0ms
])
# Add a default route for multiple DGPs using ECMP - first step
-check multinode_nbctl --ecmp lr-route-add lr0 0.0.0.0/0 20.0.2.3
-check multinode_nbctl --ecmp lr-route-add lr1 0.0.0.0/0 20.0.2.1
-
-# Add SNAT rules using gateway-port
-check multinode_nbctl --gateway-port lr0-public-p1 lr-nat-add lr0 snat
20.0.2.1 10.0.2.0/24
-check multinode_nbctl --gateway-port lr0-public-p2 lr-nat-add lr0 snat
20.0.2.2 10.0.2.0/24
-check multinode_nbctl --gateway-port lr1-public-p3 lr-nat-add lr1 snat
20.0.2.3 40.0.2.0/24
+check multinode_nbctl --ecmp lr-route-add lr0 0.0.0.0/0 20.0.1.2
+check multinode_nbctl --ecmp lr-route-add lr1 0.0.0.0/0 20.0.1.1
-M_NS_CHECK_EXEC([ovn-chassis-3], [sw1p1], [ping -q -c 3 -i 0.3 -w 2 20.0.2.1 |
FORMAT_PING], \
+M_NS_CHECK_EXEC([ovn-chassis-3], [sw1p1], [ping -q -c 3 -i 0.3 -w 2 20.0.1.1 |
FORMAT_PING], \
[0], [dnl
3 packets transmitted, 3 received, 0% packet loss, time 0ms
])
@@ -2203,7 +2192,7 @@ M_NS_CHECK_EXEC([ovn-chassis-3], [sw1p1], [ping -q -c 3
-i 0.3 -w 2 20.0.2.2 | F
# Configure the second DGP for the lr1
# DGP public4
-check multinode_nbctl lsp-add public ln-public-4
+check multinode_nbctl lsp-add public_left ln-public-4
check multinode_nbctl lsp-set-type ln-public-4 localnet
check multinode_nbctl lsp-set-addresses ln-public-4 unknown
check multinode_nbctl lsp-set-options ln-public-4 network_name=public4
@@ -2212,7 +2201,7 @@ check multinode_nbctl lsp-set-options ln-public-4
network_name=public4
m_as ovn-gw-4 ovs-vsctl set open .
external-ids:ovn-bridge-mappings=public4:br-ex
check multinode_nbctl lrp-add lr1 lr1-public-p4 40:54:00:00:00:04 20.0.2.4/24
2000::4/64
-check multinode_nbctl lsp-add public public-lr1-p4
+check multinode_nbctl lsp-add public_left public-lr1-p4
check multinode_nbctl lsp-set-type public-lr1-p4 router
check multinode_nbctl lsp-set-addresses public-lr1-p4 router
check multinode_nbctl lsp-set-options public-lr1-p4 router-port=lr1-public-p4
@@ -2223,9 +2212,6 @@ M_NS_CHECK_EXEC([ovn-chassis-3], [sw1p1], [ping -q -c 3
-i 0.3 -w 2 20.0.2.4 | F
3 packets transmitted, 3 received, 0% packet loss, time 0ms
])
-# Add SNAT rules using gateway-port
-check multinode_nbctl --gateway-port lr1-public-p4 lr-nat-add lr1 snat
20.0.2.4 40.0.2.0/24
-
# Add a default route for multiple DGPs using ECMP - second step (multipath)
check multinode_nbctl --ecmp lr-route-add lr0 0.0.0.0/0 20.0.2.4
check multinode_nbctl --ecmp lr-route-add lr1 0.0.0.0/0 20.0.2.2
@@ -2359,36 +2345,77 @@ fi
# Set use_stateless_nat to true
# Now, if the traffic passes through both gateways (GW-1 and GW-2) it will be
forwarded successfully
check multinode_nbctl set load_balancer lb0 options:use_stateless_nat=true
+check multinode_nbctl --wait=sb set load_balancer lb0
selection_fields="ip_src,tp_src,ip_dst,tp_dst"
# Check the flows again for the LB VIP - always needs to be successful
regardless of the datapath (one or two gw chassis)
M_NS_EXEC([ovn-chassis-3], [sw1p1], [sh -c 'curl -v -O
172.16.0.100:80/download_file --retry 0 --connect-timeout 1 --max-time 1
2>curl.out'])
+M_NS_EXEC([ovn-chassis-1], [sw0p1], [sh -c 'ss -nn >connections.out'])
+M_NS_EXEC([ovn-chassis-2], [sw0p2], [sh -c 'ss -nn >connections.out'])
OVS_WAIT_FOR_OUTPUT([m_as ovn-chassis-3 cat -v curl.out |
M_FORMAT_CURL([172.16.0.100], [80])], [0], [dnl
Connected to 172.16.0.100 (172.16.0.100) port 80
200 OK
])
+OVS_WAIT_FOR_OUTPUT([m_as ovn-chassis-1 cat connections.out | grep
"FIN-WAIT-2" | wc -l], [0], [dnl
+0
+])
+
+OVS_WAIT_FOR_OUTPUT([m_as ovn-chassis-2 cat connections.out | grep
"FIN-WAIT-2" | wc -l], [0], [dnl
+0
+])
+
M_NS_EXEC([ovn-chassis-3], [sw1p1], [sh -c 'curl -v -O
172.16.0.100:80/download_file --retry 0 --connect-timeout 1 --max-time 1
2>curl.out'])
+M_NS_EXEC([ovn-chassis-1], [sw0p1], [sh -c 'ss -nn >connections.out'])
+M_NS_EXEC([ovn-chassis-2], [sw0p2], [sh -c 'ss -nn >connections.out'])
OVS_WAIT_FOR_OUTPUT([m_as ovn-chassis-3 cat -v curl.out |
M_FORMAT_CURL([172.16.0.100], [80])], [0], [dnl
Connected to 172.16.0.100 (172.16.0.100) port 80
200 OK
])
+OVS_WAIT_FOR_OUTPUT([m_as ovn-chassis-1 cat connections.out | grep
"FIN-WAIT-2" | wc -l], [0], [dnl
+0
+])
+
+OVS_WAIT_FOR_OUTPUT([m_as ovn-chassis-2 cat connections.out | grep
"FIN-WAIT-2" | wc -l], [0], [dnl
+0
+])
+
M_NS_EXEC([ovn-chassis-3], [sw1p1], [sh -c 'curl -v -O
172.16.0.100:80/download_file --retry 0 --connect-timeout 1 --max-time 1
2>curl.out'])
+M_NS_EXEC([ovn-chassis-1], [sw0p1], [sh -c 'ss -nn >connections.out'])
+M_NS_EXEC([ovn-chassis-2], [sw0p2], [sh -c 'ss -nn >connections.out'])
OVS_WAIT_FOR_OUTPUT([m_as ovn-chassis-3 cat -v curl.out |
M_FORMAT_CURL([172.16.0.100], [80])], [0], [dnl
Connected to 172.16.0.100 (172.16.0.100) port 80
200 OK
])
+OVS_WAIT_FOR_OUTPUT([m_as ovn-chassis-1 cat connections.out | grep
"FIN-WAIT-2" | wc -l], [0], [dnl
+0
+])
+
+OVS_WAIT_FOR_OUTPUT([m_as ovn-chassis-2 cat connections.out | grep
"FIN-WAIT-2" | wc -l], [0], [dnl
+0
+])
+
M_NS_EXEC([ovn-chassis-3], [sw1p1], [sh -c 'curl -v -O
172.16.0.100:80/download_file --retry 0 --connect-timeout 1 --max-time 1
2>curl.out'])
+M_NS_EXEC([ovn-chassis-1], [sw0p1], [sh -c 'ss -nn >connections.out'])
+M_NS_EXEC([ovn-chassis-2], [sw0p2], [sh -c 'ss -nn >connections.out'])
OVS_WAIT_FOR_OUTPUT([m_as ovn-chassis-3 cat -v curl.out |
M_FORMAT_CURL([172.16.0.100], [80])], [0], [dnl
Connected to 172.16.0.100 (172.16.0.100) port 80
200 OK
])
+OVS_WAIT_FOR_OUTPUT([m_as ovn-chassis-1 cat connections.out | grep
"FIN-WAIT-2" | wc -l], [0], [dnl
+0
+])
+
+OVS_WAIT_FOR_OUTPUT([m_as ovn-chassis-2 cat connections.out | grep
"FIN-WAIT-2" | wc -l], [0], [dnl
+0
+])
+
# Direct backend traffic using the same LB ports needs to be dropped
M_NS_EXEC([ovn-chassis-3], [sw1p1], [sh -c 'curl -v -O
10.0.2.3:80/download_file --retry 0 --connect-timeout 1 --max-time 1
2>curl.out'])
diff --git a/tests/ovn-northd.at b/tests/ovn-northd.at
index 05acd6f4d..cebf9d6ba 100644
--- a/tests/ovn-northd.at
+++ b/tests/ovn-northd.at
@@ -14331,14 +14331,66 @@ ovn-sbctl dump-flows lr1 > lr1flows
AT_CAPTURE_FILE([lr1flows])
# Check stateless NAT rules for load balancer with multiple DGP
-# 1. Check if the backend IPs are in the ipX.dst action
+# 1. Check if the reg1[0..15] will select one of backends
+AT_CHECK([grep "lr_in_ct_extract" lr1flows | ovn_strip_lflows | grep
"30.0.0.1"], [0], [dnl
+ table=??(lr_in_ct_extract ), priority=120 , match=(ip && ip4.dst ==
30.0.0.1), action=(reg1[[0..15]] = select(0,1,2); next;)
+])
+
+# 2. Check if the backend IPs are in the ipX.dst action
AT_CHECK([grep "lr_in_dnat" lr1flows | ovn_strip_lflows | grep "30.0.0.1"],
[0], [dnl
- table=??(lr_in_dnat ), priority=110 , match=(ct.new && !ct.rel &&
ip4 && ip4.dst == 30.0.0.1 && is_chassis_resident("cr-lr1-ts1")),
action=(ip4.dst = 172.16.0.103;
ct_lb_mark(backends=172.16.0.103,172.16.0.102,172.16.0.101);)
- table=??(lr_in_dnat ), priority=110 , match=(ct.new && !ct.rel &&
ip4 && ip4.dst == 30.0.0.1 && is_chassis_resident("cr-lr1-ts2")),
action=(ip4.dst = 172.16.0.103;
ct_lb_mark(backends=172.16.0.103,172.16.0.102,172.16.0.101);)
- table=??(lr_in_dnat ), priority=110 , match=(ct.new && !ct.rel &&
ip4 && ip4.dst == 30.0.0.1 && is_chassis_resident("cr-lr1_public")),
action=(ip4.dst = 172.16.0.103;
ct_lb_mark(backends=172.16.0.103,172.16.0.102,172.16.0.101);)
+ table=??(lr_in_dnat ), priority=110 ,
match=(is_chassis_resident("cr-lr1-ts1") && ip4 && ip4.dst == 30.0.0.1 &&
reg1[[0..15]] == 0), action=(ip4.dst = 172.16.0.103; next;)
+ table=??(lr_in_dnat ), priority=110 ,
match=(is_chassis_resident("cr-lr1-ts1") && ip4 && ip4.dst == 30.0.0.1 &&
reg1[[0..15]] == 1), action=(ip4.dst = 172.16.0.102; next;)
+ table=??(lr_in_dnat ), priority=110 ,
match=(is_chassis_resident("cr-lr1-ts1") && ip4 && ip4.dst == 30.0.0.1 &&
reg1[[0..15]] == 2), action=(ip4.dst = 172.16.0.101; next;)
+ table=??(lr_in_dnat ), priority=110 ,
match=(is_chassis_resident("cr-lr1-ts2") && ip4 && ip4.dst == 30.0.0.1 &&
reg1[[0..15]] == 0), action=(ip4.dst = 172.16.0.103; next;)
+ table=??(lr_in_dnat ), priority=110 ,
match=(is_chassis_resident("cr-lr1-ts2") && ip4 && ip4.dst == 30.0.0.1 &&
reg1[[0..15]] == 1), action=(ip4.dst = 172.16.0.102; next;)
+ table=??(lr_in_dnat ), priority=110 ,
match=(is_chassis_resident("cr-lr1-ts2") && ip4 && ip4.dst == 30.0.0.1 &&
reg1[[0..15]] == 2), action=(ip4.dst = 172.16.0.101; next;)
+ table=??(lr_in_dnat ), priority=110 ,
match=(is_chassis_resident("cr-lr1_public") && ip4 && ip4.dst == 30.0.0.1 &&
reg1[[0..15]] == 0), action=(ip4.dst = 172.16.0.103; next;)
+ table=??(lr_in_dnat ), priority=110 ,
match=(is_chassis_resident("cr-lr1_public") && ip4 && ip4.dst == 30.0.0.1 &&
reg1[[0..15]] == 1), action=(ip4.dst = 172.16.0.102; next;)
+ table=??(lr_in_dnat ), priority=110 ,
match=(is_chassis_resident("cr-lr1_public") && ip4 && ip4.dst == 30.0.0.1 &&
reg1[[0..15]] == 2), action=(ip4.dst = 172.16.0.101; next;)
+])
+
+# 3. Check if the DGP ports are in the match with action next
+AT_CHECK([grep "lr_out_undnat" lr1flows | ovn_strip_lflows], [0], [dnl
+ table=??(lr_out_undnat ), priority=0 , match=(1), action=(next;)
+ table=??(lr_out_undnat ), priority=120 , match=(ip4 && ((ip4.src ==
172.16.0.103) || (ip4.src == 172.16.0.102) || (ip4.src == 172.16.0.101)) &&
(inport == "lr1-ts1" || outport == "lr1-ts1") &&
is_chassis_resident("cr-lr1-ts1") && tcp), action=(next;)
+ table=??(lr_out_undnat ), priority=120 , match=(ip4 && ((ip4.src ==
172.16.0.103) || (ip4.src == 172.16.0.102) || (ip4.src == 172.16.0.101)) &&
(inport == "lr1-ts2" || outport == "lr1-ts2") &&
is_chassis_resident("cr-lr1-ts2") && tcp), action=(next;)
+ table=??(lr_out_undnat ), priority=120 , match=(ip4 && ((ip4.src ==
172.16.0.103) || (ip4.src == 172.16.0.102) || (ip4.src == 172.16.0.101)) &&
(inport == "lr1_public" || outport == "lr1_public") &&
is_chassis_resident("cr-lr1_public") && tcp), action=(next;)
])
-# 2. Check if the DGP ports are in the match with action next
+# 4. Check if the VIP IP is in the ipX.src action
+AT_CHECK([grep "lr_out_snat" lr1flows | ovn_strip_lflows], [0], [dnl
+ table=??(lr_out_snat ), priority=0 , match=(1), action=(next;)
+ table=??(lr_out_snat ), priority=120 , match=(nd_ns), action=(next;)
+ table=??(lr_out_snat ), priority=160 , match=(ip4 && ((ip4.src ==
172.16.0.103) || (ip4.src == 172.16.0.102) || (ip4.src == 172.16.0.101)) &&
(inport == "lr1-ts1" || outport == "lr1-ts1") &&
is_chassis_resident("cr-lr1-ts1") && tcp), action=(ip4.src = 30.0.0.1; next;)
+ table=??(lr_out_snat ), priority=160 , match=(ip4 && ((ip4.src ==
172.16.0.103) || (ip4.src == 172.16.0.102) || (ip4.src == 172.16.0.101)) &&
(inport == "lr1-ts2" || outport == "lr1-ts2") &&
is_chassis_resident("cr-lr1-ts2") && tcp), action=(ip4.src = 30.0.0.1; next;)
+ table=??(lr_out_snat ), priority=160 , match=(ip4 && ((ip4.src ==
172.16.0.103) || (ip4.src == 172.16.0.102) || (ip4.src == 172.16.0.101)) &&
(inport == "lr1_public" || outport == "lr1_public") &&
is_chassis_resident("cr-lr1_public") && tcp), action=(ip4.src = 30.0.0.1; next;)
+])
+
+# Set selection fields
+check ovn-nbctl --wait=sb set load_balancer lb1
selection_fields="ip_src,tp_src,ip_dst,tp_dst"
+
+ovn-sbctl dump-flows lr1 > lr1flows
+AT_CAPTURE_FILE([lr1flows])
+
+# 1. Check if the reg1[0..15] will select one of backends using hash_fields
+AT_CHECK([grep "lr_in_ct_extract" lr1flows | ovn_strip_lflows | grep
"30.0.0.1"], [0], [dnl
+ table=??(lr_in_ct_extract ), priority=120 , match=(ip && ip4.dst ==
30.0.0.1), action=(reg1[[0..15]] = select(values=(0,1,2);
hash_fields="ip_dst,ip_src,tcp_dst,tcp_src"); next;)
+])
+
+# 2. Check if the backend IPs are in the ipX.dst action
+AT_CHECK([grep "lr_in_dnat" lr1flows | ovn_strip_lflows | grep "30.0.0.1"],
[0], [dnl
+ table=??(lr_in_dnat ), priority=110 ,
match=(is_chassis_resident("cr-lr1-ts1") && ip4 && ip4.dst == 30.0.0.1 &&
reg1[[0..15]] == 0), action=(ip4.dst = 172.16.0.103; next;)
+ table=??(lr_in_dnat ), priority=110 ,
match=(is_chassis_resident("cr-lr1-ts1") && ip4 && ip4.dst == 30.0.0.1 &&
reg1[[0..15]] == 1), action=(ip4.dst = 172.16.0.102; next;)
+ table=??(lr_in_dnat ), priority=110 ,
match=(is_chassis_resident("cr-lr1-ts1") && ip4 && ip4.dst == 30.0.0.1 &&
reg1[[0..15]] == 2), action=(ip4.dst = 172.16.0.101; next;)
+ table=??(lr_in_dnat ), priority=110 ,
match=(is_chassis_resident("cr-lr1-ts2") && ip4 && ip4.dst == 30.0.0.1 &&
reg1[[0..15]] == 0), action=(ip4.dst = 172.16.0.103; next;)
+ table=??(lr_in_dnat ), priority=110 ,
match=(is_chassis_resident("cr-lr1-ts2") && ip4 && ip4.dst == 30.0.0.1 &&
reg1[[0..15]] == 1), action=(ip4.dst = 172.16.0.102; next;)
+ table=??(lr_in_dnat ), priority=110 ,
match=(is_chassis_resident("cr-lr1-ts2") && ip4 && ip4.dst == 30.0.0.1 &&
reg1[[0..15]] == 2), action=(ip4.dst = 172.16.0.101; next;)
+ table=??(lr_in_dnat ), priority=110 ,
match=(is_chassis_resident("cr-lr1_public") && ip4 && ip4.dst == 30.0.0.1 &&
reg1[[0..15]] == 0), action=(ip4.dst = 172.16.0.103; next;)
+ table=??(lr_in_dnat ), priority=110 ,
match=(is_chassis_resident("cr-lr1_public") && ip4 && ip4.dst == 30.0.0.1 &&
reg1[[0..15]] == 1), action=(ip4.dst = 172.16.0.102; next;)
+ table=??(lr_in_dnat ), priority=110 ,
match=(is_chassis_resident("cr-lr1_public") && ip4 && ip4.dst == 30.0.0.1 &&
reg1[[0..15]] == 2), action=(ip4.dst = 172.16.0.101; next;)
+])
+
+# 3. Check if the DGP ports are in the match with action next
AT_CHECK([grep "lr_out_undnat" lr1flows | ovn_strip_lflows], [0], [dnl
table=??(lr_out_undnat ), priority=0 , match=(1), action=(next;)
table=??(lr_out_undnat ), priority=120 , match=(ip4 && ((ip4.src ==
172.16.0.103) || (ip4.src == 172.16.0.102) || (ip4.src == 172.16.0.101)) &&
(inport == "lr1-ts1" || outport == "lr1-ts1") &&
is_chassis_resident("cr-lr1-ts1") && tcp), action=(next;)
@@ -14346,7 +14398,7 @@ AT_CHECK([grep "lr_out_undnat" lr1flows |
ovn_strip_lflows], [0], [dnl
table=??(lr_out_undnat ), priority=120 , match=(ip4 && ((ip4.src ==
172.16.0.103) || (ip4.src == 172.16.0.102) || (ip4.src == 172.16.0.101)) &&
(inport == "lr1_public" || outport == "lr1_public") &&
is_chassis_resident("cr-lr1_public") && tcp), action=(next;)
])
-# 3. Check if the VIP IP is in the ipX.src action
+# 4. Check if the VIP IP is in the ipX.src action
AT_CHECK([grep "lr_out_snat" lr1flows | ovn_strip_lflows], [0], [dnl
table=??(lr_out_snat ), priority=0 , match=(1), action=(next;)
table=??(lr_out_snat ), priority=120 , match=(nd_ns), action=(next;)
@@ -14355,6 +14407,51 @@ AT_CHECK([grep "lr_out_snat" lr1flows |
ovn_strip_lflows], [0], [dnl
table=??(lr_out_snat ), priority=160 , match=(ip4 && ((ip4.src ==
172.16.0.103) || (ip4.src == 172.16.0.102) || (ip4.src == 172.16.0.101)) &&
(inport == "lr1_public" || outport == "lr1_public") &&
is_chassis_resident("cr-lr1_public") && tcp), action=(ip4.src = 30.0.0.1; next;)
])
+# Delete LB and create with one backend
+check ovn-nbctl --wait=sb lb-del lb1
+check ovn-nbctl --wait=sb lb-add lb1 "30.0.0.1" "172.16.0.103"
+
+# Set use_stateless_nat to true
+check ovn-nbctl --wait=sb set load_balancer lb1 options:use_stateless_nat=true
+
+# Associate load balancer to s1
+check ovn-nbctl ls-lb-add s1 lb1
+check ovn-nbctl lr-lb-add lr1 lb1
+check ovn-nbctl --wait=sb sync
+
+ovn-sbctl dump-flows lr1 > lr1flows
+AT_CAPTURE_FILE([lr1flows])
+
+# 1. Check if the reg1[0..15] will select one of backends using hash_fields
+AT_CHECK([grep "lr_in_ct_extract" lr1flows | ovn_strip_lflows | grep
"30.0.0.1"], [0], [dnl
+ table=??(lr_in_ct_extract ), priority=120 , match=(ip && ip4.dst ==
30.0.0.1), action=(next;)
+])
+
+# 2. Check if the backend IPs are in the ipX.dst action
+AT_CHECK([grep "lr_in_dnat" lr1flows | ovn_strip_lflows | grep "30.0.0.1"],
[0], [dnl
+ table=??(lr_in_dnat ), priority=110 ,
match=(is_chassis_resident("cr-lr1-ts1") && ip4 && ip4.dst == 30.0.0.1),
action=(ip4.dst = 172.16.0.103; next;)
+ table=??(lr_in_dnat ), priority=110 ,
match=(is_chassis_resident("cr-lr1-ts2") && ip4 && ip4.dst == 30.0.0.1),
action=(ip4.dst = 172.16.0.103; next;)
+ table=??(lr_in_dnat ), priority=110 ,
match=(is_chassis_resident("cr-lr1_public") && ip4 && ip4.dst == 30.0.0.1),
action=(ip4.dst = 172.16.0.103; next;)
+])
+
+# 3. Check if the DGP ports are in the match with action next
+AT_CHECK([grep "lr_out_undnat" lr1flows | ovn_strip_lflows], [0], [dnl
+ table=??(lr_out_undnat ), priority=0 , match=(1), action=(next;)
+ table=??(lr_out_undnat ), priority=120 , match=(ip4 && ((ip4.src ==
172.16.0.103)) && (inport == "lr1-ts1" || outport == "lr1-ts1") &&
is_chassis_resident("cr-lr1-ts1") && tcp), action=(next;)
+ table=??(lr_out_undnat ), priority=120 , match=(ip4 && ((ip4.src ==
172.16.0.103)) && (inport == "lr1-ts2" || outport == "lr1-ts2") &&
is_chassis_resident("cr-lr1-ts2") && tcp), action=(next;)
+ table=??(lr_out_undnat ), priority=120 , match=(ip4 && ((ip4.src ==
172.16.0.103)) && (inport == "lr1_public" || outport == "lr1_public") &&
is_chassis_resident("cr-lr1_public") && tcp), action=(next;)
+])
+
+# 4. Check if the VIP IP is in the ipX.src action
+AT_CHECK([grep "lr_out_snat" lr1flows | ovn_strip_lflows], [0], [dnl
+ table=??(lr_out_snat ), priority=0 , match=(1), action=(next;)
+ table=??(lr_out_snat ), priority=120 , match=(nd_ns), action=(next;)
+ table=??(lr_out_snat ), priority=160 , match=(ip4 && ((ip4.src ==
172.16.0.103)) && (inport == "lr1-ts1" || outport == "lr1-ts1") &&
is_chassis_resident("cr-lr1-ts1") && tcp), action=(ip4.src = 30.0.0.1; next;)
+ table=??(lr_out_snat ), priority=160 , match=(ip4 && ((ip4.src ==
172.16.0.103)) && (inport == "lr1-ts2" || outport == "lr1-ts2") &&
is_chassis_resident("cr-lr1-ts2") && tcp), action=(ip4.src = 30.0.0.1; next;)
+ table=??(lr_out_snat ), priority=160 , match=(ip4 && ((ip4.src ==
172.16.0.103)) && (inport == "lr1_public" || outport == "lr1_public") &&
is_chassis_resident("cr-lr1_public") && tcp), action=(ip4.src = 30.0.0.1; next;)
+])
+
+
AT_CLEANUP
])
@@ -14445,14 +14542,67 @@ ovn-sbctl dump-flows lr1 > lr1flows
AT_CAPTURE_FILE([lr1flows])
# Check stateless NAT rules for load balancer with multiple DGP
-# 1. Check if the backend IPs are in the ipX.dst action
+# 1. Check if the reg1[0..15] will select one of backends
+AT_CHECK([grep "lr_in_ct_extract" lr1flows | ovn_strip_lflows | grep
"2001:db8:cccc::1"], [0], [dnl
+ table=??(lr_in_ct_extract ), priority=120 , match=(ip && ip6.dst ==
2001:db8:cccc::1), action=(reg1[[0..15]] = select(0,1,2); next;)
+])
+
+# 2. Check if the backend IPs are in the ipX.dst action
AT_CHECK([grep "lr_in_dnat" lr1flows | ovn_strip_lflows | grep
"2001:db8:cccc::1"], [0], [dnl
- table=??(lr_in_dnat ), priority=110 , match=(ct.new && !ct.rel &&
ip6 && ip6.dst == 2001:db8:cccc::1 && is_chassis_resident("cr-lr1-ts1")),
action=(ip6.dst = 2001:db8:aaaa:3::103;
ct_lb_mark(backends=2001:db8:aaaa:3::103,2001:db8:aaaa:3::102,2001:db8:aaaa:3::101);)
- table=??(lr_in_dnat ), priority=110 , match=(ct.new && !ct.rel &&
ip6 && ip6.dst == 2001:db8:cccc::1 && is_chassis_resident("cr-lr1-ts2")),
action=(ip6.dst = 2001:db8:aaaa:3::103;
ct_lb_mark(backends=2001:db8:aaaa:3::103,2001:db8:aaaa:3::102,2001:db8:aaaa:3::101);)
- table=??(lr_in_dnat ), priority=110 , match=(ct.new && !ct.rel &&
ip6 && ip6.dst == 2001:db8:cccc::1 && is_chassis_resident("cr-lr1_public")),
action=(ip6.dst = 2001:db8:aaaa:3::103;
ct_lb_mark(backends=2001:db8:aaaa:3::103,2001:db8:aaaa:3::102,2001:db8:aaaa:3::101);)
+ table=??(lr_in_dnat ), priority=110 ,
match=(is_chassis_resident("cr-lr1-ts1") && ip6 && ip6.dst == 2001:db8:cccc::1
&& reg1[[0..15]] == 0), action=(ip6.dst = 2001:db8:aaaa:3::103; next;)
+ table=??(lr_in_dnat ), priority=110 ,
match=(is_chassis_resident("cr-lr1-ts1") && ip6 && ip6.dst == 2001:db8:cccc::1
&& reg1[[0..15]] == 1), action=(ip6.dst = 2001:db8:aaaa:3::102; next;)
+ table=??(lr_in_dnat ), priority=110 ,
match=(is_chassis_resident("cr-lr1-ts1") && ip6 && ip6.dst == 2001:db8:cccc::1
&& reg1[[0..15]] == 2), action=(ip6.dst = 2001:db8:aaaa:3::101; next;)
+ table=??(lr_in_dnat ), priority=110 ,
match=(is_chassis_resident("cr-lr1-ts2") && ip6 && ip6.dst == 2001:db8:cccc::1
&& reg1[[0..15]] == 0), action=(ip6.dst = 2001:db8:aaaa:3::103; next;)
+ table=??(lr_in_dnat ), priority=110 ,
match=(is_chassis_resident("cr-lr1-ts2") && ip6 && ip6.dst == 2001:db8:cccc::1
&& reg1[[0..15]] == 1), action=(ip6.dst = 2001:db8:aaaa:3::102; next;)
+ table=??(lr_in_dnat ), priority=110 ,
match=(is_chassis_resident("cr-lr1-ts2") && ip6 && ip6.dst == 2001:db8:cccc::1
&& reg1[[0..15]] == 2), action=(ip6.dst = 2001:db8:aaaa:3::101; next;)
+ table=??(lr_in_dnat ), priority=110 ,
match=(is_chassis_resident("cr-lr1_public") && ip6 && ip6.dst ==
2001:db8:cccc::1 && reg1[[0..15]] == 0), action=(ip6.dst =
2001:db8:aaaa:3::103; next;)
+ table=??(lr_in_dnat ), priority=110 ,
match=(is_chassis_resident("cr-lr1_public") && ip6 && ip6.dst ==
2001:db8:cccc::1 && reg1[[0..15]] == 1), action=(ip6.dst =
2001:db8:aaaa:3::102; next;)
+ table=??(lr_in_dnat ), priority=110 ,
match=(is_chassis_resident("cr-lr1_public") && ip6 && ip6.dst ==
2001:db8:cccc::1 && reg1[[0..15]] == 2), action=(ip6.dst =
2001:db8:aaaa:3::101; next;)
+])
+
+# 3. Check if the DGP ports are in the match with action next
+AT_CHECK([grep "lr_out_undnat" lr1flows | ovn_strip_lflows], [0], [dnl
+ table=??(lr_out_undnat ), priority=0 , match=(1), action=(next;)
+ table=??(lr_out_undnat ), priority=120 , match=(ip6 && ((ip6.src ==
2001:db8:aaaa:3::103) || (ip6.src == 2001:db8:aaaa:3::102) || (ip6.src ==
2001:db8:aaaa:3::101)) && (inport == "lr1-ts1" || outport == "lr1-ts1") &&
is_chassis_resident("cr-lr1-ts1") && tcp), action=(next;)
+ table=??(lr_out_undnat ), priority=120 , match=(ip6 && ((ip6.src ==
2001:db8:aaaa:3::103) || (ip6.src == 2001:db8:aaaa:3::102) || (ip6.src ==
2001:db8:aaaa:3::101)) && (inport == "lr1-ts2" || outport == "lr1-ts2") &&
is_chassis_resident("cr-lr1-ts2") && tcp), action=(next;)
+ table=??(lr_out_undnat ), priority=120 , match=(ip6 && ((ip6.src ==
2001:db8:aaaa:3::103) || (ip6.src == 2001:db8:aaaa:3::102) || (ip6.src ==
2001:db8:aaaa:3::101)) && (inport == "lr1_public" || outport == "lr1_public")
&& is_chassis_resident("cr-lr1_public") && tcp), action=(next;)
])
-# 2. Check if the DGP ports are in the match with action next
+# 4. Check if the VIP IP is in the ipX.src action
+AT_CHECK([grep "lr_out_snat" lr1flows | ovn_strip_lflows], [0], [dnl
+ table=??(lr_out_snat ), priority=0 , match=(1), action=(next;)
+ table=??(lr_out_snat ), priority=120 , match=(nd_ns), action=(next;)
+ table=??(lr_out_snat ), priority=160 , match=(ip6 && ((ip6.src ==
2001:db8:aaaa:3::103) || (ip6.src == 2001:db8:aaaa:3::102) || (ip6.src ==
2001:db8:aaaa:3::101)) && (inport == "lr1-ts1" || outport == "lr1-ts1") &&
is_chassis_resident("cr-lr1-ts1") && tcp), action=(ip6.src = 2001:db8:cccc::1;
next;)
+ table=??(lr_out_snat ), priority=160 , match=(ip6 && ((ip6.src ==
2001:db8:aaaa:3::103) || (ip6.src == 2001:db8:aaaa:3::102) || (ip6.src ==
2001:db8:aaaa:3::101)) && (inport == "lr1-ts2" || outport == "lr1-ts2") &&
is_chassis_resident("cr-lr1-ts2") && tcp), action=(ip6.src = 2001:db8:cccc::1;
next;)
+ table=??(lr_out_snat ), priority=160 , match=(ip6 && ((ip6.src ==
2001:db8:aaaa:3::103) || (ip6.src == 2001:db8:aaaa:3::102) || (ip6.src ==
2001:db8:aaaa:3::101)) && (inport == "lr1_public" || outport == "lr1_public")
&& is_chassis_resident("cr-lr1_public") && tcp), action=(ip6.src =
2001:db8:cccc::1; next;)
+])
+
+# Set selection fields
+check ovn-nbctl --wait=sb set load_balancer lb1
selection_fields="ip_src,tp_src,ip_dst,tp_dst"
+
+ovn-sbctl dump-flows lr1 > lr1flows
+AT_CAPTURE_FILE([lr1flows])
+
+# Check stateless NAT rules for load balancer with multiple DGP
+# 1. Check if the reg1[0..15] will select one of backends
+AT_CHECK([grep "lr_in_ct_extract" lr1flows | ovn_strip_lflows | grep
"2001:db8:cccc::1"], [0], [dnl
+ table=??(lr_in_ct_extract ), priority=120 , match=(ip && ip6.dst ==
2001:db8:cccc::1), action=(reg1[[0..15]] = select(values=(0,1,2);
hash_fields="ip_dst,ip_src,tcp_dst,tcp_src"); next;)
+])
+
+# 2. Check if the backend IPs are in the ipX.dst action
+AT_CHECK([grep "lr_in_dnat" lr1flows | ovn_strip_lflows | grep
"2001:db8:cccc::1"], [0], [dnl
+ table=??(lr_in_dnat ), priority=110 ,
match=(is_chassis_resident("cr-lr1-ts1") && ip6 && ip6.dst == 2001:db8:cccc::1
&& reg1[[0..15]] == 0), action=(ip6.dst = 2001:db8:aaaa:3::103; next;)
+ table=??(lr_in_dnat ), priority=110 ,
match=(is_chassis_resident("cr-lr1-ts1") && ip6 && ip6.dst == 2001:db8:cccc::1
&& reg1[[0..15]] == 1), action=(ip6.dst = 2001:db8:aaaa:3::102; next;)
+ table=??(lr_in_dnat ), priority=110 ,
match=(is_chassis_resident("cr-lr1-ts1") && ip6 && ip6.dst == 2001:db8:cccc::1
&& reg1[[0..15]] == 2), action=(ip6.dst = 2001:db8:aaaa:3::101; next;)
+ table=??(lr_in_dnat ), priority=110 ,
match=(is_chassis_resident("cr-lr1-ts2") && ip6 && ip6.dst == 2001:db8:cccc::1
&& reg1[[0..15]] == 0), action=(ip6.dst = 2001:db8:aaaa:3::103; next;)
+ table=??(lr_in_dnat ), priority=110 ,
match=(is_chassis_resident("cr-lr1-ts2") && ip6 && ip6.dst == 2001:db8:cccc::1
&& reg1[[0..15]] == 1), action=(ip6.dst = 2001:db8:aaaa:3::102; next;)
+ table=??(lr_in_dnat ), priority=110 ,
match=(is_chassis_resident("cr-lr1-ts2") && ip6 && ip6.dst == 2001:db8:cccc::1
&& reg1[[0..15]] == 2), action=(ip6.dst = 2001:db8:aaaa:3::101; next;)
+ table=??(lr_in_dnat ), priority=110 ,
match=(is_chassis_resident("cr-lr1_public") && ip6 && ip6.dst ==
2001:db8:cccc::1 && reg1[[0..15]] == 0), action=(ip6.dst =
2001:db8:aaaa:3::103; next;)
+ table=??(lr_in_dnat ), priority=110 ,
match=(is_chassis_resident("cr-lr1_public") && ip6 && ip6.dst ==
2001:db8:cccc::1 && reg1[[0..15]] == 1), action=(ip6.dst =
2001:db8:aaaa:3::102; next;)
+ table=??(lr_in_dnat ), priority=110 ,
match=(is_chassis_resident("cr-lr1_public") && ip6 && ip6.dst ==
2001:db8:cccc::1 && reg1[[0..15]] == 2), action=(ip6.dst =
2001:db8:aaaa:3::101; next;)
+])
+
+# 3. Check if the DGP ports are in the match with action next
AT_CHECK([grep "lr_out_undnat" lr1flows | ovn_strip_lflows], [0], [dnl
table=??(lr_out_undnat ), priority=0 , match=(1), action=(next;)
table=??(lr_out_undnat ), priority=120 , match=(ip6 && ((ip6.src ==
2001:db8:aaaa:3::103) || (ip6.src == 2001:db8:aaaa:3::102) || (ip6.src ==
2001:db8:aaaa:3::101)) && (inport == "lr1-ts1" || outport == "lr1-ts1") &&
is_chassis_resident("cr-lr1-ts1") && tcp), action=(next;)
@@ -14460,7 +14610,7 @@ AT_CHECK([grep "lr_out_undnat" lr1flows |
ovn_strip_lflows], [0], [dnl
table=??(lr_out_undnat ), priority=120 , match=(ip6 && ((ip6.src ==
2001:db8:aaaa:3::103) || (ip6.src == 2001:db8:aaaa:3::102) || (ip6.src ==
2001:db8:aaaa:3::101)) && (inport == "lr1_public" || outport == "lr1_public")
&& is_chassis_resident("cr-lr1_public") && tcp), action=(next;)
])
-# 3. Check if the VIP IP is in the ipX.src action
+# 4. Check if the VIP IP is in the ipX.src action
AT_CHECK([grep "lr_out_snat" lr1flows | ovn_strip_lflows], [0], [dnl
table=??(lr_out_snat ), priority=0 , match=(1), action=(next;)
table=??(lr_out_snat ), priority=120 , match=(nd_ns), action=(next;)
@@ -14469,6 +14619,50 @@ AT_CHECK([grep "lr_out_snat" lr1flows |
ovn_strip_lflows], [0], [dnl
table=??(lr_out_snat ), priority=160 , match=(ip6 && ((ip6.src ==
2001:db8:aaaa:3::103) || (ip6.src == 2001:db8:aaaa:3::102) || (ip6.src ==
2001:db8:aaaa:3::101)) && (inport == "lr1_public" || outport == "lr1_public")
&& is_chassis_resident("cr-lr1_public") && tcp), action=(ip6.src =
2001:db8:cccc::1; next;)
])
+# Delete LB and create with one backend
+check ovn-nbctl --wait=sb lb-del lb1
+check ovn-nbctl --wait=sb lb-add lb1 "2001:db8:cccc::1" "2001:db8:aaaa:3::103"
+
+# Set use_stateless_nat to true
+check ovn-nbctl --wait=sb set load_balancer lb1 options:use_stateless_nat=true
+
+# Associate load balancer to s1
+check ovn-nbctl ls-lb-add s1 lb1
+check ovn-nbctl lr-lb-add lr1 lb1
+check ovn-nbctl --wait=sb sync
+
+ovn-sbctl dump-flows lr1 > lr1flows
+AT_CAPTURE_FILE([lr1flows])
+# Check stateless NAT rules for load balancer with multiple DGP
+# 1. Check if the reg1[0..15] will select one of backends
+AT_CHECK([grep "lr_in_ct_extract" lr1flows | ovn_strip_lflows | grep
"2001:db8:cccc::1"], [0], [dnl
+ table=??(lr_in_ct_extract ), priority=120 , match=(ip && ip6.dst ==
2001:db8:cccc::1), action=(next;)
+])
+
+# 2. Check if the backend IPs are in the ipX.dst action
+AT_CHECK([grep "lr_in_dnat" lr1flows | ovn_strip_lflows | grep
"2001:db8:cccc::1"], [0], [dnl
+ table=??(lr_in_dnat ), priority=110 ,
match=(is_chassis_resident("cr-lr1-ts1") && ip6 && ip6.dst ==
2001:db8:cccc::1), action=(ip6.dst = 2001:db8:aaaa:3::103; next;)
+ table=??(lr_in_dnat ), priority=110 ,
match=(is_chassis_resident("cr-lr1-ts2") && ip6 && ip6.dst ==
2001:db8:cccc::1), action=(ip6.dst = 2001:db8:aaaa:3::103; next;)
+ table=??(lr_in_dnat ), priority=110 ,
match=(is_chassis_resident("cr-lr1_public") && ip6 && ip6.dst ==
2001:db8:cccc::1), action=(ip6.dst = 2001:db8:aaaa:3::103; next;)
+])
+
+# 3. Check if the DGP ports are in the match with action next
+AT_CHECK([grep "lr_out_undnat" lr1flows | ovn_strip_lflows], [0], [dnl
+ table=??(lr_out_undnat ), priority=0 , match=(1), action=(next;)
+ table=??(lr_out_undnat ), priority=120 , match=(ip6 && ((ip6.src ==
2001:db8:aaaa:3::103)) && (inport == "lr1-ts1" || outport == "lr1-ts1") &&
is_chassis_resident("cr-lr1-ts1") && tcp), action=(next;)
+ table=??(lr_out_undnat ), priority=120 , match=(ip6 && ((ip6.src ==
2001:db8:aaaa:3::103)) && (inport == "lr1-ts2" || outport == "lr1-ts2") &&
is_chassis_resident("cr-lr1-ts2") && tcp), action=(next;)
+ table=??(lr_out_undnat ), priority=120 , match=(ip6 && ((ip6.src ==
2001:db8:aaaa:3::103)) && (inport == "lr1_public" || outport == "lr1_public")
&& is_chassis_resident("cr-lr1_public") && tcp), action=(next;)
+])
+
+# 4. Check if the VIP IP is in the ipX.src action
+AT_CHECK([grep "lr_out_snat" lr1flows | ovn_strip_lflows], [0], [dnl
+ table=??(lr_out_snat ), priority=0 , match=(1), action=(next;)
+ table=??(lr_out_snat ), priority=120 , match=(nd_ns), action=(next;)
+ table=??(lr_out_snat ), priority=160 , match=(ip6 && ((ip6.src ==
2001:db8:aaaa:3::103)) && (inport == "lr1-ts1" || outport == "lr1-ts1") &&
is_chassis_resident("cr-lr1-ts1") && tcp), action=(ip6.src = 2001:db8:cccc::1;
next;)
+ table=??(lr_out_snat ), priority=160 , match=(ip6 && ((ip6.src ==
2001:db8:aaaa:3::103)) && (inport == "lr1-ts2" || outport == "lr1-ts2") &&
is_chassis_resident("cr-lr1-ts2") && tcp), action=(ip6.src = 2001:db8:cccc::1;
next;)
+ table=??(lr_out_snat ), priority=160 , match=(ip6 && ((ip6.src ==
2001:db8:aaaa:3::103)) && (inport == "lr1_public" || outport == "lr1_public")
&& is_chassis_resident("cr-lr1_public") && tcp), action=(ip6.src =
2001:db8:cccc::1; next;)
+])
+
AT_CLEANUP
])
--
2.34.1
--
_'Esta mensagem é direcionada apenas para os endereços constantes no
cabeçalho inicial. Se você não está listado nos endereços constantes no
cabeçalho, pedimos-lhe que desconsidere completamente o conteúdo dessa
mensagem e cuja cópia, encaminhamento e/ou execução das ações citadas estão
imediatamente anuladas e proibidas'._
* **'Apesar do Magazine Luiza tomar
todas as precauções razoáveis para assegurar que nenhum vírus esteja
presente nesse e-mail, a empresa não poderá aceitar a responsabilidade por
quaisquer perdas ou danos causados por esse e-mail ou por seus anexos'.*
_______________________________________________
dev mailing list
[email protected]
https://mail.openvswitch.org/mailman/listinfo/ovs-dev