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