Changeset View
Standalone View
sys/dev/vmware/vmxnet3/if_vmx.c
Show All 17 Lines | |||||
* $OpenBSD: src/sys/dev/pci/if_vmx.c,v 1.11 2013/06/22 00:28:10 uebayasi Exp $ | * $OpenBSD: src/sys/dev/pci/if_vmx.c,v 1.11 2013/06/22 00:28:10 uebayasi Exp $ | ||||
*/ | */ | ||||
/* Driver for VMware vmxnet3 virtual ethernet devices. */ | /* Driver for VMware vmxnet3 virtual ethernet devices. */ | ||||
#include <sys/cdefs.h> | #include <sys/cdefs.h> | ||||
__FBSDID("$FreeBSD$"); | __FBSDID("$FreeBSD$"); | ||||
#include "opt_rss.h" | |||||
#include <sys/param.h> | #include <sys/param.h> | ||||
#include <sys/systm.h> | #include <sys/systm.h> | ||||
#include <sys/kernel.h> | #include <sys/kernel.h> | ||||
#include <sys/endian.h> | #include <sys/endian.h> | ||||
#include <sys/sockio.h> | #include <sys/sockio.h> | ||||
#include <sys/mbuf.h> | #include <sys/mbuf.h> | ||||
#include <sys/malloc.h> | #include <sys/malloc.h> | ||||
#include <sys/module.h> | #include <sys/module.h> | ||||
#include <sys/socket.h> | #include <sys/socket.h> | ||||
#include <sys/sysctl.h> | #include <sys/sysctl.h> | ||||
#include <sys/smp.h> | #include <sys/smp.h> | ||||
#include <vm/vm.h> | #include <vm/vm.h> | ||||
#include <vm/pmap.h> | #include <vm/pmap.h> | ||||
#include <net/ethernet.h> | #include <net/ethernet.h> | ||||
#include <net/if.h> | #include <net/if.h> | ||||
#include <net/if_var.h> | #include <net/if_var.h> | ||||
#include <net/if_arp.h> | #include <net/if_arp.h> | ||||
#include <net/if_dl.h> | #include <net/if_dl.h> | ||||
#include <net/if_types.h> | #include <net/if_types.h> | ||||
#include <net/if_media.h> | #include <net/if_media.h> | ||||
#include <net/if_vlan_var.h> | #include <net/if_vlan_var.h> | ||||
#include <net/iflib.h> | #include <net/iflib.h> | ||||
#ifdef RSS | |||||
#include <net/rss_config.h> | |||||
#endif | |||||
#include <netinet/in_systm.h> | #include <netinet/in_systm.h> | ||||
#include <netinet/in.h> | #include <netinet/in.h> | ||||
#include <netinet/ip.h> | #include <netinet/ip.h> | ||||
#include <netinet/ip6.h> | #include <netinet/ip6.h> | ||||
#include <netinet6/ip6_var.h> | #include <netinet6/ip6_var.h> | ||||
#include <netinet/udp.h> | #include <netinet/udp.h> | ||||
#include <netinet/tcp.h> | #include <netinet/tcp.h> | ||||
▲ Show 20 Lines • Show All 1,078 Lines • ▼ Show 20 Lines | static const uint8_t rss_key[UPT1_RSS_MAX_KEY_SIZE] = { | ||||
0x35, 0x12, 0xb9, 0x56, 0x7c, 0x76, 0x4b, 0x70, | 0x35, 0x12, 0xb9, 0x56, 0x7c, 0x76, 0x4b, 0x70, | ||||
0xd8, 0x56, 0xa3, 0x18, 0x9b, 0x0a, 0xee, 0xf3, | 0xd8, 0x56, 0xa3, 0x18, 0x9b, 0x0a, 0xee, 0xf3, | ||||
0x96, 0xa6, 0x9f, 0x8f, 0x9e, 0x8c, 0x90, 0xc9, | 0x96, 0xa6, 0x9f, 0x8f, 0x9e, 0x8c, 0x90, 0xc9, | ||||
}; | }; | ||||
struct vmxnet3_driver_shared *ds; | struct vmxnet3_driver_shared *ds; | ||||
if_softc_ctx_t scctx; | if_softc_ctx_t scctx; | ||||
struct vmxnet3_rss_shared *rss; | struct vmxnet3_rss_shared *rss; | ||||
#ifdef RSS | |||||
uint8_t rss_algo; | |||||
#endif | |||||
int i; | int i; | ||||
ds = sc->vmx_ds; | ds = sc->vmx_ds; | ||||
scctx = sc->vmx_scctx; | scctx = sc->vmx_scctx; | ||||
rss = sc->vmx_rss; | rss = sc->vmx_rss; | ||||
rss->hash_type = | rss->hash_type = | ||||
UPT1_RSS_HASH_TYPE_IPV4 | UPT1_RSS_HASH_TYPE_TCP_IPV4 | | UPT1_RSS_HASH_TYPE_IPV4 | UPT1_RSS_HASH_TYPE_TCP_IPV4 | | ||||
UPT1_RSS_HASH_TYPE_IPV6 | UPT1_RSS_HASH_TYPE_TCP_IPV6; | UPT1_RSS_HASH_TYPE_IPV6 | UPT1_RSS_HASH_TYPE_TCP_IPV6; | ||||
rss->hash_func = UPT1_RSS_HASH_FUNC_TOEPLITZ; | rss->hash_func = UPT1_RSS_HASH_FUNC_TOEPLITZ; | ||||
rss->hash_key_size = UPT1_RSS_MAX_KEY_SIZE; | rss->hash_key_size = UPT1_RSS_MAX_KEY_SIZE; | ||||
rss->ind_table_size = UPT1_RSS_MAX_IND_TABLE_SIZE; | rss->ind_table_size = UPT1_RSS_MAX_IND_TABLE_SIZE; | ||||
#ifdef RSS | |||||
/* | |||||
* If the software RSS is configured to anything else other than | |||||
* Toeplitz, then just do Toeplitz in "hardware" for the sake of | |||||
* the packet distribution, but report the hash as opaque to | |||||
* disengage from the software RSS. | |||||
pkelsey: I think the correct way to do this is to modify vmxnet3_attach_post() such that when RSS is… | |||||
Done Inline ActionsAnother idea that I've just got is to regress to using M_HASHTYPE_OPAQUE_HASH for all received packets when rss_gethashalgo() is not TOEPLITZ while still configuring the "hardware" to use TOEPLITZ. With that, we still get the benefit of distributing incoming packets between queues / CPUs, but the software RSS will not expect that hardware hashes are the same as software hashes. avg: Another idea that I've just got is to regress to using M_HASHTYPE_OPAQUE_HASH for all received… | |||||
Not Done Inline ActionsMy understanding is that with that approach, the benefit would be that the work of the hashes in software would then be distributed across multiple cores (it would be done on the core handling the given receive queue prior to dispatching the packet to the core indicated by the computed hash). If that's the case, seems reasonable to me. pkelsey: My understanding is that with that approach, the benefit would be that the work of the hashes… | |||||
*/ | |||||
rss_algo = rss_gethashalgo(); | |||||
if (rss_algo == RSS_HASH_TOEPLITZ) { | |||||
rss_getkey(rss->hash_key); | |||||
for (i = 0; i < UPT1_RSS_MAX_IND_TABLE_SIZE; i++) { | |||||
rss->ind_table[i] = rss_get_indirection_to_bucket(i) % | |||||
scctx->isc_nrxqsets; | |||||
} | |||||
sc->vmx_flags |= VMXNET3_FLAG_SOFT_RSS; | |||||
} else | |||||
#endif | |||||
Done Inline ActionsI think you mean for this to be #endif, and for the #endif below to go away. pkelsey: I think you mean for this to be #endif, and for the #endif below to go away. | |||||
Done Inline ActionsOops! avg: Oops! | |||||
{ | |||||
memcpy(rss->hash_key, rss_key, UPT1_RSS_MAX_KEY_SIZE); | memcpy(rss->hash_key, rss_key, UPT1_RSS_MAX_KEY_SIZE); | ||||
for (i = 0; i < UPT1_RSS_MAX_IND_TABLE_SIZE; i++) | for (i = 0; i < UPT1_RSS_MAX_IND_TABLE_SIZE; i++) | ||||
rss->ind_table[i] = i % scctx->isc_nrxqsets; | rss->ind_table[i] = i % scctx->isc_nrxqsets; | ||||
sc->vmx_flags &= ~VMXNET3_FLAG_SOFT_RSS; | |||||
} | } | ||||
} | |||||
static void | static void | ||||
vmxnet3_reinit_shared_data(struct vmxnet3_softc *sc) | vmxnet3_reinit_shared_data(struct vmxnet3_softc *sc) | ||||
{ | { | ||||
struct ifnet *ifp; | struct ifnet *ifp; | ||||
struct vmxnet3_driver_shared *ds; | struct vmxnet3_driver_shared *ds; | ||||
if_softc_ctx_t scctx; | if_softc_ctx_t scctx; | ||||
▲ Show 20 Lines • Show All 326 Lines • ▼ Show 20 Lines | if (++cqidx == rxc->vxcr_ndesc) { | ||||
cqidx = 0; | cqidx = 0; | ||||
rxc->vxcr_gen ^= 1; | rxc->vxcr_gen ^= 1; | ||||
} | } | ||||
rxcd = &rxc->vxcr_u.rxcd[cqidx]; | rxcd = &rxc->vxcr_u.rxcd[cqidx]; | ||||
} | } | ||||
KASSERT(rxcd->sop, ("%s: expected sop", __func__)); | KASSERT(rxcd->sop, ("%s: expected sop", __func__)); | ||||
/* | /* | ||||
* RSS and flow ID | * RSS and flow ID. | ||||
* Types other than M_HASHTYPE_NONE and M_HASHTYPE_OPAQUE_HASH should | |||||
* be used only if the software RSS is enabled and it uses the same | |||||
* algorithm and the hash key as the "hardware". If the software RSS | |||||
* is not enabled, then it's simply pointless to use those types, | |||||
* otherwise there will be mismatching hash values resulting in broken | |||||
* connectivity. | |||||
*/ | */ | ||||
ri->iri_flowid = rxcd->rss_hash; | ri->iri_flowid = rxcd->rss_hash; | ||||
if ((sc->vmx_flags & VMXNET3_FLAG_SOFT_RSS) != 0) { | |||||
switch (rxcd->rss_type) { | switch (rxcd->rss_type) { | ||||
case VMXNET3_RCD_RSS_TYPE_NONE: | case VMXNET3_RCD_RSS_TYPE_NONE: | ||||
ri->iri_flowid = ri->iri_qsidx; | ri->iri_flowid = ri->iri_qsidx; | ||||
ri->iri_rsstype = M_HASHTYPE_NONE; | ri->iri_rsstype = M_HASHTYPE_NONE; | ||||
break; | break; | ||||
case VMXNET3_RCD_RSS_TYPE_IPV4: | case VMXNET3_RCD_RSS_TYPE_IPV4: | ||||
ri->iri_rsstype = M_HASHTYPE_RSS_IPV4; | ri->iri_rsstype = M_HASHTYPE_RSS_IPV4; | ||||
break; | break; | ||||
case VMXNET3_RCD_RSS_TYPE_TCPIPV4: | case VMXNET3_RCD_RSS_TYPE_TCPIPV4: | ||||
ri->iri_rsstype = M_HASHTYPE_RSS_TCP_IPV4; | ri->iri_rsstype = M_HASHTYPE_RSS_TCP_IPV4; | ||||
break; | break; | ||||
case VMXNET3_RCD_RSS_TYPE_IPV6: | case VMXNET3_RCD_RSS_TYPE_IPV6: | ||||
ri->iri_rsstype = M_HASHTYPE_RSS_IPV6; | ri->iri_rsstype = M_HASHTYPE_RSS_IPV6; | ||||
break; | break; | ||||
case VMXNET3_RCD_RSS_TYPE_TCPIPV6: | case VMXNET3_RCD_RSS_TYPE_TCPIPV6: | ||||
ri->iri_rsstype = M_HASHTYPE_RSS_TCP_IPV6; | ri->iri_rsstype = M_HASHTYPE_RSS_TCP_IPV6; | ||||
break; | break; | ||||
default: | default: | ||||
ri->iri_rsstype = M_HASHTYPE_OPAQUE_HASH; | ri->iri_rsstype = M_HASHTYPE_OPAQUE_HASH; | ||||
break; | break; | ||||
} | |||||
} else { | |||||
pkelseyUnsubmitted Not Done Inline ActionsThis could be placed under #ifdef RSS to leave the code out as VMXNET_FLAG_SOFT_RSS can't be set when RSS is not defined. Probably does not make much of a practical difference given this driver is not run on very constrained platforms. I'll leave that up to you as to whether to do it. pkelsey: This could be placed under #ifdef RSS to leave the code out as VMXNET_FLAG_SOFT_RSS can't be… | |||||
switch (rxcd->rss_type) { | |||||
case VMXNET3_RCD_RSS_TYPE_NONE: | |||||
ri->iri_flowid = ri->iri_qsidx; | |||||
ri->iri_rsstype = M_HASHTYPE_NONE; | |||||
break; | |||||
default: | |||||
ri->iri_rsstype = M_HASHTYPE_OPAQUE_HASH; | |||||
break; | |||||
} | |||||
} | } | ||||
/* VLAN */ | /* VLAN */ | ||||
if (rxcd->vlan) { | if (rxcd->vlan) { | ||||
ri->iri_flags |= M_VLANTAG; | ri->iri_flags |= M_VLANTAG; | ||||
ri->iri_vtag = rxcd->vtag; | ri->iri_vtag = rxcd->vtag; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 884 Lines • Show Last 20 Lines |
I think the correct way to do this is to modify vmxnet3_attach_post() such that when RSS is defined, if rss_gethashalgo() is not TOEPLITZ, the VMXNET3_FLAGS_RSS flag will not get set in sc->vmx_flags. When that flag is not set, vmxnet3_reinit_rss_shared_data() will never be called, and thus can be written assuming that rss->hash_func should always be set to TOEPLITZ.
The way it is written now, we have to wonder whether the vmxnet3 virtual device implementation will tolerate RSS enabled with hash_func set to NONE. We have no documentation for this virtual device implementation and no reference code that tries this mode. We do however know (via the successful operation of both the FreeBSD and Linux drivers) that the virtual device works when RSS is disabled in the virtual device requested features, and also when it is enabled in the requested features with the hash_func sent to TOEPLITZ.