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 <[email protected]> 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
