Thanks for the patches! Acked-by: Sairam Venugopal <vsai...@vmware.com>
On 3/24/17, 1:51 PM, "ovs-dev-boun...@openvswitch.org on behalf of Anand Kumar" <ovs-dev-boun...@openvswitch.org on behalf of kumaran...@vmware.com> wrote: >This patch adds functionalities to support IPv4 fragments, which will be >used by Conntrack module. > >Added a new structure to hold the Ipv4 fragments and a hash table to >hold Ipv4 datagram entries. Also added a clean up thread that runs >every minute to delete the expired IPv4 datagram entries. > >The individual fragments are ignored by the conntrack. Once all the >fragments are recieved, a new NBL is created out of the reassembled >fragments and conntrack executes actions on the new NBL. > >Created new APIs OvsProcessIpv4Fragment() to process individual fragments, >OvsIpv4Reassemble() to reassemble Ipv4 fragments. > >Signed-off-by: Anand Kumar <kumaran...@vmware.com> >--- >v5->v6: No Change >v4->v5: > - Modified Patch 3 to retain MRU in _OVS_BUFFER_CONTEXT instead of > using it in ovsForwardingContext with minor changes in rest of the > patches. >v3->v4: > - Rebase > - Acquire read lock for read operations. >v2->v3: > - using spinlock instead of RW lock. > - updated log messages, summary, fixed alignment issues. >v1->v2: > - Patch 4 updated to make it compile for release mode. >--- > datapath-windows/automake.mk | 2 + > datapath-windows/ovsext/Debug.h | 3 +- > datapath-windows/ovsext/IpFragment.c | 500 +++++++++++++++++++++++++++++++++ > datapath-windows/ovsext/IpFragment.h | 73 +++++ > datapath-windows/ovsext/Switch.c | 9 + > datapath-windows/ovsext/ovsext.vcxproj | 2 + > 6 files changed, 588 insertions(+), 1 deletion(-) > create mode 100644 datapath-windows/ovsext/IpFragment.c > create mode 100644 datapath-windows/ovsext/IpFragment.h > >diff --git a/datapath-windows/automake.mk b/datapath-windows/automake.mk >index 53983ae..4f7b55a 100644 >--- a/datapath-windows/automake.mk >+++ b/datapath-windows/automake.mk >@@ -32,6 +32,8 @@ EXTRA_DIST += \ > datapath-windows/ovsext/Flow.h \ > datapath-windows/ovsext/Gre.h \ > datapath-windows/ovsext/Gre.c \ >+ datapath-windows/ovsext/IpFragment.c \ >+ datapath-windows/ovsext/IpFragment.h \ > datapath-windows/ovsext/IpHelper.c \ > datapath-windows/ovsext/IpHelper.h \ > datapath-windows/ovsext/Jhash.c \ >diff --git a/datapath-windows/ovsext/Debug.h b/datapath-windows/ovsext/Debug.h >index cae6ac9..6de1812 100644 >--- a/datapath-windows/ovsext/Debug.h >+++ b/datapath-windows/ovsext/Debug.h >@@ -42,8 +42,9 @@ > #define OVS_DBG_STT BIT32(22) > #define OVS_DBG_CONTRK BIT32(23) > #define OVS_DBG_GENEVE BIT32(24) >+#define OVS_DBG_IPFRAG BIT32(25) > >-#define OVS_DBG_LAST 24 /* Set this to the last defined module number. */ >+#define OVS_DBG_LAST 25 /* Set this to the last defined module number. */ > /* Please add above OVS_DBG_LAST. */ > > #define OVS_DBG_ERROR DPFLTR_ERROR_LEVEL >diff --git a/datapath-windows/ovsext/IpFragment.c >b/datapath-windows/ovsext/IpFragment.c >new file mode 100644 >index 0000000..37abcd8 >--- /dev/null >+++ b/datapath-windows/ovsext/IpFragment.c >@@ -0,0 +1,500 @@ >+/* >+ * Copyright (c) 2017 VMware, Inc. >+ * >+ * Licensed under the Apache License, Version 2.0 (the "License"); >+ * you may not use this file except in compliance with the License. >+ * You may obtain a copy of the License at: >+ * >+ * >https://urldefense.proofpoint.com/v2/url?u=http-3A__www.apache.org_licenses_LICENSE-2D2.0&d=DwICAg&c=uilaK90D4TOVoH58JNXRgQ&r=Z6vowHUOjP5ysP_g372c49Nqc1vEKqHKNBkR5Q5Z7uo&m=1abLNFAEjs9Cscb3AJMpOuBIqOdZ-_J4Gaaxv_J69Uc&s=8iji8m6jUpxnBC2ddLAT_24ix4jr_EMbFXX31y-p3h4&e= > >+ * >+ * Unless required by applicable law or agreed to in writing, software >+ * distributed under the License is distributed on an "AS IS" BASIS, >+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+ * See the License for the specific language governing permissions and >+ * limitations under the License. >+ */ >+ >+#include "Conntrack.h" >+#include "Debug.h" >+#include "IpFragment.h" >+#include "Jhash.h" >+#include "Offload.h" >+#include "PacketParser.h" >+ >+#ifdef OVS_DBG_MOD >+#undef OVS_DBG_MOD >+#endif >+#define OVS_DBG_MOD OVS_DBG_IPFRAG >+ >+/* Function declarations */ >+static VOID OvsIpFragmentEntryCleaner(PVOID data); >+static VOID OvsIpFragmentEntryDelete(POVS_IPFRAG_ENTRY entry); >+ >+/* Global and static variables */ >+static OVS_IPFRAG_THREAD_CTX ipFragThreadCtx; >+static PNDIS_RW_LOCK_EX ovsIpFragmentHashLockObj; >+static UINT64 ipTotalEntries; >+static PLIST_ENTRY OvsIpFragTable; >+ >+NDIS_STATUS >+OvsInitIpFragment(POVS_SWITCH_CONTEXT context) >+{ >+ >+ NDIS_STATUS status; >+ HANDLE threadHandle = NULL; >+ >+ /* Init the sync-lock */ >+ ovsIpFragmentHashLockObj = NdisAllocateRWLock(context->NdisFilterHandle); >+ if (ovsIpFragmentHashLockObj == NULL) { >+ return STATUS_INSUFFICIENT_RESOURCES; >+ } >+ >+ /* Init the Hash Buffer */ >+ OvsIpFragTable = OvsAllocateMemoryWithTag(sizeof(LIST_ENTRY) >+ * IP_FRAG_HASH_TABLE_SIZE, >+ OVS_MEMORY_TAG); >+ if (OvsIpFragTable == NULL) { >+ NdisFreeRWLock(ovsIpFragmentHashLockObj); >+ ovsIpFragmentHashLockObj = NULL; >+ return STATUS_INSUFFICIENT_RESOURCES; >+ } >+ >+ for (int i = 0; i < IP_FRAG_HASH_TABLE_SIZE; i++) { >+ InitializeListHead(&OvsIpFragTable[i]); >+ } >+ >+ /* Init Cleaner Thread */ >+ KeInitializeEvent(&ipFragThreadCtx.event, NotificationEvent, FALSE); >+ status = PsCreateSystemThread(&threadHandle, SYNCHRONIZE, NULL, NULL, >+ NULL, OvsIpFragmentEntryCleaner, >+ &ipFragThreadCtx); >+ >+ if (status != STATUS_SUCCESS) { >+ OvsFreeMemoryWithTag(OvsIpFragTable, OVS_MEMORY_TAG); >+ OvsIpFragTable = NULL; >+ NdisFreeRWLock(ovsIpFragmentHashLockObj); >+ ovsIpFragmentHashLockObj = NULL; >+ return status; >+ } >+ >+ ObReferenceObjectByHandle(threadHandle, SYNCHRONIZE, NULL, KernelMode, >+ &ipFragThreadCtx.threadObject, NULL); >+ ZwClose(threadHandle); >+ threadHandle = NULL; >+ return STATUS_SUCCESS; >+} >+ >+static __inline UINT32 >+OvsGetIPFragmentHash(POVS_IPFRAG_KEY fragKey) >+{ >+ UINT32 arr[6]; >+ arr[0] = (UINT32)fragKey->protocol; >+ arr[1] = (UINT32)fragKey->id; >+ arr[2] = (UINT32)fragKey->sAddr; >+ arr[3] = (UINT32)fragKey->dAddr; >+ arr[4] = (UINT32)((fragKey->tunnelId & 0xFFFFFFFF00000000LL) >> 32); >+ arr[5] = (UINT32)(fragKey->tunnelId & 0xFFFFFFFFLL); >+ return OvsJhashWords(arr, 6, OVS_HASH_BASIS); >+} >+ >+static __inline POVS_IPFRAG_ENTRY >+OvsLookupIPFrag(POVS_IPFRAG_KEY fragKey, UINT32 hash) >+{ >+ POVS_IPFRAG_ENTRY entry; >+ PLIST_ENTRY link; >+ LOCK_STATE_EX lockState; >+ >+ NdisAcquireRWLockRead(ovsIpFragmentHashLockObj, &lockState, 0); >+ LIST_FORALL(&OvsIpFragTable[hash & IP_FRAG_HASH_TABLE_MASK], link) { >+ entry = CONTAINING_RECORD(link, OVS_IPFRAG_ENTRY, link); >+ if (entry->fragKey.dAddr == fragKey->dAddr && >+ entry->fragKey.sAddr == fragKey->sAddr && >+ entry->fragKey.id == fragKey->id && >+ entry->fragKey.protocol == fragKey->protocol && >+ entry->fragKey.tunnelId == fragKey->tunnelId) { >+ NdisReleaseRWLock(ovsIpFragmentHashLockObj, &lockState); >+ return entry; >+ } >+ } >+ NdisReleaseRWLock(ovsIpFragmentHashLockObj, &lockState); >+ return NULL; >+} >+ >+/* >+*---------------------------------------------------------------------------- >+* OvsIpv4Reassemble >+* Reassemble the ipv4 fragments and return newNbl on success. >+* Should be called after acquiring the lockObj for the entry. >+*---------------------------------------------------------------------------- >+*/ >+NDIS_STATUS >+OvsIpv4Reassemble(POVS_SWITCH_CONTEXT switchContext, >+ PNET_BUFFER_LIST *curNbl, >+ OvsCompletionList *completionList, >+ NDIS_SWITCH_PORT_ID sourcePort, >+ POVS_IPFRAG_ENTRY entry, >+ PNET_BUFFER_LIST *newNbl) >+{ >+ NDIS_STATUS status = NDIS_STATUS_SUCCESS; >+ NDIS_STRING filterReason; >+ POVS_BUFFER_CONTEXT ctx; >+ PNET_BUFFER curNb; >+ EthHdr *eth; >+ IPHdr *ipHdr, *newIpHdr; >+ CHAR *ethBuf[sizeof(EthHdr)]; >+ CHAR *packetBuf; >+ UINT16 ipHdrLen, packetLen, packetHeader; >+ POVS_FRAGMENT_LIST head = NULL; >+ >+ curNb = NET_BUFFER_LIST_FIRST_NB(*curNbl); >+ ASSERT(NET_BUFFER_NEXT_NB(curNb) == NULL); >+ >+ eth = (EthHdr*)NdisGetDataBuffer(curNb, ETH_HEADER_LENGTH, >+ (PVOID)ðBuf, 1, 0); >+ if (eth == NULL) { >+ return NDIS_STATUS_INVALID_PACKET; >+ } >+ ipHdr = (IPHdr *)((PCHAR)eth + ETH_HEADER_LENGTH); >+ if (ipHdr == NULL) { >+ return NDIS_STATUS_INVALID_PACKET; >+ } >+ ipHdrLen = (UINT16)(ipHdr->ihl * 4); >+ packetLen = ETH_HEADER_LENGTH + ipHdrLen + entry->totalLen; >+ packetBuf = (CHAR*)OvsAllocateMemoryWithTag(packetLen, >+ OVS_MEMORY_TAG); >+ if (packetBuf == NULL) { >+ OVS_LOG_ERROR("Insufficient resources, failed to allocate packetBuf"); >+ return NDIS_STATUS_RESOURCES; >+ } >+ >+ /* copy Ethernet header */ >+ NdisMoveMemory(packetBuf, eth, ETH_HEADER_LENGTH); >+ /* copy ipv4 header to packet buff */ >+ NdisMoveMemory(packetBuf + ETH_HEADER_LENGTH, ipHdr, ipHdrLen); >+ >+ /* update new ip header */ >+ newIpHdr = (IPHdr *)(packetBuf + ETH_HEADER_LENGTH); >+ newIpHdr->frag_off = 0; >+ newIpHdr->tot_len = htons(packetLen - ETH_HEADER_LENGTH); >+ newIpHdr->check = 0; >+ newIpHdr->check = IPChecksum((UINT8 *)packetBuf + ETH_HEADER_LENGTH, >+ ipHdrLen, 0); >+ packetHeader = ETH_HEADER_LENGTH + ipHdrLen; >+ head = entry->head; >+ while (head) { >+ ASSERT((packetHeader + head->offset) <= packetLen); >+ NdisMoveMemory(packetBuf + packetHeader + head->offset, >+ head->pbuff, head->len); >+ head = head->next; >+ } >+ /* Create new nbl from the flat buffer */ >+ *newNbl = OvsAllocateNBLFromBuffer(switchContext, packetBuf, packetLen); >+ if (*newNbl == NULL) { >+ OVS_LOG_ERROR("Insufficient resources, failed to allocate newNbl"); >+ status = NDIS_STATUS_RESOURCES; >+ } >+ >+ OvsFreeMemoryWithTag(packetBuf, OVS_MEMORY_TAG); >+ /* Timeout the entry so that clean up thread deletes it .*/ >+ entry->expiration -= IPFRAG_ENTRY_TIMEOUT; >+ >+ /* Complete the fragment NBL */ >+ ctx = (POVS_BUFFER_CONTEXT)NET_BUFFER_LIST_CONTEXT_DATA_START(*curNbl); >+ if (ctx->flags & OVS_BUFFER_NEED_COMPLETE) { >+ RtlInitUnicodeString(&filterReason, L"Complete last fragment"); >+ OvsAddPktCompletionList(completionList, TRUE, sourcePort, *curNbl, 1, >+ &filterReason); >+ } else { >+ OvsCompleteNBL(switchContext, *curNbl, TRUE); >+ } >+ /* Store mru in the ovs buffer context. */ >+ *curNbl = *newNbl; >+ return status; >+} >+/* >+*---------------------------------------------------------------------------- >+* OvsProcessIpv4Fragment >+* Reassemble the fragments once all the fragments are recieved and >+* return NDIS_STATUS_PENDING for the pending fragments >+* XXX - Instead of copying NBls, Keep the NBLs in limbo state. >+*---------------------------------------------------------------------------- >+*/ >+NDIS_STATUS >+OvsProcessIpv4Fragment(POVS_SWITCH_CONTEXT switchContext, >+ PNET_BUFFER_LIST *curNbl, >+ OvsCompletionList *completionList, >+ NDIS_SWITCH_PORT_ID sourcePort, >+ ovs_be64 tunnelId, >+ PNET_BUFFER_LIST *newNbl) >+{ >+ NDIS_STATUS status = NDIS_STATUS_PENDING; >+ PNET_BUFFER curNb; >+ CHAR *ethBuf[sizeof(EthHdr)]; >+ UINT16 offset, flags; >+ UINT16 payloadLen, ipHdrLen; >+ UINT32 hash; >+ UINT64 currentTime; >+ EthHdr *eth; >+ IPHdr *ipHdr; >+ OVS_IPFRAG_KEY fragKey; >+ POVS_IPFRAG_ENTRY entry; >+ POVS_FRAGMENT_LIST fragStorage; >+ LOCK_STATE_EX htLockState; >+ >+ curNb = NET_BUFFER_LIST_FIRST_NB(*curNbl); >+ ASSERT(NET_BUFFER_NEXT_NB(curNb) == NULL); >+ >+ eth = (EthHdr*)NdisGetDataBuffer(curNb, ETH_HEADER_LENGTH, >+ (PVOID)ðBuf, 1, 0); >+ if (eth == NULL) { >+ return NDIS_STATUS_INVALID_PACKET; >+ } >+ >+ ipHdr = (IPHdr *)((PCHAR)eth + ETH_HEADER_LENGTH); >+ if (ipHdr == NULL) { >+ return NDIS_STATUS_INVALID_PACKET; >+ } >+ ipHdrLen = (UINT16)(ipHdr->ihl * 4); >+ payloadLen = ntohs(ipHdr->tot_len) - ipHdrLen; >+ offset = ntohs(ipHdr->frag_off) & IP_OFFSET; >+ offset <<= 3; >+ flags = ntohs(ipHdr->frag_off) & IP_MF; >+ >+ /*Copy fragment specific fields. */ >+ fragKey.protocol = ipHdr->protocol; >+ fragKey.id = ipHdr->id; >+ fragKey.sAddr = ipHdr->saddr; >+ fragKey.dAddr = ipHdr->daddr; >+ fragKey.tunnelId = tunnelId; >+ /* Padding. */ >+ NdisZeroMemory(&fragKey.pad_1, 3); >+ fragKey.pad_2 = 0; >+ >+ fragStorage = (POVS_FRAGMENT_LIST ) >+ OvsAllocateMemoryWithTag(sizeof(OVS_FRAGMENT_LIST), OVS_MEMORY_TAG); >+ if (fragStorage == NULL) { >+ OVS_LOG_ERROR("Insufficient resources, failed to allocate >fragStorage"); >+ return NDIS_STATUS_RESOURCES; >+ } >+ >+ fragStorage->pbuff = (CHAR *)OvsAllocateMemoryWithTag(payloadLen, >+ OVS_MEMORY_TAG); >+ if (fragStorage->pbuff == NULL) { >+ OVS_LOG_ERROR("Insufficient resources, failed to allocate >fragStorage"); >+ OvsFreeMemoryWithTag(fragStorage, OVS_MEMORY_TAG); >+ return NDIS_STATUS_RESOURCES; >+ } >+ >+ /* Copy payload from nbl to fragment storage. */ >+ if (OvsGetPacketBytes(*curNbl, payloadLen, ETH_HEADER_LENGTH + ipHdrLen, >+ fragStorage->pbuff) == NULL) { >+ status = NDIS_STATUS_RESOURCES; >+ goto payload_copy_error; >+ } >+ fragStorage->len = payloadLen; >+ fragStorage->offset = offset; >+ fragStorage->next = NULL; >+ hash = OvsGetIPFragmentHash(&fragKey); >+ entry = OvsLookupIPFrag(&fragKey, hash); >+ if (entry == NULL) { >+ entry = (POVS_IPFRAG_ENTRY) >+ OvsAllocateMemoryWithTag(sizeof(OVS_IPFRAG_ENTRY), >+ OVS_MEMORY_TAG); >+ if (entry == NULL) { >+ status = NDIS_STATUS_RESOURCES; >+ goto payload_copy_error; >+ } >+ /* Copy the fragmeny key. */ >+ NdisZeroMemory(entry, sizeof(OVS_IPFRAG_ENTRY)); >+ NdisMoveMemory(&(entry->fragKey), &fragKey, >+ sizeof(OVS_IPFRAG_KEY)); >+ /* Init MRU. */ >+ entry->mru = ETH_HEADER_LENGTH + ipHdrLen + payloadLen; >+ entry->recvdLen += fragStorage->len; >+ entry->head = entry->tail = fragStorage; >+ if (!flags) { >+ entry->totalLen = offset + payloadLen; >+ } >+ NdisGetCurrentSystemTime((LARGE_INTEGER *)¤tTime); >+ entry->expiration = currentTime + IPFRAG_ENTRY_TIMEOUT; >+ >+ /* Init the sync-lock. */ >+ NdisAllocateSpinLock(&(entry->lockObj)); >+ NdisAcquireRWLockWrite(ovsIpFragmentHashLockObj, &htLockState, 0); >+ InsertHeadList(&OvsIpFragTable[hash & IP_FRAG_HASH_TABLE_MASK], >+ &entry->link); >+ >+ ipTotalEntries++; >+ NdisReleaseRWLock(ovsIpFragmentHashLockObj, &htLockState); >+ return NDIS_STATUS_PENDING; >+ } else { >+ /* Acquire the entry lock. */ >+ NdisAcquireSpinLock(&(entry->lockObj)); >+ NdisGetCurrentSystemTime((LARGE_INTEGER *)¤tTime); >+ if (currentTime > entry->expiration) { >+ /* Expired entry. */ >+ goto fragment_error; >+ } >+ POVS_FRAGMENT_LIST next = entry->head; >+ POVS_FRAGMENT_LIST prev = entry->tail; >+ if (prev != NULL || prev->offset < offset) { >+ next = NULL; >+ goto found; >+ } >+ prev = NULL; >+ for (next = entry->head; next != NULL; next = next->next) { >+ if (next->offset > fragStorage->offset) { >+ break; >+ } >+ prev = next; >+ } >+found: >+ /*Check for overlap. */ >+ if (prev) { >+ /* i bytes overlap. */ >+ int i = (prev->offset + prev->len) - fragStorage->offset; >+ if (i > 0) { >+ goto fragment_error; >+ } >+ } >+ if (next) { >+ /* i bytes overlap. */ >+ int i = (fragStorage->offset + fragStorage->len) - next->offset; >+ if (i > 0) { >+ goto fragment_error; >+ } >+ } >+ >+ if (entry->recvdLen + fragStorage->len > entry->recvdLen) { >+ entry->recvdLen += fragStorage->len; >+ } else { >+ /* Overflow, ignore the fragment.*/ >+ goto fragment_error; >+ } >+ >+ /*Insert. */ >+ if (prev) { >+ prev->next = fragStorage; >+ fragStorage->next = next; >+ } else { >+ fragStorage->next = next; >+ entry->head = fragStorage; >+ } >+ if (!next) { >+ entry->tail = fragStorage; >+ } >+ >+ /*Update Maximum recieved Unit */ >+ entry->mru = entry->mru > (ETH_HEADER_LENGTH + ipHdrLen + payloadLen) >? >+ entry->mru : (ETH_HEADER_LENGTH + ipHdrLen + >payloadLen); >+ if (!flags) { >+ entry->totalLen = offset + payloadLen; >+ } >+ if (entry->recvdLen == entry->totalLen) { >+ status = OvsIpv4Reassemble(switchContext, curNbl, completionList, >+ sourcePort, entry, newNbl); >+ } >+ NdisReleaseSpinLock(&(entry->lockObj)); >+ return status; >+ } >+fragment_error: >+ /* Release the entry lock. */ >+ NdisReleaseSpinLock(&(entry->lockObj)); >+payload_copy_error: >+ OvsFreeMemoryWithTag(fragStorage->pbuff, OVS_MEMORY_TAG); >+ OvsFreeMemoryWithTag(fragStorage, OVS_MEMORY_TAG); >+ return status; >+} >+ >+ >+/* >+*---------------------------------------------------------------------------- >+* OvsIpFragmentEntryCleaner >+* Runs periodically and cleans up the Ip Fragment table >+* Interval is selected as twice the entry timeout >+*---------------------------------------------------------------------------- >+*/ >+static VOID >+OvsIpFragmentEntryCleaner(PVOID data) >+{ >+ >+ POVS_IPFRAG_THREAD_CTX context = (POVS_IPFRAG_THREAD_CTX)data; >+ PLIST_ENTRY link, next; >+ POVS_IPFRAG_ENTRY entry; >+ BOOLEAN success = TRUE; >+ >+ while (success) { >+ LOCK_STATE_EX lockState; >+ NdisAcquireRWLockWrite(ovsIpFragmentHashLockObj, &lockState, 0); >+ if (context->exit) { >+ NdisReleaseRWLock(ovsIpFragmentHashLockObj, &lockState); >+ break; >+ } >+ >+ /* Set the timeout for the thread and cleanup. */ >+ UINT64 currentTime, threadSleepTimeout; >+ NdisGetCurrentSystemTime((LARGE_INTEGER *)¤tTime); >+ threadSleepTimeout = currentTime + IPFRAG_CLEANUP_INTERVAL; >+ for (int i = 0; i < IP_FRAG_HASH_TABLE_SIZE && ipTotalEntries; i++) { >+ LIST_FORALL_SAFE(&OvsIpFragTable[i], link, next) { >+ entry = CONTAINING_RECORD(link, OVS_IPFRAG_ENTRY, link); >+ if (entry->expiration < currentTime) { >+ OvsIpFragmentEntryDelete(entry); >+ } >+ } >+ } >+ >+ NdisReleaseRWLock(ovsIpFragmentHashLockObj, &lockState); >+ KeWaitForSingleObject(&context->event, Executive, KernelMode, >+ FALSE, (LARGE_INTEGER *)&threadSleepTimeout); >+ } >+ >+ PsTerminateSystemThread(STATUS_SUCCESS); >+} >+ >+static VOID >+OvsIpFragmentEntryDelete(POVS_IPFRAG_ENTRY entry) >+{ >+ NdisAcquireSpinLock(&(entry->lockObj)); >+ POVS_FRAGMENT_LIST head = entry->head; >+ POVS_FRAGMENT_LIST temp = NULL; >+ while (head) { >+ temp = head; >+ head = head->next; >+ OvsFreeMemoryWithTag(temp->pbuff, OVS_MEMORY_TAG); >+ OvsFreeMemoryWithTag(temp, OVS_MEMORY_TAG); >+ } >+ RemoveEntryList(&entry->link); >+ ipTotalEntries--; >+ NdisReleaseSpinLock(&(entry->lockObj)); >+ NdisFreeSpinLock(&(entry->lockObj)); >+ OvsFreeMemoryWithTag(entry, OVS_MEMORY_TAG); >+} >+ >+VOID >+OvsCleanupIpFragment(VOID) >+{ >+ PLIST_ENTRY link, next; >+ POVS_IPFRAG_ENTRY entry; >+ LOCK_STATE_EX lockState; >+ NdisAcquireRWLockWrite(ovsIpFragmentHashLockObj, &lockState, 0); >+ ipFragThreadCtx.exit = 1; >+ KeSetEvent(&ipFragThreadCtx.event, 0, FALSE); >+ NdisReleaseRWLock(ovsIpFragmentHashLockObj, &lockState); >+ KeWaitForSingleObject(ipFragThreadCtx.threadObject, Executive, >+ KernelMode, FALSE, NULL); >+ ObDereferenceObject(ipFragThreadCtx.threadObject); >+ >+ if (OvsIpFragTable) { >+ for (int i = 0; i < IP_FRAG_HASH_TABLE_SIZE && ipTotalEntries; i++) { >+ LIST_FORALL_SAFE(&OvsIpFragTable[i], link, next) { >+ entry = CONTAINING_RECORD(link, OVS_IPFRAG_ENTRY, link); >+ OvsIpFragmentEntryDelete(entry); >+ } >+ } >+ OvsFreeMemoryWithTag(OvsIpFragTable, OVS_MEMORY_TAG); >+ OvsIpFragTable = NULL; >+ } >+ NdisFreeRWLock(ovsIpFragmentHashLockObj); >+ ovsIpFragmentHashLockObj = NULL; >+ } >diff --git a/datapath-windows/ovsext/IpFragment.h >b/datapath-windows/ovsext/IpFragment.h >new file mode 100644 >index 0000000..e027168 >--- /dev/null >+++ b/datapath-windows/ovsext/IpFragment.h >@@ -0,0 +1,73 @@ >+/* >+* Copyright (c) 2017 VMware, Inc. >+* >+* Licensed under the Apache License, Version 2.0 (the "License"); >+* you may not use this file except in compliance with the License. >+* You may obtain a copy of the License at: >+* >+* >https://urldefense.proofpoint.com/v2/url?u=http-3A__www.apache.org_licenses_LICENSE-2D2.0&d=DwICAg&c=uilaK90D4TOVoH58JNXRgQ&r=Z6vowHUOjP5ysP_g372c49Nqc1vEKqHKNBkR5Q5Z7uo&m=1abLNFAEjs9Cscb3AJMpOuBIqOdZ-_J4Gaaxv_J69Uc&s=8iji8m6jUpxnBC2ddLAT_24ix4jr_EMbFXX31y-p3h4&e= > >+* >+* Unless required by applicable law or agreed to in writing, software >+* distributed under the License is distributed on an "AS IS" BASIS, >+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+* See the License for the specific language governing permissions and >+* limitations under the License. >+*/ >+ >+#ifndef __IPFRAGMENT_H_ >+#define __IPFRAGMENT_H_ 1 >+#include "PacketIO.h" >+ >+typedef struct _OVS_FRAGMENT_LIST { >+ CHAR *pbuff; >+ UINT16 len; >+ UINT16 offset; >+ struct _OVS_FRAGMENT_LIST *next; >+} OVS_FRAGMENT_LIST, *POVS_FRAGMENT_LIST; >+ >+typedef struct _OVS_IPFRAG_KEY { >+ UINT8 protocol; >+ UINT8 pad_1[3]; /* Align the structure to address >boundaries.*/ >+ UINT16 id; >+ UINT16 pad_2; /* Align the structure to address >boundaries.*/ >+ UINT32 sAddr; >+ UINT32 dAddr; >+ ovs_be64 tunnelId; >+} OVS_IPFRAG_KEY, *POVS_IPFRAG_KEY; >+ >+typedef struct _OVS_IPFRAG_ENTRY { >+ NDIS_SPIN_LOCK lockObj; /* To access the entry. */ >+ UINT16 totalLen; >+ UINT16 recvdLen; >+ UINT16 mru; >+ UINT64 expiration; >+ OVS_IPFRAG_KEY fragKey; >+ POVS_FRAGMENT_LIST head; >+ POVS_FRAGMENT_LIST tail; >+ LIST_ENTRY link; >+} OVS_IPFRAG_ENTRY, *POVS_IPFRAG_ENTRY; >+ >+typedef struct _OVS_IPFRAG_THREAD_CTX { >+ KEVENT event; >+ PVOID threadObject; >+ UINT32 exit; >+} OVS_IPFRAG_THREAD_CTX, *POVS_IPFRAG_THREAD_CTX; >+ >+#define IP_FRAG_HASH_TABLE_SIZE ((UINT32)1 << 10) >+#define IP_FRAG_HASH_TABLE_MASK (IP_FRAG_HASH_TABLE_SIZE - 1) >+/*30s -Sufficient time to recieve all fragments.*/ >+#define IPFRAG_ENTRY_TIMEOUT 300000000LL >+#define IPFRAG_CLEANUP_INTERVAL IPFRAG_ENTRY_TIMEOUT * 2 /*1m.*/ >+PNET_BUFFER_LIST OvsIpv4FragmentNBL(PVOID ovsContext, >+ PNET_BUFFER_LIST nbl, >+ UINT16 mru); >+ >+NDIS_STATUS OvsProcessIpv4Fragment(POVS_SWITCH_CONTEXT switchContext, >+ PNET_BUFFER_LIST *curNbl, >+ OvsCompletionList *completionList, >+ NDIS_SWITCH_PORT_ID sourcePort, >+ ovs_be64 tunnelId, >+ PNET_BUFFER_LIST *newNbl); >+NDIS_STATUS OvsInitIpFragment(POVS_SWITCH_CONTEXT context); >+VOID OvsCleanupIpFragment(VOID); >+#endif /* __IPFRAGMENT_H_ */ >diff --git a/datapath-windows/ovsext/Switch.c >b/datapath-windows/ovsext/Switch.c >index 138a656..558e3af 100644 >--- a/datapath-windows/ovsext/Switch.c >+++ b/datapath-windows/ovsext/Switch.c >@@ -27,6 +27,7 @@ > #include "Flow.h" > #include "IpHelper.h" > #include "Oid.h" >+#include "IpFragment.h" > > #ifdef OVS_DBG_MOD > #undef OVS_DBG_MOD >@@ -229,6 +230,12 @@ OvsCreateSwitch(NDIS_HANDLE ndisFilterHandle, > if (status != STATUS_SUCCESS) { > OvsUninitSwitchContext(switchContext); > OVS_LOG_ERROR("Exit: Failed to initialize Connection tracking"); >+ } >+ >+ status = OvsInitIpFragment(switchContext); >+ if (status != STATUS_SUCCESS) { >+ OvsUninitSwitchContext(switchContext); >+ OVS_LOG_ERROR("Exit: Failed to initialize Ip Fragment"); > goto create_switch_done; > } > >@@ -265,6 +272,8 @@ OvsExtDetach(NDIS_HANDLE filterModuleContext) > OvsCleanupSttDefragmentation(); > OvsCleanupConntrack(); > OvsCleanupCtRelated(); >+ OvsCleanupIpFragment(); >+ > /* This completes the cleanup, and a new attach can be handled now. */ > > OVS_LOG_TRACE("Exit: OvsDetach Successfully"); >diff --git a/datapath-windows/ovsext/ovsext.vcxproj >b/datapath-windows/ovsext/ovsext.vcxproj >index 44aea19..ecfc0b8 100644 >--- a/datapath-windows/ovsext/ovsext.vcxproj >+++ b/datapath-windows/ovsext/ovsext.vcxproj >@@ -112,6 +112,7 @@ > <ClInclude Include="Flow.h" /> > <ClInclude Include="Geneve.h" /> > <ClInclude Include="Gre.h" /> >+ <ClInclude Include="IpFragment.h" /> > <ClInclude Include="IpHelper.h" /> > <ClInclude Include="Jhash.h" /> > <ClInclude Include="Mpls.h" /> >@@ -268,6 +269,7 @@ > <ClCompile Include="Flow.c" /> > <ClCompile Include="Geneve.c" /> > <ClCompile Include="Gre.c" /> >+ <ClCompile Include="IpFragment.c" /> > <ClCompile Include="IpHelper.c" /> > <ClCompile Include="Jhash.c" /> > <ClCompile Include="Netlink/Netlink.c" /> >-- >2.9.3.windows.1 > >_______________________________________________ >dev mailing list >d...@openvswitch.org >https://urldefense.proofpoint.com/v2/url?u=https-3A__mail.openvswitch.org_mailman_listinfo_ovs-2Ddev&d=DwICAg&c=uilaK90D4TOVoH58JNXRgQ&r=Z6vowHUOjP5ysP_g372c49Nqc1vEKqHKNBkR5Q5Z7uo&m=1abLNFAEjs9Cscb3AJMpOuBIqOdZ-_J4Gaaxv_J69Uc&s=FD_SOYlWXos4dNwC3j3cUoly2fVJ-kMqyfiRXCSvtqo&e= > _______________________________________________ dev mailing list d...@openvswitch.org https://mail.openvswitch.org/mailman/listinfo/ovs-dev