<feed xmlns='http://www.w3.org/2005/Atom'>
<title>passt/vu_common.h, branch 2026_05_26.038c51e</title>
<subtitle>Plug A Simple Socket Transport</subtitle>
<link rel='alternate' type='text/html' href='https://passt.top/passt/'/>
<entry>
<title>tcp_vu: Support multibuffer frames in tcp_vu_send_flag()</title>
<updated>2026-05-26T10:18:24+00:00</updated>
<author>
<name>Laurent Vivier</name>
<email>lvivier@redhat.com</email>
</author>
<published>2026-05-20T15:18:27+00:00</published>
<link rel='alternate' type='text/html' href='https://passt.top/passt/commit/?id=21ea343b465ac9aec74d0694a2cd6a46e3838874'/>
<id>21ea343b465ac9aec74d0694a2cd6a46e3838874</id>
<content type='text'>
Build the Ethernet, IP, and TCP headers on the stack instead of
directly in the buffer via pointer casts, then write them into the
iovec with IOV_PUSH_HEADER().  This mirrors the approach already used
in tcp_vu_prepare() and udp_vu_prepare().

Remove the vu_eth(), vu_ip(), vu_payloadv4() and vu_payloadv6() helpers
from vu_common.h, as they are no longer used anywhere.

Introduce tcp_vu_send_dup() to handle DUP_ACK duplication using
vu_collect() and iov_memcpy() instead of a plain memcpy(), so that
the duplicated frame is also properly scattered across multiple iovecs.

Signed-off-by: Laurent Vivier &lt;lvivier@redhat.com&gt;
Reviewed-by: Jon Maloy &lt;jmaloy@redhat.com&gt;
Reviewed-by: David Gibson &lt;david@gibson.dropbear.id.au&gt;
Signed-off-by: Stefano Brivio &lt;sbrivio@redhat.com&gt;
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Build the Ethernet, IP, and TCP headers on the stack instead of
directly in the buffer via pointer casts, then write them into the
iovec with IOV_PUSH_HEADER().  This mirrors the approach already used
in tcp_vu_prepare() and udp_vu_prepare().

Remove the vu_eth(), vu_ip(), vu_payloadv4() and vu_payloadv6() helpers
from vu_common.h, as they are no longer used anywhere.

Introduce tcp_vu_send_dup() to handle DUP_ACK duplication using
vu_collect() and iov_memcpy() instead of a plain memcpy(), so that
the duplicated frame is also properly scattered across multiple iovecs.

Signed-off-by: Laurent Vivier &lt;lvivier@redhat.com&gt;
Reviewed-by: Jon Maloy &lt;jmaloy@redhat.com&gt;
Reviewed-by: David Gibson &lt;david@gibson.dropbear.id.au&gt;
Signed-off-by: Stefano Brivio &lt;sbrivio@redhat.com&gt;
</pre>
</div>
</content>
</entry>
<entry>
<title>vhost-user: Centralise Ethernet frame padding in vu_collect() and vu_pad()</title>
<updated>2026-05-19T23:21:55+00:00</updated>
<author>
<name>Laurent Vivier</name>
<email>lvivier@redhat.com</email>
</author>
<published>2026-05-13T11:52:18+00:00</published>
<link rel='alternate' type='text/html' href='https://passt.top/passt/commit/?id=db798fc60f4c5869cb53168354e068fb4dabd91a'/>
<id>db798fc60f4c5869cb53168354e068fb4dabd91a</id>
<content type='text'>
The previous per-protocol padding done by vu_pad() in tcp_vu.c and
udp_vu.c was only correct for single-buffer frames: it assumed the
padding area always fell within the first iov, writing past its end
with a plain memset().

It also required each caller to compute MAX(..., ETH_ZLEN + VNET_HLEN)
for vu_collect() and to call vu_pad() at the right point, duplicating
the minimum-size logic across protocols.

Move the Ethernet minimum size enforcement into vu_collect() itself, so
that enough buffer space is always reserved for padding regardless of
the requested frame size.

Rewrite vu_pad() to take a full iovec array and use iov_memset(),
making it safe for multi-buffer (mergeable rx buffer) frames.

