diff options
author | sephe <sephe@FreeBSD.org> | 2016-06-21 07:05:49 +0000 |
---|---|---|
committer | sephe <sephe@FreeBSD.org> | 2016-06-21 07:05:49 +0000 |
commit | bc9e0dd07a76c4d7a1c6fcf21824ca2cecff2c6d (patch) | |
tree | b130cc0a7e459334d166043869c71302e888a9c4 /sys/dev | |
parent | b8d88a19ec41ade378eb1628c2cca68be449fc36 (diff) | |
download | FreeBSD-src-bc9e0dd07a76c4d7a1c6fcf21824ca2cecff2c6d.zip FreeBSD-src-bc9e0dd07a76c4d7a1c6fcf21824ca2cecff2c6d.tar.gz |
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
Diffstat (limited to 'sys/dev')
-rw-r--r-- | sys/dev/hyperv/netvsc/hv_net_vsc.h | 1 | ||||
-rw-r--r-- | sys/dev/hyperv/netvsc/hv_netvsc_drv_freebsd.c | 70 | ||||
-rw-r--r-- | sys/dev/hyperv/netvsc/hv_rndis.h | 35 | ||||
-rw-r--r-- | sys/dev/hyperv/netvsc/hv_rndis_filter.c | 114 |
4 files changed, 193 insertions, 27 deletions
diff --git a/sys/dev/hyperv/netvsc/hv_net_vsc.h b/sys/dev/hyperv/netvsc/hv_net_vsc.h index db696e6..7c43f64 100644 --- a/sys/dev/hyperv/netvsc/hv_net_vsc.h +++ b/sys/dev/hyperv/netvsc/hv_net_vsc.h @@ -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; diff --git a/sys/dev/hyperv/netvsc/hv_netvsc_drv_freebsd.c b/sys/dev/hyperv/netvsc/hv_netvsc_drv_freebsd.c index 1d1fd0d..f670c12 100644 --- a/sys/dev/hyperv/netvsc/hv_netvsc_drv_freebsd.c +++ b/sys/dev/hyperv/netvsc/hv_netvsc_drv_freebsd.c @@ -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 hn_txdesc *txd, struct mbuf **m_head0) 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 hn_txdesc *txd, struct mbuf **m_head0) 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_caddr_t cp) */ 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 *chan, netvsc_packet *packet, 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, int ring_cnt) 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"); } } } diff --git a/sys/dev/hyperv/netvsc/hv_rndis.h b/sys/dev/hyperv/netvsc/hv_rndis.h index 8ece1d0..b27579d 100644 --- a/sys/dev/hyperv/netvsc/hv_rndis.h +++ b/sys/dev/hyperv/netvsc/hv_rndis.h @@ -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, diff --git a/sys/dev/hyperv/netvsc/hv_rndis_filter.c b/sys/dev/hyperv/netvsc/hv_rndis_filter.c index b320591..8e95510 100644 --- a/sys/dev/hyperv/netvsc/hv_rndis_filter.c +++ b/sys/dev/hyperv/netvsc/hv_rndis_filter.c @@ -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_device *device, rndis_msg *response) } } +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, rndis_msg *message, 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, rndis_msg *message, 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); } /* |