Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 11 Nov 2016 08:49:28 +0000 (UTC)
From:      Sepherosa Ziehau <sephe@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-11@freebsd.org
Subject:   svn commit: r308518 - in stable/11/sys: dev/hyperv/netvsc net
Message-ID:  <201611110849.uAB8nSfY020202@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: sephe
Date: Fri Nov 11 08:49:28 2016
New Revision: 308518
URL: https://svnweb.freebsd.org/changeset/base/308518

Log:
  MFC 307710-307712,307714
  
  307710
      hyperv/hn: Always query RSS capabilities.
  
      - This avoid distributing NDIS version check.
      - Only NDIS 6.20 required (earlier NDIS uses different indirect table
        format).
  
      Sponsored by:   Microsoft
      Differential Revision:  https://reviews.freebsd.org/D8291
  
  307711
      hyperv/hn: Check NVS version for HASHVAL pktinfo on sending path.
  
      Sponsored by:   Microsoft
      Differential Revision:  https://reviews.freebsd.org/D8293
  
  307712
      hyperv/hn: Add network change support.
  
      Currently the network change is simulated by link status changes.
  
      Sponsored by:   Microsoft
      Differential Revision:  https://reviews.freebsd.org/D8295
  
  307714
      hyperv/hn: Function renaming; consistent w/ hardware capabilities query.
  
      Sponsored by:   Microsoft
      Differential Revision:  https://reviews.freebsd.org/D8296

Modified:
  stable/11/sys/dev/hyperv/netvsc/hv_net_vsc.c
  stable/11/sys/dev/hyperv/netvsc/hv_net_vsc.h
  stable/11/sys/dev/hyperv/netvsc/hv_netvsc_drv_freebsd.c
  stable/11/sys/dev/hyperv/netvsc/hv_rndis_filter.c
  stable/11/sys/dev/hyperv/netvsc/if_hnreg.h
  stable/11/sys/dev/hyperv/netvsc/if_hnvar.h
  stable/11/sys/dev/hyperv/netvsc/ndis.h
  stable/11/sys/net/rndis.h
Directory Properties:
  stable/11/   (props changed)

Modified: stable/11/sys/dev/hyperv/netvsc/hv_net_vsc.c
==============================================================================
--- stable/11/sys/dev/hyperv/netvsc/hv_net_vsc.c	Fri Nov 11 08:43:34 2016	(r308517)
+++ stable/11/sys/dev/hyperv/netvsc/hv_net_vsc.c	Fri Nov 11 08:49:28 2016	(r308518)
@@ -544,8 +544,9 @@ hn_nvs_init(struct hn_softc *sc)
 		if (error) {
 			if_printf(sc->hn_ifp, "reinit NVS version 0x%x "
 			    "failed: %d\n", sc->hn_nvs_ver, error);
+			return (error);
 		}
-		return (error);
+		goto done;
 	}
 
 	/*
@@ -567,11 +568,16 @@ hn_nvs_init(struct hn_softc *sc)
 				    HN_NDIS_VERSION_MAJOR(sc->hn_ndis_ver),
 				    HN_NDIS_VERSION_MINOR(sc->hn_ndis_ver));
 			}
-			return (0);
+			goto done;
 		}
 	}
 	if_printf(sc->hn_ifp, "no NVS available\n");
 	return (ENXIO);
+
+done:
+	if (sc->hn_nvs_ver >= HN_NVS_VERSION_5)
+		sc->hn_caps |= HN_CAP_HASHVAL;
+	return (0);
 }
 
 int

Modified: stable/11/sys/dev/hyperv/netvsc/hv_net_vsc.h
==============================================================================
--- stable/11/sys/dev/hyperv/netvsc/hv_net_vsc.h	Fri Nov 11 08:43:34 2016	(r308517)
+++ stable/11/sys/dev/hyperv/netvsc/hv_net_vsc.h	Fri Nov 11 08:49:28 2016	(r308518)
@@ -207,7 +207,6 @@ struct hn_softc {
 	struct ifnet    *hn_ifp;
 	struct ifmedia	hn_media;
 	device_t        hn_dev;
-	int             hn_carrier;
 	int             hn_if_flags;
 	struct sx	hn_lock;
 	struct vmbus_channel *hn_prichan;
@@ -236,6 +235,9 @@ struct hn_softc {
 	struct taskqueue	*hn_mgmt_taskq;
 	struct taskqueue	*hn_mgmt_taskq0;
 	struct task		hn_link_task;
+	struct task		hn_netchg_init;
+	struct timeout_task	hn_netchg_status;
+	uint32_t		hn_link_flags;	/* HN_LINK_FLAG_ */
 
 	uint32_t		hn_caps;	/* HN_CAP_ */
 	uint32_t		hn_flags;	/* HN_FLAG_ */
