datapath-windows: nuke port # argument in IP helper
[cascardo/ovs.git] / datapath-windows / ovsext / Switch.c
index ac4a847..4d9cfda 100644 (file)
@@ -26,7 +26,6 @@
 #include "Event.h"
 #include "Flow.h"
 #include "IpHelper.h"
-#include "TunnelIntf.h"
 #include "Oid.h"
 
 #ifdef OVS_DBG_MOD
 #include "Debug.h"
 
 POVS_SWITCH_CONTEXT gOvsSwitchContext;
-BOOLEAN gOvsInAttach;
+LONG volatile gOvsInAttach;
 UINT64 ovsTimeIncrementPerTick;
 
-extern PNDIS_SPIN_LOCK gOvsCtrlLock;
 extern NDIS_HANDLE gOvsExtDriverHandle;
 extern NDIS_HANDLE gOvsExtDriverObject;
+extern PDEVICE_OBJECT gOvsDeviceObject;
+
+/*
+ * Reference count used to prevent premature deallocation of the global switch
+ * context structure, gOvsSwitchContext.
+ */
+volatile LONG      gOvsSwitchContextRefCount = 0;
 
 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 VOID OvsUninitSwitchContext(POVS_SWITCH_CONTEXT switchContext);
 static NDIS_STATUS OvsActivateSwitch(POVS_SWITCH_CONTEXT switchContext);
 
 
@@ -84,22 +89,18 @@ OvsExtAttach(NDIS_HANDLE ndisFilterHandle,
         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);
