diff options
author | Eric Dumazet <eric.dumazet@gmail.com> | 2012-04-11 19:05:28 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2012-04-13 13:39:37 -0400 |
commit | 447167bf565a474ff0cfb0f41d54936937479e97 (patch) | |
tree | 38b03cb4e23bec19939545575e36f7395c5b156e /net | |
parent | 77577bf93275b485cecb4f358a085949c32e9dcd (diff) |
udp: intoduce udp_encap_needed static_key
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>
Diffstat (limited to 'net')
-rw-r--r-- | net/ipv4/udp.c | 12 | ||||
-rw-r--r-- | net/l2tp/l2tp_core.c | 1 |
2 files changed, 12 insertions, 1 deletions
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index fe141052a1be..ad1e0dd4da48 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c | |||
@@ -107,6 +107,7 @@ | |||
107 | #include <net/checksum.h> | 107 | #include <net/checksum.h> |
108 | #include <net/xfrm.h> | 108 | #include <net/xfrm.h> |
109 | #include <trace/events/udp.h> | 109 | #include <trace/events/udp.h> |
110 | #include <linux/static_key.h> | ||
110 | #include "udp_impl.h" | 111 | #include "udp_impl.h" |
111 | 112 | ||
112 | struct udp_table udp_table __read_mostly; | 113 | struct udp_table udp_table __read_mostly; |
@@ -1379,6 +1380,14 @@ static int __udp_queue_rcv_skb(struct sock *sk, struct sk_buff *skb) | |||
1379 | 1380 | ||
1380 | } | 1381 | } |
1381 | 1382 | ||
1383 | static struct static_key udp_encap_needed __read_mostly; | ||
1384 | void udp_encap_enable(void) | ||
1385 | { | ||
1386 | if (!static_key_enabled(&udp_encap_needed)) | ||
1387 | static_key_slow_inc(&udp_encap_needed); | ||
1388 | } | ||
1389 | EXPORT_SYMBOL(udp_encap_enable); | ||
1390 | |||
1382 | /* returns: | 1391 | /* returns: |
1383 | * -1: error | 1392 | * -1: error |
1384 | * 0: success | 1393 | * 0: success |
@@ -1400,7 +1409,7 @@ int udp_queue_rcv_skb(struct sock *sk, struct sk_buff *skb) | |||
1400 | goto drop; | 1409 | goto drop; |
1401 | nf_reset(skb); | 1410 | nf_reset(skb); |
1402 | 1411 | ||
1403 | if (up->encap_type) { | 1412 | if (static_key_false(&udp_encap_needed) && up->encap_type) { |
1404 | int (*encap_rcv)(struct sock *sk, struct sk_buff *skb); | 1413 | int (*encap_rcv)(struct sock *sk, struct sk_buff *skb); |
1405 | 1414 | ||
1406 | /* | 1415 | /* |
@@ -1760,6 +1769,7 @@ int udp_lib_setsockopt(struct sock *sk, int level, int optname, | |||
1760 | /* FALLTHROUGH */ | 1769 | /* FALLTHROUGH */ |
1761 | case UDP_ENCAP_L2TPINUDP: | 1770 | case UDP_ENCAP_L2TPINUDP: |
1762 | up->encap_type = val; | 1771 | up->encap_type = val; |
1772 | udp_encap_enable(); | ||
1763 | break; | 1773 | break; |
1764 | default: | 1774 | default: |
1765 | err = -ENOPROTOOPT; | 1775 | err = -ENOPROTOOPT; |
diff --git a/net/l2tp/l2tp_core.c b/net/l2tp/l2tp_core.c index 89ff8c67943e..f6732b6c758b 100644 --- a/net/l2tp/l2tp_core.c +++ b/net/l2tp/l2tp_core.c | |||
@@ -1424,6 +1424,7 @@ int l2tp_tunnel_create(struct net *net, int fd, int version, u32 tunnel_id, u32 | |||
1424 | /* Mark socket as an encapsulation socket. See net/ipv4/udp.c */ | 1424 | /* Mark socket as an encapsulation socket. See net/ipv4/udp.c */ |
1425 | udp_sk(sk)->encap_type = UDP_ENCAP_L2TPINUDP; | 1425 | udp_sk(sk)->encap_type = UDP_ENCAP_L2TPINUDP; |
1426 | udp_sk(sk)->encap_rcv = l2tp_udp_encap_recv; | 1426 | udp_sk(sk)->encap_rcv = l2tp_udp_encap_recv; |
1427 | udp_encap_enable(); | ||
1427 | } | 1428 | } |
1428 | 1429 | ||
1429 | sk->sk_user_data = tunnel; | 1430 | sk->sk_user_data = tunnel; |