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

[win-pv-devel] [PATCH] Add code to set receive side backfill size



The NDIS header/data-split feature requires that the first data
MDL in a NET_BUFFER has sufficient headroom to take a copy of the
entire header MDL just in case something up the stack can't cope
with the split.
To this end NDIS specifies a 'backfill size' which must be
reserved. This patch implements support for that by copying and
adjusting the first data MDL if necessary.

Signed-off-by: Paul Durrant <paul.durrant@xxxxxxxxxx>
---
 include/revision.h       |   5 +-
 include/vif_interface.h  |  48 +++++++++++-
 src/xenvif/receiver.c    | 189 ++++++++++++++++++++++++++++++++++++++++-------
 src/xenvif/receiver.h    |   6 ++
 src/xenvif/transmitter.c |   6 +-
 src/xenvif/vif.c         |  59 +++++++++++++++
 6 files changed, 276 insertions(+), 37 deletions(-)

diff --git a/include/revision.h b/include/revision.h
index 6ae273c..e2decd0 100644
--- a/include/revision.h
+++ b/include/revision.h
@@ -37,7 +37,8 @@
 // V  - XENVIF_VIF_INTERFACE
 
 //                    REVISION   C   V
-#define DEFINE_REVISION_TABLE                                      \
-    DEFINE_REVISION(0x08000002,  1,  2)
+#define DEFINE_REVISION_TABLE               \
+    DEFINE_REVISION(0x08000002,  1,  2),    \
+    DEFINE_REVISION(0x08000003,  1,  3)
 
 #endif  // _REVISION_H
diff --git a/include/vif_interface.h b/include/vif_interface.h
index d083fd1..e5f8534 100644
--- a/include/vif_interface.h
+++ b/include/vif_interface.h
@@ -564,6 +564,19 @@ typedef VOID
     IN  XENVIF_VIF_OFFLOAD_OPTIONS  Options
     );
 
