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

[PATCH 1/2] xennet: improve NBL batching receive path


  • To: win-pv-devel@xxxxxxxxxxxxxxxxxxxx
  • From: david ambu <david.preetham@xxxxxxxxxx>
  • Date: Thu, 17 Sep 2026 16:41:29 +0100
  • Authentication-results: eu.smtp.expurgate.cloud; dkim=pass header.s=google header.d=citrix.com header.i="@citrix.com" header.h="Content-Transfer-Encoding:MIME-Version:References:In-Reply-To:Message-ID:Date:Subject:Cc:To:From"
  • Cc: david ambu <david.preetham@xxxxxxxxxx>
  • Delivery-date: Thu, 17 Sep 2026 15:43:52 +0000
  • List-id: Developer list for the Windows PV Drivers subproject <win-pv-devel.lists.xenproject.org>

  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;
 
     Flags = NDIS_RECEIVE_FLAGS_DISPATCH_LEVEL |
-- 
2.51.0.windows.1




 


Rackspace

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