* [PATCH net-next v11] net: reduce ARFS flow updates by checking LLC affinity
@ 2026-10-12 6:01 Chuang Wang
2026-10-13 7:00 ` netdev-bot+sashiko
0 siblings, 1 reply; 3+ messages in thread
From: Chuang Wang @ 2026-10-12 6:01 UTC (permalink / raw)
Cc: Chuang Wang, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Simon Horman, Kuniyuki Iwashima, Stanislav Fomichev,
Hangbin Liu, Samiullah Khawaja, Neal Cardwell, Roman Gushchin,
netdev, linux-kernel
The current implementation of rps_record_sock_flow() updates the flow
table every time a socket is processed on a different CPU. In high-load
scenarios, especially with Accelerated RFS (ARFS), this triggers
frequent flow steering updates via ndo_rx_flow_steer.
For drivers like mlx5 that implement hardware flow steering, these
constant updates lead to significant contention on internal driver locks
(e.g., arfs_lock). In high-load scenarios, this contention often becomes
a performance bottleneck that outweighs the steering benefits.
This patch introduces a cache-aware update strategy: the hardware
steering update is skipped when the flow's previous target CPU and the
new one share the same Last Level Cache (LLC), as cache locality for
the application is preserved either way. The per-queue flow bookkeeping
(rflow->cpu) is still updated, so RFS keeps steering packets to the CPU
the application is running on, and subsequent packets take the fast path
in get_rps_cpu() (tcpu == next_cpu). A new sysctl,
net.core.arfs_llc_affinity, is added to toggle this feature (default:
off).
Performance Test Results:
The patch was tested in a K8s environment (AMD CPU 128*2, 16-core Pod
with CPU pinning, mlx5 NIC) using brpc[1] echo_server and rpc_press.
rpc_press Commands:
for i in {1..8}; do
./rpc_press -proto=./echo.proto -method=example.EchoService.Echo
-server=<IP>:8000 -input='{"message":"hello"}'
-qps=0 -thread_num=512 -connection_type=pooled &
done
Monitor mlx5e_rx_flow_steer frequency:
/usr/share/bcc/tools/funccount -i 1 mlx5e_rx_flow_steer
Frequency of mlx5e_rx_flow_steer (via funccount[2]):
Before: ~200,000 counts/sec
After: ~10 counts/sec (reduced by ~99%)
These results demonstrate that filtering updates by LLC affinity
significantly reduces driver lock contention and improves overall
CPU efficiency under heavy network load.
[1] https://github.com/apache/brpc/
[2] https://github.com/iovisor/bcc/blob/master/tools/funccount.py
Signed-off-by: Chuang Wang <nashuiliang@gmail.com>
---
v10 -> v11:
- rename the sysctl from net.core.rps_feat_llc_affinity to
net.core.arfs_llc_affinity, per Neal Cardwell
v9 -> v10:
- move the LLC check from rps_record_sock_flow() into set_rps_cpu(),
so that only the ARFS hardware steering is skipped while rflow->cpu
is still updated, per Eric Dumazet
- drop the sock_rps_record_flow_hash()/sock_rps_record_flow() exports,
which are no longer needed
v6 -> v9:
- simplify code and fix errors in AI submissions, per Simon Horman
v5 -> v6:
- remove the multi-check 'old_val == new_val', per Xuan Zhuo
- fix 'modpost: "sock_rps_record_flow_hash" [drivers/net/tun.ko]
undefined!', per kernel test robot
- fix 'tcp.c:(.text+0x3e90): undefined reference to
`sock_rps_record_flow'', per kernel test robot
v4 -> v5:
- fix 'modpost: "rps_llc_check" [net/sctp/sctp.ko] undefined!', per
kernel test robot
v3 -> v4:
- add rps_llc_check, per Eric Dumazet
v2 -> v3:
- patch net -> net-next, per Jakub Kicinski
v1 -> v2:
- add rps_feat_llc_affinity; add brpc tests
include/net/rps.h | 1 +
net/core/dev.c | 23 +++++++++++++++++++++--
net/core/sysctl_net_core.c | 7 +++++++
3 files changed, 29 insertions(+), 2 deletions(-)
diff --git a/include/net/rps.h b/include/net/rps.h
index e33c6a2fa8bb..6664970e68d6 100644
--- a/include/net/rps.h
+++ b/include/net/rps.h
@@ -12,6 +12,7 @@
extern struct static_key_false rps_needed;
extern struct static_key_false rfs_needed;
+extern struct static_key_false arfs_llc_affinity;
/*
* This structure holds an RPS map which can be of variable length. The
diff --git a/net/core/dev.c b/net/core/dev.c
index a6951ea08961..434ad5499906 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -5122,6 +5122,7 @@ struct static_key_false rps_needed __read_mostly;
EXPORT_SYMBOL(rps_needed);
struct static_key_false rfs_needed __read_mostly;
EXPORT_SYMBOL(rfs_needed);
+struct static_key_false arfs_llc_affinity __read_mostly;
static u32 rfs_slot(u32 hash, rps_tag_ptr tag_ptr)
{
@@ -5160,7 +5161,7 @@ static bool rps_flow_is_active(struct rps_dev_flow *rflow,
static struct rps_dev_flow *
set_rps_cpu(struct net_device *dev, struct sk_buff *skb,
- struct rps_dev_flow *rflow, u16 next_cpu, u32 hash)
+ struct rps_dev_flow *rflow, u16 old_cpu, u16 next_cpu, u32 hash)
{
if (next_cpu < nr_cpu_ids) {
u32 head;
@@ -5179,6 +5180,24 @@ set_rps_cpu(struct net_device *dev, struct sk_buff *skb,
if (!skb_rx_queue_recorded(skb) || !dev->rx_cpu_rmap ||
!(dev->features & NETIF_F_NTUPLE))
goto out;
+
+ /*
+ * ARFS LLC Affinity Feature:
+ * Reduce ARFS flow updates by checking LLC affinity.
+ *
+ * Frequent flow table updates can trigger constant hardware steering
+ * reconfigurations (e.g., ndo_rx_flow_steer), leading to significant
+ * contention on driver internal locks (like mlx5's arfs_lock).
+ *
+ * Skip the expensive hardware steering update if the flow's previous
+ * target CPU and the new one share the last level cache: cache locality
+ * for the application is preserved either way.
+ */
+ if (static_branch_unlikely(&arfs_llc_affinity) &&
+ old_cpu < nr_cpu_ids && cpu_online(old_cpu) &&
+ cpus_share_cache(old_cpu, next_cpu))
+ goto out;
+
rxq_index = cpu_rmap_lookup_index(dev->rx_cpu_rmap, next_cpu);
if (rxq_index == skb_get_rx_queue(skb))
goto out;
@@ -5308,8 +5327,8 @@ static int get_rps_cpu(struct net_device *dev, struct sk_buff *skb,
(tcpu >= nr_cpu_ids || !cpu_online(tcpu) ||
((int)(READ_ONCE(per_cpu(softnet_data, tcpu).input_queue_head) -
rflow->last_qtail)) >= 0)) {
+ rflow = set_rps_cpu(dev, skb, rflow, tcpu, next_cpu, hash);
tcpu = next_cpu;
- rflow = set_rps_cpu(dev, skb, rflow, next_cpu, hash);
}
if (tcpu < nr_cpu_ids && cpu_online(tcpu)) {
diff --git a/net/core/sysctl_net_core.c b/net/core/sysctl_net_core.c
index 473c162736d6..9ce0bbe454c8 100644
--- a/net/core/sysctl_net_core.c
+++ b/net/core/sysctl_net_core.c
@@ -560,6 +560,13 @@ static struct ctl_table net_core_table[] = {
.mode = 0644,
.proc_handler = rps_sock_flow_sysctl
},
+ {
+ .procname = "arfs_llc_affinity",
+ .data = &arfs_llc_affinity.key,
+ .maxlen = sizeof(arfs_llc_affinity.key),
+ .mode = 0644,
+ .proc_handler = proc_do_static_key
+ },
#endif
#ifdef CONFIG_NET_FLOW_LIMIT
{
--
2.47.3
^ permalink raw reply [flat|nested] 3+ messages in thread* Re: [PATCH net-next v11] net: reduce ARFS flow updates by checking LLC affinity
2026-10-12 6:01 [PATCH net-next v11] net: reduce ARFS flow updates by checking LLC affinity Chuang Wang
@ 2026-10-13 7:00 ` netdev-bot+sashiko
2026-10-13 7:07 ` Kuniyuki Iwashima
0 siblings, 1 reply; 3+ messages in thread
From: netdev-bot+sashiko @ 2026-10-13 7:00 UTC (permalink / raw)
To: nashuiliang
Cc: davem, edumazet, kuba, pabeni, horms, kuniyu, sdf.kernel,
liuhangbin, skhawaja, ncardwell, roman.gushchin, netdev,
linux-kernel
Thank you for your contribution! Sashiko AI review found 5 potential
issue(s) to consider.
Critical: 0 · High: 0 · Medium: 1 · Low: 4
If you believe none of the issues are legitimate, please reply to each
issue of Medium severity or higher and explain why the AI is wrong.
If any of them are legitimate and you plan to respin, please let patchwork
know by including "pw-bot: cr" as a separate line at the end of your reply
(one such reply per series is enough).
- [Medium] The new LLC skip in set_rps_cpu() (net/core/dev.c:5196-5199)
assumes that `old_cpu` shows where the NIC currently delivers the flow.
- [Low] The new user-visible sysctl net.core.arfs_llc_affinity
(net/core/sysctl_net_core.c:563-569) has no documentation.
- [Low] The config guards for the sysctl and its only user do not match.
- [Low] The commit message says the results "demonstrate that filtering
updates by LLC affinity significantly reduces driver lock contention…
- [Low] In this tree, cpus_share_cache() (kernel/sched/core.c:4008-4014)
returns `per_cpu(sd_llc_id, a) == per_cpu(sd_llc_id, b)`.
--
net: reduce ARFS flow updates by checking LLC affinity
This commit adds an opt-in sysctl, net.core.arfs_llc_affinity. When it is
set, set_rps_cpu() skips the ARFS hardware steering update
(ndo_rx_flow_steer) if the flow's previous RFS CPU and the new one share
an LLC. The rflow->cpu bookkeeping is still updated, so software RFS keeps
steering packets to the CPU the application runs on.
> These results demonstrate that filtering updates by LLC affinity
> significantly reduces driver lock contention and improves overall
> CPU efficiency under heavy network load.
[Severity: Low]
Does the data above support this claim? The only number given is the
mlx5e_rx_flow_steer() call rate, which drops from about 200k/s to about
10/s. There are no throughput, latency, CPU utilisation or lock
contention numbers.
The commit message also leaves out the trade-off. When the hardware
update is skipped, the flow stays on its old queue. get_rps_cpu() then
hands every packet to next_cpu with a remote enqueue_to_backlog() plus an
RPS IPI. After a completed ARFS steer, the packet would instead be
handled on the queue's own IRQ CPU.
The phrase "subsequent packets take the fast path in get_rps_cpu()
(tcpu == next_cpu)" could be read as local processing. The packets are
still moved to a remote CPU.
The opening paragraph names rps_record_sock_flow() as the motivation.
Since v10, though, the patch only changes set_rps_cpu() and get_rps_cpu().
Could that paragraph be reworded to match?
> diff --git a/net/core/dev.c b/net/core/dev.c
> index a6951ea08961e..434ad5499906d 100644
> --- a/net/core/dev.c
> +++ b/net/core/dev.c
[ ... ]
> @@ -5179,6 +5180,24 @@ set_rps_cpu(struct net_device *dev, struct sk_buff *skb,
> if (!skb_rx_queue_recorded(skb) || !dev->rx_cpu_rmap ||
> !(dev->features & NETIF_F_NTUPLE))
> goto out;
> +
> + /*
> + * ARFS LLC Affinity Feature:
> + * Reduce ARFS flow updates by checking LLC affinity.
> + *
> + * Frequent flow table updates can trigger constant hardware steering
> + * reconfigurations (e.g., ndo_rx_flow_steer), leading to significant
> + * contention on driver internal locks (like mlx5's arfs_lock).
> + *
> + * Skip the expensive hardware steering update if the flow's previous
> + * target CPU and the new one share the last level cache: cache locality
> + * for the application is preserved either way.
> + */
> + if (static_branch_unlikely(&arfs_llc_affinity) &&
> + old_cpu < nr_cpu_ids && cpu_online(old_cpu) &&
> + cpus_share_cache(old_cpu, next_cpu))
> + goto out;
[Severity: Medium]
Is old_cpu a reliable sign of where the NIC currently delivers this flow?
get_rps_cpu() passes in tcpu = rflow->cpu. That value is read from the
hashed slot in the flow table of the queue the packet arrived on. It only
records the last software RFS target for that slot, and it may have no
hardware filter behind it. For example:
- ndo_rx_flow_steer() returned rc < 0, but set_rps_cpu() still did
WRITE_ONCE(rflow->cpu, next_cpu) on the arrival queue's slot.
mlx5e_rx_flow_steer() can return -EPROTONOSUPPORT, -ENOMEM, or -EPERM
while MLX5E_ARFS_STATE_ENABLED is clear.
- The tmp_rflow collision check or the !q_tag_ptr check took goto out.
- The slot still holds a CPU left by an earlier flow that hashed to the
same rfs_slot(). store_rps_dev_flow_table_cnt() sets RPS_NO_CPU only
when the table is allocated.
- The driver flushed or re-created its filters.
In each of these cases, if old_cpu and next_cpu share an LLC, the new
check skips ndo_rx_flow_steer() and then reaches:
WRITE_ONCE(rflow->cpu, next_cpu);
On later packets tcpu == next_cpu, so get_rps_cpu() never calls
set_rps_cpu() again. Hardware steering is not retried while the
application stays within that LLC. A new flow that lands on a stale slot
in the same LLC would never get an ARFS filter at all.
Before this patch, every CPU change triggered a new steering attempt, so
a failed or missing filter recovered on its own.
Without a filter, the flow stays on its RSS queue, which may be serviced
in another LLC or NUMA node. Every packet is then handed over by software
RFS. cpu_rmap_update() ranks queues by sibling, package and NUMA node,
not by LLC. Nothing guarantees an LLC relationship between the receiving
queue and old_cpu. Doesn't that contradict "cache locality for the
application is preserved either way"?
Could the skip be limited to the case where this flow has a live
hardware filter, for example rflow->filter != RPS_NO_FILTER &&
rflow->hash == hash? Another option would be to compare next_cpu with
the CPU that actually services the receiving queue, rather than with
rflow->cpu.
[Severity: Low]
Can cpus_share_cache() return true here for CPUs in different LLCs? In
this tree it is:
kernel/sched/core.c:cpus_share_cache() {
if (this_cpu == that_cpu)
return true;
return per_cpu(sd_llc_id, this_cpu) == per_cpu(sd_llc_id, that_cpu);
}
sd_llc_id defaults to -1. It is assigned only in build_sched_domains()
and reset to -1 by __sched_domains_free_llc_id().
sched_cpu_deactivate() calls sched_domains_free_llc_id(cpu) while the CPU
is still in cpu_online_mask. CPUs outside any sched domain, such as
isolcpus=domain CPUs, keep -1 permanently.
The new check guards old_cpu only with cpu_online(), and next_cpu only
with nr_cpu_ids. If both CPUs carry the -1 sentinel, they compare as
sharing an LLC and ndo_rx_flow_steer() is skipped. That could happen when
an application migrates between two isolated CPUs in different LLCs, or
during a hotplug window.
The sentinel handling belongs to the scheduler, but should this new
networking user guard against it?
> +
> rxq_index = cpu_rmap_lookup_index(dev->rx_cpu_rmap, next_cpu);
> if (rxq_index == skb_get_rx_queue(skb))
> goto out;
[ ... ]
> diff --git a/net/core/sysctl_net_core.c b/net/core/sysctl_net_core.c
> index 473c162736d69..9ce0bbe454c83 100644
> --- a/net/core/sysctl_net_core.c
> +++ b/net/core/sysctl_net_core.c
> @@ -560,6 +560,13 @@ static struct ctl_table net_core_table[] = {
> .mode = 0644,
> .proc_handler = rps_sock_flow_sysctl
> },
> + {
> + .procname = "arfs_llc_affinity",
> + .data = &arfs_llc_affinity.key,
> + .maxlen = sizeof(arfs_llc_affinity.key),
> + .mode = 0644,
> + .proc_handler = proc_do_static_key
> + },
> #endif
[Severity: Low]
Should this entry, and the arfs_llc_affinity definition in
net/core/dev.c, be under CONFIG_RFS_ACCEL instead of CONFIG_RPS?
The only reader, static_branch_unlikely(&arfs_llc_affinity) in
set_rps_cpu(), sits inside #ifdef CONFIG_RFS_ACCEL. RFS_ACCEL can be
turned off on its own ("depends on RPS" in net/Kconfig).
On CONFIG_RPS=y, CONFIG_RFS_ACCEL=n kernels,
/proc/sys/net/core/arfs_llc_affinity is still registered and accepts
writes that flip the key, but nothing changes.
[Severity: Low]
This isn't a bug, but net.core.arfs_llc_affinity isn't documented in
Documentation/admin-guide/sysctl/net.rst. That file covers other
net.core knobs, such as rps_default_mask and high_order_alloc_disable.
The Accelerated RFS section of Documentation/networking/scaling.rst also
still says:
The network stack automatically calls this function every time a flow
entry in rps_dev_flow_table is updated.
With the knob enabled, set_rps_cpu() now updates rflow->cpu and
rflow->last_qtail without calling ndo_rx_flow_steer() whenever the two
CPUs share an LLC.
Could the documentation describe the new knob, its default (0) and
accepted values, and this exception in scaling.rst?
--
Sashiko AI review · https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20261012060152.2930-1-nashuiliang%40gmail.com
^ permalink raw reply [flat|nested] 3+ messages in thread* Re: [PATCH net-next v11] net: reduce ARFS flow updates by checking LLC affinity
2026-10-13 7:00 ` netdev-bot+sashiko
@ 2026-10-13 7:07 ` Kuniyuki Iwashima
0 siblings, 0 replies; 3+ messages in thread
From: Kuniyuki Iwashima @ 2026-10-13 7:07 UTC (permalink / raw)
To: netdev-bot+sashiko
Cc: nashuiliang, davem, edumazet, kuba, pabeni, horms, sdf.kernel,
liuhangbin, skhawaja, ncardwell, roman.gushchin, netdev,
linux-kernel
On Tue, Oct 13, 2026 at 12:00 AM <netdev-bot+sashiko@kernel.org> wrote:
>
> Thank you for your contribution! Sashiko AI review found 5 potential
> issue(s) to consider.
>
> Critical: 0 · High: 0 · Medium: 1 · Low: 4
>
> If you believe none of the issues are legitimate, please reply to each
> issue of Medium severity or higher and explain why the AI is wrong.
> If any of them are legitimate and you plan to respin, please let patchwork
> know by including "pw-bot: cr" as a separate line at the end of your reply
> (one such reply per series is enough).
>
> - [Medium] The new LLC skip in set_rps_cpu() (net/core/dev.c:5196-5199)
> assumes that `old_cpu` shows where the NIC currently delivers the flow.
> - [Low] The new user-visible sysctl net.core.arfs_llc_affinity
> (net/core/sysctl_net_core.c:563-569) has no documentation.
> - [Low] The config guards for the sysctl and its only user do not match.
> - [Low] The commit message says the results "demonstrate that filtering
> updates by LLC affinity significantly reduces driver lock contention…
> - [Low] In this tree, cpus_share_cache() (kernel/sched/core.c:4008-4014)
> returns `per_cpu(sd_llc_id, a) == per_cpu(sd_llc_id, b)`.
>
> --
>
> net: reduce ARFS flow updates by checking LLC affinity
>
> This commit adds an opt-in sysctl, net.core.arfs_llc_affinity. When it is
> set, set_rps_cpu() skips the ARFS hardware steering update
> (ndo_rx_flow_steer) if the flow's previous RFS CPU and the new one share
> an LLC. The rflow->cpu bookkeeping is still updated, so software RFS keeps
> steering packets to the CPU the application runs on.
>
> > These results demonstrate that filtering updates by LLC affinity
> > significantly reduces driver lock contention and improves overall
> > CPU efficiency under heavy network load.
>
> [Severity: Low]
>
> Does the data above support this claim? The only number given is the
> mlx5e_rx_flow_steer() call rate, which drops from about 200k/s to about
> 10/s. There are no throughput, latency, CPU utilisation or lock
> contention numbers.
>
> The commit message also leaves out the trade-off. When the hardware
> update is skipped, the flow stays on its old queue. get_rps_cpu() then
> hands every packet to next_cpu with a remote enqueue_to_backlog() plus an
> RPS IPI. After a completed ARFS steer, the packet would instead be
> handled on the queue's own IRQ CPU.
>
> The phrase "subsequent packets take the fast path in get_rps_cpu()
> (tcpu == next_cpu)" could be read as local processing. The packets are
> still moved to a remote CPU.
>
> The opening paragraph names rps_record_sock_flow() as the motivation.
> Since v10, though, the patch only changes set_rps_cpu() and get_rps_cpu().
> Could that paragraph be reworded to match?
>
> > diff --git a/net/core/dev.c b/net/core/dev.c
> > index a6951ea08961e..434ad5499906d 100644
> > --- a/net/core/dev.c
> > +++ b/net/core/dev.c
>
> [ ... ]
>
> > @@ -5179,6 +5180,24 @@ set_rps_cpu(struct net_device *dev, struct sk_buff *skb,
> > if (!skb_rx_queue_recorded(skb) || !dev->rx_cpu_rmap ||
> > !(dev->features & NETIF_F_NTUPLE))
> > goto out;
> > +
> > + /*
> > + * ARFS LLC Affinity Feature:
> > + * Reduce ARFS flow updates by checking LLC affinity.
> > + *
> > + * Frequent flow table updates can trigger constant hardware steering
> > + * reconfigurations (e.g., ndo_rx_flow_steer), leading to significant
> > + * contention on driver internal locks (like mlx5's arfs_lock).
> > + *
> > + * Skip the expensive hardware steering update if the flow's previous
> > + * target CPU and the new one share the last level cache: cache locality
> > + * for the application is preserved either way.
> > + */
> > + if (static_branch_unlikely(&arfs_llc_affinity) &&
> > + old_cpu < nr_cpu_ids && cpu_online(old_cpu) &&
> > + cpus_share_cache(old_cpu, next_cpu))
> > + goto out;
>
> [Severity: Medium]
>
> Is old_cpu a reliable sign of where the NIC currently delivers this flow?
>
> get_rps_cpu() passes in tcpu = rflow->cpu. That value is read from the
> hashed slot in the flow table of the queue the packet arrived on. It only
> records the last software RFS target for that slot, and it may have no
> hardware filter behind it. For example:
>
> - ndo_rx_flow_steer() returned rc < 0, but set_rps_cpu() still did
> WRITE_ONCE(rflow->cpu, next_cpu) on the arrival queue's slot.
> mlx5e_rx_flow_steer() can return -EPROTONOSUPPORT, -ENOMEM, or -EPERM
> while MLX5E_ARFS_STATE_ENABLED is clear.
>
> - The tmp_rflow collision check or the !q_tag_ptr check took goto out.
>
> - The slot still holds a CPU left by an earlier flow that hashed to the
> same rfs_slot(). store_rps_dev_flow_table_cnt() sets RPS_NO_CPU only
> when the table is allocated.
>
> - The driver flushed or re-created its filters.
>
> In each of these cases, if old_cpu and next_cpu share an LLC, the new
> check skips ndo_rx_flow_steer() and then reaches:
>
> WRITE_ONCE(rflow->cpu, next_cpu);
>
> On later packets tcpu == next_cpu, so get_rps_cpu() never calls
> set_rps_cpu() again. Hardware steering is not retried while the
> application stays within that LLC. A new flow that lands on a stale slot
> in the same LLC would never get an ARFS filter at all.
>
> Before this patch, every CPU change triggered a new steering attempt, so
> a failed or missing filter recovered on its own.
>
> Without a filter, the flow stays on its RSS queue, which may be serviced
> in another LLC or NUMA node. Every packet is then handed over by software
> RFS. cpu_rmap_update() ranks queues by sibling, package and NUMA node,
> not by LLC. Nothing guarantees an LLC relationship between the receiving
> queue and old_cpu. Doesn't that contradict "cache locality for the
> application is preserved either way"?
>
> Could the skip be limited to the case where this flow has a live
> hardware filter, for example rflow->filter != RPS_NO_FILTER &&
> rflow->hash == hash? Another option would be to compare next_cpu with
> the CPU that actually services the receiving queue, rather than with
> rflow->cpu.
Eric used raw_smp_processor_id() in the v9 thread:
https://lore.kernel.org/netdev/CANn89iJkPPXruitnot9D28Xe5LWnD-irtgCUEOpmFfVkG4M=-g@mail.gmail.com/
>
> [Severity: Low]
>
> Can cpus_share_cache() return true here for CPUs in different LLCs? In
> this tree it is:
>
> kernel/sched/core.c:cpus_share_cache() {
> if (this_cpu == that_cpu)
> return true;
>
> return per_cpu(sd_llc_id, this_cpu) == per_cpu(sd_llc_id, that_cpu);
> }
>
> sd_llc_id defaults to -1. It is assigned only in build_sched_domains()
> and reset to -1 by __sched_domains_free_llc_id().
>
> sched_cpu_deactivate() calls sched_domains_free_llc_id(cpu) while the CPU
> is still in cpu_online_mask. CPUs outside any sched domain, such as
> isolcpus=domain CPUs, keep -1 permanently.
>
> The new check guards old_cpu only with cpu_online(), and next_cpu only
> with nr_cpu_ids. If both CPUs carry the -1 sentinel, they compare as
> sharing an LLC and ndo_rx_flow_steer() is skipped. That could happen when
> an application migrates between two isolated CPUs in different LLCs, or
> during a hotplug window.
>
> The sentinel handling belongs to the scheduler, but should this new
> networking user guard against it?
>
> > +
> > rxq_index = cpu_rmap_lookup_index(dev->rx_cpu_rmap, next_cpu);
> > if (rxq_index == skb_get_rx_queue(skb))
> > goto out;
>
> [ ... ]
>
> > diff --git a/net/core/sysctl_net_core.c b/net/core/sysctl_net_core.c
> > index 473c162736d69..9ce0bbe454c83 100644
> > --- a/net/core/sysctl_net_core.c
> > +++ b/net/core/sysctl_net_core.c
> > @@ -560,6 +560,13 @@ static struct ctl_table net_core_table[] = {
> > .mode = 0644,
> > .proc_handler = rps_sock_flow_sysctl
> > },
> > + {
> > + .procname = "arfs_llc_affinity",
> > + .data = &arfs_llc_affinity.key,
> > + .maxlen = sizeof(arfs_llc_affinity.key),
> > + .mode = 0644,
> > + .proc_handler = proc_do_static_key
> > + },
> > #endif
>
> [Severity: Low]
>
> Should this entry, and the arfs_llc_affinity definition in
> net/core/dev.c, be under CONFIG_RFS_ACCEL instead of CONFIG_RPS?
>
> The only reader, static_branch_unlikely(&arfs_llc_affinity) in
> set_rps_cpu(), sits inside #ifdef CONFIG_RFS_ACCEL. RFS_ACCEL can be
> turned off on its own ("depends on RPS" in net/Kconfig).
>
> On CONFIG_RPS=y, CONFIG_RFS_ACCEL=n kernels,
> /proc/sys/net/core/arfs_llc_affinity is still registered and accepts
> writes that flip the key, but nothing changes.
>
> [Severity: Low]
>
> This isn't a bug, but net.core.arfs_llc_affinity isn't documented in
> Documentation/admin-guide/sysctl/net.rst. That file covers other
> net.core knobs, such as rps_default_mask and high_order_alloc_disable.
>
> The Accelerated RFS section of Documentation/networking/scaling.rst also
> still says:
>
> The network stack automatically calls this function every time a flow
> entry in rps_dev_flow_table is updated.
>
> With the knob enabled, set_rps_cpu() now updates rflow->cpu and
> rflow->last_qtail without calling ndo_rx_flow_steer() whenever the two
> CPUs share an LLC.
>
> Could the documentation describe the new knob, its default (0) and
> accepted values, and this exception in scaling.rst?
>
> --
> Sashiko AI review · https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20261012060152.2930-1-nashuiliang%40gmail.com
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2026-10-13 7:07 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-10-12 6:01 [PATCH net-next v11] net: reduce ARFS flow updates by checking LLC affinity Chuang Wang
2026-10-13 7:00 ` netdev-bot+sashiko
2026-10-13 7:07 ` Kuniyuki Iwashima
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®