Solved datapath-windows: BSOD when initializing switch context
[cascardo/ovs.git] / datapath-windows / ovsext / Flow.c
index 1257377..69b546a 100644 (file)
@@ -31,7 +31,6 @@
 #pragma warning( push )
 #pragma warning( disable:4127 )
 
-extern PNDIS_SPIN_LOCK gOvsCtrlLock;
 extern POVS_SWITCH_CONTEXT gOvsSwitchContext;
 extern UINT64 ovsTimeIncrementPerTick;
 
@@ -247,6 +246,7 @@ OvsFlowNlCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
                     UINT32 *replyLen)
 {
     NTSTATUS rc = STATUS_SUCCESS;
+    BOOLEAN ok;
     POVS_MESSAGE msgIn = (POVS_MESSAGE)usrParamsCtx->inputBuffer;
     POVS_MESSAGE msgOut = (POVS_MESSAGE)usrParamsCtx->outputBuffer;
     PNL_MSG_HDR nlMsgHdr = &(msgIn->nlMsg);
@@ -258,7 +258,6 @@ OvsFlowNlCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
     OvsFlowStats stats;
     struct ovs_flow_stats replyStats;
     NL_ERROR nlError = NL_ERROR_SUCCESS;
-
     NL_BUFFER nlBuf;
 
     RtlZeroMemory(&mappedFlow, sizeof(OvsFlowPut));
@@ -294,13 +293,14 @@ OvsFlowNlCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
                       usrParamsCtx->outputLength);
 
             /* Prepare nl Msg headers */
-            rc = NlFillOvsMsg(&nlBuf, nlMsgHdr->nlmsgType, 0,
+            ok = NlFillOvsMsg(&nlBuf, nlMsgHdr->nlmsgType, 0,
                               nlMsgHdr->nlmsgSeq, nlMsgHdr->nlmsgPid,
                               genlMsgHdr->cmd, OVS_FLOW_VERSION,
                               ovsHdr->dp_ifindex);
-
-            if (rc == STATUS_SUCCESS) {
+            if (ok) {
                 *replyLen = msgOut->nlMsg.nlmsgLen;
+            } else {
+                rc = STATUS_INVALID_BUFFER_SIZE;
             }
        }
 
@@ -318,7 +318,7 @@ OvsFlowNlCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
     rc = OvsPutFlowIoctl(&mappedFlow, sizeof (struct OvsFlowPut),
                          &stats);
     if (rc != STATUS_SUCCESS) {
-        OVS_LOG_ERROR("OvsFlowPut failed.");
+        OVS_LOG_ERROR("OvsPutFlowIoctl failed.");
         goto done;
     }
 
@@ -330,13 +330,15 @@ OvsFlowNlCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
               usrParamsCtx->outputLength);
 
     /* Prepare nl Msg headers */
