datapath-windows: Initialize reference count when enabling extension
[cascardo/ovs.git] / datapath-windows / ovsext / Switch.c
index 020300c..f176fa0 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);
@@ -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,16 +201,17 @@ 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) {
         OvsUninitSwitchContext(switchContext);
-        OvsFreeMemory(switchContext);
         goto create_switch_done;
     }
+
     *switchContextOut = switchContext;
 
 create_switch_done:
@@ -239,7 +242,6 @@ OvsExtDetach(NDIS_HANDLE filterModuleContext)
     }
     OvsDeleteSwitch(switchContext);
     OvsCleanupIpHelper();
-    gOvsSwitchContext = NULL;
     /* This completes the cleanup, and a new attach can be handled now. */
 
     OVS_LOG_TRACE("Exit: OvsDetach Successfully");
@@ -262,10 +264,9 @@ OvsDeleteSwitch(POVS_SWITCH_CONTEXT switchContext)
     if (switchContext)
     {
         dpNo = switchContext->dpNo;
-        OvsTunnelFilterUninitialize(gOvsExtDriverObject);
         OvsClearAllSwitchVports(switchContext);
+        OvsUninitTunnelFilter(gOvsExtDriverObject);
         OvsUninitSwitchContext(switchContext);
-        OvsFreeMemory(switchContext);
     }
     OVS_LOG_TRACE("Exit: deleted switch %p  dpNo: %d", switchContext, dpNo);
 }
@@ -359,14 +360,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->pidHashArray = (PLIST_ENTRY)
-        OvsAllocateMemory(sizeof(LIST_ENTRY) * OVS_MAX_PID_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) {
@@ -377,22 +380,30 @@ OvsInitSwitchContext(POVS_SWITCH_CONTEXT switchContext)
         switchContext->portNoHashArray == NULL ||
         switchContext->ovsPortNameHashArray == NULL ||
         switchContext->portIdHashArray== NULL ||
-        switchContext->pidHashArray == 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) {
-            OvsFreeMemory(switchContext->pidHashArray);
+            OvsFreeMemoryWithTag(switchContext->pidHashArray,
+                                 OVS_SWITCH_POOL_TAG);
+        }
+
+        if (switchContext->tunnelVportsArray) {
+            OvsFreeMemory(switchContext->tunnelVportsArray);
         }
 
         OvsDeleteFlowTable(&switchContext->datapath);
@@ -404,12 +415,9 @@ 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++) {
@@ -421,6 +429,7 @@ OvsInitSwitchContext(POVS_SWITCH_CONTEXT switchContext)
     switchContext->isActivateFailed = FALSE;
     switchContext->dpNo = OVS_DP_NUMBER;
     ovsTimeIncrementPerTick = KeQueryTimeIncrement() / 10000;
+
     OVS_LOG_TRACE("Exit: Succesfully initialized switchContext: %p",
                   switchContext);
     return NDIS_STATUS_SUCCESS;
@@ -428,28 +437,92 @@ OvsInitSwitchContext(POVS_SWITCH_CONTEXT switchContext)
 
 static VOID
 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);
     switchContext->dispatchLock = NULL;
     NdisFreeSpinLock(&(switchContext->pidHashLock));
-    OvsFreeMemory(switchContext->ovsPortNameHashArray);
+    OvsFreeMemoryWithTag(switchContext->ovsPortNameHashArray,
+                         OVS_SWITCH_POOL_TAG);
     switchContext->ovsPortNameHashArray = NULL;
-    OvsFreeMemory(switchContext->portIdHashArray);
+    OvsFreeMemoryWithTag(switchContext->portIdHashArray,
+                         OVS_SWITCH_POOL_TAG);
     switchContext->portIdHashArray = NULL;
-    OvsFreeMemory(switchContext->portNoHashArray);
+    OvsFreeMemoryWithTag(switchContext->portNoHashArray,
+                         OVS_SWITCH_POOL_TAG);
     switchContext->portNoHashArray = NULL;
-    OvsFreeMemory(switchContext->pidHashArray);
+    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
@@ -493,12 +566,6 @@ cleanup:
     return status;
 }
 
-PVOID
-OvsGetExternalVport()
-{
-    return gOvsSwitchContext->externalVport;
-}
-
 
 /*
  * --------------------------------------------------------------------------
@@ -525,7 +592,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 "