[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 |