Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 14 Oct 2016 02:19:47 +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-10@freebsd.org
Subject:   svn commit: r307245 - stable/10/sys/dev/hyperv/netvsc
Message-ID:  <201610140219.u9E2Jlxh045480@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: sephe
Date: Fri Oct 14 02:19:47 2016
New Revision: 307245
URL: https://svnweb.freebsd.org/changeset/base/307245

Log:
  MFC 305962,305964-305967
  
  305962
      hyperv/hn: Don't allow NVS and NDIS version change upon reinitailization
  
      NVS and NDIS version change would break too much assumption and static
      configuration.
  
      Sponsored by:   Microsoft
      Differential Revision:  https://reviews.freebsd.org/D7919
  
  305964
      hyperv/hn: Save capabilities for later use.
  
      And don't allow capability changes during reinitialization, which
      breaks too much static configuration.
  
      Sponsored by:   Microsoft
      Differential Revision:  https://reviews.freebsd.org/D7922
  
  305965
      hyperv/hn: Don't allow MTU change, if it is not supported by the NVS.
  
      Sponsored by:   Microsoft
      Differential Revision:  https://reviews.freebsd.org/D7923
  
  305966
      hyperv/hn: Stringent RSS sysctl checks
  
      - Don't change RNDIS RSS configuration for RSS key sysctl, if the
        interface is not capable of RSS yet.
      - Don't change RSS indirect table (both cached one and RNDIS RSS
        configuration), if the interface is not capable of RSS yet.
  
      Sponsored by:   Microsoft
      Differential Revision:  https://reviews.freebsd.org/D7924
  
  305967
      hyperv/hn: Allow RSS capability flipping upon attach/reinit.
  
      Sponsored by:   Microsoft
      Differential Revision:  https://reviews.freebsd.org/D7927

Modified:
  stable/10/sys/dev/hyperv/netvsc/hv_net_vsc.c
  stable/10/sys/dev/hyperv/netvsc/hv_net_vsc.h
  stable/10/sys/dev/hyperv/netvsc/hv_netvsc_drv_freebsd.c
  stable/10/sys/dev/hyperv/netvsc/hv_rndis_filter.c
Directory Properties:
  stable/10/   (props changed)

Modified: stable/10/sys/dev/hyperv/netvsc/hv_net_vsc.c
==============================================================================
--- stable/10/sys/dev/hyperv/netvsc/hv_net_vsc.c	Fri Oct 14 02:03:53 2016	(r307244)
+++ stable/10/sys/dev/hyperv/netvsc/hv_net_vsc.c	Fri Oct 14 02:19:47 2016	(r307245)
@@ -466,9 +466,15 @@ hn_nvs_conf_ndis(struct hn_softc *sc, in
 
 	/* NOTE: No response. */
 	error = hn_nvs_req_send(sc, &conf, sizeof(conf));
-	if (error)
+	if (error) {
 		if_printf(sc->hn_ifp, "send nvs ndis conf failed: %d\n", error);
-	return (error);
+		return (error);
+	}
+
+	if (bootverbose)
+		if_printf(sc->hn_ifp, "nvs ndis conf done\n");
+	sc->hn_caps |= HN_CAP_MTU | HN_CAP_VLAN;
+	return (0);
 }
 
 static int
