[PATCH mptcp-next v2 5/5] mptcp: add TCP_SYNCNT setsockopt/getsockopt

Geliang Tang <[email protected]> Sun, 26 Jul 2026 16:43:44 +0800
Newsgroups dev.linux.lists.mptcp
Message-ID <eafc0fe4728acbfb17f1fabe5945af17d60ad558.1785054808.git.tanggeliang@kylinos.cn>
From: Geliang Tang <[email protected]>

Surface TCP_SYNCNT to userspace on the MPTCP master socket.

setsockopt(TCP_SYNCNT) validates the value via __mptcp_setsockopt_set_val()
and stores it in inet_csk(sk)->icsk_syn_retries on the msk. getsockopt()
reads the same field back.

A newly created subflow picks up the master socket's syn_retries through
sync_socket_options(), so the setting takes effect for outgoing SYNs
without further plumbing.

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

diff --git a/net/mptcp/sockopt.c b/net/mptcp/sockopt.c
index 34f6cd9c7967..6e4c5b5314af 100644
--- a/net/mptcp/sockopt.c
+++ b/net/mptcp/sockopt.c
@@ -898,6 +898,23 @@ static int mptcp_setsockopt_sol_tcp(struct mptcp_sock *msk, int optname,
 		ret = mptcp_setsockopt_all_sf(msk, SOL_TCP, optname, optval,
 					      optlen);
 		break;
+	case TCP_SYNCNT: {
+		int syncnt;
+
+		if (val < 1 || val > MAX_TCP_SYNCNT) {
+			ret = -EINVAL;
+			break;
+		}
+
+		syncnt = val;
+		ret = __mptcp_setsockopt_set_val(msk, MAX_TCP_SYNCNT,
+						 &tcp_sock_set_syncnt,
+						 &syncnt,
+						 val);
+		if (ret == 0)
+			inet_csk(sk)->icsk_syn_retries = syncnt;
+		break;
+	}
 	default:
 		ret = -ENOPROTOOPT;
 	}
@@ -1450,6 +1467,10 @@ static int mptcp_getsockopt_sol_tcp(struct mptcp_sock *msk, int optname,
 		return mptcp_put_int_option(msk, optval, optlen, msk->notsent_lowat);
 	case TCP_IS_MPTCP:
 		return mptcp_put_int_option(msk, optval, optlen, 1);
+	case TCP_SYNCNT:
+		return mptcp_put_int_option(msk, optval, optlen,
+					    inet_csk(sk)->icsk_syn_retries ? :
+					    READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_syn_retries));
 	}
 	return -EOPNOTSUPP;
 }
@@ -1604,6 +1625,11 @@ static void sync_socket_options(struct mptcp_sock *msk, struct sock *ssk)
 
 	ssk->sk_reuse = sk->sk_reuse;
 	ssk->sk_reuseport = sk->sk_reuseport;
+	if (inet_csk(sk)->icsk_syn_retries > 0) {
+		if (tcp_sock_set_syncnt(ssk, inet_csk(sk)->icsk_syn_retries))
+			pr_warn("Failed to sync TCP_SYNCNT=%u to subflow\n",
+				inet_csk(sk)->icsk_syn_retries);
+	}
 }
 
 void mptcp_sockopt_sync_locked(struct mptcp_sock *msk, struct sock *ssk)
-- 
2.53.0