+/*! \typedef XENVIF_VIF_RECEIVER_SET_BACKFILL_SIZE
+    \brief Set the required receive backfill size (free space before
+    packet payload).
+
+    \param Interface The interface header
+    \param Size The required size
+*/
+typedef VOID
+(*XENVIF_VIF_RECEIVER_SET_BACKFILL_SIZE)(
+    IN  PINTERFACE  Interface,
+    IN  ULONG       Size
+    );
+
 /*! \typedef XENVIF_VIF_TRANSMITTER_QUERY_LARGE_PACKET_SIZE
     \brief Query the maximum size of packet containing a TCP large segment
     that can be handled by the transmit side
@@ -760,7 +773,6 @@ struct _XENVIF_VIF_INTERFACE_V1 {
     XENVIF_VIF_MAC_QUERY_FILTER_LEVEL               MacQueryFilterLevel;
 };
 
-
 /*! \struct _XENVIF_VIF_INTERFACE_V2
     \brief VIF interface version 2
     \ingroup interfaces
@@ -790,7 +802,37 @@ struct _XENVIF_VIF_INTERFACE_V2 {
     XENVIF_VIF_MAC_QUERY_FILTER_LEVEL               MacQueryFilterLevel;
 };
 
-typedef struct _XENVIF_VIF_INTERFACE_V2 XENVIF_VIF_INTERFACE, 
*PXENVIF_VIF_INTERFACE;
+/*! \struct _XENVIF_VIF_INTERFACE_V3
+    \brief VIF interface version 3
+    \ingroup interfaces
+*/
+struct _XENVIF_VIF_INTERFACE_V3 {
+    INTERFACE                                       Interface;
+    XENVIF_VIF_ACQUIRE                              Acquire;
+    XENVIF_VIF_RELEASE                              Release;
+    XENVIF_VIF_ENABLE                               Enable;
+    XENVIF_VIF_DISABLE                              Disable;
+    XENVIF_VIF_QUERY_STATISTIC                      QueryStatistic;
+    XENVIF_VIF_RECEIVER_RETURN_PACKETS              ReceiverReturnPackets;
+    XENVIF_VIF_RECEIVER_SET_OFFLOAD_OPTIONS         ReceiverSetOffloadOptions;
+    XENVIF_VIF_RECEIVER_SET_BACKFILL_SIZE           ReceiverSetBackfillSize;
+    XENVIF_VIF_RECEIVER_QUERY_RING_SIZE             ReceiverQueryRingSize;
+    XENVIF_VIF_TRANSMITTER_GET_PACKET_HEADERS       
TransmitterGetPacketHeaders;
+    XENVIF_VIF_TRANSMITTER_QUEUE_PACKETS_V2         TransmitterQueuePackets;
+    XENVIF_VIF_TRANSMITTER_QUERY_OFFLOAD_OPTIONS    
TransmitterQueryOffloadOptions;
+    XENVIF_VIF_TRANSMITTER_QUERY_LARGE_PACKET_SIZE  
TransmitterQueryLargePacketSize;
+    XENVIF_VIF_TRANSMITTER_QUERY_RING_SIZE          TransmitterQueryRingSize;
+    XENVIF_VIF_MAC_QUERY_STATE                      MacQueryState;
+    XENVIF_VIF_MAC_QUERY_MAXIMUM_FRAME_SIZE         MacQueryMaximumFrameSize;
+    XENVIF_VIF_MAC_QUERY_PERMANENT_ADDRESS          MacQueryPermanentAddress;
+    XENVIF_VIF_MAC_QUERY_CURRENT_ADDRESS            MacQueryCurrentAddress;
+    XENVIF_VIF_MAC_QUERY_MULTICAST_ADDRESSES        MacQueryMulticastAddresses;
+    XENVIF_VIF_MAC_SET_MULTICAST_ADDRESSES          MacSetMulticastAddresses;
+    XENVIF_VIF_MAC_SET_FILTER_LEVEL                 MacSetFilterLevel;
+    XENVIF_VIF_MAC_QUERY_FILTER_LEVEL               MacQueryFilterLevel;
+};
+
+typedef struct _XENVIF_VIF_INTERFACE_V3 XENVIF_VIF_INTERFACE, 
*PXENVIF_VIF_INTERFACE;
 
 /*! \def XENVIF_VIF
     \brief Macro at assist in method invocation
@@ -801,6 +843,6 @@ typedef struct _XENVIF_VIF_INTERFACE_V2 
XENVIF_VIF_INTERFACE, *PXENVIF_VIF_INTER
 #endif  // _WINDLL
 
 #define XENVIF_VIF_INTERFACE_VERSION_MIN    1
-#define XENVIF_VIF_INTERFACE_VERSION_MAX    2
+#define XENVIF_VIF_INTERFACE_VERSION_MAX    3
 
 #endif  // _XENVIF_INTERFACE_H
diff --git a/src/xenvif/receiver.c b/src/xenvif/receiver.c
index 20ce0de..abe617d 100644
--- a/src/xenvif/receiver.c
+++ b/src/xenvif/receiver.c
@@ -99,6 +99,7 @@ typedef struct _XENVIF_RECEIVER_RING {
     BOOLEAN                     Enabled;
     BOOLEAN                     Stopped;
     XENVIF_VIF_OFFLOAD_OPTIONS  OffloadOptions;
+    ULONG                       BackfillSize;
     PXENBUS_DEBUG_CALLBACK      DebugCallback;
     PXENVIF_THREAD              WatchdogThread;
     LIST_ENTRY                  PacketList;
@@ -732,6 +733,7 @@ __ReceiverRingBuildSegment(
     IN  PXENVIF_PACKET_PAYLOAD  Payload
     )
 {
+    PXENVIF_RECEIVER            Receiver;
     PXENVIF_PACKET_INFO         Info;
     PXENVIF_RECEIVER_PACKET     Segment;
     PMDL                        Mdl;
@@ -742,6 +744,8 @@ __ReceiverRingBuildSegment(
     ULONG                       Seq;
     NTSTATUS                    status;
 
+    Receiver = Ring->Receiver;
+
     Info = Packet->Info;
 
     InfoVa = MmGetSystemAddressForMdlSafe(&Packet->Mdl, NormalPagePriority);
@@ -843,7 +847,12 @@ __ReceiverRingBuildSegment(
         StartVa = MmGetSystemAddressForMdlSafe(Mdl, NormalPagePriority);
         ASSERT(StartVa != NULL);
 
-        Length = __min(SegmentSize - Segment->Length, PAGE_SIZE);
+        Mdl->ByteOffset = Ring->BackfillSize;
+
+        StartVa += Ring->BackfillSize;
+        Mdl->MappedSystemVa = StartVa;
+
+        Length = __min(SegmentSize - Segment->Length, PAGE_SIZE - 
Mdl->ByteOffset);
         ASSERT(Length != 0);
 
         (VOID) ReceiverRingPullup(Ring, StartVa, Payload, Length);
@@ -854,11 +863,14 @@ __ReceiverRingBuildSegment(
         if (Segment->Length == SegmentSize)
             break;
 
-        ASSERT3U(Mdl->ByteCount, ==, PAGE_SIZE);
+        ASSERT3U(Mdl->ByteCount, ==, PAGE_SIZE - Mdl->ByteOffset);
     }
 
     Segment->Length += Info->Length;
 
+    if (Receiver->AlwaysPullup != 0)
+        __ReceiverRingPullupPacket(Ring, Segment);
+
     return Segment;
 
 fail2:
@@ -1062,6 +1074,111 @@ fail1:
 }
 
 static VOID
+ReceiverRingProcessStandardPacket(
+    IN  PXENVIF_RECEIVER_RING   Ring,
+    IN  PXENVIF_RECEIVER_PACKET Packet,
+    OUT PLIST_ENTRY             List
+    )
+{
+    PXENVIF_RECEIVER            Receiver;
+    PXENVIF_FRONTEND            Frontend;
+    PXENVIF_MAC                 Mac;
+    PXENVIF_PACKET_INFO         Info;
+    XENVIF_PACKET_PAYLOAD       Payload;
+    ULONG                       MaximumFrameSize;
+    NTSTATUS                    status;
+
+    Receiver = Ring->Receiver;
+    Frontend = Receiver->Frontend;
+    Mac = FrontendGetMac(Frontend);
+
+    Info = Packet->Info;
+
+    Payload.Mdl = Packet->Mdl.Next;
+    Payload.Offset = 0;
+    Payload.Length = Packet->Length - Info->Length;
+
+    MacQueryMaximumFrameSize(Mac, &MaximumFrameSize);
+
+    status = STATUS_INVALID_PARAMETER;
+    if (Packet->Length > MaximumFrameSize)
+        goto fail1;
+
+    // Certain HCK tests (e.g. the NDISTest 2c_Priority test) are
+    // sufficiently brain-dead that they cannot cope with
+    // multi-fragment packets, or at least packets where headers are
+    // in different fragments. All these tests seem to use IPX packets
+    // and, in practice, little else uses LLC so pull up all LLC
+    // packets into a single fragment.
+    if (Info->LLCSnapHeader.Length != 0 || Receiver->AlwaysPullup != 0)
+        __ReceiverRingPullupPacket(Ring, Packet);
+    else if (Payload.Mdl != NULL && Payload.Mdl->ByteOffset < 
Ring->BackfillSize) {
+        PMDL    Mdl;
+        PUCHAR  StartVa;
+
+        // NDIS Header/Data split requires that the data MDL has a minimum 
length
+        // of headroom (i.e. ByteOffset) so that it can pre-pend the header to 
the data
+        // if something up the stack can't cope with the split.
+
+        Mdl = __ReceiverRingGetMdl(Ring, TRUE);
+
+        status = STATUS_NO_MEMORY;
+        if (Mdl == NULL)
+            goto fail2;
+
+        StartVa = MmGetSystemAddressForMdlSafe(Mdl, NormalPagePriority);
+        ASSERT(StartVa != NULL);
+
+        Mdl->ByteOffset = Ring->BackfillSize;
+        Mdl->ByteCount = __min(Payload.Mdl->ByteCount,
+                               PAGE_SIZE - Mdl->ByteOffset);
+
+        StartVa += Ring->BackfillSize;
+        Mdl->MappedSystemVa = StartVa;
+
+        (VOID) ReceiverRingPullup(Ring, StartVa, &Payload, Mdl->ByteCount);
+
+        if (Payload.Length != 0) {
+            ASSERT(Payload.Mdl != NULL);
+            Mdl->Next = Payload.Mdl;
+        }
+
+        Packet->Mdl.Next = Mdl;
+    }
+
+    ASSERT(IsZeroMemory(&Packet->ListEntry, sizeof (LIST_ENTRY)));
+    InsertTailList(List, &Packet->ListEntry);
+
+    return;
+
+fail2:
+fail1:
+    if (Payload.Length != 0) {
+        PMDL    Mdl = Payload.Mdl;
+
+        ASSERT(Mdl != NULL);
+
+        while (Mdl != NULL) {
+            PMDL    Next;
+
+            Next = Mdl->Next;
+            Mdl->Next = NULL;
+
+            __ReceiverRingPutMdl(Ring, Mdl, TRUE);
+
+            Mdl = Next;
+        }
+    }
+
+    Packet->Mdl.Next = NULL;
+    __ReceiverRingPutPacket(Ring, Packet, TRUE);
+
+    FrontendIncrementStatistic(Frontend,
+                               XENVIF_RECEIVER_PACKETS_DROPPED,
+                               1);
+}
+
+static VOID
 ReceiverRingProcessPacket(
     IN  PXENVIF_RECEIVER_RING   Ring,
     IN  PXENVIF_RECEIVER_PACKET Packet,
@@ -1143,8 +1260,7 @@ ReceiverRingProcessPacket(
     DestinationAddress = &EthernetHeader->DestinationAddress;
 
     status = STATUS_UNSUCCESSFUL;
-    if (!MacApplyFilters(FrontendGetMac(Frontend),
-                         DestinationAddress))
+    if (!MacApplyFilters(Mac, DestinationAddress))
         goto fail3;
 
     Type = GET_ETHERNET_ADDRESS_TYPE(DestinationAddress);
@@ -1182,33 +1298,13 @@ ReceiverRingProcessPacket(
         break;
     }
 
-    if (Packet->MaximumSegmentSize != 0) {
+    if (Packet->MaximumSegmentSize != 0)
         ReceiverRingProcessLargePacket(Ring, Packet, List);
-    } else {
-        ULONG   MaximumFrameSize;
-
-        MacQueryMaximumFrameSize(Mac, &MaximumFrameSize);
-
-        if (Packet->Length > MaximumFrameSize)
-            goto fail4;
-        
-        // Certain HCK tests (e.g. the NDISTest 2c_Priority test) are
-        // sufficiently brain-dead that they cannot cope with
-        // multi-fragment packets, or at least packets where headers are
-        // in different fragments. All these tests seem to use IPX packets
-        // and, in practice, little else uses LLC so pull up all LLC
-        // packets into a single fragment.
-        if (Info->LLCSnapHeader.Length != 0 ||
-            Receiver->AlwaysPullup != 0)
-            __ReceiverRingPullupPacket(Ring, Packet);
-
-        ASSERT(IsZeroMemory(&Packet->ListEntry, sizeof (LIST_ENTRY)));
-        InsertTailList(List, &Packet->ListEntry);
-    }
+    else
+        ReceiverRingProcessStandardPacket(Ring, Packet, List);
 
     return;
 
-fail4:
 fail3:
     Packet->Mdl.Next = NULL;
     __ReceiverRingPutPacket(Ring, Packet, TRUE);
@@ -2510,6 +2606,7 @@ __ReceiverRingTeardown(
     Ring->Dpcs = 0;
     RtlZeroMemory(&Ring->Dpc, sizeof (KDPC));
 
+    Ring->BackfillSize = 0;
     Ring->OffloadOptions.Value = 0;
 
     ThreadAlert(Ring->WatchdogThread);
@@ -2558,6 +2655,23 @@ __ReceiverRingSetOffloadOptions(
     KeLowerIrql(Irql);
 }
 
+static FORCEINLINE VOID
+__ReceiverRingSetBackfillSize(
+    IN  PXENVIF_RECEIVER_RING   Ring,
+    IN  ULONG                   Size
+    )
+{
+    KIRQL                       Irql;
+
+    KeRaiseIrql(DISPATCH_LEVEL, &Irql);
+
+    __ReceiverRingAcquireLock(Ring);
+    Ring->BackfillSize = Size;
+    __ReceiverRingReleaseLock(Ring);
+
+    KeLowerIrql(Irql);
+}
+
 static VOID
 ReceiverDebugCallback(
     IN  PVOID           Argument,
@@ -3209,6 +3323,27 @@ ReceiverSetOffloadOptions(
 }
 
 VOID
+ReceiverSetBackfillSize(
+    IN  PXENVIF_RECEIVER    Receiver,
+    IN  ULONG               Size
+    )
+{
+    LONG                    Index;
+
+    ASSERT3U(Size, <, PAGE_SIZE);
+
+    for (Index = 0; Index < Receiver->MaxQueues; ++Index) {
+        PXENVIF_RECEIVER_RING   Ring;
+
+        Ring = Receiver->Ring[Index];
+        if (Ring == NULL)
+            break;
+
+        __ReceiverRingSetBackfillSize(Ring, Size);
+    }
+}
+
+VOID
 ReceiverQueryRingSize(
     IN  PXENVIF_RECEIVER    Receiver,
     OUT PULONG              Size
diff --git a/src/xenvif/receiver.h b/src/xenvif/receiver.h
index 8704101..e4ab7a7 100644
--- a/src/xenvif/receiver.h
+++ b/src/xenvif/receiver.h
@@ -95,6 +95,12 @@ ReceiverSetOffloadOptions(
     );
 
 extern VOID
+ReceiverSetBackfillSize(
+    IN  PXENVIF_RECEIVER    Receiver,
+    IN  ULONG               Size
+    );
+
+extern VOID
 ReceiverReturnPackets(
     IN  PXENVIF_RECEIVER    Receiver,
     IN  PLIST_ENTRY         List
diff --git a/src/xenvif/transmitter.c b/src/xenvif/transmitter.c
index 2d8f613..8bf0c2c 100644
--- a/src/xenvif/transmitter.c
+++ b/src/xenvif/transmitter.c
@@ -2775,15 +2775,11 @@ __TransmitterReturnPackets(
 
         break;
     }
-    case 2:
+    default:
         if (!IsListEmpty(List))
             VifTransmitterReturnPackets(VifContext, List);
 
         break;
-
-    default:
-        ASSERT(FALSE);
-        break;
     }
 }
 
diff --git a/src/xenvif/vif.c b/src/xenvif/vif.c
index b2bbf05..02d1d11 100644
--- a/src/xenvif/vif.c
+++ b/src/xenvif/vif.c
@@ -408,6 +408,22 @@ VifReceiverSetOffloadOptions(
 }
 
 static VOID
+VifReceiverSetBackfillSize(
+    IN  PINTERFACE      Interface,
+    IN  ULONG           Size
+    )
+{
+    PXENVIF_VIF_CONTEXT Context = Interface->Context;
+
+    AcquireMrswLockShared(&Context->Lock);
+
+    ReceiverSetBackfillSize(FrontendGetReceiver(Context->Frontend),
+                            Size);
+
+    ReleaseMrswLockShared(&Context->Lock);
+}
+
+static VOID
 VifMacQueryState(
     IN  PINTERFACE                  Interface,
     OUT PNET_IF_MEDIA_CONNECT_STATE MediaConnectState OPTIONAL,
@@ -747,6 +763,32 @@ static struct _XENVIF_VIF_INTERFACE_V2 
VifInterfaceVersion2 = {
     VifMacQueryFilterLevel
 };
 
+static struct _XENVIF_VIF_INTERFACE_V3 VifInterfaceVersion3 = {
+    { sizeof (struct _XENVIF_VIF_INTERFACE_V3), 3, NULL, NULL, NULL },
+    VifAcquire,
+    VifRelease,
+    VifEnable,
+    VifDisable,
+    VifQueryStatistic,
+    VifReceiverReturnPackets,
+    VifReceiverSetOffloadOptions,
+    VifReceiverSetBackfillSize,
+    VifReceiverQueryRingSize,
+    VifTransmitterGetPacketHeaders,
+    VifTransmitterQueuePackets,
+    VifTransmitterQueryOffloadOptions,
+    VifTransmitterQueryLargePacketSize,
+    VifTransmitterQueryRingSize,
+    VifMacQueryState,
+    VifMacQueryMaximumFrameSize,
+    VifMacQueryPermanentAddress,
+    VifMacQueryCurrentAddress,
+    VifMacQueryMulticastAddresses,
+    VifMacSetMulticastAddresses,
+    VifMacSetFilterLevel,
+    VifMacQueryFilterLevel
+};
+
 NTSTATUS
 VifInitialize(
     IN  PXENVIF_PDO         Pdo,
@@ -845,6 +887,23 @@ VifGetInterface(
         status = STATUS_SUCCESS;
         break;
     }
+    case 3: {
+        struct _XENVIF_VIF_INTERFACE_V3 *VifInterface;
+
+        VifInterface = (struct _XENVIF_VIF_INTERFACE_V3 *)Interface;
+
+        status = STATUS_BUFFER_OVERFLOW;
+        if (Size < sizeof (struct _XENVIF_VIF_INTERFACE_V3))
+            break;
+
+        *VifInterface = VifInterfaceVersion3;
+
+        ASSERT3U(Interface->Version, ==, Version);
+        Interface->Context = Context;
+
+        status = STATUS_SUCCESS;
+        break;
+    }
     default:
         status = STATUS_NOT_SUPPORTED;
         break;
-- 
2.1.1


_______________________________________________
win-pv-devel mailing list
win-pv-devel@xxxxxxxxxxxxxxxxxxxx
http://lists.xenproject.org/cgi-bin/mailman/listinfo/win-pv-devel


 


Rackspace

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