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

[PATCH] xennet: improve NBL batching receive path


  • To: win-pv-devel@xxxxxxxxxxxxxxxxxxxx
  • From: david ambu <david.preetham@xxxxxxxxxx>
  • Date: Fri, 25 Sep 2026 14:57:22 +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>, "Claude Sonnet 4.6" <noreply@xxxxxxxxxxxxx>
  • Delivery-date: Fri, 25 Sep 2026 14:02:25 +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.

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




 


Rackspace

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