On 12 January 2017 at 13:13, Anand Kumar <[email protected]> wrote:
> This patch adds functionalities to handle 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. > You should include your Signed-off-by for all your commits. > --- > datapath-windows/automake.mk | 2 + > datapath-windows/ovsext/Debug.h | 3 +- > datapath-windows/ovsext/IpFragment.c | 506 > +++++++++++++++++++++++++++++++++ > datapath-windows/ovsext/IpFragment.h | 74 +++++ > datapath-windows/ovsext/Switch.c | 9 + > datapath-windows/ovsext/ovsext.vcxproj | 2 + > 6 files changed, 595 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..2ce3932 > --- /dev/null > +++ b/datapath-windows/ovsext/IpFragment.c > @@ -0,0 +1,506 @@ > +/* > + * 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: > + * > + * http://www.apache.org/licenses/LICENSE-2.0 > + * > + * 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; > + > + NdisAcquireRWLockWrite(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); > + } > + *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, > + UINT16 *mru, > + 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, entryLockState; > + > + 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)); > + /* Update maximum recieving unit. */ > + entry->mru = payloadLen + ipHdrLen; > + 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. */ > + entry->lockObj = NdisAllocateRWLock(switchContext-> > NdisFilterHandle); > + if (entry->lockObj == NULL) { > + OvsFreeMemoryWithTag(entry, OVS_MEMORY_TAG); > + status = NDIS_STATUS_RESOURCES; > + goto payload_copy_error; > + } > + > + 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. */ > + NdisAcquireRWLockWrite(entry->lockObj, &entryLockState, 0); > + 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; > + } > + } > + /*Insert. */ > + if (prev) { > + prev->next = fragStorage; > + fragStorage->next = next; > + } else { > + fragStorage->next = next; > + entry->head = fragStorage; > + } > + if (!next) { > + entry->tail = fragStorage; > + } > + > + entry->mru = entry->mru > (payloadLen + ipHdrLen) ? > + entry->mru : (payloadLen + ipHdrLen); > + if (entry->recvdLen + fragStorage->len > entry->recvdLen) { > + entry->recvdLen += fragStorage->len; > + } else { > + /* Overflow, ignore the fragment.*/ > + goto fragment_error; > + } > + if (!flags) { > + entry->totalLen = offset + payloadLen; > + } > + if (entry->recvdLen == entry->totalLen) { > + /* Update mru of the forwarding context. */ > + *mru = entry->mru + ETH_HEADER_LENGTH; > + status = OvsIpv4Reassemble(switchContext, curNbl, > completionList, > + sourcePort, entry, newNbl); > + } > + NdisReleaseRWLock(entry->lockObj, &entryLockState); > + return status; > + } > +fragment_error: > + /* Release the entry lock. */ > + NdisReleaseRWLock(entry->lockObj, &entryLockState); > +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) > +{ > + LOCK_STATE_EX lockState; > + NdisAcquireRWLockWrite(entry->lockObj, &lockState, 0); > + 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--; > + NdisReleaseRWLock(entry->lockObj, &lockState); > + NdisFreeRWLock(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..8d87451 > --- /dev/null > +++ b/datapath-windows/ovsext/IpFragment.h > @@ -0,0 +1,74 @@ > +/* > +* 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: > +* > +* http://www.apache.org/licenses/LICENSE-2.0 > +* > +* 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 { > + PNDIS_RW_LOCK_EX 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, > + UINT16 *mru, > + 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 > [email protected] > https://mail.openvswitch.org/mailman/listinfo/ovs-dev > _______________________________________________ dev mailing list [email protected] https://mail.openvswitch.org/mailman/listinfo/ovs-dev
