public inbox for dev@dpdk.org
 help / color / mirror / Atom feed
From: Stephen Hemminger <stephen@networkplumber.org>
To: dev@dpdk.org
Cc: Stephen Hemminger <stephen@networkplumber.org>,
	stable@dpdk.org, Madhuker Mythri <madhukar.mythri@gmail.com>
Subject: [RFT 1/2] net/netvsc: fix RNDIS command concurrency issue
Date: Tue, 13 Jan 2026 08:58:06 -0800	[thread overview]
Message-ID: <20260113170143.70873-2-stephen@networkplumber.org> (raw)
In-Reply-To: <20260113170143.70873-1-stephen@networkplumber.org>

When multiple threads issue RNDIS command requests (such as device
info queries) simultaneously, command failures can occur due to
concurrent access to shared resources in the RNDIS execution path.
The RNDIS layer only supports one pending request at a time, and
hn_rndis_exec1() returns -EBUSY if a request is already in progress.

Functions like hn_rndis_get_offload(), hn_rndis_conf_offload(), and
hn_rndis_get_ptypes() were querying hardware capabilities on each
call, which could race with other RNDIS commands from different
threads.

Fix this by querying the hardware offload capabilities once during
device attach in hn_rndis_attach() and caching the result in the
hn_data structure. All subsequent accesses use the cached value,
eliminating the race condition.

If the hwcaps query fails during attach, the device initialization
fails entirely. This matches the behavior of the Linux netvsc driver
(see rndis_netdev_set_hwcaps in rndis_filter.c).

Fixes: 4e9c73e96e83 ("net/netvsc: add Hyper-V network device")
Cc: stable@dpdk.org

Reported-by: Madhuker Mythri <madhukar.mythri@gmail.com>
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
 drivers/net/netvsc/hn_rndis.c | 110 ++++++++++++++++------------------
 drivers/net/netvsc/hn_var.h   |   4 ++
 2 files changed, 57 insertions(+), 57 deletions(-)

