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


Reply via email to