From c71a8ea8dd611b3c742aaf56124beb3492935970 Mon Sep 17 00:00:00 2001 From: Anatol Belski Date: Tue, 5 May 2026 14:44:12 +0200 Subject: [PATCH] net_util: queue_pair: Handle RX readv EINVAL gracefully When readv from the TAP returns EINVAL the guest posted a buffer too small for the vnet_hdr. Return len 0 to the used ring and continue instead of killing the worker thread. Also move go_to_previous_position into the appropriate error branches only. Signed-off-by: Anatol Belski --- net_util/src/queue_pair.rs | 46 ++++++++++++++++++++++---------------- 1 file changed, 27 insertions(+), 19 deletions(-) diff --git a/net_util/src/queue_pair.rs b/net_util/src/queue_pair.rs index 6bce145f9..dcdc0d3d9 100644 --- a/net_util/src/queue_pair.rs +++ b/net_util/src/queue_pair.rs @@ -272,33 +272,41 @@ impl RxVirtio { }; if result < 0 { let e = std::io::Error::last_os_error(); - exhausted_descs = false; - queue.go_to_previous_position(); /* EAGAIN */ if e.kind() == std::io::ErrorKind::WouldBlock { + exhausted_descs = false; + queue.go_to_previous_position(); break; } - error!("net: rx: failed reading from tap: {e}"); - return Err(NetQueuePairError::ReadTap(e)); - } - - if (result as usize) < vnet_hdr_len() { + if e.raw_os_error() == Some(libc::EINVAL) { + error!("net: rx: dropping undersized buffer: {e}"); + desc_chain + .memory() + .write_obj(0u16, num_buffers_addr) + .map_err(NetQueuePairError::GuestMemory)?; + 0 + } else { + queue.go_to_previous_position(); + error!("net: rx: failed reading from tap: {e}"); + return Err(NetQueuePairError::ReadTap(e)); + } + } else if (result as usize) < vnet_hdr_len() { return Err(NetQueuePairError::InvalidVirtioNetHeader); + } else { + // Write num_buffers to guest memory. Always 1 because the + // frame is never spread over more than one descriptor chain. + desc_chain + .memory() + .write_obj(1u16, num_buffers_addr) + .map_err(NetQueuePairError::GuestMemory)?; + + self.counter_bytes += Wrapping(result as u64 - vnet_hdr_len() as u64); + self.counter_frames += Wrapping(1); + + result as u32 } - - // Write num_buffers to guest memory. We simply write 1 as we - // never spread the frame over more than one descriptor chain. - desc_chain - .memory() - .write_obj(1u16, num_buffers_addr) - .map_err(NetQueuePairError::GuestMemory)?; - - self.counter_bytes += Wrapping(result as u64 - vnet_hdr_len() as u64); - self.counter_frames += Wrapping(1); - - result as u32 }; // For the sake of simplicity (keeping the handling of RX_QUEUE_EVENT and