@@ -269,6 +271,10 @@ struct hn_softc {
 #define HN_CAP_UDP6CS			0x0040
 #define HN_CAP_TSO4			0x0080
 #define HN_CAP_TSO6			0x0100
+#define HN_CAP_HASHVAL			0x0200
+
+#define HN_LINK_FLAG_LINKUP		0x0001
+#define HN_LINK_FLAG_NETCHG		0x0002
 
 /*
  * Externs

Modified: stable/11/sys/dev/hyperv/netvsc/hv_netvsc_drv_freebsd.c
==============================================================================
--- stable/11/sys/dev/hyperv/netvsc/hv_netvsc_drv_freebsd.c	Fri Nov 11 08:43:34 2016	(r308517)
+++ stable/11/sys/dev/hyperv/netvsc/hv_netvsc_drv_freebsd.c	Fri Nov 11 08:49:28 2016	(r308518)
@@ -335,6 +335,8 @@ static void hn_destroy_tx_data(struct hn
 static void hn_start_taskfunc(void *, int);
 static void hn_start_txeof_taskfunc(void *, int);
 static void hn_link_taskfunc(void *, int);
+static void hn_netchg_init_taskfunc(void *, int);
+static void hn_netchg_status_taskfunc(void *, int);
 static void hn_suspend_mgmt_taskfunc(void *, int);
 static int hn_encap(struct hn_tx_ring *, struct hn_txdesc *, struct mbuf **);
 static int hn_create_rx_data(struct hn_softc *sc, int);
@@ -360,6 +362,7 @@ static void hn_rx_drain(struct vmbus_cha
 static void hn_tx_resume(struct hn_softc *, int);
 static void hn_tx_ring_qflush(struct hn_tx_ring *);
 static int netvsc_detach(device_t dev);
+static void hn_link_status(struct hn_softc *);
 
 static void hn_nvs_handle_notify(struct hn_softc *sc,
 		const struct vmbus_chanpkt_hdr *pkt);
@@ -482,7 +485,7 @@ hn_ifmedia_sts(struct ifnet *ifp, struct
 	ifmr->ifm_status = IFM_AVALID;
 	ifmr->ifm_active = IFM_ETHER;
 
-	if (!sc->hn_carrier) {
+	if ((sc->hn_link_flags & HN_LINK_FLAG_LINKUP) == 0) {
 		ifmr->ifm_active |= IFM_NONE;
 		return;
 	}
@@ -563,6 +566,9 @@ netvsc_attach(device_t dev)
 	taskqueue_start_threads(&sc->hn_mgmt_taskq0, 1, PI_NET, "%s mgmt",
 	    device_get_nameunit(dev));
 	TASK_INIT(&sc->hn_link_task, 0, hn_link_taskfunc, sc);
+	TASK_INIT(&sc->hn_netchg_init, 0, hn_netchg_init_taskfunc, sc);
+	TIMEOUT_TASK_INIT(sc->hn_mgmt_taskq0, &sc->hn_netchg_status, 0,
+	    hn_netchg_status_taskfunc, sc);
 
 	/*
 	 * Allocate ifnet and setup its name earlier, so that if_printf
@@ -808,10 +814,8 @@ netvsc_shutdown(device_t dev)
 }
 
 static void
-hn_link_taskfunc(void *xsc, int pending __unused)
+hn_link_status(struct hn_softc *sc)
 {
-	struct hn_softc *sc = xsc;
-	struct ifnet *ifp = sc->hn_ifp;
 	uint32_t link_status;
 	int error;
 
@@ -822,11 +826,51 @@ hn_link_taskfunc(void *xsc, int pending 
 	}
 
 	if (link_status == NDIS_MEDIA_STATE_CONNECTED)
-		sc->hn_carrier = 1;
+		sc->hn_link_flags |= HN_LINK_FLAG_LINKUP;
 	else
-		sc->hn_carrier = 0;
-	if_link_state_change(ifp,
-	    sc->hn_carrier ? LINK_STATE_UP : LINK_STATE_DOWN);
+		sc->hn_link_flags &= ~HN_LINK_FLAG_LINKUP;
+	if_link_state_change(sc->hn_ifp,
+	    (sc->hn_link_flags & HN_LINK_FLAG_LINKUP) ?
+	    LINK_STATE_UP : LINK_STATE_DOWN);
+}
+
+static void
+hn_link_taskfunc(void *xsc, int pending __unused)
+{
+	struct hn_softc *sc = xsc;
+
+	if (sc->hn_link_flags & HN_LINK_FLAG_NETCHG)
+		return;
+	hn_link_status(sc);
+}
+
+static void
+hn_netchg_init_taskfunc(void *xsc, int pending __unused)
+{
+	struct hn_softc *sc = xsc;
+
+	/* Prevent any link status checks from running. */
+	sc->hn_link_flags |= HN_LINK_FLAG_NETCHG;
+
+	/*
+	 * Fake up a [link down --> link up] state change; 5 seconds
+	 * delay is used, which closely simulates miibus reaction
+	 * upon link down event.
+	 */
+	sc->hn_link_flags &= ~HN_LINK_FLAG_LINKUP;
+	if_link_state_change(sc->hn_ifp, LINK_STATE_DOWN);
+	taskqueue_enqueue_timeout(sc->hn_mgmt_taskq0,
+	    &sc->hn_netchg_status, 5 * hz);
+}
+
+static void
+hn_netchg_status_taskfunc(void *xsc, int pending __unused)
+{
+	struct hn_softc *sc = xsc;
+
+	/* Re-allow link status checks. */
+	sc->hn_link_flags &= ~HN_LINK_FLAG_NETCHG;
+	hn_link_status(sc);
 }
 
 void
