> -----Original Message-----
> From: Mandal, Anurag <[email protected]>
> Sent: 06 August 2026 09:26
> To: [email protected]
> Cc: Richardson, Bruce <[email protected]>; Medvedkin, Vladimir
> <[email protected]>; Loftus, Ciara <[email protected]>;
> Mandal, Anurag <[email protected]>
> Subject: [PATCH 3/5] net/iavf: drain in-flight Tx before reset
> 
> On a link-down or impending PF reset, in-flight Tx descriptors
> were left pending when the queues were torn down, which could
> trigger Malicious Driver Detection (MDD) events and
> leak descriptors.
> 
> Added iavf_dev_tx_drain() to let already-posted Tx bursts
> complete and flush the rings within a bounded budget,
> and call it on link-down and reset-impending events
> before teardown, preventing MDD events and descriptor leaks.
> The drain selects the cleanup routine that matches the
> active Tx path: the scalar path uses ci_tx_xmit_cleanup(),
> while the vector and CTX paths use ci_tx_free_bufs_vec().
> This matters because the scalar and vector paths track
> their software rings differently
> (ci_tx_entry vs ci_tx_entry_vec) and using the scalar
> routine on a vector queue would walk the wrong ring
> and free the wrong mbufs.

I think " The drain selects the cleanup routine that matches the
active Tx path" is sufficient detail, you can clip the rest out.

> 
> Signed-off-by: Anurag Mandal <[email protected]>
> ---
>  drivers/net/intel/iavf/iavf_rxtx.c  | 104 ++++++++++++++++++++++++++++
>  drivers/net/intel/iavf/iavf_rxtx.h  |   6 ++
>  drivers/net/intel/iavf/iavf_vchnl.c |   7 ++
>  3 files changed, 117 insertions(+)
> 
> diff --git a/drivers/net/intel/iavf/iavf_rxtx.c
> b/drivers/net/intel/iavf/iavf_rxtx.c
> index 4f2ffe6188..931bb8420d 100644
> --- a/drivers/net/intel/iavf/iavf_rxtx.c
> +++ b/drivers/net/intel/iavf/iavf_rxtx.c
> @@ -32,6 +32,7 @@
> 
>  #include "iavf.h"
>  #include "iavf_rxtx.h"
> +#include "iavf_rxtx_vec_common.h"
>  #include "iavf_ipsec_crypto.h"
>  #include "rte_pmd_iavf.h"
> 
> @@ -4025,6 +4026,109 @@ iavf_tx_done_cleanup_full(struct ci_tx_queue
> *txq,
>       return (int)pkt_cnt;
>  }
> 
> +/*
> + * Reclaim completed Tx descriptors for a single queue using the cleanup
> + * routine that matches the active Tx path.

> + * The scalar and vector paths track their software rings differently
> + * (ci_tx_entry vs ci_tx_entry_vec) and keep separate completion
> + * bookkeeping, so using the scalar routine on a vector queue
> + * (or vice versa) would free the wrong mbufs.

I think the above sentence can be removed (verbose).

> + * Returns true if any descriptors were reclaimed.
> + */
> +static bool
> +iavf_tx_drain_cleanup(struct ci_tx_queue *txq,
> +                   enum iavf_tx_func_type tx_func_type)
> +{
> +     switch (tx_func_type) {
> +     case IAVF_TX_AVX2_CTX:
> +     case IAVF_TX_AVX2_CTX_OFFLOAD:
> +     case IAVF_TX_AVX512_CTX:
> +     case IAVF_TX_AVX512_CTX_OFFLOAD:
> +             return ci_tx_free_bufs_vec(txq, iavf_tx_desc_done, true) != 0;
> +     case IAVF_TX_NEON:
> +     case IAVF_TX_AVX2:
> +     case IAVF_TX_AVX2_OFFLOAD:
> +     case IAVF_TX_AVX512:
> +     case IAVF_TX_AVX512_OFFLOAD:
> +             return ci_tx_free_bufs_vec(txq, iavf_tx_desc_done, false) != 0;
> +     case IAVF_TX_DEFAULT:
> +     default:
> +             return ci_tx_xmit_cleanup(txq) == 0;
> +     }
> +}
> +

[snip]

>       /*
> @@ -341,6 +343,8 @@ iavf_read_msg_from_pf(struct iavf_adapter
> *adapter, uint16_t buf_len,
>                       if (!vf->vf_reset) {
>                               vf->vf_reset = true;
>                               iavf_set_no_poll(adapter, false);
> +                             if (adapter->devargs.no_poll_on_link_down)
> +                                     iavf_dev_tx_drain(vf->eth_dev);
>                               iavf_dev_event_post(vf->eth_dev,
>                                       RTE_ETH_EVENT_INTR_RESET,
>                                       NULL, 0);
> @@ -579,6 +583,9 @@ iavf_handle_pf_event_msg(struct rte_eth_dev *dev,
> uint8_t *msg,
>               if (!vf->vf_reset) {
>                       vf->vf_reset = true;
>                       iavf_set_no_poll(adapter, false);
> +                     iavf_dev_watchdog_enable(adapter);

Is this enabling of the watchdog intended?

> +                     if (adapter->devargs.no_poll_on_link_down)
> +                             iavf_dev_tx_drain(dev);
>                       iavf_dev_event_post(dev,
> RTE_ETH_EVENT_INTR_RESET,
>                               NULL, 0);
>               }
> --
> 2.34.1

Reply via email to