Plain code motion. No additional cleanup or refactoring peformed. I'll be doing some code refactoring in subsequent patches.
Signed-off-by: Nithin Raju <nit...@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 _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev