All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH mptcp-next v6 0/6] Fix socket options used by NVMe over MPTCP
@ 2026-08-17  3:57 Geliang Tang
  2026-08-17  3:57 ` [PATCH mptcp-next v6 1/6] mptcp: handle TCP_MAXSEG getsockopt in common case Geliang Tang
                   ` (6 more replies)
  0 siblings, 7 replies; 8+ messages in thread
From: Geliang Tang @ 2026-08-17  3:57 UTC (permalink / raw)
  To: mptcp; +Cc: Geliang Tang

From: Geliang Tang <tanggeliang@kylinos.cn>

NVMe over MPTCP relies on SO_LINGER, SO_PRIORITY, SO_REUSEADDR, TCP_SYNCNT,
TCP_NODELAY, IP_TOS, and SO_BINDTODEVICE. This series contains fixes to
make all of them work correctly, and adds tclass support for it.

v6:
 - Remove NVMe patches from this series.
 - Remove v4-mapped address patches from this series.
 - Squash "ipv6: extract and export ip6_sock_set_tclass helper" into
   "mptcp: sockopt: implement IPV6_TCLASS".
 - Patch 4: move tcp_sock_set_syncnt before __mptcp_setsockopt_set_val.

v5:
 - Include Gang Yan's TCP_MAXSEG cleanup.
 - Include two v4-mapped addr fixes.
 - Patch 9, set rcv_flowinfo to 0 for v4-mapped addr.
 - Patch 11, use rcv_flowinfo instead of np->tclass.
 - All comments from Sashiko on v4 regarding "CONFIG_IPV6=m" are false
   positives.
 - https://patchwork.kernel.org/project/mptcp/cover/cover.1786159812.git.tanggeliang@kylinos.cn/

v4:
 - patch 1: skip ssk->sk_bound_dev_if = local->ifindex when local->ifindex
   is 0, so __mptcp_subflow_connect() doesn't overwrite the inherited
   SO_BINDTODEVICE binding.
 - patch 4: assign tcp_sock_set_syncnt()'s return to ret so an invalid
   TCP_SYNCNT is propagated, not silently dropped.
 - patch 6: skip IPV6_TCLASS setsockopt/getsockopt paths on AF_INET
   sockets/subflows (inet6_sk is NULL there).
 - patch 7: treat IPv4-mapped IPv6 as AF_INET for the TOS/tclass path.
 - patch 9: gate ip6_sock_set_tclass() behind sk_family == AF_INET6 and
   IS_ENABLED(CONFIG_IPV6) to avoid IPv4 NULL-deref and link failure when
   CONFIG_IPV6 is off.
 - patch 10: gate tclass on sk_family, skip IPv6 branch for IPv4-mapped
   connections, wrap IPv6 in CONFIG_IPV6.
 - https://patchwork.kernel.org/project/mptcp/cover/cover.1785378180.git.tanggeliang@kylinos.cn/

v3:
 - include tclass patches.
 - I also included three NVMe patches here because they have dependencies.
 - https://patchwork.kernel.org/project/mptcp/cover/cover.1785238723.git.tanggeliang@kylinos.cn/

v2:
 - Drop "mptcp: don't reset dst when setting default 0 tos"
   and "selftests: mptcp: sockopt: cover LINGER, REUSEADDR,
   PRIORITY, NODELAY, SYNCNT": the 'if (val > 0)' guard
   blocked the legitimate "reset to 0" path, and the test
   only ran val_in=1, missing the SK_CAN_REUSE "any non-zero
   -> 1" normalization.
 - mptcp: bump setsockopt_seq for subflow-only socket options,
   so secondary subflows created via MP_JOIN re-sync
   sk_reuse / sk_reuseport / sk_bound_dev_if from msk.
 - mptcp: copy the subflow's TOS to the msk on accept
   (alongside the existing ssk->rcv_tos copy), so MP_JOIN'd
   subflows inherit the reflected outgoing TOS.
 - mptcp: propagate sk_reuseport to subflows via
   sync_socket_options, so secondary subflows inherit
   SO_REUSEPORT, not just SO_REUSEADDR.
 - mptcp: tighten TCP_SYNCNT bounds check
   ('val < 1 || val > MAX_TCP_SYNCNT'), so out-of-bounds
   values are rejected even when msk has no subflows yet
   (where __mptcp_setsockopt_set_val would otherwise return 0
   without invoking the set_val callback).
 - https://patchwork.kernel.org/project/mptcp/cover/cover.1785054808.git.tanggeliang@kylinos.cn/