In tcp_vu_sock_recv(), replace iov_truncate() with iov_skip_bytes():
now that all consumers receive explicit data lengths, truncating the
iovecs is no longer needed.  In tcp_vu_data_from_sock(), cap each
frame's data length against the remaining bytes actually received from
the socket, so that the last partial frame gets correct headers and
sequence number advancement.

Signed-off-by: Laurent Vivier &lt;lvivier@redhat.com&gt;
Reviewed-by: Jon Maloy &lt;jmaloy@redhat.com&gt;
Reviewed-by: David Gibson &lt;david@gibson.dropbear.id.au&gt;
Signed-off-by: Stefano Brivio &lt;sbrivio@redhat.com&gt;
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
The previous per-protocol padding done by vu_pad() in tcp_vu.c and
udp_vu.c was only correct for single-buffer frames: it assumed the
padding area always fell within the first iov, writing past its end
with a plain memset().

It also required each caller to compute MAX(..., ETH_ZLEN + VNET_HLEN)
for vu_collect() and to call vu_pad() at the right point, duplicating
the minimum-size logic across protocols.

Move the Ethernet minimum size enforcement into vu_collect() itself, so
that enough buffer space is always reserved for padding regardless of
the requested frame size.

Rewrite vu_pad() to take a full iovec array and use iov_memset(),
making it safe for multi-buffer (mergeable rx buffer) frames.

In tcp_vu_sock_recv(), replace iov_truncate() with iov_skip_bytes():
now that all consumers receive explicit data lengths, truncating the
iovecs is no longer needed.  In tcp_vu_data_from_sock(), cap each
frame's data length against the remaining bytes actually received from
the socket, so that the last partial frame gets correct headers and
sequence number advancement.

Signed-off-by: Laurent Vivier &lt;lvivier@redhat.com&gt;
Reviewed-by: Jon Maloy &lt;jmaloy@redhat.com&gt;
Reviewed-by: David Gibson &lt;david@gibson.dropbear.id.au&gt;
Signed-off-by: Stefano Brivio &lt;sbrivio@redhat.com&gt;
</pre>
</div>
</content>
</entry>
<entry>
<title>vu_common: Pass explicit frame length to vu_flush()</title>
<updated>2026-05-19T23:21:47+00:00</updated>
<author>
<name>Laurent Vivier</name>
<email>lvivier@redhat.com</email>
</author>
<published>2026-05-13T11:52:16+00:00</published>
<link rel='alternate' type='text/html' href='https://passt.top/passt/commit/?id=d83470f8b149c1108d884648d58fcdacd9ed781c'/>
<id>d83470f8b149c1108d884648d58fcdacd9ed781c</id>
<content type='text'>
Currently vu_flush() derives the frame size from the iov, but in
preparation for iov arrays that may be larger than the actual frame,
pass the total length (including vnet header) explicitly so that only
the relevant portion is reported to the virtqueue.

Ensure a minimum frame size of ETH_ZLEN + VNET_HLEN to handle short
frames. All elements are still flushed to avoid descriptor leaks,
but trailing elements beyond frame_len will report a zero length.

Signed-off-by: Laurent Vivier &lt;lvivier@redhat.com&gt;
Reviewed-by: David Gibson &lt;david@gibson.dropbear.id.au&gt;
Reviewed-by: Jon Maloy &lt;jmaloy@redhat.com&gt;
Signed-off-by: Stefano Brivio &lt;sbrivio@redhat.com&gt;
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Currently vu_flush() derives the frame size from the iov, but in
preparation for iov arrays that may be larger than the actual frame,
pass the total length (including vnet header) explicitly so that only
the relevant portion is reported to the virtqueue.

Ensure a minimum frame size of ETH_ZLEN + VNET_HLEN to handle short
frames. All elements are still flushed to avoid descriptor leaks,
but trailing elements beyond frame_len will report a zero length.