@@ -494,6 +500,22 @@ hn_nvs_init(struct hn_softc *sc)
 {
 	int i;
 
+	if (device_is_attached(sc->hn_dev)) {
+		/*
+		 * NVS version and NDIS version MUST NOT be changed.
+		 */
+		if (bootverbose) {
+			if_printf(sc->hn_ifp, "reinit NVS version 0x%x, "
+			    "NDIS version %u.%u\n", sc->hn_nvs_ver,
+			    HN_NDIS_VERSION_MAJOR(sc->hn_ndis_ver),
+			    HN_NDIS_VERSION_MINOR(sc->hn_ndis_ver));
+		}
+		return (hn_nvs_doinit(sc, sc->hn_nvs_ver));
+	}
+
+	/*
+	 * Find the supported NVS version and set NDIS version accordingly.
+	 */
 	for (i = 0; i < nitems(hn_nvs_version); ++i) {
 		int error;
 

Modified: stable/10/sys/dev/hyperv/netvsc/hv_net_vsc.h
==============================================================================
--- stable/10/sys/dev/hyperv/netvsc/hv_net_vsc.h	Fri Oct 14 02:03:53 2016	(r307244)
+++ stable/10/sys/dev/hyperv/netvsc/hv_net_vsc.h	Fri Oct 14 02:19:47 2016	(r307245)
@@ -229,7 +229,8 @@ struct hn_softc {
 	struct vmbus_xact_ctx *hn_xact;
 	uint32_t	hn_nvs_ver;
 
-	uint32_t		hn_flags;
+	uint32_t		hn_caps;	/* HN_CAP_ */
+	uint32_t		hn_flags;	/* HN_FLAG_ */
 	void			*hn_rxbuf;
 	uint32_t		hn_rxbuf_gpadl;
 	struct hyperv_dma	hn_rxbuf_dma;
@@ -245,6 +246,18 @@ struct hn_softc {
 
 #define HN_FLAG_RXBUF_CONNECTED		0x0001
 #define HN_FLAG_CHIM_CONNECTED		0x0002
+#define HN_FLAG_HAS_RSSKEY		0x0004
+#define HN_FLAG_HAS_RSSIND		0x0008
+
+#define HN_CAP_VLAN			0x0001
+#define HN_CAP_MTU			0x0002
+#define HN_CAP_IPCS			0x0004
+#define HN_CAP_TCP4CS			0x0008
+#define HN_CAP_TCP6CS			0x0010
+#define HN_CAP_UDP4CS			0x0020
+#define HN_CAP_UDP6CS			0x0040
+#define HN_CAP_TSO4			0x0080
+#define HN_CAP_TSO6			0x0100
 
 /*
  * Externs

Modified: stable/10/sys/dev/hyperv/netvsc/hv_netvsc_drv_freebsd.c
==============================================================================
--- stable/10/sys/dev/hyperv/netvsc/hv_netvsc_drv_freebsd.c	Fri Oct 14 02:03:53 2016	(r307244)
+++ stable/10/sys/dev/hyperv/netvsc/hv_netvsc_drv_freebsd.c	Fri Oct 14 02:19:47 2016	(r307245)
@@ -327,6 +327,7 @@ static int hn_rx_stat_ulong_sysctl(SYSCT
 static int hn_tx_stat_ulong_sysctl(SYSCTL_HANDLER_ARGS);
 static int hn_tx_conf_int_sysctl(SYSCTL_HANDLER_ARGS);
 static int hn_ndis_version_sysctl(SYSCTL_HANDLER_ARGS);
+static int hn_caps_sysctl(SYSCTL_HANDLER_ARGS);
 static int hn_rss_key_sysctl(SYSCTL_HANDLER_ARGS);
 static int hn_rss_ind_sysctl(SYSCTL_HANDLER_ARGS);
 static int hn_check_iplen(const struct mbuf *, int);
@@ -436,6 +437,8 @@ hn_rss_ind_fixup(struct hn_softc *sc, in
 	struct ndis_rssprm_toeplitz *rss = &sc->hn_rss;
 	int i;
 
+	KASSERT(nchan > 1, ("invalid # of channels %d", nchan));
+
 	/*
 	 * Check indirect table to make sure that all channels in it
 	 * can be used.
@@ -657,6 +660,9 @@ netvsc_attach(device_t dev)
 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "ndis_version",
 	    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
 	    hn_ndis_version_sysctl, "A", "NDIS version");
+	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "caps",
+	    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
+	    hn_caps_sysctl, "A", "capabilities");
 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rss_key",
 	    CTLTYPE_OPAQUE | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0,
 	    hn_rss_key_sysctl, "IU", "RSS key");
@@ -1588,6 +1594,13 @@ hn_ioctl(struct ifnet *ifp, u_long cmd, 
 
 		HN_LOCK(sc);
 
+		if ((sc->hn_caps & HN_CAP_MTU) == 0) {
+			/* Can't change MTU */
+			HN_UNLOCK(sc);
+			error = EOPNOTSUPP;
+			break;
+		}
+
 		if (ifp->if_mtu == ifr->ifr_mtu) {
 			HN_UNLOCK(sc);
 			break;
@@ -2115,6 +2128,30 @@ hn_ndis_version_sysctl(SYSCTL_HANDLER_AR
 }
 
 static int
+hn_caps_sysctl(SYSCTL_HANDLER_ARGS)
+{
+	struct hn_softc *sc = arg1;
+	char caps_str[128];
+	uint32_t caps;
+
+	HN_LOCK(sc);
+	caps = sc->hn_caps;
+	HN_UNLOCK(sc);
+	snprintf(caps_str, sizeof(caps_str), "%b", caps,
+	    "\020"
+	    "\001VLAN"
+	    "\002MTU"
+	    "\003IPCS"
+	    "\004TCP4CS"
+	    "\005TCP6CS"
+	    "\006UDP4CS"
+	    "\007UDP6CS"
+	    "\010TSO4"
+	    "\011TSO6");
+	return sysctl_handle_string(oidp, caps_str, sizeof(caps_str), req);
+}
+
+static int
 hn_rss_key_sysctl(SYSCTL_HANDLER_ARGS)
 {
 	struct hn_softc *sc = arg1;
@@ -2129,8 +2166,14 @@ hn_rss_key_sysctl(SYSCTL_HANDLER_ARGS)
 	error = SYSCTL_IN(req, sc->hn_rss.rss_key, sizeof(sc->hn_rss.rss_key));
 	if (error)
 		goto back;
+	sc->hn_flags |= HN_FLAG_HAS_RSSKEY;
 
-	error = hn_rss_reconfig(sc);
+	if (sc->hn_rx_ring_inuse > 1) {
+		error = hn_rss_reconfig(sc);
+	} else {
+		/* Not RSS capable, at least for now; just save the RSS key. */
+		error = 0;
+	}
 back:
 	HN_UNLOCK(sc);
 	return (error);
@@ -2148,9 +2191,19 @@ hn_rss_ind_sysctl(SYSCTL_HANDLER_ARGS)
 	if (error || req->newptr == NULL)
 		goto back;
 
+	/*
+	 * Don't allow RSS indirect table change, if this interface is not
+	 * RSS capable currently.
+	 */
+	if (sc->hn_rx_ring_inuse == 1) {
+		error = EOPNOTSUPP;
+		goto back;
+	}
+
 	error = SYSCTL_IN(req, sc->hn_rss.rss_ind, sizeof(sc->hn_rss.rss_ind));
 	if (error)
 		goto back;
+	sc->hn_flags |= HN_FLAG_HAS_RSSIND;
 
 	hn_rss_ind_fixup(sc, sc->hn_rx_ring_inuse);
 	error = hn_rss_reconfig(sc);
@@ -3243,6 +3296,11 @@ hn_synth_attach(struct hn_softc *sc, int
 {
 	struct ndis_rssprm_toeplitz *rss = &sc->hn_rss;
 	int error, nsubch, nchan, i;
+	uint32_t old_caps;
+
+	/* Save capabilities for later verification. */
+	old_caps = sc->hn_caps;
+	sc->hn_caps = 0;
 
 	/*
 	 * Attach the primary channel _before_ attaching NVS and RNDIS.
@@ -3266,6 +3324,17 @@ hn_synth_attach(struct hn_softc *sc, int
 		return (error);
 
 	/*
+	 * Make sure capabilities are not changed.
+	 */
+	if (device_is_attached(sc->hn_dev) && old_caps != sc->hn_caps) {
+		if_printf(sc->hn_ifp, "caps mismatch old 0x%08x, new 0x%08x\n",
+		    old_caps, sc->hn_caps);
+		/* Restore old capabilities and abort. */
+		sc->hn_caps = old_caps;
+		return ENXIO;
+	}
+
+	/*
 	 * Allocate sub-channels for multi-TX/RX rings.
 	 *
 	 * NOTE:
@@ -3288,24 +3357,29 @@ hn_synth_attach(struct hn_softc *sc, int
 	 * are allocated.
 	 */
 
-	if (!device_is_attached(sc->hn_dev)) {
+	if ((sc->hn_flags & HN_FLAG_HAS_RSSKEY) == 0) {
 		/*
-		 * Setup default RSS key and indirect table for the
-		 * attach DEVMETHOD.  They can be altered later on,
-		 * so don't mess them up once this interface is attached.
+		 * RSS key is not set yet; set it to the default RSS key.
 		 */
-		if (bootverbose) {
-			if_printf(sc->hn_ifp, "setup default RSS key and "
-			    "indirect table\n");
-		}
-
-		/* Setup default RSS key. */
+		if (bootverbose)
+			if_printf(sc->hn_ifp, "setup default RSS key\n");
 		memcpy(rss->rss_key, hn_rss_key_default, sizeof(rss->rss_key));
+		sc->hn_flags |= HN_FLAG_HAS_RSSKEY;
+	}
 
-		/* Setup default RSS indirect table. */
+	if ((sc->hn_flags & HN_FLAG_HAS_RSSIND) == 0) {
+		/*
+		 * RSS indirect table is not set yet; set it up in round-
+		 * robin fashion.
+		 */
+		if (bootverbose) {
+			if_printf(sc->hn_ifp, "setup default RSS indirect "
+			    "table\n");
+		}
 		/* TODO: Take ndis_rss_caps.ndis_nind into account. */
 		for (i = 0; i < NDIS_HASH_INDCNT; ++i)
 			rss->rss_ind[i] = i % nchan;
+		sc->hn_flags |= HN_FLAG_HAS_RSSIND;
 	} else {
 		/*
 		 * # of usable channels may be changed, so we have to

Modified: stable/10/sys/dev/hyperv/netvsc/hv_rndis_filter.c
==============================================================================
--- stable/10/sys/dev/hyperv/netvsc/hv_rndis_filter.c	Fri Oct 14 02:03:53 2016	(r307244)
+++ stable/10/sys/dev/hyperv/netvsc/hv_rndis_filter.c	Fri Oct 14 02:19:47 2016	(r307245)
@@ -801,6 +801,7 @@ static int
 hn_rndis_conf_offload(struct hn_softc *sc)
 {
 	struct ndis_offload_params params;
+	uint32_t caps;
 	size_t paramsz;
 	int error;
 
@@ -817,24 +818,29 @@ hn_rndis_conf_offload(struct hn_softc *s
 	}
 	params.ndis_hdr.ndis_size = paramsz;
 
+	caps = HN_CAP_IPCS | HN_CAP_TCP4CS | HN_CAP_TCP6CS;
 	params.ndis_ip4csum = NDIS_OFFLOAD_PARAM_TXRX;
 	params.ndis_tcp4csum = NDIS_OFFLOAD_PARAM_TXRX;
 	params.ndis_tcp6csum = NDIS_OFFLOAD_PARAM_TXRX;
 	if (sc->hn_ndis_ver >= HN_NDIS_VERSION_6_30) {
+		caps |= HN_CAP_UDP4CS | HN_CAP_UDP6CS;
 		params.ndis_udp4csum = NDIS_OFFLOAD_PARAM_TXRX;
 		params.ndis_udp6csum = NDIS_OFFLOAD_PARAM_TXRX;
 	}
+	caps |= HN_CAP_TSO4;
 	params.ndis_lsov2_ip4 = NDIS_OFFLOAD_LSOV2_ON;
 	/* XXX ndis_lsov2_ip6 = NDIS_OFFLOAD_LSOV2_ON */
 
 	error = hn_rndis_set(sc, OID_TCP_OFFLOAD_PARAMETERS, &params, paramsz);
 	if (error) {
 		if_printf(sc->hn_ifp, "offload config failed: %d\n", error);
-	} else {
-		if (bootverbose)
-			if_printf(sc->hn_ifp, "offload config done\n");
+		return (error);
 	}
-	return (error);
+
+	if (bootverbose)
+		if_printf(sc->hn_ifp, "offload config done\n");
+	sc->hn_caps |= caps;
+	return (0);
 }
 
 int



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