@@ -837,6 +881,14 @@ hn_link_status_update(struct hn_softc *s
 		taskqueue_enqueue(sc->hn_mgmt_taskq, &sc->hn_link_task);
 }
 
+void
+hn_network_change(struct hn_softc *sc)
+{
+
+	if (sc->hn_mgmt_taskq != NULL)
+		taskqueue_enqueue(sc->hn_mgmt_taskq, &sc->hn_netchg_init);
+}
+
 static __inline int
 hn_txdesc_dmamap_load(struct hn_tx_ring *txr, struct hn_txdesc *txd,
     struct mbuf **m_head, bus_dma_segment_t *segs, int *nsegs)
@@ -2233,7 +2285,8 @@ hn_caps_sysctl(SYSCTL_HANDLER_ARGS)
 	    "\006UDP4CS"
 	    "\007UDP6CS"
 	    "\010TSO4"
-	    "\011TSO6");
+	    "\011TSO6"
+	    "\012HASHVAL");
 	return sysctl_handle_string(oidp, caps_str, sizeof(caps_str), req);
 }
 
@@ -3008,12 +3061,15 @@ hn_fixup_tx_data(struct hn_softc *sc)
 	if (sc->hn_caps & HN_CAP_UDP6CS)
 		csum_assist |= CSUM_IP6_UDP;
 #endif
-
 	for (i = 0; i < sc->hn_tx_ring_cnt; ++i)
 		sc->hn_tx_ring[i].hn_csum_assist = csum_assist;
 
