|SUCCESS| [v2, 4/4] net/axgbe: fix descriptor status out-of-bounds access
dpdklab at iol.unh.edu
dpdklab at iol.unh.edu
Fri May 8 22:24:44 CEST 2026
Test-Label: ai-code-review
Test-Status: SUCCESS
https://dpdk.org/patch/163807
_AI Code Review_
=== Patch Review: series.patch (via Claude) ===
Review date: 2026-05-08
I'll review this DPDK patch series focusing on correctness, resource management, coding style, and guideline compliance.
Commit: 20260508191109.734377-2
Author: Stephen Hemminger <stephen at networkplumber.org>
Subject: [PATCH v2 1/4] net/axgbe: fix resource leaks in device init error paths
This patch addresses resource leaks in eth_axgbe_dev_init() by adding
proper cleanup code to multiple error paths. The changes include freeing
mac_addrs and hash_mac_addrs on failures, checking
rte_intr_callback_register() return value, and handling hw_if.exit()
errors properly.
> diff --git a/drivers/net/axgbe/axgbe_ethdev.c b/drivers/net/axgbe/axgbe_ethdev.c
> index cfcd880961..709a52acc8 100644
> --- a/drivers/net/axgbe/axgbe_ethdev.c
> +++ b/drivers/net/axgbe/axgbe_ethdev.c
> @@ -2359,6 +2359,8 @@ eth_axgbe_dev_init(struct rte_eth_dev *eth_dev)
> PMD_INIT_LOG(ERR,
> "Failed to allocate %d bytes needed to "
> "store MAC addresses", len);
> + rte_free(eth_dev->data->mac_addrs);
> + eth_dev->data->mac_addrs = NULL;
> return -ENOMEM;
> }
[ ... ]
> @@ -2405,8 +2407,14 @@ eth_axgbe_dev_init(struct rte_eth_dev *eth_dev)
> pdata->vdata->rx_max_fifo_size);
> /* Issue software reset to DMA */
> ret = pdata->hw_if.exit(pdata);
> - if (ret)
> + if (ret) {
> PMD_DRV_LOG_LINE(ERR, "hw_if->exit EBUSY error");
> + rte_free(eth_dev->data->hash_mac_addrs);
> + eth_dev->data->hash_mac_addrs = NULL;
> + rte_free(eth_dev->data->mac_addrs);
> + eth_dev->data->mac_addrs = NULL;
> + return ret;
> + }
[ ... ]
> @@ -2426,14 +2434,23 @@ eth_axgbe_dev_init(struct rte_eth_dev *eth_dev)
>
> ret = pdata->phy_if.phy_init(pdata);
> if (ret) {
> + rte_free(eth_dev->data->hash_mac_addrs);
> + eth_dev->data->hash_mac_addrs = NULL;
> rte_free(eth_dev->data->mac_addrs);
> eth_dev->data->mac_addrs = NULL;
> return ret;
> }
>
> - rte_intr_callback_register(pci_dev->intr_handle,
> + ret = rte_intr_callback_register(pci_dev->intr_handle,
> axgbe_dev_interrupt_handler,
> (void *)eth_dev);
> + if (ret) {
> + rte_free(eth_dev->data->hash_mac_addrs);
> + eth_dev->data->hash_mac_addrs = NULL;
> + rte_free(eth_dev->data->mac_addrs);
> + eth_dev->data->mac_addrs = NULL;
> + return ret;
> + }
> PMD_INIT_LOG(DEBUG, "port %d vendorID=0x%x deviceID=0x%x",
> eth_dev->data->port_id, pci_dev->id.vendor_id,
> pci_dev->id.device_id);
When rte_intr_callback_register() fails in eth_axgbe_dev_init(), does
this code need to unwind the phy_init() work? After phy_init() succeeds,
if interrupt registration fails, does this leave hardware in an
initialized state without proper cleanup? Should this error path also
call any corresponding phy cleanup function?
Commit: 20260508191109.734377-3
Author: Stephen Hemminger <stephen at networkplumber.org>
Subject: [PATCH v2 2/4] net/axgbe: fix Rx queue leak on descriptor init failure
This patch replaces individual rte_mbuf_raw_alloc() calls with
rte_pktmbuf_alloc_bulk() and adds proper cleanup of previously
initialized queues on failure.
> diff --git a/drivers/net/axgbe/axgbe_dev.c b/drivers/net/axgbe/axgbe_dev.c
> index 482d3d8062..9eabe0dfa8 100644
> --- a/drivers/net/axgbe/axgbe_dev.c
> +++ b/drivers/net/axgbe/axgbe_dev.c
> @@ -1011,13 +1011,11 @@ static void wrapper_tx_desc_init(struct axgbe_port *pdata)
>
> static int wrapper_rx_desc_init(struct axgbe_port *pdata)
> {
> - struct axgbe_rx_queue *rxq;
> - struct rte_mbuf *mbuf;
> volatile union axgbe_rx_desc *desc;
> unsigned int i, j;
>
> for (i = 0; i < pdata->eth_dev->data->nb_rx_queues; i++) {
> - rxq = pdata->eth_dev->data->rx_queues[i];
> + struct axgbe_rx_queue *rxq = pdata->eth_dev->data->rx_queues[i];
>
> /* Initialize software ring entries */
> rxq->mbuf_alloc = 0;
> @@ -1025,19 +1023,18 @@ static int wrapper_rx_desc_init(struct axgbe_port *pdata)
> rxq->dirty = 0;
> desc = AXGBE_GET_DESC_PT(rxq, 0);
>
> + if (!rte_pktmbuf_alloc_bulk(rxq->mb_pool, rxq->sw_ring, rxq->nb_desc)) {
Does the return value check here have the correct logic? Looking at
rte_pktmbuf_alloc_bulk() semantics, when does this function return 0
versus non-zero? The condition !rte_pktmbuf_alloc_bulk() suggests
entering the error path when the function returns 0, but typically bulk
allocation functions return 0 on success. Can this be verified against
the DPDK API documentation?
> + PMD_DRV_LOG_LINE(ERR, "RX mbuf alloc failed queue_id = %u, nb_desc = %u",
> + i, rxq->nb_desc);
> + for (unsigned int k = 0; k < i; k++)
> + axgbe_dev_rx_queue_release(pdata->eth_dev, k);
> + return -ENOMEM;
> + }
> +
> for (j = 0; j < rxq->nb_desc; j++) {
> - mbuf = rte_mbuf_raw_alloc(rxq->mb_pool);
> - if (mbuf == NULL) {
> - PMD_DRV_LOG_LINE(ERR, "RX mbuf alloc failed queue_id = %u, idx = %d",
> - (unsigned int)rxq->queue_id, j);
> - axgbe_dev_rx_queue_release(pdata->eth_dev, i);
> - return -ENOMEM;
> - }
> - rxq->sw_ring[j] = mbuf;
> - /* Mbuf populate */
> - mbuf->next = NULL;
> - mbuf->data_off = RTE_PKTMBUF_HEADROOM;
> - mbuf->nb_segs = 1;
> + struct rte_mbuf *mbuf = rxq->sw_ring[j];
> +
> + /* mbuf is in reset state (nb_segs = 1, headroom, etc) */
> mbuf->port = rxq->port_id;
> desc->read.baddr =
> rte_cpu_to_le_64(
The comment states mbufs are in reset state, but this changes the
behavior from using rte_mbuf_raw_alloc() to rte_pktmbuf_alloc_bulk().
Does rte_pktmbuf_alloc_bulk() provide the same guarantees as
rte_mbuf_raw_alloc() regarding mbuf initialization? The previous code
explicitly set next, data_off, and nb_segs fields after
rte_mbuf_raw_alloc(), but these assignments are removed. Does this
assume rte_pktmbuf_alloc_bulk() already initializes these fields, and
does this match the original code's expectations?
Commit: 20260508191109.734377-4
Author: Stephen Hemminger <stephen at networkplumber.org>
Subject: [PATCH v2 3/4] net/axgbe: destroy mutexes on device close
> diff --git a/drivers/net/axgbe/axgbe_ethdev.c b/drivers/net/axgbe/axgbe_ethdev.c
> index 709a52acc8..c8414998b4 100644
> --- a/drivers/net/axgbe/axgbe_ethdev.c
> +++ b/drivers/net/axgbe/axgbe_ethdev.c
> @@ -2482,6 +2482,11 @@ axgbe_dev_close(struct rte_eth_dev *eth_dev)
> /* Disable all interrupts in the hardware */
> XP_IOWRITE(pdata, XP_INT_EN, 0x0);
>
> + pthread_mutex_destroy(&pdata->xpcs_mutex);
> + pthread_mutex_destroy(&pdata->i2c_mutex);
> + pthread_mutex_destroy(&pdata->an_mutex);
> + pthread_mutex_destroy(&pdata->phy_mutex);
> +
> return 0;
> }
The mutexes are destroyed in axgbe_dev_close(), but the patch doesn't
address whether these mutexes could be in use (locked) at this point. In
the error paths added to eth_axgbe_dev_init() in patch 1/4, when init
fails before reaching the end, do any code paths leave these mutexes
locked? Does axgbe_dev_close()->pthread_mutex_destroy() need to check
lock state before destroying?
Commit: 20260508191109.734377-5
Author: Stephen Hemminger <stephen at networkplumber.org>
Subject: [PATCH v2 4/4] net/axgbe: fix descriptor status out-of-bounds access
> diff --git a/drivers/net/axgbe/axgbe_rxtx.c b/drivers/net/axgbe/axgbe_rxtx.c
> index 51a1aeb0b9..6f750d6ede 100644
> --- a/drivers/net/axgbe/axgbe_rxtx.c
> +++ b/drivers/net/axgbe/axgbe_rxtx.c
> @@ -1205,8 +1205,8 @@ axgbe_dev_rx_descriptor_status(void *rx_queue, uint16_t offset)
> if (offset >= rxq->nb_desc - rxq->dirty)
> return RTE_ETH_RX_DESC_UNAVAIL;
>
> - idx = AXGBE_GET_DESC_IDX(rxq, rxq->cur);
> - desc = &rxq->desc[idx + offset];
> + idx = AXGBE_GET_DESC_IDX(rxq, rxq->cur + offset);
> + desc = &rxq->desc[idx];
[ ... ]
> @@ -1228,8 +1228,8 @@ axgbe_dev_tx_descriptor_status(void *tx_queue, uint16_t offset)
> if (offset >= txq->nb_desc - txq->dirty)
> return RTE_ETH_TX_DESC_UNAVAIL;
>
> - idx = AXGBE_GET_DESC_IDX(txq, txq->dirty + txq->free_batch_cnt - 1);
> - desc = &txq->desc[idx + offset];
> + idx = AXGBE_GET_DESC_IDX(txq, txq->dirty + txq->free_batch_cnt - 1 + offset);
> + desc = &txq->desc[idx];
The arithmetic txq->dirty + txq->free_batch_cnt - 1 + offset involves
unsigned integer addition that could overflow before AXGBE_GET_DESC_IDX
applies the modulo operation. Does this arithmetic overflow issue matter
given that AXGBE_GET_DESC_IDX masks the result? Would it be clearer to
break this into separate operations to avoid potential undefined behavior
in the intermediate computation?
More information about the test-report
mailing list