[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20251016040159.3534435-3-kuniyu@google.com>
Date: Thu, 16 Oct 2025 04:00:34 +0000
From: Kuniyuki Iwashima <kuniyu@...gle.com>
To: Eric Dumazet <edumazet@...gle.com>, Neal Cardwell <ncardwell@...gle.com>,
"David S. Miller" <davem@...emloft.net>, Jakub Kicinski <kuba@...nel.org>, Paolo Abeni <pabeni@...hat.com>
Cc: Simon Horman <horms@...nel.org>, Yuchung Cheng <ycheng@...gle.com>,
Willem de Bruijn <willemb@...gle.com>, Kuniyuki Iwashima <kuniyu@...gle.com>,
Kuniyuki Iwashima <kuni1840@...il.com>, netdev@...r.kernel.org
Subject: [PATCH v1 net-next 2/4] selftest: packetdrill: Import TFO sendto tests.
These two TFO client tests are imported from google/packetdrill
on GitHub:
* client_nonblocking-sendto-errnos.pkt
* nonblocking-sendto-empty-buf.pkt
Both files had tests for 0 payload sendto(MSG_FASTOPEN) assuming
that SYN will be sent w/ TFO cookie if cached,
+0 sendto(4, ..., 0, MSG_FASTOPEN, ..., ...) = -1 EINPROGRESS (Operation is now in progress)
+0 > S 0:0(0) <mss 1460,nop,nop,sackOK,nop,wscale 8,FO 112233445566>
and now it fails with the previous patch, so this part is fixed
up in both files.
In addition, the former had lengthy 6s wait in the last test case
to ensure that there will not be multiple SYN retransmissions, and
I changed it to 2s because now linear timeout is enabled by default
(it can be reduced further to 1s, but 2s just in case to avoid
flakiness).
Signed-off-by: Kuniyuki Iwashima <kuniyu@...gle.com>
---
...en_client_nonblocking-sendto-empty-buf.pkt | 45 +++++++
...topen_client_nonblocking-sendto-errnos.pkt | 125 ++++++++++++++++++
2 files changed, 170 insertions(+)
create mode 100644 tools/testing/selftests/net/packetdrill/tcp_fastopen_client_nonblocking-sendto-empty-buf.pkt
create mode 100644 tools/testing/selftests/net/packetdrill/tcp_fastopen_client_nonblocking-sendto-errnos.pkt
diff --git a/tools/testing/selftests/net/packetdrill/tcp_fastopen_client_nonblocking-sendto-empty-buf.pkt b/tools/testing/selftests/net/packetdrill/tcp_fastopen_client_nonblocking-sendto-empty-buf.pkt
new file mode 100644
index 0000000000000..6ebeff7c5857e
--- /dev/null
+++ b/tools/testing/selftests/net/packetdrill/tcp_fastopen_client_nonblocking-sendto-empty-buf.pkt
@@ -0,0 +1,45 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// Non-blocking Fast Open with an empty buffer
+//
+`./defaults.sh
+ ./set_sysctls.py /proc/sys/net/ipv4/tcp_timestamps=0`
+
+ 0 socket(..., SOCK_STREAM|SOCK_NONBLOCK, IPPROTO_TCP) = 3
+ +0 sendto(3, ..., 0, MSG_FASTOPEN, ..., ...) = -1 EINPROGRESS (Operation is now in progress)
+ +0 > S 0:0(0) <mss 1460,nop,nop,sackOK,nop,wscale 8,FO,nop,nop>
+ +0 < S. 123:123(0) ack 1 win 14600 <mss 1460,nop,nop,sackOK,nop,wscale 6,FO abcd1234,nop,nop>
+ +0 > . 1:1(0) ack 1
+ +0 close(3) = 0
+ +0 > F. 1:1(0) ack 1
+ +0 < F. 1:1(0) ack 2 win 92
+ +0 > . 2:2(0) ack 2
+
+
+//
+// Test: non-blocking sendto() of 0B
+//
+ +0 socket(..., SOCK_STREAM|SOCK_NONBLOCK, IPPROTO_TCP) = 4
+ +0 sendto(4, ..., 0, MSG_FASTOPEN, ..., ...) = -1 EINPROGRESS (Operation is now in progress)
+
+// TFO cookie (FO abcd1234) is not sent w/o payload
+ +0 > S 0:0(0) <mss 1460,nop,nop,sackOK,nop,wscale 8,FO,nop,nop>
+
+// Server acks FO and replies a different MSS (940B)
+ +0 < S. 1234:1234(0) ack 1 win 14600 <mss 940,nop,nop,sackOK,nop,wscale 6,FO 12345678,nop,nop>
+ +0 > . 1:1(0) ack 1
+ +0 %{ assert (tcpi_options & TCPI_OPT_SYN_DATA) == 0, tcpi_options }%
+
+
+//
+// Test: previous server's MSS (940B) and cookie are still cached
+//
+ +0 socket(..., SOCK_STREAM|SOCK_NONBLOCK, IPPROTO_TCP) = 5
+ +0 sendto(5, ..., 2000, MSG_FASTOPEN, ..., ...) = 900
+ +0 > S 0:900(900) <mss 1460,nop,nop,sackOK,nop,wscale 8,FO 12345678,nop,nop>
+// Sever acknowledges the data but also sends new cookie
+ +0 < S. 5678:5678(0) ack 901 win 14600 <mss 1460,nop,nop,sackOK,nop,wscale 6,FO 000000000000>
+ +0 > . 901:901(0) ack 1
+ +0 %{ assert (tcpi_options & TCPI_OPT_SYN_DATA) != 0, tcpi_options }%
+
+`/tmp/sysctl_restore_${PPID}.sh`
diff --git a/tools/testing/selftests/net/packetdrill/tcp_fastopen_client_nonblocking-sendto-errnos.pkt b/tools/testing/selftests/net/packetdrill/tcp_fastopen_client_nonblocking-sendto-errnos.pkt
new file mode 100644
index 0000000000000..2f74880fe3bbc
--- /dev/null
+++ b/tools/testing/selftests/net/packetdrill/tcp_fastopen_client_nonblocking-sendto-errnos.pkt
@@ -0,0 +1,125 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// Test non-blocking sendto(MSG_FASTOPEN) errno(s).
+//
+`./defaults.sh
+ ./set_sysctls.py /proc/sys/net/ipv4/tcp_timestamps=0 \
+ /proc/sys/net/ipv4/tcp_fastopen_blackhole_timeout_sec=0`
+
+///////////////////////////////////////////////////////////////////////////////
+// Non-blocking errnos
+//
+ 0 socket(..., SOCK_STREAM|SOCK_NONBLOCK, IPPROTO_TCP) = 3
+ +0 `sysctl -q net.ipv4.tcp_fastopen=0`
+//
+// Test: EOPNOTSUPP if fastopen is disabled
+//
+ +0 sendto(3, ..., 1000, MSG_FASTOPEN, ..., ...) = -1 EOPNOTSUPP (Operation not supported)
+ +0 `sysctl -q net.ipv4.tcp_fastopen=1`
+
+
+//
+// Test: 0-byte sendto() returns EINPROGRESS when no cookie is in cache
+//
+ +0 sendto(3, ..., 0, MSG_FASTOPEN, ..., ...) = -1 EINPROGRESS (Operation now in progress)
+ +0 > S 0:0(0) <mss 1460,nop,nop,sackOK,nop,wscale 8,FO,nop,nop>
+ +0 %{ assert (tcpi_options & TCPI_OPT_SYN_DATA) == 0, tcpi_options }%
+ +0 close(3) = 0
+
+
+ +0 socket(..., SOCK_STREAM|SOCK_NONBLOCK, IPPROTO_TCP) = 4
+//
+// Test: 1000-byte sendto() returns EINPROGRESS when no cookie is in cache
+//
+ +0 sendto(4, ..., 1000, MSG_FASTOPEN|MSG_DONTWAIT, ..., ...) = -1 EINPROGRESS (Operation now in progress)
+ +0 > S 0:0(0) <mss 1460,nop,nop,sackOK,nop,wscale 8,FO,nop,nop>
+//
+// Test: EALREADY on multiple sendto(MSG_FASTOPEN) in SYN-SENT
+//
+ +0 sendto(4, ..., 1000, MSG_FASTOPEN, ..., ...) = -1 EALREADY (Operation already in progress)
+//
+// Test: EAGAIN on write() in SYN-SENT
+//
+ +0 write(4, ..., 1000) = -1 EAGAIN (Resource temporarily unavailable)
+ +0 < S. 0:0(0) ack 1 win 5840 <mss 1460,nop,nop,sackOK,nop,wscale 6,FO 112233445566>
+ +0 > . 1:1(0) ack 1
+ +0 %{ assert (tcpi_options & TCPI_OPT_SYN_DATA) == 0, tcpi_options }%
+ +0 close(4) = 0
+
+
+//
+// Repeat previous tests with a valid cookie cached locally
+//
+ +0 socket(..., SOCK_STREAM|SOCK_NONBLOCK, IPPROTO_TCP) = 5
+//
+// Test: *NO* EINPROGRESS in SYN-SENT b/c data are buffered and transmitted
+//
+ +0 sendto(5, ..., 1000, MSG_FASTOPEN, ..., ...) = 1000
+ +0 > S 0:1000(1000) <mss 1460,nop,nop,sackOK,nop,wscale 8,FO 112233445566>
+//
+// Test: EALREADY on multiple sendto(MSG_FASTOPEN) in SYN-SENT
+//
+ +0 sendto(5, ..., 1000, MSG_FASTOPEN, ..., ...) = -1 EALREADY (Operation already in progress)
+//
+// Test: EAGAIN on write() in SYN-SENT
+//
+ +0 write(5, ..., 1000) = -1 EAGAIN (Resource temporarily unavailable)
+ +0 < S. 506036:506036(0) ack 1001 win 5840 <mss 1460,nop,nop,sackOK,nop,wscale 6>
+ +0 > . 1001:1001(0) ack 1
+ +0 %{ assert (tcpi_options & TCPI_OPT_SYN_DATA) != 0, tcpi_options }%
+ +0 close(5) = 0
+
+
+//
+// Test: a 0-byte sendto() returns EINPROGRESS even if cookie is in the cache.
+// since sendto(MSG_FASTOPEN) is a connect and write combo, and a null
+// write is a no-op, so it should behave like a normal connect()
+//
+ +0 socket(..., SOCK_STREAM|SOCK_NONBLOCK, IPPROTO_TCP) = 6
+ +0 sendto(6, ..., 0, MSG_FASTOPEN, ..., ...) = -1 EINPROGRESS (Operation now in progress)
+ +0 > S 0:0(0) <mss 1460,nop,nop,sackOK,nop,wscale 8,FO,nop,nop>
+ +0 %{ assert (tcpi_options & TCPI_OPT_SYN_DATA) == 0, tcpi_options }%
+ +0 close(6) = 0
+
+
+//
+// Test: ECONNREFUSED when remote resets on SYN
+//
+ +0 socket(..., SOCK_STREAM|SOCK_NONBLOCK, IPPROTO_TCP) = 7
+ +0 sendto(7, ..., 2000, MSG_FASTOPEN, ..., ...) = 1420
+ +0 > S 0:1420(1420) <mss 1460,nop,nop,sackOK,nop,wscale 8,FO 112233445566>
+ +0 < R. 0:0(0) ack 1 win 0
+ +0 write(7, ..., 2000) = -1 ECONNREFUSED (Connection Refused)
+ +0 %{ assert (tcpi_options & TCPI_OPT_SYN_DATA) == 0, tcpi_options }%
+ +0 close(7) = 0
+
+
+//
+// Test: ECONNRESET if RST is received after SYN
+//
+ +0 socket(..., SOCK_STREAM|SOCK_NONBLOCK, IPPROTO_TCP) = 8
+ +0 sendto(8, ..., 1420, MSG_FASTOPEN, ..., ...) = 1420
+ +0 > S 0:1420(1420) <mss 1460,nop,nop,sackOK,nop,wscale 8,FO 112233445566>
+ +0 < S. 0:0(0) ack 1421 win 5840 <mss 1460,wscale 6,nop>
+ +0 > . 1421:1421(0) ack 1
+ +0 < R. 1:1(0) ack 1421 win 0
+ +0 write(8, ..., 2000) = -1 ECONNRESET (Connection reset by peer)
+ +0 %{ assert (tcpi_options & TCPI_OPT_SYN_DATA) != 0, tcpi_options }%
+
+
+//
+// Test: ETIMEOUT when SYN timed out
+//
+ +0 socket(..., SOCK_STREAM, IPPROTO_TCP) = 9
+ +0 sendto(9, ..., 2000, MSG_FASTOPEN|MSG_DONTWAIT, ..., ...) = 1420
+// Retry once to make this test shorter.
+ +0 setsockopt(9, IPPROTO_TCP, TCP_SYNCNT, [1], 4) = 0
+ +0 > S 0:1420(1420) <mss 1460,nop,nop,sackOK,nop,wscale 8,FO 112233445566>
+ +1 > S 0:0(0) <mss 1460,nop,nop,sackOK,nop,wscale 8>
+// Why wait 2 sec? it's a bug fixed in 4d22f7d372f5
+// https://bugzilla.redhat.com/show_bug.cgi?id=688989
+// Originally, it was 6 sec but now 2 sec thanks to linear timeout
+ +2 write(9, ..., 2000) = -1 ETIMEDOUT (Connection timed out)
+ +0 %{ assert (tcpi_options & TCPI_OPT_SYN_DATA) == 0, tcpi_options }%
+
+`/tmp/sysctl_restore_${PPID}.sh`
--
2.51.0.788.g6d19910ace-goog
Powered by blists - more mailing lists