v1:
 - https://patchwork.kernel.org/project/mptcp/cover/cover.1784985085.git.tanggeliang@kylinos.cn/

David 'equinox' Lamparter (1):
  mptcp: sockopt: implement IPV6_TCLASS

Gang Yan (1):
  mptcp: take TCP_MAXSEG handling into setsockopt_set_val

Geliang Tang (4):
  mptcp: handle TCP_MAXSEG getsockopt in common case
  mptcp: inherit sk_reuse and fix dev bind override
  mptcp: add TCP_SYNCNT setsockopt/getsockopt
  mptcp: copy subflow's tos/tclass to msk on accept

 include/net/ipv6.h       |  2 +
 net/ipv6/ipv6_sockglue.c | 23 +++++++----
 net/mptcp/protocol.c     | 16 ++++++++
 net/mptcp/sockopt.c      | 82 +++++++++++++++++++++++++++++++++++++---
 net/mptcp/subflow.c      |  4 +-
 5 files changed, 112 insertions(+), 15 deletions(-)

-- 
2.53.0


^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH mptcp-next v6 1/6] mptcp: handle TCP_MAXSEG getsockopt in common case
  2026-08-17  3:57 [PATCH mptcp-next v6 0/6] Fix socket options used by NVMe over MPTCP Geliang Tang
@ 2026-08-17  3:57 ` Geliang Tang
  2026-08-17  3:57 ` [PATCH mptcp-next v6 2/6] mptcp: take TCP_MAXSEG handling into setsockopt_set_val Geliang Tang
                   ` (5 subsequent siblings)
  6 siblings, 0 replies; 8+ messages in thread
From: Geliang Tang @ 2026-08-17  3:57 UTC (permalink / raw)
  To: mptcp; +Cc: Geliang Tang

From: Geliang Tang <tanggeliang@kylinos.cn>

Move TCP_MAXSEG from a tail-clause into the common case alongside other
"first subflow only" options (TCP_FASTOPEN_*), making the dispatch logic
more uniform.

No behavioural change.

Signed-off-by: Geliang Tang <tanggeliang@kylinos.cn>
---
 net/mptcp/sockopt.c | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/net/mptcp/sockopt.c b/net/mptcp/sockopt.c
index 922f6ae5c80c..2c1eaf66202a 100644
--- a/net/mptcp/sockopt.c
+++ b/net/mptcp/sockopt.c
@@ -1499,6 +1499,7 @@ static int mptcp_getsockopt_sol_tcp(struct mptcp_sock *msk, int optname,
 	case TCP_FASTOPEN_CONNECT:
 	case TCP_FASTOPEN_KEY:
 	case TCP_FASTOPEN_NO_COOKIE:
+	case TCP_MAXSEG:
 		return mptcp_getsockopt_first_sf_only(msk, SOL_TCP, optname,
 						      optval, optlen);
 	case TCP_INQ:
@@ -1523,9 +1524,6 @@ 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_MAXSEG:
-		return mptcp_getsockopt_first_sf_only(msk, SOL_TCP, optname,
-						      optval, optlen);
 	}
 	return -EOPNOTSUPP;
 }
-- 
2.53.0


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH mptcp-next v6 2/6] mptcp: take TCP_MAXSEG handling into setsockopt_set_val
  2026-08-17  3:57 [PATCH mptcp-next v6 0/6] Fix socket options used by NVMe over MPTCP Geliang Tang
  2026-08-17  3:57 ` [PATCH mptcp-next v6 1/6] mptcp: handle TCP_MAXSEG getsockopt in common case Geliang Tang
