ipv6: lockless IPV6_AUTOFLOWLABEL implementation

Move np->autoflowlabel and np->autoflowlabel_set in inet->inet_flags,
to fix data-races.

Signed-off-by: Eric Dumazet <edumazet@google.com>
Reviewed-by: David Ahern <dsahern@kernel.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Eric Dumazet 2023-09-12 16:02:06 +00:00 committed by David S. Miller
parent 6559c0ff3b
commit 5121516b0c
5 changed files with 13 additions and 16 deletions

View File

@ -253,8 +253,6 @@ struct ipv6_pinfo {
* 100: prefer care-of address * 100: prefer care-of address
*/ */
dontfrag:1, dontfrag:1,
autoflowlabel:1,
autoflowlabel_set:1,
rtalert_isolate:1; rtalert_isolate:1;
__u8 min_hopcount; __u8 min_hopcount;
__u8 tclass; __u8 tclass;

View File

@ -271,6 +271,8 @@ enum {
INET_FLAGS_MC6_LOOP = 20, INET_FLAGS_MC6_LOOP = 20,
INET_FLAGS_RECVERR6_RFC4884 = 21, INET_FLAGS_RECVERR6_RFC4884 = 21,
INET_FLAGS_MC6_ALL = 22, INET_FLAGS_MC6_ALL = 22,
INET_FLAGS_AUTOFLOWLABEL_SET = 23,
INET_FLAGS_AUTOFLOWLABEL = 24,
}; };
/* cmsg flags for inet */ /* cmsg flags for inet */

View File

@ -428,7 +428,7 @@ int ipv6_flowlabel_opt_get(struct sock *sk, struct in6_flowlabel_req *freq,
int flags); int flags);
int ip6_flowlabel_init(void); int ip6_flowlabel_init(void);
void ip6_flowlabel_cleanup(void); void ip6_flowlabel_cleanup(void);
bool ip6_autoflowlabel(struct net *net, const struct ipv6_pinfo *np); bool ip6_autoflowlabel(struct net *net, const struct sock *sk);
static inline void fl6_sock_release(struct ip6_flowlabel *fl) static inline void fl6_sock_release(struct ip6_flowlabel *fl)
{ {

View File

@ -232,12 +232,11 @@ int ip6_output(struct net *net, struct sock *sk, struct sk_buff *skb)
} }
EXPORT_SYMBOL(ip6_output); EXPORT_SYMBOL(ip6_output);
bool ip6_autoflowlabel(struct net *net, const struct ipv6_pinfo *np) bool ip6_autoflowlabel(struct net *net, const struct sock *sk)
{ {
if (!np->autoflowlabel_set) if (!inet6_test_bit(AUTOFLOWLABEL_SET, sk))
return ip6_default_np_autolabel(net); return ip6_default_np_autolabel(net);
else return inet6_test_bit(AUTOFLOWLABEL, sk);
return np->autoflowlabel;
} }
/* /*
@ -314,7 +313,7 @@ int ip6_xmit(const struct sock *sk, struct sk_buff *skb, struct flowi6 *fl6,
hlimit = ip6_dst_hoplimit(dst); hlimit = ip6_dst_hoplimit(dst);
ip6_flow_hdr(hdr, tclass, ip6_make_flowlabel(net, skb, fl6->flowlabel, ip6_flow_hdr(hdr, tclass, ip6_make_flowlabel(net, skb, fl6->flowlabel,
ip6_autoflowlabel(net, np), fl6)); ip6_autoflowlabel(net, sk), fl6));
hdr->payload_len = htons(seg_len); hdr->payload_len = htons(seg_len);
hdr->nexthdr = proto; hdr->nexthdr = proto;
@ -1938,7 +1937,6 @@ struct sk_buff *__ip6_make_skb(struct sock *sk,
struct sk_buff *skb, *tmp_skb; struct sk_buff *skb, *tmp_skb;
struct sk_buff **tail_skb; struct sk_buff **tail_skb;
struct in6_addr *final_dst; struct in6_addr *final_dst;
struct ipv6_pinfo *np = inet6_sk(sk);
struct net *net = sock_net(sk); struct net *net = sock_net(sk);
struct ipv6hdr *hdr; struct ipv6hdr *hdr;
struct ipv6_txoptions *opt = v6_cork->opt; struct ipv6_txoptions *opt = v6_cork->opt;
@ -1981,7 +1979,7 @@ struct sk_buff *__ip6_make_skb(struct sock *sk,
ip6_flow_hdr(hdr, v6_cork->tclass, ip6_flow_hdr(hdr, v6_cork->tclass,
ip6_make_flowlabel(net, skb, fl6->flowlabel, ip6_make_flowlabel(net, skb, fl6->flowlabel,
ip6_autoflowlabel(net, np), fl6)); ip6_autoflowlabel(net, sk), fl6));
hdr->hop_limit = v6_cork->hop_limit; hdr->hop_limit = v6_cork->hop_limit;
hdr->nexthdr = proto; hdr->nexthdr = proto;
hdr->saddr = fl6->saddr; hdr->saddr = fl6->saddr;

View File

@ -474,6 +474,10 @@ int do_ipv6_setsockopt(struct sock *sk, int level, int optname,
return -EINVAL; return -EINVAL;
inet6_assign_bit(MC6_ALL, sk, valbool); inet6_assign_bit(MC6_ALL, sk, valbool);
return 0; return 0;
case IPV6_AUTOFLOWLABEL:
inet6_assign_bit(AUTOFLOWLABEL, sk, valbool);
inet6_set_bit(AUTOFLOWLABEL_SET, sk);
return 0;
} }
if (needs_rtnl) if (needs_rtnl)
rtnl_lock(); rtnl_lock();
@ -970,11 +974,6 @@ done:
np->dontfrag = valbool; np->dontfrag = valbool;
retv = 0; retv = 0;
break; break;
case IPV6_AUTOFLOWLABEL:
np->autoflowlabel = valbool;
np->autoflowlabel_set = 1;
retv = 0;
break;
case IPV6_RECVFRAGSIZE: case IPV6_RECVFRAGSIZE:
np->rxopt.bits.recvfragsize = valbool; np->rxopt.bits.recvfragsize = valbool;
retv = 0; retv = 0;
@ -1447,7 +1446,7 @@ int do_ipv6_getsockopt(struct sock *sk, int level, int optname,
break; break;
case IPV6_AUTOFLOWLABEL: case IPV6_AUTOFLOWLABEL:
val = ip6_autoflowlabel(sock_net(sk), np); val = ip6_autoflowlabel(sock_net(sk), sk);
break; break;
case IPV6_RECVFRAGSIZE: case IPV6_RECVFRAGSIZE: