* [PATCH net-next v2 0/2] selftests: openvswitch: SCTP flow key coverage (IPv6 + NAT)
@ 2026-09-02 12:51 Minxi Hou
2026-09-02 12:51 ` [PATCH net-next v2 1/2] selftests/net/openvswitch: add SCTP flow key test over IPv6 Minxi Hou
2026-09-02 12:51 ` [PATCH net-next v2 2/2] selftests/net/openvswitch: add SCTP flow key test across conntrack NAT Minxi Hou
0 siblings, 2 replies; 5+ messages in thread
From: Minxi Hou @ 2026-09-02 12:51 UTC (permalink / raw)
To: netdev
Cc: aconole, davem, dev, echaudro, edumazet, i.maximets, i.maximets,
kuba, linux-kernel, linux-kselftest, pabeni, shuah, horms,
Minxi Hou
The SCTP flow key test merged in August covers only IPv4 and only the
plain forwarding path. This series extends coverage to the two paths a
regression would otherwise ship silently on: SCTP over IPv6, and SCTP
across conntrack NAT (where OVS re-extracts L3/L4 on the recirculated
skb).
Both tests verify the association and then push a known payload across
and confirm the listener received it, so a flow-key bug that matches
handshake packets but breaks DATA chunks is caught rather than passing
on the handshake alone.
Full OVS selftest suite runs 19/19 green on a freshly built kernel.
v2:
- no code changes; rebased onto current net-next after the tree
reopened (v1 was deferred while net-next was closed)
Minxi Hou (2):
selftests/net/openvswitch: add SCTP flow key test over IPv6
selftests/net/openvswitch: add SCTP flow key test across conntrack NAT
.../selftests/net/openvswitch/openvswitch.sh | 183 +++++++++++++++++-
1 file changed, 182 insertions(+), 1 deletion(-)
base-commit: d0ec95a8a4e79f2fd6063fc8932415db8c227689
--
2.55.0
^ permalink raw reply [flat|nested] 5+ messages in thread* [PATCH net-next v2 1/2] selftests/net/openvswitch: add SCTP flow key test over IPv6 2026-09-02 12:51 [PATCH net-next v2 0/2] selftests: openvswitch: SCTP flow key coverage (IPv6 + NAT) Minxi Hou @ 2026-09-02 12:51 ` Minxi Hou 2026-09-06 15:00 ` netdev-bot+sashiko 2026-09-02 12:51 ` [PATCH net-next v2 2/2] selftests/net/openvswitch: add SCTP flow key test across conntrack NAT Minxi Hou 1 sibling, 1 reply; 5+ messages in thread From: Minxi Hou @ 2026-09-02 12:51 UTC (permalink / raw) To: netdev Cc: aconole, davem, dev, echaudro, edumazet, i.maximets, i.maximets, kuba, linux-kernel, linux-kselftest, pabeni, shuah, horms, Minxi Hou The merged SCTP test covers only IPv4. The IPv6 extraction path (parse_ipv6hdr walking extension headers, then the proto=132 branch in key_extract) and the v6 side of the SCTP netlink validation have no selftest coverage at all, so a regression there would ship silently. Add test_sctp_connect_v6 mirroring the v4 test: NS/NA forwarding flows stand in for ARP, and ipv6(proto=132),sctp(dst=4443)/sctp(src=4443) flows gate the association in the same three phases (flows installed, flows removed, flows reinstalled). After the association succeeds the test also pushes a known payload across and verifies the listener received it, so a flow-key bug that matches handshake packets but breaks DATA chunks is caught too. Skips when the sctp module is missing, socat lacks SCTP support, or IPv6 is unavailable; an association or DATA failure with the flows installed fails the test. Signed-off-by: Minxi Hou <houminxi@gmail.com> --- v2: rebased onto current net-next, no code changes .../selftests/net/openvswitch/openvswitch.sh | 97 ++++++++++++++++++- 1 file changed, 96 insertions(+), 1 deletion(-) diff --git a/tools/testing/selftests/net/openvswitch/openvswitch.sh b/tools/testing/selftests/net/openvswitch/openvswitch.sh index a31f7fb6882dc..06bd98d80a084 100755 --- a/tools/testing/selftests/net/openvswitch/openvswitch.sh +++ b/tools/testing/selftests/net/openvswitch/openvswitch.sh @@ -33,7 +33,8 @@ tests=" action_set set: SET action rewrites fields trunc trunc: output truncation icmpv6 icmpv6: ICMPv6 echo type match - sctp_connect_v4 sctp: SCTP flow key matching + sctp_connect_v4 sctp: SCTP flow key matching + sctp_connect_v6 sctp6: SCTP flow key matching over IPv6 psample psample: Sampling packets with psample" info() { @@ -700,6 +701,100 @@ test_sctp_connect_v4() { return 0 } +# sctp_connect_v6 test +# - sctp(dst=4443) matches client-to-server INIT +# - sctp(src=4443) matches server-to-client INIT-ACK +# - icmpv6 NS/NA flows forward neighbour discovery +# - remove flows and verify connection fails, reinstall and recover +test_sctp_connect_v6() { + local t="test_sctp_connect_v6" + local v6="eth_type(0x86dd),ipv6(proto=132)" + local payload="SCTP6_DATA_OK" + local rxfile="${ovs_base}/${t}/sctp-rx.txt" + + modprobe -q sctp 2>/dev/null || return "$ksft_skip" + socat -V 2>&1 | grep -q "define WITH_SCTP" || return "$ksft_skip" + [ -e /proc/sys/net/ipv6 ] || return "$ksft_skip" + + sbx_add "$t" || return $? + ovs_add_dp "$t" sctp6 || return 1 + + info "create namespaces" + for ns in client server; do + ovs_add_netns_and_veths "$t" "sctp6" "$ns" \ + "${ns:0:1}0" "${ns:0:1}1" || return 1 + done + + ip netns exec client ip addr add fd00::1/64 dev c1 nodad + ip netns exec client ip link set c1 up + ip netns exec server ip addr add fd00::2/64 dev s1 nodad + ip netns exec server ip link set s1 up + + # NS/NA forwarding + ovs_add_flow "$t" sctp6 \ + 'in_port(1),eth(),eth_type(0x86dd),ipv6(proto=58),icmpv6()' \ + '2' || return 1 + ovs_add_flow "$t" sctp6 \ + 'in_port(2),eth(),eth_type(0x86dd),ipv6(proto=58),icmpv6()' \ + '1' || return 1 + + # SCTP port matching: dst for request, src for reply + ovs_add_flow "$t" sctp6 \ + "in_port(1),eth(),$v6,sctp(dst=4443)" \ + '2' || return 1 + ovs_add_flow "$t" sctp6 \ + "in_port(2),eth(),$v6,sctp(src=4443)" \ + '1' || return 1 + + ovs_netns_spawn_daemon "$t" "server" \ + socat -u -t 1 SCTP6-LISTEN:4443,fork \ + OPEN:"$rxfile",creat,append + ovs_wait sctp_eps_has server 4443 || return 1 + + info "verify SCTP association with port-keyed flows" + ovs_sbx "$t" ip netns exec client \ + timeout 3 socat -u STDIN "SCTP6-CONNECT:[fd00::2]:4443" </dev/null \ + || return 1 + + info "verify SCTP DATA chunk crosses the datapath" + ovs_sbx "$t" ip netns exec client \ + timeout 3 socat -u STDIN "SCTP6-CONNECT:[fd00::2]:4443" \ + <<< "$payload" || return 1 + grep -q "$payload" "$rxfile" 2>/dev/null \ + || { info "server did not receive SCTP DATA payload" + return 1; } + + ovs_del_flows "$t" sctp6 + + info "verify connection fails without flows" + ovs_add_flow "$t" sctp6 \ + 'in_port(1),eth(),eth_type(0x86dd),ipv6(proto=58),icmpv6()' \ + '2' || return 1 + ovs_add_flow "$t" sctp6 \ + 'in_port(2),eth(),eth_type(0x86dd),ipv6(proto=58),icmpv6()' \ + '1' || return 1 + + ovs_sbx "$t" ip netns exec client \ + timeout 3 socat -u STDIN "SCTP6-CONNECT:[fd00::2]:4443" </dev/null \ + >/dev/null 2>&1 \ + && { info "connection should fail without flows" + return 1; } + + info "reinstall flows and verify recovery" + ovs_add_flow "$t" sctp6 \ + "in_port(1),eth(),$v6,sctp(dst=4443)" \ + '2' || return 1 + ovs_add_flow "$t" sctp6 \ + "in_port(2),eth(),$v6,sctp(src=4443)" \ + '1' || return 1 + + ovs_sbx "$t" ip netns exec client \ + timeout 3 socat -u STDIN "SCTP6-CONNECT:[fd00::2]:4443" </dev/null \ + || return 1 + + return 0 +} + # psample test # - use psample to observe packets test_psample() { base-commit: d0ec95a8a4e79f2fd6063fc8932415db8c227689 -- 2.55.0 ^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [PATCH net-next v2 1/2] selftests/net/openvswitch: add SCTP flow key test over IPv6 2026-09-02 12:51 ` [PATCH net-next v2 1/2] selftests/net/openvswitch: add SCTP flow key test over IPv6 Minxi Hou @ 2026-09-06 15:00 ` netdev-bot+sashiko 0 siblings, 0 replies; 5+ messages in thread From: netdev-bot+sashiko @ 2026-09-06 15:00 UTC (permalink / raw) To: houminxi Cc: netdev, aconole, davem, dev, echaudro, edumazet, i.maximets, i.maximets, kuba, linux-kernel, linux-kselftest, pabeni, shuah, horms Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider: Critical: 0 · High: 0 · Medium: 2 · Low: 1 - [Medium] Commit message rationale is not supported by the code it claims to cover. - [Medium] Unsynchronized cross-process assertion makes the test flaky. - [Low] The patch contains a spurious hunk that rewrites the whitespace of the pre-existing `sctp_connect_v4` entry in the `tests` list… -- selftests/net/openvswitch: add SCTP flow key test over IPv6 Adds test_sctp_connect_v6 to the openvswitch selftest, mirroring the existing IPv4 SCTP test with NS/NA forwarding flows and ipv6(proto=132),sctp(dst=4443)/sctp(src=4443) flows gating an association in three phases, plus a payload transfer check. A couple of questions about the commit message and the new test below. [Severity: Medium] The commit message says: After the association succeeds the test also pushes a known payload across and verifies the listener received it, so a flow-key bug that matches handshake packets but breaks DATA chunks is caught too. Can such a flow-key bug exist? The SCTP extraction in key_extract_l3l4() never looks at chunk types, it only copies the two port fields out of the 12-byte common header: net/openvswitch/flow.c:key_extract_l3l4() { ... } else if (key->ip.proto == NEXTHDR_SCTP) { if (sctphdr_ok(skb)) { struct sctphdr *sctp = sctp_hdr(skb); key->tp.src = sctp->source; key->tp.dst = sctp->dest; ... } The IPv4 branch (key->ip.proto == IPPROTO_SCTP) does exactly the same. So INIT, INIT-ACK, DATA and SACK all produce identical key->tp.src / key->tp.dst, and the flow key cannot distinguish them. The same paragraph also says: The IPv6 extraction path (parse_ipv6hdr walking extension headers, then the proto=132 branch in key_extract) and the v6 side of the SCTP netlink validation have no selftest coverage at all Is that accurate for parse_ipv6hdr()? The pre-existing test_icmpv6() in the same script already sends IPv6 traffic through the datapath, which runs key_extract_l3l4() -> parse_ipv6hdr(). And the new test only configures fd00::1/fd00::2 and sends plain SCTP6 socat traffic, so no hop-by-hop, routing or fragment header is ever generated and this loop net/openvswitch/flow.c:parse_ipv6hdr() { ... nexthdr = ipv6_find_hdr(skb, &payload_ofs, -1, &frag_off, &flags); ... } is only exercised in the trivial nexthdr == 132 case. Could the message be narrowed to what is genuinely new, i.e. the NEXTHDR_SCTP branch and the v6 SCTP netlink key? > diff --git a/tools/testing/selftests/net/openvswitch/openvswitch.sh b/tools/testing/selftests/net/openvswitch/openvswitch.sh > index a31f7fb6882d..06bd98d80a08 100755 > --- a/tools/testing/selftests/net/openvswitch/openvswitch.sh > +++ b/tools/testing/selftests/net/openvswitch/openvswitch.sh > @@ -33,7 +33,8 @@ tests=" > action_set set: SET action rewrites fields > trunc trunc: output truncation > icmpv6 icmpv6: ICMPv6 echo type match > - sctp_connect_v4 sctp: SCTP flow key matching > + sctp_connect_v4 sctp: SCTP flow key matching > + sctp_connect_v6 sctp6: SCTP flow key matching over IPv6 [Severity: Low] This isn't a bug, but why is the pre-existing sctp_connect_v4 line rewritten here? The four tabs become three, which is unrelated to adding an IPv6 test and the changelog says v2 has "no code changes". Word splitting is unaffected because IFS is set to tab+newline before the "for t in ${tests}" loop, but usage() prints the string verbatim: echo "Available tests${tests}" With one leading tab, a 15-character name and four tabs the description starts at column 48 like every other entry; with three tabs both the modified sctp_connect_v4 row and the new sctp_connect_v6 row start at column 40 and are misaligned against the rest of the help output. > psample psample: Sampling packets with psample" > > info() { [ ... ] > @@ -700,6 +701,100 @@ test_sctp_connect_v4() { > return 0 > } > > +# sctp_connect_v6 test [ ... ] > + ovs_netns_spawn_daemon "$t" "server" \ > + socat -u -t 1 SCTP6-LISTEN:4443,fork \ > + OPEN:"$rxfile",creat,append > + ovs_wait sctp_eps_has server 4443 || return 1 > + > + info "verify SCTP association with port-keyed flows" > + ovs_sbx "$t" ip netns exec client \ > + timeout 3 socat -u STDIN "SCTP6-CONNECT:[fd00::2]:4443" </dev/null \ > + || return 1 > + > + info "verify SCTP DATA chunk crosses the datapath" > + ovs_sbx "$t" ip netns exec client \ > + timeout 3 socat -u STDIN "SCTP6-CONNECT:[fd00::2]:4443" \ > + <<< "$payload" || return 1 > + grep -q "$payload" "$rxfile" 2>/dev/null \ > + || { info "server did not receive SCTP DATA payload" > + return 1; } [Severity: Medium] Can this grep race with the listener and make the test flaky? $rxfile is written by the forked socat child spawned in the background by ovs_netns_spawn_daemon(): ip netns exec $netns $* >> $ovs_dir/stdout 2>> $ovs_dir/stderr & The client socat exits once its local send and teardown are done, so its exit status says nothing about the server child having read the DATA chunk and written it out. The grep runs immediately after, with no barrier in between. If the server child has not been scheduled yet, the file is either missing (grep exit 2, hidden by 2>/dev/null) or present but empty (grep exit 1 - the earlier payload-less association already created it via creat), and both land in the return 1 branch, giving a [FAIL] and exitcode=1. Would ovs_wait be the right primitive here? It is already used four lines above for the listener readiness check: ovs_wait sctp_eps_has server 4443 || return 1 and ovs_wait() retries for WAIT_TIMEOUT seconds, doubling it when KSFT_MACHINE_SLOW=yes, which is exactly the loaded-CI case that loses this race. The same unsynchronized pattern appears again in the follow-up commit adding test_sctp_nat_connect_v4, so it is not corrected later in the series. > + > + ovs_del_flows "$t" sctp6 [ ... ] -- Sashiko AI review · https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20260902125133.1828572-1-houminxi%40gmail.com ^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH net-next v2 2/2] selftests/net/openvswitch: add SCTP flow key test across conntrack NAT 2026-09-02 12:51 [PATCH net-next v2 0/2] selftests: openvswitch: SCTP flow key coverage (IPv6 + NAT) Minxi Hou 2026-09-02 12:51 ` [PATCH net-next v2 1/2] selftests/net/openvswitch: add SCTP flow key test over IPv6 Minxi Hou @ 2026-09-02 12:51 ` Minxi Hou 2026-09-06 15:00 ` netdev-bot+sashiko 1 sibling, 1 reply; 5+ messages in thread From: Minxi Hou @ 2026-09-02 12:51 UTC (permalink / raw) To: netdev Cc: aconole, davem, dev, echaudro, edumazet, i.maximets, i.maximets, kuba, linux-kernel, linux-kselftest, pabeni, shuah, horms, Minxi Hou Conntrack NAT rewrites the packet between the first-pass and recirc passes, and OVS re-extracts L3/L4 on the recirculated skb via ovs_flow_key_update_l3l4(). Nothing in the suite exercises SCTP key extraction on that post-NAT path: the existing nat test drives TCP over nc, and the merged SCTP test has no conntrack in the path. Add test_sctp_nat_connect_v4, reusing the nat4 fixture with the SCTP socket pair from the v4 SCTP test: untracked ipv4 traffic hits ct(commit,nat(...)),recirc, and the post-recirc flows match ct_state(+trk) with the extracted sctp(dst=4443)/sctp(src=4443) ports. A probe for the SCTP conntrack sysctl turns a kernel without working SCTP conntrack into a skip instead of an opaque timeout. After the association succeeds the test pushes a known payload across and verifies the listener received it, so a flow-key bug that matches handshake packets but breaks DATA chunks is caught too. If ct+nat is accepted but the association or DATA fails, the test fails. Signed-off-by: Minxi Hou <houminxi@gmail.com> --- v2: rebased onto current net-next, no code changes .../selftests/net/openvswitch/openvswitch.sh | 86 +++++++++++++++++++ 1 file changed, 86 insertions(+) diff --git a/tools/testing/selftests/net/openvswitch/openvswitch.sh b/tools/testing/selftests/net/openvswitch/openvswitch.sh index 06bd98d80a084..d5acdca0a0ac1 100755 --- a/tools/testing/selftests/net/openvswitch/openvswitch.sh +++ b/tools/testing/selftests/net/openvswitch/openvswitch.sh @@ -35,6 +35,7 @@ tests=" icmpv6 icmpv6: ICMPv6 echo type match sctp_connect_v4 sctp: SCTP flow key matching sctp_connect_v6 sctp6: SCTP flow key matching over IPv6 + sctp_nat_connect_v4 sctpnat4: SCTP flow key across conntrack NAT psample psample: Sampling packets with psample" info() { @@ -1186,6 +1187,91 @@ test_nat_connect_v4 () { return 0 } +# sctp_nat_connect_v4 test +# - SCTP association crosses a ct(commit,nat(dst=...)) translation +# - post-recirc flows match ct_state(+trk) plus the extracted SCTP ports +test_sctp_nat_connect_v4 () { + local t="test_sctp_nat_connect_v4" + local payload="SCTP_NAT_DATA_OK" + local rxfile="${ovs_base}/${t}/sctp-rx.txt" + + modprobe -q sctp 2>/dev/null || return "$ksft_skip" + socat -V 2>&1 | grep -q "define WITH_SCTP" || return "$ksft_skip" + # SCTP conntrack is compiled into nf_conntrack.ko, so check that + # loading it actually exposed the SCTP conntrack sysctls. + modprobe -q nf_conntrack 2>/dev/null || return "$ksft_skip" + [ -e /proc/sys/net/netfilter/nf_conntrack_sctp_timeout_established ] \ + || { info "no SCTP conntrack support - skipping" + return "$ksft_skip"; } + + sbx_add "test_sctp_nat_connect_v4" || return $? + + ovs_add_dp "test_sctp_nat_connect_v4" sctpnat4 || return 1 + info "create namespaces" + for ns in client server; do + ovs_add_netns_and_veths "test_sctp_nat_connect_v4" "sctpnat4" \ + "$ns" "${ns:0:1}0" "${ns:0:1}1" || return 1 + done + + ip netns exec client ip addr add 172.31.110.10/24 dev c1 + ip netns exec client ip link set c1 up + ip netns exec server ip addr add 172.31.110.20/24 dev s1 + ip netns exec server ip link set s1 up + + ip netns exec client ip route add default via 172.31.110.20 + + # Check if the ct action can be configured. + ovs_add_flow "test_sctp_nat_connect_v4" sctpnat4 \ + 'in_port(1),eth(),eth_type(0x0800),ipv4()' \ + 'ct(commit),recirc(0x1)' &> /dev/null + if [ $? == 1 ]; then + info "no support for ct action - skipping" + ovs_exit_sig + return $ksft_skip + fi + + ovs_del_flows "test_sctp_nat_connect_v4" sctpnat4 + + ovs_add_flow "test_sctp_nat_connect_v4" sctpnat4 \ + 'in_port(1),eth(),eth_type(0x0806),arp()' '2' || return 1 + ovs_add_flow "test_sctp_nat_connect_v4" sctpnat4 \ + 'in_port(2),eth(),eth_type(0x0806),arp()' '1' || return 1 + ovs_add_flow "test_sctp_nat_connect_v4" sctpnat4 \ + "ct_state(-trk),in_port(1),eth(),eth_type(0x0800),ipv4(dst=192.168.0.20)" \ + "ct(commit,nat(dst=172.31.110.20)),recirc(0x1)" || return 1 + ovs_add_flow "test_sctp_nat_connect_v4" sctpnat4 \ + "ct_state(-trk),in_port(2),eth(),eth_type(0x0800),ipv4()" \ + "ct(commit,nat),recirc(0x2)" || return 1 + + ovs_add_flow "test_sctp_nat_connect_v4" sctpnat4 \ + "recirc_id(0x1),ct_state(+trk-inv),in_port(1),eth(),eth_type(0x0800),ipv4(proto=132),sctp(dst=4443)" \ + "2" || return 1 + ovs_add_flow "test_sctp_nat_connect_v4" sctpnat4 \ + "recirc_id(0x2),ct_state(+trk-inv),in_port(2),eth(),eth_type(0x0800),ipv4(proto=132),sctp(src=4443)" \ + "1" || return 1 + + ovs_netns_spawn_daemon "test_sctp_nat_connect_v4" "server" \ + socat -u -t 1 SCTP4-LISTEN:4443,fork \ + OPEN:"$rxfile",creat,append + ovs_wait sctp_eps_has server 4443 || return 1 + + info "verify SCTP association across NAT" + ovs_sbx "test_sctp_nat_connect_v4" ip netns exec client \ + timeout 3 socat -u STDIN "SCTP4-CONNECT:192.168.0.20:4443" \ + </dev/null || return 1 + + info "verify SCTP DATA chunk crosses NAT" + ovs_sbx "test_sctp_nat_connect_v4" ip netns exec client \ + timeout 3 socat -u STDIN "SCTP4-CONNECT:192.168.0.20:4443" \ + <<< "$payload" || return 1 + grep -q "$payload" "$rxfile" 2>/dev/null \ + || { info "server did not receive SCTP DATA payload" + return 1; } + + info "done..." + return 0 +} + # nat_related_v4 test # - client->server ip packets go via SNAT # - client solicits ICMP destination unreachable packet from server base-commit: d0ec95a8a4e79f2fd6063fc8932415db8c227689 prerequisite-patch-id: a3848bf8ef3803b528f964b8e866dd3622e5b154 -- 2.55.0 ^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [PATCH net-next v2 2/2] selftests/net/openvswitch: add SCTP flow key test across conntrack NAT 2026-09-02 12:51 ` [PATCH net-next v2 2/2] selftests/net/openvswitch: add SCTP flow key test across conntrack NAT Minxi Hou @ 2026-09-06 15:00 ` netdev-bot+sashiko 0 siblings, 0 replies; 5+ messages in thread From: netdev-bot+sashiko @ 2026-09-06 15:00 UTC (permalink / raw) To: houminxi Cc: netdev, aconole, davem, dev, echaudro, edumazet, i.maximets, i.maximets, kuba, linux-kernel, linux-kselftest, pabeni, shuah, horms Thank you for your contribution! Sashiko AI review found 4 potential issue(s) to consider: Critical: 0 · High: 0 · Medium: 3 · Low: 1 - [Medium] Commit-message/coverage mismatch: the new `test_sctp_nat_connect_v4` cannot detect the bug class its commit… - [Medium] `test_sctp_nat_connect_v4` probes only the plain `ct(commit)` action (openvswitch.sh:1224-1231) before deciding SKIP vs. run, but… - [Medium] Unsynchronized cross-process check makes the new test flaky. - [Low] The Open vSwitch selftest Kconfig fragment (tools/testing/selftests/net/openvswitch/config) is not updated for… -- selftests/net/openvswitch: add SCTP flow key test across conntrack NAT This adds test_sctp_nat_connect_v4 to the openvswitch selftest suite. It builds a client/server namespace pair, installs ct(commit,nat(...)) plus recirc flows, and checks that an SCTP association and a DATA payload cross the translation. A few questions about the new test below. > diff --git a/tools/testing/selftests/net/openvswitch/openvswitch.sh b/tools/testing/selftests/net/openvswitch/openvswitch.sh > index 06bd98d80a08..d5acdca0a0ac 100755 > --- a/tools/testing/selftests/net/openvswitch/openvswitch.sh > +++ b/tools/testing/selftests/net/openvswitch/openvswitch.sh [ ... ] > @@ -1186,6 +1187,91 @@ test_nat_connect_v4 () { > return 0 > } > > +# sctp_nat_connect_v4 test > +# - SCTP association crosses a ct(commit,nat(dst=...)) translation > +# - post-recirc flows match ct_state(+trk) plus the extracted SCTP ports > +test_sctp_nat_connect_v4 () { > + local t="test_sctp_nat_connect_v4" > + local payload="SCTP_NAT_DATA_OK" > + local rxfile="${ovs_base}/${t}/sctp-rx.txt" > + > + modprobe -q sctp 2>/dev/null || return "$ksft_skip" > + socat -V 2>&1 | grep -q "define WITH_SCTP" || return "$ksft_skip" > + # SCTP conntrack is compiled into nf_conntrack.ko, so check that > + # loading it actually exposed the SCTP conntrack sysctls. > + modprobe -q nf_conntrack 2>/dev/null || return "$ksft_skip" > + [ -e /proc/sys/net/netfilter/nf_conntrack_sctp_timeout_established ] \ > + || { info "no SCTP conntrack support - skipping" > + return "$ksft_skip"; } [Severity: Low] Should tools/testing/selftests/net/openvswitch/config gain the kernel options this new test depends on? The sysctl probed here only exists when CONFIG_NF_CT_PROTO_SCTP is enabled, and that option is an independent bool: net/netfilter/Kconfig: config NF_CT_PROTO_SCTP bool 'SCTP protocol connection tracking support' depends on NETFILTER_ADVANCED default y With NETFILTER_ADVANCED=n the dependency is unmet and the option is off in spite of the default, and a base config that sets it to n is unaffected by merging the fragment. The current fragment has: CONFIG_IP_SCTP=y CONFIG_NF_CONNTRACK=m CONFIG_NF_CONNTRACK_OVS=y CONFIG_OPENVSWITCH=m so in those builds the test returns $ksft_skip and the coverage the changelog describes never runs. Would adding CONFIG_NF_CT_PROTO_SCTP=y (and CONFIG_NF_NAT=y, see below) to the fragment make it deterministic? [ ... ] > + # Check if the ct action can be configured. > + ovs_add_flow "test_sctp_nat_connect_v4" sctpnat4 \ > + 'in_port(1),eth(),eth_type(0x0800),ipv4()' \ > + 'ct(commit),recirc(0x1)' &> /dev/null > + if [ $? == 1 ]; then > + info "no support for ct action - skipping" > + ovs_exit_sig > + return $ksft_skip > + fi [Severity: Medium] This probe tests plain ct(commit), but the flows installed below require the nat action. Does that turn a missing CONFIG_NF_NAT into a reported failure instead of a skip? In net/openvswitch/conntrack.c, both the policy entry and the parse arm are compiled conditionally: #if IS_ENABLED(CONFIG_NF_NAT) /* NAT length is checked when parsing the nested attributes. */ [OVS_CT_ATTR_NAT] = { .minlen = 0, .maxlen = INT_MAX }, #endif With NF_NAT off the entry is {0, 0}, so the nested nat attribute fails the length check in parse_ct() and the flow add is rejected with -EINVAL, while the ct(commit) probe above still succeeds. That configuration is reachable from the suite's own fragment, which does not set CONFIG_NF_NAT, and: net/netfilter/Kconfig: config NF_NAT tristate "Network Address Translation support" depends on NF_CONNTRACK default m if NETFILTER_ADVANCED=n CONFIG_OPENVSWITCH only does "select NF_NAT_OVS if NF_NAT", so with the usual NETFILTER_ADVANCED=y, NF_NAT defaults to n. Would probing with ct(commit,nat(dst=...)) instead, or skipping rather than failing on the nat flow adds, keep this a skip? [ ... ] > + ovs_add_flow "test_sctp_nat_connect_v4" sctpnat4 \ > + "ct_state(-trk),in_port(1),eth(),eth_type(0x0800),ipv4(dst=192.168.0.20)" \ > + "ct(commit,nat(dst=172.31.110.20)),recirc(0x1)" || return 1 > + ovs_add_flow "test_sctp_nat_connect_v4" sctpnat4 \ > + "ct_state(-trk),in_port(2),eth(),eth_type(0x0800),ipv4()" \ > + "ct(commit,nat),recirc(0x2)" || return 1 > + > + ovs_add_flow "test_sctp_nat_connect_v4" sctpnat4 \ > + "recirc_id(0x1),ct_state(+trk-inv),in_port(1),eth(),eth_type(0x0800),ipv4(proto=132),sctp(dst=4443)" \ > + "2" || return 1 > + ovs_add_flow "test_sctp_nat_connect_v4" sctpnat4 \ > + "recirc_id(0x2),ct_state(+trk-inv),in_port(2),eth(),eth_type(0x0800),ipv4(proto=132),sctp(src=4443)" \ > + "1" || return 1 [Severity: Medium] Can these flows actually detect a post-NAT SCTP flow key bug? nat(dst=172.31.110.20) rewrites only the IPv4 destination and never a port, and the post-recirc flows match ipv4(proto=132) plus sctp(dst=4443) / sctp(src=4443) - exactly the fields NAT leaves alone. The translated addresses are not matched at all. The post-NAT ports are patched into the key here: net/openvswitch/conntrack.c:ovs_nat_update_key() { ... if (key->ip.proto == IPPROTO_UDP) dst = udp_hdr(skb)->dest; else if (key->ip.proto == IPPROTO_TCP) dst = tcp_hdr(skb)->dest; else if (key->ip.proto == IPPROTO_SCTP) dst = sctp_hdr(skb)->dest; else return; key->tp.dst = dst; ... } If the IPPROTO_SCTP arms were deleted so the function took the bare return, key->tp.dst / key->tp.src would keep their identical first-pass values and both flows would still match, so the test would still pass. Would matching on distinct translated SCTP ports, and/or on the translated addresses in the post-recirc flows, give the intended coverage? Also on the changelog: Conntrack NAT rewrites the packet between the first-pass and recirc passes, and OVS re-extracts L3/L4 on the recirculated skb via ovs_flow_key_update_l3l4(). Is that the path this test exercises? ovs_flow_key_update_l3l4() in net/openvswitch/flow.c has a single caller: net/openvswitch/conntrack.c:ovs_ct_handle_fragments() { ... /* The key extracted from the fragment that completed this datagram * likely didn't have an L4 header, so regenerate it. */ ovs_flow_key_update_l3l4(skb, key); ... } that is, only for datagrams reassembled from IP fragments, which this test never produces. On the plain ct+recirc path the key is not re-extracted: net/openvswitch/actions.c:execute_recirc() { ... if (!is_flow_key_valid(key)) { int err; err = ovs_flow_key_update(skb, key); ... } and the CT/NAT action does not call invalidate_flow_key(). After the association succeeds the test pushes a known payload across and verifies the listener received it, so a flow-key bug that matches handshake packets but breaks DATA chunks is caught too. Is there such a distinction? SCTP key extraction reads only the common header source/destination ports, which are the same for INIT and DATA chunks. > + ovs_netns_spawn_daemon "test_sctp_nat_connect_v4" "server" \ > + socat -u -t 1 SCTP4-LISTEN:4443,fork \ > + OPEN:"$rxfile",creat,append [ ... ] > + info "verify SCTP DATA chunk crosses NAT" > + ovs_sbx "test_sctp_nat_connect_v4" ip netns exec client \ > + timeout 3 socat -u STDIN "SCTP4-CONNECT:192.168.0.20:4443" \ > + <<< "$payload" || return 1 > + grep -q "$payload" "$rxfile" 2>/dev/null \ > + || { info "server did not receive SCTP DATA payload" > + return 1; } [Severity: Medium] Can this grep race the server writing $rxfile? The listener is started in the background: ovs_netns_spawn_daemon() { ... ip netns exec $netns $* >> $ovs_dir/stdout 2>> $ovs_dir/stderr & pid=$! ... } and ",fork" means a separate per-association child does the read() and the write() into $rxfile. The client socat exiting only means its own socket was closed; delivery to the server socket, the child's read() and its write() to the file all happen afterwards in another process, and "-t 1" decouples the child's lifetime from the client's exit. So this interleaving looks possible: client socat exits shell runs grep -q on an empty/short $rxfile -> return 1 server child writes payload Every other cross-process observation in this file goes through the retry helper, and this same test already uses it for endpoint readiness: ovs_wait sctp_eps_has server 4443 || return 1 with ovs_wait() polling up to WAIT_TIMEOUT (raised to 10s when KSFT_MACHINE_SLOW=yes). Would "ovs_wait grep -q "$payload" "$rxfile"" be more robust here? The same one-shot grep pattern was introduced one patch earlier in this series, in the IPv6 SCTP test, so both places would need the same change. > + > + info "done..." > + return 0 > +} > + [ ... ] -- Sashiko AI review · https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20260902125133.1828572-1-houminxi%40gmail.com ^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2026-09-06 15:00 UTC | newest] Thread overview: 5+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2026-09-02 12:51 [PATCH net-next v2 0/2] selftests: openvswitch: SCTP flow key coverage (IPv6 + NAT) Minxi Hou 2026-09-02 12:51 ` [PATCH net-next v2 1/2] selftests/net/openvswitch: add SCTP flow key test over IPv6 Minxi Hou 2026-09-06 15:00 ` netdev-bot+sashiko 2026-09-02 12:51 ` [PATCH net-next v2 2/2] selftests/net/openvswitch: add SCTP flow key test across conntrack NAT Minxi Hou 2026-09-06 15:00 ` netdev-bot+sashiko
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox