Thread (6 messages) 6 messages, 2 authors, 12d ago

[PATCH RFC v3 2/2] tun: support rx-tstamp

COOLING12d

From: Steffen Trumtrar <hidden>
Date: 2026-09-21 14:46:18
Also in: bpf, lkml, virtualization
Subsystem: networking drivers, the rest, tun/tap driver, virtio core, virtio net driver · Maintainers: Andrew Lunn, "David S. Miller", Eric Dumazet, Jakub Kicinski, Paolo Abeni, Linus Torvalds, Willem de Bruijn, Jason Wang, "Michael S. Tsirkin", Eugenio Pérez

Demonstrate support for new virtio-net features

VIRTIO_NET_HDR_F_TSTAMP

This is not intended to be merged.

A full feature test also requires a patched qemu binary that knows
these features and negotiates correct vnet_hdr_sz in
virtio_net_set_mrg_rx_bufs. See
https://github.com/strumtrar/qemu/tree/v11.0.1/virtio-rx-stamps

Not-yet-signed-off-by: Steffen Trumtrar [off-list ref]

---
 Changes since v2:
 - use tstamp from virtio_net_common_hdr
 - use the negotiated vnet_hdr_sz in __tun_vnet_hdr_get

Signed-off-by: Steffen Trumtrar <redacted>
---
 drivers/net/tun.c               | 20 +++++++++++++++-----
 drivers/net/tun_vnet.h          | 27 ++++++++++++++++-----------
 drivers/net/virtio_net.c        | 11 -----------
 include/uapi/linux/virtio_net.h | 11 +++++++++++
 4 files changed, 42 insertions(+), 27 deletions(-)
diff --git a/drivers/net/tun.c b/drivers/net/tun.c
index 5a302709a68aa..924784771b6b7 100644
--- a/drivers/net/tun.c
+++ b/drivers/net/tun.c
@@ -2157,12 +2157,23 @@ static ssize_t tun_put_user(struct tun_struct *tun,
 	}
 
 	if (vnet_hdr_sz) {
-		struct virtio_net_hdr_v1_hash_tunnel hdr;
-		struct virtio_net_hdr *gso;
+		struct virtio_net_common_hdr hdr;
 
 		memset(&hdr, 0, sizeof(hdr));
+
+		/* hdr has at least the size up to and including the tstamp field. */
+		if (vnet_hdr_sz >= offsetof(struct virtio_net_common_hdr, tstamp) +
+				   sizeof_field(struct virtio_net_common_hdr, tstamp)) {
+			u64 tstamp = ktime_get_clocktai_ns();
+
+			hdr.tstamp[0] = (tstamp & 0x000000000000ffffULL) >> 0;
+			hdr.tstamp[1] = (tstamp & 0x00000000ffff0000ULL) >> 16;
+			hdr.tstamp[2] = (tstamp & 0x0000ffff00000000ULL) >> 32;
+			hdr.tstamp[3] = (tstamp & 0xffff000000000000ULL) >> 48;
+		}
+
 		ret = tun_vnet_hdr_tnl_from_skb(tun->flags, tun->dev, skb,
-						&hdr);
+						(struct virtio_net_hdr_v1_hash_tunnel *)&hdr);
 		if (ret)
 			return ret;
 
@@ -2170,9 +2181,8 @@ static ssize_t tun_put_user(struct tun_struct *tun,
 		 * Drop the packet if the configured header size is too small
 		 * WRT the enabled offloads.
 		 */
-		gso = (struct virtio_net_hdr *)&hdr;
 		ret = __tun_vnet_hdr_put(vnet_hdr_sz, tun->dev->features,
-					 iter, gso);
+					 iter, &hdr);
 		if (ret)
 			return ret;
 	}
diff --git a/drivers/net/tun_vnet.h b/drivers/net/tun_vnet.h
index f4c652b1fa44d..0a7fe1ce889b5 100644
--- a/drivers/net/tun_vnet.h
+++ b/drivers/net/tun_vnet.h
@@ -109,12 +109,9 @@ static inline long tun_vnet_ioctl(int *vnet_hdr_sz, unsigned int *flags,
 	}
 }
 
