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 e3be5dc21b7d27080b398f1425bf11145896a4f3..57d563f1d4b1707264f0d79406c4c139cc0fa525 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 f1af64a4067310258a3bc45b84ad3fd093bddbab..ac75324e9e1eafe68cee7b0581e472cbb4f49aa3 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 4b6cbec059e25ea2e810b47eeace56b041e3efef..5a1f2993680dacc97013a000d487ff781b664c6b 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 363c7d5105542ec7f43f91e5071b877314584bc5..98d7aa78addaab129f7ce060b10b7652fd0acba1 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 93a594a901d12befb754e7035f56726273eead92..8fb4a791881a48d5efcebc990c8829d8f77fe94f 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 47aa42f93ccda8b49ed6ecd7a7a07703ae147928..8851fe5d45a0781c8b78c995c2c4c6c81e10cd52 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 d5d428a695f728d96a7d075d86f806cc3f926e0a..33dd4dd872e6bca2ee18a634283640007adcc692 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 5831aaa53d75eae7b764d54ab52da65db4030d73..4444b61eb23bbf483068d2b119a7559e49ba3880 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 42fcec3ecf5e171a5ebe724b8c971d90885abe41..cc9673c1809fb238f6d9ab6915116cf0dd6eb593 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 f60ba429543526b7ade2666c36dd51828ffe54a9..e4301500741a0ea79228d90860ee7f942b73d543 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 ed8ebb6f59097ac18bb284d1c48f9e801e9a92c2..40af2431e73aad74ab64e97db8a5ee79dda0879d 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;