Hi Ben, I'll test the patches to solve the issue. The v8 version was sent before seeing your mail.
Thanks, Sorin -----Original Message----- From: Ben Pfaff [mailto:b...@nicira.com] Sent: Wednesday, 27 May, 2015 19:31 To: Sorin Vinturis Cc: dev@openvswitch.org Subject: Re: [ovs-dev] [PATCH v7 1/3] datapath-windows: Support for custom VXLAN tunnel port Hi Sorin, I'd like to apply this but I get a patch failure: Applying: datapath-windows: Support for custom VXLAN tunnel port /home/blp/nicira/ovs/.git/rebase-apply/patch:917: trailing whitespace. /home/blp/nicira/ovs/.git/rebase-apply/patch:1957: trailing whitespace. NTSTATUS OvsRemoveAndDeleteVport(PVOID usrParamsCtx, /home/blp/nicira/ovs/.git/rebase-apply/patch:2016: trailing whitespace. * error: patch failed: datapath-windows/ovsext/Datapath.c:925 error: datapath-windows/ovsext/Datapath.c: patch does not apply Patch failed at 0001 datapath-windows: Support for custom VXLAN tunnel port The copy of the patch that failed is found in: /home/blp/nicira/ovs/.git/rebase-apply/patch When you have resolved this problem, run "git am --continue". If you prefer to skip this patch, run "git am --skip" instead. To restore the original branch and stop patching, run "git am --abort". On Wed, May 27, 2015 at 04:08:21PM +0000, Sorin Vinturis wrote: > The kernel datapath supports only port 4789 for VXLAN tunnel creation. > Added support in order to allow for the VXLAN tunnel port to be > configurable to any port number set by the userspace. > > The patch also checks to see if an existing WFP filter, for the > necessary UDP tunnel port, is already created before adding a new one. > This is a double check, because currently the userspace also verifies > this, but it is necessary to avoid future issues. > > Custom VXLAN tunnel port requires the addition of a new WFP filter > with the new UDP tunnel port. The creation of a new WFP filter is > triggered in OvsInitVxlanTunnel function and the removal of the WFP > filter in OvsCleanupVxlanTunnel function. > But the latter functions are running at IRQL = DISPATCH_LEVEL, due > to the NDIS RW lock acquisition, and all WFP calls must be running at > IRQL = PASSIVE_LEVEL. This is why I have created a system thread which > records all filter addition/removal requests into a list for later > processing by the system thread. The ThreadStart routine processes all > received requests at IRQL = PASSIVE_LEVEL, which is the required IRQL > for the necessary WFP calls for adding/removal of the WFP filters. > > The WFP filter for the default VXLAN port 4789 is not added anymore at > filter attach. All WFP filters for the tunnel ports are added when the > tunnel ports are initialized and are removed at cleanup. WFP operation > status is then reported to userspace. > > It is necessary that OvsTunnelFilterUninitialize function is called > after OvsClearAllSwitchVports in order to allow for the added WFP > filters to be removed. OvsTunnelFilterUninitialize function closes the > global engine handle used by most of the WFP calls, including filter > removal. > > Signed-off-by: Sorin Vinturis <svintu...@cloudbasesolutions.com> > Reported-by: Alin Gabriel Serdean <aserd...@cloudbasesolutions.com> > Reported-at: https://github.com/openvswitch/ovs-issues/issues/66 > --- > datapath-windows/ovsext/Datapath.c | 8 +- > datapath-windows/ovsext/Netlink/Netlink.c | 2 + > datapath-windows/ovsext/Netlink/NetlinkError.h | 19 +- > datapath-windows/ovsext/Switch.c | 2 +- > datapath-windows/ovsext/Tunnel.h | 6 - > datapath-windows/ovsext/TunnelFilter.c | 881 > ++++++++++++++++++++----- > datapath-windows/ovsext/TunnelIntf.h | 15 + > datapath-windows/ovsext/Vport.c | 445 ++++++++++--- > datapath-windows/ovsext/Vport.h | 12 +- > datapath-windows/ovsext/Vxlan.c | 102 ++- > datapath-windows/ovsext/Vxlan.h | 13 +- > 11 files changed, 1226 insertions(+), 279 deletions(-) > > diff --git a/datapath-windows/ovsext/Datapath.c > b/datapath-windows/ovsext/Datapath.c > index 7646f0a..d482825 100644 > --- a/datapath-windows/ovsext/Datapath.c > +++ b/datapath-windows/ovsext/Datapath.c > @@ -670,7 +670,6 @@ OvsCleanupDevice(PDEVICE_OBJECT deviceObject, > return OvsCompleteIrpRequest(irp, (ULONG_PTR)0, status); > } > > - > /* > * -------------------------------------------------------------------------- > * IOCTL function handler for the device. > @@ -925,9 +924,12 @@ exit: > KeMemoryBarrier(); > instance->inUse = 0; > > - /* Should not complete a pending IRP unless proceesing is completed */ > + /* Should not complete a pending IRP unless proceesing is completed. */ > if (status == STATUS_PENDING) { > - return status; > + /* STATUS_PENDING is returned by the NL handler when the request is > + * to be processed later, so we mark the IRP as pending and complete > + * it in another thread when the request is processed. */ > + IoMarkIrpPending(irp); > return status; > } > return OvsCompleteIrpRequest(irp, (ULONG_PTR)replyLen, status); > } > diff --git a/datapath-windows/ovsext/Netlink/Netlink.c > b/datapath-windows/ovsext/Netlink/Netlink.c > index 589e3a1..a62d760 100644 > --- a/datapath-windows/ovsext/Netlink/Netlink.c > +++ b/datapath-windows/ovsext/Netlink/Netlink.c > @@ -112,6 +112,8 @@ NlBuildErrorMsg(POVS_MESSAGE msgIn, POVS_MESSAGE_ERROR > msgError, UINT errorCode) > { > NL_BUFFER nlBuffer; > > + ASSERT(errorCode != NL_ERROR_PENDING); > + > NlBufInit(&nlBuffer, (PCHAR)msgError, sizeof *msgError); > NlFillNlHdr(&nlBuffer, NLMSG_ERROR, 0, > msgIn->nlMsg.nlmsgSeq, msgIn->nlMsg.nlmsgPid); > diff --git a/datapath-windows/ovsext/Netlink/NetlinkError.h > b/datapath-windows/ovsext/Netlink/NetlinkError.h > index 53c935f..eefa89e 100644 > --- a/datapath-windows/ovsext/Netlink/NetlinkError.h > +++ b/datapath-windows/ovsext/Netlink/NetlinkError.h > @@ -195,14 +195,16 @@ typedef enum _NL_ERROR_ > NL_ERROR_TIMEDOUT = ((ULONG)-138), > /* The given text file is busy */ > NL_ERROR_TXTBSY = ((ULONG)-139), > - /*the operation would block */ > + /* The operation would block */ > NL_ERROR_WOULDBLOCK = ((ULONG)-140), > + /* The operation is not finished */ > + NL_ERROR_PENDING = ((ULONG)-141), > } NL_ERROR; > > static __inline > NlMapStatusToNlErr(NTSTATUS status) > { > - NL_ERROR ret = NL_ERROR_INVAL; > + NL_ERROR ret; > > switch (status) > { > @@ -215,7 +217,20 @@ NlMapStatusToNlErr(NTSTATUS status) > case STATUS_SUCCESS: > ret = NL_ERROR_SUCCESS; > break; > + case STATUS_PENDING: > + ret = NL_ERROR_PENDING; > + break; > + case STATUS_CANCELLED: > + ret = NL_ERROR_CANCELED; > + break; > + case STATUS_INVALID_PARAMETER: > + ret = NL_ERROR_INVAL; > + break; > + case STATUS_OBJECT_NAME_EXISTS: > + ret = NL_ERROR_EXIST; > + break; > default: > + ret = NL_ERROR_OTHER; > break; > } > > diff --git a/datapath-windows/ovsext/Switch.c > b/datapath-windows/ovsext/Switch.c > index 032153d..416bcc0 100644 > --- a/datapath-windows/ovsext/Switch.c > +++ b/datapath-windows/ovsext/Switch.c > @@ -263,8 +263,8 @@ OvsDeleteSwitch(POVS_SWITCH_CONTEXT switchContext) > if (switchContext) > { > dpNo = switchContext->dpNo; > - OvsUninitTunnelFilter(gOvsExtDriverObject); > OvsClearAllSwitchVports(switchContext); > + OvsUninitTunnelFilter(gOvsExtDriverObject); > OvsUninitSwitchContext(switchContext); > } > OVS_LOG_TRACE("Exit: deleted switch %p dpNo: %d", switchContext, dpNo); > diff --git a/datapath-windows/ovsext/Tunnel.h > b/datapath-windows/ovsext/Tunnel.h > index 2978bb3..2c45e35 100644 > --- a/datapath-windows/ovsext/Tunnel.h > +++ b/datapath-windows/ovsext/Tunnel.h > @@ -32,12 +32,6 @@ typedef struct OVS_TUNNEL_PENDED_PACKET_ > FWPS_CLASSIFY_OUT *classifyOut; > } OVS_TUNNEL_PENDED_PACKET; > > -/* Shared global data. */ > - > -extern UINT16 configNewDestPort; > - > -extern UINT32 gCalloutIdV4; > - > // > // Shared function prototypes > // > diff --git a/datapath-windows/ovsext/TunnelFilter.c > b/datapath-windows/ovsext/TunnelFilter.c > index c2186eb..00b3c0e 100644 > --- a/datapath-windows/ovsext/TunnelFilter.c > +++ b/datapath-windows/ovsext/TunnelFilter.c > @@ -48,27 +48,24 @@ > /* Infinite timeout */ > #define INFINITE 0xFFFFFFFF > > -/* > - * The provider name should always match the provider string from the install > - * file. > - */ > +/* The provider name should always match the provider string from the install > + * file. */ > #define OVS_TUNNEL_PROVIDER_NAME L"Open vSwitch" > > -/* > - * The provider description should always contain the OVS service description > - * string from the install file. > - */ > +/* The provider description should always contain the OVS service description > + * string from the install file. */ > #define OVS_TUNNEL_PROVIDER_DESC L"Open vSwitch Extension tunnel > provider" > > /* The session name isn't required but it's useful for diagnostics. */ > #define OVS_TUNNEL_SESSION_NAME L"OVS tunnel session" > > -/* Configurable parameters (addresses and ports are in host order) */ > -UINT16 configNewDestPort = VXLAN_UDP_PORT; > +/* Maximum number of tunnel threads to be created. */ > +#define OVS_TUNFLT_MAX_THREADS 8 > > /* > * Callout and sublayer GUIDs > */ > + > // b16b0a6e-2b2a-41a3-8b39-bd3ffc855ff8 > DEFINE_GUID( > OVS_TUNNEL_CALLOUT_V4, > @@ -106,41 +103,108 @@ DEFINE_GUID( > ); > > /* > - * Callout driver global variables > + * Callout driver type definitions > */ > -PDEVICE_OBJECT gDeviceObject; > +typedef enum _OVS_TUNFLT_OPERATION { > + OVS_TUN_FILTER_CREATE = 0, > + OVS_TUN_FILTER_DELETE > +} OVS_TUNFLT_OPERATION; > + > +typedef struct _OVS_TUNFLT_REQUEST { > + LIST_ENTRY entry; > + /* Tunnel filter destination port. */ > + UINT16 port; > + /* XXX: We also need to specify the tunnel L4 protocol, because there are > + * different protocols that can use the same destination port.*/ > + union { > + /* Tunnel filter identification used for filter deletion. */ > + UINT64 delID; > + /* Pointer used to return filter ID to the caller on filter > creation. */ > + PUINT64 addID; > + }filterID; > + /* Requested operation to be performed. */ > + OVS_TUNFLT_OPERATION operation; > + /* Current I/O request to be completed when requested > + * operation is finished. */ > + PIRP irp; > + /* Callback function called before completing the IRP. */ > + PFNTunnelVportPendingOp callback; > + /* Context passed to the callback function. */ > + PVOID context; > +} OVS_TUNFLT_REQUEST, *POVS_TUNFLT_REQUEST; > + > +typedef struct _OVS_TUNFLT_REQUEST_LIST { > + /* SpinLock for syncronizing access to the requests list. */ > + NDIS_SPIN_LOCK spinlock; > + /* Head of the requests list. */ > + LIST_ENTRY head; > + /* Number of requests in the list. This variable is used by > + * InterlockedCompareExchange function and needs to be aligned > + * at 32-bit boundaries. */ > + UINT32 numEntries; > +} OVS_TUNFLT_REQUEST_LIST, *POVS_TUNFLT_REQUEST_LIST; > + > +typedef struct _OVS_TUNFLT_THREAD_CONTEXT { > + /* Thread identification. */ > + UINT threadID; > + /* Thread's engine session handle. */ > + HANDLE engineSession; > + /* Reference of the thread object. */ > + PVOID threadObject; > + /* Requests queue list. */ > + OVS_TUNFLT_REQUEST_LIST listRequests; > + /* Event signaling that there are requests to process. */ > + KEVENT requestEvent; > + /* Event for stopping thread execution. */ > + KEVENT stopEvent; > +} OVS_TUNFLT_THREAD_CONTEXT, *POVS_TUNFLT_THREAD_CONTEXT; > + > +KSTART_ROUTINE OvsTunnelFilterThreadProc; > + > +static NTSTATUS OvsTunnelFilterStartThreads(); > +static NTSTATUS OvsTunnelFilterThreadStart(POVS_TUNFLT_THREAD_CONTEXT > threadCtx); > +static VOID OvsTunnelFilterStopThreads(); > +static VOID OvsTunnelFilterThreadStop(POVS_TUNFLT_THREAD_CONTEXT > threadCtx, > + BOOLEAN signalEvent); > +static NTSTATUS OvsTunnelFilterThreadInit(POVS_TUNFLT_THREAD_CONTEXT > threadCtx); > +static VOID OvsTunnelFilterThreadUninit(POVS_TUNFLT_THREAD_CONTEXT > threadCtx); > > -HANDLE gEngineHandle = NULL; > -HANDLE gTunnelProviderBfeHandle = NULL; > -HANDLE gTunnelInitBfeHandle = NULL; > -UINT32 gCalloutIdV4; > +/* > + * Callout driver global variables > + */ > > +static PDEVICE_OBJECT gDeviceObject = NULL; > +static HANDLE gEngineHandle = NULL; > +static HANDLE gTunnelProviderBfeHandle = NULL; > +static HANDLE gTunnelInitBfeHandle = NULL; > +static HANDLE gBfeSubscriptionHandle = NULL; > +static UINT32 gCalloutIdV4 = 0; > +static OVS_TUNFLT_THREAD_CONTEXT gTunnelThreadCtx[OVS_TUNFLT_MAX_THREADS] = > { 0 }; > > -/* Callout driver implementation */ > +/* > + * Callout driver implementation. > + */ > > NTSTATUS > -OvsTunnelEngineOpen(HANDLE *handle) > +OvsTunnelEngineOpen(HANDLE *engineSession) > { > NTSTATUS status = STATUS_SUCCESS; > FWPM_SESSION session = { 0 }; > > - /* The session name isn't required but may be useful for diagnostics. */ > - session.displayData.name = OVS_TUNNEL_SESSION_NAME; > /* > * Set an infinite wait timeout, so we don't have to handle FWP_E_TIMEOUT > * errors while waiting to acquire the transaction lock. > */ > session.txnWaitTimeoutInMSec = INFINITE; > - session.flags = FWPM_SESSION_FLAG_DYNAMIC; > > /* The authentication service should always be RPC_C_AUTHN_DEFAULT. */ > status = FwpmEngineOpen(NULL, > RPC_C_AUTHN_DEFAULT, > NULL, > &session, > - handle); > + engineSession); > if (!NT_SUCCESS(status)) { > - OVS_LOG_ERROR("Fail to open filtering engine session, status: %x.", > + OVS_LOG_ERROR("Failed to open filtering engine session, status: %x.", > status); > } > > @@ -148,23 +212,23 @@ OvsTunnelEngineOpen(HANDLE *handle) > } > > VOID > -OvsTunnelEngineClose(HANDLE *handle) > +OvsTunnelEngineClose(HANDLE *engineSession) > { > - if (*handle) { > - FwpmEngineClose(*handle); > - *handle = NULL; > + if (*engineSession) { > + FwpmEngineClose(*engineSession); > + *engineSession = NULL; > } > } > > VOID > -OvsTunnelAddSystemProvider(HANDLE handle) > +OvsTunnelAddSystemProvider(HANDLE engineSession) > { > NTSTATUS status = STATUS_SUCCESS; > BOOLEAN inTransaction = FALSE; > FWPM_PROVIDER provider = { 0 }; > > do { > - status = FwpmTransactionBegin(handle, 0); > + status = FwpmTransactionBegin(engineSession, 0); > if (!NT_SUCCESS(status)) { > break; > } > @@ -180,7 +244,7 @@ OvsTunnelAddSystemProvider(HANDLE handle) > */ > provider.flags = FWPM_PROVIDER_FLAG_PERSISTENT; > > - status = FwpmProviderAdd(handle, > + status = FwpmProviderAdd(engineSession, > &provider, > NULL); > if (!NT_SUCCESS(status)) { > @@ -191,7 +255,7 @@ OvsTunnelAddSystemProvider(HANDLE handle) > } > } > > - status = FwpmTransactionCommit(handle); > + status = FwpmTransactionCommit(engineSession); > if (!NT_SUCCESS(status)) { > break; > } > @@ -200,30 +264,30 @@ OvsTunnelAddSystemProvider(HANDLE handle) > } while (inTransaction); > > if (inTransaction){ > - FwpmTransactionAbort(handle); > + FwpmTransactionAbort(engineSession); > } > } > > VOID > -OvsTunnelRemoveSystemProvider(HANDLE handle) > +OvsTunnelRemoveSystemProvider(HANDLE engineSession) > { > NTSTATUS status = STATUS_SUCCESS; > BOOLEAN inTransaction = FALSE; > > do { > - status = FwpmTransactionBegin(handle, 0); > + status = FwpmTransactionBegin(engineSession, 0); > if (!NT_SUCCESS(status)) { > break; > } > inTransaction = TRUE; > > - status = FwpmProviderDeleteByKey(handle, > + status = FwpmProviderDeleteByKey(engineSession, > &OVS_TUNNEL_PROVIDER_KEY); > if (!NT_SUCCESS(status)) { > break; > } > > - status = FwpmTransactionCommit(handle); > + status = FwpmTransactionCommit(engineSession); > if (!NT_SUCCESS(status)) { > break; > } > @@ -232,29 +296,30 @@ OvsTunnelRemoveSystemProvider(HANDLE handle) > } while (inTransaction); > > if (inTransaction){ > - FwpmTransactionAbort(handle); > + FwpmTransactionAbort(engineSession); > } > } > > NTSTATUS > -OvsTunnelAddFilter(PWSTR filterName, > +OvsTunnelAddFilter(HANDLE engineSession, > + PWSTR filterName, > const PWSTR filterDesc, > USHORT remotePort, > FWP_DIRECTION direction, > UINT64 context, > const GUID *filterKey, > const GUID *layerKey, > - const GUID *calloutKey) > + const GUID *calloutKey, > + UINT64 *filterID) > { > NTSTATUS status = STATUS_SUCCESS; > FWPM_FILTER filter = {0}; > FWPM_FILTER_CONDITION filterConditions[3] = {0}; > UINT conditionIndex; > > - UNREFERENCED_PARAMETER(remotePort); > - UNREFERENCED_PARAMETER(direction); > - > - filter.filterKey = *filterKey; > + if (filterKey) { > + filter.filterKey = *filterKey; > + } > filter.layerKey = *layerKey; > filter.displayData.name = (wchar_t*)filterName; > filter.displayData.description = (wchar_t*)filterDesc; > @@ -284,64 +349,18 @@ OvsTunnelAddFilter(PWSTR filterName, > > filter.numFilterConditions = conditionIndex; > > - status = FwpmFilterAdd(gEngineHandle, > + status = FwpmFilterAdd(engineSession, > &filter, > NULL, > - NULL); > - > - return status; > -} > - > -NTSTATUS > -OvsTunnelRemoveFilter(const GUID *filterKey, > - const GUID *sublayerKey) > -{ > - NTSTATUS status = STATUS_SUCCESS; > - BOOLEAN inTransaction = FALSE; > - > - do { > - status = FwpmTransactionBegin(gEngineHandle, 0); > - if (!NT_SUCCESS(status)) { > - break; > - } > - > - inTransaction = TRUE; > - > - /* > - * We have to delete the filter first since it references the > - * sublayer. If we tried to delete the sublayer first, it would fail > - * with FWP_ERR_IN_USE. > - */ > - status = FwpmFilterDeleteByKey(gEngineHandle, > - filterKey); > - if (!NT_SUCCESS(status)) { > - break; > - } > - > - status = FwpmSubLayerDeleteByKey(gEngineHandle, > - sublayerKey); > - if (!NT_SUCCESS(status)) { > - break; > - } > + filterID); > > - status = FwpmTransactionCommit(gEngineHandle); > - if (!NT_SUCCESS(status)){ > - break; > - } > - > - inTransaction = FALSE; > - } while (inTransaction); > - > - if (inTransaction) { > - FwpmTransactionAbort(gEngineHandle); > - } > return status; > } > > /* > * -------------------------------------------------------------------------- > - * This function registers callouts and filters that intercept UDP traffic at > - * WFP FWPM_LAYER_DATAGRAM_DATA_V4 > + * This function registers callouts for intercepting UDP traffic at WFP > + * FWPM_LAYER_DATAGRAM_DATA_V4 layer. > * -------------------------------------------------------------------------- > */ > NTSTATUS > @@ -368,10 +387,7 @@ OvsTunnelRegisterDatagramDataCallouts(const GUID > *layerKey, > sCallout.flags = FWP_CALLOUT_FLAG_CONDITIONAL_ON_FLOW; > #endif > > - status = FwpsCalloutRegister(deviceObject, > - &sCallout, > - calloutId); > - > + status = FwpsCalloutRegister(deviceObject, &sCallout, calloutId); > if (!NT_SUCCESS(status)) { > goto Exit; > } > @@ -384,24 +400,11 @@ OvsTunnelRegisterDatagramDataCallouts(const GUID > *layerKey, > mCallout.displayData = displayData; > mCallout.applicableLayer = *layerKey; > > - status = FwpmCalloutAdd(gEngineHandle, > - &mCallout, > - NULL, > - NULL); > - > + status = FwpmCalloutAdd(gEngineHandle, &mCallout, NULL, NULL); > if (!NT_SUCCESS(status)) { > goto Exit; > } > > - status = OvsTunnelAddFilter(L"Datagram-Data OVS Filter (Inbound)", > - L"address/port for UDP", > - configNewDestPort, > - FWP_DIRECTION_INBOUND, > - 0, > - &OVS_TUNNEL_FILTER_KEY, > - layerKey, > - calloutKey); > - > Exit: > > if (!NT_SUCCESS(status)){ > @@ -416,24 +419,16 @@ Exit: > > /* > * -------------------------------------------------------------------------- > - * This function registers dynamic callouts and filters that intercept UDP > - * Callouts and filters will be removed during De-Initialize. > + * This function registers non-dynamic callouts for intercepting UDP traffic. > + * Callouts will be removed during un-initializing phase. > * -------------------------------------------------------------------------- > */ > NTSTATUS > OvsTunnelRegisterCallouts(VOID *deviceObject) > { > - NTSTATUS status = STATUS_SUCCESS; > - FWPM_SUBLAYER OvsTunnelSubLayer; > - > - BOOLEAN engineOpened = FALSE; > - BOOLEAN inTransaction = FALSE; > - > - status = OvsTunnelEngineOpen(&gEngineHandle); > - if (!NT_SUCCESS(status)) { > - goto Exit; > - } > - engineOpened = TRUE; > + NTSTATUS status = STATUS_SUCCESS; > + BOOLEAN inTransaction = FALSE; > + FWPM_SUBLAYER OvsTunnelSubLayer; > > status = FwpmTransactionBegin(gEngineHandle, 0); > if (!NT_SUCCESS(status)) { > @@ -476,22 +471,17 @@ Exit: > if (inTransaction) { > FwpmTransactionAbort(gEngineHandle); > } > - if (engineOpened) { > - OvsTunnelEngineClose(&gEngineHandle); > - } > } > > return status; > } > > VOID > -OvsTunnelUnregisterCallouts(VOID) > +OvsTunnelUnregisterCallouts() > { > - OvsTunnelRemoveFilter(&OVS_TUNNEL_FILTER_KEY, > - &OVS_TUNNEL_SUBLAYER); > FwpsCalloutUnregisterById(gCalloutIdV4); > + FwpmSubLayerDeleteByKey(gEngineHandle, &OVS_TUNNEL_SUBLAYER); > FwpmCalloutDeleteById(gEngineHandle, gCalloutIdV4); > - OvsTunnelEngineClose(&gEngineHandle); > } > > VOID > @@ -499,16 +489,22 @@ OvsTunnelFilterUninitialize(PDRIVER_OBJECT driverObject) > { > UNREFERENCED_PARAMETER(driverObject); > > + OvsTunnelFilterStopThreads(); > + > OvsTunnelUnregisterCallouts(); > - IoDeleteDevice(gDeviceObject); > + OvsTunnelEngineClose(&gEngineHandle); > + > + if (gDeviceObject) { > + IoDeleteDevice(gDeviceObject); > + } > } > > > NTSTATUS > OvsTunnelFilterInitialize(PDRIVER_OBJECT driverObject) > { > - NTSTATUS status = STATUS_SUCCESS; > - UNICODE_STRING deviceName; > + NTSTATUS status = STATUS_SUCCESS; > + UNICODE_STRING deviceName; > > RtlInitUnicodeString(&deviceName, > L"\\Device\\OvsTunnelFilter"); > @@ -522,21 +518,31 @@ OvsTunnelFilterInitialize(PDRIVER_OBJECT driverObject) > &gDeviceObject); > > if (!NT_SUCCESS(status)){ > + OVS_LOG_ERROR("Failed to create tunnel filter device, status: %x.", > + status); > + goto Exit; > + } > + > + status = OvsTunnelFilterStartThreads(); > + if (!NT_SUCCESS(status)){ > + goto Exit; > + } > + > + status = OvsTunnelEngineOpen(&gEngineHandle); > + if (!NT_SUCCESS(status)){ > goto Exit; > } > > status = OvsTunnelRegisterCallouts(gDeviceObject); > + if (!NT_SUCCESS(status)) { > + OVS_LOG_ERROR("Failed to register callout, status: %x.", > + status); > + } > > Exit: > > if (!NT_SUCCESS(status)){ > - if (gEngineHandle != NULL) { > - OvsTunnelUnregisterCallouts(); > - } > - > - if (gDeviceObject) { > - IoDeleteDevice(gDeviceObject); > - } > + OvsTunnelFilterUninitialize(driverObject); > } > > return status; > @@ -546,16 +552,16 @@ VOID NTAPI > OvsTunnelProviderBfeCallback(PVOID context, > FWPM_SERVICE_STATE bfeState) > { > - HANDLE handle = NULL; > + HANDLE engineSession = NULL; > > DBG_UNREFERENCED_PARAMETER(context); > > if (FWPM_SERVICE_RUNNING == bfeState) { > - OvsTunnelEngineOpen(&handle); > - if (handle) { > - OvsTunnelAddSystemProvider(handle); > + OvsTunnelEngineOpen(&engineSession); > + if (engineSession) { > + OvsTunnelAddSystemProvider(engineSession); > } > - OvsTunnelEngineClose(&handle); > + OvsTunnelEngineClose(&engineSession); > } > } > > @@ -599,16 +605,16 @@ VOID > OvsRegisterSystemProvider(PVOID deviceObject) > { > NTSTATUS status = STATUS_SUCCESS; > - HANDLE handle = NULL; > + HANDLE engineSession = NULL; > > status = OvsSubscribeTunnelProviderBfeStateChanges(deviceObject); > if (NT_SUCCESS(status)) { > if (FWPM_SERVICE_RUNNING == FwpmBfeStateGet()) { > - OvsTunnelEngineOpen(&handle); > - if (handle) { > - OvsTunnelAddSystemProvider(handle); > + OvsTunnelEngineOpen(&engineSession); > + if (engineSession) { > + OvsTunnelAddSystemProvider(engineSession); > } > - OvsTunnelEngineClose(&handle); > + OvsTunnelEngineClose(&engineSession); > > OvsUnsubscribeTunnelProviderBfeStateChanges(); > } > @@ -617,13 +623,13 @@ OvsRegisterSystemProvider(PVOID deviceObject) > > VOID OvsUnregisterSystemProvider() > { > - HANDLE handle = NULL; > + HANDLE engineSession = NULL; > > - OvsTunnelEngineOpen(&handle); > - if (handle) { > - OvsTunnelRemoveSystemProvider(handle); > + OvsTunnelEngineOpen(&engineSession); > + if (engineSession) { > + OvsTunnelRemoveSystemProvider(engineSession); > } > - OvsTunnelEngineClose(&handle); > + OvsTunnelEngineClose(&engineSession); > > OvsUnsubscribeTunnelProviderBfeStateChanges(); > } > @@ -711,3 +717,566 @@ VOID OvsUninitTunnelFilter(PDRIVER_OBJECT driverObject) > OvsTunnelFilterUninitialize(driverObject); > OvsUnsubscribeTunnelInitBfeStateChanges(); > } > + > +NTSTATUS > +OvsTunnelAddFilterEx(HANDLE engineSession, > + UINT32 filterPort, > + UINT64 *filterID) > +{ > + NTSTATUS status = STATUS_SUCCESS; > + > + status = OvsTunnelAddFilter(engineSession, > + L"Datagram-Data OVS Filter (Inbound)", > + L"address/port for UDP", > + (USHORT)filterPort, > + FWP_DIRECTION_INBOUND, > + 0, > + NULL, > + &FWPM_LAYER_DATAGRAM_DATA_V4, > + &OVS_TUNNEL_CALLOUT_V4, > + filterID); > + if (!NT_SUCCESS(status)) { > + OVS_LOG_ERROR("Failed to add tunnel filter for port: %d, status: > %x.", > + filterPort, status); > + } else { > + OVS_LOG_INFO("Filter added, filter port: %d, filter ID: %d.", > + filterPort, *filterID); > + } > + > + return status; > +} > + > +NTSTATUS > +OvsTunnelRemoveFilterEx(HANDLE engineSession, > + UINT64 filterID) > +{ > + NTSTATUS status = STATUS_SUCCESS; > + BOOLEAN error = TRUE; > + > + do { > + if (filterID == 0) { > + OVS_LOG_INFO("No tunnel filter to remove."); > + break; > + } > + > + status = FwpmFilterDeleteById(engineSession, filterID); > + if (!NT_SUCCESS(status)) { > + OVS_LOG_ERROR("Failed to remove tunnel with filter ID: %d,\ > + status: %x.", filterID, status); > + break; > + } > + OVS_LOG_INFO("Filter removed, filter ID: %d.", > + filterID); > + > + error = FALSE; > + } while (error); > + > + return status; > +} > + > +NTSTATUS > +OvsTunnelFilterExecuteAction(HANDLE engineSession, > + POVS_TUNFLT_REQUEST request) > +{ > + NTSTATUS status = STATUS_SUCCESS; > + > + switch (request->operation) > + { > + case OVS_TUN_FILTER_CREATE: > + status = OvsTunnelAddFilterEx(engineSession, > + request->port, > + request->filterID.addID); > + break; > + case OVS_TUN_FILTER_DELETE: > + status = OvsTunnelRemoveFilterEx(engineSession, > + request->filterID.delID); > + break; > + default: > + status = STATUS_NOT_SUPPORTED; > + break; > + } > + > + return status; > +} > + > +VOID > +OvsTunnelFilterRequestPopList(POVS_TUNFLT_REQUEST_LIST listRequests, > + PLIST_ENTRY head, > + UINT32 *count) > +{ > + NdisAcquireSpinLock(&listRequests->spinlock); > + > + if (!IsListEmpty(&listRequests->head)) { > + PLIST_ENTRY PrevEntry; > + PLIST_ENTRY NextEntry; > + > + NextEntry = listRequests->head.Flink; > + PrevEntry = listRequests->head.Blink; > + > + head->Flink = NextEntry; > + NextEntry->Blink = head; > + > + head->Blink = PrevEntry; > + PrevEntry->Flink = head; > + > + *count = listRequests->numEntries; > + > + InitializeListHead(&listRequests->head); > + listRequests->numEntries = 0; > + } > + > + NdisReleaseSpinLock(&listRequests->spinlock); > +} > + > +VOID > +OvsTunnelFilterRequestPush(POVS_TUNFLT_REQUEST_LIST listRequests, > + POVS_TUNFLT_REQUEST request) > +{ > + NdisAcquireSpinLock(&listRequests->spinlock); > + > + InsertTailList(&listRequests->head, &(request->entry)); > + listRequests->numEntries++; > + > + NdisReleaseSpinLock(&listRequests->spinlock); > +} > + > +VOID > +OvsTunnelFilterThreadPush(POVS_TUNFLT_REQUEST request) > +{ > + UINT32 threadIndex; > + > + threadIndex = request->port % OVS_TUNFLT_MAX_THREADS; > + > + OvsTunnelFilterRequestPush( > + &gTunnelThreadCtx[threadIndex].listRequests, > + request); > + > + KeSetEvent(&gTunnelThreadCtx[threadIndex].requestEvent, > + IO_NO_INCREMENT, > + FALSE); > +} > + > +VOID > +OvsTunnelFilterCompleteRequest(PIRP irp, > + PFNTunnelVportPendingOp callback, > + PVOID context, > + NTSTATUS status) > +{ > + UINT32 replyLen = 0; > + > + if (callback) { > + callback(context, status, &replyLen); > + /* Release the context passed to the callback function. */ > + OvsFreeMemory(context); > + } > + > + if (irp) { > + OvsCompleteIrpRequest(irp, (ULONG_PTR)replyLen, status); > + } > +} > + > +VOID > +OvsTunnelFilterRequestListProcess(POVS_TUNFLT_THREAD_CONTEXT threadCtx) > +{ > + POVS_TUNFLT_REQUEST request = NULL; > + PLIST_ENTRY link = NULL; > + PLIST_ENTRY next = NULL; > + LIST_ENTRY head; > + NTSTATUS status = STATUS_SUCCESS; > + UINT32 count = 0; > + BOOLEAN inTransaction = FALSE; > + BOOLEAN error = TRUE; > + > + do > + { > + if (!InterlockedCompareExchange( > + (LONG volatile *)&threadCtx->listRequests.numEntries, 0, 0)) { > + OVS_LOG_INFO("Nothing to do... request list is empty."); > + break; > + } > + > + status = FwpmTransactionBegin(threadCtx->engineSession, 0); > + if (!NT_SUCCESS(status)) { > + OVS_LOG_ERROR("Failed to start transaction, status: %x.", > + status); > + break; > + } > + inTransaction = TRUE; > + > + InitializeListHead(&head); > + OvsTunnelFilterRequestPopList(&threadCtx->listRequests, &head, > &count); > + > + LIST_FORALL_SAFE(&head, link, next) { > + request = CONTAINING_RECORD(link, OVS_TUNFLT_REQUEST, entry); > + > + status = OvsTunnelFilterExecuteAction(threadCtx->engineSession, > + request); > + if (!NT_SUCCESS(status)) { > + RemoveEntryList(&request->entry); > + count--; > + > + /* Complete the IRP with the failure status. */ > + OvsTunnelFilterCompleteRequest(request->irp, > + request->callback, > + request->context, > + status); > + OvsFreeMemory(request); > + request = NULL; > + } else { > + error = FALSE; > + } > + } > + > + if (error) { > + /* No successful requests were made, so there is no point to > commit > + * the transaction. */ > + break; > + } > + > + status = FwpmTransactionCommit(threadCtx->engineSession); > + if (!NT_SUCCESS(status)){ > + OVS_LOG_ERROR("Failed to commit transaction, status: %x.", > + status); > + break; > + } > + > + inTransaction = FALSE; > + } while (inTransaction); > + > + if (inTransaction) { > + FwpmTransactionAbort(threadCtx->engineSession); > + OVS_LOG_ERROR("Failed to execute request, status: %x.\ > + Transaction aborted.", status); > + } > + > + /* Complete the requests successfully executed with the transaction > commit > + * status. */ > + while (count) { > + request = (POVS_TUNFLT_REQUEST)RemoveHeadList(&head); > + count--; > + > + OvsTunnelFilterCompleteRequest(request->irp, > + request->callback, > + request->context, > + status); > + OvsFreeMemory(request); > + request = NULL; > + } > +} > + > +/* > + > *---------------------------------------------------------------------------- > + * System thread routine that handles tunnel filter create/delete requests. > + > *---------------------------------------------------------------------------- > + */ > +_Use_decl_annotations_ > +VOID > +OvsTunnelFilterThreadProc(PVOID context) > +{ > + NTSTATUS status = STATUS_SUCCESS; > + POVS_TUNFLT_THREAD_CONTEXT threadCtx = > (POVS_TUNFLT_THREAD_CONTEXT)context; > + PKEVENT eventArray[2] = { 0 }; > + ULONG count = 0; > + BOOLEAN exit = FALSE; > + BOOLEAN error = TRUE; > + > + OVS_LOG_INFO("Starting OVS Tunnel system thread %d.", > + threadCtx->threadID); > + > + eventArray[0] = &threadCtx->stopEvent; > + eventArray[1] = &threadCtx->requestEvent; > + count = ARRAY_SIZE(eventArray); > + > + do { > + status = OvsTunnelFilterThreadInit(threadCtx); > + if (!NT_SUCCESS(status)) { > + OVS_LOG_ERROR("Failed to initialize tunnel filter thread %d.", > + threadCtx->threadID); > + break; > + } > + > + do { > + status = KeWaitForMultipleObjects(count, > + (PVOID)eventArray, > + WaitAny, > + Executive, > + KernelMode, > + FALSE, > + NULL, > + NULL); > + switch (status) { > + case STATUS_WAIT_1: > + /* Start processing requests. */ > + OvsTunnelFilterRequestListProcess(threadCtx); > + break; > + default: > + /* Finish processing the received requests and exit. */ > + OvsTunnelFilterRequestListProcess(threadCtx); > + exit = TRUE; > + break; > + } > + } while (!exit); > + > + OvsTunnelFilterThreadUninit(threadCtx); > + > + error = FALSE; > + } while (error); > + > + OVS_LOG_INFO("Terminating OVS Tunnel system thread %d.", > + threadCtx->threadID); > + > + PsTerminateSystemThread(STATUS_SUCCESS); > +}; > + > +static NTSTATUS > +OvsTunnelFilterStartThreads() > +{ > + NTSTATUS status = STATUS_SUCCESS; > + > + for (UINT index = 0; index < OVS_TUNFLT_MAX_THREADS; index++) { > + gTunnelThreadCtx[index].threadID = index; > + > + status = OvsTunnelFilterThreadStart(&gTunnelThreadCtx[index]); > + if (!NT_SUCCESS(status)) { > + OVS_LOG_ERROR("Failed to start tunnel filter thread %d.", index); > + break; > + } > + } > + > + return status; > +} > + > +static NTSTATUS > +OvsTunnelFilterThreadStart(POVS_TUNFLT_THREAD_CONTEXT threadCtx) > +{ > + NTSTATUS status = STATUS_SUCCESS; > + HANDLE threadHandle = NULL; > + BOOLEAN error = TRUE; > + > + do { > + status = PsCreateSystemThread(&threadHandle, > + SYNCHRONIZE, > + NULL, > + NULL, > + NULL, > + OvsTunnelFilterThreadProc, > + threadCtx); > + if (!NT_SUCCESS(status)) { > + OVS_LOG_ERROR("Failed to create tunnel thread, status: %x.", > + status); > + break; > + } > + > + ObReferenceObjectByHandle(threadHandle, > + SYNCHRONIZE, > + NULL, > + KernelMode, > + &threadCtx->threadObject, > + NULL); > + ZwClose(threadHandle); > + threadHandle = NULL; > + > + error = FALSE; > + } while (error); > + > + return status; > +} > + > +static VOID > +OvsTunnelFilterStopThreads() > +{ > + /* Signal all threads to stop and ignore all subsequent requests. */ > + for (UINT index = 0; index < OVS_TUNFLT_MAX_THREADS; index++) { > + OvsTunnelFilterThreadStop(&gTunnelThreadCtx[index], TRUE); > + } > + > + /* Wait for all threads to finish processing the requests. */ > + for (UINT index = 0; index < OVS_TUNFLT_MAX_THREADS; index++) { > + OvsTunnelFilterThreadStop(&gTunnelThreadCtx[index], FALSE); > + } > +} > + > +static VOID > +OvsTunnelFilterThreadStop(POVS_TUNFLT_THREAD_CONTEXT threadCtx, > + BOOLEAN signalEvent) > +{ > + if (signalEvent) { > + /* Signal stop thread event. */ > + OVS_LOG_INFO("Received stop event for OVS Tunnel system thread %d.", > + threadCtx->threadID); > + KeSetEvent(&threadCtx->stopEvent, IO_NO_INCREMENT, FALSE); > + } else { > + /* Wait for the tunnel thread to finish. */ > + KeWaitForSingleObject(threadCtx->threadObject, > + Executive, > + KernelMode, > + FALSE, > + NULL); > + > + ObDereferenceObject(threadCtx->threadObject); > + } > +} > + > +static NTSTATUS > +OvsTunnelFilterThreadInit(POVS_TUNFLT_THREAD_CONTEXT threadCtx) > +{ > + NTSTATUS status = STATUS_SUCCESS; > + BOOLEAN error = TRUE; > + > + do { > + /* Create thread's engine session object. */ > + status = OvsTunnelEngineOpen(&threadCtx->engineSession); > + if (!NT_SUCCESS(status)) { > + break; > + } > + > + NdisAllocateSpinLock(&threadCtx->listRequests.spinlock); > + > + InitializeListHead(&threadCtx->listRequests.head); > + > + KeInitializeEvent(&threadCtx->stopEvent, > + NotificationEvent, > + FALSE); > + > + KeInitializeEvent(&threadCtx->requestEvent, > + SynchronizationEvent, > + FALSE); > + > + error = FALSE; > + } while (error); > + > + return status; > +} > + > +static VOID > +OvsTunnelFilterThreadUninit(POVS_TUNFLT_THREAD_CONTEXT threadCtx) > +{ > + if (threadCtx->engineSession) { > + /* Close thread's FWPM session. */ > + OvsTunnelEngineClose(&threadCtx->engineSession); > + > + NdisFreeSpinLock(&threadCtx->listRequests.spinlock); > + } > +} > + > +NTSTATUS > +OvsTunnelFilterQueueRequest(PIRP irp, > + UINT16 remotePort, > + UINT64 *filterID, > + OVS_TUNFLT_OPERATION operation, > + PFNTunnelVportPendingOp callback, > + PVOID tunnelContext) > +{ > + POVS_TUNFLT_REQUEST request = NULL; > + NTSTATUS status = STATUS_PENDING; > + BOOLEAN error = TRUE; > + UINT64 timeout = 0; > + > + do { > + /* Verify if the stop event was signaled. */ > + if (STATUS_SUCCESS == KeWaitForSingleObject( > + &gTunnelThreadCtx[0].stopEvent, > + Executive, > + KernelMode, > + FALSE, > + (LARGE_INTEGER *)&timeout)) { > + /* The stop event is signaled. Completed the IRP with > + * STATUS_CANCELLED. */ > + status = STATUS_CANCELLED; > + break; > + } > + > + if (NULL == filterID) { > + OVS_LOG_ERROR("Invalid request."); > + status = STATUS_INVALID_PARAMETER; > + break; > + } > + > + request = (POVS_TUNFLT_REQUEST) OvsAllocateMemory(sizeof(*request)); > + if (NULL == request) { > + OVS_LOG_ERROR("Failed to allocate list item."); > + status = STATUS_INSUFFICIENT_RESOURCES; > + break; > + } > + > + request->port = remotePort; > + request->operation = operation; > + switch (operation) { > + case OVS_TUN_FILTER_CREATE: > + request->filterID.addID = filterID; > + break; > + case OVS_TUN_FILTER_DELETE: > + request->filterID.delID = *filterID; > + break; > + } > + request->irp = irp; > + request->callback = callback; > + request->context = tunnelContext; > + > + OvsTunnelFilterThreadPush(request); > + > + error = FALSE; > + } while (error); > + > + if (error) { > + OvsTunnelFilterCompleteRequest(irp, callback, tunnelContext, status); > + if (request) { > + OvsFreeMemory(request); > + request = NULL; > + } > + } > + > + return status; > +} > + > +/* > + * -------------------------------------------------------------------------- > + * This function adds a new WFP filter for the received port and returns the > + * ID of the created WFP filter. > + * > + * Note: > + * All necessary calls to the WFP filtering engine must be running at IRQL = > + * PASSIVE_LEVEL. Because the function is called at IRQL = DISPATCH_LEVEL, > + * we register an OVS_TUN_FILTER_CREATE request that will be processed by > + * the tunnel filter thread routine at IRQL = PASSIVE_LEVEL. > + * -------------------------------------------------------------------------- > + */ > +NTSTATUS > +OvsTunelFilterCreate(PIRP irp, > + UINT16 filterPort, > + UINT64 *filterID, > + PFNTunnelVportPendingOp callback, > + PVOID tunnelContext) > +{ > + return OvsTunnelFilterQueueRequest(irp, > + filterPort, > + filterID, > + OVS_TUN_FILTER_CREATE, > + callback, > + tunnelContext); > +} > + > +/* > + * -------------------------------------------------------------------------- > + * This function removes a WFP filter using the received filter ID. > + * > + * Note: > + * All necessary calls to the WFP filtering engine must be running at IRQL = > + * PASSIVE_LEVEL. Because the function is called at IRQL = DISPATCH_LEVEL, > + * we register an OVS_TUN_FILTER_DELETE request that will be processed by > + * the tunnel filter thread routine at IRQL = PASSIVE_LEVEL. > + * -------------------------------------------------------------------------- > + */ > +NTSTATUS > +OvsTunelFilterDelete(PIRP irp, > + UINT64 filterID, > + PFNTunnelVportPendingOp callback, > + PVOID tunnelContext) > +{ > + return OvsTunnelFilterQueueRequest(irp, > + 0, > + &filterID, > + OVS_TUN_FILTER_DELETE, > + callback, > + tunnelContext); > +} > diff --git a/datapath-windows/ovsext/TunnelIntf.h > b/datapath-windows/ovsext/TunnelIntf.h > index 82a5145..eb8c1d5 100644 > --- a/datapath-windows/ovsext/TunnelIntf.h > +++ b/datapath-windows/ovsext/TunnelIntf.h > @@ -17,6 +17,10 @@ > #ifndef __TUNNEL_INTF_H_ > #define __TUNNEL_INTF_H_ 1 > > +typedef VOID(*PFNTunnelVportPendingOp)(PVOID context, > + NTSTATUS status, > + UINT32 *replyLen); > + > /* Tunnel callout driver load/unload functions */ > NTSTATUS OvsInitTunnelFilter(PDRIVER_OBJECT driverObject, PVOID > deviceObject); > > @@ -26,4 +30,15 @@ VOID OvsRegisterSystemProvider(PVOID deviceObject); > > VOID OvsUnregisterSystemProvider(); > > +NTSTATUS OvsTunelFilterCreate(PIRP irp, > + UINT16 filterPort, > + UINT64 *filterID, > + PFNTunnelVportPendingOp callback, > + PVOID context); > + > +NTSTATUS OvsTunelFilterDelete(PIRP irp, > + UINT64 filterID, > + PFNTunnelVportPendingOp callback, > + PVOID context); > + > #endif /* __TUNNEL_INTF_H_ */ > diff --git a/datapath-windows/ovsext/Vport.c b/datapath-windows/ovsext/Vport.c > index 1423ace..66f9189 100644 > --- a/datapath-windows/ovsext/Vport.c > +++ b/datapath-windows/ovsext/Vport.c > @@ -47,6 +47,20 @@ > > #define OVS_VPORT_DEFAULT_WAIT_TIME_MICROSEC 100 > > +/* Context structure used to pass back and forth information to the tunnel > + * filter threads. */ > +typedef struct _OVS_TUNFLT_INIT_CONTEXT { > + POVS_SWITCH_CONTEXT switchContext; > + UINT32 outputLength; > + PVOID outputBuffer; > + PVOID inputBuffer; > + POVS_VPORT_ENTRY vport; > + BOOLEAN hvSwitchPort; > + BOOLEAN hvDelete; > + BOOLEAN ovsDelete; > +} OVS_TUNFLT_INIT_CONTEXT, *POVS_TUNFLT_INIT_CONTEXT; > + > + > extern POVS_SWITCH_CONTEXT gOvsSwitchContext; > > static VOID OvsInitVportWithPortParam(POVS_VPORT_ENTRY vport, > @@ -69,6 +83,18 @@ static POVS_VPORT_ENTRY > OvsFindVportByHvNameW(POVS_SWITCH_CONTEXT switchContext, > static NDIS_STATUS InitHvVportCommon(POVS_SWITCH_CONTEXT switchContext, > POVS_VPORT_ENTRY vport, > BOOLEAN newPort); > +static VOID OvsCleanupVportCommon(POVS_SWITCH_CONTEXT switchContext, > + POVS_VPORT_ENTRY vport, > + BOOLEAN hvSwitchPort, > + BOOLEAN hvDelete, > + BOOLEAN ovsDelete); > +static VOID OvsTunnelVportPendingInit(PVOID context, > + NTSTATUS status, > + UINT32 *replyLen); > +static VOID OvsTunnelVportPendingUninit(PVOID context, > + NTSTATUS status, > + UINT32 *replyLen); > + > > /* > * Functions implemented in relaton to NDIS port manipulation. > @@ -246,7 +272,7 @@ HvDeletePort(POVS_SWITCH_CONTEXT switchContext, > * delete will delete the vport. > */ > if (vport) { > - OvsRemoveAndDeleteVport(switchContext, vport, TRUE, FALSE, NULL); > + OvsRemoveAndDeleteVport(NULL, switchContext, vport, TRUE, FALSE); > } else { > OVS_LOG_WARN("Vport not present."); > } > @@ -534,13 +560,14 @@ HvDeleteNic(POVS_SWITCH_CONTEXT switchContext, > goto done; > } > > + vport->nicState = NdisSwitchNicStateUnknown; > + vport->ovsState = OVS_STATE_PORT_CREATED; > + > portNo = vport->portNo; > if (vport->portType == NdisSwitchPortTypeExternal && > vport->nicIndex != 0) { > - OvsRemoveAndDeleteVport(switchContext, vport, TRUE, FALSE, NULL); > + OvsRemoveAndDeleteVport(NULL, switchContext, vport, TRUE, FALSE); > } > - vport->nicState = NdisSwitchNicStateUnknown; > - vport->ovsState = OVS_STATE_PORT_CREATED; > > NdisReleaseRWLock(switchContext->dispatchLock, &lockState); > /* XXX if portNo != INVALID or always? */ > @@ -850,11 +877,14 @@ OvsInitPhysNicVport(POVS_VPORT_ENTRY physExtVport, > * -------------------------------------------------------------------------- > */ > NTSTATUS > -OvsInitTunnelVport(POVS_VPORT_ENTRY vport, > +OvsInitTunnelVport(PVOID userContext, > + POVS_VPORT_ENTRY vport, > OVS_VPORT_TYPE ovsType, > UINT16 dstPort) > { > NTSTATUS status = STATUS_SUCCESS; > + POVS_USER_PARAMS_CONTEXT usrParamsCtx = > + (POVS_USER_PARAMS_CONTEXT)userContext; > > vport->isBridgeInternal = FALSE; > vport->ovsType = ovsType; > @@ -865,8 +895,26 @@ OvsInitTunnelVport(POVS_VPORT_ENTRY vport, > case OVS_VPORT_TYPE_GRE64: > break; > case OVS_VPORT_TYPE_VXLAN: > - status = OvsInitVxlanTunnel(vport, dstPort); > + { > + POVS_TUNFLT_INIT_CONTEXT tunnelContext = NULL; > + > + tunnelContext = OvsAllocateMemory(sizeof(*tunnelContext)); > + if (tunnelContext == NULL) { > + status = STATUS_INSUFFICIENT_RESOURCES; > + break; > + } > + tunnelContext->inputBuffer = usrParamsCtx->inputBuffer; > + tunnelContext->outputBuffer = usrParamsCtx->outputBuffer; > + tunnelContext->outputLength = usrParamsCtx->outputLength; > + tunnelContext->vport = vport; > + > + status = OvsInitVxlanTunnel(usrParamsCtx->irp, > + vport, > + dstPort, > + OvsTunnelVportPendingInit, > + (PVOID)tunnelContext); > break; > + } > default: > ASSERT(0); > } > @@ -1012,7 +1060,6 @@ InitOvsVportCommon(POVS_SWITCH_CONTEXT switchContext, > > switch(vport->ovsType) { > case OVS_VPORT_TYPE_VXLAN: > - ASSERT(switchContext->vxlanVport == NULL); > switchContext->vxlanVport = vport; > switchContext->numNonHvVports++; > break; > @@ -1043,6 +1090,64 @@ InitOvsVportCommon(POVS_SWITCH_CONTEXT switchContext, > return STATUS_SUCCESS; > } > > +static VOID > +OvsCleanupVportCommon(POVS_SWITCH_CONTEXT switchContext, > + POVS_VPORT_ENTRY vport, > + BOOLEAN hvSwitchPort, > + BOOLEAN hvDelete, > + BOOLEAN ovsDelete) > +{ > + BOOLEAN deletedOnOvs = FALSE; > + BOOLEAN deletedOnHv = FALSE; > + > + /* > + * 'hvDelete' == TRUE indicates that the port should be removed from the > + * 'portIdHashArray', while 'ovsDelete' == TRUE indicates that the port > + * should be removed from 'portNoHashArray' and the > 'ovsPortNameHashArray'. > + * > + * Both 'hvDelete' and 'ovsDelete' can be set to TRUE by the caller. > + */ > + if (vport->isPresentOnHv == TRUE) { > + deletedOnHv = TRUE; > + } > + if (vport->portNo == OVS_DPPORT_NUMBER_INVALID) { > + deletedOnOvs = TRUE; > + } > + > + if (hvDelete && !deletedOnHv) { > + vport->isPresentOnHv = TRUE; > + > + /* Remove the port from the relevant lists. */ > + RemoveEntryList(&vport->portIdLink); > + InitializeListHead(&vport->portIdLink); > + deletedOnHv = TRUE; > + } > + if (ovsDelete && !deletedOnOvs) { > + vport->portNo = OVS_DPPORT_NUMBER_INVALID; > + vport->ovsName[0] = '\0'; > + > + /* Remove the port from the relevant lists. */ > + RemoveEntryList(&vport->ovsNameLink); > + InitializeListHead(&vport->ovsNameLink); > + RemoveEntryList(&vport->portNoLink); > + InitializeListHead(&vport->portNoLink); > + deletedOnOvs = TRUE; > + } > + > + /* > + * Deallocate the port if it has been deleted on the Hyper-V switch as > well > + * as OVS userspace. > + */ > + if (deletedOnHv && deletedOnOvs) { > + if (hvSwitchPort) { > + switchContext->numHvVports--; > + } > + else { > + switchContext->numNonHvVports--; > + } > + OvsFreeMemoryWithTag(vport, OVS_VPORT_POOL_TAG); > + } > +} > > /* > * -------------------------------------------------------------------------- > @@ -1055,19 +1160,17 @@ InitOvsVportCommon(POVS_SWITCH_CONTEXT switchContext, > * port being removed from OVS userspace. > * -------------------------------------------------------------------------- > */ > -VOID > -OvsRemoveAndDeleteVport(POVS_SWITCH_CONTEXT switchContext, > +NTSTATUS > +OvsRemoveAndDeleteVport(PVOID usrParamsContext, > + POVS_SWITCH_CONTEXT switchContext, > POVS_VPORT_ENTRY vport, > BOOLEAN hvDelete, > - BOOLEAN ovsDelete, > - BOOLEAN *vportDeallocated) > + BOOLEAN ovsDelete) > { > + NTSTATUS status = STATUS_SUCCESS; > + POVS_USER_PARAMS_CONTEXT usrParamsCtx = > + (POVS_USER_PARAMS_CONTEXT)usrParamsContext; > BOOLEAN hvSwitchPort = FALSE; > - BOOLEAN deletedOnOvs = FALSE, deletedOnHv = FALSE; > - > - if (vportDeallocated) { > - *vportDeallocated = FALSE; > - } > > if (vport->isExternal) { > if (vport->nicIndex == 0) { > @@ -1075,10 +1178,7 @@ OvsRemoveAndDeleteVport(POVS_SWITCH_CONTEXT > switchContext, > switchContext->virtualExternalPortId = 0; > switchContext->virtualExternalVport = NULL; > OvsFreeMemoryWithTag(vport, OVS_VPORT_POOL_TAG); > - if (vportDeallocated) { > - *vportDeallocated = TRUE; > - } > - return; > + return STATUS_SUCCESS; > } else { > ASSERT(switchContext->numPhysicalNics); > switchContext->numPhysicalNics--; > @@ -1096,9 +1196,38 @@ OvsRemoveAndDeleteVport(POVS_SWITCH_CONTEXT > switchContext, > } > break; > case OVS_VPORT_TYPE_VXLAN: > - OvsCleanupVxlanTunnel(vport); > + { > + POVS_TUNFLT_INIT_CONTEXT tunnelContext = NULL; > + PIRP irp = NULL; > + > + tunnelContext = OvsAllocateMemory(sizeof(*tunnelContext)); > + if (tunnelContext == NULL) { > + status = STATUS_INSUFFICIENT_RESOURCES; > + break; > + } > + RtlZeroMemory(tunnelContext, sizeof(*tunnelContext)); > + > + tunnelContext->switchContext = switchContext; > + tunnelContext->hvSwitchPort = hvSwitchPort; > + tunnelContext->hvDelete = hvDelete; > + tunnelContext->ovsDelete = ovsDelete; > + tunnelContext->vport = vport; > + > + if (usrParamsCtx) { > + tunnelContext->inputBuffer = usrParamsCtx->inputBuffer; > + tunnelContext->outputBuffer = usrParamsCtx->outputBuffer; > + tunnelContext->outputLength = usrParamsCtx->outputLength; > + irp = usrParamsCtx->irp; > + } > + > + status = OvsCleanupVxlanTunnel(irp, > + vport, > + OvsTunnelVportPendingUninit, > + tunnelContext); > + > switchContext->vxlanVport = NULL; > break; > + } > case OVS_VPORT_TYPE_GRE: > case OVS_VPORT_TYPE_GRE64: > break; > @@ -1108,55 +1237,15 @@ OvsRemoveAndDeleteVport(POVS_SWITCH_CONTEXT > switchContext, > break; > } > > - /* > - * 'hvDelete' == TRUE indicates that the port should be removed from the > - * 'portIdHashArray', while 'ovsDelete' == TRUE indicates that the port > - * should be removed from 'portNoHashArray' and the > 'ovsPortNameHashArray'. > - * > - * Both 'hvDelete' and 'ovsDelete' can be set to TRUE by the caller. > - */ > - if (vport->isPresentOnHv == TRUE) { > - deletedOnHv = TRUE; > - } > - if (vport->portNo == OVS_DPPORT_NUMBER_INVALID) { > - deletedOnOvs = TRUE; > - } > - > - if (hvDelete && !deletedOnHv) { > - vport->isPresentOnHv = TRUE; > - > - /* Remove the port from the relevant lists. */ > - RemoveEntryList(&vport->portIdLink); > - InitializeListHead(&vport->portIdLink); > - deletedOnHv = TRUE; > + if (STATUS_SUCCESS == status) { > + OvsCleanupVportCommon(switchContext, > + vport, > + hvSwitchPort, > + hvDelete, > + ovsDelete); > } > - if (ovsDelete && !deletedOnOvs) { > - vport->portNo = OVS_DPPORT_NUMBER_INVALID; > - vport->ovsName[0] = '\0'; > > - /* Remove the port from the relevant lists. */ > - RemoveEntryList(&vport->ovsNameLink); > - InitializeListHead(&vport->ovsNameLink); > - RemoveEntryList(&vport->portNoLink); > - InitializeListHead(&vport->portNoLink); > - deletedOnOvs = TRUE; > - } > - > - /* > - * Deallocate the port if it has been deleted on the Hyper-V switch as > well > - * as OVS userspace. > - */ > - if (deletedOnHv && deletedOnOvs) { > - if (hvSwitchPort) { > - switchContext->numHvVports--; > - } else { > - switchContext->numNonHvVports--; > - } > - OvsFreeMemoryWithTag(vport, OVS_VPORT_POOL_TAG); > - if (vportDeallocated) { > - *vportDeallocated = TRUE; > - } > - } > + return status; > } > > NDIS_STATUS > @@ -1294,7 +1383,7 @@ OvsClearAllSwitchVports(POVS_SWITCH_CONTEXT > switchContext) > LIST_FORALL_SAFE(head, link, next) { > POVS_VPORT_ENTRY vport; > vport = CONTAINING_RECORD(link, OVS_VPORT_ENTRY, portIdLink); > - OvsRemoveAndDeleteVport(switchContext, vport, TRUE, TRUE, NULL); > + OvsRemoveAndDeleteVport(NULL, switchContext, vport, TRUE, TRUE); > } > } > /* > @@ -1302,9 +1391,8 @@ OvsClearAllSwitchVports(POVS_SWITCH_CONTEXT > switchContext) > * 'portIdHashArray'. > */ > if (switchContext->virtualExternalVport) { > - OvsRemoveAndDeleteVport(switchContext, > - (POVS_VPORT_ENTRY)switchContext->virtualExternalVport, TRUE, > TRUE, > - NULL); > + OvsRemoveAndDeleteVport(NULL, switchContext, > + (POVS_VPORT_ENTRY)switchContext->virtualExternalVport, TRUE, > TRUE); > } > > for (UINT hash = 0; hash < OVS_MAX_VPORT_ARRAY_SIZE; hash++) { > @@ -1317,7 +1405,7 @@ OvsClearAllSwitchVports(POVS_SWITCH_CONTEXT > switchContext) > ASSERT(OvsIsTunnelVportType(vport->ovsType) || > (vport->ovsType == OVS_VPORT_TYPE_INTERNAL && > vport->isBridgeInternal) || vport->isPresentOnHv == > TRUE); > - OvsRemoveAndDeleteVport(switchContext, vport, TRUE, TRUE, NULL); > + OvsRemoveAndDeleteVport(NULL, switchContext, vport, TRUE, TRUE); > } > } > > @@ -1895,7 +1983,7 @@ Cleanup: > > /* > * -------------------------------------------------------------------------- > - * Command Handler for 'OVS_VPORT_CMD_NEW'. > + * Command Handler for 'OVS_VPORT_CMD_GET'. > * > * The function handles the initial call to setup the dump state, as well as > * subsequent calls to continue dumping data. > @@ -2020,8 +2108,6 @@ OvsNewVportCmdHandler(POVS_USER_PARAMS_CONTEXT > usrParamsCtx, > } else { > ASSERT(OvsIsTunnelVportType(portType) || > (portType == OVS_VPORT_TYPE_INTERNAL && isBridgeInternal)); > - ASSERT(OvsGetTunnelVport(gOvsSwitchContext, portType) == NULL || > - !OvsIsTunnelVportType(portType)); > > vport = (POVS_VPORT_ENTRY)OvsAllocateVport(); > if (vport == NULL) { > @@ -2031,11 +2117,23 @@ OvsNewVportCmdHandler(POVS_USER_PARAMS_CONTEXT > usrParamsCtx, > vportAllocated = TRUE; > > if (OvsIsTunnelVportType(portType)) { > - status = OvsInitTunnelVport(vport, portType, VXLAN_UDP_PORT); > + UINT16 udpPortDest = VXLAN_UDP_PORT; > + PNL_ATTR attr = > NlAttrFindNested(vportAttrs[OVS_VPORT_ATTR_OPTIONS], > + OVS_TUNNEL_ATTR_DST_PORT); > + if (attr) { > + udpPortDest = NlAttrGetU16(attr); > + } > + > + status = OvsInitTunnelVport(usrParamsCtx, > + vport, > + portType, > + udpPortDest); > + > nlError = NlMapStatusToNlErr(status); > } else { > OvsInitBridgeInternalVport(vport); > } > + > vportInitialized = TRUE; > > if (nlError == NL_ERROR_SUCCESS) { > @@ -2047,6 +2145,8 @@ OvsNewVportCmdHandler(POVS_USER_PARAMS_CONTEXT > usrParamsCtx, > * corresponding hyper-v switch part. > */ > vport->isPresentOnHv = TRUE; > + } else { > + goto Cleanup; > } > } > > @@ -2106,14 +2206,14 @@ OvsNewVportCmdHandler(POVS_USER_PARAMS_CONTEXT > usrParamsCtx, > Cleanup: > NdisReleaseRWLock(gOvsSwitchContext->dispatchLock, &lockState); > > - if (nlError != NL_ERROR_SUCCESS) { > + if ((nlError != NL_ERROR_SUCCESS) && (nlError != NL_ERROR_PENDING)) { > POVS_MESSAGE_ERROR msgError = (POVS_MESSAGE_ERROR) > usrParamsCtx->outputBuffer; > > if (vport && vportAllocated == TRUE) { > if (vportInitialized == TRUE) { > if (OvsIsTunnelVportType(portType)) { > - OvsCleanupVxlanTunnel(vport); > + OvsCleanupVxlanTunnel(NULL, vport, NULL, NULL); > } > } > OvsFreeMemoryWithTag(vport, OVS_VPORT_POOL_TAG); > @@ -2123,7 +2223,7 @@ Cleanup: > *replyLen = msgError->nlMsg.nlmsgLen; > } > > - return STATUS_SUCCESS; > + return (status == STATUS_PENDING) ? STATUS_PENDING : STATUS_SUCCESS; > } > > > @@ -2297,18 +2397,25 @@ OvsDeleteVportCmdHandler(POVS_USER_PARAMS_CONTEXT > usrParamsCtx, > usrParamsCtx->outputLength, > gOvsSwitchContext->dpNo); > > + *replyLen = msgOut->nlMsg.nlmsgLen; > + > /* > * Mark the port as deleted from OVS userspace. If the port does not > exist > * on the Hyper-V switch, it gets deallocated. Otherwise, it stays. > */ > - OvsRemoveAndDeleteVport(gOvsSwitchContext, vport, FALSE, TRUE, NULL); > - > - *replyLen = msgOut->nlMsg.nlmsgLen; > + status = OvsRemoveAndDeleteVport(usrParamsCtx, > + gOvsSwitchContext, > + vport, > + FALSE, > + TRUE); > + if (status) { > + nlError = NlMapStatusToNlErr(status); > + } > > Cleanup: > NdisReleaseRWLock(gOvsSwitchContext->dispatchLock, &lockState); > > - if (nlError != NL_ERROR_SUCCESS) { > + if ((nlError != NL_ERROR_SUCCESS) && (nlError != NL_ERROR_PENDING)) { > POVS_MESSAGE_ERROR msgError = (POVS_MESSAGE_ERROR) > usrParamsCtx->outputBuffer; > > @@ -2316,5 +2423,173 @@ Cleanup: > *replyLen = msgError->nlMsg.nlmsgLen; > } > > - return STATUS_SUCCESS; > + return (status == STATUS_PENDING) ? STATUS_PENDING : STATUS_SUCCESS; > +} > + > +static VOID > +OvsTunnelVportPendingUninit(PVOID context, > + NTSTATUS status, > + UINT32 *replyLen) > +{ > + POVS_TUNFLT_INIT_CONTEXT tunnelContext = > + (POVS_TUNFLT_INIT_CONTEXT) context; > + POVS_SWITCH_CONTEXT switchContext = tunnelContext->switchContext; > + POVS_VPORT_ENTRY vport = tunnelContext->vport; > + POVS_MESSAGE msgIn = (POVS_MESSAGE)tunnelContext->inputBuffer; > + POVS_MESSAGE msgOut = (POVS_MESSAGE)tunnelContext->outputBuffer; > + NL_ERROR nlError = NlMapStatusToNlErr(status); > + LOCK_STATE_EX lockState; > + > + NdisAcquireRWLockWrite(switchContext->dispatchLock, &lockState, 0); > + > + if (msgIn && msgOut) { > + /* Check the received status to reply to the caller. */ > + if (STATUS_SUCCESS == status) { > + OvsCreateMsgFromVport(vport, > + msgIn, > + msgOut, > + tunnelContext->outputLength, > + switchContext->dpNo); > + > + *replyLen = msgOut->nlMsg.nlmsgLen; > + } else { > + POVS_MESSAGE_ERROR msgError = (POVS_MESSAGE_ERROR)msgOut; > + > + NlBuildErrorMsg(msgIn, msgError, nlError); > + *replyLen = msgError->nlMsg.nlmsgLen; > + } > + } > + > + OvsCleanupVportCommon(switchContext, > + vport, > + tunnelContext->hvSwitchPort, > + tunnelContext->hvDelete, > + tunnelContext->ovsDelete); > + > + NdisReleaseRWLock(switchContext->dispatchLock, &lockState); > +} > + > +static VOID > +OvsTunnelVportPendingInit(PVOID context, > + NTSTATUS status, > + UINT32 *replyLen) > +{ > + POVS_TUNFLT_INIT_CONTEXT tunnelContext = > + (POVS_TUNFLT_INIT_CONTEXT) context; > + POVS_VPORT_ENTRY vport = tunnelContext->vport; > + POVS_MESSAGE msgIn = (POVS_MESSAGE)tunnelContext->inputBuffer; > + POVS_MESSAGE msgOut = (POVS_MESSAGE)tunnelContext->outputBuffer; > + PCHAR portName; > + ULONG portNameLen = 0; > + UINT32 portType = 0; > + NL_ERROR nlError = NL_ERROR_SUCCESS; > + BOOLEAN error = TRUE; > + > + do { > + if (!NT_SUCCESS(status)) { > + nlError = NlMapStatusToNlErr(status); > + break; > + } > + > + static const NL_POLICY ovsVportPolicy[] = { > + [OVS_VPORT_ATTR_PORT_NO] = { .type = NL_A_U32, .optional = TRUE > }, > + [OVS_VPORT_ATTR_TYPE] = { .type = NL_A_U32, .optional = FALSE }, > + [OVS_VPORT_ATTR_NAME] = { .type = NL_A_STRING, .maxLen = > IFNAMSIZ, > + .optional = FALSE }, > + [OVS_VPORT_ATTR_UPCALL_PID] = { .type = NL_A_UNSPEC, > + .optional = FALSE }, > + [OVS_VPORT_ATTR_OPTIONS] = { .type = NL_A_NESTED, .optional = > TRUE }, > + }; > + > + PNL_ATTR vportAttrs[ARRAY_SIZE(ovsVportPolicy)]; > + > + /* input buffer has been validated while validating write dev op. */ > + ASSERT(msgIn != NULL); > + > + /* Output buffer has been validated while validating transact dev > op. */ > + ASSERT(msgOut != NULL && tunnelContext->outputLength >= sizeof > *msgOut); > + > + if (!NlAttrParse((PNL_MSG_HDR)msgIn, > + NLMSG_HDRLEN + GENL_HDRLEN + OVS_HDRLEN, > + NlMsgAttrsLen((PNL_MSG_HDR)msgIn), > + ovsVportPolicy, vportAttrs, ARRAY_SIZE(vportAttrs))) { > + nlError = NL_ERROR_INVAL; > + break; > + } > + > + portName = NlAttrGet(vportAttrs[OVS_VPORT_ATTR_NAME]); > + portNameLen = NlAttrGetSize(vportAttrs[OVS_VPORT_ATTR_NAME]); > + portType = NlAttrGetU32(vportAttrs[OVS_VPORT_ATTR_TYPE]); > + > + if (vport->portNo != OVS_DPPORT_NUMBER_INVALID) { > + nlError = NL_ERROR_EXIST; > + break; > + } > + > + vport->ovsState = OVS_STATE_CONNECTED; > + vport->nicState = NdisSwitchNicStateConnected; > + > + /* > + * Allow the vport to be deleted, because there is no > + * corresponding hyper-v switch part. > + */ > + vport->isPresentOnHv = TRUE; > + > + if (vportAttrs[OVS_VPORT_ATTR_PORT_NO] != NULL) { > + /* > + * XXX: when we implement the limit for OVS port number to be > + * MAXUINT16, we'll need to check the port number received from > the > + * userspace. > + */ > + vport->portNo = > + NlAttrGetU32(vportAttrs[OVS_VPORT_ATTR_PORT_NO]); > + } else { > + vport->portNo = > + OvsComputeVportNo(gOvsSwitchContext); > + if (vport->portNo == OVS_DPPORT_NUMBER_INVALID) { > + nlError = NL_ERROR_NOMEM; > + break; > + } > + } > + > + /* The ovs port name must be uninitialized. */ > + ASSERT(vport->ovsName[0] == '\0'); > + ASSERT(portNameLen <= OVS_MAX_PORT_NAME_LENGTH); > + > + RtlCopyMemory(vport->ovsName, portName, portNameLen); > + /* if we don't have options, then vport->portOptions will be NULL */ > + vport->portOptions = vportAttrs[OVS_VPORT_ATTR_OPTIONS]; > + > + /* > + * XXX: when we implement OVS_DP_ATTR_USER_FEATURES in datapath, > + * we'll need to check the OVS_DP_F_VPORT_PIDS flag: if it is set, > + * it means we have an array of pids, instead of a single pid. > + * ATM we assume we have one pid only. > + */ > + vport->upcallPid = > + NlAttrGetU32(vportAttrs[OVS_VPORT_ATTR_UPCALL_PID]); > + > + status = InitOvsVportCommon(gOvsSwitchContext, vport); > + ASSERT(status == STATUS_SUCCESS); > + > + OvsCreateMsgFromVport(vport, > + msgIn, > + msgOut, > + tunnelContext->outputLength, > + gOvsSwitchContext->dpNo); > + > + *replyLen = msgOut->nlMsg.nlmsgLen; > + > + error = FALSE; > + } while (error); > + > + if (error) { > + POVS_MESSAGE_ERROR msgError = (POVS_MESSAGE_ERROR) msgOut; > + > + OvsCleanupVxlanTunnel(NULL, vport, NULL, NULL); > + OvsFreeMemory(vport); > + > + NlBuildErrorMsg(msgIn, msgError, nlError); > + *replyLen = msgError->nlMsg.nlmsgLen; > + } > } > diff --git a/datapath-windows/ovsext/Vport.h b/datapath-windows/ovsext/Vport.h > index 348fbfd..4cfda30 100644 > --- a/datapath-windows/ovsext/Vport.h > +++ b/datapath-windows/ovsext/Vport.h > @@ -207,15 +207,15 @@ OvsIsBridgeInternalVport(POVS_VPORT_ENTRY vport) > return vport->isBridgeInternal == TRUE; > } > > -VOID OvsRemoveAndDeleteVport(POVS_SWITCH_CONTEXT switchContext, > - POVS_VPORT_ENTRY vport, > - BOOLEAN hvDelete, BOOLEAN ovsDelete, > - BOOLEAN *vportDeallocated); > +NTSTATUS OvsRemoveAndDeleteVport(PVOID usrParamsCtx, > + POVS_SWITCH_CONTEXT switchContext, > + POVS_VPORT_ENTRY vport, > + BOOLEAN hvDelete, BOOLEAN ovsDelete); > > NDIS_STATUS InitOvsVportCommon(POVS_SWITCH_CONTEXT switchContext, > POVS_VPORT_ENTRY vport); > -NTSTATUS OvsInitTunnelVport(POVS_VPORT_ENTRY vport, OVS_VPORT_TYPE ovsType, > - UINT16 dstport); > +NTSTATUS OvsInitTunnelVport(PVOID usrParamsCtx, POVS_VPORT_ENTRY vport, > + OVS_VPORT_TYPE ovsType, UINT16 dstport); > NTSTATUS OvsInitBridgeInternalVport(POVS_VPORT_ENTRY vport); > > POVS_VPORT_ENTRY OvsAllocateVport(VOID); > diff --git a/datapath-windows/ovsext/Vxlan.c b/datapath-windows/ovsext/Vxlan.c > index 8c57185..bf16e35 100644 > --- a/datapath-windows/ovsext/Vxlan.c > +++ b/datapath-windows/ovsext/Vxlan.c > @@ -50,14 +50,57 @@ > extern POVS_SWITCH_CONTEXT gOvsSwitchContext; > > /* > + > *---------------------------------------------------------------------------- > + * This function verifies if the VXLAN tunnel already exists, in order to > + * avoid sending a duplicate request to the WFP base filtering engine. > + > *---------------------------------------------------------------------------- > + */ > +static BOOLEAN > +OvsIsTunnelFilterCreated(POVS_SWITCH_CONTEXT switchContext, > + UINT16 udpPortDest) > +{ > + for (UINT hash = 0; hash < OVS_MAX_VPORT_ARRAY_SIZE; hash++) { > + PLIST_ENTRY head, link, next; > + > + head = &(switchContext->portNoHashArray[hash & OVS_VPORT_MASK]); > + LIST_FORALL_SAFE(head, link, next) { > + POVS_VPORT_ENTRY vport = NULL; > + POVS_VXLAN_VPORT vxlanPort = NULL; > + vport = CONTAINING_RECORD(link, OVS_VPORT_ENTRY, portNoLink); > + vxlanPort = (POVS_VXLAN_VPORT)vport->priv; > + if (vxlanPort) { > + if ((udpPortDest == vxlanPort->dstPort)) { > + /* The VXLAN tunnel was already created. */ > + return TRUE; > + } > + } > + } > + } > + > + return FALSE; > +} > + > +/* > + > *---------------------------------------------------------------------------- > + * This function allocates and initializes the OVS_VXLAN_VPORT. The function > + * also creates a WFP tunnel filter for the necessary destination port. The > + * tunnel filter create request is passed to the tunnel filter threads that > + * will complete the request at a later time when IRQL is lowered to > + * PASSIVE_LEVEL. > + * > * udpDestPort: the vxlan is set as payload to a udp frame. If the > destination > * port of an udp frame is udpDestPort, we understand it to be vxlan. > + > *---------------------------------------------------------------------------- > */ > NTSTATUS > -OvsInitVxlanTunnel(POVS_VPORT_ENTRY vport, > - UINT16 udpDestPort) > +OvsInitVxlanTunnel(PIRP irp, > + POVS_VPORT_ENTRY vport, > + UINT16 udpDestPort, > + PFNTunnelVportPendingOp callback, > + PVOID tunnelContext) > { > - POVS_VXLAN_VPORT vxlanPort; > + NTSTATUS status = STATUS_SUCCESS; > + POVS_VXLAN_VPORT vxlanPort = NULL; > > vxlanPort = OvsAllocateMemoryWithTag(sizeof (*vxlanPort), > OVS_VXLAN_POOL_TAG); > @@ -67,28 +110,56 @@ OvsInitVxlanTunnel(POVS_VPORT_ENTRY vport, > > RtlZeroMemory(vxlanPort, sizeof(*vxlanPort)); > vxlanPort->dstPort = udpDestPort; > - /* > - * since we are installing the WFP filter before the port is created > - * We need to check if it is the same number > - * XXX should be removed later > - */ > - ASSERT(vxlanPort->dstPort == VXLAN_UDP_PORT); > vport->priv = (PVOID)vxlanPort; > > - return STATUS_SUCCESS; > -} > + if (!OvsIsTunnelFilterCreated(gOvsSwitchContext, udpDestPort)) { > + status = OvsTunelFilterCreate(irp, > + udpDestPort, > + &vxlanPort->filterID, > + callback, > + tunnelContext); > + } else { > + status = STATUS_OBJECT_NAME_EXISTS; > + } > > + return status; > +} > > -VOID > -OvsCleanupVxlanTunnel(POVS_VPORT_ENTRY vport) > +/* > + > *---------------------------------------------------------------------------- > + * This function releases the OVS_VXLAN_VPORT. The function also deletes the > + * WFP tunnel filter previously created. The tunnel filter delete request is > + * passed to the tunnel filter threads that will complete the request at a > + * later time when IRQL is lowered to PASSIVE_LEVEL. > + > *---------------------------------------------------------------------------- > + */ > +NTSTATUS > +OvsCleanupVxlanTunnel(PIRP irp, > + POVS_VPORT_ENTRY vport, > + PFNTunnelVportPendingOp callback, > + PVOID tunnelContext) > { > + NTSTATUS status = STATUS_SUCCESS; > + POVS_VXLAN_VPORT vxlanPort = NULL; > + > if (vport->ovsType != OVS_VPORT_TYPE_VXLAN || > vport->priv == NULL) { > - return; > + return STATUS_SUCCESS; > + } > + > + vxlanPort = (POVS_VXLAN_VPORT)vport->priv; > + > + if (vxlanPort->filterID != 0) { > + status = OvsTunelFilterDelete(irp, > + vxlanPort->filterID, > + callback, > + tunnelContext); > } > > OvsFreeMemoryWithTag(vport->priv, OVS_VXLAN_POOL_TAG); > vport->priv = NULL; > + > + return status; > } > > > @@ -475,9 +546,6 @@ OvsSlowPathDecapVxlan(const PNET_BUFFER_LIST packet, > break; > } > > - /* XXX Should be tested against the dynamic port # in the VXLAN > vport */ > - ASSERT(udp->dest == RtlUshortByteSwap(VXLAN_UDP_PORT)); > - > VxlanHeader = (VXLANHdr *)OvsGetPacketBytes(packet, > sizeof(*VxlanHeader), > layers.l7Offset, > diff --git a/datapath-windows/ovsext/Vxlan.h b/datapath-windows/ovsext/Vxlan.h > index d84796d..248a5dc 100644 > --- a/datapath-windows/ovsext/Vxlan.h > +++ b/datapath-windows/ovsext/Vxlan.h > @@ -24,6 +24,7 @@ typedef struct _OVS_VXLAN_VPORT { > UINT64 outPkts; > UINT64 slowInPkts; > UINT64 slowOutPkts; > + UINT64 filterID; > /* > * To be filled > */ > @@ -47,10 +48,16 @@ typedef struct VXLANHdr { > UINT32 reserved2:8; > } VXLANHdr; > > -NTSTATUS OvsInitVxlanTunnel(POVS_VPORT_ENTRY vport, > - UINT16 udpDestPort); > +NTSTATUS OvsInitVxlanTunnel(PIRP irp, > + POVS_VPORT_ENTRY vport, > + UINT16 udpDestPort, > + PFNTunnelVportPendingOp callback, > + PVOID tunnelContext); > > -VOID OvsCleanupVxlanTunnel(POVS_VPORT_ENTRY vport); > +NTSTATUS OvsCleanupVxlanTunnel(PIRP irp, > + POVS_VPORT_ENTRY vport, > + PFNTunnelVportPendingOp callback, > + PVOID tunnelContext); > > NDIS_STATUS OvsSlowPathDecapVxlan(const PNET_BUFFER_LIST packet, > OvsIPv4TunnelKey *tunnelKey); > -- > 1.9.0.msysgit.0 > _______________________________________________ > dev mailing list > dev@openvswitch.org > http://openvswitch.org/mailman/listinfo/dev _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev