]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
xsk: respect tailroom for ZC setups
authorMaciej Fijalkowski <maciej.fijalkowski@intel.com>
Thu, 2 Apr 2026 15:49:52 +0000 (17:49 +0200)
committerJakub Kicinski <kuba@kernel.org>
Tue, 7 Apr 2026 01:43:51 +0000 (18:43 -0700)
Multi-buffer XDP stores information about frags in skb_shared_info that
sits at the tailroom of a packet. The storage space is reserved via
xdp_data_hard_end():

((xdp)->data_hard_start + (xdp)->frame_sz - \
 SKB_DATA_ALIGN(sizeof(struct skb_shared_info)))

and then we refer to it via macro below:

static inline struct skb_shared_info *
xdp_get_shared_info_from_buff(const struct xdp_buff *xdp)
{
        return (struct skb_shared_info *)xdp_data_hard_end(xdp);
}

Currently we do not respect this tailroom space in multi-buffer AF_XDP
ZC scenario. To address this, introduce xsk_pool_get_tailroom() and use
it within xsk_pool_get_rx_frame_size() which is used in ZC drivers to
configure length of HW Rx buffer.

Typically drivers on Rx Hw buffers side work on 128 byte alignment so
let us align the value returned by xsk_pool_get_rx_frame_size() in order
to avoid addressing this on driver's side. This addresses the fact that
idpf uses mentioned function *before* pool->dev being set so we were at
risk that after subtracting tailroom we would not provide 128-byte
aligned value to HW.

Since xsk_pool_get_rx_frame_size() is actively used in xsk_rcv_check()
and __xsk_rcv(), add a variant of this routine that will not include 128
byte alignment and therefore old behavior is preserved.

Reviewed-by: Björn Töpel <bjorn@kernel.org>
Acked-by: Stanislav Fomichev <sdf@fomichev.me>
Fixes: 24ea50127ecf ("xsk: support mbuf on ZC RX")
Signed-off-by: Maciej Fijalkowski <maciej.fijalkowski@intel.com>
Link: https://patch.msgid.link/20260402154958.562179-3-maciej.fijalkowski@intel.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
include/net/xdp_sock_drv.h
net/xdp/xsk.c

index 6b9ebae2dc952e69ff6b685846f1ca8f593de69d..46797645a0c241b9e2af19fff39e11508bbd7644 100644 (file)
@@ -41,16 +41,37 @@ static inline u32 xsk_pool_get_headroom(struct xsk_buff_pool *pool)
        return XDP_PACKET_HEADROOM + pool->headroom;
 }
 
+static inline u32 xsk_pool_get_tailroom(bool mbuf)
+{
+       return mbuf ? SKB_DATA_ALIGN(sizeof(struct skb_shared_info)) : 0;
+}
+
 static inline u32 xsk_pool_get_chunk_size(struct xsk_buff_pool *pool)
 {
        return pool->chunk_size;
 }
 
-static inline u32 xsk_pool_get_rx_frame_size(struct xsk_buff_pool *pool)
+static inline u32 __xsk_pool_get_rx_frame_size(struct xsk_buff_pool *pool)
 {
        return xsk_pool_get_chunk_size(pool) - xsk_pool_get_headroom(pool);
 }
 
+static inline u32 xsk_pool_get_rx_frame_size(struct xsk_buff_pool *pool)
+{
+       u32 frame_size =  __xsk_pool_get_rx_frame_size(pool);
+       struct xdp_umem *umem = pool->umem;
+       bool mbuf;
+
+       /* Reserve tailroom only for zero-copy pools that opted into
+        * multi-buffer. The reserved area is used for skb_shared_info,
+        * matching the XDP core's xdp_data_hard_end() layout.
+        */
+       mbuf = pool->dev && (umem->flags & XDP_UMEM_SG_FLAG);
+       frame_size -= xsk_pool_get_tailroom(mbuf);
+
+       return ALIGN_DOWN(frame_size, 128);
+}
+
 static inline u32 xsk_pool_get_rx_frag_step(struct xsk_buff_pool *pool)
 {
        return pool->unaligned ? 0 : xsk_pool_get_chunk_size(pool);
index 6149f6a798971fdf98bccffe4183e5e8af1ab070..c8ef9e427c9cd5bc1ae717c9d3ae458367807552 100644 (file)
@@ -239,7 +239,7 @@ static u32 xsk_copy_xdp(void *to, void **from, u32 to_len,
 
 static int __xsk_rcv(struct xdp_sock *xs, struct xdp_buff *xdp, u32 len)
 {
-       u32 frame_size = xsk_pool_get_rx_frame_size(xs->pool);
+       u32 frame_size = __xsk_pool_get_rx_frame_size(xs->pool);
        void *copy_from = xsk_copy_xdp_start(xdp), *copy_to;
        u32 from_len, meta_len, rem, num_desc;
        struct xdp_buff_xsk *xskb;
@@ -338,7 +338,7 @@ static int xsk_rcv_check(struct xdp_sock *xs, struct xdp_buff *xdp, u32 len)
        if (xs->dev != xdp->rxq->dev || xs->queue_id != xdp->rxq->queue_index)
                return -EINVAL;
 
-       if (len > xsk_pool_get_rx_frame_size(xs->pool) && !xs->sg) {
+       if (len > __xsk_pool_get_rx_frame_size(xs->pool) && !xs->sg) {
                xs->rx_dropped++;
                return -ENOSPC;
        }