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

Reply via email to