summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNithin Raju <nithin@vmware.com>2014-11-20 16:51:37 -0800
committerBen Pfaff <blp@nicira.com>2014-11-24 17:13:16 -0800
commit012b5d13f6358b58f8048aacae658af9fdbceb0f (patch)
tree4f7a43f9adb56d35b472a985626db90d672de1bd
parent36f29fb1a763e167fa971ac695b727296ad9f811 (diff)
downloadopenvswitch-012b5d13f6358b58f8048aacae658af9fdbceb0f.tar.gz
datapath-windows: Move vport code from Datapath.c to Vport.c.
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@vmware.com> Acked-by: Sorin Vinturis <svinturis@cloudbasesolutions.com> Signed-off-by: Ben Pfaff <blp@nicira.com>
-rw-r--r--datapath-windows/ovsext/Datapath.c750
-rw-r--r--datapath-windows/ovsext/Vport.c743
2 files changed, 746 insertions, 747 deletions
diff --git a/datapath-windows/ovsext/Datapath.c b/datapath-windows/ovsext/Datapath.c
index ce56e3266..a4e63aa37 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,
@@ -1355,750 +1355,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 77a714845..fc905b1c8 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;
+}