On Tue, 3 Mar 2026 16:17:34 +0100
Laurent Vivier
Legacy virtio used two different header formats: struct virtio_net_hdr (10 bytes) when VIRTIO_NET_F_MRG_RXBUF was not negotiated, and struct virtio_net_hdr_mrg_rxbuf (12 bytes) when it was. The num_buffers field only existed in the larger header.
Modern virtio (VIRTIO_F_VERSION_1, i.e. virtio 1.0+) always uses the 12-byte struct virtio_net_hdr_mrg_rxbuf header regardless of whether VIRTIO_NET_F_MRG_RXBUF is negotiated, so num_buffers is always present in the header. passt only supports modern virtio and dies if VIRTIO_F_VERSION_1 is not negotiated (vhost_user.c), and VNET_HLEN is unconditionally defined as sizeof(struct virtio_net_hdr_mrg_rxbuf).
The virtio specification (v1.1, section 5.1.6) requires that:
"The device MUST set num_buffers to 1 if VIRTIO_NET_F_MRG_RXBUF has not been negotiated."
vu_set_vnethdr() only set num_buffers when VIRTIO_NET_F_MRG_RXBUF was negotiated. When it was not, num_buffers was left uninitialised, violating the spec.
Since vu_collect() already limits buffer collection to a single element when VIRTIO_NET_F_MRG_RXBUF is not negotiated, num_buffers passed by callers is guaranteed to be 1 in that case. We can therefore unconditionally set num_buffers, which makes the vdev parameter unnecessary.
Drop the vdev parameter from vu_set_vnethdr() and update all callers.
Signed-off-by: Laurent Vivier
Applied. -- Stefano