ipv6: lockless IPV6_DONTFRAG implementation
authorEric Dumazet <edumazet@google.com>
Tue, 12 Sep 2023 16:02:07 +0000 (16:02 +0000)
committerDavid S. Miller <davem@davemloft.net>
Fri, 15 Sep 2023 09:33:47 +0000 (10:33 +0100)
Move np->dontfrag flag to 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>
include/linux/ipv6.h
include/net/inet_sock.h
include/net/ipv6.h
include/net/xfrm.h
net/ipv6/icmp.c
net/ipv6/ip6_output.c
net/ipv6/ipv6_sockglue.c
net/ipv6/ping.c
net/ipv6/raw.c
net/ipv6/udp.c
net/l2tp/l2tp_ip6.c

index e3be5dc..57d563f 100644 (file)
@@ -252,7 +252,6 @@ struct ipv6_pinfo {
                                                 * 010: prefer public address
                                                 * 100: prefer care-of address
                                                 */
-                               dontfrag:1,
                                rtalert_isolate:1;
        __u8                    min_hopcount;
        __u8                    tclass;
index f1af64a..ac75324 100644 (file)
@@ -273,6 +273,7 @@ enum {
        INET_FLAGS_MC6_ALL      = 22,
        INET_FLAGS_AUTOFLOWLABEL_SET = 23,
        INET_FLAGS_AUTOFLOWLABEL = 24,
+       INET_FLAGS_DONTFRAG     = 25,
 };
 
 /* cmsg flags for inet */
index 4b6cbec..5a1f299 100644 (file)
@@ -373,12 +373,12 @@ static inline void ipcm6_init(struct ipcm6_cookie *ipc6)
 }
 
 static inline void ipcm6_init_sk(struct ipcm6_cookie *ipc6,
-                                const struct ipv6_pinfo *np)
+                                const struct sock *sk)
 {
        *ipc6 = (struct ipcm6_cookie) {
                .hlimit = -1,
-               .tclass = np->tclass,
-               .dontfrag = np->dontfrag,
+               .tclass = inet6_sk(sk)->tclass,
+               .dontfrag = inet6_test_bit(DONTFRAG, sk),
        };
 }
 
index 363c7d5..98d7aa7 100644 (file)
@@ -2166,7 +2166,7 @@ static inline bool xfrm6_local_dontfrag(const struct sock *sk)
 
        proto = sk->sk_protocol;
        if (proto == IPPROTO_UDP || proto == IPPROTO_RAW)
-               return inet6_sk(sk)->dontfrag;
+               return inet6_test_bit(DONTFRAG, sk);
 
        return false;
 }
index 93a594a..8fb4a79 100644 (file)
@@ -588,7 +588,7 @@ void icmp6_send(struct sk_buff *skb, u8 type, u8 code, __u32 info,
        else if (!fl6.flowi6_oif)
                fl6.flowi6_oif = np->ucast_oif;
 
-       ipcm6_init_sk(&ipc6, np);
+       ipcm6_init_sk(&ipc6, sk);
        ipc6.sockc.mark = mark;
        fl6.flowlabel = ip6_make_flowinfo(ipc6.tclass, fl6.flowlabel);
 
@@ -791,7 +791,7 @@ static enum skb_drop_reason icmpv6_echo_reply(struct sk_buff *skb)
        msg.offset = 0;
        msg.type = type;
 
-       ipcm6_init_sk(&ipc6, np);
+       ipcm6_init_sk(&ipc6, sk);
        ipc6.hlimit = ip6_sk_dst_hoplimit(np, &fl6, dst);
        ipc6.tclass = ipv6_get_dsfield(ipv6_hdr(skb));
        ipc6.sockc.mark = mark;
index 47aa42f..8851fe5 100644 (file)
@@ -2092,7 +2092,7 @@ struct sk_buff *ip6_make_skb(struct sock *sk,
                return ERR_PTR(err);
        }
        if (ipc6->dontfrag < 0)
-               ipc6->dontfrag = inet6_sk(sk)->dontfrag;
+               ipc6->dontfrag = inet6_test_bit(DONTFRAG, sk);
 
        err = __ip6_append_data(sk, &queue, cork, &v6_cork,
                                &current->task_frag, getfrag, from,
index d5d428a..33dd4dd 100644 (file)
@@ -478,6 +478,9 @@ int do_ipv6_setsockopt(struct sock *sk, int level, int optname,
                inet6_assign_bit(AUTOFLOWLABEL, sk, valbool);
                inet6_set_bit(AUTOFLOWLABEL_SET, sk);
                return 0;
+       case IPV6_DONTFRAG:
+               inet6_assign_bit(DONTFRAG, sk, valbool);
+               return 0;
        }
        if (needs_rtnl)
                rtnl_lock();
@@ -970,10 +973,6 @@ done:
                        goto e_inval;
                retv = __ip6_sock_set_addr_preferences(sk, val);
                break;
-       case IPV6_DONTFRAG:
-               np->dontfrag = valbool;
-               retv = 0;
-               break;
        case IPV6_RECVFRAGSIZE:
                np->rxopt.bits.recvfragsize = valbool;
                retv = 0;
@@ -1442,7 +1441,7 @@ int do_ipv6_getsockopt(struct sock *sk, int level, int optname,
                break;
 
        case IPV6_DONTFRAG:
-               val = np->dontfrag;
+               val = inet6_test_bit(DONTFRAG, sk);
                break;
 
        case IPV6_AUTOFLOWLABEL:
index 5831aaa..4444b61 100644 (file)
@@ -118,7 +118,7 @@ static int ping_v6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
             l3mdev_master_ifindex_by_index(sock_net(sk), oif) != sk->sk_bound_dev_if))
                return -EINVAL;
 
-       ipcm6_init_sk(&ipc6, np);
+       ipcm6_init_sk(&ipc6, sk);
        ipc6.sockc.tsflags = READ_ONCE(sk->sk_tsflags);
        ipc6.sockc.mark = READ_ONCE(sk->sk_mark);
 
index 42fcec3..cc9673c 100644 (file)
@@ -898,7 +898,7 @@ static int rawv6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
                ipc6.hlimit = ip6_sk_dst_hoplimit(np, &fl6, dst);
 
        if (ipc6.dontfrag < 0)
-               ipc6.dontfrag = np->dontfrag;
+               ipc6.dontfrag = inet6_test_bit(DONTFRAG, sk);
 
        if (msg->msg_flags&MSG_CONFIRM)
                goto do_confirm;
index f60ba42..e430150 100644 (file)
@@ -1595,7 +1595,7 @@ back_from_confirm:
 
 do_append_data:
        if (ipc6.dontfrag < 0)
-               ipc6.dontfrag = np->dontfrag;
+               ipc6.dontfrag = inet6_test_bit(DONTFRAG, sk);
        up->len += ulen;
        err = ip6_append_data(sk, getfrag, msg, ulen, sizeof(struct udphdr),
                              &ipc6, fl6, (struct rt6_info *)dst,
index ed8ebb6..40af243 100644 (file)
@@ -621,7 +621,7 @@ static int l2tp_ip6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
                ipc6.hlimit = ip6_sk_dst_hoplimit(np, &fl6, dst);
 
        if (ipc6.dontfrag < 0)
-               ipc6.dontfrag = np->dontfrag;
+               ipc6.dontfrag = inet6_test_bit(DONTFRAG, sk);
 
        if (msg->msg_flags & MSG_CONFIRM)
                goto do_confirm;