[PATCH mptcp-next] selftests: mptcp: sockopt: test passive Fast Open early write push
From: T S Rameshkumar
Date: Thu Oct 08 2026 - 07:10:22 EST
Add automated test coverage for passive Fast Open early write data
push in mptcp_sockopt.c and mptcp_sockopt.sh.
The server enables TCP_FASTOPEN on an MPTCP listening socket, accepts
an incoming connection with SYN payload data, and immediately writes
reply bytes before the 3-way handshake fully completes. The client
connects with TCP_FASTOPEN_CONNECT, sends request data, and validates
reception of the server's reply over both IPv4 and IPv6.
Signed-off-by: T S Rameshkumar <rameshkumar.t@xxxxxxxxxxxxxxxxx>
---
.../selftests/net/mptcp/mptcp_sockopt.c | 59 ++++++++++++++++++-
.../selftests/net/mptcp/mptcp_sockopt.sh | 34 +++++++++++
2 files changed, 91 insertions(+), 2 deletions(-)
diff --git a/tools/testing/selftests/net/mptcp/mptcp_sockopt.c b/tools/testing/selftests/net/mptcp/mptcp_sockopt.c
index b6e58d936..04af7cebc 100644
--- a/tools/testing/selftests/net/mptcp/mptcp_sockopt.c
+++ b/tools/testing/selftests/net/mptcp/mptcp_sockopt.c
@@ -28,6 +28,7 @@
#include <linux/compiler.h>
static int pf = AF_INET;
+static bool do_tfo;
#ifndef IPPROTO_MPTCP
#define IPPROTO_MPTCP 262
@@ -247,6 +248,14 @@ static int sock_connect_mptcp(const char * const remoteaddr,
if (sock < 0)
continue;
+ if (do_tfo) {
+ int one = 1;
+
+ if (setsockopt(sock, IPPROTO_TCP, TCP_FASTOPEN_CONNECT,
+ &one, sizeof(one)) < 0)
+ die_perror("setsockopt TCP_FASTOPEN_CONNECT");
+ }
+
if (connect(sock, a->ai_addr, a->ai_addrlen) == 0)
break; /* success */
@@ -264,7 +273,7 @@ static void parse_opts(int argc, char **argv)
{
int c;
- while ((c = getopt(argc, argv, "h6")) != -1) {
+ while ((c = getopt(argc, argv, "h6f")) != -1) {
switch (c) {
case 'h':
die_usage(0);
@@ -272,6 +281,9 @@ static void parse_opts(int argc, char **argv)
case '6':
pf = AF_INET6;
break;
+ case 'f':
+ do_tfo = true;
+ break;
default:
die_usage(1);
break;
@@ -719,13 +731,36 @@ static int server(int pipefd)
break;
}
+ if (do_tfo) {
+ int qlen = 5;
+
+ if (setsockopt(fd, IPPROTO_TCP, TCP_FASTOPEN, &qlen, sizeof(qlen)) < 0)
+ die_perror("setsockopt TCP_FASTOPEN");
+ }
+
r = write(pipefd, "conn", 4);
assert(r == 4);
alarm(15);
r = xaccept(fd);
- process_one_client(r, pipefd);
+ if (do_tfo) {
+ char buf[64] = {0};
+ ssize_t n;
+
+ n = read(r, buf, sizeof(buf) - 1);
+ if (n <= 0)
+ die_perror("read tfo syn data");
+
+ n = write(r, "PONG_REPLY", 10);
+ if (n != 10)
+ die_perror("write tfo reply");
+
+ n = read(r, buf, 1);
+ close(r);
+ } else {
+ process_one_client(r, pipefd);
+ }
close(fd);
return 0;
@@ -775,6 +810,26 @@ static int client(int pipefd)
alarm(15);
+ if (do_tfo) {
+ const char *addr = (pf == AF_INET) ? "127.0.0.1" : "::1";
+ struct timeval tv = {.tv_sec = 5, .tv_usec = 0};
+ char buf[64] = {0};
+ ssize_t n;
+
+ fd = sock_connect_mptcp(addr, "15432", IPPROTO_MPTCP);
+ n = write(fd, "PING_DATA", 9);
+ if (n != 9)
+ die_perror("write PING_DATA");
+
+ setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
+ n = read(fd, buf, sizeof(buf) - 1);
+ if (n <= 0 || strcmp(buf, "PONG_REPLY") != 0)
+ xerror("Fastopen early write failed: received %zd bytes '%s'", n, buf);
+
+ close(fd);
+ return 0;
+ }
+
switch (pf) {
case AF_INET:
fd = sock_connect_mptcp("127.0.0.1", "15432", IPPROTO_MPTCP);
diff --git a/tools/testing/selftests/net/mptcp/mptcp_sockopt.sh b/tools/testing/selftests/net/mptcp/mptcp_sockopt.sh
index e850a8742..b3b523ce8 100755
--- a/tools/testing/selftests/net/mptcp/mptcp_sockopt.sh
+++ b/tools/testing/selftests/net/mptcp/mptcp_sockopt.sh
@@ -351,6 +351,39 @@ do_tcpinq_tests()
return $?
}
+do_fastopen_tests()
+{
+ local lret=0
+
+ ip netns exec "$ns_sbox" sysctl -q net.ipv4.tcp_fastopen=3
+
+ ip netns exec "$ns_sbox" ./mptcp_sockopt -f
+ lret=$?
+
+ print_title "Fast Open early write v4"
+ if [ $lret -ne 0 ]; then
+ mptcp_lib_pr_fail
+ mptcp_lib_result_fail "Fast Open early write v4"
+ ret=$lret
+ return
+ fi
+ mptcp_lib_pr_ok
+ mptcp_lib_result_pass "Fast Open early write v4"
+
+ ip netns exec "$ns_sbox" ./mptcp_sockopt -6 -f
+ lret=$?
+
+ print_title "Fast Open early write v6"
+ if [ $lret -ne 0 ]; then
+ mptcp_lib_pr_fail
+ mptcp_lib_result_fail "Fast Open early write v6"
+ ret=$lret
+ return
+ fi
+ mptcp_lib_pr_ok
+ mptcp_lib_result_pass "Fast Open early write v6"
+}
+
sin=$(mktemp)
sout=$(mktemp)
cin=$(mktemp)
@@ -366,6 +399,7 @@ run_tests $ns1 $ns2 dead:beef:1::1
do_mptcp_sockopt_tests
do_tcpinq_tests
+do_fastopen_tests
mptcp_lib_result_print_all_tap
exit $ret
--
2.34.1