From 546e42ab2742dab67494bf320e8f4c3ff2699c7d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=87a=C4=9Fatay=20Yi=C4=9Fit=20=C5=9Eahin?= Date: Fri, 27 Jun 2025 12:08:01 +0200 Subject: [PATCH 1/2] virtio-net: allow specifying the buffer size It is possible to set a receive buffer size when MRG_RXBUF is negotiated. Expose this ability to the user through the environment variable `HERMIT_MRG_RXBUF_SIZE`. --- src/drivers/net/virtio/mod.rs | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/src/drivers/net/virtio/mod.rs b/src/drivers/net/virtio/mod.rs index 0ceef6a133..1a3caf2d9a 100644 --- a/src/drivers/net/virtio/mod.rs +++ b/src/drivers/net/virtio/mod.rs @@ -13,6 +13,7 @@ cfg_if::cfg_if! { use alloc::boxed::Box; use alloc::vec::Vec; use core::mem::{ManuallyDrop, MaybeUninit, transmute}; +use core::str::FromStr; use smallvec::SmallVec; use smoltcp::phy::{Checksum, ChecksumCapabilities, DeviceCapabilities}; @@ -59,7 +60,7 @@ fn determine_mtu(dev_cfg: &NetDevCfg) -> u16 { } } -fn determine_buf_size(dev_cfg: &NetDevCfg) -> u32 { +fn determine_rx_buf_size(dev_cfg: &NetDevCfg) -> u32 { // See Virtio specification v1.1 - 5.1.6.3.1 and 5.1.4.2 // Our desired minimum buffer size - we want it to be at least the MTU generally @@ -67,7 +68,16 @@ fn determine_buf_size(dev_cfg: &NetDevCfg) -> u32 { // If VIRTIO_NET_F_MRG_RXBUF is negotiated, each buffer MUST be at least the size of the struct virtio_net_hdr. // We just use MTU in that case, but otherwise... - if !dev_cfg.features.contains(virtio::net::F::MRG_RXBUF) { + if dev_cfg.features.contains(virtio::net::F::MRG_RXBUF) + && let Some(my_mrg_rxbuf_size) = hermit_var!("HERMIT_MRG_RXBUF_SIZE") + { + let my_mrg_rxbuf_size = u32::from_str(&my_mrg_rxbuf_size).unwrap(); + assert!( + my_mrg_rxbuf_size > 0, + "VIRTIO does not allow buffer elements of size 0." + ); + min_buf_size = my_mrg_rxbuf_size; + } else { // If [...] are negotiated, the driver SHOULD populate the receive queue(s) with buffers of at least 65562 bytes. if dev_cfg.features.contains(virtio::net::F::GUEST_TSO4) || dev_cfg.features.contains(virtio::net::F::GUEST_TSO6) @@ -92,7 +102,7 @@ impl RxQueues { pub fn new(vqs: Vec, dev_cfg: &NetDevCfg) -> Self { Self { vqs, - buf_size: determine_buf_size(dev_cfg), + buf_size: determine_rx_buf_size(dev_cfg), } } @@ -167,7 +177,7 @@ impl TxQueues { pub fn new(vqs: Vec, dev_cfg: &NetDevCfg) -> Self { Self { vqs, - buf_size: determine_buf_size(dev_cfg), + buf_size: determine_mtu(dev_cfg).into(), } } From 9dd20bcfde9d98f5ae09684fb05dcf3239c437a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=87a=C4=9Fatay=20Yi=C4=9Fit=20=C5=9Eahin?= Date: Fri, 26 Sep 2025 15:31:20 +0300 Subject: [PATCH 2/2] test(virtio-net): have a CI test with small receive buffers In order to ensure that the buffer merging works, make the receive buffers smaller in a CI step. Note, however, that this does not check if the MRG_RXBUF is available for the step. If it's not, the environment variable will have no effect. --- .github/workflows/ci.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 237520db7c..2f22ab4ec0 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -235,6 +235,11 @@ jobs: working-directory: . - run: cargo xtask ci rs --arch ${{ matrix.arch }} --profile ${{ matrix.profile }} --package httpd --features ci,hermit/dhcpv4,hermit/virtio-net qemu ${{ matrix.flags }} --devices virtio-net-pci if: matrix.arch != 'riscv64' + - run: cargo xtask ci rs --arch ${{ matrix.arch }} --profile ${{ matrix.profile }} --package httpd --features ci,hermit/dhcpv4,hermit/virtio-net qemu ${{ matrix.flags }} --devices virtio-net-pci + if: matrix.arch != 'riscv64' + env: + # The buffer is sized to be smaller than the packets received during DHCPv4 address acquisition and thus exercise the buffer merging code path. + HERMIT_MRG_RXBUF_SIZE: 200 - run: cargo xtask ci rs --arch ${{ matrix.arch }} --profile ${{ matrix.profile }} --package httpd --features ci,hermit/virtio-net qemu --sudo --devices virtio-net-pci --tap if: matrix.arch != 'riscv64' - run: cargo xtask ci rs --arch ${{ matrix.arch }} --profile ${{ matrix.profile }} --package httpd --features ci,hermit/dhcpv4,hermit/virtio-net qemu ${{ matrix.flags }} --devices virtio-net-pci --no-default-virtio-features