* [PATCH mptcp-next v3 01/14] selftests: mptcp: sockopt: replace /dev/urandom with getrandom
2025-08-26 9:29 [PATCH mptcp-next v3 00/14] selftests: consolidate TCP_INQ testing into sockopt Geliang Tang
@ 2025-08-26 9:29 ` Geliang Tang
2025-08-26 9:29 ` [PATCH mptcp-next v3 02/14] selftests: mptcp: sockopt: add protocol arguments Geliang Tang
` (13 subsequent siblings)
14 siblings, 0 replies; 16+ messages in thread
From: Geliang Tang @ 2025-08-26 9:29 UTC (permalink / raw)
To: mptcp; +Cc: Geliang Tang
From: Geliang Tang <tanggeliang@kylinos.cn>
Replace /dev/urandom with getrandom() for initializing the RNG. This
simplifies the code and avoids potential failures from opening device
files while maintaining cryptographic quality randomness.
These codes are from mptcp_inq.c.
Signed-off-by: Geliang Tang <tanggeliang@kylinos.cn>
---
.../selftests/net/mptcp/mptcp_sockopt.c | 20 +++++++------------
1 file changed, 7 insertions(+), 13 deletions(-)
diff --git a/tools/testing/selftests/net/mptcp/mptcp_sockopt.c b/tools/testing/selftests/net/mptcp/mptcp_sockopt.c
index e934dd26a59d..2bd75f731dfd 100644
--- a/tools/testing/selftests/net/mptcp/mptcp_sockopt.c
+++ b/tools/testing/selftests/net/mptcp/mptcp_sockopt.c
@@ -20,6 +20,7 @@
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/wait.h>
+#include <sys/random.h>
#include <netdb.h>
#include <netinet/in.h>
@@ -815,21 +816,14 @@ static int rcheck(int wstatus, const char *what)
static void init_rng(void)
{
- int fd = open("/dev/urandom", O_RDONLY);
+ unsigned int foo;
- if (fd >= 0) {
- unsigned int foo;
- ssize_t ret;
-
- /* can't fail */
- ret = read(fd, &foo, sizeof(foo));
- assert(ret == sizeof(foo));
-
- close(fd);
- srand(foo);
- } else {
- srand(time(NULL));
+ if (getrandom(&foo, sizeof(foo), 0) == -1) {
+ perror("getrandom");
+ exit(1);
}
+
+ srand(foo);
}
int main(int argc, char *argv[])
--
2.48.1
^ permalink raw reply related [flat|nested] 16+ messages in thread* [PATCH mptcp-next v3 02/14] selftests: mptcp: sockopt: add protocol arguments
2025-08-26 9:29 [PATCH mptcp-next v3 00/14] selftests: consolidate TCP_INQ testing into sockopt Geliang Tang
2025-08-26 9:29 ` [PATCH mptcp-next v3 01/14] selftests: mptcp: sockopt: replace /dev/urandom with getrandom Geliang Tang
@ 2025-08-26 9:29 ` Geliang Tang
2025-08-26 9:29 ` [PATCH mptcp-next v3 03/14] selftests: mptcp: sockopt: add inq argument Geliang Tang
` (12 subsequent siblings)
14 siblings, 0 replies; 16+ messages in thread
From: Geliang Tang @ 2025-08-26 9:29 UTC (permalink / raw)
To: mptcp; +Cc: Geliang Tang
From: Geliang Tang <tanggeliang@kylinos.cn>
Add -t and -r options to specify tx/rx protocols (TCP/MPTCP). This
increases testing flexibility by allowing explicit protocol selection
for both transmission and reception paths.
These codes are from mptcp_inq.c.
Signed-off-by: Geliang Tang <tanggeliang@kylinos.cn>
---
.../selftests/net/mptcp/mptcp_sockopt.c | 36 +++++++++++++++----
1 file changed, 29 insertions(+), 7 deletions(-)
diff --git a/tools/testing/selftests/net/mptcp/mptcp_sockopt.c b/tools/testing/selftests/net/mptcp/mptcp_sockopt.c
index 2bd75f731dfd..05caa9a57ac4 100644
--- a/tools/testing/selftests/net/mptcp/mptcp_sockopt.c
+++ b/tools/testing/selftests/net/mptcp/mptcp_sockopt.c
@@ -28,6 +28,8 @@
#include <linux/tcp.h>
static int pf = AF_INET;
+static int proto_tx = IPPROTO_MPTCP;
+static int proto_rx = IPPROTO_MPTCP;
#ifndef IPPROTO_MPTCP
#define IPPROTO_MPTCP 262
@@ -136,7 +138,7 @@ static void die_perror(const char *msg)
static void die_usage(int r)
{
- fprintf(stderr, "Usage: mptcp_sockopt [-6]\n");
+ fprintf(stderr, "Usage: mptcp_sockopt [-6] [-t tcp|mptcp] [-r tcp|mptcp]\n");
exit(r);
}
@@ -202,7 +204,7 @@ static int sock_listen_mptcp(const char * const listenaddr,
hints.ai_family = pf;
for (a = addr; a; a = a->ai_next) {
- sock = socket(a->ai_family, a->ai_socktype, IPPROTO_MPTCP);
+ sock = socket(a->ai_family, a->ai_socktype, proto_rx);
if (sock < 0)
continue;
@@ -260,11 +262,22 @@ static int sock_connect_mptcp(const char * const remoteaddr,
return sock;
}
+static int protostr_to_num(const char *s)
+{
+ if (strcasecmp(s, "tcp") == 0)
+ return IPPROTO_TCP;
+ if (strcasecmp(s, "mptcp") == 0)
+ return IPPROTO_MPTCP;
+
+ die_usage(1);
+ return 0;
+}
+
static void parse_opts(int argc, char **argv)
{
int c;
- while ((c = getopt(argc, argv, "h6")) != -1) {
+ while ((c = getopt(argc, argv, "h6t:r:")) != -1) {
switch (c) {
case 'h':
die_usage(0);
@@ -272,6 +285,12 @@ static void parse_opts(int argc, char **argv)
case '6':
pf = AF_INET6;
break;
+ case 't':
+ proto_tx = protostr_to_num(optarg);
+ break;
+ case 'r':
+ proto_rx = protostr_to_num(optarg);
+ break;
default:
die_usage(1);
break;
@@ -557,6 +576,9 @@ static void do_getsockopt_mptcp_full_info(struct so_state *s, int fd)
static void do_getsockopts(struct so_state *s, int fd, size_t r, size_t w)
{
+ if (proto_tx != IPPROTO_MPTCP || proto_rx != IPPROTO_MPTCP)
+ return;
+
do_getsockopt_mptcp_info(s, fd, w);
do_getsockopt_tcp_info(s, fd, r, w);
@@ -632,7 +654,7 @@ static void connect_one_server(int fd, int pipefd)
if (eof)
total += 1; /* sequence advances due to FIN */
- assert(s.mptcpi_rcv_delta == (uint64_t)total);
+ assert(s.mptcpi_rcv_delta ? s.mptcpi_rcv_delta == (uint64_t)total : true);
close(fd);
}
@@ -667,7 +689,7 @@ static void process_one_client(int fd, int pipefd)
xerror("expected EOF, got %lu", ret3);
do_getsockopts(&s, fd, ret, ret2);
- if (s.mptcpi_rcv_delta != (uint64_t)ret + 1)
+ if (s.mptcpi_rcv_delta && s.mptcpi_rcv_delta != (uint64_t)ret + 1)
xerror("mptcpi_rcv_delta %" PRIu64 ", expect %" PRIu64, s.mptcpi_rcv_delta, ret + 1, s.mptcpi_rcv_delta - ret);
/* be nice when running on top of older kernel */
@@ -772,10 +794,10 @@ static int client(int pipefd)
switch (pf) {
case AF_INET:
- fd = sock_connect_mptcp("127.0.0.1", "15432", IPPROTO_MPTCP);
+ fd = sock_connect_mptcp("127.0.0.1", "15432", proto_tx);
break;
case AF_INET6:
- fd = sock_connect_mptcp("::1", "15432", IPPROTO_MPTCP);
+ fd = sock_connect_mptcp("::1", "15432", proto_tx);
break;
default:
xerror("Unknown pf %d\n", pf);
--
2.48.1
^ permalink raw reply related [flat|nested] 16+ messages in thread* [PATCH mptcp-next v3 03/14] selftests: mptcp: sockopt: add inq argument
2025-08-26 9:29 [PATCH mptcp-next v3 00/14] selftests: consolidate TCP_INQ testing into sockopt Geliang Tang
2025-08-26 9:29 ` [PATCH mptcp-next v3 01/14] selftests: mptcp: sockopt: replace /dev/urandom with getrandom Geliang Tang
2025-08-26 9:29 ` [PATCH mptcp-next v3 02/14] selftests: mptcp: sockopt: add protocol arguments Geliang Tang
@ 2025-08-26 9:29 ` Geliang Tang
2025-08-26 9:29 ` [PATCH mptcp-next v3 04/14] selftests: mptcp: sockopt: set TCP_INQ on accepted sockets Geliang Tang
` (11 subsequent siblings)
14 siblings, 0 replies; 16+ messages in thread
From: Geliang Tang @ 2025-08-26 9:29 UTC (permalink / raw)
To: mptcp; +Cc: Geliang Tang
From: Geliang Tang <tanggeliang@kylinos.cn>
Introduce -i option to enable TCP_INQ testing. This prepares for
consolidating TCP_INQ tests into a single binary by adding the necessary
command-line interface.
Signed-off-by: Geliang Tang <tanggeliang@kylinos.cn>
---
tools/testing/selftests/net/mptcp/mptcp_sockopt.c | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/tools/testing/selftests/net/mptcp/mptcp_sockopt.c b/tools/testing/selftests/net/mptcp/mptcp_sockopt.c
index 05caa9a57ac4..cb3d8dc34997 100644
--- a/tools/testing/selftests/net/mptcp/mptcp_sockopt.c
+++ b/tools/testing/selftests/net/mptcp/mptcp_sockopt.c
@@ -30,6 +30,7 @@
static int pf = AF_INET;
static int proto_tx = IPPROTO_MPTCP;
static int proto_rx = IPPROTO_MPTCP;
+static bool inq;
#ifndef IPPROTO_MPTCP
#define IPPROTO_MPTCP 262
@@ -138,7 +139,7 @@ static void die_perror(const char *msg)
static void die_usage(int r)
{
- fprintf(stderr, "Usage: mptcp_sockopt [-6] [-t tcp|mptcp] [-r tcp|mptcp]\n");
+ fprintf(stderr, "Usage: mptcp_sockopt [-6] [-t tcp|mptcp] [-r tcp|mptcp] [-i]\n");
exit(r);
}
@@ -277,7 +278,7 @@ static void parse_opts(int argc, char **argv)
{
int c;
- while ((c = getopt(argc, argv, "h6t:r:")) != -1) {
+ while ((c = getopt(argc, argv, "h6t:r:i")) != -1) {
switch (c) {
case 'h':
die_usage(0);
@@ -291,6 +292,9 @@ static void parse_opts(int argc, char **argv)
case 'r':
proto_rx = protostr_to_num(optarg);
break;
+ case 'i':
+ inq = true;
+ break;
default:
die_usage(1);
break;
--
2.48.1
^ permalink raw reply related [flat|nested] 16+ messages in thread* [PATCH mptcp-next v3 04/14] selftests: mptcp: sockopt: set TCP_INQ on accepted sockets
2025-08-26 9:29 [PATCH mptcp-next v3 00/14] selftests: consolidate TCP_INQ testing into sockopt Geliang Tang
` (2 preceding siblings ...)
2025-08-26 9:29 ` [PATCH mptcp-next v3 03/14] selftests: mptcp: sockopt: add inq argument Geliang Tang
@ 2025-08-26 9:29 ` Geliang Tang
2025-08-26 9:29 ` [PATCH mptcp-next v3 05/14] selftests: mptcp: sockopt: use unix socket instead of pipe Geliang Tang
` (10 subsequent siblings)
14 siblings, 0 replies; 16+ messages in thread
From: Geliang Tang @ 2025-08-26 9:29 UTC (permalink / raw)
To: mptcp; +Cc: Geliang Tang
From: Geliang Tang <tanggeliang@kylinos.cn>
Add helper functions to conditionally set TCP_INQ sockopt on accepted
sockets when running in inq mode. This ensures proper testing of TCP_CM_INQ
functionality by enabling the required socket option on both ends of the
connection. This setup is necessary for validating TCP_CM_INQ behavior
during TCP_INQ-specific tests.
These codes are from mptcp_inq.c.
Signed-off-by: Geliang Tang <tanggeliang@kylinos.cn>
---
tools/testing/selftests/net/mptcp/mptcp_sockopt.c | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/tools/testing/selftests/net/mptcp/mptcp_sockopt.c b/tools/testing/selftests/net/mptcp/mptcp_sockopt.c
index cb3d8dc34997..366e4aa4df0b 100644
--- a/tools/testing/selftests/net/mptcp/mptcp_sockopt.c
+++ b/tools/testing/selftests/net/mptcp/mptcp_sockopt.c
@@ -715,6 +715,14 @@ static void process_one_client(int fd, int pipefd)
close(fd);
}
+static void do_setsockopt_inq(int fd)
+{
+ int on = 1;
+
+ if (setsockopt(fd, IPPROTO_TCP, TCP_INQ, &on, sizeof(on)))
+ die_perror("setsockopt(TCP_INQ)");
+}
+
static int xaccept(int s)
{
int fd = accept(s, NULL, 0);
@@ -722,6 +730,9 @@ static int xaccept(int s)
if (fd < 0)
die_perror("accept");
+ if (inq)
+ do_setsockopt_inq(fd);
+
return fd;
}
--
2.48.1
^ permalink raw reply related [flat|nested] 16+ messages in thread* [PATCH mptcp-next v3 05/14] selftests: mptcp: sockopt: use unix socket instead of pipe
2025-08-26 9:29 [PATCH mptcp-next v3 00/14] selftests: consolidate TCP_INQ testing into sockopt Geliang Tang
` (3 preceding siblings ...)
2025-08-26 9:29 ` [PATCH mptcp-next v3 04/14] selftests: mptcp: sockopt: set TCP_INQ on accepted sockets Geliang Tang
@ 2025-08-26 9:29 ` Geliang Tang
2025-08-26 9:29 ` [PATCH mptcp-next v3 06/14] selftests: mptcp: sockopt: read eof at the end of process_one_client Geliang Tang
` (9 subsequent siblings)
14 siblings, 0 replies; 16+ messages in thread
From: Geliang Tang @ 2025-08-26 9:29 UTC (permalink / raw)
To: mptcp; +Cc: Geliang Tang
From: Geliang Tang <tanggeliang@kylinos.cn>
Replaces pipe-based synchronization with Unix domain socket pairs
(SOCK_DGRAM) for better bidirectional communication reliability
between server and client processes.
These codes are from mptcp_inq.c.
Signed-off-by: Geliang Tang <tanggeliang@kylinos.cn>
---
.../selftests/net/mptcp/mptcp_sockopt.c | 36 +++++++++----------
1 file changed, 18 insertions(+), 18 deletions(-)
diff --git a/tools/testing/selftests/net/mptcp/mptcp_sockopt.c b/tools/testing/selftests/net/mptcp/mptcp_sockopt.c
index 366e4aa4df0b..add29bdda9e5 100644
--- a/tools/testing/selftests/net/mptcp/mptcp_sockopt.c
+++ b/tools/testing/selftests/net/mptcp/mptcp_sockopt.c
@@ -593,7 +593,7 @@ static void do_getsockopts(struct so_state *s, int fd, size_t r, size_t w)
do_getsockopt_mptcp_full_info(s, fd);
}
-static void connect_one_server(int fd, int pipefd)
+static void connect_one_server(int fd, int unixfd)
{
char buf[4096], buf2[4096];
size_t len, i, total;
@@ -618,9 +618,9 @@ static void connect_one_server(int fd, int pipefd)
do_getsockopts(&s, fd, 0, 0);
/* un-block server */
- ret = read(pipefd, buf2, 4);
+ ret = read(unixfd, buf2, 4);
assert(ret == 4);
- close(pipefd);
+ close(unixfd);
assert(strncmp(buf2, "xmit", 4) == 0);
@@ -662,7 +662,7 @@ static void connect_one_server(int fd, int pipefd)
close(fd);
}
-static void process_one_client(int fd, int pipefd)
+static void process_one_client(int fd, int unixfd)
{
ssize_t ret, ret2, ret3;
struct so_state s;
@@ -671,7 +671,7 @@ static void process_one_client(int fd, int pipefd)
memset(&s, 0, sizeof(s));
do_getsockopts(&s, fd, 0, 0);
- ret = write(pipefd, "xmit", 4);
+ ret = write(unixfd, "xmit", 4);
assert(ret == 4);
ret = read(fd, buf, sizeof(buf));
@@ -736,7 +736,7 @@ static int xaccept(int s)
return fd;
}
-static int server(int pipefd)
+static int server(int unixfd)
{
int fd = -1, r;
@@ -752,13 +752,13 @@ static int server(int pipefd)
break;
}
- r = write(pipefd, "conn", 4);
+ r = write(unixfd, "conn", 4);
assert(r == 4);
alarm(15);
r = xaccept(fd);
- process_one_client(r, pipefd);
+ process_one_client(r, unixfd);
return 0;
}
@@ -801,7 +801,7 @@ static void test_ip_tos_sockopt(int fd)
xerror("expect socklen_t == -1");
}
-static int client(int pipefd)
+static int client(int unixfd)
{
int fd = -1;
@@ -820,7 +820,7 @@ static int client(int pipefd)
test_ip_tos_sockopt(fd);
- connect_one_server(fd, pipefd);
+ connect_one_server(fd, unixfd);
return 0;
}
@@ -867,31 +867,31 @@ int main(int argc, char *argv[])
{
int e1, e2, wstatus;
pid_t s, c, ret;
- int pipefds[2];
+ int unixfds[2];
parse_opts(argc, argv);
init_rng();
- e1 = pipe(pipefds);
+ e1 = socketpair(AF_UNIX, SOCK_DGRAM, 0, unixfds);
if (e1 < 0)
- die_perror("pipe");
+ die_perror("socketpair");
s = xfork();
if (s == 0)
- return server(pipefds[1]);
+ return server(unixfds[1]);
- close(pipefds[1]);
+ close(unixfds[1]);
/* wait until server bound a socket */
- e1 = read(pipefds[0], &e1, 4);
+ e1 = read(unixfds[0], &e1, 4);
assert(e1 == 4);
c = xfork();
if (c == 0)
- return client(pipefds[0]);
+ return client(unixfds[0]);
- close(pipefds[0]);
+ close(unixfds[0]);
ret = waitpid(s, &wstatus, 0);
if (ret == -1)
--
2.48.1
^ permalink raw reply related [flat|nested] 16+ messages in thread* [PATCH mptcp-next v3 06/14] selftests: mptcp: sockopt: read eof at the end of process_one_client
2025-08-26 9:29 [PATCH mptcp-next v3 00/14] selftests: consolidate TCP_INQ testing into sockopt Geliang Tang
` (4 preceding siblings ...)
2025-08-26 9:29 ` [PATCH mptcp-next v3 05/14] selftests: mptcp: sockopt: use unix socket instead of pipe Geliang Tang
@ 2025-08-26 9:29 ` Geliang Tang
2025-08-26 9:29 ` [PATCH mptcp-next v3 07/14] selftests: mptcp: sockopt: use recvmsg instead of read Geliang Tang
` (8 subsequent siblings)
14 siblings, 0 replies; 16+ messages in thread
From: Geliang Tang @ 2025-08-26 9:29 UTC (permalink / raw)
To: mptcp; +Cc: Geliang Tang
From: Geliang Tang <tanggeliang@kylinos.cn>
Moves EOF read handling to the end of process_one_client to ensure proper
synchronization after processing all data transfers, preparing for TCP_INQ
support in subsequent patches.
Signed-off-by: Geliang Tang <tanggeliang@kylinos.cn>
---
tools/testing/selftests/net/mptcp/mptcp_sockopt.c | 14 +++++++-------
1 file changed, 7 insertions(+), 7 deletions(-)
diff --git a/tools/testing/selftests/net/mptcp/mptcp_sockopt.c b/tools/testing/selftests/net/mptcp/mptcp_sockopt.c
index add29bdda9e5..d69b10d2dbe3 100644
--- a/tools/testing/selftests/net/mptcp/mptcp_sockopt.c
+++ b/tools/testing/selftests/net/mptcp/mptcp_sockopt.c
@@ -687,14 +687,9 @@ static void process_one_client(int fd, int unixfd)
if (ret2 < 0)
die_perror("write");
- /* wait for hangup */
- ret3 = read(fd, buf, 1);
- if (ret3 != 0)
- xerror("expected EOF, got %lu", ret3);
-
do_getsockopts(&s, fd, ret, ret2);
- if (s.mptcpi_rcv_delta && s.mptcpi_rcv_delta != (uint64_t)ret + 1)
- xerror("mptcpi_rcv_delta %" PRIu64 ", expect %" PRIu64, s.mptcpi_rcv_delta, ret + 1, s.mptcpi_rcv_delta - ret);
+ if (s.mptcpi_rcv_delta && s.mptcpi_rcv_delta != (uint64_t)ret)
+ xerror("mptcpi_rcv_delta %" PRIu64 ", expect %" PRIu64, s.mptcpi_rcv_delta, ret, s.mptcpi_rcv_delta - ret);
/* be nice when running on top of older kernel */
if (s.pkt_stats_avail) {
@@ -712,6 +707,11 @@ static void process_one_client(int fd, int unixfd)
s.last_sample.mptcpi_bytes_acked - ret2);
}
+ /* wait for hangup */
+ ret3 = read(fd, buf, 1);
+ if (ret3 != 0)
+ xerror("expected EOF, got %lu", ret3);
+
close(fd);
}
--
2.48.1
^ permalink raw reply related [flat|nested] 16+ messages in thread* [PATCH mptcp-next v3 07/14] selftests: mptcp: sockopt: use recvmsg instead of read
2025-08-26 9:29 [PATCH mptcp-next v3 00/14] selftests: consolidate TCP_INQ testing into sockopt Geliang Tang
` (5 preceding siblings ...)
2025-08-26 9:29 ` [PATCH mptcp-next v3 06/14] selftests: mptcp: sockopt: read eof at the end of process_one_client Geliang Tang
@ 2025-08-26 9:29 ` Geliang Tang
2025-08-26 9:29 ` [PATCH mptcp-next v3 08/14] selftests: mptcp: sockopt: read one byte first Geliang Tang
` (7 subsequent siblings)
14 siblings, 0 replies; 16+ messages in thread
From: Geliang Tang @ 2025-08-26 9:29 UTC (permalink / raw)
To: mptcp; +Cc: Geliang Tang
From: Geliang Tang <tanggeliang@kylinos.cn>
Replaces read() with recvmsg() to enable control message (CMSG) handling,
preparing for TCP_INQ support in subsequent patches.
Signed-off-by: Geliang Tang <tanggeliang@kylinos.cn>
---
.../selftests/net/mptcp/mptcp_sockopt.c | 19 ++++++++++++++++---
1 file changed, 16 insertions(+), 3 deletions(-)
diff --git a/tools/testing/selftests/net/mptcp/mptcp_sockopt.c b/tools/testing/selftests/net/mptcp/mptcp_sockopt.c
index d69b10d2dbe3..71cb311fcc50 100644
--- a/tools/testing/selftests/net/mptcp/mptcp_sockopt.c
+++ b/tools/testing/selftests/net/mptcp/mptcp_sockopt.c
@@ -665,8 +665,19 @@ static void connect_one_server(int fd, int unixfd)
static void process_one_client(int fd, int unixfd)
{
ssize_t ret, ret2, ret3;
+ char msg_buf[4096];
struct so_state s;
char buf[4096];
+ struct iovec iov = {
+ .iov_base = buf,
+ .iov_len = 1,
+ };
+ struct msghdr msg = {
+ .msg_iov = &iov,
+ .msg_iovlen = 1,
+ .msg_control = msg_buf,
+ .msg_controllen = sizeof(msg_buf),
+ };
memset(&s, 0, sizeof(s));
do_getsockopts(&s, fd, 0, 0);
@@ -674,9 +685,10 @@ static void process_one_client(int fd, int unixfd)
ret = write(unixfd, "xmit", 4);
assert(ret == 4);
- ret = read(fd, buf, sizeof(buf));
+ iov.iov_len = sizeof(buf);
+ ret = recvmsg(fd, &msg, 0);
if (ret < 0)
- die_perror("read");
+ die_perror("recvmsg");
assert(s.mptcpi_rcv_delta <= (uint64_t)ret);
@@ -708,7 +720,8 @@ static void process_one_client(int fd, int unixfd)
}
/* wait for hangup */
- ret3 = read(fd, buf, 1);
+ iov.iov_len = 1;
+ ret3 = recvmsg(fd, &msg, 0);
if (ret3 != 0)
xerror("expected EOF, got %lu", ret3);
--
2.48.1
^ permalink raw reply related [flat|nested] 16+ messages in thread* [PATCH mptcp-next v3 08/14] selftests: mptcp: sockopt: read one byte first
2025-08-26 9:29 [PATCH mptcp-next v3 00/14] selftests: consolidate TCP_INQ testing into sockopt Geliang Tang
` (6 preceding siblings ...)
2025-08-26 9:29 ` [PATCH mptcp-next v3 07/14] selftests: mptcp: sockopt: use recvmsg instead of read Geliang Tang
@ 2025-08-26 9:29 ` Geliang Tang
2025-08-26 9:29 ` [PATCH mptcp-next v3 09/14] selftests: mptcp: sockopt: add large data transfer tests Geliang Tang
` (6 subsequent siblings)
14 siblings, 0 replies; 16+ messages in thread
From: Geliang Tang @ 2025-08-26 9:29 UTC (permalink / raw)
To: mptcp; +Cc: Geliang Tang
From: Geliang Tang <tanggeliang@kylinos.cn>
Modifies data reading to first read one byte, then the remainder, ensuring
accurate TCP_INQ validation and data consistency checks.
Signed-off-by: Geliang Tang <tanggeliang@kylinos.cn>
---
.../selftests/net/mptcp/mptcp_sockopt.c | 28 ++++++++++++-------
1 file changed, 18 insertions(+), 10 deletions(-)
diff --git a/tools/testing/selftests/net/mptcp/mptcp_sockopt.c b/tools/testing/selftests/net/mptcp/mptcp_sockopt.c
index 71cb311fcc50..675ed2dcee9f 100644
--- a/tools/testing/selftests/net/mptcp/mptcp_sockopt.c
+++ b/tools/testing/selftests/net/mptcp/mptcp_sockopt.c
@@ -642,18 +642,18 @@ static void connect_one_server(int fd, int unixfd)
}
total += ret;
- } while (total < len);
+ } while (total < len - 1);
- if (total != len)
- xerror("total %lu, len %lu eof %d\n", total, len, eof);
+ if (total != len - 1)
+ xerror("total %lu, len - 1 %lu eof %d\n", total, len - 1, eof);
- if (memcmp(buf, buf2, len))
+ if (memcmp(buf + 1, buf2, len - 1))
xerror("data corruption");
if (s.tcpi_rcv_delta)
assert(s.tcpi_rcv_delta <= total);
- do_getsockopts(&s, fd, ret, ret);
+ do_getsockopts(&s, fd, ret, ret + 1);
if (eof)
total += 1; /* sequence advances due to FIN */
@@ -685,6 +685,14 @@ static void process_one_client(int fd, int unixfd)
ret = write(unixfd, "xmit", 4);
assert(ret == 4);
+ /* read one byte, expect cmsg to return expected - 1 */
+ ret = recvmsg(fd, &msg, 0);
+ if (ret < 0)
+ die_perror("recvmsg");
+
+ if (inq && msg.msg_controllen == 0)
+ xerror("msg_controllen is 0");
+
iov.iov_len = sizeof(buf);
ret = recvmsg(fd, &msg, 0);
if (ret < 0)
@@ -699,9 +707,9 @@ static void process_one_client(int fd, int unixfd)
if (ret2 < 0)
die_perror("write");
- do_getsockopts(&s, fd, ret, ret2);
- if (s.mptcpi_rcv_delta && s.mptcpi_rcv_delta != (uint64_t)ret)
- xerror("mptcpi_rcv_delta %" PRIu64 ", expect %" PRIu64, s.mptcpi_rcv_delta, ret, s.mptcpi_rcv_delta - ret);
+ do_getsockopts(&s, fd, ret + 1, ret2);
+ if (s.mptcpi_rcv_delta && s.mptcpi_rcv_delta != (uint64_t)ret + 1)
+ xerror("mptcpi_rcv_delta %" PRIu64 ", expect %" PRIu64, s.mptcpi_rcv_delta, ret + 1, s.mptcpi_rcv_delta - ret);
/* be nice when running on top of older kernel */
if (s.pkt_stats_avail) {
@@ -709,9 +717,9 @@ static void process_one_client(int fd, int unixfd)
xerror("mptcpi_bytes_sent %" PRIu64 ", expect %" PRIu64,
s.last_sample.mptcpi_bytes_sent, ret2,
s.last_sample.mptcpi_bytes_sent - ret2);
- if (s.last_sample.mptcpi_bytes_received != ret)
+ if (s.last_sample.mptcpi_bytes_received != ret + 1)
xerror("mptcpi_bytes_received %" PRIu64 ", expect %" PRIu64,
- s.last_sample.mptcpi_bytes_received, ret,
+ s.last_sample.mptcpi_bytes_received, ret + 1,
s.last_sample.mptcpi_bytes_received - ret);
if (s.last_sample.mptcpi_bytes_acked != ret)
xerror("mptcpi_bytes_acked %" PRIu64 ", expect %" PRIu64,
--
2.48.1
^ permalink raw reply related [flat|nested] 16+ messages in thread* [PATCH mptcp-next v3 09/14] selftests: mptcp: sockopt: add large data transfer tests
2025-08-26 9:29 [PATCH mptcp-next v3 00/14] selftests: consolidate TCP_INQ testing into sockopt Geliang Tang
` (7 preceding siblings ...)
2025-08-26 9:29 ` [PATCH mptcp-next v3 08/14] selftests: mptcp: sockopt: read one byte first Geliang Tang
@ 2025-08-26 9:29 ` Geliang Tang
2025-08-26 9:29 ` [PATCH mptcp-next v3 10/14] selftests: mptcp: sockopt: add wait_for_ack Geliang Tang
` (5 subsequent siblings)
14 siblings, 0 replies; 16+ messages in thread
From: Geliang Tang @ 2025-08-26 9:29 UTC (permalink / raw)
To: mptcp; +Cc: Geliang Tang
From: Geliang Tang <tanggeliang@kylinos.cn>
Introduces large data transfer tests (1-17 MB) to validate MPTCP socket
options under high-volume conditions, including proper EOF handling,
preparing for TCP_INQ support in subsequent patches.
Signed-off-by: Geliang Tang <tanggeliang@kylinos.cn>
---
.../selftests/net/mptcp/mptcp_sockopt.c | 90 ++++++++++++++++++-
1 file changed, 88 insertions(+), 2 deletions(-)
diff --git a/tools/testing/selftests/net/mptcp/mptcp_sockopt.c b/tools/testing/selftests/net/mptcp/mptcp_sockopt.c
index 675ed2dcee9f..fc65157a41ee 100644
--- a/tools/testing/selftests/net/mptcp/mptcp_sockopt.c
+++ b/tools/testing/selftests/net/mptcp/mptcp_sockopt.c
@@ -620,10 +620,12 @@ static void connect_one_server(int fd, int unixfd)
/* un-block server */
ret = read(unixfd, buf2, 4);
assert(ret == 4);
- close(unixfd);
assert(strncmp(buf2, "xmit", 4) == 0);
+ ret = write(unixfd, &len, sizeof(len));
+ assert(ret == (ssize_t)sizeof(len));
+
ret = write(fd, buf, len);
if (ret < 0)
die_perror("write");
@@ -659,14 +661,51 @@ static void connect_one_server(int fd, int unixfd)
total += 1; /* sequence advances due to FIN */
assert(s.mptcpi_rcv_delta ? s.mptcpi_rcv_delta == (uint64_t)total : true);
+
+ ret = read(unixfd, buf2, 4);
+ assert(strncmp(buf2, "huge", 4) == 0);
+
+ total = rand() % (16 * 1024 * 1024);
+ total += (1 * 1024 * 1024);
+
+ ret = write(unixfd, &total, sizeof(total));
+ assert(ret == (ssize_t)sizeof(total));
+
+ while (total > 0) {
+ if (total > sizeof(buf))
+ len = sizeof(buf);
+ else
+ len = total;
+
+ ret = write(fd, buf, len);
+ if (ret < 0)
+ die_perror("write");
+ total -= ret;
+
+ /* we don't have to care about buf content, only
+ * number of total bytes sent
+ */
+ }
+
+ ret = read(unixfd, buf2, 4);
+ assert(ret == 4);
+ assert(strncmp(buf2, "shut", 4) == 0);
+
+ ret = write(fd, buf, 1);
+ assert(ret == 1);
close(fd);
+ ret = write(unixfd, "closed", 6);
+ assert(ret == 6);
+
+ close(unixfd);
}
static void process_one_client(int fd, int unixfd)
{
- ssize_t ret, ret2, ret3;
+ ssize_t ret, ret2, ret3, tot;
char msg_buf[4096];
struct so_state s;
+ size_t expect_len;
char buf[4096];
struct iovec iov = {
.iov_base = buf,
@@ -678,6 +717,7 @@ static void process_one_client(int fd, int unixfd)
.msg_control = msg_buf,
.msg_controllen = sizeof(msg_buf),
};
+ char tmp[16];
memset(&s, 0, sizeof(s));
do_getsockopts(&s, fd, 0, 0);
@@ -685,6 +725,12 @@ static void process_one_client(int fd, int unixfd)
ret = write(unixfd, "xmit", 4);
assert(ret == 4);
+ ret = read(unixfd, &expect_len, sizeof(expect_len));
+ assert(ret == (ssize_t)sizeof(expect_len));
+
+ if (expect_len > sizeof(buf))
+ xerror("expect len %zu exceeds buffer size", expect_len);
+
/* read one byte, expect cmsg to return expected - 1 */
ret = recvmsg(fd, &msg, 0);
if (ret < 0)
@@ -703,6 +749,9 @@ static void process_one_client(int fd, int unixfd)
if (s.tcpi_rcv_delta)
assert(s.tcpi_rcv_delta == (uint64_t)ret);
+ /* should have gotten exact remainder of all pending data */
+ assert(ret == (ssize_t)expect_len - 1);
+
ret2 = write(fd, buf, ret);
if (ret2 < 0)
die_perror("write");
@@ -727,6 +776,43 @@ static void process_one_client(int fd, int unixfd)
s.last_sample.mptcpi_bytes_acked - ret2);
}
+ /* request a large swath of data. */
+ ret = write(unixfd, "huge", 4);
+ assert(ret == 4);
+
+ ret = read(unixfd, &expect_len, sizeof(expect_len));
+ assert(ret == (ssize_t)sizeof(expect_len));
+
+ /* peer should send us a few mb of data */
+ if (expect_len <= sizeof(buf))
+ xerror("expect len %zu too small\n", expect_len);
+
+ tot = 0;
+ do {
+ iov.iov_len = sizeof(buf);
+ ret = recvmsg(fd, &msg, 0);
+ if (ret < 0)
+ die_perror("recvmsg");
+
+ tot += ret;
+ } while ((size_t)tot < expect_len);
+
+ ret = write(unixfd, "shut", 4);
+ assert(ret == 4);
+
+ /* wait for hangup. Should have received one more byte of data. */
+ ret = read(unixfd, tmp, sizeof(tmp));
+ assert(ret == 6);
+ assert(strncmp(tmp, "closed", 6) == 0);
+
+ sleep(1);
+
+ iov.iov_len = 1;
+ ret = recvmsg(fd, &msg, 0);
+ if (ret < 0)
+ die_perror("recvmsg");
+ assert(ret == 1);
+
/* wait for hangup */
iov.iov_len = 1;
ret3 = recvmsg(fd, &msg, 0);
--
2.48.1
^ permalink raw reply related [flat|nested] 16+ messages in thread* [PATCH mptcp-next v3 10/14] selftests: mptcp: sockopt: add wait_for_ack
2025-08-26 9:29 [PATCH mptcp-next v3 00/14] selftests: consolidate TCP_INQ testing into sockopt Geliang Tang
` (8 preceding siblings ...)
2025-08-26 9:29 ` [PATCH mptcp-next v3 09/14] selftests: mptcp: sockopt: add large data transfer tests Geliang Tang
@ 2025-08-26 9:29 ` Geliang Tang
2025-08-26 9:29 ` [PATCH mptcp-next v3 11/14] selftests: mptcp: sockopt: set FIONREAD ioctl Geliang Tang
` (4 subsequent siblings)
14 siblings, 0 replies; 16+ messages in thread
From: Geliang Tang @ 2025-08-26 9:29 UTC (permalink / raw)
To: mptcp; +Cc: Geliang Tang
From: Geliang Tang <tanggeliang@kylinos.cn>
Adds wait_for_ack() helper using TIOCOUTQ/SIOCOUTQNSD ioctls to synchronize
tests by waiting for data acknowledgment before proceeding.
These codes are from mptcp_inq.c.
Signed-off-by: Geliang Tang <tanggeliang@kylinos.cn>
---
.../selftests/net/mptcp/mptcp_sockopt.c | 42 ++++++++++++++++++-
1 file changed, 41 insertions(+), 1 deletion(-)
diff --git a/tools/testing/selftests/net/mptcp/mptcp_sockopt.c b/tools/testing/selftests/net/mptcp/mptcp_sockopt.c
index fc65157a41ee..b8e8fec8979f 100644
--- a/tools/testing/selftests/net/mptcp/mptcp_sockopt.c
+++ b/tools/testing/selftests/net/mptcp/mptcp_sockopt.c
@@ -21,11 +21,13 @@
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/random.h>
+#include <sys/ioctl.h>
#include <netdb.h>
#include <netinet/in.h>
#include <linux/tcp.h>
+#include <linux/sockios.h>
static int pf = AF_INET;
static int proto_tx = IPPROTO_MPTCP;
@@ -593,10 +595,43 @@ static void do_getsockopts(struct so_state *s, int fd, size_t r, size_t w)
do_getsockopt_mptcp_full_info(s, fd);
}
+/* wait up to timeout milliseconds */
+static void wait_for_ack(int fd, int timeout, size_t total)
+{
+ int i;
+
+ for (i = 0; i < timeout; i++) {
+ int nsd, ret, queued = -1;
+ struct timespec req;
+
+ ret = ioctl(fd, TIOCOUTQ, &queued);
+ if (ret < 0)
+ die_perror("TIOCOUTQ");
+
+ ret = ioctl(fd, SIOCOUTQNSD, &nsd);
+ if (ret < 0)
+ die_perror("SIOCOUTQNSD");
+
+ if ((size_t)queued > total)
+ xerror("TIOCOUTQ %u, but only %zu expected\n", queued, total);
+ assert(nsd <= queued);
+
+ if (queued == 0)
+ return;
+
+ /* wait for peer to ack rx of all data */
+ req.tv_sec = 0;
+ req.tv_nsec = 1 * 1000 * 1000ul; /* 1ms */
+ nanosleep(&req, NULL);
+ }
+
+ xerror("still tx data queued after %u ms\n", timeout);
+}
+
static void connect_one_server(int fd, int unixfd)
{
char buf[4096], buf2[4096];
- size_t len, i, total;
+ size_t len, i, total, sent;
struct so_state s;
bool eof = false;
ssize_t ret;
@@ -667,10 +702,13 @@ static void connect_one_server(int fd, int unixfd)
total = rand() % (16 * 1024 * 1024);
total += (1 * 1024 * 1024);
+ sent = total;
ret = write(unixfd, &total, sizeof(total));
assert(ret == (ssize_t)sizeof(total));
+ wait_for_ack(fd, 5000, len);
+
while (total > 0) {
if (total > sizeof(buf))
len = sizeof(buf);
@@ -691,6 +729,8 @@ static void connect_one_server(int fd, int unixfd)
assert(ret == 4);
assert(strncmp(buf2, "shut", 4) == 0);
+ wait_for_ack(fd, 5000, sent);
+
ret = write(fd, buf, 1);
assert(ret == 1);
close(fd);
--
2.48.1
^ permalink raw reply related [flat|nested] 16+ messages in thread* [PATCH mptcp-next v3 11/14] selftests: mptcp: sockopt: set FIONREAD ioctl
2025-08-26 9:29 [PATCH mptcp-next v3 00/14] selftests: consolidate TCP_INQ testing into sockopt Geliang Tang
` (9 preceding siblings ...)
2025-08-26 9:29 ` [PATCH mptcp-next v3 10/14] selftests: mptcp: sockopt: add wait_for_ack Geliang Tang
@ 2025-08-26 9:29 ` Geliang Tang
2025-08-26 9:29 ` [PATCH mptcp-next v3 12/14] selftests: mptcp: sockopt: add check_tcp_inq helper Geliang Tang
` (3 subsequent siblings)
14 siblings, 0 replies; 16+ messages in thread
From: Geliang Tang @ 2025-08-26 9:29 UTC (permalink / raw)
To: mptcp; +Cc: Geliang Tang
From: Geliang Tang <tanggeliang@kylinos.cn>
Implements FIONREAD ioctl checks to validate available data size, ensuring
synchronization between write and read operations with non-blocking waits.
These codes are from mptcp_inq.c.
Signed-off-by: Geliang Tang <tanggeliang@kylinos.cn>
---
.../selftests/net/mptcp/mptcp_sockopt.c | 18 ++++++++++++++++++
1 file changed, 18 insertions(+)
diff --git a/tools/testing/selftests/net/mptcp/mptcp_sockopt.c b/tools/testing/selftests/net/mptcp/mptcp_sockopt.c
index b8e8fec8979f..7cc4626b7bf3 100644
--- a/tools/testing/selftests/net/mptcp/mptcp_sockopt.c
+++ b/tools/testing/selftests/net/mptcp/mptcp_sockopt.c
@@ -771,6 +771,24 @@ static void process_one_client(int fd, int unixfd)
if (expect_len > sizeof(buf))
xerror("expect len %zu exceeds buffer size", expect_len);
+ for (;;) {
+ struct timespec req;
+ unsigned int queued;
+
+ ret = ioctl(fd, FIONREAD, &queued);
+ if (ret < 0)
+ die_perror("FIONREAD");
+ if (queued > expect_len)
+ xerror("FIONREAD returned %u, but only %zu expected\n",
+ queued, expect_len);
+ if (queued == expect_len)
+ break;
+
+ req.tv_sec = 0;
+ req.tv_nsec = 1000 * 1000ul;
+ nanosleep(&req, NULL);
+ }
+
/* read one byte, expect cmsg to return expected - 1 */
ret = recvmsg(fd, &msg, 0);
if (ret < 0)
--
2.48.1
^ permalink raw reply related [flat|nested] 16+ messages in thread* [PATCH mptcp-next v3 12/14] selftests: mptcp: sockopt: add check_tcp_inq helper
2025-08-26 9:29 [PATCH mptcp-next v3 00/14] selftests: consolidate TCP_INQ testing into sockopt Geliang Tang
` (10 preceding siblings ...)
2025-08-26 9:29 ` [PATCH mptcp-next v3 11/14] selftests: mptcp: sockopt: set FIONREAD ioctl Geliang Tang
@ 2025-08-26 9:29 ` Geliang Tang
2025-08-26 9:29 ` [PATCH mptcp-next v3 13/14] selftests: mptcp: sockopt: replace mptcp_inq with sockopt Geliang Tang
` (2 subsequent siblings)
14 siblings, 0 replies; 16+ messages in thread
From: Geliang Tang @ 2025-08-26 9:29 UTC (permalink / raw)
To: mptcp; +Cc: Geliang Tang
From: Geliang Tang <tanggeliang@kylinos.cn>
Adds check_tcp_inq() helper to extract and verify TCP_CM_INQ values from
control messages, ensuring correct in-queue data tracking during transfers.
Signed-off-by: Geliang Tang <tanggeliang@kylinos.cn>
---
.../selftests/net/mptcp/mptcp_sockopt.c | 40 +++++++++++++++++++
1 file changed, 40 insertions(+)
diff --git a/tools/testing/selftests/net/mptcp/mptcp_sockopt.c b/tools/testing/selftests/net/mptcp/mptcp_sockopt.c
index 7cc4626b7bf3..fb6f76c4dc07 100644
--- a/tools/testing/selftests/net/mptcp/mptcp_sockopt.c
+++ b/tools/testing/selftests/net/mptcp/mptcp_sockopt.c
@@ -740,6 +740,35 @@ static void connect_one_server(int fd, int unixfd)
close(unixfd);
}
+static void get_tcp_inq(struct msghdr *msgh, unsigned int *inqv)
+{
+ struct cmsghdr *cmsg;
+
+ for (cmsg = CMSG_FIRSTHDR(msgh); cmsg ; cmsg = CMSG_NXTHDR(msgh, cmsg)) {
+ if (cmsg->cmsg_level == IPPROTO_TCP && cmsg->cmsg_type == TCP_CM_INQ) {
+ memcpy(inqv, CMSG_DATA(cmsg), sizeof(*inqv));
+ return;
+ }
+ }
+
+ xerror("could not find TCP_CM_INQ cmsg type");
+}
+
+static void check_tcp_inq(struct msghdr *msgh, unsigned int check, bool equal)
+{
+ unsigned int tcp_inq;
+
+ if (!inq)
+ return;
+
+ get_tcp_inq(msgh, &tcp_inq);
+
+ if (equal)
+ assert(tcp_inq == check);
+ else
+ assert(tcp_inq <= check);
+}
+
static void process_one_client(int fd, int unixfd)
{
ssize_t ret, ret2, ret3, tot;
@@ -797,6 +826,8 @@ static void process_one_client(int fd, int unixfd)
if (inq && msg.msg_controllen == 0)
xerror("msg_controllen is 0");
+ check_tcp_inq(&msg, expect_len - 1, true);
+
iov.iov_len = sizeof(buf);
ret = recvmsg(fd, &msg, 0);
if (ret < 0)
@@ -810,6 +841,9 @@ static void process_one_client(int fd, int unixfd)
/* should have gotten exact remainder of all pending data */
assert(ret == (ssize_t)expect_len - 1);
+ /* should be 0, all drained */
+ check_tcp_inq(&msg, 0, true);
+
ret2 = write(fd, buf, ret);
if (ret2 < 0)
die_perror("write");
@@ -853,6 +887,8 @@ static void process_one_client(int fd, int unixfd)
die_perror("recvmsg");
tot += ret;
+
+ check_tcp_inq(&msg, expect_len - tot, false);
} while ((size_t)tot < expect_len);
ret = write(unixfd, "shut", 4);
@@ -871,11 +907,15 @@ static void process_one_client(int fd, int unixfd)
die_perror("recvmsg");
assert(ret == 1);
+ /* tcp_inq should be 1 due to received fin. */
+ check_tcp_inq(&msg, 1, true);
+
/* wait for hangup */
iov.iov_len = 1;
ret3 = recvmsg(fd, &msg, 0);
if (ret3 != 0)
xerror("expected EOF, got %lu", ret3);
+ check_tcp_inq(&msg, 1, true);
close(fd);
}
--
2.48.1
^ permalink raw reply related [flat|nested] 16+ messages in thread* [PATCH mptcp-next v3 13/14] selftests: mptcp: sockopt: replace mptcp_inq with sockopt
2025-08-26 9:29 [PATCH mptcp-next v3 00/14] selftests: consolidate TCP_INQ testing into sockopt Geliang Tang
` (11 preceding siblings ...)
2025-08-26 9:29 ` [PATCH mptcp-next v3 12/14] selftests: mptcp: sockopt: add check_tcp_inq helper Geliang Tang
@ 2025-08-26 9:29 ` Geliang Tang
2025-08-26 9:29 ` [PATCH mptcp-next v3 14/14] selftests: mptcp: sockopt: remove obsolete mptcp_inq Geliang Tang
2025-08-26 12:50 ` [PATCH mptcp-next v3 00/14] selftests: consolidate TCP_INQ testing into sockopt MPTCP CI
14 siblings, 0 replies; 16+ messages in thread
From: Geliang Tang @ 2025-08-26 9:29 UTC (permalink / raw)
To: mptcp; +Cc: Geliang Tang
From: Geliang Tang <tanggeliang@kylinos.cn>
Update mptcp_sockopt.sh to use mptcp_sockopt binary instead of
mptcp_inq. This consolidates TCP_INQ testing into a single test binary
while maintaining equivalent test coverage.
Signed-off-by: Geliang Tang <tanggeliang@kylinos.cn>
---
tools/testing/selftests/net/mptcp/mptcp_sockopt.sh | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/tools/testing/selftests/net/mptcp/mptcp_sockopt.sh b/tools/testing/selftests/net/mptcp/mptcp_sockopt.sh
index 418a903c3a4d..f5150a10b064 100755
--- a/tools/testing/selftests/net/mptcp/mptcp_sockopt.sh
+++ b/tools/testing/selftests/net/mptcp/mptcp_sockopt.sh
@@ -305,7 +305,7 @@ run_tests()
do_tcpinq_test()
{
print_title "TCP_INQ cmsg/ioctl $*"
- ip netns exec "$ns_sbox" ./mptcp_inq "$@"
+ ip netns exec "$ns_sbox" ./mptcp_sockopt "$@"
local lret=$?
if [ $lret -ne 0 ];then
ret=$lret
@@ -331,19 +331,19 @@ do_tcpinq_tests()
local args
for args in "-t tcp" "-r tcp"; do
- do_tcpinq_test $args
+ do_tcpinq_test $args -i
lret=$?
if [ $lret -ne 0 ] ; then
return $lret
fi
- do_tcpinq_test -6 $args
+ do_tcpinq_test -6 $args -i
lret=$?
if [ $lret -ne 0 ] ; then
return $lret
fi
done
- do_tcpinq_test -r tcp -t tcp
+ do_tcpinq_test -r tcp -t tcp -i
return $?
}
--
2.48.1
^ permalink raw reply related [flat|nested] 16+ messages in thread* [PATCH mptcp-next v3 14/14] selftests: mptcp: sockopt: remove obsolete mptcp_inq
2025-08-26 9:29 [PATCH mptcp-next v3 00/14] selftests: consolidate TCP_INQ testing into sockopt Geliang Tang
` (12 preceding siblings ...)
2025-08-26 9:29 ` [PATCH mptcp-next v3 13/14] selftests: mptcp: sockopt: replace mptcp_inq with sockopt Geliang Tang
@ 2025-08-26 9:29 ` Geliang Tang
2025-08-26 12:50 ` [PATCH mptcp-next v3 00/14] selftests: consolidate TCP_INQ testing into sockopt MPTCP CI
14 siblings, 0 replies; 16+ messages in thread
From: Geliang Tang @ 2025-08-26 9:29 UTC (permalink / raw)
To: mptcp; +Cc: Geliang Tang
From: Geliang Tang <tanggeliang@kylinos.cn>
Delete mptcp_inq binary and references since its functionality has been
fully integrated into mptcp_sockopt. This simplifies the test suite
structure and reduces maintenance overhead.
Signed-off-by: Geliang Tang <tanggeliang@kylinos.cn>
---
tools/testing/selftests/net/mptcp/.gitignore | 1 -
tools/testing/selftests/net/mptcp/Makefile | 2 +-
tools/testing/selftests/net/mptcp/mptcp_inq.c | 608 ------------------
3 files changed, 1 insertion(+), 610 deletions(-)
delete mode 100644 tools/testing/selftests/net/mptcp/mptcp_inq.c
diff --git a/tools/testing/selftests/net/mptcp/.gitignore b/tools/testing/selftests/net/mptcp/.gitignore
index 833279fb34e2..c62e91ce385d 100644
--- a/tools/testing/selftests/net/mptcp/.gitignore
+++ b/tools/testing/selftests/net/mptcp/.gitignore
@@ -1,7 +1,6 @@
# SPDX-License-Identifier: GPL-2.0-only
mptcp_connect
mptcp_diag
-mptcp_inq
mptcp_sockopt
pm_nl_ctl
*.pcap
diff --git a/tools/testing/selftests/net/mptcp/Makefile b/tools/testing/selftests/net/mptcp/Makefile
index 4c7e51336ab2..9c8da49313fb 100644
--- a/tools/testing/selftests/net/mptcp/Makefile
+++ b/tools/testing/selftests/net/mptcp/Makefile
@@ -8,7 +8,7 @@ TEST_PROGS := mptcp_connect.sh mptcp_connect_mmap.sh mptcp_connect_sendfile.sh \
mptcp_connect_checksum.sh pm_netlink.sh mptcp_join.sh diag.sh \
simult_flows.sh mptcp_sockopt.sh userspace_pm.sh
-TEST_GEN_FILES = mptcp_connect pm_nl_ctl mptcp_sockopt mptcp_inq mptcp_diag
+TEST_GEN_FILES = mptcp_connect pm_nl_ctl mptcp_sockopt mptcp_diag
TEST_FILES := mptcp_lib.sh settings
diff --git a/tools/testing/selftests/net/mptcp/mptcp_inq.c b/tools/testing/selftests/net/mptcp/mptcp_inq.c
deleted file mode 100644
index f3bcaa48df8f..000000000000
--- a/tools/testing/selftests/net/mptcp/mptcp_inq.c
+++ /dev/null
@@ -1,608 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-
-#define _GNU_SOURCE
-
-#include <assert.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <limits.h>
-#include <string.h>
-#include <stdarg.h>
-#include <stdbool.h>
-#include <stdint.h>
-#include <inttypes.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <strings.h>
-#include <unistd.h>
-#include <time.h>
-
-#include <sys/ioctl.h>
-#include <sys/random.h>
-#include <sys/socket.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-
-#include <netdb.h>
-#include <netinet/in.h>
-
-#include <linux/tcp.h>
-#include <linux/sockios.h>
-
-#ifndef IPPROTO_MPTCP
-#define IPPROTO_MPTCP 262
-#endif
-#ifndef SOL_MPTCP
-#define SOL_MPTCP 284
-#endif
-
-static int pf = AF_INET;
-static int proto_tx = IPPROTO_MPTCP;
-static int proto_rx = IPPROTO_MPTCP;
-
-static void die_perror(const char *msg)
-{
- perror(msg);
- exit(1);
-}
-
-static void die_usage(int r)
-{
- fprintf(stderr, "Usage: mptcp_inq [-6] [ -t tcp|mptcp ] [ -r tcp|mptcp]\n");
- exit(r);
-}
-
-static void xerror(const char *fmt, ...)
-{
- va_list ap;
-
- va_start(ap, fmt);
- vfprintf(stderr, fmt, ap);
- va_end(ap);
- fputc('\n', stderr);
- exit(1);
-}
-
-static const char *getxinfo_strerr(int err)
-{
- if (err == EAI_SYSTEM)
- return strerror(errno);
-
- return gai_strerror(err);
-}
-
-static void xgetaddrinfo(const char *node, const char *service,
- struct addrinfo *hints,
- struct addrinfo **res)
-{
- int err;
-
-again:
- err = getaddrinfo(node, service, hints, res);
- if (err) {
- const char *errstr;
-
- if (err == EAI_SOCKTYPE) {
- hints->ai_protocol = IPPROTO_TCP;
- goto again;
- }
-
- errstr = getxinfo_strerr(err);
-
- fprintf(stderr, "Fatal: getaddrinfo(%s:%s): %s\n",
- node ? node : "", service ? service : "", errstr);
- exit(1);
- }
-}
-
-static int sock_listen_mptcp(const char * const listenaddr,
- const char * const port)
-{
- int sock = -1;
- struct addrinfo hints = {
- .ai_protocol = IPPROTO_MPTCP,
- .ai_socktype = SOCK_STREAM,
- .ai_flags = AI_PASSIVE | AI_NUMERICHOST
- };
-
- hints.ai_family = pf;
-
- struct addrinfo *a, *addr;
- int one = 1;
-
- xgetaddrinfo(listenaddr, port, &hints, &addr);
- hints.ai_family = pf;
-
- for (a = addr; a; a = a->ai_next) {
- sock = socket(a->ai_family, a->ai_socktype, proto_rx);
- if (sock < 0)
- continue;
-
- if (-1 == setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &one,
- sizeof(one)))
- perror("setsockopt");
-
- if (bind(sock, a->ai_addr, a->ai_addrlen) == 0)
- break; /* success */
-
- perror("bind");
- close(sock);
- sock = -1;
- }
-
- freeaddrinfo(addr);
-
- if (sock < 0)
- xerror("could not create listen socket");
-
- if (listen(sock, 20))
- die_perror("listen");
-
- return sock;
-}
-
-static int sock_connect_mptcp(const char * const remoteaddr,
- const char * const port, int proto)
-{
- struct addrinfo hints = {
- .ai_protocol = IPPROTO_MPTCP,
- .ai_socktype = SOCK_STREAM,
- };
- struct addrinfo *a, *addr;
- int sock = -1;
-
- hints.ai_family = pf;
-
- xgetaddrinfo(remoteaddr, port, &hints, &addr);
- for (a = addr; a; a = a->ai_next) {
- sock = socket(a->ai_family, a->ai_socktype, proto);
- if (sock < 0)
- continue;
-
- if (connect(sock, a->ai_addr, a->ai_addrlen) == 0)
- break; /* success */
-
- die_perror("connect");
- }
-
- if (sock < 0)
- xerror("could not create connect socket");
-
- freeaddrinfo(addr);
- return sock;
-}
-
-static int protostr_to_num(const char *s)
-{
- if (strcasecmp(s, "tcp") == 0)
- return IPPROTO_TCP;
- if (strcasecmp(s, "mptcp") == 0)
- return IPPROTO_MPTCP;
-
- die_usage(1);
- return 0;
-}
-
-static void parse_opts(int argc, char **argv)
-{
- int c;
-
- while ((c = getopt(argc, argv, "h6t:r:")) != -1) {
- switch (c) {
- case 'h':
- die_usage(0);
- break;
- case '6':
- pf = AF_INET6;
- break;
- case 't':
- proto_tx = protostr_to_num(optarg);
- break;
- case 'r':
- proto_rx = protostr_to_num(optarg);
- break;
- default:
- die_usage(1);
- break;
- }
- }
-}
-
-/* wait up to timeout milliseconds */
-static void wait_for_ack(int fd, int timeout, size_t total)
-{
- int i;
-
- for (i = 0; i < timeout; i++) {
- int nsd, ret, queued = -1;
- struct timespec req;
-
- ret = ioctl(fd, TIOCOUTQ, &queued);
- if (ret < 0)
- die_perror("TIOCOUTQ");
-
- ret = ioctl(fd, SIOCOUTQNSD, &nsd);
- if (ret < 0)
- die_perror("SIOCOUTQNSD");
-
- if ((size_t)queued > total)
- xerror("TIOCOUTQ %u, but only %zu expected\n", queued, total);
- assert(nsd <= queued);
-
- if (queued == 0)
- return;
-
- /* wait for peer to ack rx of all data */
- req.tv_sec = 0;
- req.tv_nsec = 1 * 1000 * 1000ul; /* 1ms */
- nanosleep(&req, NULL);
- }
-
- xerror("still tx data queued after %u ms\n", timeout);
-}
-
-static void connect_one_server(int fd, int unixfd)
-{
- size_t len, i, total, sent;
- char buf[4096], buf2[4096];
- ssize_t ret;
-
- len = rand() % (sizeof(buf) - 1);
-
- if (len < 128)
- len = 128;
-
- for (i = 0; i < len ; i++) {
- buf[i] = rand() % 26;
- buf[i] += 'A';
- }
-
- buf[i] = '\n';
-
- /* un-block server */
- ret = read(unixfd, buf2, 4);
- assert(ret == 4);
-
- assert(strncmp(buf2, "xmit", 4) == 0);
-
- ret = write(unixfd, &len, sizeof(len));
- assert(ret == (ssize_t)sizeof(len));
-
- ret = write(fd, buf, len);
- if (ret < 0)
- die_perror("write");
-
- if (ret != (ssize_t)len)
- xerror("short write");
-
- ret = read(unixfd, buf2, 4);
- assert(strncmp(buf2, "huge", 4) == 0);
-
- total = rand() % (16 * 1024 * 1024);
- total += (1 * 1024 * 1024);
- sent = total;
-
- ret = write(unixfd, &total, sizeof(total));
- assert(ret == (ssize_t)sizeof(total));
-
- wait_for_ack(fd, 5000, len);
-
- while (total > 0) {
- if (total > sizeof(buf))
- len = sizeof(buf);
- else
- len = total;
-
- ret = write(fd, buf, len);
- if (ret < 0)
- die_perror("write");
- total -= ret;
-
- /* we don't have to care about buf content, only
- * number of total bytes sent
- */
- }
-
- ret = read(unixfd, buf2, 4);
- assert(ret == 4);
- assert(strncmp(buf2, "shut", 4) == 0);
-
- wait_for_ack(fd, 5000, sent);
-
- ret = write(fd, buf, 1);
- assert(ret == 1);
- close(fd);
- ret = write(unixfd, "closed", 6);
- assert(ret == 6);
-
- close(unixfd);
-}
-
-static void get_tcp_inq(struct msghdr *msgh, unsigned int *inqv)
-{
- struct cmsghdr *cmsg;
-
- for (cmsg = CMSG_FIRSTHDR(msgh); cmsg ; cmsg = CMSG_NXTHDR(msgh, cmsg)) {
- if (cmsg->cmsg_level == IPPROTO_TCP && cmsg->cmsg_type == TCP_CM_INQ) {
- memcpy(inqv, CMSG_DATA(cmsg), sizeof(*inqv));
- return;
- }
- }
-
- xerror("could not find TCP_CM_INQ cmsg type");
-}
-
-static void process_one_client(int fd, int unixfd)
-{
- unsigned int tcp_inq;
- size_t expect_len;
- char msg_buf[4096];
- char buf[4096];
- char tmp[16];
- struct iovec iov = {
- .iov_base = buf,
- .iov_len = 1,
- };
- struct msghdr msg = {
- .msg_iov = &iov,
- .msg_iovlen = 1,
- .msg_control = msg_buf,
- .msg_controllen = sizeof(msg_buf),
- };
- ssize_t ret, tot;
-
- ret = write(unixfd, "xmit", 4);
- assert(ret == 4);
-
- ret = read(unixfd, &expect_len, sizeof(expect_len));
- assert(ret == (ssize_t)sizeof(expect_len));
-
- if (expect_len > sizeof(buf))
- xerror("expect len %zu exceeds buffer size", expect_len);
-
- for (;;) {
- struct timespec req;
- unsigned int queued;
-
- ret = ioctl(fd, FIONREAD, &queued);
- if (ret < 0)
- die_perror("FIONREAD");
- if (queued > expect_len)
- xerror("FIONREAD returned %u, but only %zu expected\n",
- queued, expect_len);
- if (queued == expect_len)
- break;
-
- req.tv_sec = 0;
- req.tv_nsec = 1000 * 1000ul;
- nanosleep(&req, NULL);
- }
-
- /* read one byte, expect cmsg to return expected - 1 */
- ret = recvmsg(fd, &msg, 0);
- if (ret < 0)
- die_perror("recvmsg");
-
- if (msg.msg_controllen == 0)
- xerror("msg_controllen is 0");
-
- get_tcp_inq(&msg, &tcp_inq);
-
- assert((size_t)tcp_inq == (expect_len - 1));
-
- iov.iov_len = sizeof(buf);
- ret = recvmsg(fd, &msg, 0);
- if (ret < 0)
- die_perror("recvmsg");
-
- /* should have gotten exact remainder of all pending data */
- assert(ret == (ssize_t)tcp_inq);
-
- /* should be 0, all drained */
- get_tcp_inq(&msg, &tcp_inq);
- assert(tcp_inq == 0);
-
- /* request a large swath of data. */
- ret = write(unixfd, "huge", 4);
- assert(ret == 4);
-
- ret = read(unixfd, &expect_len, sizeof(expect_len));
- assert(ret == (ssize_t)sizeof(expect_len));
-
- /* peer should send us a few mb of data */
- if (expect_len <= sizeof(buf))
- xerror("expect len %zu too small\n", expect_len);
-
- tot = 0;
- do {
- iov.iov_len = sizeof(buf);
- ret = recvmsg(fd, &msg, 0);
- if (ret < 0)
- die_perror("recvmsg");
-
- tot += ret;
-
- get_tcp_inq(&msg, &tcp_inq);
-
- if (tcp_inq > expect_len - tot)
- xerror("inq %d, remaining %d total_len %d\n",
- tcp_inq, expect_len - tot, (int)expect_len);
-
- assert(tcp_inq <= expect_len - tot);
- } while ((size_t)tot < expect_len);
-
- ret = write(unixfd, "shut", 4);
- assert(ret == 4);
-
- /* wait for hangup. Should have received one more byte of data. */
- ret = read(unixfd, tmp, sizeof(tmp));
- assert(ret == 6);
- assert(strncmp(tmp, "closed", 6) == 0);
-
- sleep(1);
-
- iov.iov_len = 1;
- ret = recvmsg(fd, &msg, 0);
- if (ret < 0)
- die_perror("recvmsg");
- assert(ret == 1);
-
- get_tcp_inq(&msg, &tcp_inq);
-
- /* tcp_inq should be 1 due to received fin. */
- assert(tcp_inq == 1);
-
- iov.iov_len = 1;
- ret = recvmsg(fd, &msg, 0);
- if (ret < 0)
- die_perror("recvmsg");
-
- /* expect EOF */
- assert(ret == 0);
- get_tcp_inq(&msg, &tcp_inq);
- assert(tcp_inq == 1);
-
- close(fd);
-}
-
-static int xaccept(int s)
-{
- int fd = accept(s, NULL, 0);
-
- if (fd < 0)
- die_perror("accept");
-
- return fd;
-}
-
-static int server(int unixfd)
-{
- int fd = -1, r, on = 1;
-
- switch (pf) {
- case AF_INET:
- fd = sock_listen_mptcp("127.0.0.1", "15432");
- break;
- case AF_INET6:
- fd = sock_listen_mptcp("::1", "15432");
- break;
- default:
- xerror("Unknown pf %d\n", pf);
- break;
- }
-
- r = write(unixfd, "conn", 4);
- assert(r == 4);
-
- alarm(15);
- r = xaccept(fd);
-
- if (-1 == setsockopt(r, IPPROTO_TCP, TCP_INQ, &on, sizeof(on)))
- die_perror("setsockopt");
-
- process_one_client(r, unixfd);
-
- return 0;
-}
-
-static int client(int unixfd)
-{
- int fd = -1;
-
- alarm(15);
-
- switch (pf) {
- case AF_INET:
- fd = sock_connect_mptcp("127.0.0.1", "15432", proto_tx);
- break;
- case AF_INET6:
- fd = sock_connect_mptcp("::1", "15432", proto_tx);
- break;
- default:
- xerror("Unknown pf %d\n", pf);
- }
-
- connect_one_server(fd, unixfd);
-
- return 0;
-}
-
-static void init_rng(void)
-{
- unsigned int foo;
-
- if (getrandom(&foo, sizeof(foo), 0) == -1) {
- perror("getrandom");
- exit(1);
- }
-
- srand(foo);
-}
-
-static pid_t xfork(void)
-{
- pid_t p = fork();
-
- if (p < 0)
- die_perror("fork");
- else if (p == 0)
- init_rng();
-
- return p;
-}
-
-static int rcheck(int wstatus, const char *what)
-{
- if (WIFEXITED(wstatus)) {
- if (WEXITSTATUS(wstatus) == 0)
- return 0;
- fprintf(stderr, "%s exited, status=%d\n", what, WEXITSTATUS(wstatus));
- return WEXITSTATUS(wstatus);
- } else if (WIFSIGNALED(wstatus)) {
- xerror("%s killed by signal %d\n", what, WTERMSIG(wstatus));
- } else if (WIFSTOPPED(wstatus)) {
- xerror("%s stopped by signal %d\n", what, WSTOPSIG(wstatus));
- }
-
- return 111;
-}
-
-int main(int argc, char *argv[])
-{
- int e1, e2, wstatus;
- pid_t s, c, ret;
- int unixfds[2];
-
- parse_opts(argc, argv);
-
- e1 = socketpair(AF_UNIX, SOCK_DGRAM, 0, unixfds);
- if (e1 < 0)
- die_perror("pipe");
-
- s = xfork();
- if (s == 0)
- return server(unixfds[1]);
-
- close(unixfds[1]);
-
- /* wait until server bound a socket */
- e1 = read(unixfds[0], &e1, 4);
- assert(e1 == 4);
-
- c = xfork();
- if (c == 0)
- return client(unixfds[0]);
-
- close(unixfds[0]);
-
- ret = waitpid(s, &wstatus, 0);
- if (ret == -1)
- die_perror("waitpid");
- e1 = rcheck(wstatus, "server");
- ret = waitpid(c, &wstatus, 0);
- if (ret == -1)
- die_perror("waitpid");
- e2 = rcheck(wstatus, "client");
-
- return e1 ? e1 : e2;
-}
--
2.48.1
^ permalink raw reply related [flat|nested] 16+ messages in thread* Re: [PATCH mptcp-next v3 00/14] selftests: consolidate TCP_INQ testing into sockopt
2025-08-26 9:29 [PATCH mptcp-next v3 00/14] selftests: consolidate TCP_INQ testing into sockopt Geliang Tang
` (13 preceding siblings ...)
2025-08-26 9:29 ` [PATCH mptcp-next v3 14/14] selftests: mptcp: sockopt: remove obsolete mptcp_inq Geliang Tang
@ 2025-08-26 12:50 ` MPTCP CI
14 siblings, 0 replies; 16+ messages in thread
From: MPTCP CI @ 2025-08-26 12:50 UTC (permalink / raw)
To: Geliang Tang; +Cc: mptcp
Hi Geliang,
Thank you for your modifications, that's great!
Our CI did some validations and here is its report:
- KVM Validation: normal: Unstable: 1 failed test(s): selftest_mptcp_connect 🔴
- KVM Validation: debug: Unstable: 1 failed test(s): selftest_mptcp_connect 🔴
- KVM Validation: btf-normal (only bpftest_all): Success! ✅
- KVM Validation: btf-debug (only bpftest_all): Success! ✅
- Task: https://github.com/multipath-tcp/mptcp_net-next/actions/runs/17234297108
Initiator: Patchew Applier
Commits: https://github.com/multipath-tcp/mptcp_net-next/commits/2b989c1de52d
Patchwork: https://patchwork.kernel.org/project/mptcp/list/?series=995595
If there are some issues, you can reproduce them using the same environment as
the one used by the CI thanks to a docker image, e.g.:
$ cd [kernel source code]
$ docker run -v "${PWD}:${PWD}:rw" -w "${PWD}" --privileged --rm -it \
--pull always mptcp/mptcp-upstream-virtme-docker:latest \
auto-normal
For more details:
https://github.com/multipath-tcp/mptcp-upstream-virtme-docker
Please note that despite all the efforts that have been already done to have a
stable tests suite when executed on a public CI like here, it is possible some
reported issues are not due to your modifications. Still, do not hesitate to
help us improve that ;-)
Cheers,
MPTCP GH Action bot
Bot operated by Matthieu Baerts (NGI0 Core)
^ permalink raw reply [flat|nested] 16+ messages in thread