From 8a724e8d7175609c3a56d2243e53854962f38a0f Mon Sep 17 00:00:00 2001 From: "Michael Friesen (NETWORKING)" <3517159+mtfriesen@users.noreply.github.com> Date: Wed, 11 Dec 2024 13:42:55 -0500 Subject: [PATCH] wip/sync --- published/external/xdp/framechecksum.h | 15 --- src/xdp/tx.c | 105 ++++++++++++------ src/xdp/tx.h | 1 + src/xdp/xsk.c | 145 ++++++++++++------------- src/xdplwf/precomp.h | 4 + src/xdplwf/recv.c | 26 ----- src/xdplwf/send.c | 96 ++++++---------- 7 files changed, 186 insertions(+), 206 deletions(-) diff --git a/published/external/xdp/framechecksum.h b/published/external/xdp/framechecksum.h index b593f2b8..2148686e 100644 --- a/published/external/xdp/framechecksum.h +++ b/published/external/xdp/framechecksum.h @@ -38,19 +38,4 @@ C_ASSERT(sizeof(XDP_FRAME_CHECKSUM) == 1); #pragma warning(pop) -#define XDP_FRAME_EXTENSION_CHECKSUM_NAME L"ms_frame_checksum" -#define XDP_FRAME_EXTENSION_CHECKSUM_VERSION_1 1U - -#include - -inline -XDP_FRAME_CHECKSUM * -XdpGetChecksumExtension( - _In_ XDP_FRAME *Frame, - _In_ XDP_EXTENSION *Extension - ) -{ - return (XDP_FRAME_CHECKSUM *)XdpGetExtensionData(Frame, Extension); -} - EXTERN_C_END diff --git a/src/xdp/tx.c b/src/xdp/tx.c index 75078875..babd5a13 100644 --- a/src/xdp/tx.c +++ b/src/xdp/tx.c @@ -747,8 +747,6 @@ XdpTxQueueCreate( XDP_TX_QUEUE_KEY Key; XDP_TX_QUEUE *TxQueue = NULL; NTSTATUS Status; - UINT32 BufferSize, FrameSize, FrameOffset, FrameCount, TxCompletionSize; - UINT8 BufferAlignment, FrameAlignment, TxCompletionAlignment; XDP_EXTENSION_INFO ExtensionInfo; DECLARE_UNICODE_STRING_SIZE( Name, ARRAYSIZE("if_" MAXUINT32_STR "_queue_" MAXUINT32_STR "_rx")); @@ -881,6 +879,63 @@ XdpTxQueueCreate( TxQueue->FrameExtensionSet, XDP_TX_FRAME_COMPLETION_CONTEXT_EXTENSION_NAME); } + Status = + XdpIfOpenInterfaceOffloadHandle( + XdpIfGetIfSetHandle(TxQueue->Binding), &TxQueue->Key.HookId, + &TxQueue->InterfaceOffloadHandle); + if (!NT_SUCCESS(Status)) { + goto Exit; + } + + *NewTxQueue = TxQueue; + Status = STATUS_SUCCESS; + +Exit: + + TraceInfo( + TRACE_CORE, + "TxQueue=%p Hook={%!HOOK_LAYER!, %!HOOK_DIR!, %!HOOK_SUBLAYER!} Status=%!STATUS!", + TxQueue, HookId->Layer, HookId->Direction, HookId->SubLayer, Status); + + if (!NT_SUCCESS(Status)) { + if (TxQueue != NULL) { + XdpTxQueueDereference(TxQueue); + } + } + + return Status; +} + +static +VOID +XdpTxQueueDeleteRings( + _In_ XDP_TX_QUEUE *TxQueue + ) +{ + ASSERT(TxQueue->State == XdpTxQueueStateCreated || TxQueue->State == XdpTxQueueStateDeleted); + + if (TxQueue->CompletionRing != NULL) { + XdpRingFreeRing(TxQueue->CompletionRing); + } + if (TxQueue->FrameRing != NULL) { + XdpRingFreeRing(TxQueue->FrameRing); + } +} + +static +NTSTATUS +XdpTxQueueActivate( + _In_ XDP_TX_QUEUE *TxQueue + ) +{ + NTSTATUS Status; + UINT32 BufferSize, FrameSize, FrameOffset, FrameCount, TxCompletionSize; + UINT8 BufferAlignment, FrameAlignment, TxCompletionAlignment; + + TraceEnter(TRACE_CORE, "TxQueue=%p", TxQueue); + + ASSERT(TxQueue->State == XdpTxQueueStateCreated); + Status = XdpExtensionSetAssignLayout( TxQueue->BufferExtensionSet, sizeof(XDP_BUFFER), __alignof(XDP_BUFFER), @@ -949,29 +1004,28 @@ XdpTxQueueCreate( } Status = - XdpIfOpenInterfaceOffloadHandle( - XdpIfGetIfSetHandle(TxQueue->Binding), &TxQueue->Key.HookId, - &TxQueue->InterfaceOffloadHandle); + XdpIfActivateTxQueue( + TxQueue->Binding, TxQueue->InterfaceTxQueue, + (XDP_TX_QUEUE_HANDLE)&TxQueue->Dispatch, + (XDP_TX_QUEUE_CONFIG_ACTIVATE)&TxQueue->ConfigActivate); if (!NT_SUCCESS(Status)) { + TraceError( + TRACE_CORE, "TxQueue=%p XdpIfActivateTxQueue failed Status=%!STATUS!", + TxQueue, Status); goto Exit; } - *NewTxQueue = TxQueue; - Status = STATUS_SUCCESS; + TxQueue->State = XdpTxQueueStateActive; + TraceInfo(TRACE_CORE, "TxQueue=%p Activated", TxQueue); Exit: - TraceInfo( - TRACE_CORE, - "TxQueue=%p Hook={%!HOOK_LAYER!, %!HOOK_DIR!, %!HOOK_SUBLAYER!} Status=%!STATUS!", - TxQueue, HookId->Layer, HookId->Direction, HookId->SubLayer, Status); - if (!NT_SUCCESS(Status)) { - if (TxQueue != NULL) { - XdpTxQueueDereference(TxQueue); - } + XdpTxQueueDeleteRings(TxQueue); } + TraceExitStatus(TRACE_CORE); + return Status; } @@ -1112,21 +1166,15 @@ XdpTxQueueAddDatapathClient( UNREFERENCED_PARAMETER(TxClientType); if (TxQueue->State == XdpTxQueueStateCreated) { - Status = - XdpIfActivateTxQueue( - TxQueue->Binding, TxQueue->InterfaceTxQueue, - (XDP_TX_QUEUE_HANDLE)&TxQueue->Dispatch, - (XDP_TX_QUEUE_CONFIG_ACTIVATE)&TxQueue->ConfigActivate); + Status = XdpTxQueueActivate(TxQueue); + if (!NT_SUCCESS(Status)) { - TraceError( - TRACE_CORE, "TxQueue=%p XdpIfActivateTxQueue failed Status=%!STATUS!", - TxQueue, Status); goto Exit; } - - TxQueue->State = XdpTxQueueStateActive; } + TxClientEntry->NotifyRoutine(TxClientEntry, XDP_TX_QUEUE_NOTIFICATION_ATTACH); + SyncParams.TxQueue = TxQueue; SyncParams.TxClientEntry = TxClientEntry; XdpTxQueueSync(TxQueue, XdpTxQueueSyncAddDatapathClient, &SyncParams); @@ -1273,12 +1321,7 @@ XdpTxQueueDelete( TxQueue->State = XdpTxQueueStateDeleted; - if (TxQueue->CompletionRing != NULL) { - XdpRingFreeRing(TxQueue->CompletionRing); - } - if (TxQueue->FrameRing != NULL) { - XdpRingFreeRing(TxQueue->FrameRing); - } + XdpTxQueueDeleteRings(TxQueue); if (TxQueue->TxFrameCompletionExtensionSet != NULL) { XdpExtensionSetCleanup(TxQueue->TxFrameCompletionExtensionSet); } diff --git a/src/xdp/tx.h b/src/xdp/tx.h index 21eac90f..c8475f96 100644 --- a/src/xdp/tx.h +++ b/src/xdp/tx.h @@ -41,6 +41,7 @@ XdpTxQueueDereference( typedef struct _XDP_TX_QUEUE_NOTIFY_ENTRY XDP_TX_QUEUE_NOTIFICATION_ENTRY; typedef enum _XDP_TX_QUEUE_NOTIFICATION_TYPE { + XDP_TX_QUEUE_NOTIFICATION_ATTACH, XDP_TX_QUEUE_NOTIFICATION_DETACH, } XDP_TX_QUEUE_NOTIFICATION_TYPE; diff --git a/src/xdp/xsk.c b/src/xdp/xsk.c index 6fb1bcca..584ccde3 100644 --- a/src/xdp/xsk.c +++ b/src/xdp/xsk.c @@ -2140,28 +2140,80 @@ XskNotifyTxQueue( XSK *Xsk = CONTAINING_RECORD(NotificationEntry, XSK, Tx.Xdp.QueueNotificationEntry); KIRQL OldIrql; - if (NotificationType != XDP_TX_QUEUE_NOTIFICATION_DETACH) { - return; - } + if (NotificationType == XDP_TX_QUEUE_NOTIFICATION_ATTACH) { + XDP_TX_QUEUE_CONFIG_ACTIVATE Config = XdpTxQueueGetConfig(Xsk->Tx.Xdp.Queue);; + XDP_EXTENSION_INFO ExtensionInfo; - // - // Set the state to detached, except when socket closure has raced this - // detach event. - // - KeAcquireSpinLock(&Xsk->Lock, &OldIrql); - if (Xsk->State != XskClosing) { - ASSERT(Xsk->State >= XskBinding && Xsk->State <= XskActive); - Xsk->State = XskDetached; - } - KeReleaseSpinLock(&Xsk->Lock, OldIrql); + ASSERT(Xsk->State >= XskActivating); - // - // This detach event is executing in the context of XDP binding work queue - // processing on the TX queue, so it is synchronized with other detach - // instances that also utilize the XDP binding work queue (detach during - // bind failure and detach during socket closure). - // - XskDetachTxIf(Xsk); + Xsk->Tx.Xdp.Flags.OutOfOrderCompletion = XdpTxQueueIsOutOfOrderCompletionEnabled(Config); + Xsk->Tx.Xdp.Flags.CompletionContext = XdpTxQueueIsTxCompletionContextEnabled(Config); + + Xsk->Tx.Xdp.FrameRing = XdpTxQueueGetFrameRing(Config); + + if (Xsk->Tx.Xdp.Flags.CompletionContext) { + XdpInitializeExtensionInfo( + &ExtensionInfo, XDP_TX_FRAME_COMPLETION_CONTEXT_EXTENSION_NAME, + XDP_TX_FRAME_COMPLETION_CONTEXT_EXTENSION_VERSION_1, + XDP_EXTENSION_TYPE_FRAME); + XdpTxQueueGetExtension(Config, &ExtensionInfo, &Xsk->Tx.Xdp.FrameTxCompletionExtension); + } + + if (Xsk->Tx.Xdp.Flags.OutOfOrderCompletion) { + Xsk->Tx.Xdp.CompletionRing = XdpTxQueueGetCompletionRing(Config); + + if (Xsk->Tx.Xdp.Flags.CompletionContext) { + XdpInitializeExtensionInfo( + &ExtensionInfo, XDP_TX_FRAME_COMPLETION_CONTEXT_EXTENSION_NAME, + XDP_TX_FRAME_COMPLETION_CONTEXT_EXTENSION_VERSION_1, + XDP_EXTENSION_TYPE_TX_FRAME_COMPLETION); + XdpTxQueueGetExtension(Config, &ExtensionInfo, &Xsk->Tx.Xdp.TxCompletionExtension); + } + } + + Xsk->Tx.Xdp.Flags.VirtualAddressExt = XdpTxQueueIsVirtualAddressEnabled(Config); + if (Xsk->Tx.Xdp.Flags.VirtualAddressExt) { + XdpInitializeExtensionInfo( + &ExtensionInfo, XDP_BUFFER_EXTENSION_VIRTUAL_ADDRESS_NAME, + XDP_BUFFER_EXTENSION_VIRTUAL_ADDRESS_VERSION_1, XDP_EXTENSION_TYPE_BUFFER); + XdpTxQueueGetExtension(Config, &ExtensionInfo, &Xsk->Tx.Xdp.VaExtension); + } + + Xsk->Tx.Xdp.Flags.LogicalAddressExt = XdpTxQueueIsLogicalAddressEnabled(Config); + if (Xsk->Tx.Xdp.Flags.LogicalAddressExt) { + XdpInitializeExtensionInfo( + &ExtensionInfo, XDP_BUFFER_EXTENSION_LOGICAL_ADDRESS_NAME, + XDP_BUFFER_EXTENSION_LOGICAL_ADDRESS_VERSION_1, XDP_EXTENSION_TYPE_BUFFER); + XdpTxQueueGetExtension(Config, &ExtensionInfo, &Xsk->Tx.Xdp.LaExtension); + } + + Xsk->Tx.Xdp.Flags.MdlExt = XdpTxQueueIsMdlEnabled(Config); + if (Xsk->Tx.Xdp.Flags.MdlExt) { + XdpInitializeExtensionInfo( + &ExtensionInfo, XDP_BUFFER_EXTENSION_MDL_NAME, + XDP_BUFFER_EXTENSION_MDL_VERSION_1, XDP_EXTENSION_TYPE_BUFFER); + XdpTxQueueGetExtension(Config, &ExtensionInfo, &Xsk->Tx.Xdp.MdlExtension); + } + } else if (NotificationType == XDP_TX_QUEUE_NOTIFICATION_DETACH) { + // + // Set the state to detached, except when socket closure has raced this + // detach event. + // + KeAcquireSpinLock(&Xsk->Lock, &OldIrql); + if (Xsk->State != XskClosing) { + ASSERT(Xsk->State >= XskBinding && Xsk->State <= XskActive); + Xsk->State = XskDetached; + } + KeReleaseSpinLock(&Xsk->Lock, OldIrql); + + // + // This detach event is executing in the context of XDP binding work queue + // processing on the TX queue, so it is synchronized with other detach + // instances that also utilize the XDP binding work queue (detach during + // bind failure and detach during socket closure). + // + XskDetachTxIf(Xsk); + } } static @@ -2268,9 +2320,7 @@ XskBindTxIf( { XSK_BINDING_WORKITEM *WorkItem = (XSK_BINDING_WORKITEM *)Item; XSK *Xsk = WorkItem->Xsk; - XDP_TX_QUEUE_CONFIG_ACTIVATE Config; const XDP_TX_CAPABILITIES *InterfaceCapabilities; - XDP_EXTENSION_INFO ExtensionInfo; NTSTATUS Status; TraceEnter(TRACE_XSK, "Xsk=%p", Xsk); @@ -2292,57 +2342,6 @@ XskBindTxIf( Xsk->Tx.Xdp.MaxBufferLength = InterfaceCapabilities->MaximumBufferSize; Xsk->Tx.Xdp.MaxFrameLength = InterfaceCapabilities->MaximumFrameSize; - Config = XdpTxQueueGetConfig(Xsk->Tx.Xdp.Queue); - - Xsk->Tx.Xdp.Flags.OutOfOrderCompletion = XdpTxQueueIsOutOfOrderCompletionEnabled(Config); - Xsk->Tx.Xdp.Flags.CompletionContext = XdpTxQueueIsTxCompletionContextEnabled(Config); - - Xsk->Tx.Xdp.FrameRing = XdpTxQueueGetFrameRing(Config); - - if (Xsk->Tx.Xdp.Flags.CompletionContext) { - XdpInitializeExtensionInfo( - &ExtensionInfo, XDP_TX_FRAME_COMPLETION_CONTEXT_EXTENSION_NAME, - XDP_TX_FRAME_COMPLETION_CONTEXT_EXTENSION_VERSION_1, - XDP_EXTENSION_TYPE_FRAME); - XdpTxQueueGetExtension(Config, &ExtensionInfo, &Xsk->Tx.Xdp.FrameTxCompletionExtension); - } - - if (Xsk->Tx.Xdp.Flags.OutOfOrderCompletion) { - Xsk->Tx.Xdp.CompletionRing = XdpTxQueueGetCompletionRing(Config); - - if (Xsk->Tx.Xdp.Flags.CompletionContext) { - XdpInitializeExtensionInfo( - &ExtensionInfo, XDP_TX_FRAME_COMPLETION_CONTEXT_EXTENSION_NAME, - XDP_TX_FRAME_COMPLETION_CONTEXT_EXTENSION_VERSION_1, - XDP_EXTENSION_TYPE_TX_FRAME_COMPLETION); - XdpTxQueueGetExtension(Config, &ExtensionInfo, &Xsk->Tx.Xdp.TxCompletionExtension); - } - } - - Xsk->Tx.Xdp.Flags.VirtualAddressExt = XdpTxQueueIsVirtualAddressEnabled(Config); - if (Xsk->Tx.Xdp.Flags.VirtualAddressExt) { - XdpInitializeExtensionInfo( - &ExtensionInfo, XDP_BUFFER_EXTENSION_VIRTUAL_ADDRESS_NAME, - XDP_BUFFER_EXTENSION_VIRTUAL_ADDRESS_VERSION_1, XDP_EXTENSION_TYPE_BUFFER); - XdpTxQueueGetExtension(Config, &ExtensionInfo, &Xsk->Tx.Xdp.VaExtension); - } - - Xsk->Tx.Xdp.Flags.LogicalAddressExt = XdpTxQueueIsLogicalAddressEnabled(Config); - if (Xsk->Tx.Xdp.Flags.LogicalAddressExt) { - XdpInitializeExtensionInfo( - &ExtensionInfo, XDP_BUFFER_EXTENSION_LOGICAL_ADDRESS_NAME, - XDP_BUFFER_EXTENSION_LOGICAL_ADDRESS_VERSION_1, XDP_EXTENSION_TYPE_BUFFER); - XdpTxQueueGetExtension(Config, &ExtensionInfo, &Xsk->Tx.Xdp.LaExtension); - } - - Xsk->Tx.Xdp.Flags.MdlExt = XdpTxQueueIsMdlEnabled(Config); - if (Xsk->Tx.Xdp.Flags.MdlExt) { - XdpInitializeExtensionInfo( - &ExtensionInfo, XDP_BUFFER_EXTENSION_MDL_NAME, - XDP_BUFFER_EXTENSION_MDL_VERSION_1, XDP_EXTENSION_TYPE_BUFFER); - XdpTxQueueGetExtension(Config, &ExtensionInfo, &Xsk->Tx.Xdp.MdlExtension); - } - Status = STATUS_SUCCESS; Exit: diff --git a/src/xdplwf/precomp.h b/src/xdplwf/precomp.h index 00498662..ba99225c 100644 --- a/src/xdplwf/precomp.h +++ b/src/xdplwf/precomp.h @@ -29,8 +29,12 @@ #include #include #include +#include +#include #include #include +#include +#include #include #include #include diff --git a/src/xdplwf/recv.c b/src/xdplwf/recv.c index 6cf69281..cf842573 100644 --- a/src/xdplwf/recv.c +++ b/src/xdplwf/recv.c @@ -1397,9 +1397,6 @@ XdpGenericReceivePreInspectNbs( FrameRingReservedCount = CanPend ? 0 : FrameRing->Mask; do { - NDIS_TCP_IP_CHECKSUM_NET_BUFFER_LIST_INFO *ChecksumInfo = - (NDIS_TCP_IP_CHECKSUM_NET_BUFFER_LIST_INFO *) - &NET_BUFFER_LIST_INFO(*Nbl, TcpIpChecksumNetBufferListInfo); ASSERT(XdpRingFree(FrameRing) > FrameRingReservedCount); Frame = XdpRingGetElement(FrameRing, FrameRing->ProducerIndex & FrameRing->Mask); @@ -1494,29 +1491,6 @@ XdpGenericReceivePreInspectNbs( FragmentExtension = XdpGetFragmentExtension(Frame, &RxQueue->FragmentExtension); FragmentExtension->FragmentBufferCount = FragmentCount; - Frame->Layout.Layer4Type = XdpFrameLayer4TypeUnspecified; - - if (ChecksumInfo->Value != 0) { - Frame->Checksum.Layer3 = !!ChecksumInfo->Receive.IpChecksumSucceeded; - Frame->Checksum.Layer4 = - ChecksumInfo->Receive.TcpChecksumSucceeded || - ChecksumInfo->Receive.UdpChecksumSucceeded; - - if (ChecksumInfo->Receive.TcpChecksumSucceeded) { - Frame->Layout.Layer4Type = XdpFrameLayer4TypeTcp; - } - - if (ChecksumInfo->Receive.UdpChecksumSucceeded) { - Frame->Layout.Layer4Type = XdpFrameLayer4TypeUdp; - } - } else { - // - // TODO: does the compiler effectively optimize this to a single - // byte being cleared? - // - RtlZeroMemory(&Frame->Checksum, sizeof(Frame->Checksum)); - } - // // Store the original NB address so uninspected frames (e.g. those where // virtual mappings failed) can be identified and dropped later. diff --git a/src/xdplwf/send.c b/src/xdplwf/send.c index debc662d..7fc06828 100644 --- a/src/xdplwf/send.c +++ b/src/xdplwf/send.c @@ -164,9 +164,6 @@ XdpGenericBuildTxNbl( NDIS_TCP_IP_CHECKSUM_NET_BUFFER_LIST_INFO *ChecksumInfo = (NDIS_TCP_IP_CHECKSUM_NET_BUFFER_LIST_INFO *) &NET_BUFFER_LIST_INFO(Nbl, TcpIpChecksumNetBufferListInfo); - NDIS_UDP_SEGMENTATION_OFFLOAD_NET_BUFFER_LIST_INFO *UsoInfo = - (NDIS_UDP_SEGMENTATION_OFFLOAD_NET_BUFFER_LIST_INFO *) - &NET_BUFFER_LIST_INFO(Nbl, UdpSegmentationOffloadInfo); IoBuildPartialMdl( BufferMdl->Mdl, Mdl, (UCHAR *)MmGetMdlVirtualAddress(BufferMdl->Mdl) @@ -186,65 +183,42 @@ XdpGenericBuildTxNbl( ChecksumInfo->Value = 0; - if (Frame->Checksum.Layer3) { - switch (Frame->Layout.Layer3Type) { - case XdpFrameLayer3TypeIPv4NoOptions: - case XdpFrameLayer3TypeIPv4UnspecifiedOptions: - case XdpFrameLayer3TypeIPv4WithOptions: - ChecksumInfo->Transmit.IpHeaderChecksum = TRUE; - break; - } - } - - if (Frame->Checksum.Layer4) { - switch (Frame->Layout.Layer4Type) { - case XdpFrameLayer4TypeUdp: - ChecksumInfo->Transmit.UdpChecksum = TRUE; - } - } - - if (Frame->Checksum.Layer3 || Frame->Checksum.Layer4) { - switch (Frame->Layout.Layer3Type) { - case XdpFrameLayer3TypeIPv4NoOptions: - case XdpFrameLayer3TypeIPv4UnspecifiedOptions: - case XdpFrameLayer3TypeIPv4WithOptions: - ChecksumInfo->Transmit.IsIPv4 = TRUE; - break; - - case XdpFrameLayer3TypeIPv6NoExtensions: - case XdpFrameLayer3TypeIPv6UnspecifiedExtensions: - case XdpFrameLayer3TypeIPv6WithExtensions: - ChecksumInfo->Transmit.IsIPv6 = TRUE; - break; - } - } - - if (Frame->Gso.UDP.Mss > 0) { - UsoInfo->Transmit.MSS = Frame->Gso.UDP.Mss; + // + // TODO: plumb LWF send checksum + // - // - // TODO: Verify the arithmetic doesn't overflow, there is space in the - // frame for a UDP header at the offset, etc. - // - UsoInfo->Transmit.UdpHeaderOffset = - Frame->Layout.Layer2HeaderLength + Frame->Layout.Layer3HeaderLength; - - switch (Frame->Layout.Layer3Type) { - case XdpFrameLayer3TypeIPv4NoOptions: - case XdpFrameLayer3TypeIPv4UnspecifiedOptions: - case XdpFrameLayer3TypeIPv4WithOptions: - UsoInfo->Transmit.IPVersion = NDIS_UDP_SEGMENTATION_OFFLOAD_IPV4; - break; - - case XdpFrameLayer3TypeIPv6NoExtensions: - case XdpFrameLayer3TypeIPv6UnspecifiedExtensions: - case XdpFrameLayer3TypeIPv6WithExtensions: - UsoInfo->Transmit.IPVersion = NDIS_UDP_SEGMENTATION_OFFLOAD_IPV6; - break; - } - } else { - UsoInfo->Value = 0; - } + // if (Frame->Checksum.Layer3) { + // switch (Frame->Layout.Layer3Type) { + // case XdpFrameLayer3TypeIPv4NoOptions: + // case XdpFrameLayer3TypeIPv4UnspecifiedOptions: + // case XdpFrameLayer3TypeIPv4WithOptions: + // ChecksumInfo->Transmit.IpHeaderChecksum = TRUE; + // break; + // } + // } + + // if (Frame->Checksum.Layer4) { + // switch (Frame->Layout.Layer4Type) { + // case XdpFrameLayer4TypeUdp: + // ChecksumInfo->Transmit.UdpChecksum = TRUE; + // } + // } + + // if (Frame->Checksum.Layer3 || Frame->Checksum.Layer4) { + // switch (Frame->Layout.Layer3Type) { + // case XdpFrameLayer3TypeIPv4NoOptions: + // case XdpFrameLayer3TypeIPv4UnspecifiedOptions: + // case XdpFrameLayer3TypeIPv4WithOptions: + // ChecksumInfo->Transmit.IsIPv4 = TRUE; + // break; + + // case XdpFrameLayer3TypeIPv6NoExtensions: + // case XdpFrameLayer3TypeIPv6UnspecifiedExtensions: + // case XdpFrameLayer3TypeIPv6WithExtensions: + // ChecksumInfo->Transmit.IsIPv6 = TRUE; + // break; + // } + // } if (TxQueue->Flags.TxCompletionContextEnabled) { NblTxContext(Nbl)->CompletionContext =