@ 2026-08-17  3:57 ` Geliang Tang
  2026-08-17  3:57 ` [PATCH mptcp-next v6 3/6] mptcp: inherit sk_reuse and fix dev bind override Geliang Tang
                   ` (4 subsequent siblings)
  6 siblings, 0 replies; 8+ messages in thread
From: Geliang Tang @ 2026-08-17  3:57 UTC (permalink / raw)
  To: mptcp; +Cc: Gang Yan, Geliang Tang

From: Gang Yan <yangang@kylinos.cn>

Replace mptcp_setsockopt_all_sf() with __mptcp_setsockopt_set_val()
for TCP_MAXSEG option handling. This aligns the implementation with
other socket options that use the same helper and simplifies the code.

Co-developed-by: Geliang Tang <geliang@kernel.org>
Signed-off-by: Geliang Tang <geliang@kernel.org>
Signed-off-by: Gang Yan <yangang@kylinos.cn>
---
 net/mptcp/sockopt.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/net/mptcp/sockopt.c b/net/mptcp/sockopt.c
index 2c1eaf66202a..5de371e29721 100644
--- a/net/mptcp/sockopt.c
+++ b/net/mptcp/sockopt.c
@@ -968,9 +968,9 @@ static int mptcp_setsockopt_sol_tcp(struct mptcp_sock *msk, int optname,
 						 val);
 		break;
 	case TCP_MAXSEG:
-		msk->maxseg = val;
-		ret = mptcp_setsockopt_all_sf(msk, SOL_TCP, optname, optval,
-					      optlen);
+		ret = __mptcp_setsockopt_set_val(msk, MAX_TCP_WINDOW,
+						 &tcp_sock_set_maxseg,
+						 &msk->maxseg, val);
 		break;
 	default:
 		ret = -ENOPROTOOPT;
-- 
2.53.0


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH mptcp-next v6 3/6] mptcp: inherit sk_reuse and fix dev bind override
  2026-08-17  3:57 [PATCH mptcp-next v6 0/6] Fix socket options used by NVMe over MPTCP Geliang Tang
  2026-08-17  3:57 ` [PATCH mptcp-next v6 1/6] mptcp: handle TCP_MAXSEG getsockopt in common case Geliang Tang
  2026-08-17  3:57 ` [PATCH mptcp-next v6 2/6] mptcp: take TCP_MAXSEG handling into setsockopt_set_val Geliang Tang
@ 2026-08-17  3:57 ` Geliang Tang
  2026-08-17  3:57 ` [PATCH mptcp-next v6 4/6] mptcp: add TCP_SYNCNT setsockopt/getsockopt Geliang Tang
                   ` (3 subsequent siblings)
  6 siblings, 0 replies; 8+ messages in thread
From: Geliang Tang @ 2026-08-17  3:57 UTC (permalink / raw)
  To: mptcp; +Cc: Geliang Tang

From: Geliang Tang <tanggeliang@kylinos.cn>

Propagate sk_reuse and sk_reuseport from master socket to subflows, and
bump setsockopt_seq so later subflows pick up the changes.

This patch also fixes unconditional sk_bound_dev_if override in
__mptcp_subflow_connect(): only set it when local->ifindex is non-zero,
otherwise preserve the value inherited from the master socket via
sync_socket_options().

Signed-off-by: Geliang Tang <tanggeliang@kylinos.cn>
---
 net/mptcp/sockopt.c | 5 +++++
 net/mptcp/subflow.c | 4 +++-
 2 files changed, 8 insertions(+), 1 deletion(-)

diff --git a/net/mptcp/sockopt.c b/net/mptcp/sockopt.c
index 5de371e29721..d79139eb5b8a 100644
--- a/net/mptcp/sockopt.c
+++ b/net/mptcp/sockopt.c
@@ -335,6 +335,8 @@ static int mptcp_setsockopt_sol_socket(struct mptcp_sock *msk, int optname,
 				sk->sk_bound_dev_if = ssk->sk_bound_dev_if;
 			else if (optname == SO_BINDTOIFINDEX)
 				sk->sk_bound_dev_if = ssk->sk_bound_dev_if;
+
+			sockopt_seq_inc(msk);
 		}
 		release_sock(sk);
 		return ret;
