* [PATCH net-next v3 0/5] veth: link RX queues to their NAPI instances
@ 2026-11-15 19:35 Tianyi Gao
2026-11-15 19:35 ` [PATCH net-next v3 1/5] veth: refactor NAPI enable paths Tianyi Gao
` (4 more replies)
0 siblings, 5 replies; 6+ messages in thread
From: Tianyi Gao @ 2026-11-15 19:35 UTC (permalink / raw)
To: netdev
Cc: andrew+netdev, davem, edumazet, kuba, pabeni, toke, lorenzo,
horms, shuah, ast, daniel, hawk, john.fastabend, sdf, joe,
linux-kselftest, bpf, kernel-team, tianyi.gao, Tianyi Gao
veth does not link its RX queues to their NAPI instances, so queue-get
reports no napi-id for them. napi-get lists each NAPI instance, and its
thread PID when NAPI is threaded, but not the RX queue it polls.
Userspace cannot tell which NAPI thread to pin for a given queue, or
which NAPI to change with napi-set.
There is also no way to busy poll an AF_XDP socket bound to a veth
queue. xsk_bind() takes the socket's NAPI ID from the RX queue, and a
veth RX queue has none.
Patch 1 is a cleanup to ease review of patch 2. veth_enable_xdp_range()
adds the NAPI instances only to pass their napi_id to
xdp_rxq_info_reg(), which no longer uses it. Patch 1 moves
netif_napi_add() into veth_napi_enable_range(), before the loop that
enables the NAPI instances. It also drops the napi_already_on and
delete_napi arguments and two wrappers.
Patch 2 calls netif_queue_set_napi() in veth_napi_enable_range(), after
napi_enable(). In veth_napi_del_range(), it clears the link with NULL
before napi_disable().
Patch 3 adds RX queue NAPI link checks to veth.sh. The napi-ids of the
RX queues must be the IDs of the NAPI instances of the device. The
queues must be linked only while NAPI is enabled. The checks run with
GRO on and with XDP attached, and across RX channel changes and link
down/up.
Patch 4 uses netif_napi_add_config(). veth deletes the NAPI instance of
an RX queue when it no longer needs it. With a persistent NAPI config,
the queue keeps its NAPI ID and settings when veth adds the instance
again.
Patch 5 adds checks to veth.sh that each RX queue keeps its NAPI ID.
---
Changes in v3:
- Patch 1: add all NAPI instances before enabling any, as before the
series (Sashiko [1]).
- Patch 3: reword the commit message. No code change.
- New patch 4: use netif_napi_add_config() (Sashiko [2]).
- New patch 5: check that each RX queue keeps its NAPI ID.
- v2: https://lore.kernel.org/all/20261111015922.67745-1-tianyi@cloudflare.com/
[1] https://lore.kernel.org/all/179470883254.2199510.15270739408094114749@kernel.org/
[2] https://lore.kernel.org/all/179470883411.2199510.13825316417997386083@kernel.org/
Changes in v2:
- Rebase on net-next. Patch 3 no longer applied after commit
c1f04ea0aa0f ("selftests: net: check veth carrier after changing
channel counts"). The conflict is in context only. No code change.
- v1: https://lore.kernel.org/all/20261105143356.17062-1-tianyi@cloudflare.com/
Tianyi Gao (5):
veth: refactor NAPI enable paths
veth: link RX queues to their NAPI instances
selftests: net: veth: test RX queue NAPI links
veth: use persistent NAPI config
selftests: net: veth: test that RX queues keep their NAPI IDs
drivers/net/veth.c | 85 ++++++----------------
tools/testing/selftests/net/veth.sh | 108 +++++++++++++++++++++++++++-
2 files changed, 130 insertions(+), 63 deletions(-)
base-commit: 6964ff21c5d8b75649211a52dbfd92753e605649
--
2.56.0
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH net-next v3 1/5] veth: refactor NAPI enable paths
2026-11-15 19:35 [PATCH net-next v3 0/5] veth: link RX queues to their NAPI instances Tianyi Gao
@ 2026-11-15 19:35 ` Tianyi Gao
2026-11-15 19:35 ` [PATCH net-next v3 2/5] veth: link RX queues to their NAPI instances Tianyi Gao
` (3 subsequent siblings)
4 siblings, 0 replies; 6+ messages in thread
From: Tianyi Gao @ 2026-11-15 19:35 UTC (permalink / raw)
To: netdev
Cc: andrew+netdev, davem, edumazet, kuba, pabeni, toke, lorenzo,
horms, shuah, ast, daniel, hawk, john.fastabend, sdf, joe,
linux-kselftest, bpf, kernel-team, tianyi.gao, Tianyi Gao
veth_enable_xdp_range() adds the NAPI instances itself, only to pass
rq->xdp_napi.napi_id as the napi_id argument of xdp_rxq_info_reg(). That
argument is unused in __xdp_rxq_info_reg() since commit 5ef44b3cb43b
("xsk: Bring back busy polling support"). Pass 0 instead, as ena, bnxt
and fec already do.
veth_enable_xdp_range() then no longer needs the NAPI instances. Move
netif_napi_add() from it and from veth_napi_enable_range() into
__veth_napi_enable_range(). Add the instances after the allocations
that can fail, and before the loop that enables them. Drop the
napi_already_on and delete_napi arguments.
veth_napi_enable_range() and veth_napi_enable() are then trivial
wrappers. Remove them, and rename __veth_napi_enable_range() and
__veth_napi_enable() to veth_napi_enable_range() and veth_napi_enable().
Signed-off-by: Tianyi Gao <tianyi@cloudflare.com>
---
Sashiko [1] pointed out that v2 added and enabled each NAPI instance in
the same loop, so a failed kthread creation could leave earlier instances
threaded and later ones not. v3 adds all instances before it enables any,
as the old code did, so such a failure turns off threaded mode for all.
[1] https://lore.kernel.org/all/179470883254.2199510.15270739408094114749@kernel.org/
---
drivers/net/veth.c | 82 +++++++++++-----------------------------------
1 file changed, 20 insertions(+), 62 deletions(-)
diff --git a/drivers/net/veth.c b/drivers/net/veth.c
index 0539b3661793..3cbedb8bad53 100644
--- a/drivers/net/veth.c
+++ b/drivers/net/veth.c
@@ -1037,7 +1037,7 @@ static int veth_create_page_pool(struct veth_rq *rq)
return 0;
}
-static int __veth_napi_enable_range(struct net_device *dev, int start, int end)
+static int veth_napi_enable_range(struct net_device *dev, int start, int end)
{
struct veth_priv *priv = netdev_priv(dev);
int err, i;
@@ -1056,6 +1056,9 @@ static int __veth_napi_enable_range(struct net_device *dev, int start, int end)
goto err_xdp_ring;
}
+ for (i = start; i < end; i++)
+ netif_napi_add(dev, &priv->rq[i].xdp_napi, veth_poll);
+
for (i = start; i < end; i++) {
struct veth_rq *rq = &priv->rq[i];
@@ -1079,9 +1082,9 @@ static int __veth_napi_enable_range(struct net_device *dev, int start, int end)
return err;
}
-static int __veth_napi_enable(struct net_device *dev)
+static int veth_napi_enable(struct net_device *dev)
{
- return __veth_napi_enable_range(dev, 0, dev->real_num_rx_queues);
+ return veth_napi_enable_range(dev, 0, dev->real_num_rx_queues);
}
static void veth_napi_del_range(struct net_device *dev, int start, int end)
@@ -1122,8 +1125,7 @@ static bool veth_gro_requested(const struct net_device *dev)
return !!(dev->wanted_features & NETIF_F_GRO);
}
-static int veth_enable_xdp_range(struct net_device *dev, int start, int end,
- bool napi_already_on)
+static int veth_enable_xdp_range(struct net_device *dev, int start, int end)
{
struct veth_priv *priv = netdev_priv(dev);
int err, i;
@@ -1131,9 +1133,7 @@ static int veth_enable_xdp_range(struct net_device *dev, int start, int end,
for (i = start; i < end; i++) {
struct veth_rq *rq = &priv->rq[i];
- if (!napi_already_on)
- netif_napi_add(dev, &rq->xdp_napi, veth_poll);
- err = xdp_rxq_info_reg(&rq->xdp_rxq, dev, i, rq->xdp_napi.napi_id);
+ err = xdp_rxq_info_reg(&rq->xdp_rxq, dev, i, 0);
if (err < 0)
goto err_rxq_reg;
@@ -1151,21 +1151,13 @@ static int veth_enable_xdp_range(struct net_device *dev, int start, int end,
err_reg_mem:
xdp_rxq_info_unreg(&priv->rq[i].xdp_rxq);
err_rxq_reg:
- if (!napi_already_on)
- netif_napi_del(&priv->rq[i].xdp_napi);
- for (i--; i >= start; i--) {
- struct veth_rq *rq = &priv->rq[i];
-
- xdp_rxq_info_unreg(&rq->xdp_rxq);
- if (!napi_already_on)
- netif_napi_del(&rq->xdp_napi);
- }
+ for (i--; i >= start; i--)
+ xdp_rxq_info_unreg(&priv->rq[i].xdp_rxq);
return err;
}
-static void veth_disable_xdp_range(struct net_device *dev, int start, int end,
- bool delete_napi)
+static void veth_disable_xdp_range(struct net_device *dev, int start, int end)
{
struct veth_priv *priv = netdev_priv(dev);
int i;
@@ -1175,9 +1167,6 @@ static void veth_disable_xdp_range(struct net_device *dev, int start, int end,
rq->xdp_rxq.mem = rq->xdp_mem;
xdp_rxq_info_unreg(&rq->xdp_rxq);
-
- if (delete_napi)
- netif_napi_del(&rq->xdp_napi);
}
}
@@ -1188,14 +1177,15 @@ static int veth_enable_xdp(struct net_device *dev)
int err, i;
if (!xdp_rxq_info_is_reg(&priv->rq[0].xdp_rxq)) {
- err = veth_enable_xdp_range(dev, 0, dev->real_num_rx_queues, napi_already_on);
+ err = veth_enable_xdp_range(dev, 0, dev->real_num_rx_queues);
if (err)
return err;
if (!napi_already_on) {
- err = __veth_napi_enable(dev);
+ err = veth_napi_enable(dev);
if (err) {
- veth_disable_xdp_range(dev, 0, dev->real_num_rx_queues, true);
+ veth_disable_xdp_range(dev, 0,
+ dev->real_num_rx_queues);
return err;
}
}
@@ -1220,35 +1210,7 @@ static void veth_disable_xdp(struct net_device *dev)
if (!netif_running(dev) || !veth_gro_requested(dev))
veth_napi_del(dev);
- veth_disable_xdp_range(dev, 0, dev->real_num_rx_queues, false);
-}
-
-static int veth_napi_enable_range(struct net_device *dev, int start, int end)
-{
- struct veth_priv *priv = netdev_priv(dev);
- int err, i;
-
- for (i = start; i < end; i++) {
- struct veth_rq *rq = &priv->rq[i];
-
- netif_napi_add(dev, &rq->xdp_napi, veth_poll);
- }
-
- err = __veth_napi_enable_range(dev, start, end);
- if (err) {
- for (i = start; i < end; i++) {
- struct veth_rq *rq = &priv->rq[i];
-
- netif_napi_del(&rq->xdp_napi);
- }
- return err;
- }
- return err;
-}
-
-static int veth_napi_enable(struct net_device *dev)
-{
- return veth_napi_enable_range(dev, 0, dev->real_num_rx_queues);
+ veth_disable_xdp_range(dev, 0, dev->real_num_rx_queues);
}
static void veth_disable_range_safe(struct net_device *dev, int start, int end)
@@ -1260,7 +1222,7 @@ static void veth_disable_range_safe(struct net_device *dev, int start, int end)
if (priv->_xdp_prog) {
veth_napi_del_range(dev, start, end);
- veth_disable_xdp_range(dev, start, end, false);
+ veth_disable_xdp_range(dev, start, end);
} else if (veth_gro_requested(dev)) {
veth_napi_del_range(dev, start, end);
}
@@ -1275,17 +1237,13 @@ static int veth_enable_range_safe(struct net_device *dev, int start, int end)
return 0;
if (priv->_xdp_prog) {
- /* these channels are freshly initialized, napi is not on there even
- * when GRO is requeste
- */
- err = veth_enable_xdp_range(dev, start, end, false);
+ err = veth_enable_xdp_range(dev, start, end);
if (err)
return err;
- err = __veth_napi_enable_range(dev, start, end);
+ err = veth_napi_enable_range(dev, start, end);
if (err) {
- /* on error always delete the newly added napis */
- veth_disable_xdp_range(dev, start, end, true);
+ veth_disable_xdp_range(dev, start, end);
return err;
}
} else if (veth_gro_requested(dev)) {
--
2.56.0
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH net-next v3 2/5] veth: link RX queues to their NAPI instances
2026-11-15 19:35 [PATCH net-next v3 0/5] veth: link RX queues to their NAPI instances Tianyi Gao
2026-11-15 19:35 ` [PATCH net-next v3 1/5] veth: refactor NAPI enable paths Tianyi Gao
@ 2026-11-15 19:35 ` Tianyi Gao
2026-11-15 19:35 ` [PATCH net-next v3 3/5] selftests: net: veth: test RX queue NAPI links Tianyi Gao
` (2 subsequent siblings)
4 siblings, 0 replies; 6+ messages in thread
From: Tianyi Gao @ 2026-11-15 19:35 UTC (permalink / raw)
To: netdev
Cc: andrew+netdev, davem, edumazet, kuba, pabeni, toke, lorenzo,
horms, shuah, ast, daniel, hawk, john.fastabend, sdf, joe,
linux-kselftest, bpf, kernel-team, tianyi.gao, Tianyi Gao
veth does not link its RX queues to their NAPI instances. queue-get
therefore reports no napi-id for them. napi-get lists the NAPI instances
of a veth, and their thread PIDs when NAPI is threaded. It does not show
which RX queue each instance polls. Userspace cannot tell which NAPI
thread to pin for a given queue, or which NAPI to change with napi-set.
There is also no way to busy poll an AF_XDP socket bound to a veth
queue. Since commit b95ed5517354 ("xsk: Bring back busy polling support
in XDP_COPY"), xsk_bind() takes the NAPI ID of a copy-mode socket from
rxq->napi. veth never sets rxq->napi, so the socket gets no NAPI ID.
Call netif_queue_set_napi() after napi_enable(), which assigns the NAPI
ID. Call it again with NULL before napi_disable(). veth is not ops
locked, so netif_queue_set_napi() requires RTNL. veth enables and
disables NAPI only in ndo_open, ndo_stop, ndo_bpf, ndo_set_features and
ethtool's set_channels. All of them are called under RTNL.
Suggested-by: Jesper Dangaard Brouer <hawk@kernel.org>
Signed-off-by: Tianyi Gao <tianyi@cloudflare.com>
---
drivers/net/veth.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/drivers/net/veth.c b/drivers/net/veth.c
index 3cbedb8bad53..470c4f95e4a1 100644
--- a/drivers/net/veth.c
+++ b/drivers/net/veth.c
@@ -1064,6 +1064,8 @@ static int veth_napi_enable_range(struct net_device *dev, int start, int end)
rcu_assign_pointer(rq->xdp_prog, priv->_xdp_prog);
napi_enable(&rq->xdp_napi);
+ netif_queue_set_napi(dev, i, NETDEV_QUEUE_TYPE_RX,
+ &rq->xdp_napi);
rcu_assign_pointer(priv->rq[i].napi, &priv->rq[i].xdp_napi);
}
@@ -1096,6 +1098,7 @@ static void veth_napi_del_range(struct net_device *dev, int start, int end)
struct veth_rq *rq = &priv->rq[i];
rcu_assign_pointer(priv->rq[i].napi, NULL);
+ netif_queue_set_napi(dev, i, NETDEV_QUEUE_TYPE_RX, NULL);
napi_disable(&rq->xdp_napi);
rcu_assign_pointer(rq->xdp_prog, NULL);
__netif_napi_del(&rq->xdp_napi);
--
2.56.0
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH net-next v3 3/5] selftests: net: veth: test RX queue NAPI links
2026-11-15 19:35 [PATCH net-next v3 0/5] veth: link RX queues to their NAPI instances Tianyi Gao
2026-11-15 19:35 ` [PATCH net-next v3 1/5] veth: refactor NAPI enable paths Tianyi Gao
2026-11-15 19:35 ` [PATCH net-next v3 2/5] veth: link RX queues to their NAPI instances Tianyi Gao
@ 2026-11-15 19:35 ` Tianyi Gao
2026-11-15 19:35 ` [PATCH net-next v3 4/5] veth: use persistent NAPI config Tianyi Gao
2026-11-15 19:35 ` [PATCH net-next v3 5/5] selftests: net: veth: test that RX queues keep their NAPI IDs Tianyi Gao
4 siblings, 0 replies; 6+ messages in thread
From: Tianyi Gao @ 2026-11-15 19:35 UTC (permalink / raw)
To: netdev
Cc: andrew+netdev, davem, edumazet, kuba, pabeni, toke, lorenzo,
horms, shuah, ast, daniel, hawk, john.fastabend, sdf, joe,
linux-kselftest, bpf, kernel-team, tianyi.gao, Tianyi Gao
Add checks that each RX queue is linked to a NAPI instance of the
device while NAPI is enabled, and is not linked otherwise.
chk_queue_napi() reads queue-get and napi-get with the ynl CLI, as the
ndo-xmit checks do. It checks with jq that the napi-ids of the RX queues
are the IDs of the NAPI instances, and that the expected number of
queues is linked. The checks run with GRO on and with XDP attached, and
across RX channel changes and link down/up. They are skipped if the ynl
CLI or jq is not found.
Signed-off-by: Tianyi Gao <tianyi@cloudflare.com>
---
tools/testing/selftests/net/veth.sh | 79 ++++++++++++++++++++++++++++-
1 file changed, 78 insertions(+), 1 deletion(-)
diff --git a/tools/testing/selftests/net/veth.sh b/tools/testing/selftests/net/veth.sh
index 64c2a5a59821..685209995485 100755
--- a/tools/testing/selftests/net/veth.sh
+++ b/tools/testing/selftests/net/veth.sh
@@ -110,6 +110,44 @@ chk_xdp_feature() {
fi
}
+chk_queue_napi() {
+ local msg="$1"
+ local target=$2
+ local expected=$3
+ local ns=$BASE$target
+ local ifindex
+ local queues
+ local napis
+ local st
+ local linked
+
+ ifindex=`ip netns exec $ns cat /sys/class/net/veth$target/ifindex`
+ queues=`ip netns exec $ns "$YNL" --family netdev --dump queue-get \
+ --output-json --json "{\"ifindex\": $ifindex}" 2>&1`
+ st=$?
+ napis=`ip netns exec $ns "$YNL" --family netdev --dump napi-get \
+ --output-json --json "{\"ifindex\": $ifindex}" 2>&1` || st=$?
+
+ printf "%-60s" "$msg"
+ if [ $st -ne 0 ]; then
+ echo " fail - ynl cli error: $queues $napis"
+ ret=1
+ return
+ fi
+
+ queues=`echo "$queues" | \
+ jq -c 'map(select(.type == "rx") | ."napi-id" // empty) | sort'`
+ napis=`echo "$napis" | jq -c 'map(.id) | sort'`
+ linked=`echo "$queues" | jq length`
+
+ if [ "$queues" = "$napis" ] && [ "$linked" = "$expected" ]; then
+ echo " ok "
+ else
+ echo " fail - expected $expected found $queues napis $napis"
+ ret=1
+ fi
+}
+
chk_channels() {
local msg="$1"
local target=$2
@@ -330,7 +368,8 @@ fi
[ $CPUS -lt 2 ] && echo "Only one CPU available, some tests will be skipped"
[ $STRESS -gt 0 -a $CPUS -lt 3 ] && echo " stress test will be skipped, too"
-[ ! -f "$YNL" ] && echo "ynl cli not found, ndo-xmit tests will be skipped"
+[ ! -f "$YNL" ] && echo "ynl cli not found, ndo-xmit/napi tests will be skipped"
+[ ! -x "$(command -v jq)" ] && echo "jq not found, napi tests will be skipped"
chk_channels_carrier up up || ret=1
chk_channels_carrier up down || ret=1
@@ -443,6 +482,44 @@ else
fi
cleanup
+if [ -f "$YNL" ] && [ -x "$(command -v jq)" ]; then
+ create_ns
+ RXQ=1
+ if [ $CPUS -gt 1 ]; then
+ ip netns exec $NS_DST ethtool -L veth$DST rx 2
+ RXQ=2
+ fi
+ chk_queue_napi "queue napi - default" $DST 0
+ ip netns exec $NS_DST ethtool -K veth$DST gro on
+ chk_queue_napi " - with gro on" $DST $RXQ
+ if [ $CPUS -gt 1 ]; then
+ ip netns exec $NS_DST ethtool -L veth$DST rx 1
+ chk_queue_napi " - fewer rx channels with gro" $DST 1
+ ip netns exec $NS_DST ethtool -L veth$DST rx 2
+ chk_queue_napi " - more rx channels with gro" $DST 2
+ fi
+ ip -n $NS_DST link set dev veth$DST xdp object ${BPF_FILE} section xdp
+ chk_queue_napi " - with gro and xdp on" $DST $RXQ
+ ip -n $NS_DST link set dev veth$DST xdp off
+ chk_queue_napi " - after xdp off with gro on" $DST $RXQ
+ ip netns exec $NS_DST ethtool -K veth$DST gro off
+ chk_queue_napi " - after gro off" $DST 0
+ ip -n $NS_DST link set dev veth$DST xdp object ${BPF_FILE} section xdp
+ chk_queue_napi " - with xdp on" $DST $RXQ
+ if [ $CPUS -gt 1 ]; then
+ ip netns exec $NS_DST ethtool -L veth$DST rx 1
+ chk_queue_napi " - fewer rx channels with xdp" $DST 1
+ ip netns exec $NS_DST ethtool -L veth$DST rx 2
+ chk_queue_napi " - more rx channels with xdp" $DST 2
+ fi
+ ip -n $NS_DST link set dev veth$DST down
+ ip -n $NS_DST link set dev veth$DST up
+ chk_queue_napi " - after down and up" $DST $RXQ
+ ip -n $NS_DST link set dev veth$DST xdp off
+ chk_queue_napi " - after xdp off" $DST 0
+ cleanup
+fi
+
create_ns
CUR_TX=1
--
2.56.0
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH net-next v3 4/5] veth: use persistent NAPI config
2026-11-15 19:35 [PATCH net-next v3 0/5] veth: link RX queues to their NAPI instances Tianyi Gao
` (2 preceding siblings ...)
2026-11-15 19:35 ` [PATCH net-next v3 3/5] selftests: net: veth: test RX queue NAPI links Tianyi Gao
@ 2026-11-15 19:35 ` Tianyi Gao
2026-11-15 19:35 ` [PATCH net-next v3 5/5] selftests: net: veth: test that RX queues keep their NAPI IDs Tianyi Gao
4 siblings, 0 replies; 6+ messages in thread
From: Tianyi Gao @ 2026-11-15 19:35 UTC (permalink / raw)
To: netdev
Cc: andrew+netdev, davem, edumazet, kuba, pabeni, toke, lorenzo,
horms, shuah, ast, daniel, hawk, john.fastabend, sdf, joe,
linux-kselftest, bpf, kernel-team, tianyi.gao, Tianyi Gao
veth deletes the NAPI instances on link down, when NAPI is no longer
needed for GRO or XDP, and when ethtool -L reduces the number of RX
queues. When veth adds them again, each queue gets a new NAPI ID and
loses its per-NAPI settings. An AF_XDP socket bound to the queue keeps
the old NAPI ID, so its busy polling stops.
Use netif_napi_add_config(), as Documentation/networking/napi.rst asks
drivers to do whenever possible. The queue then keeps its NAPI ID and
its settings. virtio_net made the same change in commit d5d715207e29
("virtio_net: Use persistent NAPI config").
Signed-off-by: Tianyi Gao <tianyi@cloudflare.com>
---
New in v3, as Sashiko suggested on v2 [1].
[1] https://lore.kernel.org/all/179470883411.2199510.13825316417997386083@kernel.org/
---
drivers/net/veth.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/net/veth.c b/drivers/net/veth.c
index 470c4f95e4a1..1c7ee3bf65f0 100644
--- a/drivers/net/veth.c
+++ b/drivers/net/veth.c
@@ -1057,7 +1057,7 @@ static int veth_napi_enable_range(struct net_device *dev, int start, int end)
}
for (i = start; i < end; i++)
- netif_napi_add(dev, &priv->rq[i].xdp_napi, veth_poll);
+ netif_napi_add_config(dev, &priv->rq[i].xdp_napi, veth_poll, i);
for (i = start; i < end; i++) {
struct veth_rq *rq = &priv->rq[i];
--
2.56.0
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH net-next v3 5/5] selftests: net: veth: test that RX queues keep their NAPI IDs
2026-11-15 19:35 [PATCH net-next v3 0/5] veth: link RX queues to their NAPI instances Tianyi Gao
` (3 preceding siblings ...)
2026-11-15 19:35 ` [PATCH net-next v3 4/5] veth: use persistent NAPI config Tianyi Gao
@ 2026-11-15 19:35 ` Tianyi Gao
4 siblings, 0 replies; 6+ messages in thread
From: Tianyi Gao @ 2026-11-15 19:35 UTC (permalink / raw)
To: netdev
Cc: andrew+netdev, davem, edumazet, kuba, pabeni, toke, lorenzo,
horms, shuah, ast, daniel, hawk, john.fastabend, sdf, joe,
linux-kselftest, bpf, kernel-team, tianyi.gao, Tianyi Gao
Add a check that each RX queue keeps its NAPI ID when veth deletes its
NAPI instance and adds it again.
get_napi_ids() reads the NAPI ID of each RX queue with the ynl CLI. The
test saves the IDs once GRO is on. chk_napi_ids() compares them with
the saved IDs after ethtool -L raises the number of RX queues, after
XDP is attached with GRO off, and after link down/up. A failed read
fails the check.
Signed-off-by: Tianyi Gao <tianyi@cloudflare.com>
---
tools/testing/selftests/net/veth.sh | 29 +++++++++++++++++++++++++++++
1 file changed, 29 insertions(+)
diff --git a/tools/testing/selftests/net/veth.sh b/tools/testing/selftests/net/veth.sh
index 685209995485..9496b599d722 100755
--- a/tools/testing/selftests/net/veth.sh
+++ b/tools/testing/selftests/net/veth.sh
@@ -148,6 +148,30 @@ chk_queue_napi() {
fi
}
+get_napi_ids() {
+ local ns=$BASE$1
+ local ifindex
+
+ ifindex=`ip netns exec $ns cat /sys/class/net/veth$1/ifindex`
+ ip netns exec $ns "$YNL" --family netdev --dump queue-get \
+ --output-json --json "{\"ifindex\": $ifindex}" |
+ jq -c 'sort_by(.id) | map(select(.type == "rx") | ."napi-id")'
+}
+
+chk_napi_ids() {
+ local msg="$1"
+ local ids
+
+ ids=`get_napi_ids $2`
+ printf "%-60s" "$msg"
+ if [ -n "$ids" ] && [ "$ids" = "$NAPI_IDS" ]; then
+ echo " ok "
+ else
+ echo " fail - expected $NAPI_IDS found $ids"
+ ret=1
+ fi
+}
+
chk_channels() {
local msg="$1"
local target=$2
@@ -492,11 +516,13 @@ if [ -f "$YNL" ] && [ -x "$(command -v jq)" ]; then
chk_queue_napi "queue napi - default" $DST 0
ip netns exec $NS_DST ethtool -K veth$DST gro on
chk_queue_napi " - with gro on" $DST $RXQ
+ NAPI_IDS=`get_napi_ids $DST`
if [ $CPUS -gt 1 ]; then
ip netns exec $NS_DST ethtool -L veth$DST rx 1
chk_queue_napi " - fewer rx channels with gro" $DST 1
ip netns exec $NS_DST ethtool -L veth$DST rx 2
chk_queue_napi " - more rx channels with gro" $DST 2
+ chk_napi_ids " - same napi ids" $DST
fi
ip -n $NS_DST link set dev veth$DST xdp object ${BPF_FILE} section xdp
chk_queue_napi " - with gro and xdp on" $DST $RXQ
@@ -506,15 +532,18 @@ if [ -f "$YNL" ] && [ -x "$(command -v jq)" ]; then
chk_queue_napi " - after gro off" $DST 0
ip -n $NS_DST link set dev veth$DST xdp object ${BPF_FILE} section xdp
chk_queue_napi " - with xdp on" $DST $RXQ
+ chk_napi_ids " - same napi ids" $DST
if [ $CPUS -gt 1 ]; then
ip netns exec $NS_DST ethtool -L veth$DST rx 1
chk_queue_napi " - fewer rx channels with xdp" $DST 1
ip netns exec $NS_DST ethtool -L veth$DST rx 2
chk_queue_napi " - more rx channels with xdp" $DST 2
+ chk_napi_ids " - same napi ids" $DST
fi
ip -n $NS_DST link set dev veth$DST down
ip -n $NS_DST link set dev veth$DST up
chk_queue_napi " - after down and up" $DST $RXQ
+ chk_napi_ids " - same napi ids" $DST
ip -n $NS_DST link set dev veth$DST xdp off
chk_queue_napi " - after xdp off" $DST 0
cleanup
--
2.56.0
^ permalink raw reply related [flat|nested] 6+ messages in thread
end of thread, other threads:[~2026-11-15 19:35 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-11-15 19:35 [PATCH net-next v3 0/5] veth: link RX queues to their NAPI instances Tianyi Gao
2026-11-15 19:35 ` [PATCH net-next v3 1/5] veth: refactor NAPI enable paths Tianyi Gao
2026-11-15 19:35 ` [PATCH net-next v3 2/5] veth: link RX queues to their NAPI instances Tianyi Gao
2026-11-15 19:35 ` [PATCH net-next v3 3/5] selftests: net: veth: test RX queue NAPI links Tianyi Gao
2026-11-15 19:35 ` [PATCH net-next v3 4/5] veth: use persistent NAPI config Tianyi Gao
2026-11-15 19:35 ` [PATCH net-next v3 5/5] selftests: net: veth: test that RX queues keep their NAPI IDs Tianyi Gao
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox