[TEST,v10] ethdev: support single queue per port

Message ID 20241106220216.1505231-1-mb@smartsharesystems.com (mailing list archive)
State Superseded, archived
Delegated to: Thomas Monjalon
Headers
Series [TEST,v10] ethdev: support single queue per port |

Checks

Context Check Description
ci/checkpatch warning coding style issues
ci/loongarch-compilation success Compilation OK
ci/loongarch-unit-testing fail Unit Testing FAIL
ci/Intel-compilation success Compilation OK
ci/intel-Testing success Testing PASS
ci/intel-Functional success Functional PASS
ci/github-robot: build fail github build: failed
ci/iol-mellanox-Performance success Performance Testing PASS
ci/iol-marvell-Functional success Functional Testing PASS
ci/iol-intel-Functional fail Functional Testing issues
ci/iol-unit-amd64-testing fail Testing issues
ci/iol-unit-arm64-testing pending Testing pending
ci/iol-broadcom-Performance success Performance Testing PASS
ci/iol-compile-amd64-testing success Testing PASS
ci/iol-compile-arm64-testing success Testing PASS
ci/iol-sample-apps-testing success Testing PASS

Commit Message

Morten Brørup Nov. 6, 2024, 10:02 p.m. UTC
Configuring one queue per port (#define RTE_MAX_QUEUES_PER_PORT 1) fails
compilation with e.g.:

../drivers/net/bnxt/bnxt_rxq.c: In function 'bnxt_rx_queue_stop':
../drivers/net/bnxt/bnxt_rxq.c:587:34: error: array subscript 1 is above array bounds of 'uint8_t[1]' {aka 'unsigned char[1]'} [-Werror=array-bounds=]
  587 |         dev->data->rx_queue_state[q_id] = RTE_ETH_QUEUE_STATE_STOPPED;
      |         ~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~
In file included from ../drivers/net/bnxt/bnxt.h:16,
                 from ../drivers/net/bnxt/bnxt_rxq.c:10:
../lib/ethdev/ethdev_driver.h:168:17: note: while referencing 'rx_queue_state'
  168 |         uint8_t rx_queue_state[RTE_MAX_QUEUES_PER_PORT];
      |                 ^~~~~~~~~~~~~~

Use the CI to test my ideas to fix this.

Signed-off-by: Morten Brørup <mb@smartsharesystems.com>
---
v10:
* Rebased to main.
v9:
* Moved __rte_assume() in mana driver, to test if it works outside loop.
v8:
* Added __rte_unreachable() macro.
* GCC version 13 is required for __attribute__((assume())).
  Provide alternative implementation, using __rte_unreachable(), for
  older GCC versions.
* Added MSVC implementations of the two new macros.
v7:
* Introduce __rte_assume() in rte_common.h, and use this instead.
v6:
* Use __attribute__((assume(i < RTE_MAX_QUEUES_PER_PORT))) where the
  indexing warning occurs, instead of pragma GCC optimize("no-peel-loops")
  for the entire function.
v5:
* Wrap GCC optimizer pragmas in if defined(RTE_TOOLCHAIN_GCC).
v4:
* Workaound GCC optimizer incorrectly throwing a warning in these network
  drivers:
  * bnxt
  * e1000
  * failsafe
  * hns3
v3:
* Fix net/ixgbe driver.
v2:
* Fix net/vmxnet3 driver.
---
 config/rte_config.h                  |  4 ++--
 drivers/net/bnxt/bnxt_ethdev.c       |  2 ++
 drivers/net/bnxt/bnxt_rxq.c          |  1 +
 drivers/net/e1000/igb_rxtx.c         |  2 ++
 drivers/net/failsafe/failsafe_ops.c  | 10 ++++++--
 drivers/net/hns3/hns3_rxtx.c         |  2 ++
 drivers/net/mana/tx.c                |  1 +
 drivers/net/vmxnet3/vmxnet3_ethdev.c | 34 +++++++++++++++++-----------
 drivers/net/vmxnet3/vmxnet3_ethdev.h |  4 ++--
 lib/eal/include/rte_common.h         | 27 ++++++++++++++++++++++
 10 files changed, 68 insertions(+), 19 deletions(-)
  

Comments

Stephen Hemminger Nov. 6, 2024, 11:25 p.m. UTC | #1
On Wed,  6 Nov 2024 22:02:16 +0000
Morten Brørup <mb@smartsharesystems.com> wrote:

> iff --git a/drivers/net/vmxnet3/vmxnet3_ethdev.c b/drivers/net/vmxnet3/vmxnet3_ethdev.c
> index 78fac63ab6..1752c58069 100644
> --- a/drivers/net/vmxnet3/vmxnet3_ethdev.c
> +++ b/drivers/net/vmxnet3/vmxnet3_ethdev.c
> @@ -1470,42 +1470,52 @@ vmxnet3_dev_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *stats)
>  	struct vmxnet3_hw *hw = dev->data->dev_private;
>  	struct UPT1_TxStats txStats;
>  	struct UPT1_RxStats rxStats;
> +	uint64_t packets, bytes;
>  
>  	VMXNET3_WRITE_BAR1_REG(hw, VMXNET3_REG_CMD, VMXNET3_CMD_GET_STATS);
>  
>  	for (i = 0; i < hw->num_tx_queues; i++) {
>  		vmxnet3_tx_stats_get(hw, i, &txStats);
>  
> -		stats->q_opackets[i] = txStats.ucastPktsTxOK +
> +		packets = txStats.ucastPktsTxOK +
>  			txStats.mcastPktsTxOK +
>  			txStats.bcastPktsTxOK;
>  
> -		stats->q_obytes[i] = txStats.ucastBytesTxOK +
> +		bytes = txStats.ucastBytesTxOK +
>  			txStats.mcastBytesTxOK +
>  			txStats.bcastBytesTxOK;
>  
> -		stats->opackets += stats->q_opackets[i];
> -		stats->obytes += stats->q_obytes[i];
> +		stats->opackets += packets;
> +		stats->obytes += bytes;
>  		stats->oerrors += txStats.pktsTxError + txStats.pktsTxDiscard;
> +
> +		if (i < RTE_ETHDEV_QUEUE_STAT_CNTRS) {
> +			stats->q_opackets[i] = packets;
> +			stats->q_obytes[i] = bytes;
> +		}
>  	}
>  
>  	for (i = 0; i < hw->num_rx_queues; i++) {
>  		vmxnet3_rx_stats_get(hw, i, &rxStats);
>  
> -		stats->q_ipackets[i] = rxStats.ucastPktsRxOK +
> +		packets = rxStats.ucastPktsRxOK +
>  			rxStats.mcastPktsRxOK +
>  			rxStats.bcastPktsRxOK;
>  
> -		stats->q_ibytes[i] = rxStats.ucastBytesRxOK +
> +		bytes = rxStats.ucastBytesRxOK +
>  			rxStats.mcastBytesRxOK +
>  			rxStats.bcastBytesRxOK;
>  
> -		stats->ipackets += stats->q_ipackets[i];
> -		stats->ibytes += stats->q_ibytes[i];
> -
> -		stats->q_errors[i] = rxStats.pktsRxError;
> +		stats->ipackets += packets;
> +		stats->ibytes += bytes;
>  		stats->ierrors += rxStats.pktsRxError;
>  		stats->imissed += rxStats.pktsRxOutOfBuf;
> +
> +		if (i < RTE_ETHDEV_QUEUE_STAT_CNTRS) {
> +			stats->q_ipackets[i] = packets;
> +			stats->q_ibytes[i] = bytes;
> +			stats->q_errors[i] = rxStats.pktsRxError;
> +		}
>  	}
>  
>  	return 0;

This fixes a bug in existing code of RTE_ETHDEV_QUEUE_STAT_CNTRS < num queues.
Probably deserves its own patch with Fixes
  
Morten Brørup Nov. 7, 2024, 9:35 a.m. UTC | #2
> From: Stephen Hemminger [mailto:stephen@networkplumber.org]
> Sent: Thursday, 7 November 2024 00.26
T v10] ethdev: support single queue per port
> 
> On Wed,  6 Nov 2024 22:02:16 +0000
> Morten Brørup <mb@smartsharesystems.com> wrote:
> 
> > iff --git a/drivers/net/vmxnet3/vmxnet3_ethdev.c
> b/drivers/net/vmxnet3/vmxnet3_ethdev.c
> > index 78fac63ab6..1752c58069 100644
> > --- a/drivers/net/vmxnet3/vmxnet3_ethdev.c
> > +++ b/drivers/net/vmxnet3/vmxnet3_ethdev.c
> > @@ -1470,42 +1470,52 @@ vmxnet3_dev_stats_get(struct rte_eth_dev
> *dev, struct rte_eth_stats *stats)
> >  	struct vmxnet3_hw *hw = dev->data->dev_private;
> >  	struct UPT1_TxStats txStats;
> >  	struct UPT1_RxStats rxStats;
> > +	uint64_t packets, bytes;
> >
> >  	VMXNET3_WRITE_BAR1_REG(hw, VMXNET3_REG_CMD,
> VMXNET3_CMD_GET_STATS);
> >
> >  	for (i = 0; i < hw->num_tx_queues; i++) {
> >  		vmxnet3_tx_stats_get(hw, i, &txStats);
> >
> > -		stats->q_opackets[i] = txStats.ucastPktsTxOK +
> > +		packets = txStats.ucastPktsTxOK +
> >  			txStats.mcastPktsTxOK +
> >  			txStats.bcastPktsTxOK;
> >
> > -		stats->q_obytes[i] = txStats.ucastBytesTxOK +
> > +		bytes = txStats.ucastBytesTxOK +
> >  			txStats.mcastBytesTxOK +
> >  			txStats.bcastBytesTxOK;
> >
> > -		stats->opackets += stats->q_opackets[i];
> > -		stats->obytes += stats->q_obytes[i];
> > +		stats->opackets += packets;
> > +		stats->obytes += bytes;
> >  		stats->oerrors += txStats.pktsTxError +
> txStats.pktsTxDiscard;
> > +
> > +		if (i < RTE_ETHDEV_QUEUE_STAT_CNTRS) {
> > +			stats->q_opackets[i] = packets;
> > +			stats->q_obytes[i] = bytes;
> > +		}
> >  	}
> >
> >  	for (i = 0; i < hw->num_rx_queues; i++) {
> >  		vmxnet3_rx_stats_get(hw, i, &rxStats);
> >
> > -		stats->q_ipackets[i] = rxStats.ucastPktsRxOK +
> > +		packets = rxStats.ucastPktsRxOK +
> >  			rxStats.mcastPktsRxOK +
> >  			rxStats.bcastPktsRxOK;
> >
> > -		stats->q_ibytes[i] = rxStats.ucastBytesRxOK +
> > +		bytes = rxStats.ucastBytesRxOK +
> >  			rxStats.mcastBytesRxOK +
> >  			rxStats.bcastBytesRxOK;
> >
> > -		stats->ipackets += stats->q_ipackets[i];
> > -		stats->ibytes += stats->q_ibytes[i];
> > -
> > -		stats->q_errors[i] = rxStats.pktsRxError;
> > +		stats->ipackets += packets;
> > +		stats->ibytes += bytes;
> >  		stats->ierrors += rxStats.pktsRxError;
> >  		stats->imissed += rxStats.pktsRxOutOfBuf;
> > +
> > +		if (i < RTE_ETHDEV_QUEUE_STAT_CNTRS) {
> > +			stats->q_ipackets[i] = packets;
> > +			stats->q_ibytes[i] = bytes;
> > +			stats->q_errors[i] = rxStats.pktsRxError;
> > +		}
> >  	}
> >
> >  	return 0;
> 
> This fixes a bug in existing code of RTE_ETHDEV_QUEUE_STAT_CNTRS < num
> queues.
> Probably deserves its own patch with Fixes

