Files
yttrium-virtio-gpu/NetKVM/wlh/ParaNdis6-RSS.cpp
T
Dmitry Fleytman 53b6380af4 NetKVM: BZ1096505 Separate transmit path data from device context
This commit is a preparation for multiqueue implementation.
It itroduces changes driver's TX code structure the way
needed to allow creation of multiple independent transmit pathes.

Signed-off-by: Dmitry Fleytman <[email protected]>
2014-05-12 18:20:53 +10:00

575 lines
23 KiB
C++

#include "ndis56common.h"
#if PARANDIS_SUPPORT_RSS
static VOID ApplySettings(PPARANDIS_RSS_PARAMS RSSParameters,
PARANDIS_RSS_MODE NewRSSMode,
PARANDIS_HASHING_SETTINGS *ReceiveHashingSettings,
PARANDIS_SCALING_SETTINGS *ReceiveScalingSettings)
{
NdisAcquireSpinLock(&RSSParameters->RSSSettingsLock);
RSSParameters->RSSMode = NewRSSMode;
if(NewRSSMode != PARANDIS_RSS_DISABLED)
{
RSSParameters->ActiveHashingSettings = *ReceiveHashingSettings;
if(NewRSSMode == PARANDIS_RSS_FULL)
{
if(RSSParameters->ActiveRSSScalingSettings.CPUIndexMapping != NULL)
NdisFreeMemory(RSSParameters->ActiveRSSScalingSettings.CPUIndexMapping, 0, 0);
RSSParameters->ActiveRSSScalingSettings = *ReceiveScalingSettings;
ReceiveScalingSettings->CPUIndexMapping = NULL;
}
}
NdisReleaseSpinLock(&RSSParameters->RSSSettingsLock);
}
static VOID InitRSSParameters(PARANDIS_RSS_PARAMS *RSSParameters, CCHAR RSSReceiveQueuesNumber)
{
NdisZeroMemory(RSSParameters, sizeof(*RSSParameters));
NdisAllocateSpinLock(&RSSParameters->RSSSettingsLock);
RSSParameters->ReceiveQueuesNumber = RSSReceiveQueuesNumber;
}
static VOID CleanupRSSParameters(PARANDIS_RSS_PARAMS *RSSParameters)
{
if(RSSParameters->ActiveRSSScalingSettings.CPUIndexMapping != NULL)
NdisFreeMemory(RSSParameters->ActiveRSSScalingSettings.CPUIndexMapping, 0, 0);
if(RSSParameters->RSSScalingSettings.CPUIndexMapping != NULL)
NdisFreeMemory(RSSParameters->RSSScalingSettings.CPUIndexMapping, 0, 0);
NdisFreeSpinLock(&RSSParameters->RSSSettingsLock);
}
static VOID InitRSSCapabilities(NDIS_RECEIVE_SCALE_CAPABILITIES *RSSCapabilities, ULONG RSSReceiveQueuesNumber)
{
RSSCapabilities->Header.Type = NDIS_OBJECT_TYPE_RSS_CAPABILITIES;
#if (NDIS_SUPPORT_NDIS630)
RSSCapabilities->Header.Revision = NDIS_RECEIVE_SCALE_CAPABILITIES_REVISION_2;
RSSCapabilities->Header.Size = NDIS_SIZEOF_RECEIVE_SCALE_CAPABILITIES_REVISION_2;
#else
RSSCapabilities->Header.Revision = NDIS_RECEIVE_SCALE_CAPABILITIES_REVISION_1;
RSSCapabilities->Header.Size = NDIS_SIZEOF_RECEIVE_SCALE_CAPABILITIES_REVISION_1;
#endif
RSSCapabilities->CapabilitiesFlags = NDIS_RSS_CAPS_MESSAGE_SIGNALED_INTERRUPTS |
NDIS_RSS_CAPS_CLASSIFICATION_AT_ISR |
NDIS_RSS_CAPS_HASH_TYPE_TCP_IPV4 |
NDIS_RSS_CAPS_HASH_TYPE_TCP_IPV6 |
NDIS_RSS_CAPS_HASH_TYPE_TCP_IPV6_EX |
NdisHashFunctionToeplitz;
RSSCapabilities->NumberOfInterruptMessages = 1;
RSSCapabilities->NumberOfReceiveQueues = RSSReceiveQueuesNumber;
#if (NDIS_SUPPORT_NDIS630)
RSSCapabilities->NumberOfIndirectionTableEntries = NDIS_RSS_INDIRECTION_TABLE_MAX_SIZE_REVISION_2 / sizeof(PROCESSOR_NUMBER);
#endif
}
NDIS_RECEIVE_SCALE_CAPABILITIES* ParaNdis6_RSSCreateConfiguration(PARANDIS_RSS_PARAMS *RSSParameters,
NDIS_RECEIVE_SCALE_CAPABILITIES *RSSCapabilities,
CCHAR RSSReceiveQueuesNumber)
{
InitRSSParameters(RSSParameters, RSSReceiveQueuesNumber);
InitRSSCapabilities(RSSCapabilities, RSSReceiveQueuesNumber);
return RSSCapabilities;
}
VOID ParaNdis6_RSSCleanupConfiguration(PARANDIS_RSS_PARAMS *RSSParameters)
{
CleanupRSSParameters(RSSParameters);
}
static BOOLEAN IsValidHashInfo(ULONG HashInformation)
{
#define HASH_FLAGS_COMBINATION(Type, Flags) ( ((Type) & (Flags)) && !((Type) & ~(Flags)) )
ULONG ulHashType = NDIS_RSS_HASH_TYPE_FROM_HASH_INFO(HashInformation);
ULONG ulHashFunction = NDIS_RSS_HASH_FUNC_FROM_HASH_INFO(HashInformation);
if (HashInformation == 0)
return TRUE;
if (HASH_FLAGS_COMBINATION(ulHashType, NDIS_HASH_IPV4 | NDIS_HASH_TCP_IPV4 |
NDIS_HASH_IPV6 | NDIS_HASH_TCP_IPV6 |
NDIS_HASH_IPV6_EX | NDIS_HASH_TCP_IPV6_EX))
return ulHashFunction == NdisHashFunctionToeplitz;
return FALSE;
}
static __inline
BOOLEAN IsPowerOfTwo(ULONG n)
{
return ((n != 0) && ((n & (~n + 1)) == n));
}
static __inline
BOOLEAN IsCompatibleAffinities(PGROUP_AFFINITY a1, PGROUP_AFFINITY a2)
{
return (a1->Group == a2->Group) && (a1->Mask & a2->Mask);
}
static
CCHAR FindReceiveQueueForCurrentCpu(PPARANDIS_SCALING_SETTINGS RSSScalingSettings)
{
PROCESSOR_NUMBER CurrProcNum;
ULONG CurrProcIdx;
KeGetCurrentProcessorNumberEx(&CurrProcNum);
CurrProcIdx = KeGetProcessorIndexFromNumber(&CurrProcNum);
ASSERT(CurrProcIdx != INVALID_PROCESSOR_INDEX);
if(CurrProcIdx >= RSSScalingSettings->CPUIndexMappingSize)
return PARANDIS_RECEIVE_QUEUE_UNCLASSIFIED;
return RSSScalingSettings->CPUIndexMapping[CurrProcIdx];
}
static
BOOLEAN AllocateCPUMappingArray(NDIS_HANDLE NdisHandle, PPARANDIS_SCALING_SETTINGS RSSScalingSettings)
{
ULONG i;
ULONG CPUNumber = KeQueryActiveProcessorCountEx(ALL_PROCESSOR_GROUPS);
PCHAR NewCPUMappingArray = (PCHAR) NdisAllocateMemoryWithTagPriority(
NdisHandle,
sizeof(CCHAR) * CPUNumber,
PARANDIS_MEMORY_TAG,
NormalPoolPriority);
if(!NewCPUMappingArray)
return FALSE;
RSSScalingSettings->CPUIndexMapping = NewCPUMappingArray;
RSSScalingSettings->CPUIndexMappingSize = CPUNumber;
for(i = 0; i < CPUNumber; i++)
{
RSSScalingSettings->CPUIndexMapping[i] = PARANDIS_RECEIVE_QUEUE_UNCLASSIFIED;
}
return TRUE;
}
static
VOID FillCPUMappingArray(
PPARANDIS_SCALING_SETTINGS RSSScalingSettings,
CCHAR ReceiveQueuesNumber)
{
ULONG i;
CCHAR ReceiveQueue = PARANDIS_FIRST_RSS_RECEIVE_QUEUE;
for (i = 0; i < RSSScalingSettings->IndirectionTableSize/sizeof(PROCESSOR_NUMBER); i++)
{
PPROCESSOR_NUMBER ProcNum = &RSSScalingSettings->IndirectionTable[i];
ULONG CurrProcIdx = KeGetProcessorIndexFromNumber(ProcNum);
if(CurrProcIdx != INVALID_PROCESSOR_INDEX)
{
if(RSSScalingSettings->CPUIndexMapping[CurrProcIdx] == PARANDIS_RECEIVE_QUEUE_UNCLASSIFIED)
RSSScalingSettings->CPUIndexMapping[CurrProcIdx] = ReceiveQueue++;
RSSScalingSettings->QueueIndirectionTable[i] = RSSScalingSettings->CPUIndexMapping[CurrProcIdx];
if(ReceiveQueue == ReceiveQueuesNumber)
ReceiveQueue = PARANDIS_FIRST_RSS_RECEIVE_QUEUE;
}
else
{
RSSScalingSettings->QueueIndirectionTable[i] = PARANDIS_RECEIVE_QUEUE_UNCLASSIFIED;
}
}
}
NDIS_STATUS ParaNdis6_RSSSetParameters( PARANDIS_RSS_PARAMS *RSSParameters,
const NDIS_RECEIVE_SCALE_PARAMETERS* Params,
UINT ParamsLength,
PUINT ParamsBytesRead,
NDIS_HANDLE NdisHandle)
{
ULONG ProcessorMasksSize;
ULONG IndirectionTableEntries;
*ParamsBytesRead = 0;
if((RSSParameters->RSSMode == PARANDIS_RSS_HASHING) &&
!(Params->Flags & NDIS_RSS_PARAM_FLAG_DISABLE_RSS) &&
(Params->HashInformation != 0))
return NDIS_STATUS_NOT_SUPPORTED;
if (ParamsLength < sizeof(NDIS_RECEIVE_SCALE_PARAMETERS))
return NDIS_STATUS_INVALID_LENGTH;
if (!(Params->Flags & NDIS_RSS_PARAM_FLAG_HASH_INFO_UNCHANGED) &&
!IsValidHashInfo(Params->HashInformation))
return NDIS_STATUS_INVALID_PARAMETER;
IndirectionTableEntries = Params->IndirectionTableSize / sizeof(PROCESSOR_NUMBER);
if (!(Params->Flags & NDIS_RSS_PARAM_FLAG_ITABLE_UNCHANGED) &&
( (Params->IndirectionTableSize > sizeof(RSSParameters->RSSScalingSettings.IndirectionTable)) ||
(ParamsLength < (Params->IndirectionTableOffset + Params->IndirectionTableSize)) ||
!IsPowerOfTwo(IndirectionTableEntries) )
)
return NDIS_STATUS_INVALID_LENGTH;
if (!(Params->Flags & NDIS_RSS_PARAM_FLAG_HASH_KEY_UNCHANGED) &&
( (Params->HashSecretKeySize > sizeof(RSSParameters->RSSHashingSettings.HashSecretKey)) ||
(ParamsLength < (Params->HashSecretKeyOffset + Params->HashSecretKeySize)) )
)
return NDIS_STATUS_INVALID_LENGTH;
ProcessorMasksSize = Params->NumberOfProcessorMasks * Params->ProcessorMasksEntrySize;
if (ParamsLength < Params->ProcessorMasksOffset + ProcessorMasksSize)
return NDIS_STATUS_INVALID_LENGTH;
if(Params->Flags & NDIS_RSS_PARAM_FLAG_DISABLE_RSS || (Params->HashInformation == 0))
{
ApplySettings(RSSParameters, PARANDIS_RSS_DISABLED, NULL, NULL);
}
else
{
if (!(Params->Flags & NDIS_RSS_PARAM_FLAG_ITABLE_UNCHANGED))
{
if(!AllocateCPUMappingArray(NdisHandle, &RSSParameters->RSSScalingSettings))
return NDIS_STATUS_RESOURCES;
RSSParameters->RSSScalingSettings.IndirectionTableSize = Params->IndirectionTableSize;
NdisMoveMemory(RSSParameters->RSSScalingSettings.IndirectionTable,
(char*)Params + Params->IndirectionTableOffset, Params->IndirectionTableSize);
RSSParameters->RSSScalingSettings.RSSHashMask = IndirectionTableEntries - 1;
*ParamsBytesRead += Params->IndirectionTableSize;
*ParamsBytesRead += ProcessorMasksSize;
FillCPUMappingArray(&RSSParameters->RSSScalingSettings, RSSParameters->ReceiveQueuesNumber);
}
if (!(Params->Flags & NDIS_RSS_PARAM_FLAG_HASH_INFO_UNCHANGED))
RSSParameters->RSSHashingSettings.HashInformation = Params->HashInformation;
if (!(Params->Flags & NDIS_RSS_PARAM_FLAG_HASH_KEY_UNCHANGED))
{
RSSParameters->RSSHashingSettings.HashSecretKeySize = Params->HashSecretKeySize;
NdisMoveMemory(RSSParameters->RSSHashingSettings.HashSecretKey,
(char*)Params + Params->HashSecretKeyOffset, Params->HashSecretKeySize);
*ParamsBytesRead += Params->HashSecretKeySize;
}
ApplySettings(RSSParameters,
PARANDIS_RSS_FULL,
&RSSParameters->RSSHashingSettings,
&RSSParameters->RSSScalingSettings);
}
*ParamsBytesRead += sizeof(NDIS_RECEIVE_SCALE_PARAMETERS);
return NDIS_STATUS_SUCCESS;
}
ULONG ParaNdis6_QueryReceiveHash(const PARANDIS_RSS_PARAMS *RSSParameters,
RSS_HASH_KEY_PARAMETERS *RSSHashKeyParameters)
{
NdisZeroMemory(RSSHashKeyParameters, sizeof(*RSSHashKeyParameters));
RSSHashKeyParameters->ReceiveHashParameters.Header.Type = NDIS_OBJECT_TYPE_DEFAULT;
RSSHashKeyParameters->ReceiveHashParameters.Header.Revision = NDIS_RECEIVE_HASH_PARAMETERS_REVISION_1;
RSSHashKeyParameters->ReceiveHashParameters.Header.Size = NDIS_SIZEOF_RECEIVE_HASH_PARAMETERS_REVISION_1;
RSSHashKeyParameters->ReceiveHashParameters.HashInformation = RSSParameters->ReceiveHashingSettings.HashInformation;
if(RSSParameters->RSSMode == PARANDIS_RSS_HASHING)
RSSHashKeyParameters->ReceiveHashParameters.Flags = NDIS_RECEIVE_HASH_FLAG_ENABLE_HASH;
RSSHashKeyParameters->ReceiveHashParameters.HashSecretKeySize = RSSParameters->ReceiveHashingSettings.HashSecretKeySize;
NdisMoveMemory(RSSHashKeyParameters->HashSecretKey,
RSSParameters->ReceiveHashingSettings.HashSecretKey,
RSSHashKeyParameters->ReceiveHashParameters.HashSecretKeySize);
RSSHashKeyParameters->ReceiveHashParameters.HashSecretKeyOffset = FIELD_OFFSET(RSS_HASH_KEY_PARAMETERS, HashSecretKey);
return sizeof(RSSHashKeyParameters->ReceiveHashParameters) + RSSHashKeyParameters->ReceiveHashParameters.HashSecretKeySize;
}
NDIS_STATUS ParaNdis6_RSSSetReceiveHash(PARANDIS_RSS_PARAMS *RSSParameters,
const NDIS_RECEIVE_HASH_PARAMETERS* Params,
UINT ParamsLength,
PUINT ParamsBytesRead)
{
if (ParamsLength < sizeof(NDIS_RECEIVE_HASH_PARAMETERS))
return NDIS_STATUS_INVALID_LENGTH;
*ParamsBytesRead += sizeof(NDIS_RECEIVE_HASH_PARAMETERS);
if (RSSParameters->RSSMode == PARANDIS_RSS_FULL)
{
//Here we check that originator doesn't try to enable hashing while full RSS is on.
//Disable hashing abd clear parameters is legitimate operation hovewer
if(Params->Flags & NDIS_RECEIVE_HASH_FLAG_ENABLE_HASH)
{
if(!(Params->Flags & NDIS_RECEIVE_HASH_FLAG_HASH_INFO_UNCHANGED) && (Params->HashInformation != 0))
return NDIS_STATUS_NOT_SUPPORTED;
if((Params->Flags & NDIS_RECEIVE_HASH_FLAG_HASH_INFO_UNCHANGED) &&
(RSSParameters->ReceiveHashingSettings.HashInformation != 0))
return NDIS_STATUS_NOT_SUPPORTED;
}
}
if (!(Params->Flags & NDIS_RECEIVE_HASH_FLAG_HASH_INFO_UNCHANGED) &&
(!IsValidHashInfo(Params->HashInformation)))
return NDIS_STATUS_INVALID_PARAMETER;
if ( (!(Params->Flags & NDIS_RECEIVE_HASH_FLAG_HASH_KEY_UNCHANGED)) &&
( (Params->HashSecretKeySize > NDIS_RSS_HASH_SECRET_KEY_MAX_SIZE_REVISION_2) ||
(ParamsLength < (Params->HashSecretKeyOffset + Params->HashSecretKeySize)) )
)
return NDIS_STATUS_INVALID_LENGTH;
if (!(Params->Flags & NDIS_RECEIVE_HASH_FLAG_HASH_INFO_UNCHANGED))
{
RSSParameters->ReceiveHashingSettings.HashInformation = Params->HashInformation;
}
if (!(Params->Flags & NDIS_RECEIVE_HASH_FLAG_HASH_KEY_UNCHANGED))
{
RSSParameters->ReceiveHashingSettings.HashSecretKeySize = Params->HashSecretKeySize;
NdisMoveMemory(RSSParameters->ReceiveHashingSettings.HashSecretKey,
(char*)Params + Params->HashSecretKeyOffset, Params->HashSecretKeySize);
*ParamsBytesRead += Params->HashSecretKeySize;
}
if(RSSParameters->RSSMode != PARANDIS_RSS_FULL)
{
ApplySettings(RSSParameters,
((Params->Flags & NDIS_RECEIVE_HASH_FLAG_ENABLE_HASH) && (Params->HashInformation != 0))
? PARANDIS_RSS_HASHING : PARANDIS_RSS_DISABLED,
&RSSParameters->ReceiveHashingSettings, NULL);
}
return NDIS_STATUS_SUCCESS;
}
typedef struct _tagHASH_CALC_SG_BUF_ENTRY
{
PCHAR chunkPtr;
ULONG chunkLen;
} HASH_CALC_SG_BUF_ENTRY, *PHASH_CALC_SG_BUF_ENTRY;
// Little Endian version ONLY
static
UINT32 ToeplitsHash(const PHASH_CALC_SG_BUF_ENTRY sgBuff, int sgEntriesNum, PCCHAR fullKey)
{
#define TOEPLITZ_MAX_BIT_NUM (7)
#define TOEPLITZ_BYTE_HAS_BIT(byte, bit) ((byte) & (1 << (TOEPLITZ_MAX_BIT_NUM - (bit))))
#define TOEPLITZ_BYTE_BIT_STATE(byte, bit) (((byte) >> (TOEPLITZ_MAX_BIT_NUM - (bit))) & 1)
UINT32 firstKeyWord, res = 0;
UINT byte, bit;
PHASH_CALC_SG_BUF_ENTRY sgEntry;
PCCHAR next_key_byte = fullKey + sizeof(firstKeyWord);
firstKeyWord = RtlUlongByteSwap(*(UINT32*)fullKey);
for(sgEntry = sgBuff; sgEntry < sgBuff + sgEntriesNum; ++sgEntry)
{
for (byte = 0; byte < sgEntry->chunkLen; ++byte)
{
for (bit = 0; bit <= TOEPLITZ_MAX_BIT_NUM; ++bit)
{
if (TOEPLITZ_BYTE_HAS_BIT(sgEntry->chunkPtr[byte], bit))
{
res ^= firstKeyWord;
}
firstKeyWord = (firstKeyWord << 1) | TOEPLITZ_BYTE_BIT_STATE(*next_key_byte, bit);
}
++next_key_byte;
}
}
return res;
#undef TOEPLITZ_BYTE_HAS_BIT
#undef TOEPLITZ_BYTE_BIT_STATE
#undef TOEPLITZ_MAX_BIT_NUM
}
static __inline
IPV6_ADDRESS* GetIP6SrcAddrForHash(
PVOID dataBuffer,
PNET_PACKET_INFO packetInfo,
ULONG hashTypes)
{
return ((hashTypes & (NDIS_HASH_TCP_IPV6_EX | NDIS_HASH_IPV6_EX)) && packetInfo->ip6HomeAddrOffset)
? (IPV6_ADDRESS*) RtlOffsetToPointer(dataBuffer, packetInfo->ip6HomeAddrOffset)
: (IPV6_ADDRESS*) RtlOffsetToPointer(dataBuffer, packetInfo->L2HdrLen + FIELD_OFFSET(IPv6Header, ip6_src_address));
}
static __inline
IPV6_ADDRESS* GetIP6DstAddrForHash(
PVOID dataBuffer,
PNET_PACKET_INFO packetInfo,
ULONG hashTypes)
{
return ((hashTypes & (NDIS_HASH_TCP_IPV6_EX | NDIS_HASH_IPV6_EX)) && packetInfo->ip6DestAddrOffset)
? (IPV6_ADDRESS*) RtlOffsetToPointer(dataBuffer, packetInfo->ip6DestAddrOffset)
: (IPV6_ADDRESS*) RtlOffsetToPointer(dataBuffer, packetInfo->L2HdrLen + FIELD_OFFSET(IPv6Header, ip6_dst_address));
}
static
VOID RSSCalcHash(
PARANDIS_RSS_PARAMS *RSSParameters,
PVOID dataBuffer,
PNET_PACKET_INFO packetInfo)
{
HASH_CALC_SG_BUF_ENTRY sgBuff[3];
ULONG hashTypes = NDIS_RSS_HASH_TYPE_FROM_HASH_INFO(RSSParameters->ActiveHashingSettings.HashInformation);
if(packetInfo->isIP4)
{
if(packetInfo->isTCP && (hashTypes & NDIS_HASH_TCP_IPV4))
{
IPv4Header *pIpHeader = (IPv4Header *) RtlOffsetToPointer(dataBuffer, packetInfo->L2HdrLen);
TCPHeader *pTCPHeader = (TCPHeader *) RtlOffsetToPointer(pIpHeader, packetInfo->L3HdrLen);
sgBuff[0].chunkPtr = RtlOffsetToPointer(pIpHeader, FIELD_OFFSET(IPv4Header, ip_src));
sgBuff[0].chunkLen = RTL_FIELD_SIZE(IPv4Header, ip_src) + RTL_FIELD_SIZE(IPv4Header, ip_dest);
sgBuff[1].chunkPtr = RtlOffsetToPointer(pTCPHeader, FIELD_OFFSET(TCPHeader, tcp_src));
sgBuff[1].chunkLen = RTL_FIELD_SIZE(TCPHeader, tcp_src) + RTL_FIELD_SIZE(TCPHeader, tcp_dest);
packetInfo->RSSHash.Value = ToeplitsHash(sgBuff, 2, &RSSParameters->ActiveHashingSettings.HashSecretKey[0]);
packetInfo->RSSHash.Type = NDIS_HASH_TCP_IPV4;
packetInfo->RSSHash.Function = NdisHashFunctionToeplitz;
return;
}
if(hashTypes & NDIS_HASH_IPV4)
{
sgBuff[0].chunkPtr = RtlOffsetToPointer(dataBuffer, packetInfo->L2HdrLen + FIELD_OFFSET(IPv4Header, ip_src));
sgBuff[0].chunkLen = RTL_FIELD_SIZE(IPv4Header, ip_src) + RTL_FIELD_SIZE(IPv4Header, ip_dest);
packetInfo->RSSHash.Value = ToeplitsHash(sgBuff, 1, RSSParameters->ActiveHashingSettings.HashSecretKey);
packetInfo->RSSHash.Type = NDIS_HASH_IPV4;
packetInfo->RSSHash.Function = NdisHashFunctionToeplitz;
return;
}
}
else if(packetInfo->isIP6)
{
if(packetInfo->isTCP)
{
if(hashTypes & (NDIS_HASH_TCP_IPV6 | NDIS_HASH_TCP_IPV6_EX))
{
IPv6Header *pIpHeader = (IPv6Header *) RtlOffsetToPointer(dataBuffer, packetInfo->L2HdrLen);
TCPHeader *pTCPHeader = (TCPHeader *) RtlOffsetToPointer(pIpHeader, packetInfo->L3HdrLen);
sgBuff[0].chunkPtr = (PCHAR) GetIP6SrcAddrForHash(dataBuffer, packetInfo, hashTypes);
sgBuff[0].chunkLen = RTL_FIELD_SIZE(IPv6Header, ip6_src_address);
sgBuff[1].chunkPtr = (PCHAR) GetIP6DstAddrForHash(dataBuffer, packetInfo, hashTypes);
sgBuff[1].chunkLen = RTL_FIELD_SIZE(IPv6Header, ip6_dst_address);
sgBuff[2].chunkPtr = RtlOffsetToPointer(pTCPHeader, FIELD_OFFSET(TCPHeader, tcp_src));
sgBuff[2].chunkLen = RTL_FIELD_SIZE(TCPHeader, tcp_src) + RTL_FIELD_SIZE(TCPHeader, tcp_dest);
packetInfo->RSSHash.Value = ToeplitsHash(sgBuff, 3, RSSParameters->ActiveHashingSettings.HashSecretKey);
packetInfo->RSSHash.Type = (hashTypes & NDIS_HASH_TCP_IPV6_EX) ? NDIS_HASH_TCP_IPV6_EX : NDIS_HASH_TCP_IPV6;
packetInfo->RSSHash.Function = NdisHashFunctionToeplitz;
return;
}
}
if(hashTypes & (NDIS_HASH_IPV6 | NDIS_HASH_IPV6_EX))
{
sgBuff[0].chunkPtr = (PCHAR) GetIP6SrcAddrForHash(dataBuffer, packetInfo, hashTypes);
sgBuff[0].chunkLen = RTL_FIELD_SIZE(IPv6Header, ip6_src_address);
sgBuff[1].chunkPtr = (PCHAR) GetIP6DstAddrForHash(dataBuffer, packetInfo, hashTypes);
sgBuff[1].chunkLen = RTL_FIELD_SIZE(IPv6Header, ip6_dst_address);
packetInfo->RSSHash.Value = ToeplitsHash(sgBuff, 2, RSSParameters->ActiveHashingSettings.HashSecretKey);
packetInfo->RSSHash.Type = (hashTypes & NDIS_HASH_IPV6_EX) ? NDIS_HASH_IPV6_EX : NDIS_HASH_IPV6;
packetInfo->RSSHash.Function = NdisHashFunctionToeplitz;
return;
}
if(hashTypes & NDIS_HASH_IPV6)
{
IPv6Header *pIpHeader = (IPv6Header *) RtlOffsetToPointer(dataBuffer, packetInfo->L2HdrLen);
sgBuff[0].chunkPtr = RtlOffsetToPointer(pIpHeader, FIELD_OFFSET(IPv6Header, ip6_src_address));
sgBuff[0].chunkLen = RTL_FIELD_SIZE(IPv6Header, ip6_src_address) + RTL_FIELD_SIZE(IPv6Header, ip6_dst_address);
packetInfo->RSSHash.Value = ToeplitsHash(sgBuff, 2, RSSParameters->ActiveHashingSettings.HashSecretKey);
packetInfo->RSSHash.Type = NDIS_HASH_IPV6;
packetInfo->RSSHash.Function = NdisHashFunctionToeplitz;
return;
}
}
packetInfo->RSSHash.Value = 0;
packetInfo->RSSHash.Type = 0;
packetInfo->RSSHash.Function = 0;
}
VOID ParaNdis6_RSSAnalyzeReceivedPacket(
PARANDIS_RSS_PARAMS *RSSParameters,
PVOID dataBuffer,
PNET_PACKET_INFO packetInfo)
{
NdisDprAcquireSpinLock(&RSSParameters->RSSSettingsLock);
if(RSSParameters->RSSMode != PARANDIS_RSS_DISABLED)
{
RSSCalcHash(RSSParameters, dataBuffer, packetInfo);
}
NdisDprReleaseSpinLock(&RSSParameters->RSSSettingsLock);
}
CCHAR ParaNdis6_RSSGetScalingDataForPacket(
PARANDIS_RSS_PARAMS *RSSParameters,
PNET_PACKET_INFO packetInfo,
PPROCESSOR_NUMBER targetProcessor)
{
CCHAR targetQueue;
NdisDprAcquireSpinLock(&RSSParameters->RSSSettingsLock);
if((RSSParameters->RSSMode != PARANDIS_RSS_FULL) || (packetInfo->RSSHash.Type == 0))
{
targetQueue = PARANDIS_RECEIVE_QUEUE_UNCLASSIFIED;
}
else
{
ULONG indirectionIndex = packetInfo->RSSHash.Value & RSSParameters->ActiveRSSScalingSettings.RSSHashMask;
*targetProcessor = RSSParameters->ActiveRSSScalingSettings.IndirectionTable[indirectionIndex];
targetQueue = RSSParameters->ActiveRSSScalingSettings.QueueIndirectionTable[indirectionIndex];
}
NdisDprReleaseSpinLock(&RSSParameters->RSSSettingsLock);
return targetQueue;
}
CCHAR ParaNdis6_RSSGetCurrentCpuReceiveQueue(PARANDIS_RSS_PARAMS *RSSParameters)
{
CCHAR res;
NdisDprAcquireSpinLock(&RSSParameters->RSSSettingsLock);
if(RSSParameters->RSSMode != PARANDIS_RSS_FULL)
{
res = PARANDIS_RECEIVE_QUEUE_UNCLASSIFIED;
}
else
{
res = FindReceiveQueueForCurrentCpu(&RSSParameters->ActiveRSSScalingSettings);
}
NdisDprReleaseSpinLock(&RSSParameters->RSSSettingsLock);
return res;
}
#endif