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);
> +