Re: [PATCH net-next 01/10] udp: implement complete book-keeping for encap_needed

2018-11-13 Thread Eric Dumazet



On 11/07/2018 03:38 AM, Paolo Abeni wrote:
> 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 
> ---
>  include/linux/udp.h  |  7 ++-
>  include/net/udp_tunnel.h |  6 ++
>  net/ipv4/udp.c   | 19 +--
>  net/ipv6/udp.c   | 14 +-
>  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 {
>   unsigned int corkflag;  /* Cork is required */
>   __u8 encap_type;/* Is this an Encapsulation socket? */
>   unsigned charno_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.
> 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)
>  
>  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();
> diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
> index 1976fddb9e00..0ed715a72249 100644
> --- a/net/ipv4/udp.c
> +++ b/net/ipv4/udp.c
> @@ -115,6 +115,7 @@
>  #include "udp_impl.h"
>  #include 
>  #include 
> +#include 
>  
>  struct udp_table udp_table __read_mostly;
>  EXPORT_SYMBOL(udp_table);
> @@ -2398,11 +2399,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(_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(_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(_encap_needed_key);
>   }
>  }
>  
> @@ -2447,7 +2452,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;
> diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c
> index d2d97d07ef27..fc0ce6c59ebb 100644
> --- a/net/ipv6/udp.c
> +++ b/net/ipv6/udp.c
> @@ -1458,11 +1458,15 @@ void udpv6_destroy_sock(struct sock *sk)
>   udp_v6_flush_pending_frames(sk);
>   release_sock(sk);
>  
> - if (static_branch_unlikely(_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(_encap_needed_key)) {
> + if (up->encap_type) {
> + void (*encap_destroy)(struct sock *sk);
> +  

[PATCH net-next 01/10] udp: implement complete book-keeping for encap_needed

2018-11-07 Thread Paolo Abeni
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 
---
 include/linux/udp.h  |  7 ++-
 include/net/udp_tunnel.h |  6 ++
 net/ipv4/udp.c   | 19 +--
 net/ipv6/udp.c   | 14 +-
 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 {
unsigned int corkflag;  /* Cork is required */
__u8 encap_type;/* Is this an Encapsulation socket? */
unsigned charno_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.
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)
 
 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();
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
index 1976fddb9e00..0ed715a72249 100644
--- a/net/ipv4/udp.c
+++ b/net/ipv4/udp.c
@@ -115,6 +115,7 @@
 #include "udp_impl.h"
 #include 
 #include 
+#include 
 
 struct udp_table udp_table __read_mostly;
 EXPORT_SYMBOL(udp_table);
@@ -2398,11 +2399,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(_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(_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(_encap_needed_key);
}
 }
 
@@ -2447,7 +2452,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;
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c
index d2d97d07ef27..fc0ce6c59ebb 100644
--- a/net/ipv6/udp.c
+++ b/net/ipv6/udp.c
@@ -1458,11 +1458,15 @@ void udpv6_destroy_sock(struct sock *sk)
udp_v6_flush_pending_frames(sk);
release_sock(sk);
 
-   if (static_branch_unlikely(_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(_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);
+