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

Configure Feed

Select the types of activity you want to include in your feed.

net: rfs: add sock_rps_delete_flow() helper

RFS can exhibit lower performance for workloads using short-lived
flows and a small set of 4-tuple.

This is often the case for load-testers, using a pair of hosts,
if the server has a single listener port.

Typical use case :

Server : tcp_crr -T128 -F1000 -6 -U -l30 -R 14250
Client : tcp_crr -T128 -F1000 -6 -U -l30 -c -H server | grep local_throughput

This is because RFS global hash table contains stale information,
when the same RSS key is recycled for another socket and another cpu.

Make sure to undo the changes and go back to initial state when
a flow is disconnected.

Performance of the above test is increased by 22 %,
going from 372604 transactions per second to 457773.

Signed-off-by: Eric Dumazet <edumazet@google.com>
Reported-by: Octavian Purdila <tavip@google.com>
Reviewed-by: Neal Cardwell <ncardwell@google.com>
Link: https://patch.msgid.link/20250515100354.3339920-1-edumazet@google.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>

authored by

Eric Dumazet and committed by
Jakub Kicinski
9cd5ef0b f24f7b2f

+31 -3
+24
include/net/rps.h
··· 123 123 #endif 124 124 } 125 125 126 + static inline void sock_rps_delete_flow(const struct sock *sk) 127 + { 128 + #ifdef CONFIG_RPS 129 + struct rps_sock_flow_table *table; 130 + u32 hash, index; 131 + 132 + if (!static_branch_unlikely(&rfs_needed)) 133 + return; 134 + 135 + hash = READ_ONCE(sk->sk_rxhash); 136 + if (!hash) 137 + return; 138 + 139 + rcu_read_lock(); 140 + table = rcu_dereference(net_hotdata.rps_sock_flow_table); 141 + if (table) { 142 + index = hash & table->mask; 143 + if (READ_ONCE(table->ents[index]) != RPS_NO_CPU) 144 + WRITE_ONCE(table->ents[index], RPS_NO_CPU); 145 + } 146 + rcu_read_unlock(); 147 + #endif 148 + } 149 + 126 150 static inline u32 rps_input_queue_tail_incr(struct softnet_data *sd) 127 151 { 128 152 #ifdef CONFIG_RPS
+4 -2
net/ipv4/inet_hashtables.c
··· 23 23 #if IS_ENABLED(CONFIG_IPV6) 24 24 #include <net/inet6_hashtables.h> 25 25 #endif 26 - #include <net/secure_seq.h> 27 26 #include <net/hotdata.h> 28 27 #include <net/ip.h> 29 - #include <net/tcp.h> 28 + #include <net/rps.h> 29 + #include <net/secure_seq.h> 30 30 #include <net/sock_reuseport.h> 31 + #include <net/tcp.h> 31 32 32 33 u32 inet_ehashfn(const struct net *net, const __be32 laddr, 33 34 const __u16 lport, const __be32 faddr, ··· 791 790 if (sk_unhashed(sk)) 792 791 return; 793 792 793 + sock_rps_delete_flow(sk); 794 794 if (sk->sk_state == TCP_LISTEN) { 795 795 struct inet_listen_hashbucket *ilb2; 796 796
+2
net/ipv4/udp.c
··· 120 120 #if IS_ENABLED(CONFIG_IPV6) 121 121 #include <net/ipv6_stubs.h> 122 122 #endif 123 + #include <net/rps.h> 123 124 124 125 struct udp_table udp_table __read_mostly; 125 126 ··· 2201 2200 struct udp_table *udptable = udp_get_table_prot(sk); 2202 2201 struct udp_hslot *hslot, *hslot2; 2203 2202 2203 + sock_rps_delete_flow(sk); 2204 2204 hslot = udp_hashslot(udptable, sock_net(sk), 2205 2205 udp_sk(sk)->udp_port_hash); 2206 2206 hslot2 = udp_hashslot2(udptable, udp_sk(sk)->udp_portaddr_hash);
+1 -1
net/sctp/socket.c
··· 8321 8321 8322 8322 static void sctp_unhash(struct sock *sk) 8323 8323 { 8324 - /* STUB */ 8324 + sock_rps_delete_flow(sk); 8325 8325 } 8326 8326 8327 8327 /* Check if port is acceptable. Possibly find first available port.