Thanks for noticing, Stephen.

Ferruh also noticed, and has already applied such a patch:
https://patchwork.dpdk.org/project/dpdk/patch/20241104105220.1421305-1-mb@smartsharesystems.com/

The turnaround time was unusual quick on that one - it went in and out of Patchwork in a flash. Don't blink! ;-)
  

Patch

diff --git a/config/rte_config.h b/config/rte_config.h
index fd6f8a2f1a..924192c71c 100644
--- a/config/rte_config.h
+++ b/config/rte_config.h
@@ -65,8 +65,8 @@ 
 #define RTE_MBUF_DEFAULT_MEMPOOL_OPS "ring_mp_mc"
 
 /* ether defines */
-#define RTE_MAX_QUEUES_PER_PORT 1024
-#define RTE_ETHDEV_QUEUE_STAT_CNTRS 16 /* max 256 */
+#define RTE_MAX_QUEUES_PER_PORT 1 /* default 1024 */
+#define RTE_ETHDEV_QUEUE_STAT_CNTRS 1 /* max 256, default 16 */
 #define RTE_ETHDEV_RXTX_CALLBACKS 1
 #define RTE_MAX_MULTI_HOST_CTRLS 4
 
diff --git a/drivers/net/bnxt/bnxt_ethdev.c b/drivers/net/bnxt/bnxt_ethdev.c
index 1f7c0d77d5..136e308437 100644
--- a/drivers/net/bnxt/bnxt_ethdev.c
+++ b/drivers/net/bnxt/bnxt_ethdev.c
@@ -910,6 +910,7 @@  static int bnxt_start_nic(struct bnxt *bp)
 		struct bnxt_rx_queue *rxq = bp->rx_queues[j];
 
 		if (!rxq->rx_deferred_start) {
+			__rte_assume(j < RTE_MAX_QUEUES_PER_PORT);
 			bp->eth_dev->data->rx_queue_state[j] =
 				RTE_ETH_QUEUE_STATE_STARTED;
 			rxq->rx_started = true;
@@ -930,6 +931,7 @@  static int bnxt_start_nic(struct bnxt *bp)
 		struct bnxt_tx_queue *txq = bp->tx_queues[j];
 
 		if (!txq->tx_deferred_start) {
+			__rte_assume(j < RTE_MAX_QUEUES_PER_PORT);
 			bp->eth_dev->data->tx_queue_state[j] =
 				RTE_ETH_QUEUE_STATE_STARTED;
 			txq->tx_started = true;
diff --git a/drivers/net/bnxt/bnxt_rxq.c b/drivers/net/bnxt/bnxt_rxq.c
index 1c25c57ca6..1651c26545 100644
--- a/drivers/net/bnxt/bnxt_rxq.c
+++ b/drivers/net/bnxt/bnxt_rxq.c
@@ -584,6 +584,7 @@  int bnxt_rx_queue_stop(struct rte_eth_dev *dev, uint16_t rx_queue_id)
 		return -EINVAL;
 	}
 
+	__rte_assume(q_id < RTE_MAX_QUEUES_PER_PORT);
 	dev->data->rx_queue_state[q_id] = RTE_ETH_QUEUE_STATE_STOPPED;
 	rxq->rx_started = false;
 	PMD_DRV_LOG_LINE(DEBUG, "Rx queue stopped");
diff --git a/drivers/net/e1000/igb_rxtx.c b/drivers/net/e1000/igb_rxtx.c
index d61eaad2de..4276bb6d31 100644
--- a/drivers/net/e1000/igb_rxtx.c
+++ b/drivers/net/e1000/igb_rxtx.c
@@ -1868,6 +1868,7 @@  igb_dev_clear_queues(struct rte_eth_dev *dev)
 	struct igb_rx_queue *rxq;
 
 	for (i = 0; i < dev->data->nb_tx_queues; i++) {
+		__rte_assume(i < RTE_MAX_QUEUES_PER_PORT);
 		txq = dev->data->tx_queues[i];
 		if (txq != NULL) {
 			igb_tx_queue_release_mbufs(txq);
@@ -1877,6 +1878,7 @@  igb_dev_clear_queues(struct rte_eth_dev *dev)
 	}
 
 	for (i = 0; i < dev->data->nb_rx_queues; i++) {
+		__rte_assume(i < RTE_MAX_QUEUES_PER_PORT);
 		rxq = dev->data->rx_queues[i];
 		if (rxq != NULL) {
 			igb_rx_queue_release_mbufs(rxq);
diff --git a/drivers/net/failsafe/failsafe_ops.c b/drivers/net/failsafe/failsafe_ops.c
index 9c013e0419..5321c3385c 100644
--- a/drivers/net/failsafe/failsafe_ops.c
+++ b/drivers/net/failsafe/failsafe_ops.c
@@ -111,12 +111,14 @@  fs_set_queues_state_start(struct rte_eth_dev *dev)
 	uint16_t i;
 
 	for (i = 0; i < dev->data->nb_rx_queues; i++) {
+		__rte_assume(i < RTE_MAX_QUEUES_PER_PORT);
 		rxq = dev->data->rx_queues[i];
 		if (rxq != NULL && !rxq->info.conf.rx_deferred_start)
 			dev->data->rx_queue_state[i] =
 						RTE_ETH_QUEUE_STATE_STARTED;
 	}
 	for (i = 0; i < dev->data->nb_tx_queues; i++) {
+		__rte_assume(i < RTE_MAX_QUEUES_PER_PORT);
 		txq = dev->data->tx_queues[i];
 		if (txq != NULL && !txq->info.conf.tx_deferred_start)
 			dev->data->tx_queue_state[i] =
@@ -176,14 +178,18 @@  fs_set_queues_state_stop(struct rte_eth_dev *dev)
 {
 	uint16_t i;
 
-	for (i = 0; i < dev->data->nb_rx_queues; i++)
+	for (i = 0; i < dev->data->nb_rx_queues; i++) {
+		__rte_assume(i < RTE_MAX_QUEUES_PER_PORT);
 		if (dev->data->rx_queues[i] != NULL)
 			dev->data->rx_queue_state[i] =
 						RTE_ETH_QUEUE_STATE_STOPPED;
-	for (i = 0; i < dev->data->nb_tx_queues; i++)
+	}
+	for (i = 0; i < dev->data->nb_tx_queues; i++) {
+		__rte_assume(i < RTE_MAX_QUEUES_PER_PORT);
 		if (dev->data->tx_queues[i] != NULL)
 			dev->data->tx_queue_state[i] =
 						RTE_ETH_QUEUE_STATE_STOPPED;
+	}
 }
 
 static int
diff --git a/drivers/net/hns3/hns3_rxtx.c b/drivers/net/hns3/hns3_rxtx.c
index 5941b966e0..03bbbc435f 100644
--- a/drivers/net/hns3/hns3_rxtx.c
+++ b/drivers/net/hns3/hns3_rxtx.c
@@ -1309,6 +1309,7 @@  hns3_start_tqps(struct hns3_hw *hw)
 	hns3_enable_all_queues(hw, true);
 
 	for (i = 0; i < hw->data->nb_tx_queues; i++) {
+		__rte_assume(i < RTE_MAX_QUEUES_PER_PORT);
 		txq = hw->data->tx_queues[i];
 		if (txq->enabled)
 			hw->data->tx_queue_state[i] =
@@ -1316,6 +1317,7 @@  hns3_start_tqps(struct hns3_hw *hw)
 	}
 
 	for (i = 0; i < hw->data->nb_rx_queues; i++) {
+		__rte_assume(i < RTE_MAX_QUEUES_PER_PORT);
 		rxq = hw->data->rx_queues[i];
 		if (rxq->enabled)
 			hw->data->rx_queue_state[i] =
diff --git a/drivers/net/mana/tx.c b/drivers/net/mana/tx.c
index 272a28bcba..e2352e6300 100644
--- a/drivers/net/mana/tx.c
+++ b/drivers/net/mana/tx.c
@@ -74,6 +74,7 @@  mana_start_tx_queues(struct rte_eth_dev *dev)
 		if (dev->data->tx_queue_state[i] == RTE_ETH_QUEUE_STATE_STARTED)
 			return -EINVAL;
 
+    __rte_assume(priv->num_queues < RTE_MAX_QUEUES_PER_PORT);
 	for (i = 0; i < priv->num_queues; i++) {
 		struct mana_txq *txq;
 		struct ibv_qp_init_attr qp_attr = { 0 };
diff --git a/drivers/net/vmxnet3/vmxnet3_ethdev.c b/drivers/net/vmxnet3/vmxnet3_ethdev.c
index 78fac63ab6..1752c58069 100644
--- a/drivers/net/vmxnet3/vmxnet3_ethdev.c
+++ b/drivers/net/vmxnet3/vmxnet3_ethdev.c
@@ -1470,42 +1470,52 @@  vmxnet3_dev_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *stats)
 	struct vmxnet3_hw *hw = dev->data->dev_private;
 	struct UPT1_TxStats txStats;
 	struct UPT1_RxStats rxStats;
+	uint64_t packets, bytes;
 
 	VMXNET3_WRITE_BAR1_REG(hw, VMXNET3_REG_CMD, VMXNET3_CMD_GET_STATS);
 
 	for (i = 0; i < hw->num_tx_queues; i++) {
 		vmxnet3_tx_stats_get(hw, i, &txStats);
 
-		stats->q_opackets[i] = txStats.ucastPktsTxOK +
+		packets = txStats.ucastPktsTxOK +
 			txStats.mcastPktsTxOK +
 			txStats.bcastPktsTxOK;
 
-		stats->q_obytes[i] = txStats.ucastBytesTxOK +
+		bytes = txStats.ucastBytesTxOK +
 			txStats.mcastBytesTxOK +
 			txStats.bcastBytesTxOK;
 
-		stats->opackets += stats->q_opackets[i];
-		stats->obytes += stats->q_obytes[i];
+		stats->opackets += packets;
+		stats->obytes += bytes;
 		stats->oerrors += txStats.pktsTxError + txStats.pktsTxDiscard;
+
+		if (i < RTE_ETHDEV_QUEUE_STAT_CNTRS) {
+			stats->q_opackets[i] = packets;
+			stats->q_obytes[i] = bytes;
+		}
 	}
 
 	for (i = 0; i < hw->num_rx_queues; i++) {
 		vmxnet3_rx_stats_get(hw, i, &rxStats);
 
-		stats->q_ipackets[i] = rxStats.ucastPktsRxOK +
+		packets = rxStats.ucastPktsRxOK +
 			rxStats.mcastPktsRxOK +
 			rxStats.bcastPktsRxOK;
 
-		stats->q_ibytes[i] = rxStats.ucastBytesRxOK +
+		bytes = rxStats.ucastBytesRxOK +
 			rxStats.mcastBytesRxOK +
 			rxStats.bcastBytesRxOK;
 
-		stats->ipackets += stats->q_ipackets[i];
-		stats->ibytes += stats->q_ibytes[i];
-
-		stats->q_errors[i] = rxStats.pktsRxError;
+		stats->ipackets += packets;
+		stats->ibytes += bytes;
 		stats->ierrors += rxStats.pktsRxError;
 		stats->imissed += rxStats.pktsRxOutOfBuf;
+
+		if (i < RTE_ETHDEV_QUEUE_STAT_CNTRS) {
+			stats->q_ipackets[i] = packets;
+			stats->q_ibytes[i] = bytes;
+			stats->q_errors[i] = rxStats.pktsRxError;
+		}
 	}
 
 	return 0;
@@ -1521,8 +1531,6 @@  vmxnet3_dev_stats_reset(struct rte_eth_dev *dev)
 
 	VMXNET3_WRITE_BAR1_REG(hw, VMXNET3_REG_CMD, VMXNET3_CMD_GET_STATS);
 
-	RTE_BUILD_BUG_ON(RTE_ETHDEV_QUEUE_STAT_CNTRS < VMXNET3_MAX_TX_QUEUES);
-
 	for (i = 0; i < hw->num_tx_queues; i++) {
 		vmxnet3_hw_tx_stats_get(hw, i, &txStats);
 		memcpy(&hw->snapshot_tx_stats[i], &txStats,
@@ -1566,7 +1574,7 @@  vmxnet3_dev_info_get(struct rte_eth_dev *dev,
 	dev_info->min_rx_bufsize = 1518 + RTE_PKTMBUF_HEADROOM;
 	dev_info->max_rx_pktlen = 16384; /* includes CRC, cf MAXFRS register */
 	dev_info->min_mtu = VMXNET3_MIN_MTU;
-	dev_info->max_mtu = VMXNET3_MAX_MTU;
+	dev_info->max_mtu = VMXNET3_VERSION_GE_6(hw) ? VMXNET3_V6_MAX_MTU : VMXNET3_MAX_MTU;
 	dev_info->speed_capa = RTE_ETH_LINK_SPEED_10G;
 	dev_info->max_mac_addrs = VMXNET3_MAX_MAC_ADDRS;
 
diff --git a/drivers/net/vmxnet3/vmxnet3_ethdev.h b/drivers/net/vmxnet3/vmxnet3_ethdev.h
index 2b3e2c4caa..e9ded6663d 100644
--- a/drivers/net/vmxnet3/vmxnet3_ethdev.h
+++ b/drivers/net/vmxnet3/vmxnet3_ethdev.h
@@ -121,8 +121,8 @@  struct vmxnet3_hw {
 #define VMXNET3_VFT_TABLE_SIZE     (VMXNET3_VFT_SIZE * sizeof(uint32_t))
 	UPT1_TxStats	      saved_tx_stats[VMXNET3_EXT_MAX_TX_QUEUES];
 	UPT1_RxStats	      saved_rx_stats[VMXNET3_EXT_MAX_RX_QUEUES];
-	UPT1_TxStats          snapshot_tx_stats[VMXNET3_MAX_TX_QUEUES];
-	UPT1_RxStats          snapshot_rx_stats[VMXNET3_MAX_RX_QUEUES];
+	UPT1_TxStats          snapshot_tx_stats[VMXNET3_EXT_MAX_TX_QUEUES];
+	UPT1_RxStats          snapshot_rx_stats[VMXNET3_EXT_MAX_RX_QUEUES];
 	uint16_t              tx_prod_offset;
 	uint16_t              rx_prod_offset[2];
 	/* device capability bit map */
diff --git a/lib/eal/include/rte_common.h b/lib/eal/include/rte_common.h
index c79f9ed319..2f143c87e4 100644
--- a/lib/eal/include/rte_common.h
+++ b/lib/eal/include/rte_common.h
@@ -366,6 +366,16 @@  static void __attribute__((destructor(RTE_PRIO(prio)), used)) func(void)
 #define __rte_noreturn __attribute__((noreturn))
 #endif
 
+/**
+ * Hint point in program never reached
+ */
+#if defined(RTE_TOOLCHAIN_GCC) || defined(RTE_TOOLCHAIN_CLANG)
+#define __rte_unreachable() __extension__(__builtin_unreachable())
+#else
+/* MSVC or ICC */
+#define __rte_unreachable() __assume(0)
+#endif
+
 /**
  * Issue a warning in case the function's return value is ignored.
  *
@@ -423,6 +433,23 @@  static void __attribute__((destructor(RTE_PRIO(prio)), used)) func(void)
 #define __rte_cold __attribute__((cold))
 #endif
 
+/**
+ * Hint precondition
+ *
+ * @warning Depending on the compiler, any code in ``condition`` might be executed.
+ * This currently only occurs with GCC prior to version 13.
+ */
+#if defined(RTE_TOOLCHAIN_GCC) && (GCC_VERSION >= 130000)
+#define __rte_assume(condition) __attribute__((assume(condition)))
+#elif defined(RTE_TOOLCHAIN_GCC)
+#define __rte_assume(condition) do { if (!(condition)) __rte_unreachable(); } while (0)
+#elif defined(RTE_TOOLCHAIN_CLANG)
+#define __rte_assume(condition) __extension__(__builtin_assume(condition))
+#else
+/* MSVC or ICC */
+#define __rte_assume(condition) __assume(condition)
+#endif
+
 /**
  * Disable AddressSanitizer on some code
  */