]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
xsk: validate MTU against usable frame size on bind
authorMaciej Fijalkowski <maciej.fijalkowski@intel.com>
Thu, 2 Apr 2026 15:49:54 +0000 (17:49 +0200)
committerJakub Kicinski <kuba@kernel.org>
Tue, 7 Apr 2026 01:43:51 +0000 (18:43 -0700)
AF_XDP bind currently accepts zero-copy pool configurations without
verifying that the device MTU fits into the usable frame space provided
by the UMEM chunk.

This becomes a problem since we started to respect tailroom which is
subtracted from chunk_size (among with headroom). 2k chunk size might
not provide enough space for standard 1500 MTU, so let us catch such
settings at bind time. Furthermore, validate whether underlying HW will
be able to satisfy configured MTU wrt XSK's frame size multiplied by
supported Rx buffer chain length (that is exposed via
net_device::xdp_zc_max_segs).

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

index 729602a3cec0e8dfbe3be4dc208428d378dc74eb..cd7bc50872f6b56cc58831958c2272e90c113b8c 100644 (file)
@@ -10,6 +10,8 @@
 #include "xdp_umem.h"
 #include "xsk.h"
 
+#define ETH_PAD_LEN (ETH_HLEN + 2 * VLAN_HLEN  + ETH_FCS_LEN)
+
 void xp_add_xsk(struct xsk_buff_pool *pool, struct xdp_sock *xs)
 {
        if (!xs->tx)
@@ -157,8 +159,12 @@ static void xp_disable_drv_zc(struct xsk_buff_pool *pool)
 int xp_assign_dev(struct xsk_buff_pool *pool,
                  struct net_device *netdev, u16 queue_id, u16 flags)
 {
+       u32 needed = netdev->mtu + ETH_PAD_LEN;
+       u32 segs = netdev->xdp_zc_max_segs;
+       bool mbuf = flags & XDP_USE_SG;
        bool force_zc, force_copy;
        struct netdev_bpf bpf;
+       u32 frame_size;
        int err = 0;
 
        ASSERT_RTNL();
@@ -178,7 +184,7 @@ int xp_assign_dev(struct xsk_buff_pool *pool,
        if (err)
                return err;
 
-       if (flags & XDP_USE_SG)
+       if (mbuf)
                pool->umem->flags |= XDP_UMEM_SG_FLAG;
 
        if (flags & XDP_USE_NEED_WAKEUP)
@@ -200,8 +206,24 @@ int xp_assign_dev(struct xsk_buff_pool *pool,
                goto err_unreg_pool;
        }
 
-       if (netdev->xdp_zc_max_segs == 1 && (flags & XDP_USE_SG)) {
-               err = -EOPNOTSUPP;
+       if (mbuf) {
+               if (segs == 1) {
+                       err = -EOPNOTSUPP;
+                       goto err_unreg_pool;
+               }
+       } else {
+               segs = 1;
+       }
+
+       /* open-code xsk_pool_get_rx_frame_size() as pool->dev is not
+        * set yet at this point; we are before getting down to driver
+        */
+       frame_size = __xsk_pool_get_rx_frame_size(pool) -
+                    xsk_pool_get_tailroom(mbuf);
+       frame_size = ALIGN_DOWN(frame_size, 128);
+
+       if (needed > frame_size * segs) {
+               err = -EINVAL;
                goto err_unreg_pool;
        }