The IPV6_TCLASS setsockopt just needs to be forwarded to the individual TCP sockets, like IP_TOS is already handled for IPv4. The code here is pretty much identical, except there's no helper for IPv6 like IPv4's __ip_sock_set_tos(). 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.) Signed-off-by: David 'equinox' Lamparter Cc: Matthieu Baerts Cc: Mat Martineau Cc: Geliang Tang --- [v2: added guard for CONFIG_IPV6=n. I could also add a stub for ipv6_setsockopt() in include/net/ipv6.h, that might be prettier?] --- net/mptcp/sockopt.c | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/net/mptcp/sockopt.c b/net/mptcp/sockopt.c index fcf6feb2a9eb..1b83bba0b58e 100644 --- a/net/mptcp/sockopt.c +++ b/net/mptcp/sockopt.c @@ -394,6 +394,39 @@ static int mptcp_setsockopt_sol_socket(struct mptcp_sock *msk, int optname, return -EOPNOTSUPP; } +static int mptcp_setsockopt_v6_set_tclass(struct mptcp_sock *msk, int optname, + sockptr_t optval, unsigned int optlen) +{ +#if !IS_ENABLED(CONFIG_IPV6) + return -EOPNOTSUPP; +#else + struct mptcp_subflow_context *subflow; + struct sock *sk = (struct sock *)msk; + int err, val; + + 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; + + slow = lock_sock_fast(ssk); + inet6_sk(ssk)->tclass = val; + sk_dst_reset(ssk); + 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) { @@ -436,6 +469,8 @@ static int mptcp_setsockopt_v6(struct mptcp_sock *msk, int optname, release_sock(sk); break; + case IPV6_TCLASS: + return mptcp_setsockopt_v6_set_tclass(msk, optname, optval, optlen); } return ret; @@ -1485,6 +1520,9 @@ static int mptcp_getsockopt_v6(struct mptcp_sock *msk, int optname, struct sock *sk = (void *)msk; switch (optname) { + case IPV6_TCLASS: + return mptcp_put_int_option(msk, optval, optlen, + READ_ONCE(inet6_sk(sk)->tclass)); case IPV6_V6ONLY: return mptcp_put_int_option(msk, optval, optlen, sk->sk_ipv6only); -- 2.53.0