Signed-off-by: Laurent Vivier &lt;lvivier@redhat.com&gt;
Reviewed-by: David Gibson &lt;david@gibson.dropbear.id.au&gt;
Reviewed-by: Jon Maloy &lt;jmaloy@redhat.com&gt;
Signed-off-by: Stefano Brivio &lt;sbrivio@redhat.com&gt;
</pre>
</div>
</content>
</entry>
<entry>
<title>vu_common: Move vnethdr setup into vu_flush()</title>
<updated>2026-05-19T23:21:19+00:00</updated>
<author>
<name>Laurent Vivier</name>
<email>lvivier@redhat.com</email>
</author>
<published>2026-05-13T11:52:11+00:00</published>
<link rel='alternate' type='text/html' href='https://passt.top/passt/commit/?id=d3a486858be2aa3e318047929e963cb4c02aa997'/>
<id>d3a486858be2aa3e318047929e963cb4c02aa997</id>
<content type='text'>
Every caller of vu_flush() was calling vu_set_vnethdr() beforehand with
the same pattern.  Move it into vu_flush().

Remove vu_queue_notify() from vu_flush() and let callers invoke it
explicitly.  This allows paths that perform multiple flushes, such as
tcp_vu_send_flag() and tcp_vu_data_from_sock(), to issue a single guest
notification at the end.

Signed-off-by: Laurent Vivier &lt;lvivier@redhat.com&gt;
Reviewed-by: David Gibson &lt;david@gibson.dropbear.id.au&gt;
Reviewed-by: Jon Maloy &lt;jmaloy@redhat.com&gt;
Signed-off-by: Stefano Brivio &lt;sbrivio@redhat.com&gt;
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Every caller of vu_flush() was calling vu_set_vnethdr() beforehand with
the same pattern.  Move it into vu_flush().

Remove vu_queue_notify() from vu_flush() and let callers invoke it
explicitly.  This allows paths that perform multiple flushes, such as
tcp_vu_send_flag() and tcp_vu_data_from_sock(), to issue a single guest
notification at the end.

Signed-off-by: Laurent Vivier &lt;lvivier@redhat.com&gt;
Reviewed-by: David Gibson &lt;david@gibson.dropbear.id.au&gt;
Reviewed-by: Jon Maloy &lt;jmaloy@redhat.com&gt;
Signed-off-by: Stefano Brivio &lt;sbrivio@redhat.com&gt;
</pre>
</div>
</content>
</entry>
<entry>
<title>vu_common: Move iovec management into vu_collect()</title>
<updated>2026-03-20T19:05:34+00:00</updated>
<author>
<name>Laurent Vivier</name>
<email>lvivier@redhat.com</email>
</author>
<published>2026-03-18T09:19:41+00:00</published>
<link rel='alternate' type='text/html' href='https://passt.top/passt/commit/?id=451fb7600b8dfdf6800abee613f2b4f026fbd150'/>
<id>451fb7600b8dfdf6800abee613f2b4f026fbd150</id>
<content type='text'>
Previously, callers had to pre-initialize virtqueue elements with iovec
entries using vu_set_element() or vu_init_elem() before calling
vu_collect().  This meant each element owned a fixed, pre-assigned iovec
slot.

Move the iovec array into vu_collect() as explicit parameters (in_sg,
max_in_sg, and in_total), letting it pass the remaining iovec capacity
directly to vu_queue_pop().  A running current_iov counter tracks
consumed entries across elements, so multiple elements share a single
iovec pool.  The optional in_total output parameter reports how many iovec
entries were consumed, allowing callers to track usage across multiple
vu_collect() calls.

This removes vu_set_element() and vu_init_elem() which are no longer
needed, and is a prerequisite for multi-buffer support where a single
virtqueue element can use more than one iovec entry.  For now, callers
assert the current single-iovec-per-element invariant until they are
updated to handle multiple iovecs.

Signed-off-by: Laurent Vivier &lt;lvivier@redhat.com&gt;
Reviewed-by: David Gibson &lt;david@gibson.dropbear.id.au&gt;
Signed-off-by: Stefano Brivio &lt;sbrivio@redhat.com&gt;
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Previously, callers had to pre-initialize virtqueue elements with iovec
entries using vu_set_element() or vu_init_elem() before calling
vu_collect().  This meant each element owned a fixed, pre-assigned iovec
slot.

Move the iovec array into vu_collect() as explicit parameters (in_sg,
max_in_sg, and in_total), letting it pass the remaining iovec capacity
directly to vu_queue_pop().  A running current_iov counter tracks
consumed entries across elements, so multiple elements share a single
iovec pool.  The optional in_total output parameter reports how many iovec
entries were consumed, allowing callers to track usage across multiple
vu_collect() calls.