@@ -1704,6 +1706,9 @@ static void sync_socket_options(struct mptcp_sock *msk, struct sock *ssk)
 		assign_bit(b, &inet_sk(ssk)->inet_flags, src & BIT(b));
 
 	WRITE_ONCE(inet_sk(ssk)->local_port_range, READ_ONCE(inet_sk(sk)->local_port_range));
+
+	ssk->sk_reuse = sk->sk_reuse;
+	ssk->sk_reuseport = sk->sk_reuseport;
 }
 
 void mptcp_sockopt_sync_locked(struct mptcp_sock *msk, struct sock *ssk)
diff --git a/net/mptcp/subflow.c b/net/mptcp/subflow.c
index af81ad5e699d..47ff736c4d66 100644
--- a/net/mptcp/subflow.c
+++ b/net/mptcp/subflow.c
@@ -1672,7 +1672,9 @@ int __mptcp_subflow_connect(struct sock *sk, const struct mptcp_pm_local *local,
 	if (addr.ss_family == AF_INET6)
 		addrlen = sizeof(struct sockaddr_in6);
 #endif
-	ssk->sk_bound_dev_if = local->ifindex;
+	/* Only override the bound device if the path manager picked one. */
+	if (local->ifindex)
+		ssk->sk_bound_dev_if = local->ifindex;
 	err = kernel_bind(sf, (struct sockaddr_unsized *)&addr, addrlen);
 	if (err) {
 		MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_JOINSYNTXBINDERR);
-- 
2.53.0


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH mptcp-next v6 4/6] mptcp: add TCP_SYNCNT setsockopt/getsockopt
  2026-08-17  3:57 [PATCH mptcp-next v6 0/6] Fix socket options used by NVMe over MPTCP Geliang Tang
                   ` (2 preceding siblings ...)
  2026-08-17  3:57 ` [PATCH mptcp-next v6 3/6] mptcp: inherit sk_reuse and fix dev bind override Geliang Tang
