[RFC 2/2] net/iavf: restore promiscuous mode only after VF reset

Ciara Loftus ciara.loftus at intel.com
Tue Jul 21 15:08:14 CEST 2026


The promiscuous and all-multicast settings persist in hardware across
a port stop/start and are only cleared by a VF reset. Despite this,
the ethdev start path re-applied them on every `dev_start` through the
config restore logic. Together with the driver's own restore after a
reset, a reset followed by a start reprogrammed them twice and issued
redundant requests to the PF.

Implement the `get_restore_flags` callback to clear
`RTE_ETH_RESTORE_PROMISC` and `RTE_ETH_RESTORE_ALLMULTI` so ethdev
skips them on start; the driver restores them only after a VF reset.
A queue reconfiguration in `iavf_dev_configure` also triggers a reset,
so the states are re-applied there too, except during reset recovery
where the reset handler already restores them once.

Signed-off-by: Ciara Loftus <ciara.loftus at intel.com>
---
 drivers/net/intel/iavf/iavf_ethdev.c | 34 ++++++++++++++++++++++++++++
 1 file changed, 34 insertions(+)

diff --git a/drivers/net/intel/iavf/iavf_ethdev.c b/drivers/net/intel/iavf/iavf_ethdev.c
index 829573983a..183d986831 100644
--- a/drivers/net/intel/iavf/iavf_ethdev.c
+++ b/drivers/net/intel/iavf/iavf_ethdev.c
@@ -163,6 +163,9 @@ static int iavf_set_mc_addr_list(struct rte_eth_dev *dev,
 			struct rte_ether_addr *mc_addrs,
 			uint32_t mc_addrs_num);
 static int iavf_tm_ops_get(struct rte_eth_dev *dev __rte_unused, void *arg);
+static uint64_t iavf_get_restore_flags(struct rte_eth_dev *dev,
+				       enum rte_eth_dev_operation op);
+static int iavf_post_reset_reconfig(struct rte_eth_dev *dev);
 
 static const struct rte_pci_id pci_id_iavf_map[] = {
 	{ RTE_PCI_DEVICE(IAVF_INTEL_VENDOR_ID, IAVF_DEV_ID_ADAPTIVE_VF) },
@@ -262,6 +265,7 @@ static const struct eth_dev_ops iavf_eth_dev_ops = {
 	.tx_done_cleanup	    = iavf_dev_tx_done_cleanup,
 	.get_monitor_addr           = iavf_get_monitor_addr,
 	.tm_ops_get                 = iavf_tm_ops_get,
+	.get_restore_flags          = iavf_get_restore_flags,
 };
 
 static int
@@ -282,6 +286,19 @@ iavf_tm_ops_get(struct rte_eth_dev *dev,
 	return 0;
 }
 
+static uint64_t
+iavf_get_restore_flags(__rte_unused struct rte_eth_dev *dev,
+		       __rte_unused enum rte_eth_dev_operation op)
+{
+	/*
+	 * The unicast and multicast promiscuous settings persist across a
+	 * stop/start; they are only cleared by a VF reset, which the driver
+	 * restores itself. So ethdev does not need to restore them on start.
+	 */
+	return RTE_ETH_RESTORE_ALL & ~(RTE_ETH_RESTORE_PROMISC |
+				       RTE_ETH_RESTORE_ALLMULTI);
+}
+
 __rte_unused
 static int
 iavf_vfr_inprogress(struct iavf_hw *hw)
@@ -673,6 +690,7 @@ iavf_dev_configure(struct rte_eth_dev *dev)
 	struct iavf_info *vf =  IAVF_DEV_PRIVATE_TO_VF(ad);
 	uint16_t num_queue_pairs = RTE_MAX(dev->data->nb_rx_queues,
 		dev->data->nb_tx_queues);
+	bool reset_done = false;
 	int ret;
 
 	if (ad->closed)
@@ -702,6 +720,7 @@ iavf_dev_configure(struct rte_eth_dev *dev)
 		ret = iavf_queues_req_reset(dev, num_queue_pairs);
 		if (ret)
 			return ret;
+		reset_done = true;
 
 		ret = iavf_get_max_rss_queue_region(ad);
 		if (ret) {
@@ -720,6 +739,7 @@ iavf_dev_configure(struct rte_eth_dev *dev)
 			ret = iavf_queues_req_reset(dev, num_queue_pairs);
 			if (ret)
 				return ret;
+			reset_done = true;
 
 			vf->lv_enabled = false;
 		}
@@ -735,6 +755,20 @@ iavf_dev_configure(struct rte_eth_dev *dev)
 			return -1;
 		}
 	}
+
+	/*
+	 * A queue reconfiguration above triggers a VF reset, which clears the
+	 * promiscuous and all-multicast settings in hardware. Re-apply the
+	 * pre-reset states here, unless this configure is itself part of reset
+	 * recovery, in which case the reset handler restores them once at the
+	 * end (avoiding a double restore).
+	 */
+	if (reset_done && !vf->in_reset_recovery) {
+		ret = iavf_post_reset_reconfig(dev);
+		if (ret)
+			return ret;
+	}
+
 	return 0;
 }
 
-- 
2.43.0



More information about the dev mailing list