udp: intoduce udp_encap_needed static_key
authorEric Dumazet <eric.dumazet@gmail.com>
Wed, 11 Apr 2012 23:05:28 +0000 (23:05 +0000)
committerDavid S. Miller <davem@davemloft.net>
Fri, 13 Apr 2012 17:39:37 +0000 (13:39 -0400)
Most machines dont use UDP encapsulation (L2TP)

Adds a static_key so that udp_queue_rcv_skb() doesnt have to perform a
test if L2TP never setup the encap_rcv on a socket.

Idea of this patch came after Simon Horman proposal to add a hook on TCP
as well.

If static_key is not yet enabled, the fast path does a single JMP .

When static_key is enabled, JMP destination is patched to reach the real
encap_type/encap_rcv logic, possibly adding cache misses.

Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com>
Cc: Simon Horman <horms@verge.net.au>
Cc: dev@openvswitch.org
Signed-off-by: David S. Miller <davem@davemloft.net>
include/net/udp.h
net/ipv4/udp.c
net/l2tp/l2tp_core.c

index 5d606d9da9e56b30927e29228046742b23ed8d8b..9671f5f1df9cb438680f0ce95597a3268b439bdc 100644 (file)
@@ -267,4 +267,5 @@ extern void udp_init(void);
 extern int udp4_ufo_send_check(struct sk_buff *skb);
 extern struct sk_buff *udp4_ufo_fragment(struct sk_buff *skb,
        netdev_features_t features);
+extern void udp_encap_enable(void);
 #endif /* _UDP_H */
index fe141052a1beaf5c85376cfed0740c348c019dce..ad1e0dd4da4843a29173d83e704f84cc10b4d54a 100644 (file)
 #include <net/checksum.h>
 #include <net/xfrm.h>
 #include <trace/events/udp.h>
+#include <linux/static_key.h>
 #include "udp_impl.h"
 
 struct udp_table udp_table __read_mostly;
@@ -1379,6 +1380,14 @@ static int __udp_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
 
 }
 
+static struct static_key udp_encap_needed __read_mostly;
+void udp_encap_enable(void)
+{
+       if (!static_key_enabled(&udp_encap_needed))
+               static_key_slow_inc(&udp_encap_needed);
+}
+EXPORT_SYMBOL(udp_encap_enable);
+
 /* returns:
  *  -1: error
  *   0: success
@@ -1400,7 +1409,7 @@ int udp_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
                goto drop;
        nf_reset(skb);
 
-       if (up->encap_type) {
+       if (static_key_false(&udp_encap_needed) && up->encap_type) {
                int (*encap_rcv)(struct sock *sk, struct sk_buff *skb);
 
                /*
@@ -1760,6 +1769,7 @@ int udp_lib_setsockopt(struct sock *sk, int level, int optname,
                        /* FALLTHROUGH */
                case UDP_ENCAP_L2TPINUDP:
                        up->encap_type = val;
+                       udp_encap_enable();
                        break;
                default:
                        err = -ENOPROTOOPT;
index 89ff8c67943e8af26efe1bac80b306e297921ebd..f6732b6c758b6764d54af00aa7b929b6c9d5c043 100644 (file)
@@ -1424,6 +1424,7 @@ int l2tp_tunnel_create(struct net *net, int fd, int version, u32 tunnel_id, u32
                /* Mark socket as an encapsulation socket. See net/ipv4/udp.c */
                udp_sk(sk)->encap_type = UDP_ENCAP_L2TPINUDP;
                udp_sk(sk)->encap_rcv = l2tp_udp_encap_recv;
+               udp_encap_enable();
        }
 
        sk->sk_user_data = tunnel;