@ 2026-08-17  3:57 ` Geliang Tang
  2026-08-17  3:57 ` [PATCH mptcp-next v6 5/6] mptcp: sockopt: implement IPV6_TCLASS Geliang Tang
                   ` (2 subsequent siblings)
  6 siblings, 0 replies; 8+ messages in thread
From: Geliang Tang @ 2026-08-17  3:57 UTC (permalink / raw)
  To: mptcp; +Cc: Geliang Tang

From: Geliang Tang <tanggeliang@kylinos.cn>

This patch adds TCP_SYNCNT support on the MPTCP socket.

The setsockopt() path stores the value in inet_csk(sk)->icsk_syn_retries
on the msk and all subflow sockets. The getsockopt() path reads the same
field back from the master socket.

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 <tanggeliang@kylinos.cn>
---
 net/mptcp/sockopt.c | 15 +++++++++++++++
 1 file changed, 15 insertions(+)

diff --git a/net/mptcp/sockopt.c b/net/mptcp/sockopt.c
index d79139eb5b8a..50420d332b44 100644
--- a/net/mptcp/sockopt.c
+++ b/net/mptcp/sockopt.c
@@ -974,6 +974,13 @@ static int mptcp_setsockopt_sol_tcp(struct mptcp_sock *msk, int optname,
 						 &tcp_sock_set_maxseg,
 						 &msk->maxseg, val);
 		break;
+	case TCP_SYNCNT:
+		ret = tcp_sock_set_syncnt(sk, val);
+		if (ret == 0)
+			ret = __mptcp_setsockopt_set_val(msk, MAX_TCP_SYNCNT,
+							 &tcp_sock_set_syncnt,
+							 &val, val);
+		break;
 	default:
 		ret = -ENOPROTOOPT;
 	}
@@ -1526,6 +1533,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,
+					    READ_ONCE(inet_csk(sk)->icsk_syn_retries) ? :
+					    READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_syn_retries));
 	}
 	return -EOPNOTSUPP;
 }
@@ -1646,6 +1657,7 @@ static void sync_socket_options(struct mptcp_sock *msk, struct sock *ssk)
 	struct sock *sk = (struct sock *)msk;
 	unsigned long src;
 	bool keep_open;
+	int syncnt;
 	int b;
 
 	keep_open = sock_flag(sk, SOCK_KEEPOPEN);
@@ -1709,6 +1721,9 @@ static void sync_socket_options(struct mptcp_sock *msk, struct sock *ssk)
 
 	ssk->sk_reuse = sk->sk_reuse;
 	ssk->sk_reuseport = sk->sk_reuseport;
+	syncnt = READ_ONCE(inet_csk(sk)->icsk_syn_retries);
+	if (syncnt > 0 && tcp_sock_set_syncnt(ssk, syncnt))
+		pr_warn("Failed to sync TCP_SYNCNT=%u to subflow\n", syncnt);
 }
 
 void mptcp_sockopt_sync_locked(struct mptcp_sock *msk, struct sock *ssk)
-- 
2.53.0


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH mptcp-next v6 5/6] mptcp: sockopt: implement IPV6_TCLASS
  2026-08-17  3:57 [PATCH mptcp-next v6 0/6] Fix socket options used by NVMe over MPTCP Geliang Tang
                   ` (3 preceding siblings ...)
  2026-08-17  3:57 ` [PATCH mptcp-next v6 4/6] mptcp: add TCP_SYNCNT setsockopt/getsockopt Geliang Tang
@ 2026-08-17  3:57 ` Geliang Tang
  2026-08-17  3:57 ` [PATCH mptcp-next v6 6/6] mptcp: copy subflow's tos/tclass to msk on accept Geliang Tang
  2026-08-17  5:11 ` [PATCH mptcp-next v6 0/6] Fix socket options used by NVMe over MPTCP MPTCP CI
  6 siblings, 0 replies; 8+ messages in thread
From: Geliang Tang @ 2026-08-17  3:57 UTC (permalink / raw)
  To: mptcp
  Cc: David 'equinox' Lamparter, Mat Martineau, Matthieu Baerts,
	Geliang Tang

From: David 'equinox' Lamparter <equinox@diac24.net>

The IPV6_TCLASS setsockopt just needs to be forwarded to the individual
TCP sockets, like IP_TOS is already handled for IPv4.

Coincidentally, ssh uses this sockopt and prints an error in the middle
of your ongoing SSH session when it doesn't work (very annoying when
doing SCP/SFTP on a multiplexed session.)

IPV6_TCLASS handling in do_ipv6_setsockopt() inlines the same ECN mask
logic and inet6_sk(sk)->tclass write that callers need when propagating
a tclass value onto a newly created socket.

Pull this into a small helper __ip6_sock_set_tclass() exported via
<net/ipv6.h>, so MPTCP can apply IPV6_TCLASS without duplicating the
ECN handling.

For setsockopt, the value is first applied to the MPTCP socket itself via
ipv6_setsockopt(), then propagated to all existing subflows using
__ip6_sock_set_tclass(). The setsockopt_seq is bumped to ensure that
subflows created later will pick up the setting through
sync_socket_options().

For getsockopt, the value is read directly from the MPTCP socket.

Also add sync_socket_options() support for IPV6_TCLASS, so that new
subflows created after the option is set inherit the correct tclass
value.

Closes: https://github.com/multipath-tcp/mptcp_net-next/issues/568
Cc: Mat Martineau <martineau@kernel.org>
Cc: Matthieu Baerts <matttbe@kernel.org>
Co-developed-by: Geliang Tang <geliang@kernel.org>
Signed-off-by: Geliang Tang <geliang@kernel.org>
Signed-off-by: David 'equinox' Lamparter <equinox@diac24.net>
---
 include/net/ipv6.h       |  2 ++
 net/ipv6/ipv6_sockglue.c | 23 +++++++++++-------
 net/mptcp/sockopt.c      | 52 ++++++++++++++++++++++++++++++++++++++++
 3 files changed, 69 insertions(+), 8 deletions(-)

