[PATCH RFC v4 5/6] virtio-net: add XDP rx timestamp metadata
From: Steffen Trumtrar
Date: Mon Oct 26 2026 - 04:31:40 EST
For the skb, the timestamp is read from the header before the XDP
program runs, so XDP_PASS keeps it even if the program changes the
packet. XDP therefore works with rx timestamping enabled.
Add xmo_rx_timestamp so XDP programs can read the timestamp with
bpf_xdp_metadata_rx_timestamp(). It returns -ENODATA if timestamping
is not enabled or the device did not timestamp the packet. Install the
metadata ops also if only VIRTIO_NET_F_RX_TSTAMP is negotiated;
rx_hash returns -ENODATA then.
Like virtnet_xdp_rx_hash(), the callback finds the header relative to
xdp->data, so it has to be called before bpf_xdp_adjust_head().
Signed-off-by: Steffen Trumtrar <s.trumtrar@xxxxxxxxxxxxxx>
Assisted-by: Claude:claude-opus-5-5
---
drivers/net/virtio_net.c | 26 ++++++++++++++++++++++++++
1 file changed, 26 insertions(+)
diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
index 23af10c613b48..e79b65653fad7 100644
--- a/drivers/net/virtio_net.c
+++ b/drivers/net/virtio_net.c
@@ -6848,8 +6848,30 @@ static int virtnet_xdp_rx_hash(const struct xdp_md *_ctx, u32 *hash,
return 0;
}
+static int virtnet_xdp_rx_timestamp(const struct xdp_md *_ctx, u64 *timestamp)
+{
+ const struct xdp_buff *xdp = (void *)_ctx;
+ const struct virtio_net_common_hdr *hdr;
+ struct virtnet_info *vi;
+ u64 tstamp;
+
+ vi = netdev_priv(xdp->rxq->dev);
+ if (!READ_ONCE(vi->hwts_rx_en))
+ return -ENODATA;
+
+ hdr = (const struct virtio_net_common_hdr *)(xdp->data - vi->hdr_len);
+ tstamp = get_unaligned_le64(hdr->tstamp);
+ /* 0: the device did not timestamp this packet */
+ if (!tstamp)
+ return -ENODATA;
+
+ *timestamp = tstamp;
+ return 0;
+}
+
static const struct xdp_metadata_ops virtnet_xdp_metadata_ops = {
.xmo_rx_hash = virtnet_xdp_rx_hash,
+ .xmo_rx_timestamp = virtnet_xdp_rx_timestamp,
};
static int virtnet_probe(struct virtio_device *vdev)
@@ -7014,6 +7036,10 @@ static int virtnet_probe(struct virtio_device *vdev)
dev->xdp_metadata_ops = &virtnet_xdp_metadata_ops;
}
+ /* rx_hash returns -ENODATA without NETIF_F_RXHASH */
+ if (vi->has_rx_tstamp)
+ dev->xdp_metadata_ops = &virtnet_xdp_metadata_ops;
+
if (vi->has_rx_tstamp)
vi->hdr_len = offsetofend(struct virtio_net_common_hdr, tstamp);
else if (virtio_has_feature(vdev, VIRTIO_NET_F_GUEST_UDP_TUNNEL_GSO) ||
--
2.52.0