diff options
author | Samuel Ghinet <sghinet@cloudbasesolutions.com> | 2014-08-29 04:06:48 +0000 |
---|---|---|
committer | Ben Pfaff <blp@nicira.com> | 2014-08-29 07:55:05 -0700 |
commit | fa1324c92810c6b1e33b7e87caaaf2e6c4041040 (patch) | |
tree | 8e06f5d991d755215bb6839a997bc58721b2d754 /datapath-windows/ovsext/Switch.c | |
parent | fd972eb87a888242fb1a8ec2394fa7b3030fbd7d (diff) | |
download | openvswitch-fa1324c92810c6b1e33b7e87caaaf2e6c4041040.tar.gz |
datapath-windows: Rename files.
This patch includes the file renaming and accommodations needed for the file
renaming to build the forwarding extension for Hyper-V.
This patch is also a follow-up for the thread:
http://openvswitch.org/pipermail/dev/2014-August/044005.html
Signed-off-by: Samuel Ghinet <sghinet@cloudbasesolutions.com>
Co-authored-by: Alin Gabriel Serdean <aserdean@cloudbasesolutions.com>
Signed-off-by: Ben Pfaff <blp@nicira.com>
Diffstat (limited to 'datapath-windows/ovsext/Switch.c')
-rw-r--r-- | datapath-windows/ovsext/Switch.c | 530 |
1 files changed, 530 insertions, 0 deletions
diff --git a/datapath-windows/ovsext/Switch.c b/datapath-windows/ovsext/Switch.c new file mode 100644 index 000000000..9578680e0 --- /dev/null +++ b/datapath-windows/ovsext/Switch.c @@ -0,0 +1,530 @@ +/* + * Copyright (c) 2014 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. + */ + +/* + * This file contains the implementation of the management functionality of the + * OVS. + */ + +#include "precomp.h" + +#include "Switch.h" +#include "Vport.h" +#include "Event.h" +#include "Flow.h" +#include "IpHelper.h" +#include "TunnelIntf.h" +#include "Oid.h" + +#ifdef OVS_DBG_MOD +#undef OVS_DBG_MOD +#endif +#define OVS_DBG_MOD OVS_DBG_SWITCH +#include "Debug.h" + +POVS_SWITCH_CONTEXT gOvsSwitchContext; +BOOLEAN gOvsInAttach; +UINT64 ovsTimeIncrementPerTick; + +extern PNDIS_SPIN_LOCK gOvsCtrlLock; +extern NDIS_HANDLE gOvsExtDriverHandle; +extern NDIS_HANDLE gOvsExtDriverObject; + +static NDIS_STATUS OvsCreateSwitch(NDIS_HANDLE ndisFilterHandle, + POVS_SWITCH_CONTEXT *switchContextOut); +static NDIS_STATUS OvsInitSwitchContext(POVS_SWITCH_CONTEXT switchContext); +static VOID OvsDeleteSwitch(POVS_SWITCH_CONTEXT switchContext); +static VOID OvsCleanupSwitchContext(POVS_SWITCH_CONTEXT switchContext); +static NDIS_STATUS OvsActivateSwitch(POVS_SWITCH_CONTEXT switchContext); + + +/* + * -------------------------------------------------------------------------- + * Implements filter driver's FilterAttach function. + * + * This function allocates the switch context, and initializes its necessary + * members. + * -------------------------------------------------------------------------- + */ +NDIS_STATUS +OvsExtAttach(NDIS_HANDLE ndisFilterHandle, + NDIS_HANDLE filterDriverContext, + PNDIS_FILTER_ATTACH_PARAMETERS attachParameters) +{ + NDIS_STATUS status = NDIS_STATUS_FAILURE; + NDIS_FILTER_ATTRIBUTES ovsExtAttributes; + POVS_SWITCH_CONTEXT switchContext = NULL; + + UNREFERENCED_PARAMETER(filterDriverContext); + + OVS_LOG_TRACE("Enter: ndisFilterHandle %p", ndisFilterHandle); + + ASSERT(filterDriverContext == (NDIS_HANDLE)gOvsExtDriverObject); + if (attachParameters->MiniportMediaType != NdisMedium802_3) { + status = NDIS_STATUS_INVALID_PARAMETER; + goto cleanup; + } + + if (gOvsExtDriverHandle == NULL) { + OVS_LOG_TRACE("Exit: OVSEXT driver is not loaded."); + ASSERT(FALSE); + goto cleanup; + } + + NdisAcquireSpinLock(gOvsCtrlLock); + if (gOvsSwitchContext) { + NdisReleaseSpinLock(gOvsCtrlLock); + OVS_LOG_TRACE("Exit: Failed to create OVS Switch, only one datapath is" + "supported, %p.", gOvsSwitchContext); + goto cleanup; + } + if (gOvsInAttach) { + NdisReleaseSpinLock(gOvsCtrlLock); + /* Just fail the request. */ + OVS_LOG_TRACE("Exit: Failed to create OVS Switch, since another attach" + "instance is in attach process."); + goto cleanup; + } + gOvsInAttach = TRUE; + NdisReleaseSpinLock(gOvsCtrlLock); + + status = OvsInitIpHelper(ndisFilterHandle); + if (status != STATUS_SUCCESS) { + OVS_LOG_ERROR("Exit: Failed to initialize IP helper."); + goto cleanup; + } + + status = OvsCreateSwitch(ndisFilterHandle, &switchContext); + if (status != NDIS_STATUS_SUCCESS) { + OvsCleanupIpHelper(); + goto cleanup; + } + ASSERT(switchContext); + + /* + * Register the switch context with NDIS so NDIS can pass it back to the + * Filterxxx callback functions as the 'FilterModuleContext' parameter. + */ + RtlZeroMemory(&ovsExtAttributes, sizeof(NDIS_FILTER_ATTRIBUTES)); + ovsExtAttributes.Header.Revision = NDIS_FILTER_ATTRIBUTES_REVISION_1; + ovsExtAttributes.Header.Size = sizeof(NDIS_FILTER_ATTRIBUTES); + ovsExtAttributes.Header.Type = NDIS_OBJECT_TYPE_FILTER_ATTRIBUTES; + ovsExtAttributes.Flags = 0; + + NDIS_DECLARE_FILTER_MODULE_CONTEXT(OVS_SWITCH_CONTEXT); + status = NdisFSetAttributes(ndisFilterHandle, switchContext, &ovsExtAttributes); + if (status != NDIS_STATUS_SUCCESS) { + OVS_LOG_ERROR("Failed to set attributes."); + OvsCleanupIpHelper(); + goto cleanup; + } + + /* Setup the state machine. */ + switchContext->controlFlowState = OvsSwitchAttached; + switchContext->dataFlowState = OvsSwitchPaused; + + gOvsSwitchContext = switchContext; + KeMemoryBarrier(); + +cleanup: + gOvsInAttach = FALSE; + if (status != NDIS_STATUS_SUCCESS) { + if (switchContext != NULL) { + OvsDeleteSwitch(switchContext); + } + } + OVS_LOG_TRACE("Exit: status %x", status); + + return status; +} + + +/* + * -------------------------------------------------------------------------- + * This function allocated the switch context, and initializes its necessary + * members. + * -------------------------------------------------------------------------- + */ +NDIS_STATUS +OvsCreateSwitch(NDIS_HANDLE ndisFilterHandle, + POVS_SWITCH_CONTEXT *switchContextOut) +{ + NDIS_STATUS status; + POVS_SWITCH_CONTEXT switchContext; + NDIS_SWITCH_CONTEXT hostSwitchContext; + NDIS_SWITCH_OPTIONAL_HANDLERS hostSwitchHandler; + + OVS_LOG_TRACE("Enter: Create switch object"); + + switchContext = + (POVS_SWITCH_CONTEXT) OvsAllocateMemory(sizeof(OVS_SWITCH_CONTEXT)); + if (switchContext == NULL) { + status = NDIS_STATUS_RESOURCES; + goto create_switch_done; + } + RtlZeroMemory(switchContext, sizeof(OVS_SWITCH_CONTEXT)); + + /* Initialize the switch. */ + hostSwitchHandler.Header.Type = NDIS_OBJECT_TYPE_SWITCH_OPTIONAL_HANDLERS; + hostSwitchHandler.Header.Size = NDIS_SIZEOF_SWITCH_OPTIONAL_HANDLERS_REVISION_1; + hostSwitchHandler.Header.Revision = NDIS_SWITCH_OPTIONAL_HANDLERS_REVISION_1; + + status = NdisFGetOptionalSwitchHandlers(ndisFilterHandle, + &hostSwitchContext, + &hostSwitchHandler); + if (status != NDIS_STATUS_SUCCESS) { + OVS_LOG_ERROR("OvsExtAttach: Extension is running in " + "non-switch environment."); + OvsFreeMemory(switchContext); + goto create_switch_done; + } + + switchContext->NdisFilterHandle = ndisFilterHandle; + switchContext->NdisSwitchContext = hostSwitchContext; + RtlCopyMemory(&switchContext->NdisSwitchHandlers, &hostSwitchHandler, + sizeof(NDIS_SWITCH_OPTIONAL_HANDLERS)); + + status = OvsInitSwitchContext(switchContext); + if (status != NDIS_STATUS_SUCCESS) { + OvsFreeMemory(switchContext); + goto create_switch_done; + } + + status = OvsTunnelFilterInitialize(gOvsExtDriverObject); + if (status != NDIS_STATUS_SUCCESS) { + OvsFreeMemory(switchContext); + goto create_switch_done; + } + *switchContextOut = switchContext; + +create_switch_done: + OVS_LOG_TRACE("Exit: switchContext: %p status: %#lx", + switchContext, status); + return status; +} + + +/* + * -------------------------------------------------------------------------- + * Implements filter driver's FilterDetach function. + * -------------------------------------------------------------------------- + */ +_Use_decl_annotations_ +VOID +OvsExtDetach(NDIS_HANDLE filterModuleContext) +{ + POVS_SWITCH_CONTEXT switchContext = (POVS_SWITCH_CONTEXT)filterModuleContext; + + OVS_LOG_TRACE("Enter: filterModuleContext %p", filterModuleContext); + + ASSERT(switchContext->dataFlowState == OvsSwitchPaused); + switchContext->controlFlowState = OvsSwitchDetached; + KeMemoryBarrier(); + while(switchContext->pendingOidCount > 0) { + NdisMSleep(1000); + } + OvsDeleteSwitch(switchContext); + OvsCleanupIpHelper(); + gOvsSwitchContext = NULL; + /* This completes the cleanup, and a new attach can be handled now. */ + + OVS_LOG_TRACE("Exit: OvsDetach Successfully"); +} + + +/* + * -------------------------------------------------------------------------- + * This function deletes the switch by freeing all memory previously allocated. + * XXX need synchronization with other path. + * -------------------------------------------------------------------------- + */ +VOID +OvsDeleteSwitch(POVS_SWITCH_CONTEXT switchContext) +{ + UINT32 dpNo = switchContext->dpNo; + + OVS_LOG_TRACE("Enter: switchContext:%p", switchContext); + + OvsTunnelFilterUninitialize(gOvsExtDriverObject); + OvsClearAllSwitchVports(switchContext); + OvsCleanupSwitchContext(switchContext); + OvsFreeMemory(switchContext); + OVS_LOG_TRACE("Exit: deleted switch %p dpNo: %d", switchContext, dpNo); +} + + +/* + * -------------------------------------------------------------------------- + * Implements filter driver's FilterRestart function. + * -------------------------------------------------------------------------- + */ +_Use_decl_annotations_ +NDIS_STATUS +OvsExtRestart(NDIS_HANDLE filterModuleContext, + PNDIS_FILTER_RESTART_PARAMETERS filterRestartParameters) +{ + POVS_SWITCH_CONTEXT switchContext = (POVS_SWITCH_CONTEXT)filterModuleContext; + NDIS_STATUS status = NDIS_STATUS_SUCCESS; + BOOLEAN switchActive; + + UNREFERENCED_PARAMETER(filterRestartParameters); + + OVS_LOG_TRACE("Enter: filterModuleContext %p", + filterModuleContext); + + /* Activate the switch if this is the first restart. */ + if (!switchContext->isActivated && !switchContext->isActivateFailed) { + status = OvsQuerySwitchActivationComplete(switchContext, + &switchActive); + if (status != NDIS_STATUS_SUCCESS) { + switchContext->isActivateFailed = TRUE; + status = NDIS_STATUS_RESOURCES; + goto cleanup; + } + + if (switchActive) { + status = OvsActivateSwitch(switchContext); + + if (status != NDIS_STATUS_SUCCESS) { + OVS_LOG_WARN("Failed to activate switch, dpNo:%d", + switchContext->dpNo); + status = NDIS_STATUS_RESOURCES; + goto cleanup; + } + } + } + + ASSERT(switchContext->dataFlowState == OvsSwitchPaused); + switchContext->dataFlowState = OvsSwitchRunning; + +cleanup: + OVS_LOG_TRACE("Exit: Restart switch:%p, dpNo: %d, status: %#x", + switchContext, switchContext->dpNo, status); + return status; +} + + +/* + * -------------------------------------------------------------------------- + * Implements filter driver's FilterPause function + * -------------------------------------------------------------------------- + */ +NDIS_STATUS +OvsExtPause(NDIS_HANDLE filterModuleContext, + PNDIS_FILTER_PAUSE_PARAMETERS pauseParameters) +{ + POVS_SWITCH_CONTEXT switchContext = (POVS_SWITCH_CONTEXT)filterModuleContext; + + UNREFERENCED_PARAMETER(pauseParameters); + OVS_LOG_TRACE("Enter: filterModuleContext %p", + filterModuleContext); + + ASSERT(switchContext->dataFlowState == OvsSwitchRunning); + switchContext->dataFlowState = OvsSwitchPaused; + KeMemoryBarrier(); + while(switchContext->pendingOidCount > 0) { + NdisMSleep(1000); + } + + OVS_LOG_TRACE("Exit: OvsDetach Successfully"); + return NDIS_STATUS_SUCCESS; +} + +static NDIS_STATUS +OvsInitSwitchContext(POVS_SWITCH_CONTEXT switchContext) +{ + int i; + NTSTATUS status; + + OVS_LOG_TRACE("Enter: switchContext: %p", switchContext); + + switchContext->dispatchLock = + NdisAllocateRWLock(switchContext->NdisFilterHandle); + + switchContext->vportArray = + (PVOID *)OvsAllocateMemory(sizeof (PVOID) * OVS_MAX_VPORT_ARRAY_SIZE); + switchContext->nameHashArray = (PLIST_ENTRY) + OvsAllocateMemory(sizeof (LIST_ENTRY) * OVS_MAX_VPORT_ARRAY_SIZE); + switchContext->portHashArray = (PLIST_ENTRY) + OvsAllocateMemory(sizeof (LIST_ENTRY) * OVS_MAX_VPORT_ARRAY_SIZE); + status = OvsAllocateFlowTable(&switchContext->datapath, switchContext); + + if (status == NDIS_STATUS_SUCCESS) { + status = OvsInitBufferPool(switchContext); + } + if (status != NDIS_STATUS_SUCCESS || + switchContext->dispatchLock == NULL || + switchContext->vportArray == NULL || + switchContext->nameHashArray == NULL || + switchContext->portHashArray == NULL) { + if (switchContext->dispatchLock) { + NdisFreeRWLock(switchContext->dispatchLock); + } + if (switchContext->vportArray) { + OvsFreeMemory(switchContext->vportArray); + } + if (switchContext->nameHashArray) { + OvsFreeMemory(switchContext->nameHashArray); + } + if (switchContext->portHashArray) { + OvsFreeMemory(switchContext->portHashArray); + } + OvsDeleteFlowTable(&switchContext->datapath); + OvsCleanupBufferPool(switchContext); + + OVS_LOG_TRACE("Exit: Failed to init switchContext"); + return NDIS_STATUS_RESOURCES; + } + + for (i = 0; i < OVS_MAX_VPORT_ARRAY_SIZE; i++) { + InitializeListHead(&switchContext->nameHashArray[i]); + } + for (i = 0; i < OVS_MAX_VPORT_ARRAY_SIZE; i++) { + InitializeListHead(&switchContext->portHashArray[i]); + } + RtlZeroMemory(switchContext->vportArray, + sizeof (PVOID) * OVS_MAX_VPORT_ARRAY_SIZE); + + switchContext->isActivated = FALSE; + switchContext->isActivateFailed = FALSE; + switchContext->dpNo = OVS_DP_NUMBER; + switchContext->lastPortIndex = OVS_MAX_VPORT_ARRAY_SIZE -1; + ovsTimeIncrementPerTick = KeQueryTimeIncrement() / 10000; + OVS_LOG_TRACE("Exit: Succesfully initialized switchContext: %p", + switchContext); + return NDIS_STATUS_SUCCESS; +} + +static VOID +OvsCleanupSwitchContext(POVS_SWITCH_CONTEXT switchContext) +{ + OVS_LOG_TRACE("Enter: Delete switchContext:%p", switchContext); + + /* We need to do cleanup for tunnel port here. */ + ASSERT(switchContext->numVports == 0); + + NdisFreeRWLock(switchContext->dispatchLock); + OvsFreeMemory(switchContext->nameHashArray); + OvsFreeMemory(switchContext->portHashArray); + OvsFreeMemory(switchContext->vportArray); + OvsDeleteFlowTable(&switchContext->datapath); + OvsCleanupBufferPool(switchContext); + OVS_LOG_TRACE("Exit: Delete switchContext: %p", switchContext); +} + +/* + * -------------------------------------------------------------------------- + * This function activates the switch by initializing it with all the runtime + * state. First it queries all of the MAC addresses set as custom switch policy + * to allow sends from, and adds tme to the property list. Then it queries the + * NIC list and verifies it can support all of the NICs currently connected to + * the switch, and adds the NICs to the NIC list. + * -------------------------------------------------------------------------- + */ +static NDIS_STATUS +OvsActivateSwitch(POVS_SWITCH_CONTEXT switchContext) +{ + NDIS_STATUS status; + + ASSERT(!switchContext->isActivated); + + OVS_LOG_TRACE("Enter: activate switch %p, dpNo: %ld", + switchContext, switchContext->dpNo); + + status = OvsAddConfiguredSwitchPorts(switchContext); + + if (status != NDIS_STATUS_SUCCESS) { + OVS_LOG_WARN("Failed to add configured switch ports"); + goto cleanup; + + } + status = OvsInitConfiguredSwitchNics(switchContext); + + if (status != NDIS_STATUS_SUCCESS) { + OVS_LOG_WARN("Failed to add configured vports"); + OvsClearAllSwitchVports(switchContext); + goto cleanup; + } + switchContext->isActivated = TRUE; + OvsPostEvent(OVS_DEFAULT_PORT_NO, OVS_DEFAULT_EVENT_STATUS); + +cleanup: + OVS_LOG_TRACE("Exit: activate switch:%p, isActivated: %s, status = %lx", + switchContext, + (switchContext->isActivated ? "TRUE" : "FALSE"), status); + return status; +} + +PVOID +OvsGetVportFromIndex(UINT16 index) +{ + if (index < OVS_MAX_VPORT_ARRAY_SIZE && + !OVS_IS_VPORT_ENTRY_NULL(gOvsSwitchContext, index)) { + return gOvsSwitchContext->vportArray[index]; + } + return NULL; +} + +PVOID +OvsGetExternalVport() +{ + return gOvsSwitchContext->externalVport; +} + + +/* + * -------------------------------------------------------------------------- + * Implements filter driver's FilterNetPnPEvent function. + * -------------------------------------------------------------------------- + */ +NDIS_STATUS +OvsExtNetPnPEvent(NDIS_HANDLE filterModuleContext, + PNET_PNP_EVENT_NOTIFICATION netPnPEvent) +{ + NDIS_STATUS status = NDIS_STATUS_SUCCESS; + POVS_SWITCH_CONTEXT switchContext = (POVS_SWITCH_CONTEXT)filterModuleContext; + BOOLEAN switchActive; + + OVS_LOG_TRACE("Enter: filterModuleContext: %p, NetEvent: %d", + filterModuleContext, (netPnPEvent->NetPnPEvent).NetEvent); + /* + * The only interesting event is the NetEventSwitchActivate. It provides + * an asynchronous notification of the switch completing activation. + */ + if (netPnPEvent->NetPnPEvent.NetEvent == NetEventSwitchActivate) { + status = OvsQuerySwitchActivationComplete(switchContext, &switchActive); + if (status != NDIS_STATUS_SUCCESS) { + switchContext->isActivateFailed = TRUE; + } else { + ASSERT(switchContext->isActivated == FALSE); + ASSERT(switchActive == TRUE); + if (switchContext->isActivated == FALSE && switchActive == TRUE) { + status = OvsActivateSwitch(switchContext); + OVS_LOG_TRACE("OvsExtNetPnPEvent: activated switch: %p " + "status: %s", switchContext, + status ? "TRUE" : "FALSE"); + } + } + } + + if (status == NDIS_STATUS_SUCCESS) { + status = NdisFNetPnPEvent(switchContext->NdisFilterHandle, + netPnPEvent); + } + OVS_LOG_TRACE("Exit: OvsExtNetPnPEvent"); + + return status; +} |