diff --git a/drivers/net/netvsc/hn_rndis.c b/drivers/net/netvsc/hn_rndis.c
index 7c54eebcef..ed053ee905 100644
--- a/drivers/net/netvsc/hn_rndis.c
+++ b/drivers/net/netvsc/hn_rndis.c
@@ -781,15 +781,9 @@ int hn_rndis_conf_offload(struct hn_data *hv,
 			  uint64_t tx_offloads, uint64_t rx_offloads)
 {
 	struct ndis_offload_params params;
-	struct ndis_offload hwcaps;
+	const struct ndis_offload *hwcaps = &hv->hwcaps;
 	int error;
 
-	error = hn_rndis_query_hwcaps(hv, &hwcaps);
-	if (error) {
-		PMD_DRV_LOG(ERR, "hwcaps query failed: %d", error);
-		return error;
-	}
-
 	/* NOTE: 0 means "no change" */
 	memset(&params, 0, sizeof(params));
 
@@ -803,25 +797,25 @@ int hn_rndis_conf_offload(struct hn_data *hv,
 	}
 
 	if (tx_offloads & RTE_ETH_TX_OFFLOAD_TCP_CKSUM) {
-		if (hwcaps.ndis_csum.ndis_ip4_txcsum & NDIS_TXCSUM_CAP_TCP4)
+		if (hwcaps->ndis_csum.ndis_ip4_txcsum & NDIS_TXCSUM_CAP_TCP4)
 			params.ndis_tcp4csum = NDIS_OFFLOAD_PARAM_TX;
 		else
 			goto unsupported;
 
-		if (hwcaps.ndis_csum.ndis_ip6_txcsum & NDIS_TXCSUM_CAP_TCP6)
+		if (hwcaps->ndis_csum.ndis_ip6_txcsum & NDIS_TXCSUM_CAP_TCP6)
 			params.ndis_tcp6csum = NDIS_OFFLOAD_PARAM_TX;
 		else
 			goto unsupported;
 	}
 
 	if (rx_offloads & RTE_ETH_RX_OFFLOAD_TCP_CKSUM) {
-		if ((hwcaps.ndis_csum.ndis_ip4_rxcsum & NDIS_RXCSUM_CAP_TCP4)
+		if ((hwcaps->ndis_csum.ndis_ip4_rxcsum & NDIS_RXCSUM_CAP_TCP4)
 		    == NDIS_RXCSUM_CAP_TCP4)
 			params.ndis_tcp4csum |= NDIS_OFFLOAD_PARAM_RX;
 		else
 			goto unsupported;
 
-		if ((hwcaps.ndis_csum.ndis_ip6_rxcsum & NDIS_RXCSUM_CAP_TCP6)
+		if ((hwcaps->ndis_csum.ndis_ip6_rxcsum & NDIS_RXCSUM_CAP_TCP6)
 		    == NDIS_RXCSUM_CAP_TCP6)
 			params.ndis_tcp6csum |= NDIS_OFFLOAD_PARAM_RX;
 		else
@@ -829,12 +823,12 @@ int hn_rndis_conf_offload(struct hn_data *hv,
 	}
 
 	if (tx_offloads & RTE_ETH_TX_OFFLOAD_UDP_CKSUM) {
-		if (hwcaps.ndis_csum.ndis_ip4_txcsum & NDIS_TXCSUM_CAP_UDP4)
+		if (hwcaps->ndis_csum.ndis_ip4_txcsum & NDIS_TXCSUM_CAP_UDP4)
 			params.ndis_udp4csum = NDIS_OFFLOAD_PARAM_TX;
 		else
 			goto unsupported;
 
-		if ((hwcaps.ndis_csum.ndis_ip6_txcsum & NDIS_TXCSUM_CAP_UDP6)
+		if ((hwcaps->ndis_csum.ndis_ip6_txcsum & NDIS_TXCSUM_CAP_UDP6)
 		    == NDIS_TXCSUM_CAP_UDP6)
 			params.ndis_udp6csum = NDIS_OFFLOAD_PARAM_TX;
 		else
@@ -842,38 +836,38 @@ int hn_rndis_conf_offload(struct hn_data *hv,
 	}
 
 	if (rx_offloads & RTE_ETH_TX_OFFLOAD_UDP_CKSUM) {
-		if (hwcaps.ndis_csum.ndis_ip4_rxcsum & NDIS_RXCSUM_CAP_UDP4)
+		if (hwcaps->ndis_csum.ndis_ip4_rxcsum & NDIS_RXCSUM_CAP_UDP4)
 			params.ndis_udp4csum |= NDIS_OFFLOAD_PARAM_RX;
 		else
 			goto unsupported;
 
-		if (hwcaps.ndis_csum.ndis_ip6_rxcsum & NDIS_RXCSUM_CAP_UDP6)
+		if (hwcaps->ndis_csum.ndis_ip6_rxcsum & NDIS_RXCSUM_CAP_UDP6)
 			params.ndis_udp6csum |= NDIS_OFFLOAD_PARAM_RX;
 		else
 			goto unsupported;
 	}
 
 	if (tx_offloads & RTE_ETH_TX_OFFLOAD_IPV4_CKSUM) {
-		if ((hwcaps.ndis_csum.ndis_ip4_txcsum & NDIS_TXCSUM_CAP_IP4)
+		if ((hwcaps->ndis_csum.ndis_ip4_txcsum & NDIS_TXCSUM_CAP_IP4)
 		    == NDIS_TXCSUM_CAP_IP4)
 			params.ndis_ip4csum = NDIS_OFFLOAD_PARAM_TX;
 		else
 			goto unsupported;
 	}
 	if (rx_offloads & RTE_ETH_RX_OFFLOAD_IPV4_CKSUM) {
-		if (hwcaps.ndis_csum.ndis_ip4_rxcsum & NDIS_RXCSUM_CAP_IP4)
+		if (hwcaps->ndis_csum.ndis_ip4_rxcsum & NDIS_RXCSUM_CAP_IP4)
 			params.ndis_ip4csum |= NDIS_OFFLOAD_PARAM_RX;
 		else
 			goto unsupported;
 	}
 
 	if (tx_offloads & RTE_ETH_TX_OFFLOAD_TCP_TSO) {
-		if (hwcaps.ndis_lsov2.ndis_ip4_encap & NDIS_OFFLOAD_ENCAP_8023)
+		if (hwcaps->ndis_lsov2.ndis_ip4_encap & NDIS_OFFLOAD_ENCAP_8023)
 			params.ndis_lsov2_ip4 = NDIS_OFFLOAD_LSOV2_ON;
 		else
 			goto unsupported;
 
-		if ((hwcaps.ndis_lsov2.ndis_ip6_opts & HN_NDIS_LSOV2_CAP_IP6)
+		if ((hwcaps->ndis_lsov2.ndis_ip6_opts & HN_NDIS_LSOV2_CAP_IP6)
 		    == HN_NDIS_LSOV2_CAP_IP6)
 			params.ndis_lsov2_ip6 = NDIS_OFFLOAD_LSOV2_ON;
 		else
@@ -898,51 +892,42 @@ int hn_rndis_conf_offload(struct hn_data *hv,
 int hn_rndis_get_offload(struct hn_data *hv,
 			 struct rte_eth_dev_info *dev_info)
 {
-	struct ndis_offload hwcaps;
-	int error;
-
-	memset(&hwcaps, 0, sizeof(hwcaps));
-
-	error = hn_rndis_query_hwcaps(hv, &hwcaps);
-	if (error) {
-		PMD_DRV_LOG(ERR, "hwcaps query failed: %d", error);
-		return error;
-	}
+	const struct ndis_offload *hwcaps = &hv->hwcaps;
 
 	dev_info->tx_offload_capa = RTE_ETH_TX_OFFLOAD_MULTI_SEGS |
 				    RTE_ETH_TX_OFFLOAD_VLAN_INSERT;
 
-	if ((hwcaps.ndis_csum.ndis_ip4_txcsum & HN_NDIS_TXCSUM_CAP_IP4)
+	if ((hwcaps->ndis_csum.ndis_ip4_txcsum & HN_NDIS_TXCSUM_CAP_IP4)
 	    == HN_NDIS_TXCSUM_CAP_IP4)
 		dev_info->tx_offload_capa |= RTE_ETH_TX_OFFLOAD_IPV4_CKSUM;
 
-	if ((hwcaps.ndis_csum.ndis_ip4_txcsum & HN_NDIS_TXCSUM_CAP_TCP4)
+	if ((hwcaps->ndis_csum.ndis_ip4_txcsum & HN_NDIS_TXCSUM_CAP_TCP4)
 	    == HN_NDIS_TXCSUM_CAP_TCP4 &&
-	    (hwcaps.ndis_csum.ndis_ip6_txcsum & HN_NDIS_TXCSUM_CAP_TCP6)
+	    (hwcaps->ndis_csum.ndis_ip6_txcsum & HN_NDIS_TXCSUM_CAP_TCP6)
 	    == HN_NDIS_TXCSUM_CAP_TCP6)
 		dev_info->tx_offload_capa |= RTE_ETH_TX_OFFLOAD_TCP_CKSUM;
 
-	if ((hwcaps.ndis_csum.ndis_ip4_txcsum & NDIS_TXCSUM_CAP_UDP4) &&
-	    (hwcaps.ndis_csum.ndis_ip6_txcsum & NDIS_TXCSUM_CAP_UDP6))
+	if ((hwcaps->ndis_csum.ndis_ip4_txcsum & NDIS_TXCSUM_CAP_UDP4) &&
+	    (hwcaps->ndis_csum.ndis_ip6_txcsum & NDIS_TXCSUM_CAP_UDP6))
 		dev_info->tx_offload_capa |= RTE_ETH_TX_OFFLOAD_UDP_CKSUM;
 
-	if ((hwcaps.ndis_lsov2.ndis_ip4_encap & NDIS_OFFLOAD_ENCAP_8023) &&
-	    (hwcaps.ndis_lsov2.ndis_ip6_opts & HN_NDIS_LSOV2_CAP_IP6)
+	if ((hwcaps->ndis_lsov2.ndis_ip4_encap & NDIS_OFFLOAD_ENCAP_8023) &&
+	    (hwcaps->ndis_lsov2.ndis_ip6_opts & HN_NDIS_LSOV2_CAP_IP6)
 	    == HN_NDIS_LSOV2_CAP_IP6)
 		dev_info->tx_offload_capa |= RTE_ETH_TX_OFFLOAD_TCP_TSO;
 
 	dev_info->rx_offload_capa = RTE_ETH_RX_OFFLOAD_VLAN_STRIP |
 				    RTE_ETH_RX_OFFLOAD_RSS_HASH;
 
-	if (hwcaps.ndis_csum.ndis_ip4_rxcsum & NDIS_RXCSUM_CAP_IP4)
+	if (hwcaps->ndis_csum.ndis_ip4_rxcsum & NDIS_RXCSUM_CAP_IP4)
 		dev_info->rx_offload_capa |= RTE_ETH_RX_OFFLOAD_IPV4_CKSUM;
 
-	if ((hwcaps.ndis_csum.ndis_ip4_rxcsum & NDIS_RXCSUM_CAP_TCP4) &&
-	    (hwcaps.ndis_csum.ndis_ip6_rxcsum & NDIS_RXCSUM_CAP_TCP6))
+	if ((hwcaps->ndis_csum.ndis_ip4_rxcsum & NDIS_RXCSUM_CAP_TCP4) &&
+	    (hwcaps->ndis_csum.ndis_ip6_rxcsum & NDIS_RXCSUM_CAP_TCP6))
 		dev_info->rx_offload_capa |= RTE_ETH_RX_OFFLOAD_TCP_CKSUM;
 
-	if ((hwcaps.ndis_csum.ndis_ip4_rxcsum & NDIS_RXCSUM_CAP_UDP4) &&
-	    (hwcaps.ndis_csum.ndis_ip6_rxcsum & NDIS_RXCSUM_CAP_UDP6))
+	if ((hwcaps->ndis_csum.ndis_ip4_rxcsum & NDIS_RXCSUM_CAP_UDP4) &&
+	    (hwcaps->ndis_csum.ndis_ip6_rxcsum & NDIS_RXCSUM_CAP_UDP6))
 		dev_info->rx_offload_capa |= RTE_ETH_RX_OFFLOAD_UDP_CKSUM;
 
 	return 0;
@@ -951,29 +936,20 @@ int hn_rndis_get_offload(struct hn_data *hv,
 uint32_t
 hn_rndis_get_ptypes(struct hn_data *hv)
 {
-	struct ndis_offload hwcaps;
+	const struct ndis_offload *hwcaps = &hv->hwcaps;
 	uint32_t ptypes;
-	int error;
-
-	memset(&hwcaps, 0, sizeof(hwcaps));
-
-	error = hn_rndis_query_hwcaps(hv, &hwcaps);
-	if (error) {
-		PMD_DRV_LOG(ERR, "hwcaps query failed: %d", error);
-		return RTE_PTYPE_L2_ETHER;
-	}
 
 	ptypes = RTE_PTYPE_L2_ETHER;
 
-	if (hwcaps.ndis_csum.ndis_ip4_rxcsum & NDIS_RXCSUM_CAP_IP4)
+	if (hwcaps->ndis_csum.ndis_ip4_rxcsum & NDIS_RXCSUM_CAP_IP4)
 		ptypes |= RTE_PTYPE_L3_IPV4;
 
-	if ((hwcaps.ndis_csum.ndis_ip4_rxcsum & NDIS_RXCSUM_CAP_TCP4) ||
-	    (hwcaps.ndis_csum.ndis_ip6_rxcsum & NDIS_RXCSUM_CAP_TCP6))
+	if ((hwcaps->ndis_csum.ndis_ip4_rxcsum & NDIS_RXCSUM_CAP_TCP4) ||
+	    (hwcaps->ndis_csum.ndis_ip6_rxcsum & NDIS_RXCSUM_CAP_TCP6))
 		ptypes |= RTE_PTYPE_L4_TCP;
 
-	if ((hwcaps.ndis_csum.ndis_ip4_rxcsum & NDIS_RXCSUM_CAP_UDP4) ||
-	    (hwcaps.ndis_csum.ndis_ip6_rxcsum & NDIS_RXCSUM_CAP_UDP6))
+	if ((hwcaps->ndis_csum.ndis_ip4_rxcsum & NDIS_RXCSUM_CAP_UDP4) ||
+	    (hwcaps->ndis_csum.ndis_ip6_rxcsum & NDIS_RXCSUM_CAP_UDP6))
 		ptypes |= RTE_PTYPE_L4_UDP;
 
 	return ptypes;
@@ -1136,8 +1112,28 @@ hn_rndis_get_linkspeed(struct hn_data *hv)
 int
 hn_rndis_attach(struct hn_data *hv)
 {
+	int error;
+
 	/* Initialize RNDIS. */
-	return hn_rndis_init(hv);
+	error = hn_rndis_init(hv);
+	if (error)
+		return error;
+
+	/*
+	 * Query and cache hardware offload capabilities.
+	 * This avoids the need to query hwcaps on each call to
+	 * hn_rndis_get_offload(), hn_rndis_conf_offload(), or
+	 * hn_rndis_get_ptypes(), which can cause failures if
+	 * multiple threads try to query simultaneously.
+	 */
+	memset(&hv->hwcaps, 0, sizeof(hv->hwcaps));
+	error = hn_rndis_query_hwcaps(hv, &hv->hwcaps);
+	if (error) {
+		PMD_DRV_LOG(ERR, "failed to query hwcaps: %d", error);
+		return error;
+	}
+
+	return 0;
 }
 
 void
diff --git a/drivers/net/netvsc/hn_var.h b/drivers/net/netvsc/hn_var.h
index 17c1d5d07b..ae7f41dc94 100644
--- a/drivers/net/netvsc/hn_var.h
+++ b/drivers/net/netvsc/hn_var.h
@@ -9,6 +9,8 @@
 #include <rte_eal_paging.h>
 #include <ethdev_driver.h>
 
+#include "ndis.h"
+
 /*
  * Tunable ethdev params
  */
@@ -151,6 +153,8 @@ struct hn_data {
 	uint16_t	num_queues;
 	uint64_t	rss_offloads;
 
+	struct ndis_offload	hwcaps;		/* Cached hardware offload caps */
+
 	rte_spinlock_t	chim_lock;
 	struct rte_mem_resource chim_res;	/* UIO resource for Tx */
 	struct rte_bitmap *chim_bmap;		/* Send buffer map */
-- 
2.51.0


  reply	other threads:[~2026-01-13 17:01 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-01-13 10:18 [PATCH v2] net/netvsc: fix race condition in RNDIS command execution madhukar.mythri
2026-01-13 16:58 ` [RFT 0/2] net/netvsc: fix race conditions Stephen Hemminger
2026-01-13 16:58   ` Stephen Hemminger [this message]
2026-01-13 16:58   ` [RFT 2/2] net/netvsc: fix link status RNDIS command concurrency issue Stephen Hemminger
2026-01-16 23:10 ` [EXTERNAL] [PATCH v2] net/netvsc: fix race condition in RNDIS command execution Long Li
2026-03-28 23:53 ` Stephen Hemminger

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260113170143.70873-2-stephen@networkplumber.org \
    --to=stephen@networkplumber.org \
    --cc=dev@dpdk.org \
    --cc=madhukar.mythri@gmail.com \
    --cc=stable@dpdk.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox