|
[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
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |