mirror of https://gitee.com/openkylin/linux.git
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>
This commit is contained in:
parent
77577bf932
commit
447167bf56
|
@ -267,4 +267,5 @@ extern void udp_init(void);
|
||||||
extern int udp4_ufo_send_check(struct sk_buff *skb);
|
extern int udp4_ufo_send_check(struct sk_buff *skb);
|
||||||
extern struct sk_buff *udp4_ufo_fragment(struct sk_buff *skb,
|
extern struct sk_buff *udp4_ufo_fragment(struct sk_buff *skb,
|
||||||
netdev_features_t features);
|
netdev_features_t features);
|
||||||
|
extern void udp_encap_enable(void);
|
||||||
#endif /* _UDP_H */
|
#endif /* _UDP_H */
|
||||||
|
|
|
@ -107,6 +107,7 @@
|
||||||
#include <net/checksum.h>
|
#include <net/checksum.h>
|
||||||
#include <net/xfrm.h>
|
#include <net/xfrm.h>
|
||||||
#include <trace/events/udp.h>
|
#include <trace/events/udp.h>
|
||||||
|
#include <linux/static_key.h>
|
||||||
#include "udp_impl.h"
|
#include "udp_impl.h"
|
||||||
|
|
||||||
struct udp_table udp_table __read_mostly;
|
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:
|
/* returns:
|
||||||
* -1: error
|
* -1: error
|
||||||
* 0: success
|
* 0: success
|
||||||
|
@ -1400,7 +1409,7 @@ int udp_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
|
||||||
goto drop;
|
goto drop;
|
||||||
nf_reset(skb);
|
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);
|
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 */
|
/* FALLTHROUGH */
|
||||||
case UDP_ENCAP_L2TPINUDP:
|
case UDP_ENCAP_L2TPINUDP:
|
||||||
up->encap_type = val;
|
up->encap_type = val;
|
||||||
|
udp_encap_enable();
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
err = -ENOPROTOOPT;
|
err = -ENOPROTOOPT;
|
||||||
|
|
|
@ -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 */
|
/* Mark socket as an encapsulation socket. See net/ipv4/udp.c */
|
||||||
udp_sk(sk)->encap_type = UDP_ENCAP_L2TPINUDP;
|
udp_sk(sk)->encap_type = UDP_ENCAP_L2TPINUDP;
|
||||||
udp_sk(sk)->encap_rcv = l2tp_udp_encap_recv;
|
udp_sk(sk)->encap_rcv = l2tp_udp_encap_recv;
|
||||||
|
udp_encap_enable();
|
||||||
}
|
}
|
||||||
|
|
||||||
sk->sk_user_data = tunnel;
|
sk->sk_user_data = tunnel;
|
||||||
|
|
Loading…
Reference in New Issue