* [PATCH net-next v2 0/3] veth: link RX queues to their NAPI instances
@ 2026-11-11 1:59 Tianyi Gao
2026-11-11 1:59 ` [PATCH net-next v2 1/3] veth: refactor NAPI enable paths Tianyi Gao
` (2 more replies)
0 siblings, 3 replies; 6+ messages in thread
From: Tianyi Gao @ 2026-11-11 1:59 UTC (permalink / raw)
To: netdev
Cc: andrew+netdev, davem, edumazet, kuba, pabeni, toke, lorenzo,
horms, bpf, shuah, hawk, kernel-team, ast, daniel, john.fastabend,
sdf, linux-kselftest, 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. 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 the loop that enables the NAPI instances. It also
removes the arguments and wrappers that came with adding the NAPI
instances in two places.
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-id of every
RX queue must match a NAPI instance 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.
---
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 (3):
veth: refactor NAPI enable paths
veth: link RX queues to their NAPI instances
selftests: net: veth: test RX queue NAPI links
drivers/net/veth.c | 83 ++++++++---------------------
tools/testing/selftests/net/veth.sh | 79 ++++++++++++++++++++++++++-
2 files changed, 99 insertions(+), 63 deletions(-)
base-commit: 79ee9e6768721f337952e9b3edd14cedbbc03030
--
2.56.0
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH net-next v2 1/3] veth: refactor NAPI enable paths
2026-11-11 1:59 [PATCH net-next v2 0/3] veth: link RX queues to their NAPI instances Tianyi Gao
@ 2026-11-11 1:59 ` Tianyi Gao
2026-11-15 2:13 ` netdev-bot+sashiko
2026-11-11 1:59 ` [PATCH net-next v2 2/3] veth: link RX queues to their NAPI instances Tianyi Gao
2026-11-11 1:59 ` [PATCH net-next v2 3/3] selftests: net: veth: test RX queue NAPI links Tianyi Gao
2 siblings, 1 reply; 6+ messages in thread
From: Tianyi Gao @ 2026-11-11 1:59 UTC (permalink / raw)
To: netdev
Cc: andrew+netdev, davem, edumazet, kuba, pabeni, toke, lorenzo,
horms, bpf, shuah, hawk, kernel-team, ast, daniel, john.fastabend,
sdf, linux-kselftest, 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 each instance in the loop that enables
it, after the allocations that can fail. 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>
---
drivers/net/veth.c | 80 +++++++++++-----------------------------------
1 file changed, 18 insertions(+), 62 deletions(-)
diff --git a/drivers/net/veth.c b/drivers/net/veth.c
index 0539b3661793..f5097696df15 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;
@@ -1059,6 +1059,7 @@ static int __veth_napi_enable_range(struct net_device *dev, int start, int end)
for (i = start; i < end; i++) {
struct veth_rq *rq = &priv->rq[i];
+ netif_napi_add(dev, &rq->xdp_napi, veth_poll);
rcu_assign_pointer(rq->xdp_prog, priv->_xdp_prog);
napi_enable(&rq->xdp_napi);
rcu_assign_pointer(priv->rq[i].napi, &priv->rq[i].xdp_napi);
@@ -1079,9 +1080,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 +1123,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 +1131,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 +1149,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 +1165,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 +1175,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 +1208,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 +1220,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 +1235,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 v2 2/3] veth: link RX queues to their NAPI instances
2026-11-11 1:59 [PATCH net-next v2 0/3] veth: link RX queues to their NAPI instances Tianyi Gao
2026-11-11 1:59 ` [PATCH net-next v2 1/3] veth: refactor NAPI enable paths Tianyi Gao
@ 2026-11-11 1:59 ` Tianyi Gao
2026-11-15 2:13 ` netdev-bot+sashiko
2026-11-11 1:59 ` [PATCH net-next v2 3/3] selftests: net: veth: test RX queue NAPI links Tianyi Gao
2 siblings, 1 reply; 6+ messages in thread
From: Tianyi Gao @ 2026-11-11 1:59 UTC (permalink / raw)
To: netdev
Cc: andrew+netdev, davem, edumazet, kuba, pabeni, toke, lorenzo,
horms, bpf, shuah, hawk, kernel-team, ast, daniel, john.fastabend,
sdf, linux-kselftest, 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 f5097696df15..c04277186405 100644
--- a/drivers/net/veth.c
+++ b/drivers/net/veth.c
@@ -1062,6 +1062,8 @@ static int veth_napi_enable_range(struct net_device *dev, int start, int end)
netif_napi_add(dev, &rq->xdp_napi, veth_poll);
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);
}
@@ -1094,6 +1096,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 v2 3/3] selftests: net: veth: test RX queue NAPI links
2026-11-11 1:59 [PATCH net-next v2 0/3] veth: link RX queues to their NAPI instances Tianyi Gao
2026-11-11 1:59 ` [PATCH net-next v2 1/3] veth: refactor NAPI enable paths Tianyi Gao
2026-11-11 1:59 ` [PATCH net-next v2 2/3] veth: link RX queues to their NAPI instances Tianyi Gao
@ 2026-11-11 1:59 ` Tianyi Gao
2 siblings, 0 replies; 6+ messages in thread
From: Tianyi Gao @ 2026-11-11 1:59 UTC (permalink / raw)
To: netdev
Cc: andrew+netdev, davem, edumazet, kuba, pabeni, toke, lorenzo,
horms, bpf, shuah, hawk, kernel-team, ast, daniel, john.fastabend,
sdf, linux-kselftest, Tianyi Gao
Check that the napi-id of every RX queue matches a NAPI instance of the
device. Also check that the queues are linked only while NAPI is
enabled. Run the checks with GRO on and with XDP attached, and across RX
channel changes and link down/up.
queue-get and napi-get are only visible through netlink. Read them with
the ynl CLI, as the ndo-xmit checks do. Compare the results with jq.
Skip the checks 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
* Re: [PATCH net-next v2 1/3] veth: refactor NAPI enable paths
2026-11-11 1:59 ` [PATCH net-next v2 1/3] veth: refactor NAPI enable paths Tianyi Gao
@ 2026-11-15 2:13 ` netdev-bot+sashiko
0 siblings, 0 replies; 6+ messages in thread
From: netdev-bot+sashiko @ 2026-11-15 2:13 UTC (permalink / raw)
To: tianyi
Cc: netdev, andrew+netdev, davem, edumazet, kuba, pabeni, toke,
lorenzo, horms, bpf, shuah, hawk, kernel-team, ast, daniel,
john.fastabend, sdf, linux-kselftest
Thank you for your contribution! Sashiko AI review found more severe
issue(s) in other patches of this series. This mail is only an FYI, in case
you want to address the nit picks below when you respin.
Low priority / nit picks for your consideration:
- [Low] This patch changes the order of NAPI setup in
veth_napi_enable_range() (drivers/net/veth.c).
--
veth: refactor NAPI enable paths
This patch stops passing rq->xdp_napi.napi_id to xdp_rxq_info_reg(). It
moves netif_napi_add() out of veth_enable_xdp_range() and the old
veth_napi_enable_range() wrapper and into the loop in
__veth_napi_enable_range() that enables each NAPI. The trivial wrappers
are removed, and the double-underscore helpers take over their names.
> diff --git a/drivers/net/veth.c b/drivers/net/veth.c
> index 0539b3661793d..f5097696df15e 100644
> --- a/drivers/net/veth.c
> +++ b/drivers/net/veth.c
[ ... ]
> @@ -1059,6 +1059,7 @@ static int __veth_napi_enable_range(struct net_device *dev, int start, int end)
> for (i = start; i < end; i++) {
> struct veth_rq *rq = &priv->rq[i];
>
> + netif_napi_add(dev, &rq->xdp_napi, veth_poll);
> rcu_assign_pointer(rq->xdp_prog, priv->_xdp_prog);
> napi_enable(&rq->xdp_napi);
[Severity: Low]
Can this leave a veth device with threaded NAPI half on and half off?
Before this patch, every caller added all NAPIs in the range before it
enabled any of them. The core seems to depend on that order.
netif_napi_add_weight_locked() in net/core/dev.c says:
/* Create kthread for this napi if dev->threaded is set.
* Clear dev->threaded if kthread creation failed so that
* threaded mode will not be enabled in napi_enable().
*/
if (napi_get_threaded_config(dev, napi))
if (napi_kthread_create(napi))
dev->threaded = NETDEV_NAPI_THREADED_DISABLED;
napi_enable_locked() reads dev->threaded at the time it runs:
if (n->dev->threaded && n->thread)
new |= NAPIF_STATE_THREADED;
With add and enable now in the same loop, suppose threaded mode is on and
napi_kthread_create() fails for some queue k > start. Queues start..k-1
have already been enabled with NAPIF_STATE_THREADED. Queue k and the
queues after it come up non-threaded, and dev->threaded is cleared.
The device then reports threaded mode as disabled through sysfs and
netlink, while some of its NAPIs are still polled by kthreads. This can
happen in any path that reaches veth_napi_enable_range():
veth_set_features() toggling GRO, veth_set_channels() calling
veth_enable_range_safe(), veth_open(), and veth_enable_xdp(). The
kthread_run() failure can come from ENOMEM or from a pending fatal
signal.
netif_set_threaded() avoids this state by reverting all NAPIs when
kthread creation fails, but this path doesn't do that.
Could netif_napi_add() stay in its own loop over the whole range? It
could sit after the page_pool and ptr_ring allocations that can fail and
before the napi_enable() loop. That would keep the new error handling
and the old ordering.
[ ... ]
--
Sashiko AI review · https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20261111015922.67745-1-tianyi%40cloudflare.com
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH net-next v2 2/3] veth: link RX queues to their NAPI instances
2026-11-11 1:59 ` [PATCH net-next v2 2/3] veth: link RX queues to their NAPI instances Tianyi Gao
@ 2026-11-15 2:13 ` netdev-bot+sashiko
0 siblings, 0 replies; 6+ messages in thread
From: netdev-bot+sashiko @ 2026-11-15 2:13 UTC (permalink / raw)
To: tianyi
Cc: netdev, andrew+netdev, davem, edumazet, kuba, pabeni, toke,
lorenzo, horms, bpf, shuah, hawk, kernel-team, ast, daniel,
john.fastabend, sdf, linux-kselftest
Thank you for your contribution! Sashiko AI review found 1 potential
issue(s) to consider.
Critical: 0 · High: 0 · Medium: 1 · Low: 0
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] In drivers/net/veth.c, veth_napi_enable_range() still creates
the per-queue NAPI with plain netif_napi_add(dev, &rq->xdp_napi,…
--
veth: link RX queues to their NAPI instances
This patch links each veth RX queue to its NAPI instance with
netif_queue_set_napi(). The link is set after napi_enable() and cleared
before napi_disable(). With it, queue-get reports a napi-id, and AF_XDP
copy-mode sockets bound to a veth queue get a NAPI ID for busy polling.
> diff --git a/drivers/net/veth.c b/drivers/net/veth.c
> index f5097696df15e..c042771864051 100644
> --- a/drivers/net/veth.c
> +++ b/drivers/net/veth.c
> @@ -1062,6 +1062,8 @@ static int veth_napi_enable_range(struct net_device *dev, int start, int end)
> netif_napi_add(dev, &rq->xdp_napi, veth_poll);
> 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);
[Severity: Medium]
Should this be netif_napi_add_config(dev, &rq->xdp_napi, veth_poll, i)
rather than netif_napi_add()?
As written, the queue-to-NAPI link only holds until the next
reconfiguration. veth_napi_del_range() deletes the NAPI completely, via
napi_disable() and then __netif_napi_del(). On the next enable,
napi_enable_locked() finds no n->config and allocates a new ID:
net/core/dev.c:napi_enable_locked() {
...
if (n->config)
napi_restore_config(n);
else
napi_hash_add(n);
...
}
So the same queue gets a new napi-id after each of these:
- ip link set down/up (veth_close()/veth_open())
- XDP detach and re-attach (veth_xdp_set())
- a GRO toggle without XDP (veth_set_features())
- ethtool -L (veth_disable_range_safe()/veth_enable_range_safe())
Any per-NAPI settings applied with napi-set are dropped silently on each
of these paths. That covers defer-hard-irqs, gro-flush-timeout,
irq-suspend-timeout and threaded.
An AF_XDP copy-mode socket is affected the same way. xsk_bind() records
the ID only once:
net/xdp/xsk.c:xsk_bind() {
...
if (rxq->napi)
__sk_mark_napi_id_once(sk, rxq->napi->napi_id);
...
}
The xsk notifier only unbinds on NETDEV_UNREGISTER, so the socket stays
bound across a down/up and keeps the old ID. Would sk_busy_loop() then
call napi_busy_loop() with an ID that no longer resolves, so busy polling
stops without any error?
The commit message gives napi-set and AF_XDP busy polling as the
motivation. Documentation/networking/napi.rst ("Persistent NAPI config")
says "Drivers should try to use netif_napi_add_config() whenever
possible." The queue index i is already available here, and
dev->napi_config has max(num_tx_queues, num_rx_queues) entries.
The selftest added later in this series ("selftests: net: veth: test RX
queue NAPI links") checks that the IDs match napi-get after each step.
It does not check that they stay the same across these reconfigurations.
> rcu_assign_pointer(priv->rq[i].napi, &priv->rq[i].xdp_napi);
> }
>
[ ... ]
--
Sashiko AI review · https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20261111015922.67745-1-tianyi%40cloudflare.com
^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2026-11-15 2:13 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-11-11 1:59 [PATCH net-next v2 0/3] veth: link RX queues to their NAPI instances Tianyi Gao
2026-11-11 1:59 ` [PATCH net-next v2 1/3] veth: refactor NAPI enable paths Tianyi Gao
2026-11-15 2:13 ` netdev-bot+sashiko
2026-11-11 1:59 ` [PATCH net-next v2 2/3] veth: link RX queues to their NAPI instances Tianyi Gao
2026-11-15 2:13 ` netdev-bot+sashiko
2026-11-11 1:59 ` [PATCH net-next v2 3/3] selftests: net: veth: test RX queue NAPI links Tianyi Gao
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox