Most linux hosts never setup TCP MD5 keys. We can avoid a cache line miss (accessing tp->md5ig_info) on RX and TX using a jump label.
Signed-off-by: Eric Dumazet <eduma...@google.com> --- include/net/tcp.h | 18 +++++++++++++++--- net/ipv4/tcp.c | 5 ++++- net/ipv4/tcp_ipv4.c | 11 +++++++---- net/ipv4/tcp_output.c | 6 ++++-- 4 files changed, 30 insertions(+), 10 deletions(-) diff --git a/include/net/tcp.h b/include/net/tcp.h index 63e37dd1c274cc396e41ea9612cf67a5b7c89776..7764349842c1816f12becd752b2ba76269b82b9e 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -1555,9 +1555,21 @@ struct tcp_md5sig_key *tcp_v4_md5_lookup(const struct sock *sk, const struct sock *addr_sk); #ifdef CONFIG_TCP_MD5SIG -struct tcp_md5sig_key *tcp_md5_do_lookup(const struct sock *sk, - const union tcp_md5_addr *addr, - int family); +#include <linux/jump_label.h> +extern struct static_key tcp_md5_needed; +struct tcp_md5sig_key *__tcp_md5_do_lookup(const struct sock *sk, + const union tcp_md5_addr *addr, + int family); +static inline struct tcp_md5sig_key * +tcp_md5_do_lookup(const struct sock *sk, + const union tcp_md5_addr *addr, + int family) +{ + if (!static_key_false(&tcp_md5_needed)) + return NULL; + return __tcp_md5_do_lookup(sk, addr, family); +} + #define tcp_twsk_md5_key(twsk) ((twsk)->tw_md5_key) #else static inline struct tcp_md5sig_key *tcp_md5_do_lookup(const struct sock *sk, diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 252048776dbb0727737eb60bde6d606dbf057488..215e4d3b361657c434ff019ebe638437b65dd351 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -3656,8 +3656,11 @@ bool tcp_alloc_md5sig_pool(void) if (unlikely(!tcp_md5sig_pool_populated)) { mutex_lock(&tcp_md5sig_mutex); - if (!tcp_md5sig_pool_populated) + if (!tcp_md5sig_pool_populated) { __tcp_alloc_md5sig_pool(); + if (tcp_md5sig_pool_populated) + static_key_slow_inc(&tcp_md5_needed); + } mutex_unlock(&tcp_md5sig_mutex); } diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 795605a2327504b8a025405826e7e0ca8dc8501d..c7d872babd724dbd7e81a89e6a9de5e871198ad9 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -970,10 +970,13 @@ static void tcp_v4_reqsk_destructor(struct request_sock *req) * We need to maintain these in the sk structure. */ +struct static_key tcp_md5_needed __read_mostly; +EXPORT_SYMBOL(tcp_md5_needed); + /* Find the Key structure for an address. */ -struct tcp_md5sig_key *tcp_md5_do_lookup(const struct sock *sk, - const union tcp_md5_addr *addr, - int family) +struct tcp_md5sig_key *__tcp_md5_do_lookup(const struct sock *sk, + const union tcp_md5_addr *addr, + int family) { const struct tcp_sock *tp = tcp_sk(sk); struct tcp_md5sig_key *key; @@ -1011,7 +1014,7 @@ struct tcp_md5sig_key *tcp_md5_do_lookup(const struct sock *sk, } return best_match; } -EXPORT_SYMBOL(tcp_md5_do_lookup); +EXPORT_SYMBOL(__tcp_md5_do_lookup); static struct tcp_md5sig_key *tcp_md5_do_lookup_exact(const struct sock *sk, const union tcp_md5_addr *addr, diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index c5dc4c4fdaddd553e6734d51bd9e3698f6d68e65..3ae4a277991a3473f61b1f73acd5ee355cf6a5df 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -596,7 +596,8 @@ static unsigned int tcp_syn_options(struct sock *sk, struct sk_buff *skb, *md5 = NULL; #ifdef CONFIG_TCP_MD5SIG - if (unlikely(rcu_access_pointer(tp->md5sig_info))) { + if (static_key_false(&tcp_md5_needed) && + rcu_access_pointer(tp->md5sig_info)) { *md5 = tp->af_specific->md5_lookup(sk, sk); if (*md5) { opts->options |= OPTION_MD5; @@ -732,7 +733,8 @@ static unsigned int tcp_established_options(struct sock *sk, struct sk_buff *skb *md5 = NULL; #ifdef CONFIG_TCP_MD5SIG - if (unlikely(rcu_access_pointer(tp->md5sig_info))) { + if (static_key_false(&tcp_md5_needed) && + rcu_access_pointer(tp->md5sig_info)) { *md5 = tp->af_specific->md5_lookup(sk, sk); if (*md5) { opts->options |= OPTION_MD5; -- 2.20.0.rc0.387.gc7a69e6b6c-goog