This removes vu_set_element() and vu_init_elem() which are no longer
needed, and is a prerequisite for multi-buffer support where a single
virtqueue element can use more than one iovec entry.  For now, callers
assert the current single-iovec-per-element invariant until they are
updated to handle multiple iovecs.

Signed-off-by: Laurent Vivier &lt;lvivier@redhat.com&gt;
Reviewed-by: David Gibson &lt;david@gibson.dropbear.id.au&gt;
Signed-off-by: Stefano Brivio &lt;sbrivio@redhat.com&gt;
</pre>
</div>
</content>
</entry>
<entry>
<title>vu_common: Always set num_buffers in virtio-net header</title>
<updated>2026-03-04T17:50:49+00:00</updated>
<author>
<name>Laurent Vivier</name>
<email>lvivier@redhat.com</email>
</author>
<published>2026-03-03T15:17:34+00:00</published>
<link rel='alternate' type='text/html' href='https://passt.top/passt/commit/?id=71a0d6cbbb0f0c936130e28dd33d48a16894491b'/>
<id>71a0d6cbbb0f0c936130e28dd33d48a16894491b</id>
<content type='text'>
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 &lt;lvivier@redhat.com&gt;
Reviewed-by: David Gibson &lt;david@gibson.dropbear.id.au&gt;
Signed-off-by: Stefano Brivio &lt;sbrivio@redhat.com&gt;
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
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 &lt;lvivier@redhat.com&gt;
Reviewed-by: David Gibson &lt;david@gibson.dropbear.id.au&gt;
Signed-off-by: Stefano Brivio &lt;sbrivio@redhat.com&gt;
</pre>
</div>
</content>
</entry>
<entry>
<title>Add missing includes to headers</title>
<updated>2026-03-04T16:39:57+00:00</updated>
<author>
<name>Peter Foley</name>
<email>pefoley@google.com</email>
</author>
<published>2026-02-23T18:11:19+00:00</published>
<link rel='alternate' type='text/html' href='https://passt.top/passt/commit/?id=adbf5c135f19db5b6751393b7f5cbf516031bde8'/>
<id>adbf5c135f19db5b6751393b7f5cbf516031bde8</id>
<content type='text'>
Support build systems like bazel that check that headers are
self-contained.

Also update includes so that clang-include-cleaner succeeds.

Tested with:
clang-include-cleaner-19 --extra-arg=-D_GNU_SOURCE --extra-arg=-DPAGE_SIZE=4096 --extra-arg=-DVERSION=\"git\" --extra-arg=-DHAS_GETRANDOM *.h *.c

Signed-off-by: Peter Foley &lt;pefoley@google.com&gt;
Signed-off-by: Stefano Brivio &lt;sbrivio@redhat.com&gt;
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Support build systems like bazel that check that headers are
self-contained.

Also update includes so that clang-include-cleaner succeeds.

Tested with:
clang-include-cleaner-19 --extra-arg=-D_GNU_SOURCE --extra-arg=-DPAGE_SIZE=4096 --extra-arg=-DVERSION=\"git\" --extra-arg=-DHAS_GETRANDOM *.h *.c

Signed-off-by: Peter Foley &lt;pefoley@google.com&gt;
Signed-off-by: Stefano Brivio &lt;sbrivio@redhat.com&gt;
</pre>
</div>
</content>
</entry>
<entry>
<title>virtio: Introduce VNET_HLEN macro for virtio net header length</title>
<updated>2026-02-15T01:52:51+00:00</updated>
<author>
<name>Laurent Vivier</name>
<email>lvivier@redhat.com</email>
</author>
<published>2026-02-12T11:39:31+00:00</published>
<link rel='alternate' type='text/html' href='https://passt.top/passt/commit/?id=02af38d4177550c086bae54246fc3aaa33ddc018'/>
<id>02af38d4177550c086bae54246fc3aaa33ddc018</id>
<content type='text'>
Replace all open-coded sizeof(struct virtio_net_hdr_mrg_rxbuf) with a
VNET_HLEN macro.

Signed-off-by: Laurent Vivier &lt;lvivier@redhat.com&gt;
Signed-off-by: Stefano Brivio &lt;sbrivio@redhat.com&gt;
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Replace all open-coded sizeof(struct virtio_net_hdr_mrg_rxbuf) with a
VNET_HLEN macro.

