datapath-windows: Solved memory leak in OVS datapath
[cascardo/ovs.git] / datapath-windows / ovsext / Datapath.c
index edb2bde..4af909c 100644 (file)
  * OVS_USE_NL_INTERFACE = 0 => legacy inteface to use with dpif-windows.c
  * OVS_USE_NL_INTERFACE = 1 => netlink inteface to use with ported dpif-linux.c
  */
-#if defined OVS_USE_NL_INTERFACE && OVS_USE_NL_INTERFACE == 1
 
 #include "precomp.h"
 #include "Switch.h"
 #include "User.h"
 #include "Datapath.h"
 #include "Jhash.h"
-#include "Switch.h"
 #include "Vport.h"
 #include "Event.h"
 #include "User.h"
@@ -80,17 +78,17 @@ typedef struct _NETLINK_CMD {
 /* A netlink family is a group of commands. */
 typedef struct _NETLINK_FAMILY {
     CHAR *name;
-    UINT32 id;
+    UINT16 id;
     UINT8 version;
-    UINT8 pad;
+    UINT8 pad1;
     UINT16 maxAttr;
+    UINT16 pad2;
     NETLINK_CMD *cmds;          /* Array of netlink commands and handlers. */
     UINT16 opsCount;
 } NETLINK_FAMILY, *PNETLINK_FAMILY;
 
 /* Handlers for the various netlink commands. */
-static NetlinkCmdHandler OvsGetPidCmdHandler,
-                         OvsPendEventCmdHandler,
+static NetlinkCmdHandler OvsPendEventCmdHandler,
                          OvsPendPacketCmdHandler,
                          OvsSubscribeEventCmdHandler,
                          OvsSubscribePacketCmdHandler,
@@ -98,20 +96,22 @@ static NetlinkCmdHandler OvsGetPidCmdHandler,
                          OvsReadPacketCmdHandler,
                          OvsNewDpCmdHandler,
                          OvsGetDpCmdHandler,
-                         OvsSetDpCmdHandler,
+                         OvsSetDpCmdHandler;
+
+NetlinkCmdHandler        OvsGetNetdevCmdHandler,
                          OvsGetVportCmdHandler,
                          OvsSetVportCmdHandler,
                          OvsNewVportCmdHandler,
                          OvsDeleteVportCmdHandler;
 
-NetlinkCmdHandler        OvsGetNetdevCmdHandler;
-
 static NTSTATUS HandleGetDpTransaction(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
                                        UINT32 *replyLen);
 static NTSTATUS HandleGetDpDump(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
                                 UINT32 *replyLen);
 static NTSTATUS HandleDpTransactionCommon(
                     POVS_USER_PARAMS_CONTEXT usrParamsCtx, UINT32 *replyLen);
+static NTSTATUS OvsGetPidHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
+                                    UINT32 *replyLen);
 
 /*
  * The various netlink families, along with the supported commands. Most of
@@ -122,11 +122,6 @@ static NTSTATUS HandleDpTransactionCommon(
 
 /* Netlink control family: this is a Windows specific family. */
 NETLINK_CMD nlControlFamilyCmdOps[] = {
-    { .cmd             = OVS_CTRL_CMD_WIN_GET_PID,
-      .handler         = OvsGetPidCmdHandler,
-      .supportedDevOp  = OVS_TRANSACTION_DEV_OP,
-      .validateDpIndex = FALSE,
-    },
     { .cmd = OVS_CTRL_CMD_WIN_PEND_REQ,
       .handler = OvsPendEventCmdHandler,
       .supportedDevOp = OVS_WRITE_DEV_OP,
@@ -149,12 +144,12 @@ NETLINK_CMD nlControlFamilyCmdOps[] = {
     },
     { .cmd = OVS_CTRL_CMD_EVENT_NOTIFY,
       .handler = OvsReadEventCmdHandler,
-      .supportedDevOp = OVS_READ_EVENT_DEV_OP,
+      .supportedDevOp = OVS_READ_DEV_OP,
       .validateDpIndex = FALSE,
     },
     { .cmd = OVS_CTRL_CMD_READ_NOTIFY,
       .handler = OvsReadPacketCmdHandler,
-      .supportedDevOp = OVS_READ_PACKET_DEV_OP,
+      .supportedDevOp = OVS_READ_DEV_OP,
       .validateDpIndex = FALSE,
     }
 };
@@ -351,6 +346,37 @@ extern POVS_SWITCH_CONTEXT gOvsSwitchContext;
 NDIS_SPIN_LOCK ovsCtrlLockObj;
 PNDIS_SPIN_LOCK gOvsCtrlLock;
 
+NTSTATUS
+InitUserDumpState(POVS_OPEN_INSTANCE instance,
+                  POVS_MESSAGE ovsMsg)
+{
+    /* Clear the dumpState from a previous dump sequence. */
+    ASSERT(instance->dumpState.ovsMsg == NULL);
+    ASSERT(ovsMsg);
+
+    instance->dumpState.ovsMsg =
+        (POVS_MESSAGE)OvsAllocateMemoryWithTag(sizeof(OVS_MESSAGE),
+                                               OVS_DATAPATH_POOL_TAG);
+    if (instance->dumpState.ovsMsg == NULL) {
+        return STATUS_NO_MEMORY;
+    }
+    RtlCopyMemory(instance->dumpState.ovsMsg, ovsMsg,
+                  sizeof *instance->dumpState.ovsMsg);
+    RtlZeroMemory(instance->dumpState.index,
+                  sizeof instance->dumpState.index);
+
+    return STATUS_SUCCESS;
+}
+
+VOID
+FreeUserDumpState(POVS_OPEN_INSTANCE instance)
+{
+    if (instance->dumpState.ovsMsg != NULL) {
+        OvsFreeMemoryWithTag(instance->dumpState.ovsMsg,
+                             OVS_DATAPATH_POOL_TAG);
+        RtlZeroMemory(&instance->dumpState, sizeof instance->dumpState);
+    }
+}
 
 VOID
 OvsInit()
@@ -435,9 +461,9 @@ OvsCreateDeviceObject(NDIS_HANDLE ovsExtDriverHandle)
             ovsExt->numberOpenInstance = 0;
         }
     } else {
-        /* Initialize the associated data structures. */
-        OvsInit();
+        OvsRegisterSystemProvider((PVOID)gOvsDeviceObject);
     }
+
     OVS_LOG_TRACE("DeviceObject: %p", gOvsDeviceObject);
     return status;
 }
@@ -459,8 +485,9 @@ OvsDeleteDeviceObject()
         NdisDeregisterDeviceEx(gOvsDeviceHandle);
         gOvsDeviceHandle = NULL;
         gOvsDeviceObject = NULL;
+
+        OvsUnregisterSystemProvider();
     }
-    OvsCleanup();
 }
 
 POVS_OPEN_INSTANCE