-    rc = NlFillOvsMsg(&nlBuf, nlMsgHdr->nlmsgType, 0,
+    ok = NlFillOvsMsg(&nlBuf, nlMsgHdr->nlmsgType, 0,
                       nlMsgHdr->nlmsgSeq, nlMsgHdr->nlmsgPid,
                       genlMsgHdr->cmd, OVS_FLOW_VERSION,
                       ovsHdr->dp_ifindex);
-
-    if (rc != STATUS_SUCCESS) {
+    if (!ok) {
+        rc = STATUS_INVALID_BUFFER_SIZE;
         goto done;
+    } else {
+        rc = STATUS_SUCCESS;
     }
 
     /* Append OVS_FLOW_ATTR_STATS attribute */
@@ -355,7 +357,7 @@ done:
     if (nlError != NL_ERROR_SUCCESS) {
         POVS_MESSAGE_ERROR msgError = (POVS_MESSAGE_ERROR)
                                        usrParamsCtx->outputBuffer;
-        BuildErrorMsg(msgIn, msgError, nlError);
+        NlBuildErrorMsg(msgIn, msgError, nlError);
         *replyLen = msgError->nlMsg.nlmsgLen;
         rc = STATUS_SUCCESS;
     }
@@ -387,7 +389,7 @@ OvsFlowNlGetCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
             (usrParamsCtx->outputBuffer)) {
             POVS_MESSAGE_ERROR msgError = (POVS_MESSAGE_ERROR)
                                            usrParamsCtx->outputBuffer;
-            BuildErrorMsg(msgIn, msgError, nlError);
+            NlBuildErrorMsg(msgIn, msgError, nlError);
             *replyLen = msgError->nlMsg.nlmsgLen;
             status = STATUS_SUCCESS;
             goto done;
@@ -430,6 +432,7 @@ _FlowNlGetCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
     RtlZeroMemory(&getOutput, sizeof(OvsFlowGetOutput));
     UINT32 keyAttrOffset = 0;
     UINT32 tunnelKeyAttrOffset = 0;
+    BOOLEAN ok;
 
     if (usrParamsCtx->inputLength > usrParamsCtx->outputLength) {
         /* Should not be the case.
@@ -503,8 +506,12 @@ _FlowNlGetCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
 
     /* Input already has all the attributes for the flow key.
      * Lets copy the values back. */
-    RtlCopyMemory(usrParamsCtx->outputBuffer, usrParamsCtx->inputBuffer,
-                  usrParamsCtx->inputLength);
+    ok = NlMsgPutTail(&nlBuf, (PCHAR)(usrParamsCtx->inputBuffer),
+                      usrParamsCtx->inputLength);
+    if (!ok) {
+        OVS_LOG_ERROR("Could not copy the data to the buffer tail");
+        goto done;
+    }
 
     rc = _MapFlowStatsToNlStats(&nlBuf, &((getOutput.info).stats));
     if (rc != STATUS_SUCCESS) {
@@ -586,15 +593,20 @@ _FlowNlDumpCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
 
         /* Done with Dump, send NLMSG_DONE */
         if (!(dumpOutput.n)) {
+            BOOLEAN ok;
+
             OVS_LOG_INFO("Dump Done");
 
             nlMsgOutHdr = (PNL_MSG_HDR)(NlBufAt(&nlBuf, NlBufSize(&nlBuf), 0));
-            rc = NlFillNlHdr(&nlBuf, NLMSG_DONE, NLM_F_MULTI,
+            ok = NlFillNlHdr(&nlBuf, NLMSG_DONE, NLM_F_MULTI,
                              nlMsgHdr->nlmsgSeq, nlMsgHdr->nlmsgPid);
 
-            if (rc != STATUS_SUCCESS) {
+            if (!ok) {
+                rc = STATUS_INVALID_BUFFER_SIZE;
                 OVS_LOG_ERROR("Unable to prepare DUMP_DONE reply.");
                 break;
+            } else {
+                rc = STATUS_SUCCESS;
             }
 
             NlMsgAlignSize(nlMsgOutHdr);
@@ -603,17 +615,18 @@ _FlowNlDumpCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
             FreeUserDumpState(instance);
             break;
         } else {
+            BOOLEAN ok;
 
             hdrOffset = NlBufSize(&nlBuf);
             nlMsgOutHdr = (PNL_MSG_HDR)(NlBufAt(&nlBuf, hdrOffset, 0));
 
             /* Netlink header */
-            rc = NlFillOvsMsg(&nlBuf, nlMsgHdr->nlmsgType, NLM_F_MULTI,
+            ok = NlFillOvsMsg(&nlBuf, nlMsgHdr->nlmsgType, NLM_F_MULTI,
                               nlMsgHdr->nlmsgSeq, nlMsgHdr->nlmsgPid,
                               genlMsgHdr->cmd, genlMsgHdr->version,
                               ovsHdr->dp_ifindex);
 
-            if (rc != STATUS_SUCCESS) {
+            if (!ok) {
                 /* Reset rc to success so that we can
                  * send already added messages to user space. */
                 rc = STATUS_SUCCESS;
@@ -1498,8 +1511,13 @@ OvsDeleteFlowTable(OVS_DATAPATH *datapath)
     }
 
     DeleteAllFlows(datapath);
-    OvsFreeMemory(datapath->flowTable);
+    OvsFreeMemoryWithTag(datapath->flowTable, OVS_FLOW_POOL_TAG);
     datapath->flowTable = NULL;
+
+    if (datapath->lock == NULL) {
+        return NDIS_STATUS_SUCCESS;
+    }
+
     NdisFreeRWLock(datapath->lock);
 
     return NDIS_STATUS_SUCCESS;
@@ -1520,8 +1538,8 @@ OvsAllocateFlowTable(OVS_DATAPATH *datapath,
     PLIST_ENTRY bucket;
     int i;
 
-    datapath->flowTable = OvsAllocateMemory(OVS_FLOW_TABLE_SIZE *
-                                            sizeof (LIST_ENTRY));
+    datapath->flowTable = OvsAllocateMemoryWithTag(
+        OVS_FLOW_TABLE_SIZE * sizeof(LIST_ENTRY), OVS_FLOW_POOL_TAG);
     if (!datapath->flowTable) {
         return NDIS_STATUS_RESOURCES;
     }
@@ -1531,6 +1549,10 @@ OvsAllocateFlowTable(OVS_DATAPATH *datapath,
     }
     datapath->lock = NdisAllocateRWLock(switchContext->NdisFilterHandle);
 
+    if (!datapath->lock) {
+        return NDIS_STATUS_RESOURCES;
+    }
+
     return NDIS_STATUS_SUCCESS;
 }
 
@@ -1873,7 +1895,6 @@ RemoveFlow(OVS_DATAPATH *datapath,
 {
     OvsFlow *f = *flow;
     *flow = NULL;
-    UNREFERENCED_PARAMETER(datapath);
 
     ASSERT(datapath->nFlows);
     datapath->nFlows--;
@@ -1963,7 +1984,7 @@ VOID
 FreeFlow(OvsFlow *flow)
 {
     ASSERT(flow);
-    OvsFreeMemory(flow);
+    OvsFreeMemoryWithTag(flow, OVS_FLOW_POOL_TAG);
 }
 
 NTSTATUS
@@ -1982,25 +2003,23 @@ OvsDoDumpFlows(OvsFlowDumpInput *dumpInput,
     BOOLEAN findNextNonEmpty = FALSE;
 
     dpNo = dumpInput->dpNo;
-    NdisAcquireSpinLock(gOvsCtrlLock);
     if (gOvsSwitchContext->dpNo != dpNo) {
         status = STATUS_INVALID_PARAMETER;
-        goto unlock;
+        goto exit;
     }
 
     rowIndex = dumpInput->position[0];
     if (rowIndex >= OVS_FLOW_TABLE_SIZE) {
         dumpOutput->n = 0;
         *replyLen = sizeof(*dumpOutput);
-        goto unlock;
+        goto exit;
     }
 
     columnIndex = dumpInput->position[1];
 
     datapath = &gOvsSwitchContext->datapath;
     ASSERT(datapath);
-    ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
-    OvsAcquireDatapathRead(datapath, &dpLockState, TRUE);
+    OvsAcquireDatapathRead(datapath, &dpLockState, FALSE);
 
     head = &datapath->flowTable[rowIndex];
     node = head->Flink;
@@ -2049,33 +2068,10 @@ OvsDoDumpFlows(OvsFlowDumpInput *dumpInput,
 dp_unlock:
     OvsReleaseDatapath(datapath, &dpLockState);
 
-unlock:
-    NdisReleaseSpinLock(gOvsCtrlLock);
+exit:
     return status;
 }
 
-NTSTATUS
-OvsDumpFlowIoctl(PVOID inputBuffer,
-                 UINT32 inputLength,
-                 PVOID outputBuffer,
-                 UINT32 outputLength,
-                 UINT32 *replyLen)
-{
-    OvsFlowDumpOutput *dumpOutput = (OvsFlowDumpOutput *)outputBuffer;
-    OvsFlowDumpInput *dumpInput = (OvsFlowDumpInput *)inputBuffer;
-
-    if (inputBuffer == NULL || outputBuffer == NULL) {
-        return STATUS_INVALID_PARAMETER;
-    }
-
-    if ((inputLength != sizeof(OvsFlowDumpInput))
-        || (outputLength != sizeof *dumpOutput + dumpInput->actionsLen)) {
-        return STATUS_INFO_LENGTH_MISMATCH;
-    }
-
-    return OvsDoDumpFlows(dumpInput, dumpOutput, replyLen);
-}
-
 static NTSTATUS
 ReportFlowInfo(OvsFlow *flow,
                UINT32 getFlags,
@@ -2133,21 +2129,18 @@ OvsPutFlowIoctl(PVOID inputBuffer,
     }
 
     dpNo = put->dpNo;
-    NdisAcquireSpinLock(gOvsCtrlLock);
     if (gOvsSwitchContext->dpNo != dpNo) {
         status = STATUS_INVALID_PARAMETER;
-        goto unlock;
+        goto exit;
     }
 
     datapath = &gOvsSwitchContext->datapath;
     ASSERT(datapath);
-    ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
-    OvsAcquireDatapathWrite(datapath, &dpLockState, TRUE);
+    OvsAcquireDatapathWrite(datapath, &dpLockState, FALSE);
     status = HandleFlowPut(put, datapath, stats);
     OvsReleaseDatapath(datapath, &dpLockState);
 
-unlock:
-    NdisReleaseSpinLock(gOvsCtrlLock);
+exit:
     return status;
 }
 
@@ -2179,7 +2172,6 @@ HandleFlowPut(OvsFlowPut *put,
 
         status = OvsPrepareFlow(&KernelFlow, put, hash);
         if (status != STATUS_SUCCESS) {
-            FreeFlow(KernelFlow);
             return STATUS_UNSUCCESSFUL;
         }
 
@@ -2268,7 +2260,8 @@ OvsPrepareFlow(OvsFlow **flow,
 
     do {
         *flow = localFlow =
-            OvsAllocateMemory(sizeof(OvsFlow) + put->actionsLen);
+            OvsAllocateMemoryWithTag(sizeof(OvsFlow) + put->actionsLen,
+                                     OVS_FLOW_POOL_TAG);
         if (localFlow == NULL) {
             status = STATUS_NO_MEMORY;
             break;
@@ -2314,16 +2307,14 @@ OvsGetFlowIoctl(PVOID inputBuffer,
     }
 
     dpNo = getInput->dpNo;
-    NdisAcquireSpinLock(gOvsCtrlLock);
     if (gOvsSwitchContext->dpNo != dpNo) {
         status = STATUS_INVALID_PARAMETER;
-        goto unlock;
+        goto exit;
     }
 
     datapath = &gOvsSwitchContext->datapath;
     ASSERT(datapath);
-    ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
-    OvsAcquireDatapathRead(datapath, &dpLockState, TRUE);
+    OvsAcquireDatapathRead(datapath, &dpLockState, FALSE);
     flow = OvsLookupFlow(datapath, &getInput->key, &hash, FALSE);
     if (!flow) {
         status = STATUS_INVALID_PARAMETER;
@@ -2335,8 +2326,7 @@ OvsGetFlowIoctl(PVOID inputBuffer,
 
 dp_unlock:
     OvsReleaseDatapath(datapath, &dpLockState);
-unlock:
-    NdisReleaseSpinLock(gOvsCtrlLock);
+exit:
     return status;
 }
 
@@ -2347,21 +2337,18 @@ OvsFlushFlowIoctl(UINT32 dpNo)
     OVS_DATAPATH *datapath = NULL;
     LOCK_STATE_EX dpLockState;
 
-    NdisAcquireSpinLock(gOvsCtrlLock);
     if (gOvsSwitchContext->dpNo != dpNo) {
         status = STATUS_INVALID_PARAMETER;
-        goto unlock;
+        goto exit;
     }
 
     datapath = &gOvsSwitchContext->datapath;
     ASSERT(datapath);
-    ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
-    OvsAcquireDatapathWrite(datapath, &dpLockState, TRUE);
+    OvsAcquireDatapathWrite(datapath, &dpLockState, FALSE);
     DeleteAllFlows(datapath);
     OvsReleaseDatapath(datapath, &dpLockState);
 
-unlock:
-    NdisReleaseSpinLock(gOvsCtrlLock);
+exit:
     return status;
 }