veth: Fix TXQ stall race condition and add recovery
Subsystems (3)
v3 cover veth: Fix TXQ stall race condition and add recovery
This patchset addresses a race condition introduced in commit dc82a33297fc ("veth: apply qdisc backpressure on full ptr_ring to reduce TX drops"). In production, this has been observed to cause a permanently stalled transmit queue (TXQ) on ARM64 (Ampere Altra Max) systems, leading to a "lost wakeup" scenario where the TXQ remains in the QUEUE_STATE_DRV_XOFF state and traffic halts.
The root cause, which is fixed in patch 2, is a racy use of the __ptr_ring_empty() API from the producer side (veth_xmit). The producer stops the queue and then checks the ptr_ring consumer's head, but this is not guaranteed to be correct, when observed from the producer side, when the NAPI consumer on another CPU has just finished consuming.
This series fixes the bug and make the driver more resilient to recover. The patches are ordered to first add recovery mechanisms, then fix the underlying race.
V3:
- Don't keep NAPI running when detecting race, because end of veth_poll will see TXQ is stopped anyway and wake queue, making it responsibility of the producer veth_xmit to do a "flush" that restarts NAPI.
V2: https://lore.kernel.org/all/176159549627.5396.15971398227283515867.stgit@firesoul/
- Drop patch that changed up/down NDOs
- For race fix add a smb_rmb and improve commit message reasoning for race cases
V1: https://lore.kernel.org/all/176123150256.2281302.7000617032469740443.stgit@firesoul/
---
Jesper Dangaard Brouer (2):
veth: enable dev_watchdog for detecting stalled TXQs
veth: more robust handing of race to avoid txq getting stuck
drivers/net/veth.c | 50 +++++++++++++++++++++++++++++----------------- 1 file changed, 32 insertions(+), 18 deletions(-)
--
PATCH v3 1/2 veth: enable dev_watchdog for detecting stalled TXQs
The changes introduced in commit dc82a33297fc ("veth: apply qdisc backpressure on full ptr_ring to reduce TX drops") have been found to cause a race condition in production environments.
Under specific circumstances, observed exclusively on ARM64 (aarch64) systems with Ampere Altra Max CPUs, a transmit queue (TXQ) can become permanently stalled. This happens when the race condition leads to the TXQ entering the QUEUE_STATE_DRV_XOFF state without a corresponding queue wake-up, preventing the attached qdisc from dequeueing packets and causing the network link to halt.
As a first step towards resolving this issue, this patch introduces a failsafe mechanism. It enables the net device watchdog by setting a timeout value and implements the .ndo_tx_timeout callback.
If a TXQ stalls, the watchdog will trigger the veth_tx_timeout() function, which logs a warning and calls netif_tx_wake_queue() to unstall the queue and allow traffic to resume.
The log message will look like this:
veth42: NETDEV WATCHDOG: CPU: 34: transmit queue 0 timed out 5393 ms
veth42: veth backpressure stalled(n:1) TXQ(0) re-enable
This provides a necessary recovery mechanism while the underlying race condition is investigated further. Subsequent patches will address the root cause and add more robust state handling.
--- drivers/net/veth.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-)
drivers/net/veth.c +15 -1
@@ -959,8 +959,10 @@ static int veth_xdp_rcv(struct veth_rq *rq, int budget, rq->stats.vs.xdp_packets += done;u64_stats_update_end (&rq->stats.syncp); -if (peer_txq &&unlikely (netif_tx_queue_stopped (peer_txq))) +if (peer_txq &&unlikely (netif_tx_queue_stopped (peer_txq))) { +txq_trans_cond_update (peer_txq);netif_tx_wake_queue (peer_txq); + }return done; }
@@ -1373,6 +1375,16 @@ static int veth_set_channels(struct net_device *dev, goto out; } +static void veth_tx_timeout (struct net_device *dev,unsigned int txqueue) +{ +struct netdev_queue *txq =netdev_get_tx_queue (dev, txqueue); + +netdev_err (dev,"veth backpressure stalled(n:%ld) TXQ(%u) re-enable\n" , +atomic_long_read (&txq->trans_timeout), txqueue); + +netif_tx_wake_queue (txq); +} +static int veth_open (struct net_device *dev) {struct veth_priv *priv =netdev_priv (dev);
@@ -1711,6 +1723,7 @@ static const struct net_device_ops veth_netdev_ops = { .ndo_bpf = veth_xdp, .ndo_xdp_xmit = veth_ndo_xdp_xmit, .ndo_get_peer_dev = veth_peer_dev, + .ndo_tx_timeout = veth_tx_timeout, };static const struct xdp_metadata_ops veth_xdp_metadata_ops = {
@@ -1749,6 +1762,7 @@ static void veth_setup(struct net_device *dev) dev->priv_destructor = veth_dev_free; dev->pcpu_stat_type =NETDEV_PCPU_STAT_TSTATS ; dev->max_mtu =ETH_MAX_MTU ; + dev->watchdog_timeo =msecs_to_jiffies (5000 ); dev->hw_features =VETH_FEATURES ; dev->hw_enc_features =VETH_FEATURES ;
Jakub Kicinski
maintainerRe: [PATCH net V3 1/2] veth: enable dev_watchdog for detecting stalled TXQs
Quoted 24 lines · On Wed, 05 Nov 2025 18:28:12 +0100 Jesper Dangaard Brouer wrote:
The changes introduced in commit
dc82a33297fc("veth: apply qdisc backpressure on fullptr_ringto reduce TX drops") have been found to cause a race condition in production environments.Under specific circumstances, observed exclusively on ARM64 (aarch64) systems with Ampere Altra Max CPUs, a transmit queue (TXQ) can become permanently stalled. This happens when the race condition leads to the TXQ entering the
QUEUE_STATE_DRV_XOFFstate without a corresponding queue wake-up, preventing the attached qdisc from dequeueing packets and causing the network link to halt.As a first step towards resolving this issue, this patch introduces a failsafe mechanism. It enables the net device watchdog by setting a timeout value and implements the .ndo_tx_timeout callback.
If a TXQ stalls, the watchdog will trigger the
veth_tx_timeout()function, which logs a warning and callsnetif_tx_wake_queue()to unstall the queue and allow traffic to resume.The log message will look like this:
veth42: NETDEV WATCHDOG: CPU: 34: transmit queue 0 timed out 5393 ms
veth42: veth backpressure stalled(n:1) TXQ(0) re-enable
Quoted 7 lines
This provides a necessary recovery mechanism while the underlying race condition is investigated further. Subsequent patches will address the root cause and add more robust state handling.
Fixes dc82a33297fc ("veth: apply qdisc backpressure on full ptr_ring to reduce TX drops")Reviewed-by Toke Høiland-Jørgensen <[email protected]>Signed-off-by Jesper Dangaard Brouer <[email protected]>
I think this belongs in net-next.. Fail safe is not really a bug fix. I'm slightly worried we're missing a corner case and will cause timeouts to get printed for someone's config.
drivers/net/veth.c static int veth_set_channels(struct net_device *dev, · line 1383
Quoted 6 lines
drivers/net/veth.c +6
-0+static void veth_tx_timeout (struct net_device *dev,unsigned int txqueue) +{ +struct netdev_queue *txq =netdev_get_tx_queue (dev, txqueue); + +netdev_err (dev,"veth backpressure stalled(n:%ld) TXQ(%u) re-enable\n" , +atomic_long_read (&txq->trans_timeout), txqueue);
If you think the trans_timeout is useful, let's add it to the message core prints? And then we can make this msg just veth specific, I don't think we should be repeating what core already printed.
Quoted 24 lines
drivers/net/veth.c +5
-0+netif_tx_wake_queue (txq); +} +static int veth_open (struct net_device *dev) {struct veth_priv *priv =netdev_priv (dev);@@ -1711,6 +1723,7 @@ static const struct net_device_ops veth_netdev_ops = { .ndo_bpf = veth_xdp, .ndo_xdp_xmit = veth_ndo_xdp_xmit, .ndo_get_peer_dev = veth_peer_dev, + .ndo_tx_timeout = veth_tx_timeout, };static const struct xdp_metadata_ops veth_xdp_metadata_ops = {@@ -1749,6 +1762,7 @@ static void veth_setup(struct net_device *dev) dev->priv_destructor = veth_dev_free; dev->pcpu_stat_type =NETDEV_PCPU_STAT_TSTATS ; dev->max_mtu =ETH_MAX_MTU ; + dev->watchdog_timeo =msecs_to_jiffies (5000 ); dev->hw_features =VETH_FEATURES ; dev->hw_enc_features =VETH_FEATURES ;
Re: [PATCH net V3 1/2] veth: enable dev_watchdog for detecting stalled TXQs
Quoted 29 lines · Jakub Kicinski
Quoted 28 lines · On Wed, 05 Nov 2025 18:28:12 +0100 Jesper Dangaard Brouer wrote:
The changes introduced in commit
dc82a33297fc("veth: apply qdisc backpressure on fullptr_ringto reduce TX drops") have been found to cause a race condition in production environments.Under specific circumstances, observed exclusively on ARM64 (aarch64) systems with Ampere Altra Max CPUs, a transmit queue (TXQ) can become permanently stalled. This happens when the race condition leads to the TXQ entering the
QUEUE_STATE_DRV_XOFFstate without a corresponding queue wake-up, preventing the attached qdisc from dequeueing packets and causing the network link to halt.As a first step towards resolving this issue, this patch introduces a failsafe mechanism. It enables the net device watchdog by setting a timeout value and implements the .ndo_tx_timeout callback.
If a TXQ stalls, the watchdog will trigger the
veth_tx_timeout()function, which logs a warning and callsnetif_tx_wake_queue()to unstall the queue and allow traffic to resume.The log message will look like this:
veth42: NETDEV WATCHDOG: CPU: 34: transmit queue 0 timed out 5393 ms
veth42: veth backpressure stalled(n:1) TXQ(0) re-enableThis provides a necessary recovery mechanism while the underlying race condition is investigated further. Subsequent patches will address the root cause and add more robust state handling.
Quoted 8 lines
Quoted 3 lines
Fixes dc82a33297fc ("veth: apply qdisc backpressure on full ptr_ring to reduce TX drops")Reviewed-by Toke Høiland-Jørgensen <[email protected]>Signed-off-by Jesper Dangaard Brouer <[email protected]>I think this belongs in net-next.. Fail safe is not really a bug fix. I'm slightly worried we're missing a corner case and will cause timeouts to get printed for someone's config.
This is a recovery fix. If the race condition fix isn't 100% then this patch will allow veth to recover. Thus, to me it makes sense to group these two patches together.
I'm more worried that we we're missing a corner case that we cannot recover from. Than triggering timeouts to get printed, for a config where NAPI consumer veth_poll() takes more that 5 seconds to run (budget max 64 packets this needs to consume packets at a rate less than 12.8 pps). It might be good to get some warnings if the system is operating this slow.
Also remember this is not the default config that most people use. The code is only activated if attaching a qdisc to veth, which isn't default. Plus, NAPI mode need to be activated, where in normal NAPI mode the producer and consumer usually runs on the same CPU, which makes it impossible to overflow the ptr_ring. The veth backpressure is primarily needed when running with threaded-NAPI, where it is natural that producer and consumer runs on different CPUs. In our production setup the consumer is always slower than the producer (as the product inside the namespace have installed too many nftables rules).
Quoted 10 lines
drivers/net/veth.c static int veth_set_channels(struct net_device *dev, · line 1383
Quoted 6 lines
drivers/net/veth.c +6
-0+static void veth_tx_timeout (struct net_device *dev,unsigned int txqueue) +{ +struct netdev_queue *txq =netdev_get_tx_queue (dev, txqueue); + +netdev_err (dev,"veth backpressure stalled(n:%ld) TXQ(%u) re-enable\n" , +atomic_long_read (&txq->trans_timeout), txqueue);If you think the
trans_timeoutis useful, let's add it to the message core prints? And then we can make this msg just veth specific, I don't think we should be repeating what core already printed.
The trans_timeout is a counter for how many times this TXQ have seen a timeout. It is practical as it directly tell us if this a frequent event (without having to search log files for similar events).
It does make sense to add this to the core message ("NETDEV WATCHDOG") with the same argument. For physical NICs these logs are present in production. Looking at logs through Kibana (right now) and it would make my life easier to see the number of times the individual queues have experienced timeouts. The logs naturally gets spaced in time by the timeout, making it harder to tell the even frequency. Such a patch would naturally go though net-next.
Do you still want me to remove the frequency counter from this message? By the same argument it is practical for me to have as a single log line when troubleshooting this in practice. BTW, I've already backported this watchdog patch to prod kernel (without race fix) and I'll try to reproduce the race in staging/lab on some ARM64 servers. If I reproduce it will be practical to have this counter.
--Jesper
Jakub Kicinski
maintainerRe: [PATCH net V3 1/2] veth: enable dev_watchdog for detecting stalled TXQs
Quoted 15 lines · On Fri, 7 Nov 2025 14:42:58 +0100 Jesper Dangaard Brouer wrote:
Quoted 3 lines
I think this belongs in net-next.. Fail safe is not really a bug fix. I'm slightly worried we're missing a corner case and will cause timeouts to get printed for someone's config.
This is a recovery fix. If the race condition fix isn't 100% then this patch will allow veth to recover. Thus, to me it makes sense to group these two patches together.
I'm more worried that we we're missing a corner case that we cannot recover from. Than triggering timeouts to get printed, for a config where NAPI consumer
veth_poll()takes more that 5 seconds to run (budget max 64 packets this needs to consume packets at a rate less than 12.8 pps). It might be good to get some warnings if the system is operating this slow.
Quoted 9 lines
Also remember this is not the default config that most people use. The code is only activated if attaching a qdisc to veth, which isn't default. Plus, NAPI mode need to be activated, where in normal NAPI mode the producer and consumer usually runs on the same CPU, which makes it impossible to overflow the
ptr_ring. The veth backpressure is primarily needed when running with threaded-NAPI, where it is natural that producer and consumer runs on different CPUs. In our production setup the consumer is always slower than the producer (as the product inside the namespace have installed too many nftables rules).
I understand all of this, but IMO the fix is in patch 2. This is a resiliency improvement, not a fix.
Quoted 15 lines
Quoted 10 lines
drivers/net/veth.c static int veth_set_channels(struct net_device *dev, · line 1383
Quoted 6 lines
drivers/net/veth.c +6
-0+static void veth_tx_timeout (struct net_device *dev,unsigned int txqueue) +{ +struct netdev_queue *txq =netdev_get_tx_queue (dev, txqueue); + +netdev_err (dev,"veth backpressure stalled(n:%ld) TXQ(%u) re-enable\n" , +atomic_long_read (&txq->trans_timeout), txqueue);If you think the
trans_timeoutis useful, let's add it to the message core prints? And then we can make this msg just veth specific, I don't think we should be repeating what core already printed.The
trans_timeoutis a counter for how many times this TXQ have seen a timeout. It is practical as it directly tell us if this a frequent event (without having to search log files for similar events).
Quoted 7 lines
It does make sense to add this to the core message ("NETDEV WATCHDOG") with the same argument. For physical NICs these logs are present in production. Looking at logs through Kibana (right now) and it would make my life easier to see the number of times the individual queues have experienced timeouts. The logs naturally gets spaced in time by the timeout, making it harder to tell the even frequency. Such a patch would naturally go though net-next.
Right, I see how it'd be useful. I think it's worth adding in the core.
Quoted 3 lines
Do you still want me to remove the frequency counter from this message? By the same argument it is practical for me to have as a single log line when troubleshooting this in practice.
IOW it makes it easier to query logs for veth timeouts vs non-veth timeouts? I'm tempted to suggest adding driver name to the logs in the core :) but it's fine, I'm already asking you to add the timeout count in the core.
I'm just trying to make sure everyone can benefit from the good ideas, rather than hiding them in one driver.
Quoted 4 lines
BTW, I've already backported this watchdog patch to prod kernel (without race fix) and I'll try to reproduce the race in staging/lab on some ARM64 servers. If I reproduce it will be practical to have this counter.
Re: [PATCH net V3 1/2] veth: enable dev_watchdog for detecting stalled TXQs
Quoted 26 lines · Jakub Kicinski
Quoted 15 lines · On Fri, 7 Nov 2025 14:42:58 +0100 Jesper Dangaard Brouer wrote:
Quoted 3 lines
I think this belongs in net-next.. Fail safe is not really a bug fix. I'm slightly worried we're missing a corner case and will cause timeouts to get printed for someone's config.
This is a recovery fix. If the race condition fix isn't 100% then this patch will allow veth to recover. Thus, to me it makes sense to group these two patches together.
I'm more worried that we we're missing a corner case that we cannot recover from. Than triggering timeouts to get printed, for a config where NAPI consumer
veth_poll()takes more that 5 seconds to run (budget max 64 packets this needs to consume packets at a rate less than 12.8 pps). It might be good to get some warnings if the system is operating this slow.Quoted 9 lines
Also remember this is not the default config that most people use. The code is only activated if attaching a qdisc to veth, which isn't default. Plus, NAPI mode need to be activated, where in normal NAPI mode the producer and consumer usually runs on the same CPU, which makes it impossible to overflow the
ptr_ring. The veth backpressure is primarily needed when running with threaded-NAPI, where it is natural that producer and consumer runs on different CPUs. In our production setup the consumer is always slower than the producer (as the product inside the namespace have installed too many nftables rules).
Quoted 2 lines
I understand all of this, but IMO the fix is in patch 2. This is a resiliency improvement, not a fix.
As maintainer you have the final say, so I send a [V4]. Notice that doing it this way will cause a merge conflict once net and net-next gets merged.
[V4] https://lore.kernel.org/all/176295319819.307447.6162285688886096284.stgit@firesoul/
--Jesper
PATCH v3 2/2 veth: more robust handing of race to avoid txq getting stuck
In reply to Jesper Dangaard BrouerCommit dc82a33297fc ("veth: apply qdisc backpressure on full ptr_ring to reduce TX drops") introduced a race condition that can lead to a permanently stalled TXQ. This was observed in production on ARM64 systems (Ampere Altra Max).
The race occurs in veth_xmit(). The producer observes a full ptr_ring and stops the queue (netif_tx_stop_queue()). The subsequent conditional logic, intended to re-wake the queue if the consumer had just emptied it (if (__ptr_ring_empty(...)) netif_tx_wake_queue()), can fail. This leads to a "lost wakeup" where the TXQ remains stopped (QUEUE_STATE_DRV_XOFF) and traffic halts.
This failure is caused by an incorrect use of the __ptr_ring_empty() API from the producer side. As noted in kernel comments, this check is not guaranteed to be correct if a consumer is operating on another CPU. The empty test is based on ptr_ring->consumer_head, making it reliable only for the consumer. Using this check from the producer side is fundamentally racy.
This patch fixes the race by adopting the more robust logic from an earlier version V4 of the patchset, which always flushed the peer:
(1) In veth_xmit(), the racy conditional wake-up logic and its memory barrier are removed. Instead, after stopping the queue, we unconditionally call __veth_xdp_flush(rq). This guarantees that the NAPI consumer is scheduled, making it solely responsible for re-waking the TXQ.
This handles the race where veth_poll() consumes all packets and completes
NAPI *before* veth_xmit() on the producer side has called netif_tx_stop_queue. The __veth_xdp_flush(rq) will observe rx_notify_masked is false and schedule NAPI.
(2) On the consumer side, the logic for waking the peer TXQ is moved out of veth_xdp_rcv() and placed at the end of the veth_poll() function. This placement is part of fixing the race, as the netif_tx_queue_stopped() check must occur after rx_notify_masked is potentially set to false during NAPI completion.
This handles the race where veth_poll() consumes all packets, but haven't
finished (rx_notify_masked is still true). The producer veth_xmit() stops the TXQ and __veth_xdp_flush(rq) will observe rx_notify_masked is true, meaning not starting NAPI. Then veth_poll() change rx_notify_masked to false and stops NAPI. Before exiting veth_poll() will observe TXQ is stopped and wake it up.
--- drivers/net/veth.c | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-)
drivers/net/veth.c +20 -20
@@ -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); +/* 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:
@@ -900,17 +898,9 @@ static int veth_xdp_rcv(struct veth_rq *rq, int budget,struct veth_xdp_tx_bq *bq, struct veth_stats *stats) { - struct veth_priv *priv = netdev_priv(rq->dev); -int queue_idx = rq->xdp_rxq.queue_index; -struct netdev_queue *peer_txq; -struct net_device *peer_dev; int i, done = 0, n_xdpf = 0;void *xdpf[VETH_XDP_BATCH ]; -/* NAPI functions as RCU section */ - peer_dev =rcu_dereference_check (priv->peer,rcu_read_lock_bh_held ()); - peer_txq = peer_dev ?netdev_get_tx_queue (peer_dev, queue_idx) :NULL ; -for (i =0 ; i < budget; i++) {void *ptr =__ptr_ring_consume (&rq->xdp_ring);
@@ -959,11 +949,6 @@ static int veth_xdp_rcv(struct veth_rq *rq, int budget, rq->stats.vs.xdp_packets += done;u64_stats_update_end (&rq->stats.syncp); -if (peer_txq &&unlikely (netif_tx_queue_stopped (peer_txq))) { -txq_trans_cond_update (peer_txq); -netif_tx_wake_queue (peer_txq); - } -return done; }
@@ -971,12 +956,20 @@ static int veth_poll(struct napi_struct *napi, int budget) {struct veth_rq *rq = container_of(napi, struct veth_rq, xdp_napi); +struct veth_priv *priv =netdev_priv (rq->dev); +int queue_idx = rq->xdp_rxq.queue_index; +struct netdev_queue *peer_txq;struct veth_stats stats = {}; +struct net_device *peer_dev;struct veth_xdp_tx_bq bq;int done; bq.count =0 ; +/* NAPI functions as RCU section */ + peer_dev =rcu_dereference_check (priv->peer,rcu_read_lock_bh_held ()); + peer_txq = peer_dev ?netdev_get_tx_queue (peer_dev, queue_idx) :NULL ; +xdp_set_return_frame_no_direct (); done =veth_xdp_rcv (rq, budget, &bq, &stats);
@@ -998,6 +991,13 @@ 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 */ +smp_rmb ();/* Paired with netif_tx_stop_queue set_bit */ +if (peer_txq &&netif_tx_queue_stopped (peer_txq)) { +txq_trans_cond_update (peer_txq); +netif_tx_wake_queue (peer_txq); + } +return done; }
Re: [PATCH net V3 2/2] veth: more robust handing of race to avoid txq getting stuck
Quoted 42 lines · Jesper Dangaard Brouer
Commit
dc82a33297fc("veth: apply qdisc backpressure on fullptr_ringto reduce TX drops") introduced a race condition that can lead to a permanently stalled TXQ. This was observed in production on ARM64 systems (Ampere Altra Max).The race occurs in
veth_xmit(). The producer observes a fullptr_ringand stops the queue (netif_tx_stop_queue()). The subsequent conditional logic, intended to re-wake the queue if the consumer had just emptied it (if (__ptr_ring_empty(...))netif_tx_wake_queue()), can fail. This leads to a "lost wakeup" where the TXQ remains stopped (QUEUE_STATE_DRV_XOFF) and traffic halts.This failure is caused by an incorrect use of the
__ptr_ring_empty()API from the producer side. As noted in kernel comments, this check is not guaranteed to be correct if a consumer is operating on another CPU. The empty test is based onptr_ring->consumer_head, making it reliable only for the consumer. Using this check from the producer side is fundamentally racy.This patch fixes the race by adopting the more robust logic from an earlier version V4 of the patchset, which always flushed the peer:
(1) In
veth_xmit(), the racy conditional wake-up logic and its memory barrier are removed. Instead, after stopping the queue, we unconditionally call__veth_xdp_flush(rq). This guarantees that the NAPI consumer is scheduled, making it solely responsible for re-waking the TXQ.
This handles the race whereveth_poll()consumes all packets and completes
NAPI *before*veth_xmit()on the producer side has callednetif_tx_stop_queue. The__veth_xdp_flush(rq)will observerx_notify_maskedis false and schedule NAPI.(2) On the consumer side, the logic for waking the peer TXQ is moved out of
veth_xdp_rcv()and placed at the end of theveth_poll()function. This placement is part of fixing the race, as thenetif_tx_queue_stopped()check must occur afterrx_notify_maskedis potentially set to false during NAPI completion.
This handles the race whereveth_poll()consumes all packets, but haven't
finished (rx_notify_maskedis still true). The producerveth_xmit()stops the TXQ and__veth_xdp_flush(rq)will observerx_notify_maskedis true, meaning not starting NAPI. Thenveth_poll()changerx_notify_maskedto false and stops NAPI. Before exitingveth_poll()will observe TXQ is stopped and wake it up.
Quoted 2 lines
Fixes dc82a33297fc ("veth: apply qdisc backpressure on full ptr_ring to reduce TX drops")Signed-off-by Jesper Dangaard Brouer <[email protected]>