-	if (sc->hn_ndis_ver >= HN_NDIS_VERSION_6_30) {
-		/* Support HASHVAL pktinfo on TX path. */
+	if (sc->hn_caps & HN_CAP_HASHVAL) {
+		/*
+		 * Support HASHVAL pktinfo on TX path.
+		 */
+		if (bootverbose)
+			if_printf(sc->hn_ifp, "support HASHVAL pktinfo\n");
 		for (i = 0; i < sc->hn_tx_ring_cnt; ++i)
 			sc->hn_tx_ring[i].hn_tx_flags |= HN_TX_FLAG_HASHVAL;
 	}
@@ -3408,20 +3464,19 @@ hn_synth_alloc_subchans(struct hn_softc 
 	int nchan, rxr_cnt, error;
 
 	nchan = *nsubch + 1;
-	if (sc->hn_ndis_ver < HN_NDIS_VERSION_6_30 || nchan == 1) {
+	if (nchan == 1) {
 		/*
-		 * Either RSS is not supported, or multiple RX/TX rings
-		 * are not requested.
+		 * Multiple RX/TX rings are not requested.
 		 */
 		*nsubch = 0;
 		return (0);
 	}
 
 	/*
-	 * Get RSS capabilities, e.g. # of RX rings, and # of indirect
+	 * Query RSS capabilities, e.g. # of RX rings, and # of indirect
 	 * table entries.
 	 */
-	error = hn_rndis_get_rsscaps(sc, &rxr_cnt);
+	error = hn_rndis_query_rsscaps(sc, &rxr_cnt);
 	if (error) {
 		/* No RSS; this is benign. */
 		*nsubch = 0;
@@ -3716,6 +3771,8 @@ hn_suspend_mgmt(struct hn_softc *sc)
 	/*
 	 * Make sure that all pending management tasks are completed.
 	 */
+	taskqueue_drain(sc->hn_mgmt_taskq0, &sc->hn_netchg_init);
+	taskqueue_drain_timeout(sc->hn_mgmt_taskq0, &sc->hn_netchg_status);
 	taskqueue_drain_all(sc->hn_mgmt_taskq0);
 }
 
@@ -3793,10 +3850,11 @@ hn_resume_mgmt(struct hn_softc *sc)
 {
 
 	/*
-	 * Kick off link status check.
+	 * Kick off network change detection, which will
+	 * do link status check too.
 	 */
 	sc->hn_mgmt_taskq = sc->hn_mgmt_taskq0;
-	hn_link_status_update(sc);
+	hn_network_change(sc);
 }
 
 static void

Modified: stable/11/sys/dev/hyperv/netvsc/hv_rndis_filter.c
==============================================================================
--- stable/11/sys/dev/hyperv/netvsc/hv_rndis_filter.c	Fri Nov 11 08:43:34 2016	(r308517)
+++ stable/11/sys/dev/hyperv/netvsc/hv_rndis_filter.c	Fri Nov 11 08:49:28 2016	(r308518)
@@ -158,6 +158,7 @@ static void 
 hv_rf_receive_indicate_status(struct hn_softc *sc, const void *data, int dlen)
 {
 	const struct rndis_status_msg *msg;
+	int ofs;
 
 	if (dlen < sizeof(*msg)) {
 		if_printf(sc->hn_ifp, "invalid RNDIS status\n");
@@ -176,8 +177,19 @@ hv_rf_receive_indicate_status(struct hn_
 		break;
 
 	case RNDIS_STATUS_NETWORK_CHANGE:
-		/* TODO */
-		if_printf(sc->hn_ifp, "network changed\n");
+		ofs = RNDIS_STBUFOFFSET_ABS(msg->rm_stbufoffset);
+		if (dlen < ofs + msg->rm_stbuflen ||
+		    msg->rm_stbuflen < sizeof(uint32_t)) {
+			if_printf(sc->hn_ifp, "network changed\n");
+		} else {
+			uint32_t change;
+
+			memcpy(&change, ((const uint8_t *)msg) + ofs,
+			    sizeof(change));
+			if_printf(sc->hn_ifp, "network changed, change %u\n",
+			    change);
+		}
+		hn_network_change(sc);
 		break;
 
 	default:
@@ -736,7 +748,7 @@ done:
 }
 
 int
-hn_rndis_get_rsscaps(struct hn_softc *sc, int *rxr_cnt)
+hn_rndis_query_rsscaps(struct hn_softc *sc, int *rxr_cnt)
 {
 	struct ndis_rss_caps in, caps;
 	size_t caps_len;
@@ -744,15 +756,13 @@ hn_rndis_get_rsscaps(struct hn_softc *sc
 
 	*rxr_cnt = 0;
 
+	if (sc->hn_ndis_ver < HN_NDIS_VERSION_6_20)
+		return (EOPNOTSUPP);
+
 	memset(&in, 0, sizeof(in));
 	in.ndis_hdr.ndis_type = NDIS_OBJTYPE_RSS_CAPS;
-	if (sc->hn_ndis_ver < HN_NDIS_VERSION_6_30) {
-		in.ndis_hdr.ndis_rev = NDIS_RSS_CAPS_REV_1;
-		in.ndis_hdr.ndis_size = NDIS_RSS_CAPS_SIZE_6_0;
-	} else {
-		in.ndis_hdr.ndis_rev = NDIS_RSS_CAPS_REV_2;
-		in.ndis_hdr.ndis_size = NDIS_RSS_CAPS_SIZE;
-	}
+	in.ndis_hdr.ndis_rev = NDIS_RSS_CAPS_REV_2;
+	in.ndis_hdr.ndis_size = NDIS_RSS_CAPS_SIZE;
 
 	caps_len = NDIS_RSS_CAPS_SIZE;
 	error = hn_rndis_query2(sc, OID_GEN_RECEIVE_SCALE_CAPABILITIES,
@@ -1027,10 +1037,12 @@ hn_rndis_conf_rss(struct hn_softc *sc, u
 	int error;
 
 	/*
-	 * Only NDIS 6.30+ is supported.
+	 * Only NDIS 6.20+ is supported:
+	 * We only support 4bytes element in indirect table, which has been
+	 * adopted since NDIS 6.20.
 	 */
-	KASSERT(sc->hn_ndis_ver >= HN_NDIS_VERSION_6_30,
-	    ("NDIS 6.30+ is required, NDIS version 0x%08x", sc->hn_ndis_ver));
+	KASSERT(sc->hn_ndis_ver >= HN_NDIS_VERSION_6_20,
+	    ("NDIS 6.20+ is required, NDIS version 0x%08x", sc->hn_ndis_ver));
 
 	/*
 	 * NOTE:

Modified: stable/11/sys/dev/hyperv/netvsc/if_hnreg.h
==============================================================================
--- stable/11/sys/dev/hyperv/netvsc/if_hnreg.h	Fri Nov 11 08:43:34 2016	(r308517)
+++ stable/11/sys/dev/hyperv/netvsc/if_hnreg.h	Fri Nov 11 08:49:28 2016	(r308518)
@@ -36,6 +36,7 @@
  * NDIS protocol version numbers
  */
 #define HN_NDIS_VERSION_6_1		0x00060001
+#define HN_NDIS_VERSION_6_20		0x00060014
 #define HN_NDIS_VERSION_6_30		0x0006001e
 #define HN_NDIS_VERSION_MAJOR(ver)	(((ver) & 0xffff0000) >> 16)
 #define HN_NDIS_VERSION_MINOR(ver)	((ver) & 0xffff)

Modified: stable/11/sys/dev/hyperv/netvsc/if_hnvar.h
==============================================================================
--- stable/11/sys/dev/hyperv/netvsc/if_hnvar.h	Fri Nov 11 08:43:34 2016	(r308517)
+++ stable/11/sys/dev/hyperv/netvsc/if_hnvar.h	Fri Nov 11 08:49:28 2016	(r308518)
@@ -122,7 +122,7 @@ void		hn_rndis_detach(struct hn_softc *s
 int		hn_rndis_conf_rss(struct hn_softc *sc, uint16_t flags);
 void		*hn_rndis_pktinfo_append(struct rndis_packet_msg *,
 		    size_t pktsize, size_t pi_dlen, uint32_t pi_type);
-int		hn_rndis_get_rsscaps(struct hn_softc *sc, int *rxr_cnt);
+int		hn_rndis_query_rsscaps(struct hn_softc *sc, int *rxr_cnt);
 int		hn_rndis_get_eaddr(struct hn_softc *sc, uint8_t *eaddr);
 int		hn_rndis_get_linkstatus(struct hn_softc *sc,
 		    uint32_t *link_status);
@@ -139,6 +139,7 @@ int		hn_rxpkt(struct hn_rx_ring *rxr, co
 		    const struct hn_recvinfo *info);
 void		hn_chan_rollup(struct hn_rx_ring *rxr, struct hn_tx_ring *txr);
 void		hn_link_status_update(struct hn_softc *sc);
+void		hn_network_change(struct hn_softc *sc);
 
 extern struct hn_send_ctx	hn_send_ctx_none;
 

Modified: stable/11/sys/dev/hyperv/netvsc/ndis.h
==============================================================================
--- stable/11/sys/dev/hyperv/netvsc/ndis.h	Fri Nov 11 08:43:34 2016	(r308517)
+++ stable/11/sys/dev/hyperv/netvsc/ndis.h	Fri Nov 11 08:49:28 2016	(r308518)
@@ -32,6 +32,10 @@
 #define	NDIS_MEDIA_STATE_CONNECTED	0
 #define	NDIS_MEDIA_STATE_DISCONNECTED	1
 
+#define	NDIS_NETCHANGE_TYPE_POSSIBLE	1
+#define	NDIS_NETCHANGE_TYPE_DEFINITE	2
+#define	NDIS_NETCHANGE_TYPE_FROMMEDIA	3
+
 #define	NDIS_OFFLOAD_SET_NOCHG		0
 #define	NDIS_OFFLOAD_SET_ON		1
 #define	NDIS_OFFLOAD_SET_OFF		2

Modified: stable/11/sys/net/rndis.h
==============================================================================
--- stable/11/sys/net/rndis.h	Fri Nov 11 08:43:34 2016	(r308517)
+++ stable/11/sys/net/rndis.h	Fri Nov 11 08:49:28 2016	(r308518)
@@ -320,6 +320,10 @@ struct rndis_status_msg {
 	/* rndis_diag_info */
 };
 
+/* stbuf offset from the beginning of rndis_status_msg. */
+#define	RNDIS_STBUFOFFSET_ABS(ofs)	\
+	((ofs) + __offsetof(struct rndis_status_msg, rm_status))
+
 /*
  * Immediately after rndis_status_msg.rm_stbufoffset, if a control
  * message is malformatted, or a packet message contains inappropriate



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201611110849.uAB8nSfY020202>