[PATCH mptcp-next v2 1/3] mptcp: add IPV6_TCLASS socket option support

Geliang Tang posted 3 patches 1 month ago
[PATCH mptcp-next v2 1/3] mptcp: add IPV6_TCLASS socket option support
Posted by Geliang Tang 1 month ago
From: Geliang Tang <tanggeliang@kylinos.cn>

Implement support for IPV6_TCLASS socket option in MPTCP:
1. setsockopt(IPV6_TCLASS):
   - Sets traffic class on main MPTCP socket
   - Propagates value to all IPv6 subflows
2. getsockopt(IPV6_TCLASS):
   - Returns current value from inet6_sk(sk)->tclass
3. Syncs traffic class to new subflows

Mirrors existing IPv4 TOS handling and ensures consistent QoS across
subflows. Fixes reported issues with traffic class propagation in MPTCP.

Reported-by: kernel test robot <lkp@intel.com>
Closes: https://lore.kernel.org/oe-kbuild-all/202508021003.tEAjvv2S-lkp@intel.com/
Closes: https://github.com/multipath-tcp/mptcp_net-next/issues/568
Signed-off-by: Geliang Tang <tanggeliang@kylinos.cn>
---
 net/mptcp/sockopt.c | 27 +++++++++++++++++++++++----
 1 file changed, 23 insertions(+), 4 deletions(-)

diff --git a/net/mptcp/sockopt.c b/net/mptcp/sockopt.c
index 5b0648ab663e..bb296813c578 100644
--- a/net/mptcp/sockopt.c
+++ b/net/mptcp/sockopt.c
@@ -458,6 +458,9 @@ static int mptcp_setsockopt_v6(struct mptcp_sock *msk, int optname,
 	case IPV6_FREEBIND:
 		return mptcp_setsockopt_first_sf_only(msk, SOL_IPV6, optname,
 						      optval, optlen);
+	case IPV6_TCLASS:
+		return mptcp_setsockopt_all_sf(msk, SOL_IPV6, optname,
+					       optval, optlen);
 	}
 
 	return -EOPNOTSUPP;
@@ -765,7 +768,7 @@ static int mptcp_setsockopt_sol_ip_first_sf_only(struct mptcp_sock *msk, int opt
 	return 0;
 }
 
-static int mptcp_setsockopt_sol_ip_all_sf(struct mptcp_sock *msk,
+static int mptcp_setsockopt_sol_ip_all_sf(struct mptcp_sock *msk, int level,
 					  int optname, sockptr_t optval,
 					  unsigned int optlen)
 {
@@ -773,10 +776,16 @@ static int mptcp_setsockopt_sol_ip_all_sf(struct mptcp_sock *msk,
 	struct sock *sk = (struct sock *)msk;
 	int err, val;
 
-	if (optname != IP_TOS)
+	if (optname != IP_TOS &&
+	    optname != IPV6_TCLASS)
 		return -EOPNOTSUPP;
 
-	err = ip_setsockopt(sk, SOL_IP, optname, optval, optlen);
+	if (level == SOL_IP)
+		err = ip_setsockopt(sk, level, optname, optval, optlen);
+#if IS_ENABLED(CONFIG_MPTCP_IPV6)
+	else
+		err = ipv6_setsockopt(sk, level, optname, optval, optlen);
+#endif
 
 	if (err != 0)
 		return err;
@@ -785,6 +794,8 @@ static int mptcp_setsockopt_sol_ip_all_sf(struct mptcp_sock *msk,
 	sockopt_seq_inc(msk);
 	if (optname == IP_TOS)
 		val = READ_ONCE(inet_sk(sk)->tos);
+	else if (optname == IPV6_TCLASS)
+		val = READ_ONCE(inet6_sk(sk)->tclass);
 	mptcp_for_each_subflow(msk, subflow) {
 		struct sock *ssk = mptcp_subflow_tcp_sock(subflow);
 		bool slow;
@@ -792,6 +803,8 @@ static int mptcp_setsockopt_sol_ip_all_sf(struct mptcp_sock *msk,
 		slow = lock_sock_fast(ssk);
 		if (optname == IP_TOS)
 			__ip_sock_set_tos(ssk, val);
+		else if (optname == IPV6_TCLASS)
+			WRITE_ONCE(inet6_sk(ssk)->tclass, val);
 		unlock_sock_fast(ssk, slow);
 	}
 	release_sock(sk);
@@ -885,7 +898,8 @@ static int mptcp_setsockopt_all_sf(struct mptcp_sock *msk, int level,
 		return mptcp_setsockopt_sol_tcp_all_sf(msk, optname,
 						       optval, optlen);
 	case SOL_IP:
-		return mptcp_setsockopt_sol_ip_all_sf(msk, optname,
+	case SOL_IPV6:
+		return mptcp_setsockopt_sol_ip_all_sf(msk, level, optname,
 						      optval, optlen);
 	}
 
@@ -1569,6 +1583,9 @@ static int mptcp_getsockopt_v6(struct mptcp_sock *msk, int optname,
 	case IPV6_FREEBIND:
 		return mptcp_put_int_option(msk, optval, optlen,
 					    inet_test_bit(FREEBIND, sk));
+	case IPV6_TCLASS:
+		return mptcp_put_int_option(msk, optval, optlen,
+					    inet6_sk(sk)->tclass);
 	}
 
 	return -EOPNOTSUPP;
@@ -1677,6 +1694,8 @@ static void sync_socket_options(struct mptcp_sock *msk, struct sock *ssk)
 	inet_assign_bit(FREEBIND, ssk, inet_test_bit(FREEBIND, sk));
 	inet_assign_bit(BIND_ADDRESS_NO_PORT, ssk, inet_test_bit(BIND_ADDRESS_NO_PORT, sk));
 	WRITE_ONCE(inet_sk(ssk)->local_port_range, READ_ONCE(inet_sk(sk)->local_port_range));
+	if (ssk->sk_family == AF_INET6)
+		WRITE_ONCE(inet6_sk(ssk)->tclass, READ_ONCE(inet6_sk(sk)->tclass));
 }
 
 void mptcp_sockopt_sync_locked(struct mptcp_sock *msk, struct sock *ssk)
-- 
2.48.1