[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [PATCH] xennet: improve NBL batching receive path


  • To: david ambu <david.preetham@xxxxxxxxxx>, win-pv-devel@xxxxxxxxxxxxxxxxxxxx
  • From: Mounah Honore Cesaire <cesaire.mounah@xxxxxxxxxx>
  • Date: Fri, 25 Sep 2026 16:36:06 +0200
  • Authentication-results: eu.smtp.expurgate.cloud; dkim=pass header.s=selector1 header.d=vates.tech header.i="@vates.tech" header.h="From:Subject:Date:Message-ID:To:MIME-Version:Content-Type:In-Reply-To:References:Feedback-ID"
  • Delivery-date: Fri, 25 Sep 2026 14:36:13 +0000
  • Feedback-id: default:8631fc262581453bbf619ec5b2062170:Sweego
  • List-id: Developer list for the Windows PV Drivers subproject <win-pv-devel.lists.xenproject.org>

On 9/25/26 4:02 PM, 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.
>
> In __ReceiverPushPackets, sample Returned before the InterlockedAdd
> so it is read prior to the implicit full memory barrier that
> InterlockedAdd provides. Use the return value of InterlockedAdd
> directly as Indicated and remove the now-redundant KeMemoryBarrier.
>
> Return early when queue is empty.
>
> Signed-off-by: david ambu <david.preetham@xxxxxxxxxx>
> Co-Authored-By: Claude Sonnet 4.6 <noreply@xxxxxxxxxxxxx>
> ---
>   src/xennet.inf        |   6 +++
>   src/xennet/adapter.c  |  13 +++++
>   src/xennet/adapter.h  |   8 +++
>   src/xennet/receiver.c | 110 ++++++++++++++++++++++++++++++------------
>   4 files changed, 107 insertions(+), 30 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..9df4192 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;
> +    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++;
> +        }
>   
> -    VifInterface = AdapterGetVifInterface(Receiver->Adapter);
> +        NET_BUFFER_LIST_NEXT_NBL(BatchTail) = NULL;
>   
> -    Count = 0;
> -    while (NetBufferLists != NULL) {
> -        PNET_BUFFER_LIST        Next;
> -
> -        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 (BatchFlags & NDIS_RECEIVE_FLAGS_RESOURCES) {
> +            PNET_BUFFER_LIST    Current = Remaining;
> +
> +            VifInterface = AdapterGetVifInterface(Receiver->Adapter);
> +
> +            while (Current != NULL) {
> +                PNET_BUFFER_LIST    Next = NET_BUFFER_LIST_NEXT_NBL(Current);
> +                NET_BUFFER_LIST_NEXT_NBL(Current) = NULL;
>   
> -        if (ReceiveFlags & NDIS_RECEIVE_FLAGS_RESOURCES) {
> -            PVOID   Cookie;
> +                PVOID Cookie = __ReceiverReleaseNetBufferList(Receiver,
> +                                                              Current,
> +                                                              FALSE);
>   
> -            Cookie = __ReceiverReleaseNetBufferList(Receiver,
> -                                                    NetBufferLists,
> -                                                    FALSE);
> +                XENVIF_VIF(ReceiverReturnPacket,
> +                           VifInterface,
> +                           Cookie);
>   
> -            XENVIF_VIF(ReceiverReturnPacket,
> -                       VifInterface,
> -                       Cookie);
> +                Current = Next;
> +            }
>   
> -            (VOID) InterlockedIncrement(&Receiver->Returned);
> +            (VOID)InterlockedAdd(&Receiver->Returned, BatchCount);
>           }
>   
> -        Count++;
> -        NetBufferLists = Next;
> +        Count += BatchCount;
> +        Remaining = NextNbl;
>       }
>       ASSERT3U(Count, ==, NumberOfNetBufferLists);
>   }
> @@ -402,13 +454,11 @@ __ReceiverPushPackets(
>   
>       KeReleaseSpinLockFromDpcLevel(&Queue->Lock);
>   
> -    (VOID) InterlockedAdd(&Receiver->Indicated, Count);
> +    if (Count == 0)
> +        return;
>   
>       Returned = Receiver->Returned;
> -
> -    KeMemoryBarrier();
> -
> -    Indicated = Receiver->Indicated;
> +    Indicated = InterlockedAdd(&Receiver->Indicated, Count);
>   
>       Flags = NDIS_RECEIVE_FLAGS_DISPATCH_LEVEL |
>               NDIS_RECEIVE_FLAGS_PERFECT_FILTERED;

Reviewed-by: Césaire Mounah <cesaire.mounah@xxxxxxxxxx>

-- 
Césaire Mounah | Vates Windows Guest Tools Engineer

XCP-ng & Xen Orchestra - Vates solutions

web: https://vates.tech



--
Césaire Mounah | Vates Windows Guest Tools Engineer

XCP-ng & Xen Orchestra - Vates solutions

web: https://vates.tech

 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.