Hi Martin. Sorry I wasn't able to comment on v1. In my opinion, this should be separated into two patches. * Patch 1 adds the NS_CHECK_CONNECTIVITY macro and converts existing tests to use it. * Patch 2 fixes the issue with committing to the incorrect CT zone.
On Tue, Sep 23, 2025 at 2:44 PM Martin Kalcok <[email protected]> wrote: > > Commit 40136a2f2c84 introduced the ability to directly reach networks behind > SNAT and DNAT_AND_SNAT on Distributed Routers, matching the behavior > of Gateway Routers. This was achieved by committing the incoming traffic into > the SNAT TC zone, which allowed the router to SNAT only traffic that > originated > from inside the SNATed network. > An unintended consequence was that incoming traffic destined for the external > IP of a DNAT_AND_SNAT rule would also be committed to the SNAT CT zone, > resulting in an unnecessary entry, lingering in the table until it expired. > > This change attempts to fix that by handling traffic matching DNAT_AND_SNAT > rule with slightly higher priority than the simple SNAT, and committing it to > DNAT CT zone instead. > > Tests for the connectivity are also improved. Previously the system tests > 'DNAT and SNAT on distributed router - N/S' used: > * 'ping' for ICMP traffic > * 'nc -u -z' for UDP traffic > * 'nc --send-only' for TCP traffic > > It was especially the TCP traffic test that was problematic, because it would > not detect errors that occurred after the initial TCP handshake. > This patch proposes a new macro NS_CHECK_CONNECTIVITY that validates the > connectivity more thoroughly by exchanging multiple messages over the TCP > and UDP to make sure that the traffic can flow. > > Fixes: 40136a2f2c84 ("northd: Fix direct access to SNAT network.") > Signed-off-by: Martin Kalcok <[email protected]> > --- > northd/northd.c | 48 ++++++++---- > tests/ovn-northd.at | 27 ++++--- > tests/system-common-macros.at | 47 ++++++++++++ > tests/system-ovn.at | 138 +++++++++------------------------- > 4 files changed, 134 insertions(+), 126 deletions(-) > > diff --git a/northd/northd.c b/northd/northd.c > index 8b5413ef3..6db6c7aed 100644 > --- a/northd/northd.c > +++ b/northd/northd.c > @@ -16611,27 +16611,49 @@ build_lrouter_out_snat_flow(struct lflow_table > *lflows, > * properly tracked so we can decide whether to perform SNAT on traffic > * exiting the network. */ > if (features->ct_commit_to_zone && features->ct_next_zone && > - nat_entry->type == SNAT && !od->is_gw_router && !commit_all) { > - /* For traffic that comes from SNAT network, initiate CT state before > - * entering S_ROUTER_OUT_SNAT to allow matching on various CT states. > - */ > - ovn_lflow_add(lflows, od, S_ROUTER_OUT_POST_UNDNAT, 70, > - ds_cstr(match), "ct_next(snat);", > + !od->is_gw_router && !commit_all) { > + const char *zone; > + uint16_t prio_offset; > + /* Traffic to/from hosts behind SNAT is tracked through the > + * SNAT CT zone.*/ > + if (nat_entry->type == SNAT) { > + zone = "snat"; > + prio_offset = 0; > + /* Traffic to/from hosts behind DNAT_AND_SNAT is tracked through the > + * DNAT CT zone with slightly higher priority flows.*/ > + } else { > + zone = "dnat"; > + prio_offset = 5; > + } > + > + /* For traffic that comes from the SNAT network, initiate CT state > + * from the correct zone, before entering S_ROUTER_OUT_SNAT to allow > + * matching on various CT states.*/ > + ds_clear(actions); > + ds_put_format(actions, "ct_next(%s);", zone); > + ovn_lflow_add(lflows, od, S_ROUTER_OUT_POST_UNDNAT, 70 + prio_offset, > + ds_cstr(match), ds_cstr(actions), > lflow_ref); > > + /* New traffic that goes into the SNAT network is committed to the > + * correct CT zone to avoid SNAT-ing replies.*/ > build_lrouter_out_snat_match(lflows, od, nat, match, > distributed_nat, cidr_bits, is_v6, > l3dgw_port, lflow_ref, true); > - > - /* New traffic that goes into SNAT network is committed to CT to > avoid > - * SNAT-ing replies.*/ > - ovn_lflow_add(lflows, od, S_ROUTER_OUT_SNAT, priority, > - ds_cstr(match), "ct_snat;", > + size_t match_any_state_len = match->length; > + ds_put_cstr(match, " && (!ct.trk || !ct.rpl)"); > + ds_clear(actions); > + ds_put_format(actions, "ct_%s;", zone); > + ovn_lflow_add(lflows, od, S_ROUTER_OUT_SNAT, priority + prio_offset, > + ds_cstr(match), ds_cstr(actions), > lflow_ref); > > + ds_truncate(match, match_any_state_len); > ds_put_cstr(match, " && ct.new"); > - ovn_lflow_add(lflows, od, S_ROUTER_OUT_POST_SNAT, priority, > - ds_cstr(match), "ct_commit_to_zone(snat);", > + ds_clear(actions); > + ds_put_format(actions, "ct_commit_to_zone(%s);", zone); > + ovn_lflow_add(lflows, od, S_ROUTER_OUT_POST_SNAT, > + priority + prio_offset, ds_cstr(match), > ds_cstr(actions), > lflow_ref); > } > } > diff --git a/tests/ovn-northd.at b/tests/ovn-northd.at > index c9e998129..d99815dd6 100644 > --- a/tests/ovn-northd.at > +++ b/tests/ovn-northd.at > @@ -1242,7 +1242,7 @@ AT_CAPTURE_FILE([crflows]) > AT_CHECK([grep -e "lr_out_snat" drflows | ovn_strip_lflows], [0], [dnl > table=??(lr_out_snat ), priority=0 , match=(1), action=(next;) > table=??(lr_out_snat ), priority=120 , match=(nd_ns), > action=(next;) > - table=??(lr_out_snat ), priority=161 , match=(ip && ip4.dst == > 50.0.0.11 && inport == "DR-S1" && is_chassis_resident("cr-DR-S1") && ip4.src > == $allowed_range), action=(ct_snat;) > + table=??(lr_out_snat ), priority=161 , match=(ip && ip4.dst == > 50.0.0.11 && inport == "DR-S1" && is_chassis_resident("cr-DR-S1") && ip4.src > == $allowed_range && (!ct.trk || !ct.rpl)), action=(ct_snat;) > table=??(lr_out_snat ), priority=161 , match=(ip && ip4.src == > 50.0.0.11 && outport == "DR-S1" && is_chassis_resident("cr-DR-S1") && ip4.dst > == $allowed_range && (!ct.trk || !ct.rpl)), action=(ct_snat(172.16.1.1);) > ]) > > @@ -1281,7 +1281,7 @@ AT_CAPTURE_FILE([crflows2]) > AT_CHECK([grep -e "lr_out_snat" drflows2 | ovn_strip_lflows], [0], [dnl > table=??(lr_out_snat ), priority=0 , match=(1), action=(next;) > table=??(lr_out_snat ), priority=120 , match=(nd_ns), > action=(next;) > - table=??(lr_out_snat ), priority=161 , match=(ip && ip4.dst == > 50.0.0.11 && inport == "DR-S1" && is_chassis_resident("cr-DR-S1")), > action=(ct_snat;) > + table=??(lr_out_snat ), priority=161 , match=(ip && ip4.dst == > 50.0.0.11 && inport == "DR-S1" && is_chassis_resident("cr-DR-S1") && (!ct.trk > || !ct.rpl)), action=(ct_snat;) > table=??(lr_out_snat ), priority=161 , match=(ip && ip4.src == > 50.0.0.11 && outport == "DR-S1" && is_chassis_resident("cr-DR-S1") && > (!ct.trk || !ct.rpl)), action=(ct_snat(172.16.1.1);) > table=??(lr_out_snat ), priority=163 , match=(ip && ip4.src == > 50.0.0.11 && outport == "DR-S1" && is_chassis_resident("cr-DR-S1") && ip4.dst > == $disallowed_range), action=(next;) > ]) > @@ -1321,10 +1321,12 @@ AT_CHECK([grep -e "lr_out_snat" drflows3 | > ovn_strip_lflows], [0], [dnl > table=??(lr_out_snat ), priority=0 , match=(1), action=(next;) > table=??(lr_out_snat ), priority=120 , match=(nd_ns), > action=(next;) > table=??(lr_out_snat ), priority=161 , match=(ip && ip4.src == > 50.0.0.11 && outport == "DR-S1" && is_chassis_resident("cr-DR-S1") && ip4.dst > == $allowed_range && (!ct.trk || !ct.rpl)), action=(ct_snat(172.16.1.2);) > + table=??(lr_out_snat ), priority=166 , match=(ip && ip4.dst == > 50.0.0.11 && inport == "DR-S1" && is_chassis_resident("cr-DR-S1") && ip4.src > == $allowed_range && (!ct.trk || !ct.rpl)), action=(ct_dnat;) > ]) > > AT_CHECK([grep -e "lr_out_post_snat" drflows3 | ovn_strip_lflows], [0], [dnl > table=??(lr_out_post_snat ), priority=0 , match=(1), action=(next;) > + table=??(lr_out_post_snat ), priority=166 , match=(ip && ip4.dst == > 50.0.0.11 && inport == "DR-S1" && is_chassis_resident("cr-DR-S1") && ip4.src > == $allowed_range && ct.new), action=(ct_commit_to_zone(dnat);) > ]) > > AT_CHECK([grep -e "lr_out_snat" crflows3 | ovn_strip_lflows], [0], [dnl > @@ -1357,6 +1359,7 @@ AT_CHECK([grep -e "lr_out_snat" drflows4 | > ovn_strip_lflows], [0], [dnl > table=??(lr_out_snat ), priority=120 , match=(nd_ns), > action=(next;) > table=??(lr_out_snat ), priority=161 , match=(ip && ip4.src == > 50.0.0.11 && outport == "DR-S1" && is_chassis_resident("cr-DR-S1") && > (!ct.trk || !ct.rpl)), action=(ct_snat(172.16.1.2);) > table=??(lr_out_snat ), priority=163 , match=(ip && ip4.src == > 50.0.0.11 && outport == "DR-S1" && is_chassis_resident("cr-DR-S1") && ip4.dst > == $disallowed_range), action=(next;) > + table=??(lr_out_snat ), priority=166 , match=(ip && ip4.dst == > 50.0.0.11 && inport == "DR-S1" && is_chassis_resident("cr-DR-S1") && (!ct.trk > || !ct.rpl)), action=(ct_dnat;) > ]) > > AT_CHECK([grep -e "lr_out_snat" crflows4 | ovn_strip_lflows], [0], [dnl > @@ -5999,22 +6002,25 @@ AT_CHECK([grep "lr_out_post_undnat" lr0flows | > ovn_strip_lflows], [0], [dnl > table=??(lr_out_post_undnat ), priority=0 , match=(1), action=(next;) > table=??(lr_out_post_undnat ), priority=70 , match=(ip && ip4.src == > 10.0.0.0/24 && outport == "lr0-public" && > is_chassis_resident("cr-lr0-public") && (!ct.trk || !ct.rpl)), > action=(ct_next(snat);) > table=??(lr_out_post_undnat ), priority=70 , match=(ip && ip4.src == > 10.0.0.10 && outport == "lr0-public" && is_chassis_resident("cr-lr0-public") > && (!ct.trk || !ct.rpl)), action=(ct_next(snat);) > + table=??(lr_out_post_undnat ), priority=75 , match=(ip && ip4.src == > 10.0.0.3 && outport == "lr0-public" && is_chassis_resident("cr-lr0-public") > && (!ct.trk || !ct.rpl)), action=(ct_next(dnat);) > ]) > > AT_CHECK([grep "lr_out_snat" lr0flows | ovn_strip_lflows], [0], [dnl > table=??(lr_out_snat ), priority=0 , match=(1), action=(next;) > table=??(lr_out_snat ), priority=120 , match=(nd_ns), > action=(next;) > - table=??(lr_out_snat ), priority=153 , match=(ip && ip4.dst == > 10.0.0.0/24 && inport == "lr0-public" && > is_chassis_resident("cr-lr0-public")), action=(ct_snat;) > + table=??(lr_out_snat ), priority=153 , match=(ip && ip4.dst == > 10.0.0.0/24 && inport == "lr0-public" && is_chassis_resident("cr-lr0-public") > && (!ct.trk || !ct.rpl)), action=(ct_snat;) > table=??(lr_out_snat ), priority=153 , match=(ip && ip4.src == > 10.0.0.0/24 && outport == "lr0-public" && > is_chassis_resident("cr-lr0-public") && (!ct.trk || !ct.rpl)), > action=(ct_snat(172.168.0.10);) > - table=??(lr_out_snat ), priority=161 , match=(ip && ip4.dst == > 10.0.0.10 && inport == "lr0-public" && is_chassis_resident("cr-lr0-public")), > action=(ct_snat;) > + table=??(lr_out_snat ), priority=161 , match=(ip && ip4.dst == > 10.0.0.10 && inport == "lr0-public" && is_chassis_resident("cr-lr0-public") > && (!ct.trk || !ct.rpl)), action=(ct_snat;) > table=??(lr_out_snat ), priority=161 , match=(ip && ip4.src == > 10.0.0.10 && outport == "lr0-public" && is_chassis_resident("cr-lr0-public") > && (!ct.trk || !ct.rpl)), action=(ct_snat(172.168.0.30);) > table=??(lr_out_snat ), priority=161 , match=(ip && ip4.src == > 10.0.0.3 && outport == "lr0-public" && is_chassis_resident("cr-lr0-public") > && (!ct.trk || !ct.rpl)), action=(ct_snat(172.168.0.20);) > + table=??(lr_out_snat ), priority=166 , match=(ip && ip4.dst == > 10.0.0.3 && inport == "lr0-public" && is_chassis_resident("cr-lr0-public") && > (!ct.trk || !ct.rpl)), action=(ct_dnat;) > ]) > > AT_CHECK([grep "lr_out_post_snat" lr0flows | ovn_strip_lflows], [0], [dnl > table=??(lr_out_post_snat ), priority=0 , match=(1), action=(next;) > table=??(lr_out_post_snat ), priority=153 , match=(ip && ip4.dst == > 10.0.0.0/24 && inport == "lr0-public" && is_chassis_resident("cr-lr0-public") > && ct.new), action=(ct_commit_to_zone(snat);) > table=??(lr_out_post_snat ), priority=161 , match=(ip && ip4.dst == > 10.0.0.10 && inport == "lr0-public" && is_chassis_resident("cr-lr0-public") > && ct.new), action=(ct_commit_to_zone(snat);) > + table=??(lr_out_post_snat ), priority=166 , match=(ip && ip4.dst == > 10.0.0.3 && inport == "lr0-public" && is_chassis_resident("cr-lr0-public") && > ct.new), action=(ct_commit_to_zone(dnat);) > ]) > > # Associate load balancer to lr0 > @@ -6157,22 +6163,25 @@ AT_CHECK([grep "lr_out_post_undnat" lr0flows | > ovn_strip_lflows], [0], [dnl > table=??(lr_out_post_undnat ), priority=0 , match=(1), action=(next;) > table=??(lr_out_post_undnat ), priority=70 , match=(ip && ip4.src == > 10.0.0.0/24 && outport == "lr0-public" && > is_chassis_resident("cr-lr0-public") && (!ct.trk || !ct.rpl)), > action=(ct_next(snat);) > table=??(lr_out_post_undnat ), priority=70 , match=(ip && ip4.src == > 10.0.0.10 && outport == "lr0-public" && is_chassis_resident("cr-lr0-public") > && (!ct.trk || !ct.rpl)), action=(ct_next(snat);) > + table=??(lr_out_post_undnat ), priority=75 , match=(ip && ip4.src == > 10.0.0.3 && outport == "lr0-public" && is_chassis_resident("cr-lr0-public") > && (!ct.trk || !ct.rpl)), action=(ct_next(dnat);) > ]) > > AT_CHECK([grep "lr_out_snat" lr0flows | ovn_strip_lflows], [0], [dnl > table=??(lr_out_snat ), priority=0 , match=(1), action=(next;) > table=??(lr_out_snat ), priority=120 , match=(nd_ns), > action=(next;) > - table=??(lr_out_snat ), priority=153 , match=(ip && ip4.dst == > 10.0.0.0/24 && inport == "lr0-public" && > is_chassis_resident("cr-lr0-public")), action=(ct_snat;) > + table=??(lr_out_snat ), priority=153 , match=(ip && ip4.dst == > 10.0.0.0/24 && inport == "lr0-public" && is_chassis_resident("cr-lr0-public") > && (!ct.trk || !ct.rpl)), action=(ct_snat;) > table=??(lr_out_snat ), priority=153 , match=(ip && ip4.src == > 10.0.0.0/24 && outport == "lr0-public" && > is_chassis_resident("cr-lr0-public") && (!ct.trk || !ct.rpl)), > action=(ct_snat(172.168.0.10);) > - table=??(lr_out_snat ), priority=161 , match=(ip && ip4.dst == > 10.0.0.10 && inport == "lr0-public" && is_chassis_resident("cr-lr0-public")), > action=(ct_snat;) > + table=??(lr_out_snat ), priority=161 , match=(ip && ip4.dst == > 10.0.0.10 && inport == "lr0-public" && is_chassis_resident("cr-lr0-public") > && (!ct.trk || !ct.rpl)), action=(ct_snat;) > table=??(lr_out_snat ), priority=161 , match=(ip && ip4.src == > 10.0.0.10 && outport == "lr0-public" && is_chassis_resident("cr-lr0-public") > && (!ct.trk || !ct.rpl)), action=(ct_snat(172.168.0.30);) > table=??(lr_out_snat ), priority=161 , match=(ip && ip4.src == > 10.0.0.3 && outport == "lr0-public" && is_chassis_resident("cr-lr0-public") > && (!ct.trk || !ct.rpl)), action=(ct_snat(172.168.0.20);) > + table=??(lr_out_snat ), priority=166 , match=(ip && ip4.dst == > 10.0.0.3 && inport == "lr0-public" && is_chassis_resident("cr-lr0-public") && > (!ct.trk || !ct.rpl)), action=(ct_dnat;) > ]) > > AT_CHECK([grep "lr_out_post_snat" lr0flows | ovn_strip_lflows], [0], [dnl > table=??(lr_out_post_snat ), priority=0 , match=(1), action=(next;) > table=??(lr_out_post_snat ), priority=153 , match=(ip && ip4.dst == > 10.0.0.0/24 && inport == "lr0-public" && is_chassis_resident("cr-lr0-public") > && ct.new), action=(ct_commit_to_zone(snat);) > table=??(lr_out_post_snat ), priority=161 , match=(ip && ip4.dst == > 10.0.0.10 && inport == "lr0-public" && is_chassis_resident("cr-lr0-public") > && ct.new), action=(ct_commit_to_zone(snat);) > + table=??(lr_out_post_snat ), priority=166 , match=(ip && ip4.dst == > 10.0.0.3 && inport == "lr0-public" && is_chassis_resident("cr-lr0-public") && > ct.new), action=(ct_commit_to_zone(dnat);) > ]) > > # Make the logical router as Gateway router > @@ -8389,9 +8398,9 @@ AT_CHECK([grep lr_in_unsnat lrflows | grep ct_snat | > ovn_strip_lflows], [0], [dn > ]) > > AT_CHECK([grep lr_out_snat lrflows | grep ct_snat | ovn_strip_lflows], [0], > [dnl > - table=??(lr_out_snat ), priority=161 , match=(ip && ip4.dst == > 20.0.0.10 && inport == "DR-S1" && is_chassis_resident("cr-DR-S1")), > action=(ct_snat;) > - table=??(lr_out_snat ), priority=161 , match=(ip && ip4.dst == > 20.0.0.10 && inport == "DR-S2" && is_chassis_resident("cr-DR-S2")), > action=(ct_snat;) > - table=??(lr_out_snat ), priority=161 , match=(ip && ip4.dst == > 20.0.0.10 && inport == "DR-S3" && is_chassis_resident("cr-DR-S3")), > action=(ct_snat;) > + table=??(lr_out_snat ), priority=161 , match=(ip && ip4.dst == > 20.0.0.10 && inport == "DR-S1" && is_chassis_resident("cr-DR-S1") && (!ct.trk > || !ct.rpl)), action=(ct_snat;) > + table=??(lr_out_snat ), priority=161 , match=(ip && ip4.dst == > 20.0.0.10 && inport == "DR-S2" && is_chassis_resident("cr-DR-S2") && (!ct.trk > || !ct.rpl)), action=(ct_snat;) > + table=??(lr_out_snat ), priority=161 , match=(ip && ip4.dst == > 20.0.0.10 && inport == "DR-S3" && is_chassis_resident("cr-DR-S3") && (!ct.trk > || !ct.rpl)), action=(ct_snat;) > table=??(lr_out_snat ), priority=161 , match=(ip && ip4.src == > 20.0.0.10 && outport == "DR-S1" && is_chassis_resident("cr-DR-S1") && > (!ct.trk || !ct.rpl)), action=(ct_snat(172.16.1.10);) > table=??(lr_out_snat ), priority=161 , match=(ip && ip4.src == > 20.0.0.10 && outport == "DR-S2" && is_chassis_resident("cr-DR-S2") && > (!ct.trk || !ct.rpl)), action=(ct_snat(10.0.0.10);) > table=??(lr_out_snat ), priority=161 , match=(ip && ip4.src == > 20.0.0.10 && outport == "DR-S3" && is_chassis_resident("cr-DR-S3") && > (!ct.trk || !ct.rpl)), action=(ct_snat(192.168.0.10);) > diff --git a/tests/system-common-macros.at b/tests/system-common-macros.at > index 251a4c0b8..1c6cefcd9 100644 > --- a/tests/system-common-macros.at > +++ b/tests/system-common-macros.at > @@ -614,3 +614,50 @@ m4_define([OVN_NEIGH_EQUAL], > m4_define([OVN_NEIGH_V6_EQUAL], > [OVS_WAIT_UNTIL_EQUAL([ip -6 neigh show dev $1 $2 | sed -e > 's|[[[[:space:]]]]*$||g' | grep $3 | sort], [$4]) > ]) > + > +# NS_CHECK_CONNECTIVITY([NS_SRC], [NS_DST], [IP_ADDR]) > +# > +# Ensures that network namespace NS_SRC can reach NS_DST on IP_ADDR. The > check performs: > +# * Ping > +# * Exchange of multiple messages over TCP > +# * Exchange of multiple messages over UDP > +m4_define([NS_CHECK_CONNECTIVITY], > +[ > + ns_src="$1" > + ns_dst="$2" > + ip="$3" > + # Start a simple TCP and UDP echo server that replies with "ack > <received_msg>". > + NETNS_DAEMONIZE($ns_dst, [nc -l -k -p 1235 -d 0.1 -c 'while read msg; do > echo "ack $msg"; done'], [nc-$ns_dst-$ip-tcp.pid]) > + NETNS_DAEMONIZE($ns_dst, [nc -l -u -k -p 1234 -d 0.1 -c 'read msg; echo > "ack $msg"'], [nc-$ns_dst-$ip-udp.pid]) > + > + # Ensure that the destination NS can be pinged on the specified IP > + NS_CHECK_EXEC([$ns_src], [ping -q -c 3 -i 0.3 -w 2 $ip | FORMAT_PING], \ > + [0], [dnl > +3 packets transmitted, 3 received, 0% packet loss, time 0ms > +]) > + > + # Exchange multiple messages over TCP and UDP to verify connectivity > + # Note(mkalcok): Server replies are printed to file, because STDOUT is > captured by the nc. > + truncate --size 0 ./tcp_data > + truncate --size 0 ./udp_data > + > + NETNS_DAEMONIZE($ns_src, [nc $ip 1235 -d 0.1 -c 'for i in $(seq 1 3); do > echo "tcp_data $i"; read msg; echo "$msg" >>./tcp_data; done'], > [nc_$ns_src-$ip-tcp.pid]) > + NETNS_DAEMONIZE($ns_src, [nc -u $ip 1234 -d 0.1 -c 'for i in $(seq 1 3); > do echo "udp_data $i"; read msg; echo "$msg" >>./udp_data; done'], > [nc_$ns_src-$ip-udp.pid]) > + > + OVS_WAIT_FOR_OUTPUT([cat ./tcp_data], [0], [dnl > +ack tcp_data 1 > +ack tcp_data 2 > +ack tcp_data 3 > +]) > + OVS_WAIT_FOR_OUTPUT([cat ./udp_data], [0], [dnl > +ack udp_data 1 > +ack udp_data 2 > +ack udp_data 3 > +]) > + > + # cleanup echo processes > + kill $(cat nc-$ns_dst-$ip-tcp.pid) > + kill $(cat nc-$ns_dst-$ip-udp.pid) > + kill $(cat nc_$ns_src-$ip-tcp.pid) > + kill $(cat nc_$ns_src-$ip-udp.pid) > +]) > diff --git a/tests/system-ovn.at b/tests/system-ovn.at > index 8e356df6f..0d01582a4 100644 > --- a/tests/system-ovn.at > +++ b/tests/system-ovn.at > @@ -3777,46 +3777,49 @@ AT_CHECK([ovn-nbctl lr-route-add R1 10.0.0.0/24 > 172.16.1.2]) > check ovn-nbctl --wait=hv sync > OVS_WAIT_UNTIL([ovs-ofctl dump-flows br-int | grep 'nat(src=172.16.1.1)']) > > -# North-South DNAT: 'alice1' pings 'foo1' using 172.16.1.3. > -NS_CHECK_EXEC([alice1], [ping -q -c 3 -i 0.3 -w 2 172.16.1.3 | FORMAT_PING], > \ > -[0], [dnl > -3 packets transmitted, 3 received, 0% packet loss, time 0ms > -]) > +# North-South DNAT: 'alice1' reaches 'foo1' on 172.16.1.3. > +NS_CHECK_CONNECTIVITY([alice1], [foo1], [172.16.1.3]) > > # We verify that DNAT indeed happened via 'dump-conntrack' command. > AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(172.16.1.3) | \ > sed -e 's/zone=[[0-9]]*/zone=<cleared>/'], [0], [dnl > > icmp,orig=(src=172.16.1.2,dst=172.16.1.3,id=<cleared>,type=8,code=0),reply=(src=192.168.1.2,dst=172.16.1.2,id=<cleared>,type=0,code=0),zone=<cleared> > +tcp,orig=(src=172.16.1.2,dst=172.16.1.3,sport=<cleared>,dport=<cleared>),reply=(src=192.168.1.2,dst=172.16.1.2,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>) > +udp,orig=(src=172.16.1.2,dst=172.16.1.3,sport=<cleared>,dport=<cleared>),reply=(src=192.168.1.2,dst=172.16.1.2,sport=<cleared>,dport=<cleared>),zone=<cleared> > ]) > > -# South-North SNAT: 'foo2' pings 'alice1'. But 'alice1' receives traffic > +# South-North SNAT: 'foo2' reaches 'alice1'. But 'alice1' receives traffic > # from 172.16.1.4 > -NS_CHECK_EXEC([foo2], [ping -q -c 3 -i 0.3 -w 2 172.16.1.2 | FORMAT_PING], \ > -[0], [dnl > -3 packets transmitted, 3 received, 0% packet loss, time 0ms > -]) > +NS_CHECK_CONNECTIVITY([foo2], [alice1], 172.16.1.2) > > # We verify that SNAT indeed happened via 'dump-conntrack' command. > AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(172.16.1.4) | \ > sed -e 's/zone=[[0-9]]*/zone=<cleared>/'], [0], [dnl > > icmp,orig=(src=192.168.1.3,dst=172.16.1.2,id=<cleared>,type=8,code=0),reply=(src=172.16.1.2,dst=172.16.1.4,id=<cleared>,type=0,code=0),zone=<cleared> > +tcp,orig=(src=192.168.1.3,dst=172.16.1.2,sport=<cleared>,dport=<cleared>),reply=(src=172.16.1.2,dst=172.16.1.4,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>) > +udp,orig=(src=192.168.1.3,dst=172.16.1.2,sport=<cleared>,dport=<cleared>),reply=(src=172.16.1.2,dst=172.16.1.4,sport=<cleared>,dport=<cleared>),zone=<cleared> > ]) > > AT_CHECK([ovs-appctl dpctl/flush-conntrack]) > > -# South-North SNAT: 'bar1' pings 'alice1'. But 'alice1' receives traffic > +# South-North SNAT: 'bar1' reaches 'alice1'. But 'alice1' receives traffic > # from 172.16.1.1 > -NS_CHECK_EXEC([bar1], [ping -q -c 3 -i 0.3 -w 2 172.16.1.2 | FORMAT_PING], \ > -[0], [dnl > -3 packets transmitted, 3 received, 0% packet loss, time 0ms > -]) > +NS_CHECK_CONNECTIVITY([bar1], [alice1], 172.16.1.2) > > # We verify that SNAT indeed happened via 'dump-conntrack' command. > AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(172.16.1.1) | \ > sed -e 's/zone=[[0-9]]*/zone=<cleared>/'], [0], [dnl > > icmp,orig=(src=192.168.2.2,dst=172.16.1.2,id=<cleared>,type=8,code=0),reply=(src=172.16.1.2,dst=172.16.1.1,id=<cleared>,type=0,code=0),zone=<cleared> > +tcp,orig=(src=192.168.2.2,dst=172.16.1.2,sport=<cleared>,dport=<cleared>),reply=(src=172.16.1.2,dst=172.16.1.1,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>) > +udp,orig=(src=192.168.2.2,dst=172.16.1.2,sport=<cleared>,dport=<cleared>),reply=(src=172.16.1.2,dst=172.16.1.1,sport=<cleared>,dport=<cleared>),zone=<cleared> > ]) > > +# North-South Direct (Bypassing DNAT): 'alice1' reaches 'foo1' using > 192.168.1.2 > +NS_CHECK_CONNECTIVITY(alice1, foo1, 192.168.1.2) > + > +# North-South Direct (Bypassing SNAT): 'alice1' reaches 'bar1' using > 192.168.2.2 > +NS_CHECK_CONNECTIVITY(alice1, bar1, 192.168.2.2) > + > # Try to ping external network > NETNS_START_TCPDUMP([ext-net], [-n -c 3 -i ext-veth dst 172.16.1.3 and > icmp], [ext-net]) > AT_CHECK([ovn-nbctl lr-nat-del R1 snat]) > @@ -3825,43 +3828,6 @@ NS_CHECK_EXEC([foo1], [ping -q -c 3 -i 0.3 -w 2 > 10.0.0.1 | FORMAT_PING], \ > 3 packets transmitted, 3 received, 0% packet loss, time 0ms > ]) > > -# test_connectivity_from_ext takes parameters 'vm' and 'ip'. It tests > -# icmp, udp and tcp connectivity from external network to the 'vm' on > -# the specified 'ip'. > -test_connectivity_from_ext() { > - local vm=$1; shift > - local ip=$1; shift > - > - # Start listening daemon TCP connections. > - NETNS_DAEMONIZE($vm, [nc -l -k 1235], [nc-$vm-$ip-tcp.pid]) > - > - # Ensure that vm can be pinged on the specified IP > - NS_CHECK_EXEC([alice1], [ping -q -c 3 -i 0.3 -w 2 $ip | FORMAT_PING], \ > - [0], [dnl > -3 packets transmitted, 3 received, 0% packet loss, time 0ms > -]) > - > - # Perform two consecutive UDP connections to the specified IP > - NETNS_DAEMONIZE($vm, [nc -l -u 1234], [nc-$vm-$ip-udp.pid]) > - NS_CHECK_EXEC([alice1], [nc -u $ip 1234 -p 2000 -z]) > - kill $(cat nc-$vm-$ip-udp.pid) > - > - NETNS_DAEMONIZE($vm, [nc -l -u 1234], [nc-$vm-$ip-udp.pid]) > - NS_CHECK_EXEC([alice1], [nc -u $ip 1234 -p 2000 -z]) > - kill $(cat nc-$vm-$ip-udp.pid) > - > - # Send data over TCP connection to the specified IP > - NS_CHECK_EXEC([alice1], [echo "TCP test" | nc --send-only $ip 1235]) > -} > - > -# Test access from external network to the internal IP of a VM that > -# has also configured DNAT > -test_connectivity_from_ext foo1 192.168.1.2 > - > -# Test access from external network to the internal IP of a VM that > -# does not have DNAT > -test_connectivity_from_ext bar1 192.168.2.2 > - > OVS_WAIT_UNTIL([ > total_pkts=$(cat ext-net.tcpdump | wc -l) > test "${total_pkts}" = "3" > @@ -3980,26 +3946,22 @@ AT_CHECK([ovn-nbctl lr-nat-add R1 snat fd20::1 ::/0]) > check ovn-nbctl --wait=hv sync > OVS_WAIT_UNTIL([ovs-ofctl dump-flows br-int | grep 'nat(src=fd20::1)']) > > -# North-South DNAT: 'alice1' pings 'foo1' using fd20::3 > -NS_CHECK_EXEC([alice1], [ping6 -q -c 3 -i 0.3 -w 2 fd20::3 | FORMAT_PING], \ > -[0], [dnl > -3 packets transmitted, 3 received, 0% packet loss, time 0ms > -]) > +# North-South DNAT: 'alice1' reaches 'foo1' using fd20::3 > +NS_CHECK_CONNECTIVITY([alice1], [foo1], [fd20::3]) > > # We verify that DNAT indeed happened via 'dump-conntrack' command. > AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(fd20::3) | \ > sed -e 's/zone=[[0-9]]*/zone=<cleared>/'], [0], [dnl > > icmpv6,orig=(src=fd20::2,dst=fd20::3,id=<cleared>,type=128,code=0),reply=(src=fd11::2,dst=fd20::2,id=<cleared>,type=129,code=0),zone=<cleared> > +tcp,orig=(src=fd20::2,dst=fd20::3,sport=<cleared>,dport=<cleared>),reply=(src=fd11::2,dst=fd20::2,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>) > +udp,orig=(src=fd20::2,dst=fd20::3,sport=<cleared>,dport=<cleared>),reply=(src=fd11::2,dst=fd20::2,sport=<cleared>,dport=<cleared>),zone=<cleared> > ]) > > AT_CHECK([ovs-appctl dpctl/flush-conntrack]) > > -# South-North SNAT: 'foo2' pings 'alice1'. But 'alice1' receives traffic > +# South-North SNAT: 'foo2' reaches 'alice1'. But 'alice1' receives traffic > # from fd20::4 > -NS_CHECK_EXEC([foo2], [ping6 -q -c 3 -i 0.3 -w 2 fd20::2 | FORMAT_PING], \ > -[0], [dnl > -3 packets transmitted, 3 received, 0% packet loss, time 0ms > -]) > +NS_CHECK_CONNECTIVITY([foo2], [alice1], fd20::2) > > ovs-appctl dpctl/dump-conntrack | grep icmpv6 > AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(fd11::3) | \ > @@ -4010,59 +3972,29 @@ sed -e 's/zone=[[0-9]]*/zone=<cleared>/'], [0], [dnl > AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(fd20::4) | \ > sed -e 's/zone=[[0-9]]*/zone=<cleared>/'], [0], [dnl > > icmpv6,orig=(src=fd11::3,dst=fd20::2,id=<cleared>,type=128,code=0),reply=(src=fd20::2,dst=fd20::4,id=<cleared>,type=129,code=0),zone=<cleared> > +tcp,orig=(src=fd11::3,dst=fd20::2,sport=<cleared>,dport=<cleared>),reply=(src=fd20::2,dst=fd20::4,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>) > +udp,orig=(src=fd11::3,dst=fd20::2,sport=<cleared>,dport=<cleared>),reply=(src=fd20::2,dst=fd20::4,sport=<cleared>,dport=<cleared>),zone=<cleared> > ]) > > AT_CHECK([ovs-appctl dpctl/flush-conntrack]) > > -# South-North SNAT: 'bar1' pings 'alice1'. But 'alice1' receives traffic > +# South-North SNAT: 'bar1' reaches 'alice1'. But 'alice1' receives traffic > # from fd20::1 > -NS_CHECK_EXEC([bar1], [ping6 -q -c 3 -i 0.3 -w 2 fd20::2 | FORMAT_PING], \ > -[0], [dnl > -3 packets transmitted, 3 received, 0% packet loss, time 0ms > -]) > +NS_CHECK_CONNECTIVITY([bar1], [alice1], fd20::2) > > # We verify that SNAT indeed happened via 'dump-conntrack' command. > AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(fd20::1) | \ > sed -e 's/zone=[[0-9]]*/zone=<cleared>/'], [0], [dnl > > icmpv6,orig=(src=fd12::2,dst=fd20::2,id=<cleared>,type=128,code=0),reply=(src=fd20::2,dst=fd20::1,id=<cleared>,type=129,code=0),zone=<cleared> > +tcp,orig=(src=fd12::2,dst=fd20::2,sport=<cleared>,dport=<cleared>),reply=(src=fd20::2,dst=fd20::1,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>) > +udp,orig=(src=fd12::2,dst=fd20::2,sport=<cleared>,dport=<cleared>),reply=(src=fd20::2,dst=fd20::1,sport=<cleared>,dport=<cleared>),zone=<cleared> > ]) > > -# test_connectivity_from_ext takes parameters 'vm' and 'ip'. It tests > -# icmp, udp and tcp connectivity from external network to the 'vm' on > -# the specified 'ip'. > -test_connectivity_from_ext() { > - local vm=$1; shift > - local ip=$1; shift > - > - # Start listening daemon for TCP connections. > - NETNS_DAEMONIZE($vm, [nc -6 -l -k 1235], [nc-$vm-$ip-tcp.pid]) > - > - # Ensure that vm can be pinged on the specified IP > - NS_CHECK_EXEC([alice1], [ping -q -c 3 -i 0.3 -w 2 $ip | FORMAT_PING], \ > - [0], [dnl > -3 packets transmitted, 3 received, 0% packet loss, time 0ms > -]) > - > - # Perform two consecutive UDP connections to the specified IP > - NETNS_DAEMONIZE($vm, [nc -6 -l -u 1234], [nc-$vm-$ip-udp.pid]) > - NS_CHECK_EXEC([alice1], [nc -u $ip 1234 -p 2000 -z]) > - kill $(cat nc-$vm-$ip-udp.pid) > - > - NETNS_DAEMONIZE($vm, [nc -6 -l -u 1234], [nc-$vm-$ip-udp.pid]) > - NS_CHECK_EXEC([alice1], [nc -u $ip 1234 -p 2000 -z]) > - kill $(cat nc-$vm-$ip-udp.pid) > - > - # Send data over TCP connection to the specified IP > - NS_CHECK_EXEC([alice1], [echo "TCP test" | nc --send-only $ip 1235]) > -} > - > -# Test access from external network to the internal IP of a VM that > -# has also configured DNAT > -test_connectivity_from_ext foo1 fd11::2 > +# North-South Direct (Bypassing DNAT): 'alice1' reaches 'foo1' using fd11::2 > +NS_CHECK_CONNECTIVITY([alice1], [foo1], [fd11::2]) > > -# Test access from external network to the internal IP of a VM that > -# does not have DNAT > -test_connectivity_from_ext bar1 fd12::2 > +# North-South Direct (Bypassing SNAT): 'alice1' reaches 'bar1' using fd12::2 > +NS_CHECK_CONNECTIVITY([alice1], [bar1], [fd12::2]) > > OVN_CLEANUP_CONTROLLER([hv1]) > > @@ -4244,7 +4176,6 @@ NS_CHECK_EXEC([foo2], [ping -q -c 3 -i 0.3 -w 2 > 172.16.1.4 | FORMAT_PING], \ > AT_CHECK([ovs-appctl dpctl/dump-conntrack | grep icmp | > FORMAT_CT(172.16.1.1) | \ > sed -e 's/zone=[[0-9]]*/zone=<cleared>/'], [0], [dnl > > icmp,orig=(src=172.16.1.1,dst=172.16.1.4,id=<cleared>,type=8,code=0),reply=(src=192.168.2.2,dst=172.16.1.1,id=<cleared>,type=0,code=0),zone=<cleared> > -icmp,orig=(src=172.16.1.1,dst=192.168.2.2,id=<cleared>,type=8,code=0),reply=(src=192.168.2.2,dst=172.16.1.1,id=<cleared>,type=0,code=0),zone=<cleared> > > icmp,orig=(src=192.168.1.3,dst=172.16.1.4,id=<cleared>,type=8,code=0),reply=(src=172.16.1.4,dst=172.16.1.1,id=<cleared>,type=0,code=0),zone=<cleared> > ]) > > @@ -4412,7 +4343,6 @@ NS_CHECK_EXEC([foo2], [ping -q -c 3 -i 0.3 -w 2 fd20::4 > | FORMAT_PING], \ > AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(fd20::1) | \ > sed -e 's/zone=[[0-9]]*/zone=<cleared>/'], [0], [dnl > > icmpv6,orig=(src=fd11::3,dst=fd20::4,id=<cleared>,type=128,code=0),reply=(src=fd20::4,dst=fd20::1,id=<cleared>,type=129,code=0),zone=<cleared> > -icmpv6,orig=(src=fd20::1,dst=fd12::2,id=<cleared>,type=128,code=0),reply=(src=fd12::2,dst=fd20::1,id=<cleared>,type=129,code=0),zone=<cleared> > > icmpv6,orig=(src=fd20::1,dst=fd20::4,id=<cleared>,type=128,code=0),reply=(src=fd12::2,dst=fd20::1,id=<cleared>,type=129,code=0),zone=<cleared> > ]) > > -- > 2.48.1 > > _______________________________________________ > dev mailing list > [email protected] > https://mail.openvswitch.org/mailman/listinfo/ovs-dev > _______________________________________________ dev mailing list [email protected] https://mail.openvswitch.org/mailman/listinfo/ovs-dev
