On Tue, Feb 17, 2026 at 02:24:43PM +0100, Larysa Zaremba wrote:
> Current way of handling XDP RxQ info in i40e has following problems:
> * when xsk_buff_pool is detached, memory model is not unregistered before
> registering a new one, this leads to a dangling xsk_buff_pool in the
> memory model table
What is 'memory model table' in this context?
I believe you are referring to a case where XDP prog is kept alive on
interface put you close one socket and then bind the other one?
> * frag_size is not updated when xsk_buff_pool is detached or when MTU is
> changed, this leads to growing tail always failing for multi-buffer
> packets.
Good catch, i now see that i40e_change_mtu() only does the link flap and
i40e_free_rx_resources() is not called in this path.
>
> Couple XDP RxQ info registering with buffer allocations and unregistering
> with cleaning the ring.
>
> Fixes: a045d2f2d03d ("i40e: set xdp_rxq_info::frag_size")
> Signed-off-by: Larysa Zaremba <[email protected]>
> ---
> drivers/net/ethernet/intel/i40e/i40e_main.c | 34 ++++++++++++---------
> drivers/net/ethernet/intel/i40e/i40e_txrx.c | 5 +--
> 2 files changed, 22 insertions(+), 17 deletions(-)
>
> diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c
> b/drivers/net/ethernet/intel/i40e/i40e_main.c
> index d3bc3207054f..eaa5b65e6daf 100644
> --- a/drivers/net/ethernet/intel/i40e/i40e_main.c
> +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c
> @@ -3577,18 +3577,8 @@ static int i40e_configure_rx_ring(struct i40e_ring
> *ring)
> if (ring->vsi->type != I40E_VSI_MAIN)
> goto skip;
>
> - if (!xdp_rxq_info_is_reg(&ring->xdp_rxq)) {
> - err = __xdp_rxq_info_reg(&ring->xdp_rxq, ring->netdev,
> - ring->queue_index,
> - ring->q_vector->napi.napi_id,
> - ring->rx_buf_len);
> - if (err)
> - return err;
> - }
> -
> ring->xsk_pool = i40e_xsk_pool(ring);
> if (ring->xsk_pool) {
> - xdp_rxq_info_unreg(&ring->xdp_rxq);
> ring->rx_buf_len = xsk_pool_get_rx_frame_size(ring->xsk_pool);
> err = __xdp_rxq_info_reg(&ring->xdp_rxq, ring->netdev,
> ring->queue_index,
> @@ -3600,17 +3590,23 @@ static int i40e_configure_rx_ring(struct i40e_ring
> *ring)
> MEM_TYPE_XSK_BUFF_POOL,
> NULL);
> if (err)
> - return err;
> + goto unreg_xdp;
> dev_info(&vsi->back->pdev->dev,
> "Registered XDP mem model MEM_TYPE_XSK_BUFF_POOL on Rx
> ring %d\n",
> ring->queue_index);
>
> } else {
> + err = __xdp_rxq_info_reg(&ring->xdp_rxq, ring->netdev,
> + ring->queue_index,
> + ring->q_vector->napi.napi_id,
> + ring->rx_buf_len);
> + if (err)
> + return err;
> err = xdp_rxq_info_reg_mem_model(&ring->xdp_rxq,
> MEM_TYPE_PAGE_SHARED,
> NULL);
> if (err)
> - return err;
> + goto unreg_xdp;
> }
>
> skip:
> @@ -3648,7 +3644,8 @@ static int i40e_configure_rx_ring(struct i40e_ring
> *ring)
> dev_info(&vsi->back->pdev->dev,
> "Failed to clear LAN Rx queue context on Rx ring %d
> (pf_q %d), error: %d\n",
> ring->queue_index, pf_q, err);
> - return -ENOMEM;
> + err = -ENOMEM;
> + goto unreg_xdp;
> }
>
> /* set the context in the HMC */
> @@ -3657,7 +3654,8 @@ static int i40e_configure_rx_ring(struct i40e_ring
> *ring)
> dev_info(&vsi->back->pdev->dev,
> "Failed to set LAN Rx queue context on Rx ring %d
> (pf_q %d), error: %d\n",
> ring->queue_index, pf_q, err);
> - return -ENOMEM;
> + err = -ENOMEM;
> + goto unreg_xdp;
> }
>
> /* configure Rx buffer alignment */
> @@ -3665,7 +3663,8 @@ static int i40e_configure_rx_ring(struct i40e_ring
> *ring)
> if (I40E_2K_TOO_SMALL_WITH_PADDING) {
> dev_info(&vsi->back->pdev->dev,
> "2k Rx buffer is too small to fit standard MTU
> and skb_shared_info\n");
> - return -EOPNOTSUPP;
> + err = -EOPNOTSUPP;
> + goto unreg_xdp;
> }
> clear_ring_build_skb_enabled(ring);
> } else {
> @@ -3695,6 +3694,11 @@ static int i40e_configure_rx_ring(struct i40e_ring
> *ring)
> }
>
> return 0;
> +unreg_xdp:
> + if (ring->vsi->type == I40E_VSI_MAIN)
> + xdp_rxq_info_unreg(&ring->xdp_rxq);
> +
> + return err;
> }
>
> /**
> diff --git a/drivers/net/ethernet/intel/i40e/i40e_txrx.c
> b/drivers/net/ethernet/intel/i40e/i40e_txrx.c
> index cc0b9efc2637..816179c7e271 100644
> --- a/drivers/net/ethernet/intel/i40e/i40e_txrx.c
> +++ b/drivers/net/ethernet/intel/i40e/i40e_txrx.c
> @@ -1470,6 +1470,9 @@ void i40e_clean_rx_ring(struct i40e_ring *rx_ring)
> if (!rx_ring->rx_bi)
> return;
>
> + if (xdp_rxq_info_is_reg(&rx_ring->xdp_rxq))
> + xdp_rxq_info_unreg(&rx_ring->xdp_rxq);
> +
> if (rx_ring->xsk_pool) {
> i40e_xsk_clean_rx_ring(rx_ring);
> goto skip_free;
> @@ -1527,8 +1530,6 @@ void i40e_clean_rx_ring(struct i40e_ring *rx_ring)
> void i40e_free_rx_resources(struct i40e_ring *rx_ring)
> {
> i40e_clean_rx_ring(rx_ring);
> - if (rx_ring->vsi->type == I40E_VSI_MAIN)
> - xdp_rxq_info_unreg(&rx_ring->xdp_rxq);
> rx_ring->xdp_prog = NULL;
> kfree(rx_ring->rx_bi);
> rx_ring->rx_bi = NULL;
> --
> 2.52.0
>