diff --git a/include/net/ipv6.h b/include/net/ipv6.h
index 3de07e738538..30fcae5ae054 100644
--- a/include/net/ipv6.h
+++ b/include/net/ipv6.h
@@ -1252,6 +1252,8 @@ static inline void ip6_sock_set_recverr(struct sock *sk)
 	inet6_set_bit(RECVERR6, sk);
 }
 
+void __ip6_sock_set_tclass(struct sock *sk, int val);
+
 #define IPV6_PREFER_SRC_MASK (IPV6_PREFER_SRC_TMP | IPV6_PREFER_SRC_PUBLIC | \
 			      IPV6_PREFER_SRC_COA)
 
diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c
index b4c977434c2e..3bc87f3e266e 100644
--- a/net/ipv6/ipv6_sockglue.c
+++ b/net/ipv6/ipv6_sockglue.c
@@ -373,6 +373,20 @@ static int ipv6_set_opt_hdr(struct sock *sk, int optname, sockptr_t optval,
 	return err;
 }
 
+void __ip6_sock_set_tclass(struct sock *sk, int val)
+{
+	u8 old_tclass = inet6_sk(sk)->tclass;
+
+	if (sk->sk_type == SOCK_STREAM) {
+		val &= ~INET_ECN_MASK;
+		val |= old_tclass & INET_ECN_MASK;
+	}
+	if (old_tclass != val) {
+		WRITE_ONCE(inet6_sk(sk)->tclass, val);
+		sk_dst_reset(sk);
+	}
+}
+
 int do_ipv6_setsockopt(struct sock *sk, int level, int optname,
 		       sockptr_t optval, unsigned int optlen)
 {
@@ -713,14 +727,7 @@ int do_ipv6_setsockopt(struct sock *sk, int level, int optname,
 		/* RFC 3542, 6.5: default traffic class of 0x0 */
 		if (val == -1)
 			val = 0;
-		if (sk->sk_type == SOCK_STREAM) {
-			val &= ~INET_ECN_MASK;
-			val |= np->tclass & INET_ECN_MASK;
-		}
-		if (np->tclass != val) {
-			np->tclass = val;
-			sk_dst_reset(sk);
-		}
+		__ip6_sock_set_tclass(sk, val);
 		retv = 0;
 		break;
 
diff --git a/net/mptcp/sockopt.c b/net/mptcp/sockopt.c
index 50420d332b44..442167e66c48 100644
--- a/net/mptcp/sockopt.c
+++ b/net/mptcp/sockopt.c
@@ -485,6 +485,42 @@ static int mptcp_setsockopt_recverr(struct mptcp_sock *msk, int level,
 	return ret;
 }
 
+#if IS_ENABLED(CONFIG_IPV6)
+static int mptcp_setsockopt_v6_set_tclass(struct mptcp_sock *msk, int optname,
+					  sockptr_t optval, unsigned int optlen)
+{
+	struct mptcp_subflow_context *subflow;
+	struct sock *sk = (struct sock *)msk;
+	int err, val;
+
+	if (sk->sk_family != AF_INET6)
+		return -EOPNOTSUPP;
+
+	err = ipv6_setsockopt(sk, SOL_IPV6, optname, optval, optlen);
+
+	if (err != 0)
+		return err;
+
+	lock_sock(sk);
+	sockopt_seq_inc(msk);
+	val = READ_ONCE(inet6_sk(sk)->tclass);
+	mptcp_for_each_subflow(msk, subflow) {
+		struct sock *ssk = mptcp_subflow_tcp_sock(subflow);
+		bool slow;
+
+		if (ssk->sk_family != AF_INET6)
+			continue;
+
+		slow = lock_sock_fast(ssk);
+		__ip6_sock_set_tclass(ssk, val);
+		unlock_sock_fast(ssk, slow);
+	}
+	release_sock(sk);
+
+	return 0;
+}
+#endif
+
 static int mptcp_setsockopt_v6(struct mptcp_sock *msk, int optname,
 			       sockptr_t optval, unsigned int optlen)
 {
@@ -532,6 +568,11 @@ static int mptcp_setsockopt_v6(struct mptcp_sock *msk, int optname,
 		ret = mptcp_setsockopt_recverr(msk, SOL_IPV6, optname, optval,
 					       optlen);
 		break;
+#if IS_ENABLED(CONFIG_IPV6)
+	case IPV6_TCLASS:
+		return mptcp_setsockopt_v6_set_tclass(msk, optname, optval,
+						      optlen);
+#endif
 	}
 
 	return ret;
@@ -1597,6 +1638,13 @@ static int mptcp_getsockopt_v6(struct mptcp_sock *msk, int optname,
 			return -ENOPROTOOPT;
 		return mptcp_put_int_option(msk, optval, optlen,
 					    inet6_test_bit(RECVERR6_RFC4884, sk));
+#if IS_ENABLED(CONFIG_IPV6)
+	case IPV6_TCLASS:
+		if (sk->sk_family != AF_INET6)
+			return -EOPNOTSUPP;
+		return mptcp_put_int_option(msk, optval, optlen,
+					    READ_ONCE(inet6_sk(sk)->tclass));
+#endif
 	}
 
 	return -EOPNOTSUPP;
@@ -1724,6 +1772,10 @@ static void sync_socket_options(struct mptcp_sock *msk, struct sock *ssk)
 	syncnt = READ_ONCE(inet_csk(sk)->icsk_syn_retries);
 	if (syncnt > 0 && tcp_sock_set_syncnt(ssk, syncnt))
 		pr_warn("Failed to sync TCP_SYNCNT=%u to subflow\n", syncnt);
+#if IS_ENABLED(CONFIG_IPV6)
+	if (sk->sk_family == AF_INET6 && ssk->sk_family == AF_INET6)
+		__ip6_sock_set_tclass(ssk, READ_ONCE(inet6_sk(sk)->tclass));
+#endif
 }
 
 void mptcp_sockopt_sync_locked(struct mptcp_sock *msk, struct sock *ssk)
-- 
2.53.0


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH mptcp-next v6 6/6] mptcp: copy subflow's tos/tclass to msk on accept
  2026-08-17  3:57 [PATCH mptcp-next v6 0/6] Fix socket options used by NVMe over MPTCP Geliang Tang
                   ` (4 preceding siblings ...)
  2026-08-17  3:57 ` [PATCH mptcp-next v6 5/6] mptcp: sockopt: implement IPV6_TCLASS Geliang Tang
@ 2026-08-17  3:57 ` Geliang Tang
  2026-08-17  5:11 ` [PATCH mptcp-next v6 0/6] Fix socket options used by NVMe over MPTCP MPTCP CI
  6 siblings, 0 replies; 8+ messages in thread
From: Geliang Tang @ 2026-08-17  3:57 UTC (permalink / raw)
  To: mptcp; +Cc: Geliang Tang

From: Geliang Tang <tanggeliang@kylinos.cn>

When a new MPTCP socket is accepted, copy the tos (and rcv_tos for IPv4)
or tclass (and rcv_flowinfo for IPv6) from the first subflow to the
newly-created msk.

This mirrors what plain TCP does in tcp_v4_syn_recv_sock() and
tcp_v6_syn_recv_sock(), where these values are copied from the incoming
skb to the accepted socket.

Without this, MP_JOIN subflows created later would inherit tos/tclass=0
from the msk and lose the peer's reflected value, causing inconsistent
traffic class behavior.

Signed-off-by: Geliang Tang <tanggeliang@kylinos.cn>
---
 net/mptcp/protocol.c | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c
index c2762d74f29d..f18af725e8e2 100644
--- a/net/mptcp/protocol.c
+++ b/net/mptcp/protocol.c
@@ -3756,6 +3756,22 @@ struct sock *mptcp_sk_clone_init(const struct sock *sk,
 #endif
 		mptcp_copy_ip_options(nsk, sk);
 
+	if (ssk->sk_family == AF_INET) {
+		inet_sk(nsk)->rcv_tos = inet_sk(ssk)->rcv_tos;
+		__ip_sock_set_tos(nsk, inet_sk(ssk)->tos);
+	}
+#if IS_ENABLED(CONFIG_MPTCP_IPV6)
+	else if (ssk->sk_family == AF_INET6 &&
+		 ipv6_addr_v4mapped(&ssk->sk_v6_daddr)) {
+		inet_sk(nsk)->rcv_tos = inet_sk(ssk)->rcv_tos;
+		__ip_sock_set_tos(nsk, inet_sk(ssk)->tos);
+		inet6_sk(nsk)->rcv_flowinfo = 0;
+	} else if (ssk->sk_family == AF_INET6) {
+		inet6_sk(nsk)->rcv_flowinfo = inet6_sk(ssk)->rcv_flowinfo;
+		__ip6_sock_set_tclass(nsk, inet6_sk(ssk)->tclass);
+	}
+#endif
+
 	msk = mptcp_sk(nsk);
 	WRITE_ONCE(msk->local_key, subflow_req->local_key);
 	WRITE_ONCE(msk->token, subflow_req->token);
-- 
2.53.0


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* Re: [PATCH mptcp-next v6 0/6] Fix socket options used by NVMe over MPTCP
  2026-08-17  3:57 [PATCH mptcp-next v6 0/6] Fix socket options used by NVMe over MPTCP Geliang Tang
                   ` (5 preceding siblings ...)
  2026-08-17  3:57 ` [PATCH mptcp-next v6 6/6] mptcp: copy subflow's tos/tclass to msk on accept Geliang Tang
@ 2026-08-17  5:11 ` MPTCP CI
  6 siblings, 0 replies; 8+ messages in thread
From: MPTCP CI @ 2026-08-17  5:11 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 (except selftest_mptcp_join): Success! ✅
- KVM Validation: normal (only selftest_mptcp_join): Success! ✅
- KVM Validation: debug (except selftest_mptcp_join): Success! ✅
- KVM Validation: debug (only selftest_mptcp_join): Success! ✅
- 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/31994206151

Initiator: Patchew Applier
Commits: https://github.com/multipath-tcp/mptcp_net-next/commits/f3f2396df333
Patchwork: https://patchwork.kernel.org/project/mptcp/list/?series=1146924


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] 8+ messages in thread

end of thread, other threads:[~2026-08-17  5:11 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-17  3:57 [PATCH mptcp-next v6 0/6] Fix socket options used by NVMe over MPTCP Geliang Tang
2026-08-17  3:57 ` [PATCH mptcp-next v6 1/6] mptcp: handle TCP_MAXSEG getsockopt in common case Geliang Tang
2026-08-17  3:57 ` [PATCH mptcp-next v6 2/6] mptcp: take TCP_MAXSEG handling into setsockopt_set_val Geliang Tang
2026-08-17  3:57 ` [PATCH mptcp-next v6 3/6] mptcp: inherit sk_reuse and fix dev bind override Geliang Tang
2026-08-17  3:57 ` [PATCH mptcp-next v6 4/6] mptcp: add TCP_SYNCNT setsockopt/getsockopt Geliang Tang
2026-08-17  3:57 ` [PATCH mptcp-next v6 5/6] mptcp: sockopt: implement IPV6_TCLASS Geliang Tang
2026-08-17  3:57 ` [PATCH mptcp-next v6 6/6] mptcp: copy subflow's tos/tclass to msk on accept Geliang Tang
2026-08-17  5:11 ` [PATCH mptcp-next v6 0/6] Fix socket options used by NVMe over MPTCP MPTCP CI

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.