]> git.proxmox.com Git - mirror_ubuntu-disco-kernel.git/commitdiff
udp: implement complete book-keeping for encap_needed
authorPaolo Abeni <pabeni@redhat.com>
Wed, 7 Nov 2018 11:38:28 +0000 (12:38 +0100)
committerDavid S. Miller <davem@davemloft.net>
Thu, 8 Nov 2018 00:23:04 +0000 (16:23 -0800)
The *encap_needed static keys are enabled by UDP tunnels
and several UDP encapsulations type, but they are never
turned off. This can cause unneeded overall performance
degradation for systems where such features are used
transiently.

This patch introduces complete book-keeping for such keys,
decreasing the usage at socket destruction time, if needed,
and avoiding that the same socket could increase the key
usage multiple times.

rfc v3 -> v1:
 - add socket lock around udp_tunnel_encap_enable()

rfc v2 -> rfc v3:
 - use udp_tunnel_encap_enable() in setsockopt()

Signed-off-by: Paolo Abeni <pabeni@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
include/linux/udp.h
include/net/udp_tunnel.h
net/ipv4/udp.c
net/ipv6/udp.c

index 320d49d85484d4ac2d0fdbbe365ad339bf949c0b..a4dafff407fb8bd2fec7cd619cdf5dcf8245b997 100644 (file)
@@ -49,7 +49,12 @@ struct udp_sock {
        unsigned int     corkflag;      /* Cork is required */
        __u8             encap_type;    /* Is this an Encapsulation socket? */
        unsigned char    no_check6_tx:1,/* Send zero UDP6 checksums on TX? */
-                        no_check6_rx:1;/* Allow zero UDP6 checksums on RX? */
+                        no_check6_rx:1,/* Allow zero UDP6 checksums on RX? */
+                        encap_enabled:1; /* This socket enabled encap
+                                          * processing; UDP tunnels and
+                                          * different encapsulation layer set
+                                          * this
+                                          */
        /*
         * Following member retains the information to create a UDP header
         * when the socket is uncorked.
index fe680ab6b15a18aba378d161d57461176b75d8cb..3fbe56430e3b381749fe97f006e2b66332e18447 100644 (file)
@@ -165,6 +165,12 @@ static inline int udp_tunnel_handle_offloads(struct sk_buff *skb, bool udp_csum)
 
 static inline void udp_tunnel_encap_enable(struct socket *sock)
 {
+       struct udp_sock *up = udp_sk(sock->sk);
+
+       if (up->encap_enabled)
+               return;
+
+       up->encap_enabled = 1;
 #if IS_ENABLED(CONFIG_IPV6)
        if (sock->sk->sk_family == PF_INET6)
                ipv6_stub->udpv6_encap_enable();
index cf73c9194bb6947632c4cb220ca472d821dc89ed..f81409921e272fec6f582a31c548fa27eeb417b3 100644 (file)
 #include "udp_impl.h"
 #include <net/sock_reuseport.h>
 #include <net/addrconf.h>
+#include <net/udp_tunnel.h>
 
 struct udp_table udp_table __read_mostly;
 EXPORT_SYMBOL(udp_table);
@@ -2395,11 +2396,15 @@ void udp_destroy_sock(struct sock *sk)
        bool slow = lock_sock_fast(sk);
        udp_flush_pending_frames(sk);
        unlock_sock_fast(sk, slow);
-       if (static_branch_unlikely(&udp_encap_needed_key) && up->encap_type) {
-               void (*encap_destroy)(struct sock *sk);
-               encap_destroy = READ_ONCE(up->encap_destroy);
-               if (encap_destroy)
-                       encap_destroy(sk);
+       if (static_branch_unlikely(&udp_encap_needed_key)) {
+               if (up->encap_type) {
+                       void (*encap_destroy)(struct sock *sk);
+                       encap_destroy = READ_ONCE(up->encap_destroy);
+                       if (encap_destroy)
+                               encap_destroy(sk);
+               }
+               if (up->encap_enabled)
+                       static_branch_disable(&udp_encap_needed_key);
        }
 }
 
@@ -2444,7 +2449,9 @@ int udp_lib_setsockopt(struct sock *sk, int level, int optname,
                        /* FALLTHROUGH */
                case UDP_ENCAP_L2TPINUDP:
                        up->encap_type = val;
-                       udp_encap_enable();
+                       lock_sock(sk);
+                       udp_tunnel_encap_enable(sk->sk_socket);
+                       release_sock(sk);
                        break;
                default:
                        err = -ENOPROTOOPT;
index a25571c12a8a2c5f745ce6712de26fcb1906a12c..bdf7e071a63b57cdd8a6b6ac1b154480be2f66a8 100644 (file)
@@ -1456,11 +1456,15 @@ void udpv6_destroy_sock(struct sock *sk)
        udp_v6_flush_pending_frames(sk);
        release_sock(sk);
 
-       if (static_branch_unlikely(&udpv6_encap_needed_key) && up->encap_type) {
-               void (*encap_destroy)(struct sock *sk);
-               encap_destroy = READ_ONCE(up->encap_destroy);
-               if (encap_destroy)
-                       encap_destroy(sk);
+       if (static_branch_unlikely(&udpv6_encap_needed_key)) {
+               if (up->encap_type) {
+                       void (*encap_destroy)(struct sock *sk);
+                       encap_destroy = READ_ONCE(up->encap_destroy);
+                       if (encap_destroy)
+                               encap_destroy(sk);
+               }
+               if (up->encap_enabled)
+                       static_branch_disable(&udpv6_encap_needed_key);
        }
 
        inet6_destroy_sock(sk);