aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSairam Venugopal <vsairam@vmware.com>2015-10-26 16:48:40 -0700
committerGurucharan Shetty <gshetty@nicira.com>2015-10-27 13:48:46 -0700
commitcab433d0f3d96fd143e76b6fea21449ab7b89240 (patch)
treebc6206a87a4662b99b36c7156f8eb2777888710b
parent9a80ee1443134fe36d15c76bc77b567315f948f9 (diff)
datapath-windows: STT - Add support for TCP Segmentation Offload
Create and initialize the background thread and buffer that assists in defragmenting and completing a TSO packet. Signed-off-by: Sairam Venugopal <vsairam@vmware.com> Acked-by: Nithin Raju <nithin@vmware.com> Signed-off-by: Gurucharan Shetty <gshetty@nicira.com>
-rw-r--r--datapath-windows/ovsext/Stt.c128
-rw-r--r--datapath-windows/ovsext/Stt.h33
-rw-r--r--datapath-windows/ovsext/Switch.c7
3 files changed, 162 insertions, 6 deletions
diff --git a/datapath-windows/ovsext/Stt.c b/datapath-windows/ovsext/Stt.c
index 4a5a4a687..b78ef952c 100644
--- a/datapath-windows/ovsext/Stt.c
+++ b/datapath-windows/ovsext/Stt.c
@@ -35,6 +35,11 @@
#define OVS_DBG_MOD OVS_DBG_STT
#include "Debug.h"
+KSTART_ROUTINE OvsSttDefragCleaner;
+static PLIST_ENTRY OvsSttPktFragHash;
+static NDIS_SPIN_LOCK OvsSttSpinLock;
+static OVS_STT_THREAD_CTX sttDefragThreadCtx;
+
static NDIS_STATUS
OvsDoEncapStt(POVS_VPORT_ENTRY vport, PNET_BUFFER_LIST curNbl,
const OvsIPv4TunnelKey *tunKey,
@@ -349,7 +354,7 @@ OvsCalculateTCPChecksum(PNET_BUFFER_LIST curNbl, PNET_BUFFER curNb)
if (csumInfo.Receive.TcpChecksumSucceeded) {
return NDIS_STATUS_SUCCESS;
}
-
+
EthHdr *eth = (EthHdr *)NdisGetDataBuffer(curNb, sizeof(EthHdr),
NULL, 1, 0);
@@ -379,6 +384,123 @@ OvsCalculateTCPChecksum(PNET_BUFFER_LIST curNbl, PNET_BUFFER curNb)
}
/*
+ *----------------------------------------------------------------------------
+ * OvsInitSttDefragmentation
+ * Initialize the components used by the stt lso defragmentation
+ *----------------------------------------------------------------------------
+ */
+NTSTATUS
+OvsInitSttDefragmentation()
+{
+ NTSTATUS status;
+ HANDLE threadHandle = NULL;
+
+ /* Init the sync-lock */
+ NdisAllocateSpinLock(&OvsSttSpinLock);
+
+ /* Init the Hash Buffer */
+ OvsSttPktFragHash = (PLIST_ENTRY) OvsAllocateMemoryWithTag(
+ sizeof(LIST_ENTRY)
+ * STT_HASH_TABLE_SIZE,
+ OVS_STT_POOL_TAG);
+ if (OvsSttPktFragHash == NULL) {
+ NdisFreeSpinLock(&OvsSttSpinLock);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ for (int i = 0; i < STT_HASH_TABLE_SIZE; i++) {
+ InitializeListHead(&OvsSttPktFragHash[i]);
+ }
+
+ /* Init Defrag Cleanup Thread */
+ KeInitializeEvent(&sttDefragThreadCtx.event, NotificationEvent, FALSE);
+ status = PsCreateSystemThread(&threadHandle, SYNCHRONIZE, NULL, NULL,
+ NULL, OvsSttDefragCleaner,
+ &sttDefragThreadCtx);
+
+ if (status != STATUS_SUCCESS) {
+ OvsCleanupSttDefragmentation();
+ return status;
+ }
+
+ ObReferenceObjectByHandle(threadHandle, SYNCHRONIZE, NULL, KernelMode,
+ &sttDefragThreadCtx.threadObject, NULL);
+ ZwClose(threadHandle);
+ threadHandle = NULL;
+ return STATUS_SUCCESS;
+}
+
+/*
+ *----------------------------------------------------------------------------
+ * OvsCleanupSttDefragmentation
+ * Cleanup memory and thread that were spawned for STT LSO defragmentation
+ *----------------------------------------------------------------------------
+ */
+VOID
+OvsCleanupSttDefragmentation(VOID)
+{
+ NdisAcquireSpinLock(&OvsSttSpinLock);
+ sttDefragThreadCtx.exit = 1;
+ KeSetEvent(&sttDefragThreadCtx.event, 0, FALSE);
+ NdisReleaseSpinLock(&OvsSttSpinLock);
+
+ KeWaitForSingleObject(sttDefragThreadCtx.threadObject, Executive,
+ KernelMode, FALSE, NULL);
+ ObDereferenceObject(sttDefragThreadCtx.threadObject);
+
+ if (OvsSttPktFragHash) {
+ OvsFreeMemoryWithTag(OvsSttPktFragHash, OVS_STT_POOL_TAG);
+ OvsSttPktFragHash = NULL;
+ }
+
+ NdisFreeSpinLock(&OvsSttSpinLock);
+}
+
+/*
+ *----------------------------------------------------------------------------
+ * OvsSttDefragCleaner
+ * Runs periodically and cleans up the buffer to remove expired segments
+ *----------------------------------------------------------------------------
+ */
+VOID
+OvsSttDefragCleaner(PVOID data)
+{
+ POVS_STT_THREAD_CTX context = (POVS_STT_THREAD_CTX)data;
+ PLIST_ENTRY link, next;
+ POVS_STT_PKT_ENTRY entry;
+ BOOLEAN success = TRUE;
+
+ while (success) {
+ NdisAcquireSpinLock(&OvsSttSpinLock);
+ if (context->exit) {
+ NdisReleaseSpinLock(&OvsSttSpinLock);
+ break;
+ }
+
+ /* Set the timeout for the thread and cleanup */
+ UINT64 currentTime, threadSleepTimeout;
+ NdisGetCurrentSystemTime((LARGE_INTEGER *)&currentTime);
+ threadSleepTimeout = currentTime + STT_CLEANUP_INTERVAL;
+
+ for (int i = 0; i < STT_HASH_TABLE_SIZE; i++) {
+ LIST_FORALL_SAFE(&OvsSttPktFragHash[i], link, next) {
+ entry = CONTAINING_RECORD(link, OVS_STT_PKT_ENTRY, link);
+ if (entry->timeout < currentTime) {
+ RemoveEntryList(&entry->link);
+ OvsFreeMemoryWithTag(entry, OVS_STT_POOL_TAG);
+ }
+ }
+ }
+
+ NdisReleaseSpinLock(&OvsSttSpinLock);
+ KeWaitForSingleObject(&context->event, Executive, KernelMode,
+ FALSE, (LARGE_INTEGER *)&threadSleepTimeout);
+ }
+
+ PsTerminateSystemThread(STATUS_SUCCESS);
+}
+
+/*
* --------------------------------------------------------------------------
* OvsDecapStt --
* Decapsulates an STT packet.
@@ -416,7 +538,7 @@ OvsDecapStt(POVS_SWITCH_CONTEXT switchContext,
if (csumInfo.Receive.TcpChecksumFailed) {
return NDIS_STATUS_INVALID_PACKET;
}
-
+
/* Calculate the TCP Checksum */
status = OvsCalculateTCPChecksum(curNbl, curNb);
if (status != NDIS_STATUS_SUCCESS) {
@@ -455,7 +577,7 @@ OvsDecapStt(POVS_SWITCH_CONTEXT switchContext,
hdrLen = STT_HDR_LEN;
NdisAdvanceNetBufferDataStart(curNb, hdrLen, FALSE, NULL);
advanceCnt += hdrLen;
-
+
/* Verify checksum for inner packet if it's required */
if (!(sttHdr->flags & STT_CSUM_VERIFIED)) {
BOOLEAN innerChecksumPartial = sttHdr->flags & STT_CSUM_PARTIAL;
diff --git a/datapath-windows/ovsext/Stt.h b/datapath-windows/ovsext/Stt.h
index 38d721c49..9a453791f 100644
--- a/datapath-windows/ovsext/Stt.h
+++ b/datapath-windows/ovsext/Stt.h
@@ -34,6 +34,11 @@
#define STT_PROTO_TCP (1 << 3)
#define STT_PROTO_TYPES (STT_PROTO_IPV4 | STT_PROTO_TCP)
+#define STT_HASH_TABLE_SIZE ((UINT32)1 << 10)
+#define STT_HASH_TABLE_MASK (STT_HASH_TABLE_SIZE - 1)
+#define STT_ENTRY_TIMEOUT 300000000 // 30s
+#define STT_CLEANUP_INTERVAL 300000000 // 30s
+
#define STT_ETH_PAD 2
typedef struct SttHdr {
UINT8 version;
@@ -58,14 +63,32 @@ typedef struct _OVS_STT_VPORT {
UINT64 slowOutPkts;
} OVS_STT_VPORT, *POVS_STT_VPORT;
+typedef struct _OVS_STT_PKT_KEY {
+ UINT32 sAddr;
+ UINT32 dAddr;
+ UINT32 ackSeq;
+} OVS_STT_PKT_KEY, *POVS_STT_PKT_KEY;
+
+typedef struct _OVS_STT_PKT_ENTRY {
+ OVS_STT_PKT_KEY ovsPktKey;
+ UINT64 timeout;
+ UINT32 recvdLen;
+ SttHdr sttHdr;
+ PCHAR packetBuf;
+ LIST_ENTRY link;
+} OVS_STT_PKT_ENTRY, *POVS_STT_PKT_ENTRY;
+
+typedef struct _OVS_STT_THREAD_CTX {
+ KEVENT event;
+ PVOID threadObject;
+ UINT32 exit;
+} OVS_STT_THREAD_CTX, *POVS_STT_THREAD_CTX;
+
NTSTATUS OvsInitSttTunnel(POVS_VPORT_ENTRY vport,
UINT16 udpDestPort);
VOID OvsCleanupSttTunnel(POVS_VPORT_ENTRY vport);
-
-void OvsCleanupSttTunnel(POVS_VPORT_ENTRY vport);
-
NDIS_STATUS OvsEncapStt(POVS_VPORT_ENTRY vport,
PNET_BUFFER_LIST curNbl,
OvsIPv4TunnelKey *tunKey,
@@ -79,6 +102,10 @@ NDIS_STATUS OvsDecapStt(POVS_SWITCH_CONTEXT switchContext,
OvsIPv4TunnelKey *tunKey,
PNET_BUFFER_LIST *newNbl);
+NTSTATUS OvsInitSttDefragmentation();
+
+VOID OvsCleanupSttDefragmentation(VOID);
+
static __inline UINT32
OvsGetSttTunHdrSize(VOID)
{
diff --git a/datapath-windows/ovsext/Switch.c b/datapath-windows/ovsext/Switch.c
index f176fa09f..2878e9192 100644
--- a/datapath-windows/ovsext/Switch.c
+++ b/datapath-windows/ovsext/Switch.c
@@ -212,6 +212,12 @@ OvsCreateSwitch(NDIS_HANDLE ndisFilterHandle,
goto create_switch_done;
}
+ status = OvsInitSttDefragmentation();
+ if (status != STATUS_SUCCESS) {
+ OVS_LOG_ERROR("Exit: Failed to initialize Stt Defragmentation");
+ goto create_switch_done;
+ }
+
*switchContextOut = switchContext;
create_switch_done:
@@ -242,6 +248,7 @@ OvsExtDetach(NDIS_HANDLE filterModuleContext)
}
OvsDeleteSwitch(switchContext);
OvsCleanupIpHelper();
+ OvsCleanupSttDefragmentation();
/* This completes the cleanup, and a new attach can be handled now. */
OVS_LOG_TRACE("Exit: OvsDetach Successfully");