Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ipv4: guard IP_MINTTL with a static key

RFC 5082 IP_MINTTL option is rarely used on hosts.

Add a static key to remove from TCP fast path useless code,
and potential cache line miss to fetch inet_sk(sk)->min_ttl

Note that once ip4_min_ttl static key has been enabled,
it stays enabled until next boot.

Signed-off-by: Eric Dumazet <edumazet@google.com>
Acked-by: Soheil Hassas Yeganeh <soheil@google.com>
Signed-off-by: Jakub Kicinski <kuba@kernel.org>

authored by

Eric Dumazet and committed by
Jakub Kicinski
020e71a3 14834c4f

+20 -8
+2
include/net/ip.h
··· 24 24 #include <linux/skbuff.h> 25 25 #include <linux/jhash.h> 26 26 #include <linux/sockptr.h> 27 + #include <linux/static_key.h> 27 28 28 29 #include <net/inet_sock.h> 29 30 #include <net/route.h> ··· 751 750 struct sk_buff *skb, int tlen, int offset); 752 751 int ip_cmsg_send(struct sock *sk, struct msghdr *msg, 753 752 struct ipcm_cookie *ipc, bool allow_ipv6); 753 + DECLARE_STATIC_KEY_FALSE(ip4_min_ttl); 754 754 int ip_setsockopt(struct sock *sk, int level, int optname, sockptr_t optval, 755 755 unsigned int optlen); 756 756 int ip_getsockopt(struct sock *sk, int level, int optname, char __user *optval,
+6
net/ipv4/ip_sockglue.c
··· 886 886 return ip_mc_leave_group(sk, &mreq); 887 887 } 888 888 889 + DEFINE_STATIC_KEY_FALSE(ip4_min_ttl); 890 + 889 891 static int do_ip_setsockopt(struct sock *sk, int level, int optname, 890 892 sockptr_t optval, unsigned int optlen) 891 893 { ··· 1354 1352 goto e_inval; 1355 1353 if (val < 0 || val > 255) 1356 1354 goto e_inval; 1355 + 1356 + if (val) 1357 + static_branch_enable(&ip4_min_ttl); 1358 + 1357 1359 /* tcp_v4_err() and tcp_v4_rcv() might read min_ttl 1358 1360 * while we are changint it. 1359 1361 */
+12 -8
net/ipv4/tcp_ipv4.c
··· 508 508 if (sk->sk_state == TCP_CLOSE) 509 509 goto out; 510 510 511 - /* min_ttl can be changed concurrently from do_ip_setsockopt() */ 512 - if (unlikely(iph->ttl < READ_ONCE(inet_sk(sk)->min_ttl))) { 513 - __NET_INC_STATS(net, LINUX_MIB_TCPMINTTLDROP); 514 - goto out; 511 + if (static_branch_unlikely(&ip4_min_ttl)) { 512 + /* min_ttl can be changed concurrently from do_ip_setsockopt() */ 513 + if (unlikely(iph->ttl < READ_ONCE(inet_sk(sk)->min_ttl))) { 514 + __NET_INC_STATS(net, LINUX_MIB_TCPMINTTLDROP); 515 + goto out; 516 + } 515 517 } 516 518 517 519 tp = tcp_sk(sk); ··· 2072 2070 } 2073 2071 } 2074 2072 2075 - /* min_ttl can be changed concurrently from do_ip_setsockopt() */ 2076 - if (unlikely(iph->ttl < READ_ONCE(inet_sk(sk)->min_ttl))) { 2077 - __NET_INC_STATS(net, LINUX_MIB_TCPMINTTLDROP); 2078 - goto discard_and_relse; 2073 + if (static_branch_unlikely(&ip4_min_ttl)) { 2074 + /* min_ttl can be changed concurrently from do_ip_setsockopt() */ 2075 + if (unlikely(iph->ttl < READ_ONCE(inet_sk(sk)->min_ttl))) { 2076 + __NET_INC_STATS(net, LINUX_MIB_TCPMINTTLDROP); 2077 + goto discard_and_relse; 2078 + } 2079 2079 } 2080 2080 2081 2081 if (!xfrm4_policy_check(sk, XFRM_POLICY_IN, skb))