udp: lockless UDP_ENCAP_L2TPINUDP / UDP_GRO
authorEric Dumazet <edumazet@google.com>
Tue, 12 Sep 2023 09:17:27 +0000 (09:17 +0000)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 20 Nov 2023 10:58:56 +0000 (11:58 +0100)
[ Upstream commit ac9a7f4ce5dda1472e8f44096f33066c6ec1a3b4 ]

Move udp->encap_enabled to udp->udp_flags.

Add udp_test_and_set_bit() helper to allow lockless
udp_tunnel_encap_enable() implementation.

Signed-off-by: Eric Dumazet <edumazet@google.com>
Reviewed-by: Willem de Bruijn <willemb@google.com>
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
Stable-dep-of: 70a36f571362 ("udp: annotate data-races around udp->encap_type")
Signed-off-by: Sasha Levin <sashal@kernel.org>
include/linux/udp.h
include/net/udp_tunnel.h
net/ipv4/udp.c
net/ipv4/udp_tunnel_core.c
net/ipv6/udp.c

index bb2b87a..0cf8327 100644 (file)
@@ -39,6 +39,7 @@ enum {
        UDP_FLAGS_GRO_ENABLED,  /* Request GRO aggregation */
        UDP_FLAGS_ACCEPT_FRAGLIST,
        UDP_FLAGS_ACCEPT_L4,
+       UDP_FLAGS_ENCAP_ENABLED, /* This socket enabled encap */
 };
 
 struct udp_sock {
@@ -52,11 +53,7 @@ struct udp_sock {
 
        int              pending;       /* Any pending frames ? */
        __u8             encap_type;    /* Is this an Encapsulation socket? */
-       unsigned char    encap_enabled:1; /* This socket enabled encap
-                                          * processing; UDP tunnels and
-                                          * different encapsulation layer set
-                                          * this
-                                          */
+
 /* indicator bits used by pcflag: */
 #define UDPLITE_BIT      0x1           /* set by udplite proto init function */
 #define UDPLITE_SEND_CC  0x2           /* set via udplite setsockopt         */
@@ -104,6 +101,8 @@ struct udp_sock {
        test_bit(UDP_FLAGS_##nr, &udp_sk(sk)->udp_flags)
 #define udp_set_bit(nr, sk)                    \
        set_bit(UDP_FLAGS_##nr, &udp_sk(sk)->udp_flags)
+#define udp_test_and_set_bit(nr, sk)           \
+       test_and_set_bit(UDP_FLAGS_##nr, &udp_sk(sk)->udp_flags)
 #define udp_clear_bit(nr, sk)                  \
        clear_bit(UDP_FLAGS_##nr, &udp_sk(sk)->udp_flags)
 #define udp_assign_bit(nr, sk, val)            \
index 0ca9b7a..29251c3 100644 (file)
@@ -174,16 +174,13 @@ static inline int udp_tunnel_handle_offloads(struct sk_buff *skb, bool udp_csum)
 }
 #endif
 
-static inline void udp_tunnel_encap_enable(struct socket *sock)
+static inline void udp_tunnel_encap_enable(struct sock *sk)
 {
-       struct udp_sock *up = udp_sk(sock->sk);
-
-       if (up->encap_enabled)
+       if (udp_test_and_set_bit(ENCAP_ENABLED, sk))
                return;
 
-       up->encap_enabled = 1;
 #if IS_ENABLED(CONFIG_IPV6)
-       if (sock->sk->sk_family == PF_INET6)
+       if (READ_ONCE(sk->sk_family) == PF_INET6)
                ipv6_stub->udpv6_encap_enable();
 #endif
        udp_encap_enable();
index 75ba86a..637a4fa 100644 (file)
@@ -2618,7 +2618,7 @@ void udp_destroy_sock(struct sock *sk)
                        if (encap_destroy)
                                encap_destroy(sk);
                }
-               if (up->encap_enabled)
+               if (udp_test_bit(ENCAP_ENABLED, sk))
                        static_branch_dec(&udp_encap_needed_key);
        }
 }
@@ -2685,9 +2685,7 @@ int udp_lib_setsockopt(struct sock *sk, int level, int optname,
                        fallthrough;
                case UDP_ENCAP_L2TPINUDP:
                        up->encap_type = val;
-                       lock_sock(sk);
-                       udp_tunnel_encap_enable(sk->sk_socket);
-                       release_sock(sk);
+                       udp_tunnel_encap_enable(sk);
                        break;
                default:
                        err = -ENOPROTOOPT;
@@ -2710,14 +2708,12 @@ int udp_lib_setsockopt(struct sock *sk, int level, int optname,
                break;
 
        case UDP_GRO:
-               lock_sock(sk);
 
                /* when enabling GRO, accept the related GSO packet type */
                if (valbool)
-                       udp_tunnel_encap_enable(sk->sk_socket);
+                       udp_tunnel_encap_enable(sk);
                udp_assign_bit(GRO_ENABLED, sk, valbool);
                udp_assign_bit(ACCEPT_L4, sk, valbool);
-               release_sock(sk);
                break;
 
        /*
index 9b18f37..1e7e4ae 100644 (file)
@@ -78,7 +78,7 @@ void setup_udp_tunnel_sock(struct net *net, struct socket *sock,
        udp_sk(sk)->gro_receive = cfg->gro_receive;
        udp_sk(sk)->gro_complete = cfg->gro_complete;
 
-       udp_tunnel_encap_enable(sock);
+       udp_tunnel_encap_enable(sk);
 }
 EXPORT_SYMBOL_GPL(setup_udp_tunnel_sock);
 
index 2c32818..9068887 100644 (file)
@@ -1670,7 +1670,7 @@ void udpv6_destroy_sock(struct sock *sk)
                        if (encap_destroy)
                                encap_destroy(sk);
                }
-               if (up->encap_enabled) {
+               if (udp_test_bit(ENCAP_ENABLED, sk)) {
                        static_branch_dec(&udpv6_encap_needed_key);
                        udp_encap_disable();
                }