]> xenbits.xensource.com Git - people/pauldu/xenvif.git/commitdiff
Add code to set receive side backfill size
authorPaul Durrant <paul.durrant@citrix.com>
Wed, 29 Jul 2015 15:19:15 +0000 (16:19 +0100)
committerPaul Durrant <paul.durrant@citrix.com>
Fri, 4 Dec 2015 13:29:23 +0000 (13:29 +0000)
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@citrix.com>
include/revision.h
include/vif_interface.h
src/xenvif/receiver.c
src/xenvif/receiver.h
src/xenvif/transmitter.c
src/xenvif/vif.c

index 9829ad6f9a9d4d242fa87c7a82f832ae18e4e08e..0184539f364212b0574f5de039eb712ceccf7b09 100644 (file)
@@ -42,8 +42,9 @@
 #define DEFINE_REVISION_TABLE                       \
     DEFINE_REVISION(0x08000002,  1,  2,  0,  0),    \
     DEFINE_REVISION(0x08000005,  1,  2,  1,  1),    \
+    DEFINE_REVISION(0x08000007,  1,  3,  1,  1)
 
-// Revisions 0x08000003 and 0x08000004 are already in use in the
-// master branch.
+// Revisions 0x08000003, 0x08000004 and 0x08000006 are already in use
+// in the master branch.
 
 #endif  // _REVISION_H
index d083fd156e084045c84a20a7bf5f0f87a59cdcb1..e5f8534bc0878497eae3106c06157f8d500e8b23 100644 (file)
@@ -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
index fa27a08fbe9dc6f322ea4459534f2254aaffc391..c6f64b5ab7e31af715abd8d66d9cb3b55740e0a5 100644 (file)
@@ -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:
@@ -1061,6 +1073,111 @@ fail1:
                                1);
 }
 
+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,
@@ -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);
@@ -2519,6 +2615,7 @@ __ReceiverRingTeardown(
     Ring->Dpcs = 0;
     RtlZeroMemory(&Ring->Dpc, sizeof (KDPC));
 
+    Ring->BackfillSize = 0;
     Ring->OffloadOptions.Value = 0;
 
     ThreadAlert(Ring->WatchdogThread);
@@ -2557,6 +2654,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,
@@ -3207,6 +3321,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,
index 87041010c0527991fb4197d979e3a572f95ed762..e4ab7a76e3c65244bece30445592ca69f051ef74 100644 (file)
@@ -94,6 +94,12 @@ ReceiverSetOffloadOptions(
     IN  XENVIF_VIF_OFFLOAD_OPTIONS  Options
     );
 
+extern VOID
+ReceiverSetBackfillSize(
+    IN  PXENVIF_RECEIVER    Receiver,
+    IN  ULONG               Size
+    );
+
 extern VOID
 ReceiverReturnPackets(
     IN  PXENVIF_RECEIVER    Receiver,
index 4b47fd878c6c24f9063ade5a8a823b20f7145a6a..1450e26075d92df10ee19491438ad5d5558ea518 100644 (file)
@@ -2775,15 +2775,11 @@ __TransmitterReturnPackets(
 
         break;
     }
-    case 2:
+    default:
         if (!IsListEmpty(List))
             VifTransmitterReturnPackets(VifContext, List);
 
         break;
-
-    default:
-        ASSERT(FALSE);
-        break;
     }
 }
 
index de39b027f72c27df344e513dac1e590506c1ebc8..b43695e0b6531486b67f071541e667977624e8e1 100644 (file)
@@ -486,6 +486,22 @@ VifReceiverSetOffloadOptions(
     ReleaseMrswLockShared(&Context->Lock);
 }
 
+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,
@@ -771,6 +787,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,
@@ -869,6 +911,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;