* [PATCH net v2] net: dsa: clear the conduit RX queue on receive
@ 2026-10-28 2:51 John Macias
2026-11-02 15:47 ` Paolo Abeni
0 siblings, 1 reply; 3+ messages in thread
From: John Macias @ 2026-10-28 2:51 UTC (permalink / raw)
To: netdev
Cc: Andrew Lunn, Vladimir Oltean, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Simon Horman, linux-kernel
A multi-queue conduit records its RX queue in skb->queue_mapping with
skb_record_rx_queue(), as stmmac, mtk_eth_soc, fec and dpaa2 do.
dsa_switch_rcv() passes the skb on with that index unchanged, although
it counts the conduit's queues, not those of skb->dev. A user port has
a single RX queue. For a packet from conduit queue 1 or above,
get_rps_cpu() finds the index past the port's real_num_rx_queues and
returns without steering, and its WARN_ONCE() stays silent because the
port has only one queue. So rps_cpus on a user port only takes effect
for packets from conduit queue 0.
Trunk-tagged frames go straight to a bond or team (tag_dsa), through
the netif_rx() branch for devices that are not user ports. That device
has its own RX queue count, so the conduit's index there selects the
RPS map of an unrelated rx-N queue, skips RPS, or, when the device has
more than one queue and an index at or above that count, triggers
the WARN_ONCE().
Clear the queue mapping once the tagger has chosen skb->dev, before
that branch, so both paths are covered.
This leaves no RX queue recorded, rather than recording queue 0. Both
make get_rps_cpu() use the first RX queue's map. They differ for code
that reads the recorded queue later:
- skb_tx_hash() picks the TX queue from a recorded RX queue when no
socket mapping or XPS map decides. A flow forwarded from a DSA port
to a multi-queue device now gets its TX queue from the flow hash
instead of the conduit's RX queue number. Recording queue 0 would
instead put every such flow on the first TX queue of its traffic
class. The selected TX queue is also an input to several taggers:
tag_brcm encodes it directly, while tag_ksz, tag_sja1105,
tag_ocelot_8021q, tag_netc and tag_vsc73xx_8021q derive a traffic
class or PCP from it. A different queue within the same traffic
class need not change that encoded class.
- With CONFIG_SOCK_RX_QUEUE_MAPPING, packets received through DSA ports
no longer update sk_rx_queue_mapping, so XPS by RX queue (xps_rxqs)
stops following the conduit's queue number for those sockets. A
mapping the socket already holds is left as it is.
Found on an IPQ8074 board (OpenWrt, Linux 6.18, conduit with four RX
rings): with rps_cpus set on the LAN and WAN user ports,
/proc/net/softnet_stat showed RPS only for traffic hashed to conduit
ring 0.
Claude and Codex assisted with diagnosing the queue-metadata issue,
preparing the change and its explanation, and checking source and test
results.
Fixes: 91da11f870f0 ("net: Distributed Switch Architecture protocol support")
Signed-off-by: John Macias <dencity7@gmail.com>
---
Changes in v2:
- Clear the queue mapping before the branch for devices that are not
user ports, so trunk-tagged frames delivered to a bond or team are
covered too (Sashiko review).
- Replace the claim that TX queue selection is unaffected. The changelog
now describes the effect on skb_tx_hash(), taggers that consume the
selected TX queue, and sk_rx_queue_mapping and
xps_rxqs, and says why no queue is recorded instead of queue 0.
- Subject: "on user port receive" -> "on receive".
v1: https://lore.kernel.org/all/20261025072203.1519561-1-dencity7@gmail.com/
Claude assisted with diagnosis, the patch and runtime harness. Codex
independently reviewed the code, claims and raw results, and corrected
the test descriptions.
Testing on net/main (5d7f3375c), x86_64 under QEMU: a 4-queue virtio-net
conduit with dsa_loop, which for this test only was changed to use the
Marvell DSA tagger and to accept LAG offload (lan2 + lan3 in a
balance-xor bond with 2 RX queues). The host injects DSA-tagged UDP on
chosen conduit RX queues; rps_cpus on lan1 and on bond0 rx-0 points to
an otherwise idle CPU. 200 datagrams per queue and path. The RPS columns
say on which conduit queues the receiving socket saw the RPS CPU
(SO_INCOMING_CPU, which holds the socket's latest receive CPU, so this
is a per-socket observation rather than a per-packet one):
lan1 RPS bond0 RPS WARN_ONCE eth1 TX
(q0-q3) (q0-q3) per queue
unpatched q0 only q0 only yes 800/0/1/0
v1 all q0 only yes 201/100/150/350
v2 all all no 201/100/350/150
skb_record_rx_queue all all no 800/0/0/1
(skb, 0) instead
(Queue 2's NAPI happened to run on the RPS CPU, so q2 does not tell the
cases apart; q1 and q3 do.) The last column is the eth1 TX packet delta
per queue while 16 UDP flows (800 datagrams), all from conduit RX
queue 0, were routed out a 4-queue virtio-net with XPS cleared; each
total is 801 because one other packet was also sent. The aggregate
counters are consistent with fallback TX selection favoring queue 0
when RX queue 0 is recorded, and flow-hash distribution
when none is recorded; the unclassified extra packet is not attributed
to a test flow. W=1 build of net/dsa is clean.
On the original hardware (Netgear RAX120 v1, IPQ8074, OpenWrt Linux
6.18, four-ring conduit), v1 was tested as described in v1. v2 has not
run there yet, and I have no switch with LAG offload to test the trunk
path on real hardware.
net/dsa/tag.c | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/net/dsa/tag.c b/net/dsa/tag.c
index 6a5aa7fc3..e53dc3f3c 100644
--- a/net/dsa/tag.c
+++ b/net/dsa/tag.c
@@ -95,6 +95,13 @@ static int dsa_switch_rcv(struct sk_buff *skb,
struct net_device *dev,
skb->pkt_type = PACKET_HOST;
skb->protocol = eth_type_trans(skb, skb->dev);
+ /* The RX queue the conduit recorded is an index into the conduit's
+ * queues. It means nothing on skb->dev, a user port with a single RX
+ * queue or a bond/team with its own queue count, and get_rps_cpu()
+ * would check it against that device. Leave no queue recorded.
+ */
+ skb_set_queue_mapping(skb, 0);
+
if (unlikely(!dsa_user_dev_check(skb->dev))) {
/* Packet is to be injected directly on an upper
* device, e.g. a team/bond, so skip all DSA-port
--
2.47.3
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [PATCH net v2] net: dsa: clear the conduit RX queue on receive
2026-10-28 2:51 [PATCH net v2] net: dsa: clear the conduit RX queue on receive John Macias
@ 2026-11-02 15:47 ` Paolo Abeni
2026-11-07 21:03 ` John Macias
0 siblings, 1 reply; 3+ messages in thread
From: Paolo Abeni @ 2026-11-02 15:47 UTC (permalink / raw)
To: John Macias, netdev
Cc: Andrew Lunn, Vladimir Oltean, David S. Miller, Eric Dumazet,
Jakub Kicinski, Simon Horman, linux-kernel
On 10/28/26 03:51, John Macias wrote:
> diff --git a/net/dsa/tag.c b/net/dsa/tag.c
> index 6a5aa7fc3..e53dc3f3c 100644
> --- a/net/dsa/tag.c
> +++ b/net/dsa/tag.c
> @@ -95,6 +95,13 @@ static int dsa_switch_rcv(struct sk_buff *skb,
> struct net_device *dev,
The diff is damaged. Please fix your setup and re-submit.
/P
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [PATCH net v2] net: dsa: clear the conduit RX queue on receive
2026-11-02 15:47 ` Paolo Abeni
@ 2026-11-07 21:03 ` John Macias
0 siblings, 0 replies; 3+ messages in thread
From: John Macias @ 2026-11-07 21:03 UTC (permalink / raw)
To: pabeni
Cc: netdev, andrew, olteanv, davem, edumazet, kuba, horms, linux-kernel
On 11/2/26 16:47, Paolo Abeni wrote:
> The diff is damaged. Please fix your setup and re-submit.
Sorry about that. My mail setup re-wrapped the diff. I've sent v3
with git send-email, with no code changes.
John
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2026-11-07 21:03 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-10-28 2:51 [PATCH net v2] net: dsa: clear the conduit RX queue on receive John Macias
2026-11-02 15:47 ` Paolo Abeni
2026-11-07 21:03 ` John Macias
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®