svn commit: r324516 - head/sys/dev/hyperv/netvsc

Sepherosa Ziehau sephe at FreeBSD.org
Wed Oct 11 05:15:50 UTC 2017


Author: sephe
Date: Wed Oct 11 05:15:49 2017
New Revision: 324516
URL: https://svnweb.freebsd.org/changeset/base/324516

Log:
  hyperv/hn: Workaround erroneous hash type observed on WS2016 for VF.
  
  The background was described in r324489.
  
  MFC after:	3 days
  Sponsored by:	Microsoft

Modified:
  head/sys/dev/hyperv/netvsc/hn_rndis.c
  head/sys/dev/hyperv/netvsc/if_hn.c
  head/sys/dev/hyperv/netvsc/ndis.h

Modified: head/sys/dev/hyperv/netvsc/hn_rndis.c
==============================================================================
--- head/sys/dev/hyperv/netvsc/hn_rndis.c	Wed Oct 11 05:07:37 2017	(r324515)
+++ head/sys/dev/hyperv/netvsc/hn_rndis.c	Wed Oct 11 05:15:49 2017	(r324516)
@@ -521,6 +521,10 @@ hn_rndis_query_rsscaps(struct hn_softc *sc, int *rxr_c
 	/* Commit! */
 	sc->hn_rss_ind_size = indsz;
 	sc->hn_rss_hcap = hash_func | hash_types;
+	if (sc->hn_caps & HN_CAP_UDPHASH) {
+		/* UDP 4-tuple hash is unconditionally enabled. */
+		sc->hn_rss_hcap |= NDIS_HASH_UDP_IPV4_X;
+	}
 	*rxr_cnt0 = rxr_cnt;
 	return (0);
 }
@@ -760,8 +764,10 @@ hn_rndis_conf_rss(struct hn_softc *sc, uint16_t flags)
 	    ("NDIS 6.20+ is required, NDIS version 0x%08x", sc->hn_ndis_ver));
 
 	/* XXX only one can be specified through, popcnt? */
-	KASSERT((sc->hn_rss_hash & NDIS_HASH_FUNCTION_MASK), ("no hash func"));
-	KASSERT((sc->hn_rss_hash & NDIS_HASH_TYPE_MASK), ("no hash types"));
+	KASSERT((sc->hn_rss_hash & NDIS_HASH_FUNCTION_MASK),
+	    ("no hash func %08x", sc->hn_rss_hash));
+	KASSERT((sc->hn_rss_hash & NDIS_HASH_STD),
+	    ("no standard hash types %08x", sc->hn_rss_hash));
 	KASSERT(sc->hn_rss_ind_size > 0, ("no indirect table size"));
 
 	if (bootverbose) {
@@ -780,7 +786,8 @@ hn_rndis_conf_rss(struct hn_softc *sc, uint16_t flags)
 	prm->ndis_hdr.ndis_rev = NDIS_RSS_PARAMS_REV_2;
 	prm->ndis_hdr.ndis_size = rss_size;
 	prm->ndis_flags = flags;
-	prm->ndis_hash = sc->hn_rss_hash;
+	prm->ndis_hash = sc->hn_rss_hash &
+	    (NDIS_HASH_FUNCTION_MASK | NDIS_HASH_STD);
 	prm->ndis_indsize = sizeof(rss->rss_ind[0]) * sc->hn_rss_ind_size;
 	prm->ndis_indoffset =
 	    __offsetof(struct ndis_rssprm_toeplitz, rss_ind[0]);

Modified: head/sys/dev/hyperv/netvsc/if_hn.c
==============================================================================
--- head/sys/dev/hyperv/netvsc/if_hn.c	Wed Oct 11 05:07:37 2017	(r324515)
+++ head/sys/dev/hyperv/netvsc/if_hn.c	Wed Oct 11 05:15:49 2017	(r324516)
@@ -1424,6 +1424,8 @@ hn_rss_type_fromndis(uint32_t rss_hash)
 		types |= RSS_TYPE_TCP_IPV6;
 	if (rss_hash & NDIS_HASH_TCP_IPV6_EX)
 		types |= RSS_TYPE_TCP_IPV6_EX;
+	if (rss_hash & NDIS_HASH_UDP_IPV4_X)
+		types |= RSS_TYPE_UDP_IPV4;
 	return (types);
 }
 
