|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [PATCH 1/2] xennet: improve NBL batching receive path
On 17/09/2026 17:43, david ambu wrote:
> Raise NblBatchMax default to 32 (max 64). Split batches at
> EtherType boundaries and set NDIS_RECEIVE_FLAGS_SINGLE_ETHER_TYPE per
> batch. Fix __ReceiverPushPackets: move KeMemoryBarrier before Returned/
> Indicated reads, and return early when queue is empty.
>
> Signed-off-by: david ambu <david.preetham@xxxxxxxxxx>
> ---
> src/xennet.inf | 6 +++
> src/xennet/adapter.c | 13 +++++
> src/xennet/adapter.h | 8 ++++
> src/xennet/receiver.c | 108 +++++++++++++++++++++++++++++++-----------
> 4 files changed, 108 insertions(+), 27 deletions(-)
>
> diff --git a/src/xennet.inf b/src/xennet.inf
> index 55e11a2..79730e8 100644
> --- a/src/xennet.inf
> +++ b/src/xennet.inf
> @@ -186,6 +186,11 @@ HKR, Ndi\params\*NumRSSQueues,
> Default, 0, "8"
> HKR, Ndi\params\*NumRSSQueues, Min, 0, "1"
> HKR, Ndi\params\*NumRSSQueues, Max, 0, "8"
>
> +HKR, Ndi\Params\NblBatchMax,
> ParamDesc, 0, %NblBatchMax%
> +HKR, Ndi\Params\NblBatchMax, Type,
> 0, "int"
> +HKR, Ndi\Params\NblBatchMax,
> Default, 0, "32"
> +HKR, Ndi\Params\NblBatchMax, Min,
> 0, "1"
> +HKR, Ndi\Params\NblBatchMax, Max,
> 0, "64"
> [XenNet_Inst.Services]
> AddService=xennet,0x02,XenNet_Service,XenNet_EventLog
>
> @@ -248,6 +253,7 @@ Enabled="Enabled"
> Enabled-Rx="Rx Enabled"
> Enabled-Tx="Tx Enabled"
> Enabled-TxRx="Rx & Tx Enabled"
> +NblBatchMax="Max Receive Indicate NBLS"
>
> SERVICE_BOOT_START=0x0
> SERVICE_SYSTEM_START=0x1
> diff --git a/src/xennet/adapter.c b/src/xennet/adapter.c
> index f79c0c8..6e5a95a 100644
> --- a/src/xennet/adapter.c
> +++ b/src/xennet/adapter.c
> @@ -63,6 +63,7 @@ typedef struct _PROPERTIES {
> int lrov6;
> int rss;
> int numrssqueues;
> + int nblbatchmax;
> } PROPERTIES, *PPROPERTIES;
>
> typedef struct _XENNET_RSS {
> @@ -1480,6 +1481,17 @@ AdapterGetHandle(
> return Adapter->NdisAdapterHandle;
> }
>
> +ULONG
> +AdapterGetNblMaxBatchSize(
> + IN PXENNET_ADAPTER Adapter
> + )
> +{
> + ULONG val = (ULONG)Adapter->Properties.nblbatchmax;
> + if (val == 0 || val > NBL_BATCH_SIZE_MAX)
> + return NBL_BATCH_SIZE_DEFAULT;
> + return val;
> +}
> +
> PXENVIF_VIF_INTERFACE
> AdapterGetVifInterface(
> IN PXENNET_ADAPTER Adapter
> @@ -2939,6 +2951,7 @@ AdapterGetAdvancedSettings(
> READ_PROPERTY(Adapter->Properties.need_csum_value,
> L"NeedChecksumValue", 1, Handle);
> READ_PROPERTY(Adapter->Properties.rss, L"*RSS", 1, Handle);
> READ_PROPERTY(Adapter->Properties.numrssqueues, L"*NumRSSQueues", 8,
> Handle);
> + READ_PROPERTY(Adapter->Properties.nblbatchmax, L"NblBatchMax",
> NBL_BATCH_SIZE_DEFAULT, Handle);
>
> NdisCloseConfiguration(Handle);
>
> diff --git a/src/xennet/adapter.h b/src/xennet/adapter.h
> index 2ea0345..a54cb4d 100644
> --- a/src/xennet/adapter.h
> +++ b/src/xennet/adapter.h
> @@ -121,4 +121,12 @@ AdapterQueryInformation(
> IN PNDIS_OID_REQUEST Request
> );
>
> +#define NBL_BATCH_SIZE_DEFAULT 32
> +#define NBL_BATCH_SIZE_MAX 64
> +
> +extern ULONG
> +AdapterGetNblMaxBatchSize(
> + IN PXENNET_ADAPTER Adapter
> + );
> +
> #endif // _XENNET_ADAPTER_H_
> diff --git a/src/xennet/receiver.c b/src/xennet/receiver.c
> index b4cf4f0..c46e6a3 100644
> --- a/src/xennet/receiver.c
> +++ b/src/xennet/receiver.c
> @@ -34,6 +34,7 @@
> #include <procgrp.h>
> #include <tcpip.h>
> #include <xen.h>
> +#include <ethernet.h>
>
> #include "util.h"
> #include "receiver.h"
> @@ -64,6 +65,7 @@ struct _XENNET_RECEIVER {
>
> typedef struct _NET_BUFFER_LIST_RESERVED {
> PVOID Cookie;
> + USHORT EtherType;
> } NET_BUFFER_LIST_RESERVED, *PNET_BUFFER_LIST_RESERVED;
>
> C_ASSERT(sizeof (NET_BUFFER_LIST_RESERVED) <=
> RTL_FIELD_SIZE(NET_BUFFER_LIST, MiniportReserved));
> @@ -120,6 +122,7 @@ __ReceiverAllocateNetBufferList(
> IN PMDL Mdl,
> IN ULONG Offset,
> IN ULONG Length,
> + IN PXENVIF_PACKET_INFO Info,
> IN PVOID Cookie
> )
> {
> @@ -156,10 +159,25 @@ __ReceiverAllocateNetBufferList(
>
> if (NetBufferList != NULL) {
> PNET_BUFFER_LIST_RESERVED ListReserved;
> + USHORT EtherType = 0;
> +
> + if (Info->EthernetHeader.Length != 0) {
> + PUCHAR Buffer;
> + PETHERNET_HEADER EthernetHeader;
> +
> + Buffer = MmGetSystemAddressForMdlSafe(Mdl, NormalPagePriority |
> MdlMappingNoExecute);
> + if (Buffer != NULL) {
> + EthernetHeader = (PETHERNET_HEADER)(Buffer + Offset +
> Info->EthernetHeader.Offset);
> + EtherType = ETHERNET_HEADER_IS_TAGGED(EthernetHeader) ?
> + EthernetHeader->Tagged.TypeOrLength :
> + EthernetHeader->Untagged.TypeOrLength;
> + }
> + }
>
> ListReserved =
> (PNET_BUFFER_LIST_RESERVED)NET_BUFFER_LIST_MINIPORT_RESERVED(NetBufferList);
> ASSERT3P(ListReserved->Cookie, ==, NULL);
> ListReserved->Cookie = Cookie;
> + ListReserved->EtherType = EtherType;
> }
>
> return NetBufferList;
> @@ -178,6 +196,7 @@ __ReceiverReleaseNetBufferList(
> ListReserved =
> (PNET_BUFFER_LIST_RESERVED)NET_BUFFER_LIST_MINIPORT_RESERVED(NetBufferList);
> Cookie = ListReserved->Cookie;
> ListReserved->Cookie = NULL;
> + ListReserved->EtherType = 0;
>
> if (Cache)
> __ReceiverPutNetBufferList(Receiver, NetBufferList);
> @@ -240,12 +259,12 @@ __ReceiverReceivePacket(
> NDIS_TCP_IP_CHECKSUM_NET_BUFFER_LIST_INFO csumInfo;
>
> UNREFERENCED_PARAMETER(MaximumSegmentSize);
> - UNREFERENCED_PARAMETER(Info);
>
> NetBufferList = __ReceiverAllocateNetBufferList(Receiver,
> Mdl,
> Offset,
> Length,
> + Info,
> Cookie);
> if (NetBufferList == NULL)
> goto fail1;
> @@ -328,9 +347,11 @@ fail1:
> return NULL;
> }
>
> -static FORCEINLINE VOID __IndicateReceiveNetBufferLists(
> +
> +static FORCEINLINE VOID
> +__IndicateReceiveNetBufferLists(
> IN PXENNET_RECEIVER Receiver,
> - IN PNET_BUFFER_LIST NetBufferLists,
> + IN PNET_BUFFER_LIST Remaining,
> IN NDIS_PORT_NUMBER PortNumber,
> IN ULONG NumberOfNetBufferLists,
> IN ULONG ReceiveFlags
> @@ -339,39 +360,70 @@ static FORCEINLINE VOID __IndicateReceiveNetBufferLists(
> PXENNET_ADAPTER Adapter = Receiver->Adapter;
> NDIS_HANDLE MiniportAdapterHandle =
> AdapterGetHandle(Adapter);
> PXENVIF_VIF_INTERFACE VifInterface;
> - ULONG Count;
> -
> - VifInterface = AdapterGetVifInterface(Receiver->Adapter);
> + ULONG Count = 0;
> + ULONG NblMaxBatch = AdapterGetNblMaxBatchSize(Adapter);
> +
> + while (Remaining != NULL) {
> + PNET_BUFFER_LIST BatchTail = Remaining;
> + PNET_BUFFER_LIST NextNbl;
> + ULONG BatchCount = 1;
> + ULONG BatchFlags;
> + USHORT FirstEth;
> +
> + FirstEth = ((PNET_BUFFER_LIST_RESERVED)
> + NET_BUFFER_LIST_MINIPORT_RESERVED(Remaining))->EtherType;
> + NextNbl = NET_BUFFER_LIST_NEXT_NBL(BatchTail);
> +
> + while (NextNbl != NULL && BatchCount < NblMaxBatch) {
> + USHORT CurEth;
> + CurEth = ((PNET_BUFFER_LIST_RESERVED)
> + NET_BUFFER_LIST_MINIPORT_RESERVED(NextNbl))->EtherType;
> + if (CurEth != FirstEth)
> + break;
> + BatchTail = NextNbl;
> + NextNbl = NET_BUFFER_LIST_NEXT_NBL(BatchTail);
> + BatchCount++;
> + }
>
> - Count = 0;
> - while (NetBufferLists != NULL) {
> - PNET_BUFFER_LIST Next;
> + NET_BUFFER_LIST_NEXT_NBL(BatchTail) = NULL;
>
> - Next = NET_BUFFER_LIST_NEXT_NBL(NetBufferLists);
> - NET_BUFFER_LIST_NEXT_NBL(NetBufferLists) = NULL;
> + BatchFlags = ReceiveFlags;
> + if (FirstEth != 0)
> + BatchFlags |= NDIS_RECEIVE_FLAGS_SINGLE_ETHER_TYPE;
> + else
> + BatchFlags &= ~NDIS_RECEIVE_FLAGS_SINGLE_ETHER_TYPE;
>
> NdisMIndicateReceiveNetBufferLists(MiniportAdapterHandle,
> - NetBufferLists,
> + Remaining,
> PortNumber,
> - 1,
> - ReceiveFlags);
> + BatchCount,
> + BatchFlags);
>
> - if (ReceiveFlags & NDIS_RECEIVE_FLAGS_RESOURCES) {
> - PVOID Cookie;
> + if (BatchFlags & NDIS_RECEIVE_FLAGS_RESOURCES) {
> + PNET_BUFFER_LIST Current = Remaining;
>
> - Cookie = __ReceiverReleaseNetBufferList(Receiver,
> - NetBufferLists,
> - FALSE);
> + VifInterface = AdapterGetVifInterface(Receiver->Adapter);
>
> - XENVIF_VIF(ReceiverReturnPacket,
> - VifInterface,
> - Cookie);
> + while (Current != NULL) {
> + PNET_BUFFER_LIST Next = NET_BUFFER_LIST_NEXT_NBL(Current);
> + NET_BUFFER_LIST_NEXT_NBL(Current) = NULL;
>
> - (VOID) InterlockedIncrement(&Receiver->Returned);
> + PVOID Cookie = __ReceiverReleaseNetBufferList(Receiver,
> + Current,
> + FALSE);
> +
> + XENVIF_VIF(ReceiverReturnPacket,
> + VifInterface,
> + Cookie);
> +
> + Current = Next;
> + }
> +
> + (VOID)InterlockedAdd(&Receiver->Returned, BatchCount);
> }
>
> - Count++;
> - NetBufferLists = Next;
> + Count += BatchCount;
> + Remaining = NextNbl;
> }
> ASSERT3U(Count, ==, NumberOfNetBufferLists);
> }
> @@ -402,12 +454,14 @@ __ReceiverPushPackets(
>
> KeReleaseSpinLockFromDpcLevel(&Queue->Lock);
>
> - (VOID) InterlockedAdd(&Receiver->Indicated, Count);
> + if (Count == 0)
> + return;
>
> - Returned = Receiver->Returned;
> + (VOID) InterlockedAdd(&Receiver->Indicated, Count);
>
> KeMemoryBarrier();
>
> + Returned = Receiver->Returned;
> Indicated = Receiver->Indicated;
I wasn't sure about the purpose of the previous barriers so I went
digging. I've found that Receiver->Returned and Receiver->Indicated are
only ever added to, without a dependency between the two. So wouldn't
this be sufficient without any further barriers?
if (Count == 0)
return;
Indicated = InterlockedAdd(&Receiver->Indicated, Count);
Returned = Receiver->Returned;
>
> Flags = NDIS_RECEIVE_FLAGS_DISPATCH_LEVEL |
--
Ngoc Tu Dinh | Vates XCP-ng Developer
XCP-ng & Xen Orchestra - Vates solutions
web: https://vates.tech
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |