This is an automated email from the ASF dual-hosted git repository.
casaroli pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git
The following commit(s) were added to refs/heads/master by this push:
new 290d9ec3764 drivers/virtio-net: handle addbuffer failure in send
290d9ec3764 is described below
commit 290d9ec3764b7f9ac65fb3e75e60eb9e42bc3c74
Author: Brijesh Thakkar <[email protected]>
AuthorDate: Fri Oct 23 13:09:08 2026 +0530
drivers/virtio-net: handle addbuffer failure in send
virtio_net_send() ignored the return value of virtio_net_addbuffer().
When the TX virtqueue has no room, virtqueue_add_buffer() fails with
ERROR_VRING_FULL without queueing anything, but send still returned OK.
According to the transmit() contract in netdev_lowerhalf.h, returning OK
transfers the ownership of the netpkt to the driver, which has to free
it with netpkt_free() once the packet is sent. Since the packet was never
queued, nobody ever frees it: for every failed send the IOB chain and one
TX quota are leaked. After bufnum such failures the TX quota is
exhausted, netdev_upper_can_tx() never returns true again and the
interface stops transmitting for good.
Fix it by returning a negated errno on failure, as the contract
requires and as other lowerhalf drivers (e1000, igb) do when their TX
ring is full. The upper half then recycles the packet and restores the
TX quota. The virtqueue error code is not an errno, so it is mapped to
-ENOMEM.
Also reclaim the buffers already consumed by the other side and enable
the TX done callback before returning, so the transmission is resumed
when the ring drains instead of waiting for the next txavail. This is
the same sequence the successful path already runs at the end of send.
Assisted-by: Claude Sonnet 5.5 <[email protected]>
Signed-off-by: Brijesh Thakkar <[email protected]>
---
drivers/virtio/virtio-net.c | 17 ++++++++++++++++-
1 file changed, 16 insertions(+), 1 deletion(-)
diff --git a/drivers/virtio/virtio-net.c b/drivers/virtio/virtio-net.c
index 633e6e27598..37bf52d8f10 100644
--- a/drivers/virtio/virtio-net.c
+++ b/drivers/virtio/virtio-net.c
@@ -516,6 +516,7 @@ static int virtio_net_send(FAR struct netdev_lowerhalf_s
*dev,
{
FAR struct virtio_net_priv_s *priv = (FAR struct virtio_net_priv_s *)dev;
FAR struct virtqueue *vq = priv->vdev->vrings_info[VIRTIO_NET_TX].vq;
+ int ret;
/* Check the send length */
@@ -527,7 +528,21 @@ static int virtio_net_send(FAR struct netdev_lowerhalf_s
*dev,
/* Add buffer to vq and notify the other side */
- virtio_net_addbuffer(dev, vq, pkt, VIRTIO_NET_TX);
+ ret = virtio_net_addbuffer(dev, vq, pkt, VIRTIO_NET_TX);
+ if (ret < 0)
+ {
+ /* The virtqueue has no room. The packet was not queued, so it is
+ * still owned (and will be recycled) by the upper-half. Reclaim what
+ * the other side has finished and ask for a TX done callback to
+ * resume the transmission.
+ */
+
+ vrterr("net send failed: %d\n", ret);
+ virtio_net_txfree(dev);
+ virtqueue_enable_cb_lock(vq, &priv->lock[VIRTIO_NET_TX]);
+ return -ENOMEM;
+ }
+
virtqueue_kick_lock(vq, &priv->lock[VIRTIO_NET_TX]);
/* Try return Netpkt TX buffer to upper-half. */