summaryrefslogtreecommitdiff
path: root/datapath-windows/ovsext/Switch.c
diff options
context:
space:
mode:
authorSamuel Ghinet <sghinet@cloudbasesolutions.com>2014-08-29 04:06:48 +0000
committerBen Pfaff <blp@nicira.com>2014-08-29 07:55:05 -0700
commitfa1324c92810c6b1e33b7e87caaaf2e6c4041040 (patch)
tree8e06f5d991d755215bb6839a997bc58721b2d754 /datapath-windows/ovsext/Switch.c
parentfd972eb87a888242fb1a8ec2394fa7b3030fbd7d (diff)
downloadopenvswitch-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.c530
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;
+}