[PATCH mptcp-next 6/6] selftests: mptcp: sockopt: cover LINGER REUSEADDR PRIORITY NODELAY SYNCNT

Geliang Tang <[email protected]> Sat, 25 Jul 2026 21:13:43 +0800
Newsgroups dev.linux.lists.mptcp
Message-ID <d8365475a20c80c0d4b33d490de4f9885e0838b8.1784985085.git.tanggeliang@kylinos.cn>
From: Geliang Tang <[email protected]>

Extend mptcp_sockopt.c with tests for SOL_SOCKET (SO_REUSEADDR,
SO_LINGER, SO_PRIORITY) and SOL_TCP (TCP_NODELAY, TCP_SYNCNT), each
exercising both setsockopt() and getsockopt() on a connected
MPTCP socket.

SO_REUSEADDR on the msk reports 1 (SK_CAN_REUSE) once any non-zero
value is set; this captures the documented behaviour where the
master socket reflects the subflow's reuse state.

TCP_SYNCNT coverage pairs with the kernel side that propagates
icsk_syn_retries to the subflow.

Signed-off-by: Geliang Tang <[email protected]>
---
 .../selftests/net/mptcp/mptcp_sockopt.c       | 116 ++++++++++++++++++
 1 file changed, 116 insertions(+)

diff --git a/tools/testing/selftests/net/mptcp/mptcp_sockopt.c b/tools/testing/selftests/net/mptcp/mptcp_sockopt.c
index b6e58d936ebe..b04e24df9dfe 100644
--- a/tools/testing/selftests/net/mptcp/mptcp_sockopt.c
+++ b/tools/testing/selftests/net/mptcp/mptcp_sockopt.c
@@ -35,6 +35,9 @@ static int pf = AF_INET;
 #ifndef SOL_MPTCP
 #define SOL_MPTCP 284
 #endif
+#ifndef SOL_TCP
+#define SOL_TCP 6
+#endif
 
 #ifndef MPTCP_INFO
 struct mptcp_info {
@@ -229,6 +232,30 @@ static int sock_listen_mptcp(const char * const listenaddr,
 	return sock;
 }
 
+static void test_so_reuseaddr_sockopt(int fd)
+{
+	int val_in = 1, val_out, expected;
+	socklen_t s;
+	int r;
+
+	r = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &val_in, sizeof(val_in));
+	if (r != 0)
+		die_perror("setsockopt SO_REUSEADDR");
+
+	s = sizeof(val_out);
+	r = getsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &val_out, &s);
+	if (r != 0)
+		die_perror("getsockopt SO_REUSEADDR");
+
+	/* SO_REUSEADDR on MPTCP msk returns 1 (SK_CAN_REUSE) when set,
+	 * regardless of the input value. The actual reuse semantics are
+	 * applied to the nmpc subflow.
+	 */
+	expected = val_in ? 1 : 0;
+	if (val_out != expected)
+		xerror("SO_REUSEADDR %d != %d\n", expected, val_out);
+}
+
 static int sock_connect_mptcp(const char * const remoteaddr,
 			      const char * const port, int proto)
 {
@@ -247,6 +274,8 @@ static int sock_connect_mptcp(const char * const remoteaddr,
 		if (sock < 0)
 			continue;
 
+		test_so_reuseaddr_sockopt(sock);
+
 		if (connect(sock, a->ai_addr, a->ai_addrlen) == 0)
 			break; /* success */
 
@@ -769,6 +798,89 @@ static void test_ip_tos_sockopt(int fd)
 		xerror("expect socklen_t == -1");
 }
 
+static void test_so_linger_sockopt(int fd)
+{
+	struct linger ling_in, ling_out;
+	socklen_t s;
+	int r;
+
+	ling_in.l_onoff = 1;
+	ling_in.l_linger = 30;
+	r = setsockopt(fd, SOL_SOCKET, SO_LINGER, &ling_in, sizeof(ling_in));
+	if (r != 0)
+		die_perror("setsockopt SO_LINGER");
+
+	s = sizeof(ling_out);
+	memset(&ling_out, 0, sizeof(ling_out));
+	r = getsockopt(fd, SOL_SOCKET, SO_LINGER, &ling_out, &s);
+	if (r != 0)
+		die_perror("getsockopt SO_LINGER");
+
+	if (ling_in.l_onoff != ling_out.l_onoff ||
+	    ling_in.l_linger != ling_out.l_linger)
+		xerror("SO_LINGER %d/%d != %d/%d\n",
+		       ling_in.l_onoff, ling_in.l_linger,
+		       ling_out.l_onoff, ling_out.l_linger);
+}
+
+static void test_so_priority_sockopt(int fd)
+{
+	int prio_in, prio_out;
+	socklen_t s;
+	int r;
+
+	prio_in = 5;
+	r = setsockopt(fd, SOL_SOCKET, SO_PRIORITY, &prio_in, sizeof(prio_in));
+	if (r != 0)
+		die_perror("setsockopt SO_PRIORITY");
+
+	s = sizeof(prio_out);
+	r = getsockopt(fd, SOL_SOCKET, SO_PRIORITY, &prio_out, &s);
+	if (r != 0)
+		die_perror("getsockopt SO_PRIORITY");
+
+	if (prio_in != prio_out)
+		xerror("SO_PRIORITY %d != %d\n", prio_in, prio_out);
+}
+
+static void test_tcp_nodelay_sockopt(int fd)
+{
+	int val_in = 1, val_out;
+	socklen_t s;
+	int r;
+
+	r = setsockopt(fd, SOL_TCP, TCP_NODELAY, &val_in, sizeof(val_in));
+	if (r != 0)
+		die_perror("setsockopt TCP_NODELAY");
+
+	s = sizeof(val_out);
+	r = getsockopt(fd, SOL_TCP, TCP_NODELAY, &val_out, &s);
+	if (r != 0)
+		die_perror("getsockopt TCP_NODELAY");
+
+	if (val_in != val_out)
+		xerror("TCP_NODELAY %d != %d\n", val_in, val_out);
+}
+
+static void test_tcp_syncnt_sockopt(int fd)
+{
+	int val_in = 3, val_out;
+	socklen_t s;
+	int r;
+
+	r = setsockopt(fd, SOL_TCP, TCP_SYNCNT, &val_in, sizeof(val_in));
+	if (r != 0)
+		die_perror("setsockopt TCP_SYNCNT");
+
+	s = sizeof(val_out);
+	r = getsockopt(fd, SOL_TCP, TCP_SYNCNT, &val_out, &s);
+	if (r != 0)
+		die_perror("getsockopt TCP_SYNCNT");
+
+	if (val_in != val_out)
+		xerror("TCP_SYNCNT %d != %d\n", val_in, val_out);
+}
+
 static int client(int pipefd)
 {
 	int fd = -1;
@@ -787,6 +899,10 @@ static int client(int pipefd)
 	}
 
 	test_ip_tos_sockopt(fd);
+	test_so_linger_sockopt(fd);
+	test_so_priority_sockopt(fd);
+	test_tcp_nodelay_sockopt(fd);
+	test_tcp_syncnt_sockopt(fd);
 
 	connect_one_server(fd, pipefd);
 
-- 
2.53.0