Advertise VIRTIO_NET_F_RX_TSTAMP to userspace and size the vnet header
for it, so a guest can negotiate the feature with a vhost-net backed
tap device.

The header is 40 bytes if the feature is negotiated. Whoever writes
the header (tun, or vhost itself with VHOST_NET_F_VIRTIO_NET_HDR) has
to fill in the timestamp; vhost only reserves the room. If vhost
writes the header, it zeroes everything behind num_buffers, so the
timestamp is 0, which the guest ignores.

Signed-off-by: Steffen Trumtrar <[email protected]>
Assisted-by: Claude:claude-opus-5-5
---
 drivers/vhost/net.c | 17 ++++++++++++++++-
 1 file changed, 16 insertions(+), 1 deletion(-)

diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c
index 2cc730729e08a..2a38ad0ea1af2 100644
--- a/drivers/vhost/net.c
+++ b/drivers/vhost/net.c
@@ -77,7 +77,8 @@ static const int vhost_net_bits[] = {
        VIRTIO_F_RING_RESET,
        VIRTIO_F_IN_ORDER,
        VIRTIO_NET_F_GUEST_UDP_TUNNEL_GSO,
-       VIRTIO_NET_F_HOST_UDP_TUNNEL_GSO
+       VIRTIO_NET_F_HOST_UDP_TUNNEL_GSO,
+       VIRTIO_NET_F_RX_TSTAMP
 };
 
 enum {
@@ -1282,6 +1283,16 @@ static void handle_rx(struct vhost_net *net)
                        vhost_discard_vq_desc(vq, headcount, ndesc);
                        goto out;
                }
+               /* Zero the rest of a header supplied by vhost, e.g. tstamp */
+               if (unlikely(vhost_hlen > sizeof(hdr) + sizeof(num_buffers))) {
+                       size_t rest = vhost_hlen - sizeof(hdr) - 
sizeof(num_buffers);
+
+                       if (iov_iter_zero(rest, &fixup) != rest) {
+                               vq_err(vq, "Failed vnet_hdr zeroing");
+                               vhost_discard_vq_desc(vq, headcount, ndesc);
+                               goto out;
+                       }
+               }
                nvq->done_idx += headcount;
                count += in_order ? 1 : headcount;
                if (nvq->done_idx > VHOST_NET_BATCH) {
@@ -1688,6 +1699,10 @@ static int vhost_net_set_features(struct vhost_net *n, 
const u64 *features)
                                     VIRTIO_NET_F_GUEST_UDP_TUNNEL_GSO))
                hdr_len = sizeof(struct virtio_net_hdr_v1_hash_tunnel);
 
+       /* The header layout is cumulative, tstamp sits behind all other 
fields. */
+       if (virtio_features_test_bit(features, VIRTIO_NET_F_RX_TSTAMP))
+               hdr_len = offsetofend(struct virtio_net_common_hdr, tstamp);
+
        if (virtio_features_test_bit(features, VHOST_NET_F_VIRTIO_NET_HDR)) {
                /* vhost provides vnet_hdr */
                vhost_hlen = hdr_len;

-- 
2.52.0


Reply via email to