@@ -470,8 +497,7 @@ OvsGetOpenInstance(PFILE_OBJECT fileObject,
     POVS_OPEN_INSTANCE instance = (POVS_OPEN_INSTANCE)fileObject->FsContext;
     ASSERT(instance);
     ASSERT(instance->fileObject == fileObject);
-    if (gOvsSwitchContext == NULL ||
-        gOvsSwitchContext->dpNo != dpNo) {
+    if (gOvsSwitchContext->dpNo != dpNo) {
         return NULL;
     }
     return instance;
@@ -499,7 +525,8 @@ OvsAddOpenInstance(POVS_DEVICE_EXTENSION ovsExt,
                    PFILE_OBJECT fileObject)
 {
     POVS_OPEN_INSTANCE instance =
-        (POVS_OPEN_INSTANCE) OvsAllocateMemory(sizeof (OVS_OPEN_INSTANCE));
+        (POVS_OPEN_INSTANCE)OvsAllocateMemoryWithTag(sizeof(OVS_OPEN_INSTANCE),
+                                                     OVS_DATAPATH_POOL_TAG);
     UINT32 i;
 
     if (instance == NULL) {
@@ -510,7 +537,7 @@ OvsAddOpenInstance(POVS_DEVICE_EXTENSION ovsExt,
 
     if (ovsNumberOfOpenInstances >= OVS_MAX_OPEN_INSTANCES) {
         OvsReleaseCtrlLock();
-        OvsFreeMemory(instance);
+        OvsFreeMemoryWithTag(instance, OVS_DATAPATH_POOL_TAG);
         return STATUS_INSUFFICIENT_RESOURCES;
     }
     RtlZeroMemory(instance, sizeof (OVS_OPEN_INSTANCE));
@@ -561,7 +588,8 @@ OvsRemoveOpenInstance(PFILE_OBJECT fileObject)
     OvsReleaseCtrlLock();
     ASSERT(instance->eventQueue == NULL);
     ASSERT (instance->packetQueue == NULL);
-    OvsFreeMemory(instance);
+    FreeUserDumpState(instance);
+    OvsFreeMemoryWithTag(instance, OVS_DATAPATH_POOL_TAG);
 }
 
 NTSTATUS
@@ -643,7 +671,6 @@ OvsCleanupDevice(PDEVICE_OBJECT deviceObject,
     return OvsCompleteIrpRequest(irp, (ULONG_PTR)0, status);
 }
 
-
 /*
  * --------------------------------------------------------------------------
  * IOCTL function handler for the device.
@@ -653,7 +680,6 @@ NTSTATUS
 OvsDeviceControl(PDEVICE_OBJECT deviceObject,
                  PIRP irp)
 {
-
     PIO_STACK_LOCATION irpSp;
     NTSTATUS status = STATUS_SUCCESS;
     PFILE_OBJECT fileObject;
@@ -690,10 +716,15 @@ OvsDeviceControl(PDEVICE_OBJECT deviceObject,
     outputBufferLen = irpSp->Parameters.DeviceIoControl.OutputBufferLength;
     inputBuffer = irp->AssociatedIrp.SystemBuffer;
 
-    /* Concurrent netlink operations are not supported. */
-    if (InterlockedCompareExchange((LONG volatile *)&instance->inUse, 1, 0)) {
-        status = STATUS_RESOURCE_IN_USE;
-        goto done;
+    /* Check if the extension is enabled. */
+    if (NULL == gOvsSwitchContext) {
+        status = STATUS_NOT_FOUND;
+        goto exit;
+    }
+
+    if (!OvsAcquireSwitchContext()) {
+        status = STATUS_NOT_FOUND;
+        goto exit;
     }
 
     /*
@@ -701,8 +732,26 @@ OvsDeviceControl(PDEVICE_OBJECT deviceObject,
      * operation.
      */
     switch (code) {
+    case OVS_IOCTL_GET_PID:
+        /* Both input buffer and output buffer use the same location. */
+        outputBuffer = irp->AssociatedIrp.SystemBuffer;
+        if (outputBufferLen != 0) {
+            InitUserParamsCtx(irp, instance, 0, NULL,
+                              inputBuffer, inputBufferLen,
+                              outputBuffer, outputBufferLen,
+                              &usrParamsCtx);
+
+            ASSERT(outputBuffer);
+        } else {
+            status = STATUS_NDIS_INVALID_LENGTH;
+            goto done;
+        }
+
+        status = OvsGetPidHandler(&usrParamsCtx, &replyLen);
+        goto done;
+
     case OVS_IOCTL_TRANSACT:
-        /* Input buffer is mandatory, output buffer is optional. */
+        /* Both input buffer and output buffer are mandatory. */
         if (outputBufferLen != 0) {
             status = MapIrpOutputBuffer(irp, outputBufferLen,
                                         sizeof *ovsMsg, &outputBuffer);
@@ -710,6 +759,9 @@ OvsDeviceControl(PDEVICE_OBJECT deviceObject,
                 goto done;
             }
             ASSERT(outputBuffer);
+        } else {
+            status = STATUS_NDIS_INVALID_LENGTH;
+            goto done;
         }
 
         if (inputBufferLen < sizeof (*ovsMsg)) {
@@ -723,7 +775,10 @@ OvsDeviceControl(PDEVICE_OBJECT deviceObject,
 
     case OVS_IOCTL_READ_EVENT:
     case OVS_IOCTL_READ_PACKET:
-        /* This IOCTL is used to read events */
+        /*
+         * Output buffer is mandatory. These IOCTLs are used to read events and
+         * packets respectively. It is convenient to have separate ioctls.
+         */
         if (outputBufferLen != 0) {
             status = MapIrpOutputBuffer(irp, outputBufferLen,
                                         sizeof *ovsMsg, &outputBuffer);
@@ -739,12 +794,17 @@ OvsDeviceControl(PDEVICE_OBJECT deviceObject,
         inputBufferLen = 0;
 
         ovsMsg = &ovsMsgReadOp;
-        ovsMsg->nlMsg.nlmsgType = OVS_WIN_NL_CTRL_FAMILY_ID;
+        RtlZeroMemory(ovsMsg, sizeof *ovsMsg);
+        ovsMsg->nlMsg.nlmsgLen = sizeof *ovsMsg;
+        ovsMsg->nlMsg.nlmsgType = nlControlFamilyOps.id;
         ovsMsg->nlMsg.nlmsgPid = instance->pid;
+
         /* An "artificial" command so we can use NL family function table*/
         ovsMsg->genlMsg.cmd = (code == OVS_IOCTL_READ_EVENT) ?
                               OVS_CTRL_CMD_EVENT_NOTIFY :
                               OVS_CTRL_CMD_READ_NOTIFY;
+        ovsMsg->genlMsg.version = nlControlFamilyOps.version;
+
         devOp = OVS_READ_DEV_OP;
         break;
 
@@ -774,7 +834,7 @@ OvsDeviceControl(PDEVICE_OBJECT deviceObject,
          * state in the instance to indicate the command that started the dump
          * operation. The state can setup 'ovsMsgReadOp' appropriately. Note
          * that 'ovsMsgReadOp' is needed only in this function to call into the
-         * appropraite handler. The handler itself can access the state in the
+         * appropriate handler. The handler itself can access the state in the
          * instance.
          *
          * In the absence of a dump start, return 0 bytes.
@@ -835,8 +895,8 @@ OvsDeviceControl(PDEVICE_OBJECT deviceObject,
     }
 
     /*
-     * For read operation, the netlink command has already been validated
-     * previously.
+     * For read operation, avoid duplicate validation since 'ovsMsg' is either
+     * "artificial" or was copied from a previously validated 'ovsMsg'.
      */
     if (devOp != OVS_READ_DEV_OP) {
         status = ValidateNetlinkCmd(devOp, instance, ovsMsg, nlFamilyOps);
@@ -853,8 +913,17 @@ OvsDeviceControl(PDEVICE_OBJECT deviceObject,
     status = InvokeNetlinkCmdHandler(&usrParamsCtx, nlFamilyOps, &replyLen);
 
 done:
-    KeMemoryBarrier();
-    instance->inUse = 0;
+    OvsReleaseSwitchContext(gOvsSwitchContext);
+
+exit:
+    /* Should not complete a pending IRP unless proceesing is completed. */
+    if (status == STATUS_PENDING) {
+        /* STATUS_PENDING is returned by the NL handler when the request is
+         * to be processed later, so we mark the IRP as pending and complete
+         * it in another thread when the request is processed. */
+        IoMarkIrpPending(irp);
+        return status;
+    }
     return OvsCompleteIrpRequest(irp, (ULONG_PTR)replyLen, status);
 }
 
@@ -890,22 +959,17 @@ ValidateNetlinkCmd(UINT32 devOp,
 
             /* Validate the DP for commands that require a DP. */
             if (nlFamilyOps->cmds[i].validateDpIndex == TRUE) {
-                OvsAcquireCtrlLock();
-                if (!gOvsSwitchContext || ovsMsg->ovsHdr.dp_ifindex !=
+                if (ovsMsg->ovsHdr.dp_ifindex !=
                                           (INT)gOvsSwitchContext->dpNo) {
                     status = STATUS_INVALID_PARAMETER;
-                    OvsReleaseCtrlLock();
                     goto done;
                 }
-                OvsReleaseCtrlLock();
             }
 
             /* Validate the PID. */
-            if (ovsMsg->genlMsg.cmd != OVS_CTRL_CMD_WIN_GET_PID) {
-                if (ovsMsg->nlMsg.nlmsgPid != instance->pid) {
-                    status = STATUS_INVALID_PARAMETER;
-                    goto done;
-                }
+            if (ovsMsg->nlMsg.nlmsgPid != instance->pid) {
+                status = STATUS_INVALID_PARAMETER;
+                goto done;
             }
 
             status = STATUS_SUCCESS;
@@ -919,7 +983,9 @@ done:
 
 /*
  * --------------------------------------------------------------------------
- * Function to invoke the netlink command handler.
+ * Function to invoke the netlink command handler. The function also stores
+ * the return value of the handler function to construct a 'NL_ERROR' message,
+ * and in turn returns success to the caller.
  * --------------------------------------------------------------------------
  */
 static NTSTATUS
@@ -941,50 +1007,81 @@ InvokeNetlinkCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
         }
     }
 
+    /*
+     * Netlink socket semantics dictate that the return value of the netlink
+     * function should be an error ONLY under fatal conditions. If the message
+     * made it all the way to the handler function, it is not a fatal condition.
+     * Absorb the error returned by the handler function into a 'struct
+     * NL_ERROR' and populate the 'output buffer' to return to userspace.
+     *
+     * This behavior is obviously applicable only to netlink commands that
+     * specify an 'output buffer'. For other commands, we return the error as
+     * is.
+     *
+     * 'STATUS_PENDING' is a special return value and userspace is equipped to
+     * handle it.
+     */
+    if (status != STATUS_SUCCESS && status != STATUS_PENDING) {
+        if (usrParamsCtx->devOp != OVS_WRITE_DEV_OP && *replyLen == 0) {
+            NL_ERROR nlError = NlMapStatusToNlErr(status);
+            POVS_MESSAGE msgIn = (POVS_MESSAGE)usrParamsCtx->inputBuffer;
+            POVS_MESSAGE_ERROR msgError = (POVS_MESSAGE_ERROR)
+                usrParamsCtx->outputBuffer;
+
+            ASSERT(msgError);
+            NlBuildErrorMsg(msgIn, msgError, nlError);
+            *replyLen = msgError->nlMsg.nlmsgLen;
+        }
+
+        if (*replyLen != 0) {
+            status = STATUS_SUCCESS;
+        }
+    }
+
+#ifdef DBG
+    if (usrParamsCtx->devOp != OVS_WRITE_DEV_OP) {
+        ASSERT(status == STATUS_PENDING || *replyLen != 0 || status == STATUS_SUCCESS);
+    }
+#endif
+
     return status;
 }
 
 /*
  * --------------------------------------------------------------------------
- *  Command Handler for 'OVS_CTRL_CMD_WIN_GET_PID'.
+ *  Handler for 'OVS_IOCTL_GET_PID'.
  *
  *  Each handle on the device is assigned a unique PID when the handle is
- *  created. On platforms that support netlink natively, the PID is available
- *  to userspace when the netlink socket is created. However, without native
- *  netlink support on Windows, OVS datapath generates the PID and lets the
- *  userspace query it.
- *
- *  This function implements the query.
+ *  created. This function passes the PID to userspace using METHOD_BUFFERED
+ *  method.
  * --------------------------------------------------------------------------
  */
 static NTSTATUS
-OvsGetPidCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
-                    UINT32 *replyLen)
+OvsGetPidHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
+                 UINT32 *replyLen)
 {
-    POVS_MESSAGE msgIn = (POVS_MESSAGE)usrParamsCtx->inputBuffer;
-    POVS_MESSAGE msgOut = (POVS_MESSAGE)usrParamsCtx->outputBuffer;
+    NTSTATUS status = STATUS_SUCCESS;
+    PUINT32 msgOut = (PUINT32)usrParamsCtx->outputBuffer;
 
     if (usrParamsCtx->outputLength >= sizeof *msgOut) {
         POVS_OPEN_INSTANCE instance =
             (POVS_OPEN_INSTANCE)usrParamsCtx->ovsInstance;
 
         RtlZeroMemory(msgOut, sizeof *msgOut);
-        msgOut->nlMsg.nlmsgSeq = msgIn->nlMsg.nlmsgSeq;
-        msgOut->nlMsg.nlmsgPid = instance->pid;
+        RtlCopyMemory(msgOut, &instance->pid, sizeof(*msgOut));
         *replyLen = sizeof *msgOut;
-        /* XXX: We might need to return the DP index as well. */
     } else {
-        return STATUS_NDIS_INVALID_LENGTH;
+        *replyLen = sizeof *msgOut;
+        status = STATUS_NDIS_INVALID_LENGTH;
     }
 
-    return STATUS_SUCCESS;
+    return status;
 }
 
 /*
  * --------------------------------------------------------------------------
  * Utility function to fill up information about the datapath in a reply to
  * userspace.
- * Assumes that 'gOvsCtrlLock' lock is acquired.
  * --------------------------------------------------------------------------
  */
 static NTSTATUS
@@ -1177,22 +1274,14 @@ HandleGetDpDump(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
 
         /* Dump state must have been deleted after previous dump operation. */
         ASSERT(instance->dumpState.index[0] == 0);
+
         /* Output buffer has been validated while validating read dev op. */
         ASSERT(msgOut != NULL && usrParamsCtx->outputLength >= sizeof *msgOut);
 
         NlBufInit(&nlBuf, usrParamsCtx->outputBuffer,
                   usrParamsCtx->outputLength);
 
-        OvsAcquireCtrlLock();
-        if (!gOvsSwitchContext) {
-            /* Treat this as a dump done. */
-            OvsReleaseCtrlLock();
-            *replyLen = 0;
-            FreeUserDumpState(instance);
-            return STATUS_SUCCESS;
-        }
         status = OvsDpFillInfo(gOvsSwitchContext, msgIn, &nlBuf);
-        OvsReleaseCtrlLock();
 
         if (status != STATUS_SUCCESS) {
             *replyLen = 0;
@@ -1249,6 +1338,8 @@ HandleDpTransactionCommon(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
     };
     PNL_ATTR dpAttrs[ARRAY_SIZE(ovsDatapathSetPolicy)];
 
+    UNREFERENCED_PARAMETER(msgOut);
+
     /* input buffer has been validated while validating write dev op. */
     ASSERT(msgIn != NULL && usrParamsCtx->inputLength >= sizeof *msgIn);
 
@@ -1272,18 +1363,14 @@ HandleDpTransactionCommon(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
         RtlZeroMemory(dpAttrs, sizeof dpAttrs);
     }
 
-    /* Output buffer is optional for OVS_TRANSACTION_DEV_OP. */
-    if (msgOut == NULL || usrParamsCtx->outputLength < sizeof *msgOut) {
-        return STATUS_NDIS_INVALID_LENGTH;
-    }
+    /* Output buffer has been validated while validating transact dev op. */
+    ASSERT(msgOut != NULL && usrParamsCtx->outputLength >= sizeof *msgOut);
+
     NlBufInit(&nlBuf, usrParamsCtx->outputBuffer, usrParamsCtx->outputLength);
 
-    OvsAcquireCtrlLock();
     if (dpAttrs[OVS_DP_ATTR_NAME] != NULL) {
-        if (!gOvsSwitchContext &&
-            !OvsCompareString(NlAttrGet(dpAttrs[OVS_DP_ATTR_NAME]),
+        if (!OvsCompareString(NlAttrGet(dpAttrs[OVS_DP_ATTR_NAME]),
                               OVS_SYSTEM_DP_NAME)) {
-            OvsReleaseCtrlLock();
 
             /* Creation of new datapaths is not supported. */
             if (usrParamsCtx->ovsMsg->genlMsg.cmd == OVS_DP_CMD_SET) {
@@ -1295,19 +1382,16 @@ HandleDpTransactionCommon(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
             goto cleanup;
         }
     } else if ((UINT32)msgIn->ovsHdr.dp_ifindex != gOvsSwitchContext->dpNo) {
-        OvsReleaseCtrlLock();
         nlError = NL_ERROR_NODEV;
         goto cleanup;
     }
 
     if (usrParamsCtx->ovsMsg->genlMsg.cmd == OVS_DP_CMD_NEW) {
-        OvsReleaseCtrlLock();
         nlError = NL_ERROR_EXIST;
         goto cleanup;
     }
 
     status = OvsDpFillInfo(gOvsSwitchContext, msgIn, &nlBuf);
-    OvsReleaseCtrlLock();
 
     *replyLen = NlBufSize(&nlBuf);
 
@@ -1316,7 +1400,7 @@ cleanup:
         POVS_MESSAGE_ERROR msgError = (POVS_MESSAGE_ERROR)
             usrParamsCtx->outputBuffer;
 
-        BuildErrorMsg(msgIn, msgError, nlError);
+        NlBuildErrorMsg(msgIn, msgError, nlError);
         *replyLen = msgError->nlMsg.nlmsgLen;
     }
 
@@ -1344,813 +1428,11 @@ OvsSetupDumpStart(POVS_USER_PARAMS_CONTEXT usrParamsCtx)
      * This operation should be setting up the dump state. If there's any
      * previous state, clear it up so as to set it up afresh.
      */
-    if (instance->dumpState.ovsMsg != NULL) {
-        FreeUserDumpState(instance);
-    }
+    FreeUserDumpState(instance);
 
     return InitUserDumpState(instance, msgIn);
 }
 
-static VOID
-BuildMsgOut(POVS_MESSAGE msgIn, POVS_MESSAGE msgOut, UINT16 type,
-            UINT32 length, UINT16 flags)
-{
-    msgOut->nlMsg.nlmsgType = type;
-    msgOut->nlMsg.nlmsgFlags = flags;
-    msgOut->nlMsg.nlmsgSeq = msgIn->nlMsg.nlmsgSeq;
-    msgOut->nlMsg.nlmsgPid = msgIn->nlMsg.nlmsgPid;
-    msgOut->nlMsg.nlmsgLen = length;
-
-    msgOut->genlMsg.cmd = msgIn->genlMsg.cmd;
-    msgOut->genlMsg.version = msgIn->genlMsg.version;
-    msgOut->genlMsg.reserved = 0;
-}
-
-/*
- * XXX: should move out these functions to a Netlink.c or to a OvsMessage.c
- * or even make them inlined functions in Datapath.h. Can be done after the
- * first sprint once we have more code to refactor.
- */
-VOID
-BuildReplyMsgFromMsgIn(POVS_MESSAGE msgIn, POVS_MESSAGE msgOut, UINT16 flags)
-{
-    BuildMsgOut(msgIn, msgOut, msgIn->nlMsg.nlmsgType, sizeof(OVS_MESSAGE),
-                flags);
-}
-
-VOID
-BuildErrorMsg(POVS_MESSAGE msgIn, POVS_MESSAGE_ERROR msgOut, UINT errorCode)
-{
-    BuildMsgOut(msgIn, (POVS_MESSAGE)msgOut, NLMSG_ERROR,
-                sizeof(OVS_MESSAGE_ERROR), 0);
-
-    msgOut->errorMsg.error = errorCode;
-    msgOut->errorMsg.nlMsg = msgIn->nlMsg;
-}
-
-static NTSTATUS
-OvsCreateMsgFromVport(POVS_VPORT_ENTRY vport,
-                      POVS_MESSAGE msgIn,
-                      PVOID outBuffer,
-                      UINT32 outBufLen,
-                      int dpIfIndex)
-{
-    NL_BUFFER nlBuffer;
-    OVS_VPORT_FULL_STATS vportStats;
-    BOOLEAN ok;
-    OVS_MESSAGE msgOut;
-    PNL_MSG_HDR nlMsg;
-
-    NlBufInit(&nlBuffer, outBuffer, outBufLen);
-
-    BuildReplyMsgFromMsgIn(msgIn, &msgOut, NLM_F_MULTI);
-    msgOut.ovsHdr.dp_ifindex = dpIfIndex;
-
-    ok = NlMsgPutHead(&nlBuffer, (PCHAR)&msgOut, sizeof msgOut);
-    if (!ok) {
-        return STATUS_INSUFFICIENT_RESOURCES;
-    }
-
-    ok = NlMsgPutTailU32(&nlBuffer, OVS_VPORT_ATTR_PORT_NO, vport->portNo);
-    if (!ok) {
-        return STATUS_INSUFFICIENT_RESOURCES;
-    }
-
-    ok = NlMsgPutTailU32(&nlBuffer, OVS_VPORT_ATTR_TYPE, vport->ovsType);
-    if (!ok) {
-        return STATUS_INSUFFICIENT_RESOURCES;
-    }
-
-    ok = NlMsgPutTailString(&nlBuffer, OVS_VPORT_ATTR_NAME, vport->ovsName);
-    if (!ok) {
-        return STATUS_INSUFFICIENT_RESOURCES;
-    }
-
-    /*
-     * XXX: when we implement OVS_DP_ATTR_USER_FEATURES in datapath,
-     * we'll need to check the OVS_DP_F_VPORT_PIDS flag: if it is set,
-     * it means we have an array of pids, instead of a single pid.
-     * ATM we assume we have one pid only.
-    */
-
-    ok = NlMsgPutTailU32(&nlBuffer, OVS_VPORT_ATTR_UPCALL_PID,
-                         vport->upcallPid);
-    if (!ok) {
-        return STATUS_INSUFFICIENT_RESOURCES;
-    }
-
-    /*stats*/
-    vportStats.rxPackets = vport->stats.rxPackets;
-    vportStats.rxBytes = vport->stats.rxBytes;
-    vportStats.txPackets = vport->stats.txPackets;
-    vportStats.txBytes = vport->stats.txBytes;
-    vportStats.rxErrors = vport->errStats.rxErrors;
-    vportStats.txErrors = vport->errStats.txErrors;
-    vportStats.rxDropped = vport->errStats.rxDropped;
-    vportStats.txDropped = vport->errStats.txDropped;
-
-    ok = NlMsgPutTailUnspec(&nlBuffer, OVS_VPORT_ATTR_STATS,
-                            (PCHAR)&vportStats,
-                            sizeof(OVS_VPORT_FULL_STATS));
-    if (!ok) {
-        return STATUS_INSUFFICIENT_RESOURCES;
-    }
-
-    /*
-     * XXX: when vxlan udp dest port becomes configurable, we will also need
-     * to add vport options
-    */
-
-    nlMsg = (PNL_MSG_HDR)NlBufAt(&nlBuffer, 0, 0);
-    nlMsg->nlmsgLen = NlBufSize(&nlBuffer);
-
-    return STATUS_SUCCESS;
-}
-
-static NTSTATUS
-OvsGetVportDumpNext(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
-                    UINT32 *replyLen)
-{
-    POVS_MESSAGE msgIn;
-    POVS_OPEN_INSTANCE instance =
-        (POVS_OPEN_INSTANCE)usrParamsCtx->ovsInstance;
-    LOCK_STATE_EX lockState;
-    UINT32 i = OVS_MAX_VPORT_ARRAY_SIZE;
-
-    /*
-     * XXX: this function shares some code with other dump command(s).
-     * In the future, we will need to refactor the dump functions
-    */
-
-    ASSERT(usrParamsCtx->devOp == OVS_READ_DEV_OP);
-
-    if (instance->dumpState.ovsMsg == NULL) {
-        ASSERT(FALSE);
-        return STATUS_INVALID_DEVICE_STATE;
-    }
-
-    /* Output buffer has been validated while validating read dev op. */
-    ASSERT(usrParamsCtx->outputBuffer != NULL);
-
-    msgIn = instance->dumpState.ovsMsg;
-
-    OvsAcquireCtrlLock();
-    if (!gOvsSwitchContext) {
-        /* Treat this as a dump done. */
-        OvsReleaseCtrlLock();
-        *replyLen = 0;
-        FreeUserDumpState(instance);
-        return STATUS_SUCCESS;
-    }
-
-    /*
-     * XXX: when we implement OVS_DP_ATTR_USER_FEATURES in datapath,
-     * we'll need to check the OVS_DP_F_VPORT_PIDS flag: if it is set,
-     * it means we have an array of pids, instead of a single pid.
-     * ATM we assume we have one pid only.
-    */
-    ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
-    NdisAcquireRWLockRead(gOvsSwitchContext->dispatchLock, &lockState,
-                          NDIS_RWL_AT_DISPATCH_LEVEL);
-
-    if (gOvsSwitchContext->numVports > 0) {
-        /* inBucket: the bucket, used for lookup */
-        UINT32 inBucket = instance->dumpState.index[0];
-        /* inIndex: index within the given bucket, used for lookup */
-        UINT32 inIndex = instance->dumpState.index[1];
-        /* the bucket to be used for the next dump operation */
-        UINT32 outBucket = 0;
-        /* the index within the outBucket to be used for the next dump */
-        UINT32 outIndex = 0;
-
-        for (i = inBucket; i < OVS_MAX_VPORT_ARRAY_SIZE; i++) {
-            PLIST_ENTRY head, link;
-            head = &(gOvsSwitchContext->portIdHashArray[i]);
-            POVS_VPORT_ENTRY vport = NULL;
-
-            outIndex = 0;
-            LIST_FORALL(head, link) {
-
-                /*
-                 * if one or more dumps were previously done on this same bucket,
-                 * inIndex will be > 0, so we'll need to reply with the
-                 * inIndex + 1 vport from the bucket.
-                */
-                if (outIndex >= inIndex) {
-                    vport = CONTAINING_RECORD(link, OVS_VPORT_ENTRY, portIdLink);
-
-                    if (vport->portNo != OVS_DPPORT_NUMBER_INVALID) {
-                        OvsCreateMsgFromVport(vport, msgIn,
-                                              usrParamsCtx->outputBuffer,
-                                              usrParamsCtx->outputLength,
-                                              gOvsSwitchContext->dpNo);
-                        ++outIndex;
-                        break;
-                    } else {
-                        vport = NULL;
-                    }
-                }
-
-                ++outIndex;
-            }
-
-            if (vport) {
-                break;
-            }
-
-            /*
-             * if no vport was found above, check the next bucket, beginning
-             * with the first (i.e. index 0) elem from within that bucket
-            */
-            inIndex = 0;
-        }
-
-        outBucket = i;
-
-        /* XXX: what about NLMSG_DONE (as msg type)? */
-        instance->dumpState.index[0] = outBucket;
-        instance->dumpState.index[1] = outIndex;
-    }
-
-    NdisReleaseRWLock(gOvsSwitchContext->dispatchLock, &lockState);
-
-    OvsReleaseCtrlLock();
-
-    /* if i < OVS_MAX_VPORT_ARRAY_SIZE => vport was found */
-    if (i < OVS_MAX_VPORT_ARRAY_SIZE) {
-        POVS_MESSAGE msgOut = (POVS_MESSAGE)usrParamsCtx->outputBuffer;
-        *replyLen = msgOut->nlMsg.nlmsgLen;
-    } else {
-        /*
-         * if i >= OVS_MAX_VPORT_ARRAY_SIZE => vport was not found =>
-         * it's dump done
-         */
-        *replyLen = 0;
-        /* Free up the dump state, since there's no more data to continue. */
-        FreeUserDumpState(instance);
-    }
-
-    return STATUS_SUCCESS;
-}
-
-static NTSTATUS
-OvsGetVport(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
-            UINT32 *replyLen)
-{
-    NTSTATUS status = STATUS_SUCCESS;
-    LOCK_STATE_EX lockState;
-
-    POVS_MESSAGE msgIn = (POVS_MESSAGE)usrParamsCtx->inputBuffer;
-    POVS_MESSAGE msgOut = (POVS_MESSAGE)usrParamsCtx->outputBuffer;
-    POVS_VPORT_ENTRY vport = NULL;
-    NL_ERROR nlError = NL_ERROR_SUCCESS;
-    PCHAR portName = NULL;
-    UINT32 portNameLen = 0;
-    UINT32 portNumber = OVS_DPPORT_NUMBER_INVALID;
-
-    static const NL_POLICY ovsVportPolicy[] = {
-        [OVS_VPORT_ATTR_PORT_NO] = { .type = NL_A_U32, .optional = TRUE },
-        [OVS_VPORT_ATTR_NAME] = { .type = NL_A_STRING,
-                                  .minLen = 2,
-                                  .maxLen = IFNAMSIZ,
-                                  .optional = TRUE},
-    };
-    PNL_ATTR vportAttrs[ARRAY_SIZE(ovsVportPolicy)];
-
-    /* input buffer has been validated while validating write dev op. */
-    ASSERT(usrParamsCtx->inputBuffer != NULL);
-
-    if (!NlAttrParse((PNL_MSG_HDR)msgIn,
-        NLMSG_HDRLEN + GENL_HDRLEN + OVS_HDRLEN,
-        NlMsgAttrsLen((PNL_MSG_HDR)msgIn),
-        ovsVportPolicy, vportAttrs, ARRAY_SIZE(vportAttrs))) {
-        return STATUS_INVALID_PARAMETER;
-    }
-
-    if (msgOut == NULL || usrParamsCtx->outputLength < sizeof *msgOut) {
-        return STATUS_INVALID_BUFFER_SIZE;
-    }
-
-    OvsAcquireCtrlLock();
-    if (!gOvsSwitchContext) {
-        OvsReleaseCtrlLock();
-        return STATUS_INVALID_PARAMETER;
-    }
-    OvsReleaseCtrlLock();
-
-    NdisAcquireRWLockRead(gOvsSwitchContext->dispatchLock, &lockState, 0);
-    if (vportAttrs[OVS_VPORT_ATTR_NAME] != NULL) {
-        portName = NlAttrGet(vportAttrs[OVS_VPORT_ATTR_NAME]);
-        portNameLen = NlAttrGetSize(vportAttrs[OVS_VPORT_ATTR_NAME]);
-
-        /* the port name is expected to be null-terminated */
-        ASSERT(portName[portNameLen - 1] == '\0');
-
-        vport = OvsFindVportByOvsName(gOvsSwitchContext, portName);
-    } else if (vportAttrs[OVS_VPORT_ATTR_PORT_NO] != NULL) {
-        portNumber = NlAttrGetU32(vportAttrs[OVS_VPORT_ATTR_PORT_NO]);
-
-        vport = OvsFindVportByPortNo(gOvsSwitchContext, portNumber);
-    } else {
-        nlError = NL_ERROR_INVAL;
-        NdisReleaseRWLock(gOvsSwitchContext->dispatchLock, &lockState);
-        goto Cleanup;
-    }
-
-    if (!vport) {
-        nlError = NL_ERROR_NODEV;
-        NdisReleaseRWLock(gOvsSwitchContext->dispatchLock, &lockState);
-        goto Cleanup;
-    }
-
-    status = OvsCreateMsgFromVport(vport, msgIn, usrParamsCtx->outputBuffer,
-                                   usrParamsCtx->outputLength,
-                                   gOvsSwitchContext->dpNo);
-    NdisReleaseRWLock(gOvsSwitchContext->dispatchLock, &lockState);
-
-    *replyLen = msgOut->nlMsg.nlmsgLen;
-
-Cleanup:
-    if (nlError != NL_ERROR_SUCCESS) {
-        POVS_MESSAGE_ERROR msgError = (POVS_MESSAGE_ERROR)
-            usrParamsCtx->outputBuffer;
-
-        BuildErrorMsg(msgIn, msgError, nlError);
-        *replyLen = msgError->nlMsg.nlmsgLen;
-    }
-
-    return STATUS_SUCCESS;
-}
-
-/*
- * --------------------------------------------------------------------------
- *  Handler for the get vport command. The function handles the initial call to
- *  setup the dump state, as well as subsequent calls to continue dumping data.
- * --------------------------------------------------------------------------
-*/
-static NTSTATUS
-OvsGetVportCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
-                      UINT32 *replyLen)
-{
-    *replyLen = 0;
-
-    switch (usrParamsCtx->devOp)
-    {
-    case OVS_WRITE_DEV_OP:
-        return OvsSetupDumpStart(usrParamsCtx);
-
-    case OVS_READ_DEV_OP:
-        return OvsGetVportDumpNext(usrParamsCtx, replyLen);
-
-    case OVS_TRANSACTION_DEV_OP:
-        return OvsGetVport(usrParamsCtx, replyLen);
-
-    default:
-        return STATUS_INVALID_DEVICE_REQUEST;
-    }
-
-}
-
-
-
-static UINT32
-OvsComputeVportNo(POVS_SWITCH_CONTEXT switchContext)
-{
-    /* we are not allowed to create the port OVS_DPPORT_NUMBER_LOCAL */
-    for (ULONG i = OVS_DPPORT_NUMBER_LOCAL + 1; i < MAXUINT16; ++i) {
-        POVS_VPORT_ENTRY vport;
-
-        vport = OvsFindVportByPortNo(switchContext, i);
-        if (!vport) {
-            return i;
-        }
-    }
-
-    return OVS_DPPORT_NUMBER_INVALID;
-}
-
-/*
- * --------------------------------------------------------------------------
- *  Command Handler for 'OVS_VPORT_CMD_NEW'.
- * --------------------------------------------------------------------------
- */
-static NTSTATUS
-OvsNewVportCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
-                      UINT32 *replyLen)
-{
-    NDIS_STATUS status = STATUS_SUCCESS;
-    LOCK_STATE_EX lockState;
-
-    NL_ERROR nlError = NL_ERROR_SUCCESS;
-    POVS_MESSAGE msgIn = (POVS_MESSAGE)usrParamsCtx->inputBuffer;
-    POVS_MESSAGE msgOut = (POVS_MESSAGE)usrParamsCtx->outputBuffer;
-    POVS_VPORT_ENTRY vport = NULL;
-    PCHAR portName;
-    ULONG portNameLen;
-    UINT32 portType;
-    UINT32 hash;
-
-    static const NL_POLICY ovsVportPolicy[] = {
-        [OVS_VPORT_ATTR_PORT_NO] = { .type = NL_A_U32, .optional = TRUE },
-        [OVS_VPORT_ATTR_TYPE] = { .type = NL_A_U32, .optional = FALSE },
-        [OVS_VPORT_ATTR_NAME] = { .type = NL_A_STRING, .maxLen = IFNAMSIZ,
-                                  .optional = FALSE},
-        [OVS_VPORT_ATTR_UPCALL_PID] = { .type = NL_A_UNSPEC,
-                                        .optional = FALSE },
-        [OVS_VPORT_ATTR_OPTIONS] = { .type = NL_A_NESTED, .optional = TRUE },
-    };
-
-    PNL_ATTR vportAttrs[ARRAY_SIZE(ovsVportPolicy)];
-
-    /* input buffer has been validated while validating write dev op. */
-    ASSERT(usrParamsCtx->inputBuffer != NULL);
-
-    if (msgOut == NULL || usrParamsCtx->outputLength < sizeof *msgOut) {
-        return STATUS_INVALID_BUFFER_SIZE;
-    }
-
-    if (!NlAttrParse((PNL_MSG_HDR)msgIn,
-        NLMSG_HDRLEN + GENL_HDRLEN + OVS_HDRLEN,
-        NlMsgAttrsLen((PNL_MSG_HDR)msgIn),
-        ovsVportPolicy, vportAttrs, ARRAY_SIZE(vportAttrs))) {
-        return STATUS_INVALID_PARAMETER;
-    }
-
-    OvsAcquireCtrlLock();
-    if (!gOvsSwitchContext) {
-        OvsReleaseCtrlLock();
-        return STATUS_INVALID_PARAMETER;
-    }
-    OvsReleaseCtrlLock();
-
-    portName = NlAttrGet(vportAttrs[OVS_VPORT_ATTR_NAME]);
-    portNameLen = NlAttrGetSize(vportAttrs[OVS_VPORT_ATTR_NAME]);
-    portType = NlAttrGetU32(vportAttrs[OVS_VPORT_ATTR_TYPE]);
-
-    /* we are expecting null terminated strings to be passed */
-    ASSERT(portName[portNameLen - 1] == '\0');
-
-    NdisAcquireRWLockWrite(gOvsSwitchContext->dispatchLock, &lockState, 0);
-
-    vport = OvsFindVportByOvsName(gOvsSwitchContext, portName);
-    if (vport) {
-        nlError = NL_ERROR_EXIST;
-        goto Cleanup;
-    }
-
-    if (portType == OVS_VPORT_TYPE_INTERNAL) {
-        vport = gOvsSwitchContext->internalVport;
-    } else if (portType == OVS_VPORT_TYPE_NETDEV) {
-        if (!strcmp(portName, "external")) {
-            vport = gOvsSwitchContext->externalVport;
-        } else {
-            vport = OvsFindVportByHvName(gOvsSwitchContext, portName);
-        }
-    } else {
-        /* XXX: change when other tunneling ports are added */
-        ASSERT(portType == OVS_VPORT_TYPE_VXLAN);
-
-        if (gOvsSwitchContext->vxlanVport) {
-            nlError = NL_ERROR_EXIST;
-            goto Cleanup;
-        }
-
-        vport = (POVS_VPORT_ENTRY)OvsAllocateVport();
-        if (vport == NULL) {
-            nlError = NL_ERROR_NOMEM;
-            goto Cleanup;
-        }
-
-        vport->ovsState = OVS_STATE_PORT_CREATED;
-
-        /*
-         * XXX: when we allow configuring the vxlan udp port, we should read
-         * this from vport->options instead!
-        */
-        nlError = OvsInitVxlanTunnel(vport, VXLAN_UDP_PORT);
-        if (nlError != NL_ERROR_SUCCESS) {
-            goto Cleanup;
-        }
-    }
-
-    if (!vport) {
-        nlError = NL_ERROR_INVAL;
-        goto Cleanup;
-    }
-
-    if (vport->portNo != OVS_DPPORT_NUMBER_INVALID) {
-        nlError = NL_ERROR_EXIST;
-        goto Cleanup;
-    }
-
-    /* Fill the data in vport */
-    vport->ovsType = portType;
-
-    if (vportAttrs[OVS_VPORT_ATTR_PORT_NO] != NULL) {
-        /*
-        * XXX: when we implement the limit for ovs port number to be
-        * MAXUINT16, we'll need to check the port number received from the
-        * userspace.
-        */
-        vport->portNo = NlAttrGetU32(vportAttrs[OVS_VPORT_ATTR_PORT_NO]);
-    } else {
-        vport->portNo = OvsComputeVportNo(gOvsSwitchContext);
-        if (vport->portNo == OVS_DPPORT_NUMBER_INVALID) {
-            nlError = NL_ERROR_NOMEM;
-            goto Cleanup;
-        }
-    }
-
-    /* The ovs port name must be uninitialized. */
-    ASSERT(vport->ovsName[0] == '\0');
-    ASSERT(portNameLen <= OVS_MAX_PORT_NAME_LENGTH);
-
-    RtlCopyMemory(vport->ovsName, portName, portNameLen);
-
-    /* if we don't have options, then vport->portOptions will be NULL */
-    vport->portOptions = vportAttrs[OVS_VPORT_ATTR_OPTIONS];
-
-    /*
-    * XXX: when we implement OVS_DP_ATTR_USER_FEATURES in datapath,
-    * we'll need to check the OVS_DP_F_VPORT_PIDS flag: if it is set,
-    * it means we have an array of pids, instead of a single pid.
-    * ATM we assume we have one pid only.
-    */
-    vport->upcallPid = NlAttrGetU32(vportAttrs[OVS_VPORT_ATTR_UPCALL_PID]);
-
-    if (vport->ovsType == OVS_VPORT_TYPE_VXLAN) {
-        gOvsSwitchContext->vxlanVport = vport;
-    } else if (vport->ovsType == OVS_VPORT_TYPE_INTERNAL) {
-        gOvsSwitchContext->internalVport = vport;
-        gOvsSwitchContext->internalPortId = vport->portId;
-    } else if (vport->ovsType == OVS_VPORT_TYPE_NETDEV &&
-               vport->isExternal) {
-        gOvsSwitchContext->externalVport = vport;
-        gOvsSwitchContext->externalPortId = vport->portId;
-    }
-
-    /*
-     * insert the port into the hash array of ports: by port number and ovs
-     * and ovs (datapath) port name.
-     * NOTE: OvsJhashWords has portNo as "1" word. This is ok, because the
-     * portNo is stored in 2 bytes only (max port number = MAXUINT16).
-    */
-    hash = OvsJhashWords(&vport->portNo, 1, OVS_HASH_BASIS);
-    InsertHeadList(&gOvsSwitchContext->portNoHashArray[hash & OVS_VPORT_MASK],
-                   &vport->portNoLink);
-
-    hash = OvsJhashBytes(vport->ovsName, portNameLen, OVS_HASH_BASIS);
-    InsertHeadList(&gOvsSwitchContext->ovsPortNameHashArray[hash & OVS_VPORT_MASK],
-                   &vport->ovsNameLink);
-
-    status = OvsCreateMsgFromVport(vport, msgIn, usrParamsCtx->outputBuffer,
-                                   usrParamsCtx->outputLength,
-                                   gOvsSwitchContext->dpNo);
-
-    *replyLen = msgOut->nlMsg.nlmsgLen;
-
-Cleanup:
-    NdisReleaseRWLock(gOvsSwitchContext->dispatchLock, &lockState);
-
-    if (nlError != NL_ERROR_SUCCESS) {
-        POVS_MESSAGE_ERROR msgError = (POVS_MESSAGE_ERROR)
-            usrParamsCtx->outputBuffer;
-
-        if (vport && vport->ovsType == OVS_VPORT_TYPE_VXLAN) {
-            OvsRemoveAndDeleteVport(gOvsSwitchContext, vport);
-        }
-
-        BuildErrorMsg(msgIn, msgError, nlError);
-        *replyLen = msgError->nlMsg.nlmsgLen;
-    }
-
-    return STATUS_SUCCESS;
-}
-
-
-/*
- * --------------------------------------------------------------------------
- *  Command Handler for 'OVS_VPORT_CMD_SET'.
- * --------------------------------------------------------------------------
- */
-static NTSTATUS
-OvsSetVportCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
-                      UINT32 *replyLen)
-{
-    NDIS_STATUS status = STATUS_SUCCESS;
-    LOCK_STATE_EX lockState;
-
-    POVS_MESSAGE msgIn = (POVS_MESSAGE)usrParamsCtx->inputBuffer;
-    POVS_MESSAGE msgOut = (POVS_MESSAGE)usrParamsCtx->outputBuffer;
-    POVS_VPORT_ENTRY vport = NULL;
-    NL_ERROR nlError = NL_ERROR_SUCCESS;
-
-    static const NL_POLICY ovsVportPolicy[] = {
-        [OVS_VPORT_ATTR_PORT_NO] = { .type = NL_A_U32, .optional = TRUE },
-        [OVS_VPORT_ATTR_TYPE] = { .type = NL_A_U32, .optional = TRUE },
-        [OVS_VPORT_ATTR_NAME] = { .type = NL_A_STRING, .maxLen = IFNAMSIZ,
-                                  .optional = TRUE },
-        [OVS_VPORT_ATTR_UPCALL_PID] = { .type = NL_A_UNSPEC,
-                                        .optional = TRUE },
-        [OVS_VPORT_ATTR_STATS] = { .type = NL_A_UNSPEC,
-                                   .minLen = sizeof(OVS_VPORT_FULL_STATS),
-                                   .maxLen = sizeof(OVS_VPORT_FULL_STATS),
-                                   .optional = TRUE },
-        [OVS_VPORT_ATTR_OPTIONS] = { .type = NL_A_NESTED, .optional = TRUE },
-    };
-    PNL_ATTR vportAttrs[ARRAY_SIZE(ovsVportPolicy)];
-
-    ASSERT(usrParamsCtx->inputBuffer != NULL);
-
-    if (!NlAttrParse((PNL_MSG_HDR)msgIn,
-        NLMSG_HDRLEN + GENL_HDRLEN + OVS_HDRLEN,
-        NlMsgAttrsLen((PNL_MSG_HDR)msgIn),
-        ovsVportPolicy, vportAttrs, ARRAY_SIZE(vportAttrs))) {
-        return STATUS_INVALID_PARAMETER;
-    }
-
-    if (msgOut == NULL || usrParamsCtx->outputLength < sizeof *msgOut) {
-        return STATUS_NDIS_INVALID_LENGTH;
-    }
-
-    OvsAcquireCtrlLock();
-    if (!gOvsSwitchContext) {
-        OvsReleaseCtrlLock();
-        return STATUS_INVALID_PARAMETER;
-    }
-
-    NdisAcquireRWLockWrite(gOvsSwitchContext->dispatchLock, &lockState, 0);
-    if (vportAttrs[OVS_VPORT_ATTR_NAME] != NULL) {
-        PSTR portName = NlAttrGet(vportAttrs[OVS_VPORT_ATTR_NAME]);
-#ifdef DBG
-        UINT32 portNameLen = NlAttrGetSize(vportAttrs[OVS_VPORT_ATTR_NAME]);
-#endif
-        /* the port name is expected to be null-terminated */
-        ASSERT(portName[portNameLen - 1] == '\0');
-
-        vport = OvsFindVportByOvsName(gOvsSwitchContext, portName);
-    } else if (vportAttrs[OVS_VPORT_ATTR_PORT_NO] != NULL) {
-        vport = OvsFindVportByPortNo(gOvsSwitchContext,
-                    NlAttrGetU32(vportAttrs[OVS_VPORT_ATTR_PORT_NO]));
-    }
-
-    if (!vport) {
-        nlError = NL_ERROR_NODEV;
-        goto Cleanup;
-    }
-
-    /*
-     * XXX: when we implement OVS_DP_ATTR_USER_FEATURES in datapath,
-     * we'll need to check the OVS_DP_F_VPORT_PIDS flag: if it is set,
-     * it means we have an array of pids, instead of a single pid.
-     * Currently, we support only one pid.
-     */
-    if (vportAttrs[OVS_VPORT_ATTR_UPCALL_PID]) {
-        vport->upcallPid = NlAttrGetU32(vportAttrs[OVS_VPORT_ATTR_UPCALL_PID]);
-    }
-
-    if (vportAttrs[OVS_VPORT_ATTR_TYPE]) {
-        OVS_VPORT_TYPE type = NlAttrGetU32(vportAttrs[OVS_VPORT_ATTR_TYPE]);
-        if (type != vport->ovsType) {
-            nlError = NL_ERROR_INVAL;
-            goto Cleanup;
-        }
-    }
-
-    if (vportAttrs[OVS_VPORT_ATTR_OPTIONS]) {
-        OVS_LOG_ERROR("Vport options not supported");
-        nlError = NL_ERROR_NOTSUPP;
-        goto Cleanup;
-    }
-
-    status = OvsCreateMsgFromVport(vport, msgIn, usrParamsCtx->outputBuffer,
-                                   usrParamsCtx->outputLength,
-                                   gOvsSwitchContext->dpNo);
-
-    *replyLen = msgOut->nlMsg.nlmsgLen;
-
-Cleanup:
-    NdisReleaseRWLock(gOvsSwitchContext->dispatchLock, &lockState);
-    OvsReleaseCtrlLock();
-
-    if (nlError != NL_ERROR_SUCCESS) {
-        POVS_MESSAGE_ERROR msgError = (POVS_MESSAGE_ERROR)
-            usrParamsCtx->outputBuffer;
-
-        BuildErrorMsg(msgIn, msgError, nlError);
-        *replyLen = msgError->nlMsg.nlmsgLen;
-    }
-
-    return STATUS_SUCCESS;
-}
-
-/*
- * --------------------------------------------------------------------------
- *  Command Handler for 'OVS_VPORT_CMD_DEL'.
- * --------------------------------------------------------------------------
- */
-static NTSTATUS
-OvsDeleteVportCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
-                         UINT32 *replyLen)
-{
-    NDIS_STATUS status = STATUS_SUCCESS;
-    LOCK_STATE_EX lockState;
-
-    POVS_MESSAGE msgIn = (POVS_MESSAGE)usrParamsCtx->inputBuffer;
-    POVS_MESSAGE msgOut = (POVS_MESSAGE)usrParamsCtx->outputBuffer;
-    POVS_VPORT_ENTRY vport = NULL;
-    NL_ERROR nlError = NL_ERROR_SUCCESS;
-    PSTR portName = NULL;
-    UINT32 portNameLen = 0;
-
-    static const NL_POLICY ovsVportPolicy[] = {
-        [OVS_VPORT_ATTR_PORT_NO] = { .type = NL_A_U32, .optional = TRUE },
-        [OVS_VPORT_ATTR_NAME] = { .type = NL_A_STRING, .maxLen = IFNAMSIZ, .optional = TRUE },
-    };
-    PNL_ATTR vportAttrs[ARRAY_SIZE(ovsVportPolicy)];
-
-    ASSERT(usrParamsCtx->inputBuffer != NULL);
-
-    if (!NlAttrParse((PNL_MSG_HDR)msgIn,
-        NLMSG_HDRLEN + GENL_HDRLEN + OVS_HDRLEN,
-        NlMsgAttrsLen((PNL_MSG_HDR)msgIn),
-        ovsVportPolicy, vportAttrs, ARRAY_SIZE(vportAttrs))) {
-        return STATUS_INVALID_PARAMETER;
-    }
-
-    if (msgOut == NULL || usrParamsCtx->outputLength < sizeof *msgOut) {
-        return STATUS_NDIS_INVALID_LENGTH;
-    }
-
-    OvsAcquireCtrlLock();
-    if (!gOvsSwitchContext) {
-        OvsReleaseCtrlLock();
-        return STATUS_INVALID_PARAMETER;
-    }
-    OvsReleaseCtrlLock();
-
-    NdisAcquireRWLockWrite(gOvsSwitchContext->dispatchLock, &lockState, 0);
-    if (vportAttrs[OVS_VPORT_ATTR_NAME] != NULL) {
-        portName = NlAttrGet(vportAttrs[OVS_VPORT_ATTR_NAME]);
-        portNameLen = NlAttrGetSize(vportAttrs[OVS_VPORT_ATTR_NAME]);
-
-        /* the port name is expected to be null-terminated */
-        ASSERT(portName[portNameLen - 1] == '\0');
-
-        vport = OvsFindVportByOvsName(gOvsSwitchContext, portName);
-    }
-    else if (vportAttrs[OVS_VPORT_ATTR_PORT_NO] != NULL) {
-        vport = OvsFindVportByPortNo(gOvsSwitchContext,
-            NlAttrGetU32(vportAttrs[OVS_VPORT_ATTR_PORT_NO]));
-    }
-
-    if (!vport) {
-        nlError = NL_ERROR_NODEV;
-        goto Cleanup;
-    }
-
-    status = OvsCreateMsgFromVport(vport, msgIn, usrParamsCtx->outputBuffer,
-                                   usrParamsCtx->outputLength,
-                                   gOvsSwitchContext->dpNo);
-
-    if (vport->hvDeleted || OvsIsTunnelVportType(vport->ovsType)) {
-        /*
-         * The associated hyper-v switch port is not in created state, or,
-         * there is no hyper-v switch port counterpart (for logical ports).
-         * This means that this datapath port is not mapped to a living
-         * hyper-v switc hport. We can destroy and remove the vport from the
-         * list.
-        */
-        OvsRemoveAndDeleteVport(gOvsSwitchContext, vport);
-    } else {
-        /* The associated hyper-v switch port is in the created state, and the
-         * datapath port is mapped to a living hyper-v switch port. We cannot
-         * destroy the vport and cannot remove it from the list of vports.
-         * Instead, we mark the datapath (ovs) part of the vport as
-         * "not created", i.e. we set vport->portNo = OVS_PORT_NUMBER_INVALID.
-        */
-        RemoveEntryList(&vport->ovsNameLink);
-        RemoveEntryList(&vport->portNoLink);
-        vport->portNo = OVS_DPPORT_NUMBER_INVALID;
-        vport->ovsName[0] = '\0';
-    }
-
-    *replyLen = msgOut->nlMsg.nlmsgLen;
-
-Cleanup:
-    NdisReleaseRWLock(gOvsSwitchContext->dispatchLock, &lockState);
-
-    if (nlError != NL_ERROR_SUCCESS) {
-        POVS_MESSAGE_ERROR msgError = (POVS_MESSAGE_ERROR)
-            usrParamsCtx->outputBuffer;
-
-        BuildErrorMsg(msgIn, msgError, nlError);
-        *replyLen = msgError->nlMsg.nlmsgLen;
-    }
-
-    return STATUS_SUCCESS;
-}
-
 
 /*
  * --------------------------------------------------------------------------
@@ -2191,7 +1473,6 @@ MapIrpOutputBuffer(PIRP irp,
  * --------------------------------------------------------------------------
  * Utility function to fill up information about the state of a port in a reply
  * to* userspace.
- * Assumes that 'gOvsCtrlLock' lock is acquired.
  * --------------------------------------------------------------------------
  */
 static NTSTATUS
@@ -2200,7 +1481,7 @@ OvsPortFillInfo(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
                 PNL_BUFFER nlBuf)
 {
     NTSTATUS status;
-    BOOLEAN rc;
+    BOOLEAN ok;
     OVS_MESSAGE msgOutTmp;
     PNL_MSG_HDR nlMsg;
     POVS_VPORT_ENTRY vport;
@@ -2229,8 +1510,8 @@ OvsPortFillInfo(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
     }
     msgOutTmp.ovsHdr.dp_ifindex = gOvsSwitchContext->dpNo;
 
-    rc = NlMsgPutHead(nlBuf, (PCHAR)&msgOutTmp, sizeof msgOutTmp);
-    if (!rc) {
+    ok = NlMsgPutHead(nlBuf, (PCHAR)&msgOutTmp, sizeof msgOutTmp);
+    if (!ok) {
         status = STATUS_INVALID_BUFFER_SIZE;
         goto cleanup;
     }
@@ -2241,10 +1522,12 @@ OvsPortFillInfo(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
         goto cleanup;
     }
 
-    rc = NlMsgPutTailU32(nlBuf, OVS_VPORT_ATTR_PORT_NO, eventEntry->portNo) ||
-         NlMsgPutTailU32(nlBuf, OVS_VPORT_ATTR_TYPE, vport->ovsType) ||
+    ok = NlMsgPutTailU32(nlBuf, OVS_VPORT_ATTR_PORT_NO, eventEntry->portNo) &&
+         NlMsgPutTailU32(nlBuf, OVS_VPORT_ATTR_TYPE, vport->ovsType) &&
+         NlMsgPutTailU32(nlBuf, OVS_VPORT_ATTR_UPCALL_PID,
+                         vport->upcallPid) &&
          NlMsgPutTailString(nlBuf, OVS_VPORT_ATTR_NAME, vport->ovsName);
-    if (!rc) {
+    if (!ok) {
         status = STATUS_INVALID_BUFFER_SIZE;
         goto cleanup;
     }
@@ -2293,12 +1576,6 @@ OvsReadEventCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
 
     NlBufInit(&nlBuf, usrParamsCtx->outputBuffer, usrParamsCtx->outputLength);
 
-    OvsAcquireCtrlLock();
-    if (!gOvsSwitchContext) {
-        status = STATUS_SUCCESS;
-        goto cleanup;
-    }
-
     /* remove an event entry from the event queue */
     status = OvsRemoveEventEntry(usrParamsCtx->ovsInstance, &eventEntry);
     if (status != STATUS_SUCCESS) {
@@ -2314,7 +1591,6 @@ OvsReadEventCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
     }
 
 cleanup:
-    OvsReleaseCtrlLock();
     return status;
 }
 
@@ -2346,14 +1622,6 @@ OvsReadPacketCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
     /* Output buffer has been validated while validating read dev op. */
     ASSERT(msgOut != NULL && usrParamsCtx->outputLength >= sizeof *msgOut);
 
-    OvsAcquireCtrlLock();
-    if (!gOvsSwitchContext) {
-        status = STATUS_SUCCESS;
-        OvsReleaseCtrlLock();
-        return status;
-    }
-    OvsReleaseCtrlLock();
-
     /* Read a packet from the instance queue */
     status = OvsReadDpIoctl(instance->fileObject, usrParamsCtx->outputBuffer,
                             usrParamsCtx->outputLength, replyLen);
@@ -2432,5 +1700,3 @@ OvsPendPacketCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
      */
     return OvsWaitDpIoctl(usrParamsCtx->irp, instance->fileObject);
 }
-
-#endif /* OVS_USE_NL_INTERFACE */