[ovs-dev] [PATCH] datapath-windows: move vport code from Datapath.c to Vport.c

Nithin Raju nithin at vmware.com
Fri Nov 21 00:51:37 UTC 2014


Plain code motion. No additional cleanup or refactoring peformed.

I'll be doing some code refactoring in subsequent patches.

Signed-off-by: Nithin Raju <nithin at vmware.com>
---
 datapath-windows/ovsext/Datapath.c |  750 +-----------------------------------
 datapath-windows/ovsext/Vport.c    |  743 +++++++++++++++++++++++++++++++++++
 2 files changed, 746 insertions(+), 747 deletions(-)

diff --git a/datapath-windows/ovsext/Datapath.c b/datapath-windows/ovsext/Datapath.c
index bdbf72c..d57719e 100644
--- a/datapath-windows/ovsext/Datapath.c
+++ b/datapath-windows/ovsext/Datapath.c
@@ -97,14 +97,14 @@ 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,
@@ -1352,750 +1352,6 @@ OvsSetupDumpStart(POVS_USER_PARAMS_CONTEXT usrParamsCtx)
     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();
-
-    /*
-     * 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->numHvVports > 0 ||
-            gOvsSwitchContext->numNonHvVports > 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->portNoHashArray[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, portNoLink);
-
-                    ASSERT(vport->portNo != OVS_DPPORT_NUMBER_INVALID);
-                    OvsCreateMsgFromVport(vport, msgIn,
-                                          usrParamsCtx->outputBuffer,
-                                          usrParamsCtx->outputLength,
-                                          gOvsSwitchContext->dpNo);
-                    ++outIndex;
-                    break;
-                }
-
-                ++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;
-    }
-
-    /* Output buffer has been validated while validating transact dev op. */
-    ASSERT(msgOut != NULL && usrParamsCtx->outputLength >= sizeof *msgOut);
-
-    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;
-    BOOLEAN isBridgeInternal = FALSE;
-    BOOLEAN vportAllocated = FALSE, vportInitialized = FALSE;
-    BOOLEAN addInternalPortAsNetdev = FALSE;
-
-    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);
-
-    /* Output buffer has been validated while validating transact dev op. */
-    ASSERT(msgOut != NULL && usrParamsCtx->outputLength >= sizeof *msgOut);
-
-    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;
-    }
-
-    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 (portName && portType == OVS_VPORT_TYPE_NETDEV &&
-        !strcmp(OVS_DPPORT_INTERNAL_NAME_A, portName)) {
-        addInternalPortAsNetdev = TRUE;
-    }
-
-    if (portName && portType == OVS_VPORT_TYPE_INTERNAL &&
-        strcmp(OVS_DPPORT_INTERNAL_NAME_A, portName)) {
-        isBridgeInternal = TRUE;
-    }
-
-    if (portType == OVS_VPORT_TYPE_INTERNAL && !isBridgeInternal) {
-        vport = gOvsSwitchContext->internalVport;
-    } else if (portType == OVS_VPORT_TYPE_NETDEV) {
-        /* External ports can also be looked up like VIF ports. */
-        vport = OvsFindVportByHvNameA(gOvsSwitchContext, portName);
-    } else {
-        ASSERT(OvsIsTunnelVportType(portType) ||
-               (portType == OVS_VPORT_TYPE_INTERNAL && isBridgeInternal));
-        ASSERT(OvsGetTunnelVport(gOvsSwitchContext, portType) == NULL ||
-               !OvsIsTunnelVportType(portType));
-
-        vport = (POVS_VPORT_ENTRY)OvsAllocateVport();
-        if (vport == NULL) {
-            nlError = NL_ERROR_NOMEM;
-            goto Cleanup;
-        }
-        vportAllocated = TRUE;
-
-        if (OvsIsTunnelVportType(portType)) {
-            status = OvsInitTunnelVport(vport, portType, VXLAN_UDP_PORT);
-            nlError = NlMapStatusToNlErr(status);
-        } else {
-            OvsInitBridgeInternalVport(vport);
-        }
-        vportInitialized = TRUE;
-
-        if (nlError == NL_ERROR_SUCCESS) {
-            vport->ovsState = OVS_STATE_CONNECTED;
-            vport->nicState = NdisSwitchNicStateConnected;
-
-            /*
-             * Allow the vport to be deleted, because there is no
-             * corresponding hyper-v switch part.
-             */
-            vport->isPresentOnHv = TRUE;
-        }
-    }
-
-    if (!vport) {
-        nlError = NL_ERROR_INVAL;
-        goto Cleanup;
-    }
-    if (vport->portNo != OVS_DPPORT_NUMBER_INVALID) {
-        nlError = NL_ERROR_EXIST;
-        goto Cleanup;
-    }
-
-    /* Initialize the vport with OVS specific properties. */
-    if (addInternalPortAsNetdev != TRUE) {
-        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]);
-
-    status = InitOvsVportCommon(gOvsSwitchContext, vport);
-    ASSERT(status == STATUS_SUCCESS);
-
-    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 && vportAllocated == TRUE) {
-            if (vportInitialized == TRUE) {
-                if (OvsIsTunnelVportType(portType)) {
-                    OvsCleanupVxlanTunnel(vport);
-                }
-            }
-            OvsFreeMemory(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;
-    }
-
-    /* Output buffer has been validated while validating transact dev op. */
-    ASSERT(msgOut != NULL && usrParamsCtx->outputLength >= sizeof *msgOut);
-
-    OvsAcquireCtrlLock();
-
-    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;
-    }
-
-    /* Output buffer has been validated while validating transact dev op. */
-    ASSERT(msgOut != NULL && usrParamsCtx->outputLength >= sizeof *msgOut);
-
-    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);
-
-    /*
-     * Mark the port as deleted from OVS userspace. If the port does not exist
-     * on the Hyper-V switch, it gets deallocated. Otherwise, it stays.
-     */
-    OvsRemoveAndDeleteVport(gOvsSwitchContext, vport, FALSE, TRUE, NULL);
-
-    *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;
-}
-
 
 /*
  * --------------------------------------------------------------------------
diff --git a/datapath-windows/ovsext/Vport.c b/datapath-windows/ovsext/Vport.c
index 77a7148..fc905b1 100644
--- a/datapath-windows/ovsext/Vport.c
+++ b/datapath-windows/ovsext/Vport.c
@@ -1630,3 +1630,746 @@ OvsWaitActivate(POVS_SWITCH_CONTEXT switchContext, ULONG sleepMicroSec)
         NdisMSleep(sleepMicroSec);
     }
 }
+
+
+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();
+
+    /*
+     * 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->numHvVports > 0 ||
+            gOvsSwitchContext->numNonHvVports > 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->portNoHashArray[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, portNoLink);
+
+                    ASSERT(vport->portNo != OVS_DPPORT_NUMBER_INVALID);
+                    OvsCreateMsgFromVport(vport, msgIn,
+                                          usrParamsCtx->outputBuffer,
+                                          usrParamsCtx->outputLength,
+                                          gOvsSwitchContext->dpNo);
+                    ++outIndex;
+                    break;
+                }
+
+                ++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;
+    }
+
+    /* Output buffer has been validated while validating transact dev op. */
+    ASSERT(msgOut != NULL && usrParamsCtx->outputLength >= sizeof *msgOut);
+
+    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.
+ * --------------------------------------------------------------------------
+*/
+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'.
+ * --------------------------------------------------------------------------
+ */
+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;
+    BOOLEAN isBridgeInternal = FALSE;
+    BOOLEAN vportAllocated = FALSE, vportInitialized = FALSE;
+    BOOLEAN addInternalPortAsNetdev = FALSE;
+
+    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);
+
+    /* Output buffer has been validated while validating transact dev op. */
+    ASSERT(msgOut != NULL && usrParamsCtx->outputLength >= sizeof *msgOut);
+
+    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;
+    }
+
+    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 (portName && portType == OVS_VPORT_TYPE_NETDEV &&
+        !strcmp(OVS_DPPORT_INTERNAL_NAME_A, portName)) {
+        addInternalPortAsNetdev = TRUE;
+    }
+
+    if (portName && portType == OVS_VPORT_TYPE_INTERNAL &&
+        strcmp(OVS_DPPORT_INTERNAL_NAME_A, portName)) {
+        isBridgeInternal = TRUE;
+    }
+
+    if (portType == OVS_VPORT_TYPE_INTERNAL && !isBridgeInternal) {
+        vport = gOvsSwitchContext->internalVport;
+    } else if (portType == OVS_VPORT_TYPE_NETDEV) {
+        /* External ports can also be looked up like VIF ports. */
+        vport = OvsFindVportByHvNameA(gOvsSwitchContext, portName);
+    } else {
+        ASSERT(OvsIsTunnelVportType(portType) ||
+               (portType == OVS_VPORT_TYPE_INTERNAL && isBridgeInternal));
+        ASSERT(OvsGetTunnelVport(gOvsSwitchContext, portType) == NULL ||
+               !OvsIsTunnelVportType(portType));
+
+        vport = (POVS_VPORT_ENTRY)OvsAllocateVport();
+        if (vport == NULL) {
+            nlError = NL_ERROR_NOMEM;
+            goto Cleanup;
+        }
+        vportAllocated = TRUE;
+
+        if (OvsIsTunnelVportType(portType)) {
+            status = OvsInitTunnelVport(vport, portType, VXLAN_UDP_PORT);
+            nlError = NlMapStatusToNlErr(status);
+        } else {
+            OvsInitBridgeInternalVport(vport);
+        }
+        vportInitialized = TRUE;
+
+        if (nlError == NL_ERROR_SUCCESS) {
+            vport->ovsState = OVS_STATE_CONNECTED;
+            vport->nicState = NdisSwitchNicStateConnected;
+
+            /*
+             * Allow the vport to be deleted, because there is no
+             * corresponding hyper-v switch part.
+             */
+            vport->isPresentOnHv = TRUE;
+        }
+    }
+
+    if (!vport) {
+        nlError = NL_ERROR_INVAL;
+        goto Cleanup;
+    }
+    if (vport->portNo != OVS_DPPORT_NUMBER_INVALID) {
+        nlError = NL_ERROR_EXIST;
+        goto Cleanup;
+    }
+
+    /* Initialize the vport with OVS specific properties. */
+    if (addInternalPortAsNetdev != TRUE) {
+        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]);
+
+    status = InitOvsVportCommon(gOvsSwitchContext, vport);
+    ASSERT(status == STATUS_SUCCESS);
+
+    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 && vportAllocated == TRUE) {
+            if (vportInitialized == TRUE) {
+                if (OvsIsTunnelVportType(portType)) {
+                    OvsCleanupVxlanTunnel(vport);
+                }
+            }
+            OvsFreeMemory(vport);
+        }
+
+        BuildErrorMsg(msgIn, msgError, nlError);
+        *replyLen = msgError->nlMsg.nlmsgLen;
+    }
+
+    return STATUS_SUCCESS;
+}
+
+
+/*
+ * --------------------------------------------------------------------------
+ *  Command Handler for 'OVS_VPORT_CMD_SET'.
+ * --------------------------------------------------------------------------
+ */
+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;
+    }
+
+    /* Output buffer has been validated while validating transact dev op. */
+    ASSERT(msgOut != NULL && usrParamsCtx->outputLength >= sizeof *msgOut);
+
+    OvsAcquireCtrlLock();
+
+    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'.
+ * --------------------------------------------------------------------------
+ */
+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;
+    }
+
+    /* Output buffer has been validated while validating transact dev op. */
+    ASSERT(msgOut != NULL && usrParamsCtx->outputLength >= sizeof *msgOut);
+
+    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);
+
+    /*
+     * Mark the port as deleted from OVS userspace. If the port does not exist
+     * on the Hyper-V switch, it gets deallocated. Otherwise, it stays.
+     */
+    OvsRemoveAndDeleteVport(gOvsSwitchContext, vport, FALSE, TRUE, NULL);
+
+    *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;
+}
-- 
1.7.4.1




More information about the dev mailing list