From: Eric Dumazet <hidden> Date: 2021-10-21 16:23:01
From: Eric Dumazet <edumazet@google.com>
This series aims to reduce cache line misses in RX path.
I am still working on better cache locality in tcp_sock but
this will wait few more weeks.
Eric Dumazet (9):
tcp: move inet->rx_dst_ifindex to sk->sk_rx_dst_ifindex
ipv6: move inet6_sk(sk)->rx_dst_cookie to sk->sk_rx_dst_cookie
net: avoid dirtying sk->sk_napi_id
net: avoid dirtying sk->sk_rx_queue_mapping
ipv6: annotate data races around np->min_hopcount
ipv6: guard IPV6_MINHOPCOUNT with a static key
ipv4: annotate data races arount inet->min_ttl
ipv4: guard IP_MINTTL with a static key
ipv6/tcp: small drop monitor changes
include/linux/ipv6.h | 1 -
include/net/busy_poll.h | 3 ++-
include/net/inet_sock.h | 3 +--
include/net/ip.h | 2 ++
include/net/ipv6.h | 1 +
include/net/sock.h | 11 +++++++----
net/ipv4/ip_sockglue.c | 11 ++++++++++-
net/ipv4/tcp_ipv4.c | 25 ++++++++++++++++---------
net/ipv6/ipv6_sockglue.c | 11 ++++++++++-
net/ipv6/tcp_ipv6.c | 35 +++++++++++++++++++++--------------
net/ipv6/udp.c | 4 ++--
11 files changed, 72 insertions(+), 35 deletions(-)
--
2.33.0.1079.g6e70778dc9-goog
From: Eric Dumazet <hidden> Date: 2021-10-21 16:23:04
From: Eric Dumazet <edumazet@google.com>
For non TCQ_F_NOLOCK qdisc, qdisc_run_begin() tries to set
__QDISC_STATE_RUNNING and should return true if the bit was not set.
test_and_set_bit() returns old bit value, therefore we need to invert.
Fixes: 29cbcd858283 ("net: sched: Remove Qdisc::running sequence counter")
Signed-off-by: Eric Dumazet <edumazet@google.com>
Cc: Ahmed S. Darwish <redacted>
Cc: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
---
include/net/sch_generic.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
From: Eric Dumazet <hidden> Date: 2021-10-21 16:23:15
From: Eric Dumazet <edumazet@google.com>
Increase cache locality by moving rx_dst_ifindex next to sk->sk_rx_dst
This is part of an effort to reduce cache line misses in TCP fast path.
This removes one cache line miss in early demux.
Signed-off-by: Eric Dumazet <edumazet@google.com>
---
include/net/inet_sock.h | 3 +--
include/net/sock.h | 3 +++
net/ipv4/tcp_ipv4.c | 6 +++---
net/ipv6/tcp_ipv6.c | 6 +++---
4 files changed, 10 insertions(+), 8 deletions(-)
From: Eric Dumazet <hidden> Date: 2021-10-21 16:23:15
From: Eric Dumazet <edumazet@google.com>
Increase cache locality by moving rx_dst_coookie next to sk->sk_rx_dst
This removes one or two cache line misses in IPv6 early demux (TCP/UDP)
Signed-off-by: Eric Dumazet <edumazet@google.com>
---
include/linux/ipv6.h | 1 -
include/net/sock.h | 2 ++
net/ipv6/tcp_ipv6.c | 6 +++---
net/ipv6/udp.c | 4 ++--
4 files changed, 7 insertions(+), 6 deletions(-)
From: Eric Dumazet <hidden> Date: 2021-10-21 16:23:16
From: Eric Dumazet <edumazet@google.com>
sk_napi_id is located in a cache line that can be kept read mostly.
Signed-off-by: Eric Dumazet <edumazet@google.com>
---
include/net/busy_poll.h | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
From: Eric Dumazet <hidden> Date: 2021-10-21 16:23:17
From: Eric Dumazet <edumazet@google.com>
__QDISC_STATE_RUNNING is only set/cleared from contexts owning qdisc lock.
Thus we can use less expensive bit operations, as we were doing
before commit f9eb8aea2a1e ("net_sched: transform qdisc running bit into a seqcount")
Fixes: 29cbcd858283 ("net: sched: Remove Qdisc::running sequence counter")
Signed-off-by: Eric Dumazet <edumazet@google.com>
Cc: Ahmed S. Darwish <redacted>
Cc: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
---
include/net/sch_generic.h | 12 ++++++++----
1 file changed, 8 insertions(+), 4 deletions(-)
@@ -38,10 +38,13 @@ enum qdisc_state_t {__QDISC_STATE_DEACTIVATED,__QDISC_STATE_MISSED,__QDISC_STATE_DRAINING,+};++enumqdisc_state2_t{/* Only for !TCQ_F_NOLOCK qdisc. Never access it directly.*Useqdisc_run_begin/end()orqdisc_is_running()instead.*/-__QDISC_STATE_RUNNING,+__QDISC_STATE2_RUNNING,};#define QDISC_STATE_MISSED BIT(__QDISC_STATE_MISSED)
@@ -114,6 +117,7 @@ struct Qdisc {structgnet_stats_basic_syncbstats;structgnet_stats_queueqstats;unsignedlongstate;+unsignedlongstate2;/* must be written under qdisc spinlock */structQdisc*next_sched;structsk_buff_headskb_bad_txq;
From: Eric Dumazet <hidden> Date: 2021-10-21 16:23:18
From: Eric Dumazet <edumazet@google.com>
sk_rx_queue_mapping is located in a cache line that should be kept read mostly.
Signed-off-by: Eric Dumazet <edumazet@google.com>
---
include/net/sock.h | 6 ++----
1 file changed, 2 insertions(+), 4 deletions(-)
@@ -950,7 +950,10 @@ static int do_ipv6_setsockopt(struct sock *sk, int level, int optname,gotoe_inval;if(val<0||val>255)gotoe_inval;-np->min_hopcount=val;+/* tcp_v6_err() and tcp_v6_rcv() might read min_hopcount+*whilewearechangingit.+*/+WRITE_ONCE(np->min_hopcount,val);retv=0;break;caseIPV6_DONTFRAG:
@@ -414,7 +414,8 @@ static int tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,if(sk->sk_state==TCP_CLOSE)gotoout;-if(ipv6_hdr(skb)->hop_limit<tcp_inet6_sk(sk)->min_hopcount){+/* min_hopcount can be changed concurrently from do_ipv6_setsockopt() */+if(ipv6_hdr(skb)->hop_limit<READ_ONCE(tcp_inet6_sk(sk)->min_hopcount)){__NET_INC_STATS(net,LINUX_MIB_TCPMINTTLDROP);gotoout;}
@@ -1723,7 +1724,8 @@ INDIRECT_CALLABLE_SCOPE int tcp_v6_rcv(struct sk_buff *skb)return0;}}-if(hdr->hop_limit<tcp_inet6_sk(sk)->min_hopcount){+/* min_hopcount can be changed concurrently from do_ipv6_setsockopt() */+if(hdr->hop_limit<READ_ONCE(tcp_inet6_sk(sk)->min_hopcount)){__NET_INC_STATS(net,LINUX_MIB_TCPMINTTLDROP);gotodiscard_and_relse;}
From: Eric Dumazet <hidden> Date: 2021-10-21 16:23:19
From: Eric Dumazet <edumazet@google.com>
RFC 5082 IPV6_MINHOPCOUNT is rarely used on hosts.
Add a static key to remove from TCP fast path useless code,
and potential cache line miss to fetch tcp_inet6_sk(sk)->min_hopcount
Note that once ip6_min_hopcount static key has been enabled,
it stays enabled until next boot.
Signed-off-by: Eric Dumazet <edumazet@google.com>
---
include/net/ipv6.h | 1 +
net/ipv6/ipv6_sockglue.c | 6 ++++++
net/ipv6/tcp_ipv6.c | 21 +++++++++++++--------
3 files changed, 20 insertions(+), 8 deletions(-)
@@ -950,6 +952,10 @@ static int do_ipv6_setsockopt(struct sock *sk, int level, int optname,gotoe_inval;if(val<0||val>255)gotoe_inval;++if(val)+static_branch_enable(&ip6_min_hopcount);+/* tcp_v6_err() and tcp_v6_rcv() might read min_hopcount*whilewearechangingit.*/
@@ -414,10 +414,12 @@ static int tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,if(sk->sk_state==TCP_CLOSE)gotoout;-/* min_hopcount can be changed concurrently from do_ipv6_setsockopt() */-if(ipv6_hdr(skb)->hop_limit<READ_ONCE(tcp_inet6_sk(sk)->min_hopcount)){-__NET_INC_STATS(net,LINUX_MIB_TCPMINTTLDROP);-gotoout;+if(static_branch_unlikely(&ip6_min_hopcount)){+/* min_hopcount can be changed concurrently from do_ipv6_setsockopt() */+if(ipv6_hdr(skb)->hop_limit<READ_ONCE(tcp_inet6_sk(sk)->min_hopcount)){+__NET_INC_STATS(net,LINUX_MIB_TCPMINTTLDROP);+gotoout;+}}tp=tcp_sk(sk);
@@ -1724,10 +1726,13 @@ INDIRECT_CALLABLE_SCOPE int tcp_v6_rcv(struct sk_buff *skb)return0;}}-/* min_hopcount can be changed concurrently from do_ipv6_setsockopt() */-if(hdr->hop_limit<READ_ONCE(tcp_inet6_sk(sk)->min_hopcount)){-__NET_INC_STATS(net,LINUX_MIB_TCPMINTTLDROP);-gotodiscard_and_relse;++if(static_branch_unlikely(&ip6_min_hopcount)){+/* min_hopcount can be changed concurrently from do_ipv6_setsockopt() */+if(hdr->hop_limit<READ_ONCE(tcp_inet6_sk(sk)->min_hopcount)){+__NET_INC_STATS(net,LINUX_MIB_TCPMINTTLDROP);+gotodiscard_and_relse;+}}if(!xfrm6_policy_check(sk,XFRM_POLICY_IN,skb))
@@ -1352,7 +1352,10 @@ static int do_ip_setsockopt(struct sock *sk, int level, int optname,gotoe_inval;if(val<0||val>255)gotoe_inval;-inet->min_ttl=val;+/* tcp_v4_err() and tcp_v4_rcv() might read min_ttl+*whilewearechangintit.+*/+WRITE_ONCE(inet->min_ttl,val);break;default:
@@ -508,7 +508,8 @@ int tcp_v4_err(struct sk_buff *skb, u32 info)if(sk->sk_state==TCP_CLOSE)gotoout;-if(unlikely(iph->ttl<inet_sk(sk)->min_ttl)){+/* min_ttl can be changed concurrently from do_ip_setsockopt() */+if(unlikely(iph->ttl<READ_ONCE(inet_sk(sk)->min_ttl))){__NET_INC_STATS(net,LINUX_MIB_TCPMINTTLDROP);gotoout;}
@@ -2049,7 +2050,9 @@ int tcp_v4_rcv(struct sk_buff *skb)return0;}}-if(unlikely(iph->ttl<inet_sk(sk)->min_ttl)){++/* min_ttl can be changed concurrently from do_ip_setsockopt() */+if(unlikely(iph->ttl<READ_ONCE(inet_sk(sk)->min_ttl))){__NET_INC_STATS(net,LINUX_MIB_TCPMINTTLDROP);gotodiscard_and_relse;}
From: Eric Dumazet <hidden> Date: 2021-10-21 16:23:21
From: Eric Dumazet <edumazet@google.com>
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>
---
include/net/ip.h | 2 ++
net/ipv4/ip_sockglue.c | 6 ++++++
net/ipv4/tcp_ipv4.c | 20 ++++++++++++--------
3 files changed, 20 insertions(+), 8 deletions(-)
@@ -886,6 +886,8 @@ static int compat_ip_mcast_join_leave(struct sock *sk, int optname,returnip_mc_leave_group(sk,&mreq);}+DEFINE_STATIC_KEY_FALSE(ip4_min_ttl);+staticintdo_ip_setsockopt(structsock*sk,intlevel,intoptname,sockptr_toptval,unsignedintoptlen){
@@ -1352,6 +1354,10 @@ static int do_ip_setsockopt(struct sock *sk, int level, int optname,gotoe_inval;if(val<0||val>255)gotoe_inval;++if(val)+static_branch_enable(&ip4_min_ttl);+/* tcp_v4_err() and tcp_v4_rcv() might read min_ttl*whilewearechangintit.*/
@@ -508,10 +508,12 @@ int tcp_v4_err(struct sk_buff *skb, u32 info)if(sk->sk_state==TCP_CLOSE)gotoout;-/* min_ttl can be changed concurrently from do_ip_setsockopt() */-if(unlikely(iph->ttl<READ_ONCE(inet_sk(sk)->min_ttl))){-__NET_INC_STATS(net,LINUX_MIB_TCPMINTTLDROP);-gotoout;+if(static_branch_unlikely(&ip4_min_ttl)){+/* min_ttl can be changed concurrently from do_ip_setsockopt() */+if(unlikely(iph->ttl<READ_ONCE(inet_sk(sk)->min_ttl))){+__NET_INC_STATS(net,LINUX_MIB_TCPMINTTLDROP);+gotoout;+}}tp=tcp_sk(sk);
@@ -2051,10 +2053,12 @@ int tcp_v4_rcv(struct sk_buff *skb)}}-/* min_ttl can be changed concurrently from do_ip_setsockopt() */-if(unlikely(iph->ttl<READ_ONCE(inet_sk(sk)->min_ttl))){-__NET_INC_STATS(net,LINUX_MIB_TCPMINTTLDROP);-gotodiscard_and_relse;+if(static_branch_unlikely(&ip4_min_ttl)){+/* min_ttl can be changed concurrently from do_ip_setsockopt() */+if(unlikely(iph->ttl<READ_ONCE(inet_sk(sk)->min_ttl))){+__NET_INC_STATS(net,LINUX_MIB_TCPMINTTLDROP);+gotodiscard_and_relse;+}}if(!xfrm4_policy_check(sk,XFRM_POLICY_IN,skb))
From: Eric Dumazet <hidden> Date: 2021-10-21 16:23:23
From: Eric Dumazet <edumazet@google.com>
Two kfree_skb() calls must be replaced by consume_skb()
for skbs that are not technically dropped.
Signed-off-by: Eric Dumazet <edumazet@google.com>
---
net/ipv6/tcp_ipv6.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
From: Eric Dumazet <edumazet@google.com> Date: 2021-10-21 16:24:53
On Thu, Oct 21, 2021 at 9:23 AM Eric Dumazet [off-list ref] wrote:
From: Eric Dumazet <edumazet@google.com>
For non TCQ_F_NOLOCK qdisc, qdisc_run_begin() tries to set
__QDISC_STATE_RUNNING and should return true if the bit was not set.
test_and_set_bit() returns old bit value, therefore we need to invert.
Fixes: 29cbcd858283 ("net: sched: Remove Qdisc::running sequence counter")
Signed-off-by: Eric Dumazet <edumazet@google.com>
Cc: Ahmed S. Darwish <redacted>
Cc: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
---
Please disregard, I have accidentally resent this already merged patch.
From: Eric Dumazet <edumazet@google.com> Date: 2021-10-21 16:25:43
On Thu, Oct 21, 2021 at 9:23 AM Eric Dumazet [off-list ref] wrote:
From: Eric Dumazet <edumazet@google.com>
__QDISC_STATE_RUNNING is only set/cleared from contexts owning qdisc lock.
Thus we can use less expensive bit operations, as we were doing
before commit f9eb8aea2a1e ("net_sched: transform qdisc running bit into a seqcount")
Fixes: 29cbcd858283 ("net: sched: Remove Qdisc::running sequence counter")
Signed-off-by: Eric Dumazet <edumazet@google.com>
Cc: Ahmed S. Darwish <redacted>
Cc: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
---
Please disregard, I have accidentally resent this patch while sending
another unrelated patch series.
On Thu, Oct 21, 2021 at 12:23 PM Eric Dumazet [off-list ref] wrote:
From: Eric Dumazet <edumazet@google.com>
This series aims to reduce cache line misses in RX path.
I am still working on better cache locality in tcp_sock but
this will wait few more weeks.
Eric Dumazet (9):
tcp: move inet->rx_dst_ifindex to sk->sk_rx_dst_ifindex
ipv6: move inet6_sk(sk)->rx_dst_cookie to sk->sk_rx_dst_cookie
net: avoid dirtying sk->sk_napi_id
net: avoid dirtying sk->sk_rx_queue_mapping
ipv6: annotate data races around np->min_hopcount
ipv6: guard IPV6_MINHOPCOUNT with a static key
ipv4: annotate data races arount inet->min_ttl
ipv4: guard IP_MINTTL with a static key
ipv6/tcp: small drop monitor changes
Acked-by: Soheil Hassas Yeganeh <redacted>
Very nice patch series! The IP_MINTTL patch is an excellent find. I
wonder how many more of these we have. Thank you, Eric!