From 2a089db26921cc75f71b32537fe3b8baea7202e1 Mon Sep 17 00:00:00 2001 From: Rob Bradford Date: Sat, 18 Apr 2026 11:13:57 +0100 Subject: [PATCH] virtio-devices: net: Report correct used length on TX and ctrl The virtio spec says the used-ring length is bytes the device wrote to device writable descriptors. The net TX descriptors are device readable only (the device wrote nothing back) so the length needs to be 0. On the ctrl queue the number of bytes reported was wrongly the size of the status descriptor not the number of bytes written (the descriptor is permitted to be larger). Signed-off-by: Rob Bradford --- net_util/src/ctrl_queue.rs | 8 +++----- net_util/src/queue_pair.rs | 11 +++++++---- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/net_util/src/ctrl_queue.rs b/net_util/src/ctrl_queue.rs index b14b38036..8b34a33a7 100644 --- a/net_util/src/ctrl_queue.rs +++ b/net_util/src/ctrl_queue.rs @@ -174,12 +174,10 @@ impl CtrlQueue { .map_err(|e| Error::GuestMemory(GuestMemoryError::IOError(e)))?, ) .map_err(Error::GuestMemory)?; - // Per virtio spec 2.6.8, used_len is the number of bytes written - // to device-writable descriptors. Only the status byte is written. - let len = status_desc.len(); - + // Per the virtio spec the used length is bytes the device wrote + // to device-writable descriptors; here just the 1-byte ack. queue - .add_used(desc_chain.memory(), desc_chain.head_index(), len) + .add_used(desc_chain.memory(), desc_chain.head_index(), 1) .map_err(Error::QueueAddUsed)?; if !queue diff --git a/net_util/src/queue_pair.rs b/net_util/src/queue_pair.rs index a56903181..ee4d4d61c 100644 --- a/net_util/src/queue_pair.rs +++ b/net_util/src/queue_pair.rs @@ -97,7 +97,7 @@ impl TxVirtio { next_desc = desc_chain.next(); } - let len = if iovecs.is_empty() { + let bytes_sent = if iovecs.is_empty() { 0 } else { // SAFETY: FFI call with correct arguments @@ -129,7 +129,7 @@ impl TxVirtio { self.counter_bytes += Wrapping(result as u64 - vnet_hdr_len() as u64); self.counter_frames += Wrapping(1); - result as u32 + result as u64 }; // For the sake of simplicity (similar to the RX rate limiting), we always @@ -137,11 +137,14 @@ impl TxVirtio { // limit, and simply stop processing oncoming `avail_desc` if any. if let Some(rate_limiter) = rate_limiter { rate_limit_reached = !rate_limiter.consume(1, TokenType::Ops) - || !rate_limiter.consume(len as u64, TokenType::Bytes); + || !rate_limiter.consume(bytes_sent, TokenType::Bytes); } + // TX descriptors are device-readable only; the device wrote + // nothing back to guest memory, so per the virtio spec the used + // length is 0. queue - .add_used(desc_chain.memory(), desc_chain.head_index(), len) + .add_used(desc_chain.memory(), desc_chain.head_index(), 0) .map_err(NetQueuePairError::QueueAddUsed)?; if !queue