[PATCH 06/10] net/bnxt: fix packet burst truncation after invalid Tx descriptor descriptor
Mohammad Shuab Siddique
mohammad-shuab.siddique at broadcom.com
Thu Jun 4 05:18:47 CEST 2026
From: Zoe Cheimets <zoe.cheimets at broadcom.com>
When bnxt_start_xmit() returned -EINVAL for a bad packet, the burst
loop broke immediately, dropping all subsequent valid packets. The
Tx ring was also left in a corrupt state because tx_raw_prod was not
rolled back after a partial descriptor write. Additionally, the
tx_mbuf_drop oerrors accumulation was gated behind a tx_started
check, silently omitting drops from the statistics.
Fix by rolling back tx_raw_prod and any partially-written ring slots
on the drop path, replacing the break with continue so the burst
loop keeps processing remaining packets, and moving the tx_mbuf_drop
read to before the tx_started guard in both stats paths. Return
value is corrected to RTE_MIN(nb_tx_pkts + dropped, nb_pkts) to
accurately report consumed packet count.
Fixes: 220de9869bc3 ("net/bnxt: optimize Tx batching")
Cc: stable at dpdk.org
Signed-off-by: Zoe Cheimets <zoe.cheimets at broadcom.com>
Signed-off-by: Mohammad Shuab Siddique <mohammad-shuab.siddique at broadcom.com>
---
drivers/net/bnxt/bnxt_txr.c | 34 ++++++++++++++++++++++++++++++----
1 file changed, 30 insertions(+), 4 deletions(-)
diff --git a/drivers/net/bnxt/bnxt_txr.c b/drivers/net/bnxt/bnxt_txr.c
index a6b062637c..bb9917d705 100644
--- a/drivers/net/bnxt/bnxt_txr.c
+++ b/drivers/net/bnxt/bnxt_txr.c
@@ -239,15 +239,17 @@ static int bnxt_start_xmit(struct rte_mbuf *tx_pkt,
uint16_t *coal_pkts,
struct tx_bd_long **last_txbd)
{
+ struct tx_bd_long *last_txbd_save = *last_txbd;
struct bnxt_tx_ring_info *txr = txq->tx_ring;
struct bnxt_ring *ring = txr->tx_ring_struct;
+ uint16_t tx_raw_prod_save = txr->tx_raw_prod;
uint32_t outer_tpid_bd = 0;
struct tx_bd_long *txbd;
struct tx_bd_long_hi *txbd1 = NULL;
uint32_t vlan_tag_flags;
bool long_bd = false;
unsigned short nr_bds;
- uint16_t prod;
+ uint16_t prod, idx;
bool pkt_needs_ts = 0;
struct rte_mbuf *m_seg;
struct rte_mbuf **tx_buf;
@@ -507,6 +509,24 @@ static int bnxt_start_xmit(struct rte_mbuf *tx_pkt,
return 0;
drop:
+ /* Roll back any descriptors and tx_buf_ring slots that were written
+ * for this packet before the failure was detected. Walking from the
+ * saved producer index up to (but not including) the current one is
+ * safe because we hold the Tx lock and the HW has not been notified
+ * (the doorbell is only rung after bnxt_start_xmit() returns
+ * successfully).
+ */
+ idx = tx_raw_prod_save;
+
+ while (idx != txr->tx_raw_prod) {
+ uint16_t slot = RING_IDX(ring, idx);
+
+ txr->tx_buf_ring[slot] = NULL;
+ txr->tx_desc_ring[slot].address = 0;
+ idx = RING_NEXT(idx);
+ }
+ txr->tx_raw_prod = tx_raw_prod_save;
+ *last_txbd = last_txbd_save;
rte_pktmbuf_free(tx_pkt);
ret:
return rc;
@@ -836,22 +856,28 @@ uint16_t _bnxt_xmit_pkts(void *tx_queue, struct rte_mbuf **tx_pkts,
if (unlikely(rc)) {
if (rc == -EINVAL) {
+ coal_pkts--;
rte_atomic_fetch_add_explicit(&txq->tx_mbuf_drop, 1,
rte_memory_order_relaxed);
dropped++;
+ continue;
}
break;
}
}
- if (likely(nb_tx_pkts)) {
+ /* last_txbd is used to check for if any packets have been sent in
+ * the burst as bnxt_start_xmit will update it to the most recent
+ * non-dropped buffer descriptor in the burst.
+ */
+ if (likely(last_txbd != NULL)) {
/* Request a completion on the last packet */
last_txbd->flags_type &= ~TX_BD_LONG_FLAGS_NO_CMPL;
bnxt_db_write(&txq->tx_ring->tx_db, txq->tx_ring->tx_raw_prod);
}
- nb_tx_pkts += dropped;
- return nb_tx_pkts;
+ return RTE_MIN((uint16_t)(nb_tx_pkts + dropped), nb_pkts);
+
}
int bnxt_tx_queue_start(struct rte_eth_dev *dev, uint16_t tx_queue_id)
--
2.47.3
More information about the dev
mailing list