summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaolo Abeni <pabeni@redhat.com>2018-11-07 06:38:28 -0500
committerDavid S. Miller <davem@davemloft.net>2018-11-07 19:23:04 -0500
commit60fb9567bf30937e6bedfa939d7c8fd4ee6a1b1c (patch)
tree92197dd09800c0f4704f94bfd49ffe2d9a9d664e
parent7e225619e8afc432fb054ef135f10c11cf8cfc85 (diff)
udp: implement complete book-keeping for encap_needed
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>
-rw-r--r--include/linux/udp.h7
-rw-r--r--include/net/udp_tunnel.h6
-rw-r--r--net/ipv4/udp.c19
-rw-r--r--net/ipv6/udp.c14
4 files changed, 34 insertions, 12 deletions
diff --git a/include/linux/udp.h b/include/linux/udp.h
index 320d49d85484..a4dafff407fb 100644
--- a/include/linux/udp.h
+++ b/include/linux/udp.h
@@ -49,7 +49,12 @@ struct udp_sock {
49 unsigned int corkflag; /* Cork is required */ 49 unsigned int corkflag; /* Cork is required */
50 __u8 encap_type; /* Is this an Encapsulation socket? */ 50 __u8 encap_type; /* Is this an Encapsulation socket? */
51 unsigned char no_check6_tx:1,/* Send zero UDP6 checksums on TX? */ 51 unsigned char no_check6_tx:1,/* Send zero UDP6 checksums on TX? */
52 no_check6_rx:1;/* Allow zero UDP6 checksums on RX? */ 52 no_check6_rx:1,/* Allow zero UDP6 checksums on RX? */
53 encap_enabled:1; /* This socket enabled encap
54 * processing; UDP tunnels and
55 * different encapsulation layer set
56 * this
57 */
53 /* 58 /*
54 * Following member retains the information to create a UDP header 59 * Following member retains the information to create a UDP header
55 * when the socket is uncorked. 60 * when the socket is uncorked.
diff --git a/include/net/udp_tunnel.h b/include/net/udp_tunnel.h
index fe680ab6b15a..3fbe56430e3b 100644
--- a/include/net/udp_tunnel.h
+++ b/include/net/udp_tunnel.h
@@ -165,6 +165,12 @@ static inline int udp_tunnel_handle_offloads(struct sk_buff *skb, bool udp_csum)
165 165
166static inline void udp_tunnel_encap_enable(struct socket *sock) 166static inline void udp_tunnel_encap_enable(struct socket *sock)
167{ 167{
168 struct udp_sock *up = udp_sk(sock->sk);
169
170 if (up->encap_enabled)
171 return;
172
173 up->encap_enabled = 1;
168#if IS_ENABLED(CONFIG_IPV6) 174#if IS_ENABLED(CONFIG_IPV6)
169 if (sock->sk->sk_family == PF_INET6) 175 if (sock->sk->sk_family == PF_INET6)
170 ipv6_stub->udpv6_encap_enable(); 176 ipv6_stub->udpv6_encap_enable();
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
index cf73c9194bb6..f81409921e27 100644
--- a/net/ipv4/udp.c
+++ b/net/ipv4/udp.c
@@ -115,6 +115,7 @@
115#include "udp_impl.h" 115#include "udp_impl.h"
116#include <net/sock_reuseport.h> 116#include <net/sock_reuseport.h>
117#include <net/addrconf.h> 117#include <net/addrconf.h>
118#include <net/udp_tunnel.h>
118 119
119struct udp_table udp_table __read_mostly; 120struct udp_table udp_table __read_mostly;
120EXPORT_SYMBOL(udp_table); 121EXPORT_SYMBOL(udp_table);
@@ -2395,11 +2396,15 @@ void udp_destroy_sock(struct sock *sk)
2395 bool slow = lock_sock_fast(sk); 2396 bool slow = lock_sock_fast(sk);
2396 udp_flush_pending_frames(sk); 2397 udp_flush_pending_frames(sk);
2397 unlock_sock_fast(sk, slow); 2398 unlock_sock_fast(sk, slow);
2398 if (static_branch_unlikely(&udp_encap_needed_key) && up->encap_type) { 2399 if (static_branch_unlikely(&udp_encap_needed_key)) {
2399 void (*encap_destroy)(struct sock *sk); 2400 if (up->encap_type) {
2400 encap_destroy = READ_ONCE(up->encap_destroy); 2401 void (*encap_destroy)(struct sock *sk);
2401 if (encap_destroy) 2402 encap_destroy = READ_ONCE(up->encap_destroy);
2402 encap_destroy(sk); 2403 if (encap_destroy)
2404 encap_destroy(sk);
2405 }
2406 if (up->encap_enabled)
2407 static_branch_disable(&udp_encap_needed_key);
2403 } 2408 }
2404} 2409}
2405 2410
@@ -2444,7 +2449,9 @@ int udp_lib_setsockopt(struct sock *sk, int level, int optname,
2444 /* FALLTHROUGH */ 2449 /* FALLTHROUGH */
2445 case UDP_ENCAP_L2TPINUDP: 2450 case UDP_ENCAP_L2TPINUDP:
2446 up->encap_type = val; 2451 up->encap_type = val;
2447 udp_encap_enable(); 2452 lock_sock(sk);
2453 udp_tunnel_encap_enable(sk->sk_socket);
2454 release_sock(sk);
2448 break; 2455 break;
2449 default: 2456 default:
2450 err = -ENOPROTOOPT; 2457 err = -ENOPROTOOPT;
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c
index a25571c12a8a..bdf7e071a63b 100644
--- a/net/ipv6/udp.c
+++ b/net/ipv6/udp.c
@@ -1456,11 +1456,15 @@ void udpv6_destroy_sock(struct sock *sk)
1456 udp_v6_flush_pending_frames(sk); 1456 udp_v6_flush_pending_frames(sk);
1457 release_sock(sk); 1457 release_sock(sk);
1458 1458
1459 if (static_branch_unlikely(&udpv6_encap_needed_key) && up->encap_type) { 1459 if (static_branch_unlikely(&udpv6_encap_needed_key)) {
1460 void (*encap_destroy)(struct sock *sk); 1460 if (up->encap_type) {
1461 encap_destroy = READ_ONCE(up->encap_destroy); 1461 void (*encap_destroy)(struct sock *sk);
1462 if (encap_destroy) 1462 encap_destroy = READ_ONCE(up->encap_destroy);
1463 encap_destroy(sk); 1463 if (encap_destroy)
1464 encap_destroy(sk);
1465 }
1466 if (up->encap_enabled)
1467 static_branch_disable(&udpv6_encap_needed_key);
1464 } 1468 }
1465 1469
1466 inet6_destroy_sock(sk); 1470 inet6_destroy_sock(sk);