-static inline unsigned int tun_vnet_parse_size(netdev_features_t features)
+static inline unsigned int tun_vnet_parse_size(int vnet_hdr_sz)
 {
-	if (!(features & NETIF_F_GSO_UDP_TUNNEL))
-		return sizeof(struct virtio_net_hdr);
-
-	return TUN_VNET_TNL_SIZE;
+	return min_t(unsigned int, sizeof(struct virtio_net_common_hdr), vnet_hdr_sz);
 }
 
 static inline int __tun_vnet_hdr_get(int sz, unsigned int flags,
@@ -122,15 +119,20 @@ static inline int __tun_vnet_hdr_get(int sz, unsigned int flags,
 				     struct iov_iter *from,
 				     struct virtio_net_hdr *hdr)
 {
-	unsigned int parsed_size = tun_vnet_parse_size(features);
+	unsigned int parsed_size = tun_vnet_parse_size(sz);
+	u8 tmp[sizeof(struct virtio_net_common_hdr)]; // temp buffer with known size
 	u16 hdr_len;
 
 	if (iov_iter_count(from) < sz)
 		return -EINVAL;
 
-	if (!copy_from_iter_full(hdr, parsed_size, from))
+	/* copy parsed size data to the tmp buffer, otherwise compiler will complain */
+	if (!copy_from_iter_full(tmp, parsed_size, from))
 		return -EFAULT;
 
+	/* now copy the relevant data from tmp to hdr */
+	memcpy(hdr, tmp, min(parsed_size, sizeof(*hdr)));
+
 	hdr_len = tun_vnet16_to_cpu(flags, hdr->hdr_len);
 
 	if (hdr->flags & VIRTIO_NET_HDR_F_NEEDS_CSUM) {
@@ -155,14 +157,17 @@ static inline int tun_vnet_hdr_get(int sz, unsigned int flags,
 
 static inline int __tun_vnet_hdr_put(int sz, netdev_features_t features,
 				     struct iov_iter *iter,
-				     const struct virtio_net_hdr *hdr)
+				     const struct virtio_net_common_hdr *hdr)
 {
-	unsigned int parsed_size = tun_vnet_parse_size(features);
+	unsigned int parsed_size = tun_vnet_parse_size(sz);
+	u8 buf[sizeof(*hdr)];
 
 	if (unlikely(iov_iter_count(iter) < sz))
 		return -EINVAL;
 
-	if (unlikely(copy_to_iter(hdr, parsed_size, iter) != parsed_size))
+	memcpy(buf, hdr, parsed_size);
+
+	if (unlikely(copy_to_iter(buf, parsed_size, iter) != parsed_size))
 		return -EFAULT;
 
 	if (iov_iter_zero(sz - parsed_size, iter) != sz - parsed_size)
@@ -174,7 +179,7 @@ static inline int __tun_vnet_hdr_put(int sz, netdev_features_t features,
 static inline int tun_vnet_hdr_put(int sz, struct iov_iter *iter,
 				   const struct virtio_net_hdr *hdr)
 {
-	return __tun_vnet_hdr_put(sz, 0, iter, hdr);
+	return __tun_vnet_hdr_put(sz, 0, iter, (struct virtio_net_common_hdr *)hdr);
 }
 
 static inline int tun_vnet_hdr_to_skb(unsigned int flags, struct sk_buff *skb,
diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
index ef6238cb336b9..60ae9392f9876 100644
--- a/drivers/net/virtio_net.c
+++ b/drivers/net/virtio_net.c
@@ -498,17 +498,6 @@ struct padded_vnet_hdr {
 	char padding[12];
 };
 
-struct virtio_net_common_hdr {
-	union {
-		struct virtio_net_hdr hdr;
-		struct virtio_net_hdr_mrg_rxbuf	mrg_hdr;
-		struct virtio_net_hdr_v1_hash hash_v1_hdr;
-		struct virtio_net_hdr_v1_hash_tunnel tnl_hdr;
-	};
-
-	__le16 tstamp[4];	/* 64-bit timestamp, 2-byte aligned */
-};
-
 static struct virtio_net_common_hdr xsk_hdr;
 
 static void virtnet_sq_free_unused_buf(struct virtqueue *vq, void *buf);
diff --git a/include/uapi/linux/virtio_net.h b/include/uapi/linux/virtio_net.h
index 39977765b72aa..8fed76755dcb1 100644
--- a/include/uapi/linux/virtio_net.h
+++ b/include/uapi/linux/virtio_net.h
@@ -238,6 +238,17 @@ struct virtio_net_hdr_mrg_rxbuf {
 	struct virtio_net_hdr hdr;
 	__virtio16 num_buffers;	/* Number of merged rx buffers */
 };
+
+struct virtio_net_common_hdr {
+	union {
+		struct virtio_net_hdr hdr;
+		struct virtio_net_hdr_mrg_rxbuf	mrg_hdr;
+		struct virtio_net_hdr_v1_hash hash_v1_hdr;
+		struct virtio_net_hdr_v1_hash_tunnel tnl_hdr;
+	};
+
+	__virtio16 tstamp[4];	/* 64-bit timestamp, 2-byte aligned */
+};
 #endif /* ...VIRTIO_NET_NO_LEGACY */
 
 /*
-- 
2.52.0
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help