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 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