@@ -1432,9 +1434,8 @@ hn_rss_type_tondis(uint32_t types)
 {
 	uint32_t rss_hash = 0;
 
-	KASSERT((types &
-	(RSS_TYPE_UDP_IPV4 | RSS_TYPE_UDP_IPV6 | RSS_TYPE_UDP_IPV6_EX)) == 0,
-	("UDP4, UDP6 and UDP6EX are not supported"));
+	KASSERT((types & (RSS_TYPE_UDP_IPV6 | RSS_TYPE_UDP_IPV6_EX)) == 0,
+	    ("UDP6 and UDP6EX are not supported"));
 
 	if (types & RSS_TYPE_IPV4)
 		rss_hash |= NDIS_HASH_IPV4;
@@ -1448,6 +1449,8 @@ hn_rss_type_tondis(uint32_t types)
 		rss_hash |= NDIS_HASH_TCP_IPV6;
 	if (types & RSS_TYPE_TCP_IPV6_EX)
 		rss_hash |= NDIS_HASH_TCP_IPV6_EX;
+	if (types & RSS_TYPE_UDP_IPV4)
+		rss_hash |= NDIS_HASH_UDP_IPV4_X;
 	return (rss_hash);
 }
 
@@ -1546,6 +1549,13 @@ hn_vf_rss_fixup(struct hn_softc *sc, bool reconf)
 	 * NOTE:
 	 * We don't disable the hash type, but stop delivery the hash
 	 * value/type through mbufs on RX path.
+	 *
+	 * XXX If HN_CAP_UDPHASH is set in hn_caps, then UDP 4-tuple
+	 * hash is delivered with type of TCP_IPV4.  This means if
+	 * UDP_IPV4 is enabled, then TCP_IPV4 should be forced, at
+	 * least to hn_mbuf_hash.  However, given that _all_ of the
+	 * NICs implement TCP_IPV4, this will _not_ impose any issues
+	 * here.
 	 */
 	if ((my_types & RSS_TYPE_IPV4) &&
 	    (diff_types & ifrh.ifrh_types &
@@ -3582,7 +3592,9 @@ hn_rxpkt(struct hn_rx_ring *rxr, const void *data, int
 						    &l3proto, &l4proto);
 					}
 					if (l3proto == ETHERTYPE_IP) {
-						if (l4proto == IPPROTO_UDP) {
+						if (l4proto == IPPROTO_UDP &&
+						    (rxr->hn_mbuf_hash &
+						     NDIS_HASH_UDP_IPV4_X)) {
 							hash_type =
 							M_HASHTYPE_RSS_UDP_IPV4;
 							do_lro = 0;

Modified: head/sys/dev/hyperv/netvsc/ndis.h
==============================================================================
--- head/sys/dev/hyperv/netvsc/ndis.h	Wed Oct 11 05:07:37 2017	(r324515)
+++ head/sys/dev/hyperv/netvsc/ndis.h	Wed Oct 11 05:15:49 2017	(r324516)
@@ -56,17 +56,26 @@
 #define	NDIS_HASH_IPV6_EX		0x00000800
 #define	NDIS_HASH_TCP_IPV6		0x00001000
 #define	NDIS_HASH_TCP_IPV6_EX		0x00002000
+#define	NDIS_HASH_UDP_IPV4_X		0x00004000	/* XXX non-standard */
 
 #define	NDIS_HASH_ALL			(NDIS_HASH_IPV4 |	\
 					 NDIS_HASH_TCP_IPV4 |	\
 					 NDIS_HASH_IPV6 |	\
 					 NDIS_HASH_IPV6_EX |	\
 					 NDIS_HASH_TCP_IPV6 |	\
+					 NDIS_HASH_TCP_IPV6_EX |\
+					 NDIS_HASH_UDP_IPV4_X)
+
+#define	NDIS_HASH_STD			(NDIS_HASH_IPV4 |	\
+					 NDIS_HASH_TCP_IPV4 |	\
+					 NDIS_HASH_IPV6 |	\
+					 NDIS_HASH_IPV6_EX |	\
+					 NDIS_HASH_TCP_IPV6 |	\
 					 NDIS_HASH_TCP_IPV6_EX)
 
 /* Hash description for use with printf(9) %b identifier. */
 #define	NDIS_HASH_BITS			\
-	"\20\1TOEPLITZ\11IP4\12TCP4\13IP6\14IP6EX\15TCP6\16TCP6EX"
+	"\20\1TOEPLITZ\11IP4\12TCP4\13IP6\14IP6EX\15TCP6\16TCP6EX\17UDP4_X"
 
 #define	NDIS_HASH_KEYSIZE_TOEPLITZ	40
 #define	NDIS_HASH_INDCNT		128


More information about the svn-src-all mailing list