From: Geliang Tang 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 small helpers __ip6_sock_set_tclass()/ip6_sock_set_tclass() exported via , so external modules can apply IPV6_TCLASS without duplicating the ECN handling. __ip6_sock_set_tclass() will be used by MPTCP's sockopt implementation (similar to __ip_sock_set_tos), while ip6_sock_set_tclass() will be used by nvme-tcp (similar to ip_sock_set_tos). Signed-off-by: Geliang Tang --- include/net/ipv6.h | 3 +++ net/ipv6/ipv6_sockglue.c | 31 +++++++++++++++++++++++-------- 2 files changed, 26 insertions(+), 8 deletions(-) diff --git a/include/net/ipv6.h b/include/net/ipv6.h index 3de07e738538..82e57b34ba57 100644 --- a/include/net/ipv6.h +++ b/include/net/ipv6.h @@ -1252,6 +1252,9 @@ 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); +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..c59f25fbb336 100644 --- a/net/ipv6/ipv6_sockglue.c +++ b/net/ipv6/ipv6_sockglue.c @@ -373,6 +373,28 @@ 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); + } +} + +void ip6_sock_set_tclass(struct sock *sk, int val) +{ + sockopt_lock_sock(sk); + __ip6_sock_set_tclass(sk, val); + sockopt_release_sock(sk); +} +EXPORT_SYMBOL(ip6_sock_set_tclass); + int do_ipv6_setsockopt(struct sock *sk, int level, int optname, sockptr_t optval, unsigned int optlen) { @@ -713,14 +735,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; -- 2.53.0