Signed-off-by: Laurent Vivier &lt;lvivier@redhat.com&gt;
Signed-off-by: Stefano Brivio &lt;sbrivio@redhat.com&gt;
</pre>
</div>
</content>
</entry>
<entry>
<title>treewide: Fix places where we incorrectly indented with spaces</title>
<updated>2026-01-11T00:31:50+00:00</updated>
<author>
<name>David Gibson</name>
<email>david@gibson.dropbear.id.au</email>
</author>
<published>2026-01-09T04:09:22+00:00</published>
<link rel='alternate' type='text/html' href='https://passt.top/passt/commit/?id=b973f4a6cc50571f8375c60a7e511a77bcf5c202'/>
<id>b973f4a6cc50571f8375c60a7e511a77bcf5c202</id>
<content type='text'>
Had a moment to address this trivial issue.

The passt convention is to indent code with tabs (K&amp;R / kernel style).
However there were a handful of places where we used spaces instead.  Fix
them.

Link: https://bugs.passt.top/show_bug.cgi?id=135
Reported-by: Xun Gu &lt;xugu@redhat.com&gt;
Signed-off-by: David Gibson &lt;david@gibson.dropbear.id.au&gt;
Signed-off-by: Stefano Brivio &lt;sbrivio@redhat.com&gt;
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Had a moment to address this trivial issue.

The passt convention is to indent code with tabs (K&amp;R / kernel style).
However there were a handful of places where we used spaces instead.  Fix
them.

Link: https://bugs.passt.top/show_bug.cgi?id=135
Reported-by: Xun Gu &lt;xugu@redhat.com&gt;
Signed-off-by: David Gibson &lt;david@gibson.dropbear.id.au&gt;
Signed-off-by: Stefano Brivio &lt;sbrivio@redhat.com&gt;
</pre>
</div>
</content>
</entry>
<entry>
<title>tcp, udp: Pad batched frames for vhost-user modes to 60 bytes (802.3 minimum)</title>
<updated>2025-12-08T03:47:46+00:00</updated>
<author>
<name>Stefano Brivio</name>
<email>sbrivio@redhat.com</email>
</author>
<published>2025-11-03T10:16:12+00:00</published>
<link rel='alternate' type='text/html' href='https://passt.top/passt/commit/?id=0cb8f90036540527133ad55a5976d2f639cce8da'/>
<id>0cb8f90036540527133ad55a5976d2f639cce8da</id>
<content type='text'>
For both TCP and UDP, instead of just expecting the first provided
buffer to be large enough to contain the headers we need (from 42
bytes for UDP data over IPv4 to 82 bytes for TCP with options over
IPv6), change that assumption to make sure that buffers are anyway
at least ETH_ZLEN-sized buffers (60 bytes).

This looks reasonable because there are no known vhost-user
hypervisor implementations that would give us smaller buffers than
that, and we would anyway hit an assertion failure with IPv6 if we
ever had less than 60 bytes per buffer.

At this point, all we need to do is to pad the first (and only)
buffer, should data and headers use less than that.

Link: https://bugs.passt.top/show_bug.cgi?id=166
Signed-off-by: Stefano Brivio &lt;sbrivio@redhat.com&gt;
Reviewed-by: David Gibson &lt;david@gibson.dropbear.id.au&gt;
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
For both TCP and UDP, instead of just expecting the first provided
buffer to be large enough to contain the headers we need (from 42
bytes for UDP data over IPv4 to 82 bytes for TCP with options over
IPv6), change that assumption to make sure that buffers are anyway
at least ETH_ZLEN-sized buffers (60 bytes).

This looks reasonable because there are no known vhost-user
hypervisor implementations that would give us smaller buffers than
that, and we would anyway hit an assertion failure with IPv6 if we
ever had less than 60 bytes per buffer.

At this point, all we need to do is to pad the first (and only)
buffer, should data and headers use less than that.

Link: https://bugs.passt.top/show_bug.cgi?id=166
Signed-off-by: Stefano Brivio &lt;sbrivio@redhat.com&gt;
Reviewed-by: David Gibson &lt;david@gibson.dropbear.id.au&gt;
</pre>
</div>
</content>
</entry>
</feed>