+
+    if (InterlockedCompareExchange(&gOvsInAttach, 1, 0)) {
         /* 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) {
@@ -116,7 +117,7 @@ OvsExtAttach(NDIS_HANDLE ndisFilterHandle,
 
     /*
      * Register the switch context with NDIS so NDIS can pass it back to the
-     * Filterxxx callback functions as the 'FilterModuleContext' parameter.
+     * FilterXXX callback functions as the 'FilterModuleContext' parameter.
      */
     RtlZeroMemory(&ovsExtAttributes, sizeof(NDIS_FILTER_ATTRIBUTES));
     ovsExtAttributes.Header.Revision = NDIS_FILTER_ATTRIBUTES_REVISION_1;
@@ -136,6 +137,7 @@ OvsExtAttach(NDIS_HANDLE ndisFilterHandle,
     switchContext->controlFlowState = OvsSwitchAttached;
     switchContext->dataFlowState = OvsSwitchPaused;
 
+    gOvsSwitchContextRefCount = 1;
     gOvsSwitchContext = switchContext;
     KeMemoryBarrier();
 
@@ -169,8 +171,8 @@ OvsCreateSwitch(NDIS_HANDLE ndisFilterHandle,
 
     OVS_LOG_TRACE("Enter: Create switch object");
 
-    switchContext =
-        (POVS_SWITCH_CONTEXT) OvsAllocateMemory(sizeof(OVS_SWITCH_CONTEXT));
+    switchContext = (POVS_SWITCH_CONTEXT) OvsAllocateMemoryWithTag(
+        sizeof(OVS_SWITCH_CONTEXT), OVS_SWITCH_POOL_TAG);
     if (switchContext == NULL) {
         status = NDIS_STATUS_RESOURCES;
         goto create_switch_done;
@@ -188,7 +190,7 @@ OvsCreateSwitch(NDIS_HANDLE ndisFilterHandle,
     if (status != NDIS_STATUS_SUCCESS) {
         OVS_LOG_ERROR("OvsExtAttach: Extension is running in "
                       "non-switch environment.");
-        OvsFreeMemory(switchContext);
+        OvsFreeMemoryWithTag(switchContext, OVS_SWITCH_POOL_TAG);
         goto create_switch_done;
     }
 
@@ -199,15 +201,23 @@ OvsCreateSwitch(NDIS_HANDLE ndisFilterHandle,
 
     status = OvsInitSwitchContext(switchContext);
     if (status != NDIS_STATUS_SUCCESS) {
-        OvsFreeMemory(switchContext);
+        OvsFreeMemoryWithTag(switchContext, OVS_SWITCH_POOL_TAG);
+        switchContext = NULL;
         goto create_switch_done;
     }
 
-    status = OvsTunnelFilterInitialize(gOvsExtDriverObject);
+    status = OvsInitTunnelFilter(gOvsExtDriverObject, gOvsDeviceObject);
     if (status != NDIS_STATUS_SUCCESS) {
-        OvsFreeMemory(switchContext);
+        OvsUninitSwitchContext(switchContext);
         goto create_switch_done;
     }
+
+    status = OvsInitSttDefragmentation();
+    if (status != STATUS_SUCCESS) {
+        OVS_LOG_ERROR("Exit: Failed to initialize Stt Defragmentation");
+        goto create_switch_done;
+    }
+
     *switchContextOut = switchContext;
 
 create_switch_done:
@@ -238,7 +248,7 @@ OvsExtDetach(NDIS_HANDLE filterModuleContext)
     }
     OvsDeleteSwitch(switchContext);
     OvsCleanupIpHelper();
-    gOvsSwitchContext = NULL;
+    OvsCleanupSttDefragmentation();
     /* This completes the cleanup, and a new attach can be handled now. */
 
     OVS_LOG_TRACE("Exit: OvsDetach Successfully");
@@ -254,14 +264,17 @@ OvsExtDetach(NDIS_HANDLE filterModuleContext)
 VOID
 OvsDeleteSwitch(POVS_SWITCH_CONTEXT switchContext)
 {
-    UINT32 dpNo = switchContext->dpNo;
+    UINT32 dpNo = (UINT32) -1;
 
     OVS_LOG_TRACE("Enter: switchContext:%p", switchContext);
 
-    OvsTunnelFilterUninitialize(gOvsExtDriverObject);
-    OvsClearAllSwitchVports(switchContext);
-    OvsCleanupSwitchContext(switchContext);
-    OvsFreeMemory(switchContext);
+    if (switchContext)
+    {
+        dpNo = switchContext->dpNo;
+        OvsClearAllSwitchVports(switchContext);
+        OvsUninitTunnelFilter(gOvsExtDriverObject);
+        OvsUninitSwitchContext(switchContext);
+    }
     OVS_LOG_TRACE("Exit: deleted switch %p  dpNo: %d", switchContext, dpNo);
 }
 
@@ -354,12 +367,16 @@ OvsInitSwitchContext(POVS_SWITCH_CONTEXT switchContext)
     switchContext->dispatchLock =
         NdisAllocateRWLock(switchContext->NdisFilterHandle);
 
-    switchContext->portNoHashArray = (PLIST_ENTRY)
-        OvsAllocateMemory(sizeof(LIST_ENTRY) * OVS_MAX_VPORT_ARRAY_SIZE);
-    switchContext->ovsPortNameHashArray = (PLIST_ENTRY)
-        OvsAllocateMemory(sizeof (LIST_ENTRY) * OVS_MAX_VPORT_ARRAY_SIZE);
-    switchContext->portIdHashArray= (PLIST_ENTRY)
-        OvsAllocateMemory(sizeof (LIST_ENTRY) * OVS_MAX_VPORT_ARRAY_SIZE);
+    switchContext->portNoHashArray = (PLIST_ENTRY)OvsAllocateMemoryWithTag(
+        sizeof(LIST_ENTRY) * OVS_MAX_VPORT_ARRAY_SIZE, OVS_SWITCH_POOL_TAG);
+    switchContext->ovsPortNameHashArray = (PLIST_ENTRY)OvsAllocateMemoryWithTag(
+        sizeof(LIST_ENTRY) * OVS_MAX_VPORT_ARRAY_SIZE, OVS_SWITCH_POOL_TAG);
+    switchContext->portIdHashArray= (PLIST_ENTRY)OvsAllocateMemoryWithTag(
+        sizeof(LIST_ENTRY) * OVS_MAX_VPORT_ARRAY_SIZE, OVS_SWITCH_POOL_TAG);
+    switchContext->pidHashArray = (PLIST_ENTRY)OvsAllocateMemoryWithTag(
+        sizeof(LIST_ENTRY) * OVS_MAX_PID_ARRAY_SIZE, OVS_SWITCH_POOL_TAG);
+    switchContext->tunnelVportsArray = (PLIST_ENTRY)OvsAllocateMemoryWithTag(
+        sizeof(LIST_ENTRY) * OVS_MAX_VPORT_ARRAY_SIZE, OVS_SWITCH_POOL_TAG);
     status = OvsAllocateFlowTable(&switchContext->datapath, switchContext);
 
     if (status == NDIS_STATUS_SUCCESS) {
@@ -369,19 +386,33 @@ OvsInitSwitchContext(POVS_SWITCH_CONTEXT switchContext)
         switchContext->dispatchLock == NULL ||
         switchContext->portNoHashArray == NULL ||
         switchContext->ovsPortNameHashArray == NULL ||
-        switchContext->portIdHashArray== NULL) {
+        switchContext->portIdHashArray== NULL ||
+        switchContext->pidHashArray == NULL ||
+        switchContext->tunnelVportsArray == NULL) {
         if (switchContext->dispatchLock) {
             NdisFreeRWLock(switchContext->dispatchLock);
         }
         if (switchContext->portNoHashArray) {
-            OvsFreeMemory(switchContext->portNoHashArray);
+            OvsFreeMemoryWithTag(switchContext->portNoHashArray,
+                                 OVS_SWITCH_POOL_TAG);
         }
         if (switchContext->ovsPortNameHashArray) {
-            OvsFreeMemory(switchContext->ovsPortNameHashArray);
+            OvsFreeMemoryWithTag(switchContext->ovsPortNameHashArray,
+                                 OVS_SWITCH_POOL_TAG);
         }
         if (switchContext->portIdHashArray) {
-            OvsFreeMemory(switchContext->portIdHashArray);
+            OvsFreeMemoryWithTag(switchContext->portIdHashArray,
+                                 OVS_SWITCH_POOL_TAG);
+        }
+        if (switchContext->pidHashArray) {
+            OvsFreeMemoryWithTag(switchContext->pidHashArray,
+                                 OVS_SWITCH_POOL_TAG);
         }
+
+        if (switchContext->tunnelVportsArray) {
+            OvsFreeMemory(switchContext->tunnelVportsArray);
+        }
+
         OvsDeleteFlowTable(&switchContext->datapath);
         OvsCleanupBufferPool(switchContext);
 
@@ -391,40 +422,114 @@ OvsInitSwitchContext(POVS_SWITCH_CONTEXT switchContext)
 
     for (i = 0; i < OVS_MAX_VPORT_ARRAY_SIZE; i++) {
         InitializeListHead(&switchContext->ovsPortNameHashArray[i]);
-    }
-    for (i = 0; i < OVS_MAX_VPORT_ARRAY_SIZE; i++) {
         InitializeListHead(&switchContext->portIdHashArray[i]);
-    }
-    for (i = 0; i < OVS_MAX_VPORT_ARRAY_SIZE; i++) {
         InitializeListHead(&switchContext->portNoHashArray[i]);
+        InitializeListHead(&switchContext->tunnelVportsArray[i]);
     }
 
+    for (i = 0; i < OVS_MAX_PID_ARRAY_SIZE; i++) {
+        InitializeListHead(&switchContext->pidHashArray[i]);
+    }
+
+    NdisAllocateSpinLock(&(switchContext->pidHashLock));
     switchContext->isActivated = FALSE;
     switchContext->isActivateFailed = FALSE;
     switchContext->dpNo = OVS_DP_NUMBER;
     ovsTimeIncrementPerTick = KeQueryTimeIncrement() / 10000;
+
     OVS_LOG_TRACE("Exit: Succesfully initialized switchContext: %p",
                   switchContext);
     return NDIS_STATUS_SUCCESS;
 }
 
 static VOID
-OvsCleanupSwitchContext(POVS_SWITCH_CONTEXT switchContext)
+OvsUninitSwitchContext(POVS_SWITCH_CONTEXT switchContext)
+{
+    OvsReleaseSwitchContext(switchContext);
+}
+
+/*
+ * --------------------------------------------------------------------------
+ *  Frees up the contents of and also the switch context.
+ * --------------------------------------------------------------------------
+ */
+static VOID
+OvsDeleteSwitchContext(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);
+    ASSERT(switchContext->numHvVports == 0);
+    ASSERT(switchContext->numNonHvVports == 0);
 
     NdisFreeRWLock(switchContext->dispatchLock);
-    OvsFreeMemory(switchContext->ovsPortNameHashArray);
-    OvsFreeMemory(switchContext->portIdHashArray);
-    OvsFreeMemory(switchContext->portNoHashArray);
+    switchContext->dispatchLock = NULL;
+    NdisFreeSpinLock(&(switchContext->pidHashLock));
+    OvsFreeMemoryWithTag(switchContext->ovsPortNameHashArray,
+                         OVS_SWITCH_POOL_TAG);
+    switchContext->ovsPortNameHashArray = NULL;
+    OvsFreeMemoryWithTag(switchContext->portIdHashArray,
+                         OVS_SWITCH_POOL_TAG);
+    switchContext->portIdHashArray = NULL;
+    OvsFreeMemoryWithTag(switchContext->portNoHashArray,
+                         OVS_SWITCH_POOL_TAG);
+    switchContext->portNoHashArray = NULL;
+    OvsFreeMemoryWithTag(switchContext->pidHashArray,
+                         OVS_SWITCH_POOL_TAG);
+    switchContext->pidHashArray = NULL;
+    OvsFreeMemory(switchContext->tunnelVportsArray);
+    switchContext->tunnelVportsArray = NULL;
     OvsDeleteFlowTable(&switchContext->datapath);
     OvsCleanupBufferPool(switchContext);
+
+    OvsFreeMemoryWithTag(switchContext, OVS_SWITCH_POOL_TAG);
     OVS_LOG_TRACE("Exit: Delete switchContext: %p", switchContext);
 }
 
+VOID
+OvsReleaseSwitchContext(POVS_SWITCH_CONTEXT switchContext)
+{
+    LONG ref = 0;
+    LONG newRef = 0;
+    LONG icxRef = 0;
+
+    do {
+        ref = gOvsSwitchContextRefCount;
+        newRef = (0 == ref) ? 0 : ref - 1;
+        icxRef = InterlockedCompareExchange(&gOvsSwitchContextRefCount,
+                                            newRef,
+                                            ref);
+    } while (icxRef != ref);
+
+    if (ref == 1) {
+        OvsDeleteSwitchContext(switchContext);
+        gOvsSwitchContext = NULL;
+    }
+}
+
+BOOLEAN
+OvsAcquireSwitchContext(VOID)
+{
+    LONG ref = 0;
+    LONG newRef = 0;
+    LONG icxRef = 0;
+    BOOLEAN ret = FALSE;
+
+    do {
+        ref = gOvsSwitchContextRefCount;
+        newRef = (0 == ref) ? 0 : ref + 1;
+        icxRef = InterlockedCompareExchange(&gOvsSwitchContextRefCount,
+                                            newRef,
+                                            ref);
+    } while (icxRef != ref);
+
+    if (ref != 0) {
+        ret = TRUE;
+    }
+
+    return ret;
+}
+
 /*
  * --------------------------------------------------------------------------
  *  This function activates the switch by initializing it with all the runtime
@@ -444,6 +549,7 @@ OvsActivateSwitch(POVS_SWITCH_CONTEXT switchContext)
     OVS_LOG_TRACE("Enter: activate switch %p, dpNo: %ld",
                   switchContext, switchContext->dpNo);
 
+    switchContext->isActivated = TRUE;
     status = OvsAddConfiguredSwitchPorts(switchContext);
 
     if (status != NDIS_STATUS_SUCCESS) {
@@ -458,22 +564,18 @@ OvsActivateSwitch(POVS_SWITCH_CONTEXT switchContext)
         OvsClearAllSwitchVports(switchContext);
         goto cleanup;
     }
-    switchContext->isActivated = TRUE;
-    OvsPostEvent(OVS_DEFAULT_PORT_NO, OVS_DEFAULT_EVENT_STATUS);
 
 cleanup:
+    if (status != NDIS_STATUS_SUCCESS) {
+        switchContext->isActivated = TRUE;
+    }
+
     OVS_LOG_TRACE("Exit: activate switch:%p, isActivated: %s, status = %lx",
                   switchContext,
                   (switchContext->isActivated ? "TRUE" : "FALSE"), status);
     return status;
 }
 
-PVOID
-OvsGetExternalVport()
-{
-    return gOvsSwitchContext->externalVport;
-}
-
 
 /*
  * --------------------------------------------------------------------------
@@ -500,7 +602,6 @@ OvsExtNetPnPEvent(NDIS_HANDLE filterModuleContext,
             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 "