Re: [PATCH net V1 3/3] veth: more robust handing of race to avoid txq getting stuck

From: Jesper Dangaard Brouer
Date: Mon Oct 27 2025 - 15:30:02 EST




On 23/10/2025 16.59, Jesper Dangaard Brouer wrote:
[...]
---
drivers/net/veth.c | 42 +++++++++++++++++++++---------------------
1 file changed, 21 insertions(+), 21 deletions(-)

diff --git a/drivers/net/veth.c b/drivers/net/veth.c
index 3976ddda5fb8..1d70377481eb 100644
--- a/drivers/net/veth.c
+++ b/drivers/net/veth.c
@@ -392,14 +392,12 @@ static netdev_tx_t veth_xmit(struct sk_buff *skb, struct net_device *dev)
}
/* Restore Eth hdr pulled by dev_forward_skb/eth_type_trans */
__skb_push(skb, ETH_HLEN);
- /* Depend on prior success packets started NAPI consumer via
- * __veth_xdp_flush(). Cancel TXQ stop if consumer stopped,
- * paired with empty check in veth_poll().
- */
netif_tx_stop_queue(txq);
- smp_mb__after_atomic();
- if (unlikely(__ptr_ring_empty(&rq->xdp_ring)))
- netif_tx_wake_queue(txq);
+ /* Handle race: Makes sure NAPI peer consumer runs. Consumer is
+ * responsible for starting txq again, until then ndo_start_xmit
+ * (this function) will not be invoked by the netstack again.
+ */
+ __veth_xdp_flush(rq);
break;
case NET_RX_DROP: /* same as NET_XMIT_DROP */
drop:
[...]
@@ -986,7 +979,8 @@ static int veth_poll(struct napi_struct *napi, int budget)
if (done < budget && napi_complete_done(napi, done)) {
/* Write rx_notify_masked before reading ptr_ring */
smp_store_mb(rq->rx_notify_masked, false);
- if (unlikely(!__ptr_ring_empty(&rq->xdp_ring))) {
+ if (unlikely(!__ptr_ring_empty(&rq->xdp_ring) ||
+ (peer_txq && netif_tx_queue_stopped(peer_txq)))) {
if (napi_schedule_prep(&rq->xdp_napi)) {
WRITE_ONCE(rq->rx_notify_masked, true);
__napi_schedule(&rq->xdp_napi);
@@ -998,6 +992,12 @@ static int veth_poll(struct napi_struct *napi, int budget)
veth_xdp_flush(rq, &bq);
xdp_clear_return_frame_no_direct();
+ /* Release backpressure per NAPI poll */
+ if (peer_txq && netif_tx_queue_stopped(peer_txq)) {
^^^^^^^^^^^^^^^^^^^^^^
The check netif_tx_queue_stopped() use a non-atomic test_bit().
Thus, I'm considering adding a smp_rmb() before the if statement, to be
paired with the netif_tx_stop_queue() in veth_xmit().


+ txq_trans_cond_update(peer_txq);
+ netif_tx_wake_queue(peer_txq);
+ }
+
return done;
}

--Jesper