svn commit: r302053 - stable/10/sys/dev/hyperv/netvsc

Sepherosa Ziehau sephe at FreeBSD.org
Tue Jun 21 07:05:51 UTC 2016


Author: sephe
Date: Tue Jun 21 07:05:49 2016
New Revision: 302053
URL: https://svnweb.freebsd.org/changeset/base/302053

Log:
  MFC 299401,299888
  
  299401
      hyperv/hn: Extract RSS hash value and type.
  
      MFC after:  1 week
      Sponsored by:       Microsoft OSTC
      Differential Revision:      https://reviews.freebsd.org/D6287
  
  299888
      hyperv/hn: Combine per-packet-information parsing.
  
      MFC after:  1 week
      Sponsored by:       Microsoft OSTC

Modified:
  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.h
  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.h
==============================================================================
--- stable/10/sys/dev/hyperv/netvsc/hv_net_vsc.h	Tue Jun 21 06:56:09 2016	(r302052)
+++ stable/10/sys/dev/hyperv/netvsc/hv_net_vsc.h	Tue Jun 21 07:05:49 2016	(r302053)
@@ -1164,6 +1164,7 @@ struct hn_rx_ring {
 	u_long		hn_lro_tried;
 	u_long		hn_small_pkts;
 	u_long		hn_pkts;
+	u_long		hn_rss_pkts;
 
 	/* Rarely used stuffs */
 	struct sysctl_oid *hn_rx_sysctl_tree;

Modified: stable/10/sys/dev/hyperv/netvsc/hv_netvsc_drv_freebsd.c
==============================================================================
--- stable/10/sys/dev/hyperv/netvsc/hv_netvsc_drv_freebsd.c	Tue Jun 21 06:56:09 2016	(r302052)
+++ stable/10/sys/dev/hyperv/netvsc/hv_netvsc_drv_freebsd.c	Tue Jun 21 07:05:49 2016	(r302053)
@@ -142,7 +142,7 @@ __FBSDID("$FreeBSD$");
 
 #define HN_RNDIS_MSG_LEN		\
     (sizeof(rndis_msg) +		\
-     RNDIS_HASH_PPI_SIZE +		\
+     RNDIS_HASHVAL_PPI_SIZE +		\
      RNDIS_VLAN_PPI_SIZE +		\
      RNDIS_TSO_PPI_SIZE +		\
      RNDIS_CSUM_PPI_SIZE)
@@ -883,7 +883,7 @@ hn_encap(struct hn_tx_ring *txr, struct 
 	rndis_msg *rndis_mesg;
 	rndis_packet *rndis_pkt;
 	rndis_per_packet_info *rppi;
-	struct ndis_hash_info *hash_info;
+	struct rndis_hash_value *hash_value;
 	uint32_t rndis_msg_size;
 
 	packet = &txd->netvsc_pkt;
@@ -909,16 +909,16 @@ hn_encap(struct hn_tx_ring *txr, struct 
 	rndis_msg_size = RNDIS_MESSAGE_SIZE(rndis_packet);
 
 	/*
-	 * Set the hash info for this packet, so that the host could
+	 * Set the hash value for this packet, so that the host could
 	 * dispatch the TX done event for this packet back to this TX
 	 * ring's channel.
 	 */
-	rndis_msg_size += RNDIS_HASH_PPI_SIZE;
-	rppi = hv_set_rppi_data(rndis_mesg, RNDIS_HASH_PPI_SIZE,
+	rndis_msg_size += RNDIS_HASHVAL_PPI_SIZE;
+	rppi = hv_set_rppi_data(rndis_mesg, RNDIS_HASHVAL_PPI_SIZE,
 	    nbl_hash_value);
-	hash_info = (struct ndis_hash_info *)((uint8_t *)rppi +
+	hash_value = (struct rndis_hash_value *)((uint8_t *)rppi +
 	    rppi->per_packet_info_offset);
-	hash_info->hash = txr->hn_tx_idx;
+	hash_value->hash_value = txr->hn_tx_idx;
 
 	if (m_head->m_flags & M_VLANTAG) {
 		ndis_8021q_info *rppi_vlan_info;
@@ -1308,7 +1308,9 @@ hv_m_append(struct mbuf *m0, int len, c_
  */
 int
 netvsc_recv(struct hv_vmbus_channel *chan, netvsc_packet *packet,
-    rndis_tcp_ip_csum_info *csum_info)
+    const rndis_tcp_ip_csum_info *csum_info,
+    const struct rndis_hash_info *hash_info,
+    const struct rndis_hash_value *hash_value)
 {
 	struct hn_rx_ring *rxr = chan->hv_chan_rxr;
 	struct ifnet *ifp = rxr->hn_ifp;
@@ -1417,7 +1419,6 @@ netvsc_recv(struct hv_vmbus_channel *cha
 					    CSUM_DATA_VALID | CSUM_PSEUDO_HDR);
 					m_new->m_pkthdr.csum_data = 0xffff;
 				}
-				/* Rely on SW csum verification though... */
 				do_lro = 1;
 			} else if (pr == IPPROTO_UDP) {
 				if (do_csum &&
@@ -1444,8 +1445,50 @@ skip:
 		m_new->m_flags |= M_VLANTAG;
 	}
 
-	m_new->m_pkthdr.flowid = rxr->hn_rx_idx;
-	M_HASHTYPE_SET(m_new, M_HASHTYPE_OPAQUE);
+	if (hash_info != NULL && hash_value != NULL) {
+		int hash_type = M_HASHTYPE_OPAQUE;
+
+		rxr->hn_rss_pkts++;
+		m_new->m_pkthdr.flowid = hash_value->hash_value;
+		if ((hash_info->hash_info & NDIS_HASH_FUNCTION_MASK) ==
+		    NDIS_HASH_FUNCTION_TOEPLITZ) {
+			uint32_t type =
+			    (hash_info->hash_info & NDIS_HASH_TYPE_MASK);
+
+			switch (type) {
+			case NDIS_HASH_IPV4:
+				hash_type = M_HASHTYPE_RSS_IPV4;
+				break;
+
+			case NDIS_HASH_TCP_IPV4:
+				hash_type = M_HASHTYPE_RSS_TCP_IPV4;
+				break;
+
+			case NDIS_HASH_IPV6:
+				hash_type = M_HASHTYPE_RSS_IPV6;
+				break;
+
+			case NDIS_HASH_IPV6_EX:
+				hash_type = M_HASHTYPE_RSS_IPV6_EX;
+				break;
+
+			case NDIS_HASH_TCP_IPV6:
+				hash_type = M_HASHTYPE_RSS_TCP_IPV6;
+				break;
+
+			case NDIS_HASH_TCP_IPV6_EX:
+				hash_type = M_HASHTYPE_RSS_TCP_IPV6_EX;
+				break;
+			}
+		}
+		M_HASHTYPE_SET(m_new, hash_type);
+	} else {
+		if (hash_value != NULL)
+			m_new->m_pkthdr.flowid = hash_value->hash_value;
+		else
+			m_new->m_pkthdr.flowid = rxr->hn_rx_idx;
+		M_HASHTYPE_SET(m_new, M_HASHTYPE_OPAQUE);
+	}
 
 	/*
 	 * Note:  Moved RX completion back to hv_nv_on_receive() so all
@@ -2265,6 +2308,11 @@ hn_create_rx_data(struct hn_softc *sc, i
 				    SYSCTL_CHILDREN(rxr->hn_rx_sysctl_tree),
 				    OID_AUTO, "packets", CTLFLAG_RW,
 				    &rxr->hn_pkts, "# of packets received");
+				SYSCTL_ADD_ULONG(ctx,
+				    SYSCTL_CHILDREN(rxr->hn_rx_sysctl_tree),
+				    OID_AUTO, "rss_pkts", CTLFLAG_RW,
+				    &rxr->hn_rss_pkts,
+				    "# of packets w/ RSS info received");
 			}
 		}
 	}

Modified: stable/10/sys/dev/hyperv/netvsc/hv_rndis.h
==============================================================================
--- stable/10/sys/dev/hyperv/netvsc/hv_rndis.h	Tue Jun 21 06:56:09 2016	(r302052)
+++ stable/10/sys/dev/hyperv/netvsc/hv_rndis.h	Tue Jun 21 07:05:49 2016	(r302053)
@@ -617,6 +617,7 @@ typedef enum ndis_per_pkt_infotype_ {
 } ndis_per_pkt_infotype;
 
 #define nbl_hash_value	pkt_cancel_id
+#define nbl_hash_info	original_netbuf_list
 
 typedef struct ndis_8021q_info_ {
 	union {
@@ -630,10 +631,6 @@ typedef struct ndis_8021q_info_ {
 	} u1;
 } ndis_8021q_info;
 
-struct ndis_hash_info {
-	uint32_t	hash;
-} __packed;
-
 struct rndis_object_header {
 	uint8_t type;
 	uint8_t revision;
@@ -694,6 +691,28 @@ typedef struct rndis_tcp_ip_csum_info_ {
 	};
 } rndis_tcp_ip_csum_info;
 
+struct rndis_hash_value {
+	uint32_t	hash_value;
+} __packed;
+
+struct rndis_hash_info {
+	uint32_t	hash_info;
+} __packed;
+
+#define NDIS_HASH_FUNCTION_MASK		0x000000FF	/* see hash function */
+#define NDIS_HASH_TYPE_MASK		0x00FFFF00	/* see hash type */
+
+/* hash function */
+#define NDIS_HASH_FUNCTION_TOEPLITZ	0x00000001
+
+/* hash type */
+#define NDIS_HASH_IPV4			0x00000100
+#define NDIS_HASH_TCP_IPV4		0x00000200
+#define NDIS_HASH_IPV6			0x00000400
+#define NDIS_HASH_IPV6_EX		0x00000800
+#define NDIS_HASH_TCP_IPV6		0x00001000
+#define NDIS_HASH_TCP_IPV6_EX		0x00002000
+
 typedef struct rndis_tcp_tso_info_ {
 	union {
 		struct {
@@ -727,8 +746,8 @@ typedef struct rndis_tcp_tso_info_ {
 	};
 } rndis_tcp_tso_info;
 
-#define RNDIS_HASH_PPI_SIZE	(sizeof(rndis_per_packet_info) + \
-				sizeof(struct ndis_hash_info))
+#define RNDIS_HASHVAL_PPI_SIZE	(sizeof(rndis_per_packet_info) + \
+				sizeof(struct rndis_hash_value))
 
 #define RNDIS_VLAN_PPI_SIZE	(sizeof(rndis_per_packet_info) + \
 				sizeof(ndis_8021q_info))
@@ -1066,7 +1085,9 @@ typedef struct rndismp_rx_bufs_info_ {
 struct hv_vmbus_channel;
 
 int netvsc_recv(struct hv_vmbus_channel *chan,
-    netvsc_packet *packet, rndis_tcp_ip_csum_info *csum_info);
+    netvsc_packet *packet, const rndis_tcp_ip_csum_info *csum_info,
+    const struct rndis_hash_info *hash_info,
+    const struct rndis_hash_value *hash_value);
 void netvsc_channel_rollup(struct hv_vmbus_channel *chan);
 
 void* hv_set_rppi_data(rndis_msg *rndis_mesg,

Modified: stable/10/sys/dev/hyperv/netvsc/hv_rndis_filter.c
==============================================================================
--- stable/10/sys/dev/hyperv/netvsc/hv_rndis_filter.c	Tue Jun 21 06:56:09 2016	(r302052)
+++ stable/10/sys/dev/hyperv/netvsc/hv_rndis_filter.c	Tue Jun 21 07:05:49 2016	(r302053)
@@ -50,6 +50,22 @@ __FBSDID("$FreeBSD$");
 #include "hv_rndis.h"
 #include "hv_rndis_filter.h"
 
+struct hv_rf_recvinfo {
+	const ndis_8021q_info		*vlan_info;
+	const rndis_tcp_ip_csum_info	*csum_info;
+	const struct rndis_hash_info	*hash_info;
+	const struct rndis_hash_value	*hash_value;
+};
+
+#define HV_RF_RECVINFO_VLAN	0x1
+#define HV_RF_RECVINFO_CSUM	0x2
+#define HV_RF_RECVINFO_HASHINF	0x4
+#define HV_RF_RECVINFO_HASHVAL	0x8
+#define HV_RF_RECVINFO_ALL		\
+	(HV_RF_RECVINFO_VLAN |		\
+	 HV_RF_RECVINFO_CSUM |		\
+	 HV_RF_RECVINFO_HASHINF |	\
+	 HV_RF_RECVINFO_HASHVAL)
 
 /*
  * Forward declarations
@@ -434,6 +450,84 @@ hv_rf_receive_indicate_status(rndis_devi
 	}
 }
 
+static int
+hv_rf_find_recvinfo(const rndis_packet *rpkt, struct hv_rf_recvinfo *info)
+{
+	const rndis_per_packet_info *ppi;
+	uint32_t mask, len;
+
+	info->vlan_info = NULL;
+	info->csum_info = NULL;
+	info->hash_info = NULL;
+	info->hash_value = NULL;
+
+	if (rpkt->per_pkt_info_offset == 0)
+		return 0;
+
+	ppi = (const rndis_per_packet_info *)
+	    ((const uint8_t *)rpkt + rpkt->per_pkt_info_offset);
+	len = rpkt->per_pkt_info_length;
+	mask = 0;
+
+	while (len != 0) {
+		const void *ppi_dptr;
+		uint32_t ppi_dlen;
+
+		if (__predict_false(ppi->size < ppi->per_packet_info_offset))
+			return EINVAL;
+		ppi_dlen = ppi->size - ppi->per_packet_info_offset;
+		ppi_dptr = (const uint8_t *)ppi + ppi->per_packet_info_offset;
+
+		switch (ppi->type) {
+		case ieee_8021q_info:
+			if (__predict_false(ppi_dlen < sizeof(ndis_8021q_info)))
+				return EINVAL;
+			info->vlan_info = ppi_dptr;
+			mask |= HV_RF_RECVINFO_VLAN;
+			break;
+
+		case tcpip_chksum_info:
+			if (__predict_false(ppi_dlen <
+			    sizeof(rndis_tcp_ip_csum_info)))
+				return EINVAL;
+			info->csum_info = ppi_dptr;
+			mask |= HV_RF_RECVINFO_CSUM;
+			break;
+
+		case nbl_hash_value:
+			if (__predict_false(ppi_dlen <
+			    sizeof(struct rndis_hash_value)))
+				return EINVAL;
+			info->hash_value = ppi_dptr;
+			mask |= HV_RF_RECVINFO_HASHVAL;
+			break;
+
+		case nbl_hash_info:
+			if (__predict_false(ppi_dlen <
+			    sizeof(struct rndis_hash_info)))
+				return EINVAL;
+			info->hash_info = ppi_dptr;
+			mask |= HV_RF_RECVINFO_HASHINF;
+			break;
+
+		default:
+			goto skip;
+		}
+
+		if (mask == HV_RF_RECVINFO_ALL) {
+			/* All found; done */
+			break;
+		}
+skip:
+		if (__predict_false(len < ppi->size))
+			return EINVAL;
+		len -= ppi->size;
+		ppi = (const rndis_per_packet_info *)
+		    ((const uint8_t *)ppi + ppi->size);
+	}
+	return 0;
+}
+
 /*
  * RNDIS filter receive data
  */
@@ -442,10 +536,9 @@ hv_rf_receive_data(rndis_device *device,
     struct hv_vmbus_channel *chan, netvsc_packet *pkt)
 {
 	rndis_packet *rndis_pkt;
-	ndis_8021q_info *rppi_vlan_info;
 	uint32_t data_offset;
-	rndis_tcp_ip_csum_info *csum_info = NULL;
 	device_t dev = device->net_dev->dev->device;
+	struct hv_rf_recvinfo info;
 
 	rndis_pkt = &message->msg.packet;
 
@@ -469,15 +562,18 @@ hv_rf_receive_data(rndis_device *device,
 	pkt->tot_data_buf_len = rndis_pkt->data_length;
 	pkt->data = (void *)((unsigned long)pkt->data + data_offset);
 
-	rppi_vlan_info = hv_get_ppi_data(rndis_pkt, ieee_8021q_info);
-	if (rppi_vlan_info) {
-		pkt->vlan_tci = rppi_vlan_info->u1.s1.vlan_id;
-	} else {
-		pkt->vlan_tci = 0;
+	if (hv_rf_find_recvinfo(rndis_pkt, &info)) {
+		pkt->status = nvsp_status_failure;
+		device_printf(dev, "recvinfo parsing failed\n");
+		return;
 	}
 
-	csum_info = hv_get_ppi_data(rndis_pkt, tcpip_chksum_info);
-	netvsc_recv(chan, pkt, csum_info);
+	if (info.vlan_info != NULL)
+		pkt->vlan_tci = info.vlan_info->u1.s1.vlan_id;
+	else
+		pkt->vlan_tci = 0;
+
+	netvsc_recv(chan, pkt, info.csum_info, info.hash_info, info.hash_value);
 }
 
 /*


More information about the svn-src-all mailing list