Subject: Re: [PATCH bpf v3 5/9] i40e: fix registering XDP RxQ info

From: Maciej Fijalkowski <[email-masked]>
Date: Thu, 19 Feb 2026 13:00:05 +0100

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-masked]>
> ---
>  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
>